ZOMBIE_ATTACK_TURTLE_EGG = create("zombie_attack_turtle_egg", Zombie.class);
diff --git a/purpur-api/paper-patches/files/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java.patch b/purpur-api/paper-patches/files/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java.patch
index 4264eea11..25a7de1a8 100644
--- a/purpur-api/paper-patches/files/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java.patch
@@ -1,8 +1,8 @@
--- a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java
-@@ -28,6 +_,12 @@
- */
- Component getVersionMessage(String serverVersion);
+@@ -40,6 +_,12 @@
+ return getVersionMessage();
+ }
+ // Purpur start
+ default int distance() {
@@ -10,6 +10,6 @@
+ }
+ // Purpur end
+
- @ApiStatus.Internal
- class DummyVersionFetcher implements VersionFetcher {
-
+ /**
+ * @hidden
+ */
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/Bukkit.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Bukkit.java.patch
index 7bdf2cf76..20a83c6cf 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/Bukkit.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Bukkit.java.patch
@@ -1,8 +1,8 @@
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
-@@ -2980,4 +_,133 @@
- public static Server.Spigot spigot() {
- return server.spigot();
+@@ -3003,4 +_,147 @@
+ public static void restart() {
+ server.restart();
}
+
+ // Purpur start - Bring back server name
@@ -48,14 +48,16 @@
+ }
+ // Purpur end - Added the ability to add combustible items
+
-+ // Purpur start - Debug Marker API
++ // Purpur start - Debug Marker API
+ /**
+ * Creates debug block highlight on specified block location and show it to all players on the server.
+ *
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration) {
+ server.sendBlockHighlight(location, duration);
+ }
@@ -67,7 +69,9 @@
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, int argb) {
+ server.sendBlockHighlight(location, duration, argb);
+ }
@@ -79,7 +83,9 @@
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text) {
+ server.sendBlockHighlight(location, duration, text);
+ }
@@ -92,7 +98,9 @@
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb) {
+ server.sendBlockHighlight(location, duration, text, argb);
+ }
@@ -106,7 +114,9 @@
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency) {
+ server.sendBlockHighlight(location, duration, color, transparency);
+ }
@@ -121,14 +131,18 @@
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency) {
+ server.sendBlockHighlight(location, duration, text, color, transparency);
+ }
+
+ /**
+ * Clears all debug block highlights for all players on the server.
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ public static void clearBlockHighlights() {
+ server.clearBlockHighlights();
+ }
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/Material.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Material.java.patch
index 48bef86e4..02f7f5abb 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/Material.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Material.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/Material.java
+++ b/src/main/java/org/bukkit/Material.java
-@@ -5812,4 +_,40 @@
+@@ -3708,4 +_,40 @@
return this.asItemType().getDefaultDataTypes();
}
// Paper end - data component API
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch
index 5048818d2..47eb17201 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch
@@ -1,9 +1,9 @@
--- a/src/main/java/org/bukkit/OfflinePlayer.java
+++ b/src/main/java/org/bukkit/OfflinePlayer.java
-@@ -573,4 +_,106 @@
- @Override
- io.papermc.paper.persistence.@NotNull PersistentDataContainerView getPersistentDataContainer();
- // Paper end - add pdc to offline player
+@@ -592,4 +_,104 @@
+ default void applySkinToPlayerHeadContents(final PlayerHeadObjectContents.@NonNull Builder builder) {
+ builder.id(this.getUniqueId());
+ }
+
+ // Purpur start - OfflinePlayer API
+ /**
@@ -12,7 +12,7 @@
+ *
+ * @return True if the player is allowed to fly.
+ */
-+ public boolean getAllowFlight();
++ boolean getAllowFlight();
+
+ /**
+ * Sets if the OfflinePlayer is allowed to fly via jump key double-tap like in
@@ -20,21 +20,21 @@
+ *
+ * @param flight If flight should be allowed.
+ */
-+ public void setAllowFlight(boolean flight);
++ void setAllowFlight(boolean flight);
+
+ /**
+ * Checks to see if this player is currently flying or not.
+ *
+ * @return True if the player is flying, else false.
+ */
-+ public boolean isFlying();
++ boolean isFlying();
+
+ /**
+ * Makes this player start or stop flying.
+ *
+ * @param value True to fly.
+ */
-+ public void setFlying(boolean value);
++ void setFlying(boolean value);
+
+ /**
+ * Sets the speed at which a client will fly. Negative values indicate
@@ -44,7 +44,7 @@
+ * @throws IllegalArgumentException If new speed is less than -1 or
+ * greater than 1
+ */
-+ public void setFlySpeed(float value) throws IllegalArgumentException;
++ void setFlySpeed(float value) throws IllegalArgumentException;
+
+ /**
+ * Sets the speed at which a client will walk. Negative values indicate
@@ -54,21 +54,21 @@
+ * @throws IllegalArgumentException If new speed is less than -1 or
+ * greater than 1
+ */
-+ public void setWalkSpeed(float value) throws IllegalArgumentException;
++ void setWalkSpeed(float value) throws IllegalArgumentException;
+
+ /**
+ * Gets the current allowed speed that a client can fly.
+ *
+ * @return The current allowed speed, from -1 to 1
+ */
-+ public float getFlySpeed();
++ float getFlySpeed();
+
+ /**
+ * Gets the current allowed speed that a client can walk.
+ *
+ * @return The current allowed speed, from -1 to 1
+ */
-+ public float getWalkSpeed();
++ float getWalkSpeed();
+
+ /**
+ * Sets OfflinePlayer's location. If player is online, it falls back to the Player#teleport implementation.
@@ -76,7 +76,7 @@
+ * @param destination
+ * @return true if teleportation was successful
+ */
-+ public boolean teleportOffline(@NotNull org.bukkit.Location destination);
++ boolean teleportOffline(org.bukkit.Location destination);
+
+ /**
+ * Sets OfflinePlayer's location. If player is online, it falls back to the Player#teleport implementation.
@@ -85,7 +85,7 @@
+ * @param cause Teleport cause used if player is online
+ * @return true if teleportation was successful
+ */
-+ public boolean teleportOffline(@NotNull org.bukkit.Location destination, @NotNull org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause);
++ boolean teleportOffline(org.bukkit.Location destination, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause);
+
+ /**
+ * Sets OfflinePlayer's location. If player is online, it falls back to the Player#teleportAsync implementation.
@@ -93,8 +93,7 @@
+ * @param destination
+ * @return true if teleportation successful
+ */
-+ @NotNull
-+ public java.util.concurrent.CompletableFuture teleportOfflineAsync(@NotNull Location destination);
++ java.util.concurrent.CompletableFuture teleportOfflineAsync(Location destination);
+
+ /**
+ * Sets OfflinePlayer's location. If player is online, it falls back to the Player#teleportAsync implementation.
@@ -103,7 +102,6 @@
+ * @param cause Teleport cause used if player is online
+ * @return true if teleportation successful
+ */
-+ @NotNull
-+ public java.util.concurrent.CompletableFuture teleportOfflineAsync(@NotNull Location destination, @NotNull org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause);
++ java.util.concurrent.CompletableFuture teleportOfflineAsync(Location destination, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause);
+ // Purpur end - OfflinePlayer API
}
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch
index b149d0c27..80e794576 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
-@@ -2654,4 +_,111 @@
+@@ -2761,4 +_,125 @@
*/
void allowPausing(@NotNull org.bukkit.plugin.Plugin plugin, boolean value);
// Paper end - API to check if the server is sleeping
@@ -47,7 +47,9 @@
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration);
+
+ /**
@@ -57,7 +59,9 @@
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, int argb);
+
+ /**
@@ -67,7 +71,9 @@
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text);
+
+ /**
@@ -78,7 +84,9 @@
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb);
+
+ /**
@@ -90,7 +98,9 @@
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency);
+
+ /**
@@ -103,12 +113,16 @@
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency);
+
+ /**
+ * Clears all debug block highlights for all players on the server.
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void clearBlockHighlights();
+ // Purpur end - Debug Marker API
}
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch
index eaa0ae079..1233b1a23 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
-@@ -4253,6 +_,86 @@
+@@ -4497,6 +_,100 @@
@Nullable
public DragonBattle getEnderDragonBattle();
@@ -19,7 +19,9 @@
+ * Clients may be inconsistent in displaying it.
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration);
+
+ /**
@@ -29,7 +31,9 @@
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, int argb);
+
+ /**
@@ -39,7 +43,9 @@
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text);
+
+ /**
@@ -50,7 +56,9 @@
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb);
+
+ /**
@@ -62,7 +70,9 @@
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency);
+
+ /**
@@ -75,12 +85,16 @@
+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency);
+
+ /**
+ * Clears all debug block highlights for all players on this world.
++ * @deprecated until further notice. NOOP since 1.21.10
+ */
++ @Deprecated
+ void clearBlockHighlights();
+ // Purpur end
+
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch
index 83f75df21..979407b0c 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java
+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java
-@@ -153,6 +_,19 @@
+@@ -148,6 +_,19 @@
return false;
}
@@ -20,7 +20,7 @@
// Paper start - Plugins do weird things to workaround normal registration
if (target.timings == null) {
target.timings = co.aikar.timings.TimingsManager.getCommandTiming(null, target);
-@@ -160,10 +_,10 @@
+@@ -155,10 +_,10 @@
// Paper end
try {
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch
index b424f2eb9..1f09b0518 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java
-@@ -215,7 +_,7 @@
+@@ -214,7 +_,7 @@
String version = Bukkit.getVersion();
// Paper start
if (version.startsWith("null")) { // running from ide?
@@ -9,7 +9,7 @@
return;
}
setVersionMessage(getVersionFetcher().getVersionMessage(version));
-@@ -256,9 +_,11 @@
+@@ -255,9 +_,11 @@
// Paper start
private void setVersionMessage(final @NotNull Component msg) {
lastCheck = System.currentTimeMillis();
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java.patch
index 45b679507..23ee8f4b5 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java.patch
@@ -1,8 +1,8 @@
--- a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java
+++ b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java
-@@ -227,6 +_,30 @@
+@@ -169,6 +_,30 @@
public boolean includes(@NotNull Material item) {
- return BREAKABLE.includes(item) || (WEARABLE.includes(item) && !item.equals(Material.ELYTRA)) || item.equals(Material.COMPASS);
+ return Tag.ITEMS_ENCHANTABLE_VANISHING.isTagged(item);
}
+ // Purpur start - Add enchantment target for bows and crossbows
+ },
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/CopperGolem.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/CopperGolem.java.patch
new file mode 100644
index 000000000..31f8abbab
--- /dev/null
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/CopperGolem.java.patch
@@ -0,0 +1,25 @@
+--- a/src/main/java/org/bukkit/entity/CopperGolem.java
++++ b/src/main/java/org/bukkit/entity/CopperGolem.java
+@@ -39,6 +_,22 @@
+ */
+ void setOxidizing(Oxidizing oxidizing);
+
++ // Purpur start
++ /**
++ * Get the player that summoned this iron golem
++ *
++ * @return UUID of summoner
++ */
++ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner();
++
++ /**
++ * Set the player that summoned this iron golem
++ *
++ * @param summoner UUID of summoner
++ */
++ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner);
++ // Purpur end
++
+ /**
+ * Represents the oxidizing state of a copper golem.
+ *
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Endermite.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Endermite.java.patch
index 218b3659e..b2f7a4584 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Endermite.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Endermite.java.patch
@@ -13,7 +13,7 @@
* @return player spawned status
- * @deprecated this functionality no longer exists
*/
-- @Deprecated(since = "1.17")
+- @Deprecated(since = "1.17", forRemoval = true)
boolean isPlayerSpawned();
/**
@@ -26,7 +26,7 @@
* @param playerSpawned player spawned status
- * @deprecated this functionality no longer exists
*/
-- @Deprecated(since = "1.17")
+- @Deprecated(since = "1.17", forRemoval = true)
void setPlayerSpawned(boolean playerSpawned);
// Paper start
/**
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch
index 2ee29df0c..72cd7af9e 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/entity/Entity.java
+++ b/src/main/java/org/bukkit/entity/Entity.java
-@@ -1196,4 +_,59 @@
+@@ -1322,4 +_,59 @@
*/
void broadcastHurtAnimation(@NotNull java.util.Collection players);
// Paper end - broadcast hurt animation
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/LivingEntity.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/LivingEntity.java.patch
index 2ec452396..092e2189b 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/LivingEntity.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/LivingEntity.java.patch
@@ -1,9 +1,9 @@
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
-@@ -1468,4 +_,20 @@
+@@ -1494,4 +_,20 @@
*/
- boolean canUseEquipmentSlot(org.bukkit.inventory.@NotNull EquipmentSlot slot);
- // Paper end - Expose canUseSlot
+ @ApiStatus.Experimental
+ @NotNull CombatTracker getCombatTracker();
+
+ // Purpur start - API for any mob to burn daylight
+ /**
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch
index efdb19897..95b49e83f 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch
@@ -1,9 +1,9 @@
--- a/src/main/java/org/bukkit/entity/Player.java
+++ b/src/main/java/org/bukkit/entity/Player.java
-@@ -3928,4 +_,123 @@
- * @return the result of this method, holding leftovers and spawned items.
+@@ -4004,4 +_,123 @@
*/
- @NotNull PlayerGiveResult give(@NotNull Collection<@NotNull ItemStack> items, boolean dropIfFull);
+ @ApiStatus.Experimental
+ PlayerGameConnection getConnection();
+
+ // Purpur start
+ /**
@@ -11,7 +11,7 @@
+ *
+ * @return true if player uses PurpurClient
+ */
-+ public boolean usesPurpurClient();
++ boolean usesPurpurClient();
+
+ /**
+ * Check if player is AFK
@@ -40,7 +40,7 @@
+ * @param location Location to highlight
+ * @param duration Duration for highlight to show in milliseconds
+ */
-+ void sendBlockHighlight(@NotNull Location location, int duration);
++ void sendBlockHighlight(Location location, int duration);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
@@ -50,7 +50,7 @@
+ * @param duration Duration for highlight to show in milliseconds
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ */
-+ void sendBlockHighlight(@NotNull Location location, int duration, int argb);
++ void sendBlockHighlight(Location location, int duration, int argb);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
@@ -60,7 +60,7 @@
+ * @param duration Duration for highlight to show in milliseconds
+ * @param text Text to show above the highlight
+ */
-+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text);
++ void sendBlockHighlight(Location location, int duration, String text);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
@@ -71,7 +71,7 @@
+ * @param text Text to show above the highlight
+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client
+ */
-+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb);
++ void sendBlockHighlight(Location location, int duration, String text, int argb);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
@@ -83,7 +83,7 @@
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ */
-+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency);
++ void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency);
+
+ /**
+ * Creates debug block highlight on specified block location and show it to this player.
@@ -96,7 +96,7 @@
+ * @param transparency Transparency of the highlight
+ * @throws IllegalArgumentException If transparency is outside 0-255 range
+ */
-+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency);
++ void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency);
+
+ /**
+ * Clears all debug block highlights
@@ -108,7 +108,7 @@
+ *
+ * @param message The death message to show the player
+ */
-+ void sendDeathScreen(@NotNull net.kyori.adventure.text.Component message);
++ void sendDeathScreen(net.kyori.adventure.text.Component message);
+
+ /**
+ * Sends a player the death screen with a specified death message,
@@ -119,7 +119,7 @@
+ * @deprecated Use {@link #sendDeathScreen(net.kyori.adventure.text.Component)} instead, as 1.20 removed the killer ID from the packet.
+ */
+ @Deprecated(since = "1.20")
-+ default void sendDeathScreen(@NotNull net.kyori.adventure.text.Component message, @Nullable Entity killer) {
++ default void sendDeathScreen(net.kyori.adventure.text.Component message, @Nullable Entity killer) {
+ sendDeathScreen(message);
+ }
+ // Purpur end
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Villager.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Villager.java.patch
index 90aac0f52..446119a47 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Villager.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Villager.java.patch
@@ -1,12 +1,11 @@
--- a/src/main/java/org/bukkit/entity/Villager.java
+++ b/src/main/java/org/bukkit/entity/Villager.java
-@@ -367,4 +_,14 @@
+@@ -406,4 +_,13 @@
+ * Demand is still updated even if all events are canceled.
*/
- public void clearReputations();
- // Paper end
+ public void restock();
+
+ // Purpur start
-+
+ /**
+ * Check if villager is currently lobotomized
+ *
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wither.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wither.java.patch
index 1080c3d6d..e2f1daf25 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wither.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wither.java.patch
@@ -1,9 +1,9 @@
--- a/src/main/java/org/bukkit/entity/Wither.java
+++ b/src/main/java/org/bukkit/entity/Wither.java
-@@ -107,4 +_,20 @@
+@@ -105,4 +_,20 @@
+ * This is called in vanilla directly after spawning the wither.
*/
void enterInvulnerabilityPhase();
- // Paper end
+
+ // Purpur start
+ /**
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wolf.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wolf.java.patch
index f3ac2ef4a..201466d6b 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wolf.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wolf.java.patch
@@ -1,7 +1,7 @@
--- a/src/main/java/org/bukkit/entity/Wolf.java
+++ b/src/main/java/org/bukkit/entity/Wolf.java
-@@ -110,4 +_,20 @@
- return RegistryAccess.registryAccess().getRegistry(RegistryKey.WOLF_VARIANT).getOrThrow(NamespacedKey.minecraft(key));
+@@ -162,4 +_,20 @@
+ return RegistryAccess.registryAccess().getRegistry(RegistryKey.WOLF_SOUND_VARIANT).getOrThrow(NamespacedKey.minecraft(key));
}
}
+
@@ -11,13 +11,13 @@
+ *
+ * @return whether the wolf is rabid
+ */
-+ public boolean isRabid();
++ boolean isRabid();
+
+ /**
+ * Sets this wolf to be rabid or not
+ *
+ * @param rabid whether the wolf should be rabid
+ */
-+ public void setRabid(boolean rabid);
++ void setRabid(boolean rabid);
+ // Purpur end
}
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java.patch
index 0d86a78ae..9796956cd 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java
+++ b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java
-@@ -308,7 +_,8 @@
+@@ -310,7 +_,8 @@
WORLD_BORDER,
/**
* Damage caused when an entity contacts a block such as a Cactus,
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java.patch
index 24085dc5d..2676d9629 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java
+++ b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java
-@@ -216,6 +_,12 @@
+@@ -218,6 +_,12 @@
* When all effects are removed due to a bucket of milk.
*/
MILK,
@@ -11,5 +11,5 @@
+ NETHERITE_ARMOR,
+ // Purpur end
/**
- * When a player gets bad omen after killing a patrol captain.
- *
+ * When the entity gets the effect from a nautilus.
+ */
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryType.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryType.java.patch
index ec2e9aabe..77457e035 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryType.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryType.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java
+++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java
-@@ -164,7 +_,7 @@
+@@ -170,7 +_,7 @@
SMITHING_NEW(4, "Upgrade Gear", MenuType.SMITHING),
;
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/ItemStack.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/ItemStack.java.patch
index 02c8dfc89..f1144543b 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/ItemStack.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/ItemStack.java.patch
@@ -1,7 +1,7 @@
--- a/src/main/java/org/bukkit/inventory/ItemStack.java
+++ b/src/main/java/org/bukkit/inventory/ItemStack.java
-@@ -21,6 +_,13 @@
- import org.bukkit.material.MaterialData;
+@@ -24,6 +_,13 @@
+ import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+// Purpur start - ItemStack convenience methods
@@ -14,7 +14,7 @@
/**
* Represents a stack of items.
-@@ -1329,4 +_,482 @@
+@@ -1373,4 +_,482 @@
return this.craftDelegate.matchesWithoutData(item, excludeTypes, ignoreCount);
}
// Paper end - data component API
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch
index d4cb6a9fd..c0117bc6c 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch
@@ -1,6 +1,6 @@
--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
-@@ -55,6 +_,7 @@
+@@ -53,6 +_,7 @@
private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")};
private final List loaders = new CopyOnWriteArrayList();
private final LibraryLoader libraryLoader;
diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/LibraryLoader.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/LibraryLoader.java.patch
index f8702315d..29f7d6f64 100644
--- a/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/LibraryLoader.java.patch
+++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/LibraryLoader.java.patch
@@ -1,26 +1,26 @@
--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java
+++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java
-@@ -68,6 +_,7 @@
+@@ -69,6 +_,7 @@
+ session.setTransferListener(new AbstractTransferListener() {
@Override
- public void transferStarted(@NotNull TransferEvent event) throws TransferCancelledException
- {
+ public void transferStarted(@NotNull TransferEvent event) {
+ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - Add log suppression for LibraryLoader
- logger.log( Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName() );
+ logger.log(Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
}
- } );
+ });
@@ -94,6 +_,7 @@
- {
+ // Paper end - plugin loader api
return null;
}
+ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - Add log suppression for LibraryLoader
- logger.log( Level.INFO, "[{0}] Loading {1} libraries... please wait", new Object[]
- {
- java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), desc.getLibraries().size() // Paper - use configured log prefix
-@@ -144,6 +_,7 @@
+ logger.log(Level.INFO, "[{0}] Loading {1} libraries... please wait", new Object[]
+ {
+ java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), desc.getLibraries().size() // Paper - use configured log prefix
+@@ -146,6 +_,7 @@
}
- jarFiles.add( url );
+ jarFiles.add(url);
+ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - Add log suppression for LibraryLoader
- logger.log( Level.INFO, "[{0}] Loaded library {1}", new Object[]
- {
- java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), file // Paper - use configured log prefix
+ logger.log(Level.INFO, "[{0}] Loaded library {1}", new Object[]
+ {
+ java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), file // Paper - use configured log prefix
diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java
deleted file mode 100644
index daf3bbf83..000000000
--- a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package org.purpurmc.purpur.event.entity;
-
-import org.bukkit.entity.Entity;
-import org.bukkit.event.HandlerList;
-import org.bukkit.event.entity.EntityEvent;
-import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
-import org.jetbrains.annotations.ApiStatus;
-import org.jspecify.annotations.NullMarked;
-import org.jspecify.annotations.Nullable;
-
-/**
- * Fired when an entity is hindered from teleporting.
- */
-@NullMarked
-public class EntityTeleportHinderedEvent extends EntityEvent {
- private static final HandlerList handlers = new HandlerList();
-
- private final Reason reason;
-
- private final @Nullable TeleportCause teleportCause;
-
- private boolean retry = false;
-
- @ApiStatus.Internal
- public EntityTeleportHinderedEvent(Entity what, Reason reason, @Nullable TeleportCause teleportCause) {
- super(what);
- this.reason = reason;
- this.teleportCause = teleportCause;
- }
-
- /**
- * @return why the teleport was hindered.
- */
- public Reason getReason() {
- return reason;
- }
-
- /**
- * @return why the teleport occurred if cause was given, otherwise {@code null}.
- */
- @Nullable
- public TeleportCause getTeleportCause() {
- return teleportCause;
- }
-
- /**
- * Whether the teleport should be retried.
- *
- * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack
- * overflow. Do not retry more than necessary.
- *
- *
- * @return whether the teleport should be retried.
- */
- public boolean shouldRetry() {
- return retry;
- }
-
- /**
- * Sets whether the teleport should be retried.
- *
- * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack
- * overflow. Do not retry more than necessary.
- *
- *
- * @param retry whether the teleport should be retried.
- */
- public void setShouldRetry(boolean retry) {
- this.retry = retry;
- }
-
- /**
- * Calls the event and tests if should retry.
- *
- * @return whether the teleport should be retried.
- */
- @Override
- public boolean callEvent() {
- super.callEvent();
- return shouldRetry();
- }
-
- @Override
- public HandlerList getHandlers() {
- return handlers;
- }
-
- public static HandlerList getHandlerList() {
- return handlers;
- }
-
- /**
- * Reason for hindrance in teleports.
- */
- public enum Reason {
- /**
- * The teleported entity is a passenger of another entity.
- */
- IS_PASSENGER,
-
- /**
- * The teleported entity has passengers.
- */
- IS_VEHICLE,
-
- /**
- * The teleport event was cancelled.
- *
- * This is only caused by players teleporting.
- *
- */
- EVENT_CANCELLED,
- }
-}
diff --git a/purpur-server/build.gradle.kts.patch b/purpur-server/build.gradle.kts.patch
index 59cc82d61..a90912979 100644
--- a/purpur-server/build.gradle.kts.patch
+++ b/purpur-server/build.gradle.kts.patch
@@ -1,9 +1,18 @@
--- a/paper-server/build.gradle.kts
+++ b/paper-server/build.gradle.kts
-@@ -21,6 +_,16 @@
- // macheOldPath = file("F:\\Projects\\PaperTooling\\mache\\versions\\1.21.4\\src\\main\\java")
- // gitFilePatches = true
+@@ -2,6 +_,7 @@
+ import io.papermc.paperweight.attribute.DevBundleOutput
+ import io.papermc.paperweight.util.*
+ import java.time.Instant
++import kotlin.io.path.writeText
+ plugins {
+ `java-library`
+@@ -22,6 +_,18 @@
+ minecraftVersion = providers.gradleProperty("mcVersion")
+ gitFilePatches = false
+
++ // Purpur start - Rebrand
+ val purpur = forks.register("purpur") {
+ upstream.patchDir("paperServer") {
+ upstreamPath = "paper-server"
@@ -13,15 +22,17 @@
+ }
+ }
+ activeFork = purpur
++ // Purpur end - Rebrand
+
spigot {
- buildDataRef = "3edaf46ec1eed4115ce1b18d2846cded42577e42"
- packageVersion = "v1_21_R3" // also needs to be updated in MappingEnvironment
-@@ -101,7 +_,20 @@
+ enabled = false
+ buildDataRef = "42d18d4c4653ffc549778dbe223f6994a031d69e"
+@@ -104,7 +_,21 @@
}
}
-val log4jPlugins = sourceSets.create("log4jPlugins")
++// Purpur start - Rebrand
+sourceSets {
+ main {
+ java { srcDir("../paper-server/src/main/java") }
@@ -32,34 +43,34 @@
+ resources { srcDir("../paper-server/src/test/resources") }
+ }
+}
-+
+val log4jPlugins = sourceSets.create("log4jPlugins") {
+ java { srcDir("../paper-server/src/log4jPlugins/java") }
+}
++// Purpur end - Rebrand
configurations.named(log4jPlugins.compileClasspathConfigurationName) {
extendsFrom(configurations.compileClasspath.get())
}
-@@ -119,7 +_,7 @@
+@@ -127,7 +_,7 @@
}
dependencies {
- implementation(project(":paper-api"))
-+ implementation(project(":purpur-api"))
- implementation("ca.spottedleaf:concurrentutil:0.0.3")
++ implementation(project(":purpur-api")) // Purpur
+ implementation("ca.spottedleaf:concurrentutil:0.0.7")
implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21
-@@ -149,6 +_,10 @@
- runtimeOnly("com.mysql:mysql-connector-j:9.1.0")
- runtimeOnly("com.lmax:disruptor:3.4.4")
+@@ -153,6 +_,10 @@
+ implementation("org.ow2.asm:asm-commons:9.8")
+ implementation("org.spongepowered:configurate-yaml:4.2.0")
+ implementation("org.mozilla:rhino-runtime:1.7.14") // Purpur
+ implementation("org.mozilla:rhino-engine:1.7.14") // Purpur
+ implementation("dev.omega24:upnp4j:1.0") // Purpur
+
- runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6")
- runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
- runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18")
-@@ -188,14 +_,14 @@
+ // Deps that were previously in the API but have now been moved here for backwards compat, eventually to be removed
+ runtimeOnly("commons-lang:commons-lang:2.6")
+ runtimeOnly("org.xerial:sqlite-jdbc:3.49.1.0")
+@@ -198,14 +_,14 @@
val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim()
attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main",
@@ -79,3 +90,67 @@
"Build-Number" to (build ?: ""),
"Build-Time" to buildTime.toString(),
"Git-Branch" to gitBranch,
+@@ -264,7 +_,7 @@
+ jvmArgumentProviders.add(provider)
+ }
+
+-val generatedDir: java.nio.file.Path = layout.projectDirectory.dir("src/generated/java").asFile.toPath()
++val generatedDir: java.nio.file.Path = layout.projectDirectory.dir("../paper-server/src/generated/java").asFile.toPath() // Purpur
+ idea {
+ module {
+ generatedSourceDirs.add(generatedDir.toFile())
+@@ -356,7 +_,7 @@
+ mainClass.set(null as String?)
+ }
+
+-fill {
++/* fill { // Purpur - we don't use fill
+ project("paper")
+ versionFamily(paperweight.minecraftVersion.map { it.split(".", "-").takeWhile { part -> part.toIntOrNull() != null }.take(2).joinToString(".") })
+ version(paperweight.minecraftVersion)
+@@ -371,4 +_,44 @@
+ }
+ }
+ }
+-}
++} */ // Purpur - we don't use fill
++
++// tasks.register("rebuildMinecraftSourcesWithGit") {
++// group = "temp"
++//
++// val patchDir = project.rootDir.resolve("purpur-server/minecraft-patches/sources").convertToPath().cleanDir()
++// val inputDir = this.project.rootDir.resolve("purpur-server/src/minecraft/java").convertToPath()
++//
++// val git = Git(inputDir)
++// git("stash", "push").executeSilently(silenceErr = true)
++// git("checkout", "file").executeSilently(silenceErr = true)
++//
++// rebuildWithGit(git, patchDir)
++// }
++//
++// private fun rebuildWithGit(
++// git: Git,
++// patchDir: java.nio.file.Path
++// ): Int {
++// val files = git("diff-tree", "--name-only", "--no-commit-id", "-r", "HEAD").getText().split("\n")
++// files.parallelStream().forEach { filename ->
++// if (filename.isBlank()) return@forEach
++// val patch = git(
++// "format-patch",
++// "--diff-algorithm=myers",
++// "--full-index",
++// "--no-signature",
++// "--no-stat",
++// "--no-numbered",
++// "-1",
++// "HEAD",
++// "--stdout",
++// filename
++// ).getText()
++// val patchFile = patchDir.resolve("$filename.patch")
++// patchFile.createParentDirectories()
++// patchFile.writeText(patch)
++// }
++//
++// return files.size
++// }
diff --git a/purpur-server/minecraft-patches/features/0001-Ridables.patch b/purpur-server/minecraft-patches/features/0001-Ridables.patch
index f6921b145..be3daf702 100644
--- a/purpur-server/minecraft-patches/features/0001-Ridables.patch
+++ b/purpur-server/minecraft-patches/features/0001-Ridables.patch
@@ -5,50 +5,50 @@ Subject: [PATCH] Ridables
diff --git a/net/minecraft/gametest/framework/GameTestHelper.java b/net/minecraft/gametest/framework/GameTestHelper.java
-index 29d402620d2e1cbed94f941f933ae8eb5d786e7f..ec0998369158286fccb38c8e10c3cfa2a653a8aa 100644
+index 05eb0c3273ffa1b5a1ebd8f8ae42c11830d755c7..49d3154afe2ca5789e63bdf972c791969405c16d 100644
--- a/net/minecraft/gametest/framework/GameTestHelper.java
+++ b/net/minecraft/gametest/framework/GameTestHelper.java
-@@ -281,6 +281,8 @@ public class GameTestHelper {
+@@ -324,6 +324,8 @@ public class GameTestHelper {
public void setAfk(final boolean afk) {} // Purpur - AFK API
+ public void resetLastActionTime() {} // Purpur - Ridables
+
@Override
- public boolean isLocalPlayer() {
- return true;
+ public boolean isClientAuthoritative() {
+ return false;
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
-index 121b57c7f5345f5d8884eaa1d36dac79fb7d42ef..9afbfe9bf493e09ca1963e8956ab7573964479b4 100644
+index c714782f047c211443723738527f4bd019aaa322..cfd9596246713030f7c0f28a65abeed6dcc8d81b 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
-@@ -1745,6 +1745,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - Add EntityMoveEvent
serverLevel.updateLagCompensationTick(); // Paper - lag compensation
net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
+ serverLevel.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - Ridables
- profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location());
+ profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().identifier());
/* Drop global time updates
if (this.tickCount % 20 == 0) {
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
-index 5cf2c7f8fb05a91ed17f1d9c07f7d3e748738058..3770dc90d9412c6378c0bd57a651b9c3e62b9a72 100644
+index c18844ca7c9840f28fe5167d67387ebaf758a9da..c99ba8c3eba14efcf7906fe2b42e4db1c73c90fe 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
-@@ -217,6 +217,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
+@@ -230,6 +230,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current)
+ public boolean hasRidableMoveEvent = false; // Purpur - Ridables
- public LevelChunk getChunkIfLoaded(int x, int z) {
- return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
+ @Override
+ public @Nullable LevelChunk getChunkIfLoaded(int x, int z) {
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
-index a6f771cbee878eb383b67c61fa2469f2916413b5..d77381237f8a7d1b2f280a5032f5e1c8f0ab8f94 100644
+index 9ec896ad8e95d7822095c42054e76e7a5db91481..2eba1b0ac8b4a0bb34d04b81c4c279db6e716b3b 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
-@@ -848,6 +848,15 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
+@@ -772,6 +772,15 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.trackEnteredOrExitedLavaOnVehicle();
this.updatePlayerAttributes();
- this.advancements.flushDirty(this);
+ this.advancements.flushDirty(this, true);
+
+ // Purpur start - Ridables
+ if (this.level().purpurConfig.useNightVisionWhenRiding && this.getVehicle() != null && this.getVehicle().getRider() == this && this.level().getGameTime() % 100 == 0) { // 5 seconds
@@ -62,37 +62,37 @@ index a6f771cbee878eb383b67c61fa2469f2916413b5..d77381237f8a7d1b2f280a5032f5e1c8
private void updatePlayerAttributes() {
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index d681e14d33a8de6ca2c7f0a2e1ff9bb9d55adbbb..ee002c2cef9d4810fdacac71de77e948f5b0e89d 100644
+index cd7ecd971b5a0ffdf6cabeaa874f2a221431052e..e587414dd1250b14a0fecf8d1b25dd70b20816eb 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -2835,6 +2835,8 @@ public class ServerGamePacketListenerImpl
-
+@@ -2895,6 +2895,8 @@ public class ServerGamePacketListenerImpl
ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event);
+ final boolean resendData = event.isCancelled() || !ServerGamePacketListenerImpl.this.player.getItemInHand(hand).is(itemType);
+ player.processClick(hand); // Purpur - Ridables
+
- // Entity in bucket - SPIGOT-4048 and SPIGOT-6859a
- if ((target instanceof Bucketable && target instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) {
+ // Entity in bucket - SPIGOT-4048 and SPIGOT-6859
+ if (itemType == Items.WATER_BUCKET && target instanceof net.minecraft.world.entity.animal.Bucketable && target instanceof LivingEntity && resendData) {
target.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
-index 43a4427a8f327fbb224cb25e63a5c6b244eb9b09..62a38ecedbd579b32a8fd9cff5a433bfe635fc62 100644
+index c133b6796c0251500801b2e41df9ae4b38d111a1..468df93a0302f200c2bd5e9bc65feccdd8649bf3 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
-@@ -3151,6 +3151,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+@@ -3371,6 +3371,13 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
+
this.passengers = ImmutableList.copyOf(list);
}
-
++
+ // Purpur start - Ridables
+ if (isRidable() && this.passengers.get(0) == passenger && passenger instanceof Player player) {
+ onMount(player);
+ this.rider = player;
+ }
+ // Purpur end - Ridables
-+
- this.gameEvent(GameEvent.ENTITY_MOUNT, passenger);
}
}
-@@ -3192,6 +3199,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+
+@@ -3411,6 +3418,14 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
return false;
}
// CraftBukkit end
@@ -107,8 +107,8 @@ index 43a4427a8f327fbb224cb25e63a5c6b244eb9b09..62a38ecedbd579b32a8fd9cff5a433bf
if (this.passengers.size() == 1 && this.passengers.get(0) == passenger) {
this.passengers = ImmutableList.of();
} else {
-@@ -5115,4 +5130,44 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
- return ((ServerLevel) this.level).isPositionEntityTicking(this.blockPosition());
+@@ -5462,4 +5477,44 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
+ return ((ServerLevel) this.level()).isPositionEntityTicking(this.blockPosition());
}
// Paper end - Expose entity id counter
+ // Purpur start - Ridables
@@ -130,7 +130,7 @@ index 43a4427a8f327fbb224cb25e63a5c6b244eb9b09..62a38ecedbd579b32a8fd9cff5a433bf
+
+ public void onMount(Player rider) {
+ if (this instanceof Mob) {
-+ ((Mob) this).setTarget(null, null, false);
++ ((Mob) this).setTarget(null, null);
+ ((Mob) this).getNavigation().stop();
+ }
+ rider.setJumping(false); // fixes jump on mount
@@ -152,36 +152,12 @@ index 43a4427a8f327fbb224cb25e63a5c6b244eb9b09..62a38ecedbd579b32a8fd9cff5a433bf
+ }
+ // Purpur end - Ridables
}
-diff --git a/net/minecraft/world/entity/GlowSquid.java b/net/minecraft/world/entity/GlowSquid.java
-index 95d78dcdb6777df73898694367ee17b1cb76d7a2..d0313fd5368baa53ec511c8c07fc78a1f1ecec4e 100644
---- a/net/minecraft/world/entity/GlowSquid.java
-+++ b/net/minecraft/world/entity/GlowSquid.java
-@@ -32,6 +32,19 @@ public class GlowSquid extends Squid {
- }
- // Purpur end - Flying squids! Oh my!
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.glowSquidRidable;
-+ }
-+
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.glowSquidControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected ParticleOptions getInkParticle() {
- return ParticleTypes.GLOW_SQUID_INK;
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
-index f41d5ffe83e3cfb4c30d150f8b66f8f2568ae20c..8c2bdb1775f7c4110c5f967b1052eba6a8fcbbfa 100644
+index aeadca3aa7baf337aff8c8e24bf557f6a9db322a..6e0a2741db06f93f31349515d1d13181b70e08ed 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
-@@ -250,9 +250,9 @@ public abstract class LivingEntity extends Entity implements Attackable {
- protected float rotOffs;
+@@ -244,9 +244,9 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ protected int noActionTime;
public float lastHurt;
public boolean jumping;
- public float xxa;
@@ -190,27 +166,48 @@ index f41d5ffe83e3cfb4c30d150f8b66f8f2568ae20c..8c2bdb1775f7c4110c5f967b1052eba6
+ public float xxa; public float getStrafeMot() { return xxa; } public void setStrafeMot(float strafe) { xxa = strafe; } // Purpur - OBFHELPER
+ public float yya; public float getVerticalMot() { return yya; } public void setVerticalMot(float vertical) { yya = vertical; } // Purpur - OBFHELPER
+ public float zza; public float getForwardMot() { return zza; } public void setForwardMot(float forward) { zza = forward; } // Purpur - OBFHELPER
- protected int lerpSteps;
- protected double lerpX;
- protected double lerpY;
-@@ -310,7 +310,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
+ protected InterpolationHandler interpolation = new InterpolationHandler(this);
+ protected double lerpYHeadRot;
+ protected int lerpHeadSteps;
+@@ -294,7 +294,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
- protected LivingEntity(EntityType extends LivingEntity> entityType, Level level) {
- super(entityType, level);
-- this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entityType));
-+ this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entityType), this); // Purpur - Ridables
- this.craftAttributes = new CraftAttributeMap(this.attributes); // CraftBukkit
+ protected LivingEntity(EntityType extends LivingEntity> type, Level level) {
+ super(type, level);
+- this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type));
++ this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type), this); // Purpur - Ridables
+ this.craftAttributes = new org.bukkit.craftbukkit.attribute.CraftAttributeMap(this.attributes); // CraftBukkit
// CraftBukkit - this.setHealth(this.getMaxHealth()) inlined and simplified to skip the instanceof check for Player, as getBukkitEntity() is not initialized in constructor
this.entityData.set(LivingEntity.DATA_HEALTH_ID, this.getMaxHealth());
-@@ -377,6 +377,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
- .add(Attributes.MOVEMENT_EFFICIENCY)
- .add(Attributes.ATTACK_KNOCKBACK);
+@@ -371,6 +371,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ .add(Attributes.CAMERA_DISTANCE)
+ .add(Attributes.WAYPOINT_TRANSMIT_RANGE);
}
+ public boolean shouldSendAttribute(Attribute attribute) { return true; } // Purpur - Ridables
@Override
protected void checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos) {
-@@ -3537,8 +3538,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
+@@ -3111,6 +3112,20 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ this.move(MoverType.SELF, this.getDeltaMovement());
+ this.setDeltaMovement(this.getDeltaMovement().scale(0.5));
+ } else {
++ // Purpur start - Ridables
++ if (this.getRider() != null && this.isControllable()) {
++ float friction = 0.91F;
++ if (this.onGround()) {
++ friction = this.level().getBlockState(this.getBlockPosBelowThatAffectsMyMovement()).getBlock().getFriction() * 0.91F;
++ }
++
++ float frictionCompensation = 0.16277137F / (friction * friction * friction);
++ this.moveRelative(this.onGround() ? 0.1F * frictionCompensation : 0.02F, relative);
++ this.move(MoverType.SELF, this.getDeltaMovement());
++ this.setDeltaMovement(this.getDeltaMovement().scale(friction));
++ return;
++ }
++ // Purpur end - Ridables
+ this.moveRelative(amount, relative);
+ this.move(MoverType.SELF, this.getDeltaMovement());
+ this.setDeltaMovement(this.getDeltaMovement().scale(0.91F));
+@@ -3799,8 +3814,10 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
this.pushEntities();
profilerFiller.pop();
// Paper start - Add EntityMoveEvent
@@ -223,8 +220,8 @@ index f41d5ffe83e3cfb4c30d150f8b66f8f2568ae20c..8c2bdb1775f7c4110c5f967b1052eba6
Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO);
Location to = new Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
io.papermc.paper.event.entity.EntityMoveEvent event = new io.papermc.paper.event.entity.EntityMoveEvent(this.getBukkitLivingEntity(), from, to.clone());
-@@ -3548,6 +3551,21 @@ public abstract class LivingEntity extends Entity implements Attackable {
- this.absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch());
+@@ -3810,6 +3827,21 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ this.absSnapTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch());
}
}
+ // Purpur start - Ridables
@@ -235,22 +232,22 @@ index f41d5ffe83e3cfb4c30d150f8b66f8f2568ae20c..8c2bdb1775f7c4110c5f967b1052eba6
+ Location to = new Location(level().getWorld(), getX(), getY(), getZ(), this.getYRot(), this.getXRot());
+ org.purpurmc.purpur.event.entity.RidableMoveEvent event = new org.purpurmc.purpur.event.entity.RidableMoveEvent((org.bukkit.entity.Mob) getBukkitLivingEntity(), (org.bukkit.entity.Player) getRider().getBukkitEntity(), from, to.clone());
+ if (!event.callEvent()) {
-+ absMoveTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch());
++ this.absSnapTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch());
+ } else if (!to.equals(event.getTo())) {
-+ absMoveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch());
++ this.absSnapTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch());
+ }
+ }
+ }
+ // Purpur end - Ridables
}
// Paper end - Add EntityMoveEvent
- if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) {
+ if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterOrRain()) {
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
-index 26f7cd5ddacf5f908702adbf55b56dcc6fcbe162..c431f28c3f4f6cec946048f5752c364429af5ba1 100644
+index dd0f83b9355271f7aab15eb49833f518e499595e..c519f3f501963bde3f1cadf24f88edd2a043215d 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
-@@ -151,8 +151,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
- super(entityType, level);
+@@ -156,8 +156,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
+ super(type, level);
this.goalSelector = new GoalSelector();
this.targetSelector = new GoalSelector();
- this.lookControl = new LookControl(this);
@@ -260,7 +257,15 @@ index 26f7cd5ddacf5f908702adbf55b56dcc6fcbe162..c431f28c3f4f6cec946048f5752c3644
this.jumpControl = new JumpControl(this);
this.bodyRotationControl = this.createBodyControl();
this.navigation = this.createNavigation(level);
-@@ -1405,7 +1405,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
+@@ -594,6 +594,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
+ }
+ }
+ } else {
++ if (getRider() == null || !this.isControllable()) // Purpur - Ridables
+ this.igniteForSeconds(8.0F);
+ }
+ }
+@@ -1357,7 +1358,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
}
protected InteractionResult mobInteract(Player player, InteractionHand hand) {
@@ -268,10 +273,10 @@ index 26f7cd5ddacf5f908702adbf55b56dcc6fcbe162..c431f28c3f4f6cec946048f5752c3644
+ return tryRide(player, hand); // Purpur - Ridables
}
- public boolean isWithinRestriction() {
-@@ -1723,4 +1723,58 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
- public float[] getArmorDropChances() {
- return this.armorDropChances;
+ protected void usePlayerItem(Player player, InteractionHand hand, ItemStack stack) {
+@@ -1697,4 +1698,58 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
+ public float chargeSpeedModifier() {
+ return 1.0F;
}
+
+ // Purpur start - Ridables
@@ -329,10 +334,10 @@ index 26f7cd5ddacf5f908702adbf55b56dcc6fcbe162..c431f28c3f4f6cec946048f5752c3644
+ // Purpur end - Ridables
}
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
-index 4c808c7ef336de74048f40bd1cc8b14131a9325d..a25d74592e89e3d6339479c6dc2b6f45d1932cfc 100644
+index 92b7f4cbd276dad49cba78514db3552af8cdd80c..fd26471047cc5bef28ee9ddba4a8542deef889cc 100644
--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java
+++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
-@@ -23,14 +23,21 @@ public class AttributeMap {
+@@ -18,14 +18,21 @@ public class AttributeMap {
private final Set attributesToSync = new ObjectOpenHashSet<>();
private final Set attributesToUpdate = new ObjectOpenHashSet<>();
private final AttributeSupplier supplier;
@@ -356,7 +361,7 @@ index 4c808c7ef336de74048f40bd1cc8b14131a9325d..a25d74592e89e3d6339479c6dc2b6f45
this.attributesToSync.add(instance);
}
}
-@@ -44,7 +51,7 @@ public class AttributeMap {
+@@ -39,7 +46,7 @@ public class AttributeMap {
}
public Collection getSyncableAttributes() {
@@ -364,14 +369,14 @@ index 4c808c7ef336de74048f40bd1cc8b14131a9325d..a25d74592e89e3d6339479c6dc2b6f45
+ return this.attributes.values().stream().filter(instance -> instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))).collect(Collectors.toList()); // Purpur - Ridables
}
- @Nullable
+ public @Nullable AttributeInstance getInstance(Holder attribute) {
diff --git a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
-index 33527a1825119f3667fb3c7ccec318f2c7328ec9..61ed4d687120fcbb7b91863e400f3657ebcde687 100644
+index 6cf01fe1aac41af171b444ac737816a06bd80d6f..686776bb00560f9da8838bd5f8dd64aaddfa7a2b 100644
--- a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
+++ b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
-@@ -131,7 +131,7 @@ public class DefaultAttributes {
- .put(EntityType.OCELOT, Ocelot.createAttributes().build())
+@@ -142,7 +142,7 @@ public class DefaultAttributes {
.put(EntityType.PANDA, Panda.createAttributes().build())
+ .put(EntityType.PARCHED, Parched.createAttributes().build())
.put(EntityType.PARROT, Parrot.createAttributes().build())
- .put(EntityType.PHANTOM, Monster.createMonsterAttributes().build())
+ .put(EntityType.PHANTOM, net.minecraft.world.entity.monster.Phantom.createAttributes().build()) // Purpur - Ridables
@@ -379,7 +384,7 @@ index 33527a1825119f3667fb3c7ccec318f2c7328ec9..61ed4d687120fcbb7b91863e400f3657
.put(EntityType.PIGLIN, Piglin.createAttributes().build())
.put(EntityType.PIGLIN_BRUTE, PiglinBrute.createAttributes().build())
diff --git a/net/minecraft/world/entity/ai/control/MoveControl.java b/net/minecraft/world/entity/ai/control/MoveControl.java
-index 0f9bf0cb0655a6ed449a86e99b17f89b4e3264df..1860b4ab2314f5da017313977c6423e735a4f96b 100644
+index b7a4b5ad718e8f4ea108f606669d4fcaf5219e6f..0604fca0687e02e75c097ff864b13e2763bfeb76 100644
--- a/net/minecraft/world/entity/ai/control/MoveControl.java
+++ b/net/minecraft/world/entity/ai/control/MoveControl.java
@@ -29,6 +29,20 @@ public class MoveControl implements Control {
@@ -426,15 +431,15 @@ index d7f9b3b2b1077ea10e8f64b87c8f4c4354e90858..713f62b34a91fa76f40e49a5e390145f
this.lookAtCooldown--;
this.getYRotD().ifPresent(rotationWanted -> this.mob.yHeadRot = this.rotateTowards(this.mob.yHeadRot, rotationWanted + 20.0F, this.yMaxRotSpeed));
diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java
-index 4d715a29f1ad31e87977562bd0e2aeddb54ee082..e7ea944e77175ee4051b8e7361c502d0cc2115d5 100644
+index ca68d356e892e0ac8a651ced92aab7dbfd4699b4..2cfcf1f7473d8612777ca0752f6d1521c231ef42 100644
--- a/net/minecraft/world/entity/ambient/Bat.java
+++ b/net/minecraft/world/entity/ambient/Bat.java
@@ -42,11 +42,58 @@ public class Bat extends AmbientCreature {
- public Bat(EntityType extends Bat> entityType, Level level) {
- super(entityType, level);
+ public Bat(EntityType extends Bat> type, Level level) {
+ super(type, level);
+ this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.075F); // Purpur - Ridables
- if (!level.isClientSide) {
+ if (!level.isClientSide()) {
this.setResting(true);
}
}
@@ -488,7 +493,7 @@ index 4d715a29f1ad31e87977562bd0e2aeddb54ee082..e7ea944e77175ee4051b8e7361c502d0
@Override
public boolean isFlapping() {
return !this.isResting() && this.tickCount % 10.0F == 0.0F;
-@@ -98,7 +145,7 @@ public class Bat extends AmbientCreature {
+@@ -97,7 +144,7 @@ public class Bat extends AmbientCreature {
}
public static AttributeSupplier.Builder createAttributes() {
@@ -497,7 +502,7 @@ index 4d715a29f1ad31e87977562bd0e2aeddb54ee082..e7ea944e77175ee4051b8e7361c502d0
}
public boolean isResting() {
-@@ -129,6 +176,14 @@ public class Bat extends AmbientCreature {
+@@ -128,6 +175,14 @@ public class Bat extends AmbientCreature {
@Override
protected void customServerAiStep(ServerLevel level) {
@@ -512,74 +517,183 @@ index 4d715a29f1ad31e87977562bd0e2aeddb54ee082..e7ea944e77175ee4051b8e7361c502d0
super.customServerAiStep(level);
BlockPos blockPos = this.blockPosition();
BlockPos blockPos1 = blockPos.above();
-diff --git a/net/minecraft/world/entity/animal/AbstractFish.java b/net/minecraft/world/entity/animal/AbstractFish.java
-index c0997c8c0f8ee4474d3acdd5938b1879c4e589a2..28ae152125ed83d8917674b6068f227f87890f30 100644
---- a/net/minecraft/world/entity/animal/AbstractFish.java
-+++ b/net/minecraft/world/entity/animal/AbstractFish.java
-@@ -87,6 +87,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
- @Override
- protected void registerGoals() {
- super.registerGoals();
+diff --git a/net/minecraft/world/entity/animal/allay/Allay.java b/net/minecraft/world/entity/animal/allay/Allay.java
+index 0591dc9c39f94768c5ebf74cad7bae98921ff66c..6ab6305f0b25f7c860673c70d9ce911688ecf1e6 100644
+--- a/net/minecraft/world/entity/animal/allay/Allay.java
++++ b/net/minecraft/world/entity/animal/allay/Allay.java
+@@ -113,10 +113,23 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
+ private float spinningAnimationTicks;
+ private float spinningAnimationTicks0;
+ public boolean forceDancing = false; // CraftBukkit
++ private org.purpurmc.purpur.controller.FlyingMoveControllerWASD purpurController; // Purpur - Ridables
+
+ public Allay(EntityType extends Allay> type, Level level) {
+ super(type, level);
+- this.moveControl = new FlyingMoveControl(this, 20, true);
++ // Purpur start - Ridables
++ this.purpurController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.1F, 0.5F);
++ this.moveControl = new FlyingMoveControl(this, 20, true) {
++ @Override
++ public void tick() {
++ if (mob.getRider() != null && mob.isControllable()) {
++ purpurController.purpurTick(mob.getRider());
++ } else {
++ super.tick();
++ }
++ }
++ };
++ // Purpur end - Ridables
+ this.setCanPickUpLoot(this.canPickUpLoot());
+ this.vibrationUser = new Allay.VibrationUser();
+ this.vibrationData = new VibrationSystem.Data();
+@@ -132,6 +145,28 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
+ }
+ // CraftBukkit end
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.allayRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.allayRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.allayControllable;
++ }
++
++ @Override
++ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(0, new PanicGoal(this, 1.25));
- this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6, 1.4, EntitySelector.NO_SPECTATORS::test));
- this.goalSelector.addGoal(4, new AbstractFish.FishSwimGoal(this));
-@@ -100,7 +101,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
++ }
++ // Purpur end - Ridables
++
@Override
- public void travel(Vec3 travelVector) {
- if (this.isControlledByLocalInstance() && this.isInWater()) {
-- this.moveRelative(0.01F, travelVector);
-+ this.moveRelative(getRider() != null ? getSpeed() : 0.01F, travelVector); // Purpur - Ridables
- this.move(MoverType.SELF, this.getDeltaMovement());
- this.setDeltaMovement(this.getDeltaMovement().scale(0.9));
- if (this.getTarget() == null) {
-@@ -160,7 +161,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
- protected void playStepSound(BlockPos pos, BlockState block) {
+ protected Brain.Provider brainProvider() {
+ return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
+@@ -227,6 +262,7 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
+ protected void customServerAiStep(ServerLevel level) {
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("allayBrain");
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
+ this.getBrain().tick(level, this);
+ profilerFiller.pop();
+ profilerFiller.push("allayActivityUpdate");
+diff --git a/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/net/minecraft/world/entity/animal/armadillo/Armadillo.java
+index 901e4e9897e76cd4158d7f8bb8ec829df8ff8196..767a730baa8a7694ed7d5f05b70118da1f4288cc 100644
+--- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java
++++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java
+@@ -82,6 +82,23 @@ public class Armadillo extends Animal {
+ return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 12.0).add(Attributes.MOVEMENT_SPEED, 0.14);
}
-- static class FishMoveControl extends MoveControl {
-+ static class FishMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur - Ridables
- private final AbstractFish fish;
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.armadilloRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.armadilloRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.armadilloControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
+index 2e5291af79a04ff7ebfc533596a008b404571214..3837397563bf3d568c120ae4e4e38d1a6dc7a8b2 100644
+--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java
++++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
+@@ -121,6 +121,23 @@ public class Axolotl extends Animal implements Bucketable {
+ this.lookControl = new Axolotl.AxolotlLookControl(this, 20);
+ }
- FishMoveControl(AbstractFish mob) {
-@@ -168,14 +169,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
- this.fish = mob;
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.axolotlRidable;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.axolotlControllable;
++ }
++
++ @Override
++ protected void registerGoals() {
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
++ }
++ // Purpur end - Ridables
++
+ @Override
+ public float getWalkTargetValue(BlockPos pos, LevelReader level) {
+ return 0.0F;
+@@ -328,6 +345,7 @@ public class Axolotl extends Animal implements Bucketable {
+ protected void customServerAiStep(ServerLevel level) {
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("axolotlBrain");
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
+ this.getBrain().tick(level, this);
+ profilerFiller.pop();
+ profilerFiller.push("axolotlActivityUpdate");
+@@ -564,23 +582,31 @@ public class Axolotl extends Animal implements Bucketable {
}
-+ // Purpur start - Ridables
@Override
- public void tick() {
-+ public void purpurTick(Player rider) {
-+ super.purpurTick(rider);
-+ fish.setDeltaMovement(fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D));
-+ }
-+ // Purpur end - Ridables
-+
-+ @Override
+ public void vanillaTick() { // Purpur - Ridables
- if (this.fish.isEyeInFluid(FluidTags.WATER)) {
- this.fish.setDeltaMovement(this.fish.getDeltaMovement().add(0.0, 0.005, 0.0));
+ if (!Axolotl.this.isPlayingDead()) {
+- super.tick();
++ super.vanillaTick(); // Purpur - Ridables
}
+ }
+ }
- if (this.operation == MoveControl.Operation.MOVE_TO && !this.fish.getNavigation().isDone()) {
-- float f = (float)(this.speedModifier * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED));
-+ float f = (float)(this.getSpeedModifier() * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables
- this.fish.setSpeed(Mth.lerp(0.125F, this.fish.getSpeed(), f));
- double d = this.wantedX - this.fish.getX();
- double d1 = this.wantedY - this.fish.getY();
-diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java
-index 3793570827eb6ca21c6b990d76c679c00ad100f4..af0cf64b4c74d290dec8032f8a6127867e301130 100644
---- a/net/minecraft/world/entity/animal/Bee.java
-+++ b/net/minecraft/world/entity/animal/Bee.java
-@@ -145,6 +145,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+ static class AxolotlMoveControl extends SmoothSwimmingMoveControl {
+ private final Axolotl axolotl;
++ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterController; // Purpur - Ridables
- public Bee(EntityType extends Bee> entityType, Level level) {
- super(entityType, level);
+ public AxolotlMoveControl(Axolotl axolotl) {
+ super(axolotl, 85, 10, 0.1F, 0.5F, false);
+ this.axolotl = axolotl;
++ waterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(axolotl, 0.5D); // Purpur - Ridables
+ }
+
+ @Override
+ public void tick() {
++ // Purpur start - Ridables
++ if (axolotl.getRider() != null && axolotl.isControllable()) {
++ waterController.purpurTick(axolotl.getRider());
++ return;
++ }
++ // Purpur end - Ridables
+ if (!this.axolotl.isPlayingDead()) {
+ super.tick();
+ }
+diff --git a/net/minecraft/world/entity/animal/bee/Bee.java b/net/minecraft/world/entity/animal/bee/Bee.java
+index 7b9280526af353c3ab1f32e5195499e773731352..bd3dc923058b884afcfad08062230182810c65a2 100644
+--- a/net/minecraft/world/entity/animal/bee/Bee.java
++++ b/net/minecraft/world/entity/animal/bee/Bee.java
+@@ -153,6 +153,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+
+ public Bee(EntityType extends Bee> type, Level level) {
+ super(type, level);
+ final org.purpurmc.purpur.controller.FlyingMoveControllerWASD flyingController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.25F, 1.0F, false); // Purpur - Ridables
// Paper start - Fix MC-167279
class BeeFlyingMoveControl extends FlyingMoveControl {
- public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) {
-@@ -153,11 +154,24 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+ public BeeFlyingMoveControl(final Mob mob, final int maxTurn, final boolean hoversInPlace) {
+@@ -161,11 +162,24 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
@Override
public void tick() {
@@ -604,7 +718,7 @@ index 3793570827eb6ca21c6b990d76c679c00ad100f4..af0cf64b4c74d290dec8032f8a612786
}
this.moveControl = new BeeFlyingMoveControl(this, 20, true);
// Paper end - Fix MC-167279
-@@ -169,6 +183,40 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+@@ -177,6 +191,40 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
this.setPathfindingMalus(PathType.FENCE, -1.0F);
}
@@ -645,7 +759,7 @@ index 3793570827eb6ca21c6b990d76c679c00ad100f4..af0cf64b4c74d290dec8032f8a612786
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
-@@ -183,6 +231,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+@@ -191,6 +239,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
@Override
protected void registerGoals() {
@@ -653,15 +767,15 @@ index 3793570827eb6ca21c6b990d76c679c00ad100f4..af0cf64b4c74d290dec8032f8a612786
this.goalSelector.addGoal(0, new Bee.BeeAttackGoal(this, 1.4F, true));
this.goalSelector.addGoal(1, new Bee.BeeEnterHiveGoal());
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0));
-@@ -200,6 +249,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+@@ -208,6 +257,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
this.goalSelector.addGoal(7, new Bee.BeeGrowCropGoal());
this.goalSelector.addGoal(8, new Bee.BeeWanderGoal());
this.goalSelector.addGoal(9, new FloatGoal(this));
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new Bee.BeeHurtByOtherGoal(this).setAlertOthers(new Class[0]));
+ this.targetSelector.addGoal(1, new Bee.BeeHurtByOtherGoal(this).setAlertOthers());
this.targetSelector.addGoal(2, new Bee.BeeBecomeAngryTargetGoal(this));
this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true));
-@@ -1084,15 +1134,15 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+@@ -1085,15 +1135,15 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
}
}
@@ -680,68 +794,29 @@ index 3793570827eb6ca21c6b990d76c679c00ad100f4..af0cf64b4c74d290dec8032f8a612786
}
}
-diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java
-index 618f184ce9fed4d9b01f2df4d9a4476d20a55546..f066b0acfa0e954f6d71e62962c76afa1f05a4a5 100644
---- a/net/minecraft/world/entity/animal/Cat.java
-+++ b/net/minecraft/world/entity/animal/Cat.java
-@@ -93,10 +93,36 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true);
- this.goalSelector.addGoal(1, new FloatGoal(this));
-+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(1, new TamableAnimal.TamableAnimalPanicGoal(1.5));
- this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this));
- this.goalSelector.addGoal(3, new Cat.CatRelaxOnOwnerGoal(this));
-@@ -109,6 +135,7 @@ public class Cat extends TamableAnimal implements VariantHolder(this, Rabbit.class, false, null));
- this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR));
- }
-@@ -360,6 +387,7 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CHICKEN_FOOD), false));
-diff --git a/net/minecraft/world/entity/animal/Cod.java b/net/minecraft/world/entity/animal/Cod.java
-index 708bcc39e7242292d5d5bfcaf599e3738628df9b..6a19086e272363701260801f3c6db9b5c91b8ef5 100644
---- a/net/minecraft/world/entity/animal/Cod.java
-+++ b/net/minecraft/world/entity/animal/Cod.java
-@@ -13,6 +13,18 @@ public class Cod extends AbstractSchoolingFish {
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.codRidable;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.codControllable;
-+ }
-+ // Purpur end - Ridables
-+
+diff --git a/net/minecraft/world/entity/animal/cow/AbstractCow.java b/net/minecraft/world/entity/animal/cow/AbstractCow.java
+index f6f251227db315b58bee45f8011624a347eb8fea..a25ef3bc802759f61947ef8242c19e9320693d35 100644
+--- a/net/minecraft/world/entity/animal/cow/AbstractCow.java
++++ b/net/minecraft/world/entity/animal/cow/AbstractCow.java
+@@ -38,6 +38,7 @@ public abstract class AbstractCow extends Animal {
@Override
- public ItemStack getBucketItemStack() {
- return new ItemStack(Items.COD_BUCKET);
-diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java
-index 8c1f74c6be53cbf48bd6b5641511359578801c08..656babc0c8810a85eb9f78ced1f3ad9551fdc286 100644
---- a/net/minecraft/world/entity/animal/Cow.java
-+++ b/net/minecraft/world/entity/animal/Cow.java
-@@ -38,9 +38,27 @@ public class Cow extends Animal {
- super(entityType, level);
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new FloatGoal(this));
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(1, new PanicGoal(this, 2.0));
+ this.goalSelector.addGoal(2, new BreedGoal(this, 1.0));
+ this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, itemStack -> 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), false)); // Purpur - Cows eat mushrooms
+@@ -83,13 +84,14 @@ public abstract class AbstractCow extends Animal {
+
+ @Override
+ public InteractionResult mobInteract(Player player, InteractionHand hand) {
++ if (getRider() != null) return InteractionResult.PASS; // Purpur - Ridables
+ ItemStack itemInHand = player.getItemInHand(hand);
+ if (itemInHand.is(Items.BUCKET) && !this.isBaby()) {
+ // CraftBukkit start - Got milk?
+ org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(player.level(), player, this.blockPosition(), this.blockPosition(), null, itemInHand, Items.MILK_BUCKET, hand);
+ if (event.isCancelled()) {
+ player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
+- return InteractionResult.PASS;
++ return tryRide(player, hand); // Purpur - Ridables
+ }
+ // CraftBukkit end
+ player.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F);
+diff --git a/net/minecraft/world/entity/animal/cow/Cow.java b/net/minecraft/world/entity/animal/cow/Cow.java
+index f37322e0d90ea055a643b144dd87578df6a0bcc9..0268063bb0db8c30c594a7d75d0d11f7236c3a68 100644
+--- a/net/minecraft/world/entity/animal/cow/Cow.java
++++ b/net/minecraft/world/entity/animal/cow/Cow.java
+@@ -29,6 +29,23 @@ public class Cow extends AbstractCow {
+ super(type, level);
}
+ // Purpur start - Ridables
@@ -818,40 +898,57 @@ index 8c1f74c6be53cbf48bd6b5641511359578801c08..656babc0c8810a85eb9f78ced1f3ad95
+ // Purpur end - Ridables
+
@Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new FloatGoal(this));
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(1, new PanicGoal(this, 2.0));
- this.goalSelector.addGoal(2, new BreedGoal(this, 1.0));
- this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, itemStack -> 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), false)); // Purpur - Cows eat mushrooms
-@@ -86,13 +104,14 @@ public class Cow extends Animal {
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/cow/MushroomCow.java b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+index ea6299e728d7c7e7a52d7c65d759407ba27c8eac..1a9f5f17e46af831bc6621c83c57e5436397dbc2 100644
+--- a/net/minecraft/world/entity/animal/cow/MushroomCow.java
++++ b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+@@ -61,6 +61,23 @@ public class MushroomCow extends AbstractCow implements Shearable {
+ super(type, level);
+ }
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.mooshroomRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.mooshroomRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.mooshroomControllable;
++ }
++ // Purpur end - Ridables
++
@Override
- public InteractionResult mobInteract(Player player, InteractionHand hand) {
-+ if (getRider() != null) return InteractionResult.PASS; // Purpur - Ridables
- ItemStack itemInHand = player.getItemInHand(hand);
- if (itemInHand.is(Items.BUCKET) && !this.isBaby()) {
- // CraftBukkit start - Got milk?
- org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemInHand, Items.MILK_BUCKET, hand);
- if (event.isCancelled()) {
- player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
-- return InteractionResult.PASS;
-+ return tryRide(player, hand); // Purpur - Ridables
- }
- // CraftBukkit end
- player.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F);
-diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java
-index 8be0dd148d88dfdfb9efab91124c829e60b5dea5..35bce598bb5857356823594d2a001006ce19f835 100644
---- a/net/minecraft/world/entity/animal/Dolphin.java
-+++ b/net/minecraft/world/entity/animal/Dolphin.java
-@@ -72,14 +72,82 @@ public class Dolphin extends AgeableWaterCreature {
- public static final Predicate ALLOWED_ITEMS = itemEntity -> !itemEntity.hasPickUpDelay() && itemEntity.isAlive() && itemEntity.isInWater();
- public static final float BABY_SCALE = 0.65F;
+ public float getWalkTargetValue(BlockPos pos, LevelReader level) {
+ return level.getBlockState(pos.below()).is(Blocks.MYCELIUM) ? 10.0F : level.getPathfindingCostFromLightLevels(pos);
+@@ -121,7 +138,7 @@ public class MushroomCow extends AbstractCow implements Shearable {
+ java.util.List drops = this.generateDefaultDrops(serverLevel, itemInHand);
+ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops);
+ if (event != null) {
+- if (event.isCancelled()) return InteractionResult.PASS;
++ if (event.isCancelled()) return tryRide(player, hand); // Purpur - Ridables
+ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
+ // Paper end - custom shear drops
+ }
+diff --git a/net/minecraft/world/entity/animal/dolphin/Dolphin.java b/net/minecraft/world/entity/animal/dolphin/Dolphin.java
+index 45b6707ce9944a6a69f51196c3323821648d500b..656335a3bd021efc538ab407673c09a83178ed7c 100644
+--- a/net/minecraft/world/entity/animal/dolphin/Dolphin.java
++++ b/net/minecraft/world/entity/animal/dolphin/Dolphin.java
+@@ -76,14 +76,82 @@ public class Dolphin extends AgeableWaterCreature {
+ private static final boolean DEFAULT_GOT_FISH = false;
+ @Nullable public BlockPos treasurePos;
private boolean isNaturallyAggressiveToPlayers; // Purpur - Dolphins naturally aggressive to players chance
+ private int spitCooldown; // Purpur - Ridables
- public Dolphin(EntityType extends Dolphin> entityType, Level level) {
- super(entityType, level);
+ public Dolphin(EntityType extends Dolphin> type, Level level) {
+ super(type, level);
- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true);
+ // Purpur start - Ridables
+ class DolphinMoveControl extends SmoothSwimmingMoveControl {
@@ -925,10 +1022,10 @@ index 8be0dd148d88dfdfb9efab91124c829e60b5dea5..35bce598bb5857356823594d2a001006
+ }
+ // Purpur end - Ridables
+
- @Nullable
@Override
- public SpawnGroupData finalizeSpawn(
-@@ -172,6 +240,7 @@ public class Dolphin extends AgeableWaterCreature {
+ public @Nullable SpawnGroupData finalizeSpawn(
+ ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
+@@ -158,6 +226,7 @@ public class Dolphin extends AgeableWaterCreature {
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 - Dolphins naturally aggressive to players chance
@@ -936,7 +1033,7 @@ index 8be0dd148d88dfdfb9efab91124c829e60b5dea5..35bce598bb5857356823594d2a001006
this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this));
this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0));
this.goalSelector.addGoal(4, new RandomSwimmingGoal(this, 1.0, 10));
-@@ -182,6 +251,7 @@ public class Dolphin extends AgeableWaterCreature {
+@@ -168,6 +237,7 @@ public class Dolphin extends AgeableWaterCreature {
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.0, 1.0));
@@ -944,7 +1041,7 @@ index 8be0dd148d88dfdfb9efab91124c829e60b5dea5..35bce598bb5857356823594d2a001006
this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Guardian.class).setAlertOthers());
this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (ignored, ignored2) -> isNaturallyAggressiveToPlayers)); // Purpur - Dolphins naturally aggressive to players chance
}
-@@ -227,7 +297,7 @@ public class Dolphin extends AgeableWaterCreature {
+@@ -213,7 +283,7 @@ public class Dolphin extends AgeableWaterCreature {
@Override
protected boolean canRide(Entity entity) {
@@ -953,7 +1050,7 @@ index 8be0dd148d88dfdfb9efab91124c829e60b5dea5..35bce598bb5857356823594d2a001006
}
@Override
-@@ -256,6 +326,11 @@ public class Dolphin extends AgeableWaterCreature {
+@@ -242,6 +312,11 @@ public class Dolphin extends AgeableWaterCreature {
@Override
public void tick() {
super.tick();
@@ -965,11 +1062,507 @@ index 8be0dd148d88dfdfb9efab91124c829e60b5dea5..35bce598bb5857356823594d2a001006
if (this.isNoAi()) {
this.setAirSupply(this.getMaxAirSupply());
} else {
-diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java
-index ddc252c76cedec0a0e9e268d8a874015a5ad52fe..8b0a813f9dd001c6dd108ba7aac04d134a20fbc1 100644
---- a/net/minecraft/world/entity/animal/Fox.java
-+++ b/net/minecraft/world/entity/animal/Fox.java
-@@ -129,6 +129,44 @@ public class Fox extends Animal implements VariantHolder {
+diff --git a/net/minecraft/world/entity/animal/equine/AbstractHorse.java b/net/minecraft/world/entity/animal/equine/AbstractHorse.java
+index e837c63631c637238b9fe0ba05984af5e0d2b833..a1dce0a5ce1fcd0a2ff7104b3592ffd5c948db34 100644
+--- a/net/minecraft/world/entity/animal/equine/AbstractHorse.java
++++ b/net/minecraft/world/entity/animal/equine/AbstractHorse.java
+@@ -128,11 +128,21 @@ public abstract class AbstractHorse extends Animal implements HasCustomInventory
+
+ protected AbstractHorse(EntityType extends AbstractHorse> type, Level level) {
+ super(type, level);
++ this.moveControl = new net.minecraft.world.entity.ai.control.MoveControl(this); // Purpur - use vanilla controller
++ this.lookControl = new net.minecraft.world.entity.ai.control.LookControl(this); // Purpur - use vanilla controller
+ this.createInventory();
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return false; // vanilla handles
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void registerGoals() {
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(1, new AbstractHorse.MountPanicGoal(1.2));
+ this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2));
+ this.goalSelector.addGoal(2, new BreedGoal(this, 1.0, AbstractHorse.class));
+@@ -143,6 +153,7 @@ public abstract class AbstractHorse extends Animal implements HasCustomInventory
+ if (this.canPerformRearing()) {
+ this.goalSelector.addGoal(9, new RandomStandGoal(this));
+ }
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables
+
+ this.addBehaviourGoals();
+ }
+diff --git a/net/minecraft/world/entity/animal/equine/Donkey.java b/net/minecraft/world/entity/animal/equine/Donkey.java
+index 55844fe13c403a55d135ec4ff4731d88601b205e..8aec9f254c82993632e68368d37b8c9bee7869cc 100644
+--- a/net/minecraft/world/entity/animal/equine/Donkey.java
++++ b/net/minecraft/world/entity/animal/equine/Donkey.java
+@@ -16,6 +16,13 @@ public class Donkey extends AbstractChestedHorse {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.donkeyRidableInWater;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ public SoundEvent getAmbientSound() {
+ return SoundEvents.DONKEY_AMBIENT;
+diff --git a/net/minecraft/world/entity/animal/equine/Horse.java b/net/minecraft/world/entity/animal/equine/Horse.java
+index 1763543942a25a788c0f90241db75ddad70a7da8..cc50151ce6e6daffc1ecd41eb89a0d2f159f651e 100644
+--- a/net/minecraft/world/entity/animal/equine/Horse.java
++++ b/net/minecraft/world/entity/animal/equine/Horse.java
+@@ -50,6 +50,13 @@ public class Horse extends AbstractHorse {
+ this.setPathfindingMalus(PathType.DAMAGE_OTHER, -1.0F);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.horseRidableInWater;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void randomizeAttributes(RandomSource random) {
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt));
+diff --git a/net/minecraft/world/entity/animal/equine/Llama.java b/net/minecraft/world/entity/animal/equine/Llama.java
+index cceb66525a4d017b2db21bd301e63670c639223f..bba6493eee2f605faac0d49d665117d2f2c41213 100644
+--- a/net/minecraft/world/entity/animal/equine/Llama.java
++++ b/net/minecraft/world/entity/animal/equine/Llama.java
+@@ -82,7 +82,58 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
+ super(type, level);
+ this.getNavigation().setRequiredPathLength(40.0F);
+ this.maxDomestication = 30; // Paper - Missing entity API; configure max temper instead of a hardcoded value
++ // Purpur start - Ridables
++ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this) {
++ @Override
++ public void tick() {
++ if (entity.getRider() != null && entity.isControllable() && isSaddled()) {
++ purpurTick(entity.getRider());
++ } else {
++ vanillaTick();
++ }
++ }
++ };
++ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) {
++ @Override
++ public void tick() {
++ if (entity.getRider() != null && entity.isControllable() && isSaddled()) {
++ purpurTick(entity.getRider());
++ } else {
++ vanillaTick();
++ }
++ }
++ };
++ // Purpur end - Ridables
++ }
++
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.llamaRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.llamaRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.llamaControllable;
++ }
++
++ @Override
++ public boolean isSaddled() {
++ return super.isWearingBodyArmor() || this.isTamed();
++ }
++
++ @Nullable
++ @Override
++ public LivingEntity getControllingPassenger() {
++ Entity firstPassenger = this.getFirstPassenger();
++ return !this.isNoAi() && firstPassenger instanceof net.minecraft.world.entity.Mob mob && firstPassenger.canControlVehicle() ? mob : null;
+ }
++ // Purpur end - Ridables
+
+ public boolean isTraderLlama() {
+ return false;
+@@ -120,6 +171,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new FloatGoal(this));
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.LlamaHasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2));
+ this.goalSelector.addGoal(2, new LlamaFollowCaravanGoal(this, 2.1F));
+ this.goalSelector.addGoal(3, new RangedAttackGoal(this, 1.25, 40, 20.0F));
+@@ -130,6 +182,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
+ this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.7));
+ this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 6.0F));
+ this.goalSelector.addGoal(9, new RandomLookAroundGoal(this));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.LlamaHasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new Llama.LlamaHurtByTargetGoal(this));
+ this.targetSelector.addGoal(2, new Llama.LlamaAttackWolfGoal(this));
+ }
+diff --git a/net/minecraft/world/entity/animal/equine/Mule.java b/net/minecraft/world/entity/animal/equine/Mule.java
+index b5444b88d30e7d375495bdbbe1469beb72beb87a..60c151af9e51ba1dd1063344a3f5c021b6a48440 100644
+--- a/net/minecraft/world/entity/animal/equine/Mule.java
++++ b/net/minecraft/world/entity/animal/equine/Mule.java
+@@ -15,6 +15,13 @@ public class Mule extends AbstractChestedHorse {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.muleRidableInWater;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ public SoundEvent getAmbientSound() {
+ return SoundEvents.MULE_AMBIENT;
+diff --git a/net/minecraft/world/entity/animal/equine/SkeletonHorse.java b/net/minecraft/world/entity/animal/equine/SkeletonHorse.java
+index 0afb4c836e697f820696bd760cca761520bc8250..3d98259439c3bdb97ab2c66734daf90a56b290ef 100644
+--- a/net/minecraft/world/entity/animal/equine/SkeletonHorse.java
++++ b/net/minecraft/world/entity/animal/equine/SkeletonHorse.java
+@@ -43,6 +43,13 @@ public class SkeletonHorse extends AbstractHorse {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isTamed() {
++ return super.isTamed() || this.level().purpurConfig.skeletonHorseRidable;
++ }
++ // Purpur end - Ridables
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0).add(Attributes.MOVEMENT_SPEED, 0.2F);
+ }
+@@ -62,6 +69,7 @@ public class SkeletonHorse extends AbstractHorse {
+
+ @Override
+ protected void addBehaviourGoals() {
++ if (level().purpurConfig.skeletonHorseCanSwim) goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur - Ridables
+ }
+
+ @Override
+diff --git a/net/minecraft/world/entity/animal/equine/TraderLlama.java b/net/minecraft/world/entity/animal/equine/TraderLlama.java
+index 44f85dc4075e9fc000dc89ba01e2039c01989dde..68b72c18a3880dead3b32b646a2f6a09d4b98c44 100644
+--- a/net/minecraft/world/entity/animal/equine/TraderLlama.java
++++ b/net/minecraft/world/entity/animal/equine/TraderLlama.java
+@@ -31,6 +31,28 @@ public class TraderLlama extends Llama {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.traderLlamaRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.traderLlamaRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.traderLlamaControllable;
++ }
++
++ @Override
++ public boolean isSaddled() {
++ return super.isSaddled() || isTamed();
++ }
++ // Purpur end - Ridables
++
+ @Override
+ public boolean isTraderLlama() {
+ return true;
+diff --git a/net/minecraft/world/entity/animal/equine/ZombieHorse.java b/net/minecraft/world/entity/animal/equine/ZombieHorse.java
+index 4cfae7e877c6545780a8b9fdb3e326edb8cc7943..c1a13047c673cafc5de873215dd368eae6ac8b5e 100644
+--- a/net/minecraft/world/entity/animal/equine/ZombieHorse.java
++++ b/net/minecraft/world/entity/animal/equine/ZombieHorse.java
+@@ -52,6 +52,18 @@ public class ZombieHorse extends AbstractHorse {
+ this.setPathfindingMalus(PathType.DAMAGE_OTHER, -1.0F);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieHorseRidableInWater;
++ }
++
++ @Override
++ public boolean isTamed() {
++ return super.isTamed() || this.level().purpurConfig.zombieHorseRidable;
++ }
++ // Purpur end - Ridables
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 25.0);
+ }
+diff --git a/net/minecraft/world/entity/animal/feline/Cat.java b/net/minecraft/world/entity/animal/feline/Cat.java
+index 6acd39413ab4fed1eaf251d3b6d9b9e184060e5c..2fe8b8382b7cb4056f4d430cf632ecf413e8e25b 100644
+--- a/net/minecraft/world/entity/animal/feline/Cat.java
++++ b/net/minecraft/world/entity/animal/feline/Cat.java
+@@ -95,10 +95,36 @@ public class Cat extends TamableAnimal {
+ this.reassessTameGoals();
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.catRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.catRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.catControllable;
++ }
++
++ @Override
++ public void onMount(Player rider) {
++ super.onMount(rider);
++ setInSittingPose(false);
++ setLying(false);
++ setRelaxStateOne(false);
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void registerGoals() {
+ this.temptGoal = new Cat.CatTemptGoal(this, 0.6, stack -> stack.is(ItemTags.CAT_FOOD), true);
+ this.goalSelector.addGoal(1, new FloatGoal(this));
++ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(1, new TamableAnimal.TamableAnimalPanicGoal(1.5));
+ this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this));
+ this.goalSelector.addGoal(3, new Cat.CatRelaxOnOwnerGoal(this));
+@@ -111,6 +137,7 @@ public class Cat extends TamableAnimal {
+ this.goalSelector.addGoal(10, new BreedGoal(this, 0.8));
+ this.goalSelector.addGoal(11, new WaterAvoidingRandomStrollGoal(this, 0.8, 1.0000001E-5F));
+ this.goalSelector.addGoal(12, new LookAtPlayerGoal(this, Player.class, 10.0F));
++ this.targetSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Rabbit.class, false, null));
+ this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR));
+ }
+@@ -373,6 +400,7 @@ public class Cat extends TamableAnimal {
+
+ @Override
+ public InteractionResult mobInteract(Player player, InteractionHand hand) {
++ if (getRider() != null) return InteractionResult.PASS; // Purpur - Ridables
+ ItemStack itemInHand = player.getItemInHand(hand);
+ Item item = itemInHand.getItem();
+ if (this.isTame()) {
+diff --git a/net/minecraft/world/entity/animal/feline/Ocelot.java b/net/minecraft/world/entity/animal/feline/Ocelot.java
+index 94fdbae92dabf7505a7c7b518d4c07b4f68c8e9c..22fa29aa785eda8fb4a895d36413626da8a49a0e 100644
+--- a/net/minecraft/world/entity/animal/feline/Ocelot.java
++++ b/net/minecraft/world/entity/animal/feline/Ocelot.java
+@@ -66,6 +66,23 @@ public class Ocelot extends Animal {
+ this.reassessTrustingGoals();
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.ocelotRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ocelotRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.ocelotControllable;
++ }
++ // Purpur end - Ridables
++
+ public boolean isTrusting() {
+ return this.entityData.get(DATA_TRUSTING);
+ }
+@@ -97,12 +114,14 @@ public class Ocelot extends Animal {
+ protected void registerGoals() {
+ this.temptGoal = new Ocelot.OcelotTemptGoal(this, 0.6, itemStack -> itemStack.is(ItemTags.OCELOT_FOOD), true);
+ this.goalSelector.addGoal(1, new FloatGoal(this));
++ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(3, this.temptGoal);
+ this.goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3F));
+ this.goalSelector.addGoal(8, new OcelotAttackGoal(this));
+ this.goalSelector.addGoal(9, new BreedGoal(this, 0.8));
+ this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 0.8, 1.0000001E-5F));
+ this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0F));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Chicken.class, false));
+ this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR));
+ }
+diff --git a/net/minecraft/world/entity/animal/fish/AbstractFish.java b/net/minecraft/world/entity/animal/fish/AbstractFish.java
+index 7b4215058325812e8dc785277d1ece0fd5dd6ea3..970904ce07ebc6aabc97166284cbb855d2976f09 100644
+--- a/net/minecraft/world/entity/animal/fish/AbstractFish.java
++++ b/net/minecraft/world/entity/animal/fish/AbstractFish.java
+@@ -91,6 +91,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(0, new PanicGoal(this, 1.25));
+ this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6, 1.4, EntitySelector.NO_SPECTATORS));
+ this.goalSelector.addGoal(4, new AbstractFish.FishSwimGoal(this));
+@@ -103,7 +104,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
+
+ @Override
+ protected void travelInWater(Vec3 travelVector, double gravity, boolean isFalling, double previousY) {
+- this.moveRelative(0.01F, travelVector);
++ this.moveRelative(getRider() != null ? getSpeed() : 0.01F, travelVector); // Purpur - Ridables
+ this.move(MoverType.SELF, this.getDeltaMovement());
+ this.setDeltaMovement(this.getDeltaMovement().scale(0.9));
+ if (this.getTarget() == null) {
+@@ -160,7 +161,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
+ protected void playStepSound(BlockPos pos, BlockState block) {
+ }
+
+- static class FishMoveControl extends MoveControl {
++ static class FishMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur - Ridables
+ private final AbstractFish fish;
+
+ FishMoveControl(AbstractFish mob) {
+@@ -168,14 +169,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
+ this.fish = mob;
+ }
+
++ // Purpur start - Ridables
+ @Override
+- public void tick() {
++ public void purpurTick(Player rider) {
++ super.purpurTick(rider);
++ fish.setDeltaMovement(fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D));
++ }
++ // Purpur end - Ridables
++
++ @Override
++ public void vanillaTick() { // Purpur - Ridables
+ if (this.fish.isEyeInFluid(FluidTags.WATER)) {
+ this.fish.setDeltaMovement(this.fish.getDeltaMovement().add(0.0, 0.005, 0.0));
+ }
+
+ if (this.operation == MoveControl.Operation.MOVE_TO && !this.fish.getNavigation().isDone()) {
+- float f = (float)(this.speedModifier * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED));
++ float f = (float)(this.getSpeedModifier() * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables
+ this.fish.setSpeed(Mth.lerp(0.125F, this.fish.getSpeed(), f));
+ double d = this.wantedX - this.fish.getX();
+ double d1 = this.wantedY - this.fish.getY();
+diff --git a/net/minecraft/world/entity/animal/fish/Cod.java b/net/minecraft/world/entity/animal/fish/Cod.java
+index 9a473f29931059e36a6fe8fa541c4706ababf59d..f73b3f5ae65f7793ff25145c72fb35e3daec8494 100644
+--- a/net/minecraft/world/entity/animal/fish/Cod.java
++++ b/net/minecraft/world/entity/animal/fish/Cod.java
+@@ -13,6 +13,18 @@ public class Cod extends AbstractSchoolingFish {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.codRidable;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.codControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ public ItemStack getBucketItemStack() {
+ return new ItemStack(Items.COD_BUCKET);
+diff --git a/net/minecraft/world/entity/animal/fish/Pufferfish.java b/net/minecraft/world/entity/animal/fish/Pufferfish.java
+index d8280671bb36d57b86a5d212d8deae9acc745bd4..1eaa5e5fb65b18e5042d69b5dbfea15a7271c0aa 100644
+--- a/net/minecraft/world/entity/animal/fish/Pufferfish.java
++++ b/net/minecraft/world/entity/animal/fish/Pufferfish.java
+@@ -47,6 +47,18 @@ public class Pufferfish extends AbstractFish {
+ this.refreshDimensions();
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.pufferfishRidable;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.pufferfishControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/fish/Salmon.java b/net/minecraft/world/entity/animal/fish/Salmon.java
+index c691912a8b109e7430ffb39bb832983cbf33fc8a..b362ce156765ad45b8c29b5dc2c6d9d99d2e1474 100644
+--- a/net/minecraft/world/entity/animal/fish/Salmon.java
++++ b/net/minecraft/world/entity/animal/fish/Salmon.java
+@@ -40,6 +40,18 @@ public class Salmon extends AbstractSchoolingFish {
+ this.refreshDimensions();
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.salmonRidable;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.salmonControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ public int getMaxSchoolSize() {
+ return 5;
+diff --git a/net/minecraft/world/entity/animal/fish/TropicalFish.java b/net/minecraft/world/entity/animal/fish/TropicalFish.java
+index e3961892ffc05bef4947bda75445ca5e255dce11..3281e75c48fb6cafdba088254009e5b4285b3819 100644
+--- a/net/minecraft/world/entity/animal/fish/TropicalFish.java
++++ b/net/minecraft/world/entity/animal/fish/TropicalFish.java
+@@ -77,6 +77,18 @@ public class TropicalFish extends AbstractSchoolingFish {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.tropicalFishRidable;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.tropicalFishControllable;
++ }
++ // Purpur end - Ridables
++
+ public static String getPredefinedName(int variantId) {
+ return "entity.minecraft.tropical_fish.predefined." + variantId;
+ }
+diff --git a/net/minecraft/world/entity/animal/fox/Fox.java b/net/minecraft/world/entity/animal/fox/Fox.java
+index 6d0eb7e0310b3fdd234dee5b8bf993d1c5ef27f1..bf00cf5e6fd8b9143e1b327ef7b90ae055d264ff 100644
+--- a/net/minecraft/world/entity/animal/fox/Fox.java
++++ b/net/minecraft/world/entity/animal/fox/Fox.java
+@@ -151,6 +151,44 @@ public class Fox extends Animal {
this.getNavigation().setRequiredPathLength(32.0F);
}
@@ -1014,7 +1607,7 @@ index ddc252c76cedec0a0e9e268d8a874015a5ad52fe..8b0a813f9dd001c6dd108ba7aac04d13
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
-@@ -148,6 +186,7 @@ public class Fox extends Animal implements VariantHolder {
+@@ -170,6 +208,7 @@ public class Fox extends Animal {
this, AbstractFish.class, 20, false, false, (entity, level) -> entity instanceof AbstractSchoolingFish
);
this.goalSelector.addGoal(0, new Fox.FoxFloatGoal());
@@ -1022,7 +1615,7 @@ index ddc252c76cedec0a0e9e268d8a874015a5ad52fe..8b0a813f9dd001c6dd108ba7aac04d13
this.goalSelector.addGoal(0, new ClimbOnTopOfPowderSnowGoal(this, this.level()));
this.goalSelector.addGoal(1, new Fox.FaceplantGoal());
this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2));
-@@ -175,6 +214,7 @@ public class Fox extends Animal implements VariantHolder {
+@@ -195,6 +234,7 @@ public class Fox extends Animal {
this.goalSelector.addGoal(11, new Fox.FoxSearchForItemsGoal());
this.goalSelector.addGoal(12, new Fox.FoxLookAtPlayerGoal(this, Player.class, 24.0F));
this.goalSelector.addGoal(13, new Fox.PerchAndSearchGoal());
@@ -1030,7 +1623,7 @@ index ddc252c76cedec0a0e9e268d8a874015a5ad52fe..8b0a813f9dd001c6dd108ba7aac04d13
this.targetSelector
.addGoal(
3,
-@@ -1095,15 +1135,15 @@ public class Fox extends Animal implements VariantHolder {
+@@ -1119,15 +1159,15 @@ public class Fox extends Animal {
}
}
@@ -1049,7 +1642,7 @@ index ddc252c76cedec0a0e9e268d8a874015a5ad52fe..8b0a813f9dd001c6dd108ba7aac04d13
}
}
-@@ -1139,15 +1179,15 @@ public class Fox extends Animal implements VariantHolder {
+@@ -1163,15 +1203,15 @@ public class Fox extends Animal {
}
}
@@ -1068,11 +1661,256 @@ index ddc252c76cedec0a0e9e268d8a874015a5ad52fe..8b0a813f9dd001c6dd108ba7aac04d13
}
}
}
-diff --git a/net/minecraft/world/entity/animal/IronGolem.java b/net/minecraft/world/entity/animal/IronGolem.java
-index 46921562c9c5caf7e04ee180325a638273d6bad2..223c4796f659a24062a719045e484a22d31ab2f0 100644
---- a/net/minecraft/world/entity/animal/IronGolem.java
-+++ b/net/minecraft/world/entity/animal/IronGolem.java
-@@ -73,9 +73,28 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
+diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java
+index 09d817aa34d4a6d8a49d614087f9942d75e673e8..5b4bb6fd100abc569c5da167735a220014bf5d8c 100644
+--- a/net/minecraft/world/entity/animal/frog/Frog.java
++++ b/net/minecraft/world/entity/animal/frog/Frog.java
+@@ -105,6 +105,8 @@ public class Frog extends Animal {
+ public final AnimationState croakAnimationState = new AnimationState();
+ public final AnimationState tongueAnimationState = new AnimationState();
+ public final AnimationState swimIdleAnimationState = new AnimationState();
++ private org.purpurmc.purpur.controller.MoveControllerWASD purpurLandController; // Purpur - Ridables
++ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurWaterController; // Purpur - Ridables
+
+ public Frog(EntityType extends Animal> type, Level level) {
+ super(type, level);
+@@ -112,7 +114,55 @@ public class Frog extends Animal {
+ this.setPathfindingMalus(PathType.WATER, 4.0F);
+ this.setPathfindingMalus(PathType.TRAPDOOR, -1.0F);
+ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true);
++ // Purpur start - Ridables
++ this.purpurLandController = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.2F);
++ this.purpurWaterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F);
++ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) {
++ @Override
++ public void tick() {
++ net.minecraft.world.entity.player.Player rider = mob.getRider();
++ if (rider != null && mob.isControllable()) {
++ if (mob.isInWater()) {
++ purpurWaterController.purpurTick(rider);
++ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, -0.005D, 0.0D));
++ } else {
++ purpurLandController.purpurTick(rider);
++ }
++ } else {
++ super.tick();
++ }
++ }
++ };
++ // Purpur end - Ridables
++ }
++
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.frogRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.frogRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.frogControllable;
++ }
++
++ @Override
++ protected void registerGoals() {
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
++ }
++
++ @Override
++ public float getJumpPower() {
++ return (getRider() != null && isControllable()) ? level().purpurConfig.frogRidableJumpHeight * this.getBlockJumpFactor() : super.getJumpPower();
+ }
++ // Purpur end - Ridables
+
+ @Override
+ protected Brain.Provider brainProvider() {
+@@ -204,6 +254,7 @@ public class Frog extends Animal {
+ protected void customServerAiStep(ServerLevel level) {
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("frogBrain");
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
+ this.getBrain().tick(level, this);
+ profilerFiller.pop();
+ profilerFiller.push("frogActivityUpdate");
+@@ -373,7 +424,7 @@ public class Frog extends Animal {
+ return level.getBlockState(pos.below()).is(BlockTags.FROGS_SPAWNABLE_ON) && isBrightEnoughToSpawn(level, pos);
+ }
+
+- class FrogLookControl extends LookControl {
++ class FrogLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables
+ FrogLookControl(final Mob mob) {
+ super(mob);
+ }
+diff --git a/net/minecraft/world/entity/animal/frog/Tadpole.java b/net/minecraft/world/entity/animal/frog/Tadpole.java
+index f65cfb908aac16e6df4d209c6b5c3ee5065289d3..9b5205d7f481d4cd8fe454ae588dc2a89bc613bf 100644
+--- a/net/minecraft/world/entity/animal/frog/Tadpole.java
++++ b/net/minecraft/world/entity/animal/frog/Tadpole.java
+@@ -65,13 +65,50 @@ public class Tadpole extends AbstractFish {
+ MemoryModuleType.IS_PANICKING
+ );
+ public boolean ageLocked; // Paper
++ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurController; // Purpur - Ridables
+
+ public Tadpole(EntityType extends AbstractFish> type, Level level) {
+ super(type, level);
+- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true);
++ // Purpur start - Ridables
++ this.purpurController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F);
++ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) {
++ @Override
++ public void tick() {
++ Player rider = mob.getRider();
++ if (rider != null && mob.isControllable()) {
++ purpurController.purpurTick(rider);
++ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, 0.002D, 0.0D));
++ } else {
++ super.tick();
++ }
++ }
++ };
++ // Purpur end - Ridables
+ this.lookControl = new SmoothSwimmingLookControl(this, 10);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.tadpoleRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.tadpoleRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.tadpoleControllable;
++ }
++
++ @Override
++ protected void registerGoals() {
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected PathNavigation createNavigation(Level level) {
+ return new WaterBoundPathNavigation(this, level);
+@@ -101,6 +138,7 @@ public class Tadpole extends AbstractFish {
+ protected void customServerAiStep(ServerLevel level) {
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("tadpoleBrain");
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
+ this.getBrain().tick(level, this);
+ profilerFiller.pop();
+ profilerFiller.push("tadpoleActivityUpdate");
+diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java
+index 566390c9258c1132c9ffa2df8ecc3e713963787f..6e4d611c959960e8d13f79704c176b41ea5c12c4 100644
+--- a/net/minecraft/world/entity/animal/goat/Goat.java
++++ b/net/minecraft/world/entity/animal/goat/Goat.java
+@@ -115,6 +115,23 @@ public class Goat extends Animal {
+ .orElseGet(() -> new ItemStack(Items.GOAT_HORN));
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.goatRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.goatRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.goatControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected Brain.Provider brainProvider() {
+ return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
+@@ -191,6 +208,7 @@ public class Goat extends Animal {
+ protected void customServerAiStep(ServerLevel level) {
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("goatBrain");
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
+ this.getBrain().tick(level, this);
+ profilerFiller.pop();
+ profilerFiller.push("goatActivityUpdate");
+diff --git a/net/minecraft/world/entity/animal/golem/CopperGolem.java b/net/minecraft/world/entity/animal/golem/CopperGolem.java
+index ad88672368b66ac99f437f8af48b9fd1dcc32c8a..4dc1ce5e07e23134cf3ed68e78a055c3b75fdc83 100644
+--- a/net/minecraft/world/entity/animal/golem/CopperGolem.java
++++ b/net/minecraft/world/entity/animal/golem/CopperGolem.java
+@@ -108,6 +108,28 @@ public class CopperGolem extends AbstractGolem implements ContainerUser, Shearab
+ }
+ // Purpur end - Summoner API
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.copperGolemRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.copperGolemRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.copperGolemControllable;
++ }
++
++ @Override
++ protected void registerGoals() {
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this));
++ }
++ // Purpur end - Ridables
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F).add(Attributes.STEP_HEIGHT, 1.0).add(Attributes.MAX_HEALTH, 12.0);
+ }
+@@ -198,6 +220,7 @@ public class CopperGolem extends AbstractGolem implements ContainerUser, Shearab
+ protected void customServerAiStep(ServerLevel level) {
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("copperGolemBrain");
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
+ this.getBrain().tick(level, this);
+ profilerFiller.pop();
+ profilerFiller.push("copperGolemActivityUpdate");
+@@ -237,7 +260,7 @@ public class CopperGolem extends AbstractGolem implements ContainerUser, Shearab
+ java.util.List drops = this.generateDefaultDrops(serverLevel, itemInHand);
+ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops);
+ if (event != null) {
+- if (event.isCancelled()) return InteractionResult.PASS;
++ if (event.isCancelled()) return tryRide(player, hand); // Purpur - Ridables
+ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
+ }
+ this.shear(serverLevel, SoundSource.PLAYERS, itemInHand, drops);
+@@ -273,6 +296,8 @@ public class CopperGolem extends AbstractGolem implements ContainerUser, Shearab
+ }
+ }
+
++ if (level().purpurConfig.villagerRidable && itemInHand.isEmpty()) return tryRide(player, hand); // Purpur - Ridables
++
+ return super.mobInteract(player, hand);
+ }
+ }
+diff --git a/net/minecraft/world/entity/animal/golem/IronGolem.java b/net/minecraft/world/entity/animal/golem/IronGolem.java
+index 32425f0aaa748c7f80f2e5cf95ef27238fe50489..363bf7781c8785bc6fdbc65941794a5a02f8a57a 100644
+--- a/net/minecraft/world/entity/animal/golem/IronGolem.java
++++ b/net/minecraft/world/entity/animal/golem/IronGolem.java
+@@ -74,9 +74,28 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
}
// Purpur end - Summoner API
@@ -1101,7 +1939,7 @@ index 46921562c9c5caf7e04ee180325a638273d6bad2..223c4796f659a24062a719045e484a22
this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0, true));
this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9, 32.0F));
this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6, false));
-@@ -83,6 +102,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
+@@ -84,6 +103,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
this.goalSelector.addGoal(5, new OfferFlowerGoal(this));
this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F));
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
@@ -1124,91 +1962,91 @@ index 46921562c9c5caf7e04ee180325a638273d6bad2..223c4796f659a24062a719045e484a22
} else {
float f = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F;
this.playSound(SoundEvents.IRON_GOLEM_REPAIR, 1.0F, f);
-diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java
-index a8aeb79b1c1413d74a5d18a57bd4ba4beca6039c..1292146341022483f78a9128ef9d7a88089274a0 100644
---- a/net/minecraft/world/entity/animal/MushroomCow.java
-+++ b/net/minecraft/world/entity/animal/MushroomCow.java
-@@ -55,6 +55,23 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder drops = this.generateDefaultDrops(serverLevel, itemInHand);
+ protected void registerGoals() {
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(1, new RangedAttackGoal(this, level().purpurConfig.snowGolemAttackDistance, level().purpurConfig.snowGolemSnowBallMin, level().purpurConfig.snowGolemSnowBallMax, level().purpurConfig.snowGolemSnowBallModifier)); // Purpur - Snow Golem rate of fire config
+ this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D, 1.0000001E-5F));
+ this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F));
+ this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entity, level) -> entity instanceof Enemy));
+ }
+
+@@ -112,6 +131,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
+ return;
+ }
+
++ if (getRider() != null && this.isControllable() && !level().purpurConfig.snowGolemLeaveTrailWhenRidden) return; // Purpur - don't leave snow trail when being ridden
+ BlockState blockState = Blocks.SNOW.defaultBlockState();
+
+ for (int i = 0; i < 4; i++) {
+@@ -154,7 +174,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops);
if (event != null) {
-- if (event.isCancelled()) return InteractionResult.PASS;
-+ if (event.isCancelled()) return tryRide(player, hand); // Purpur - Ridables
+ if (event.isCancelled()) {
+- return InteractionResult.PASS;
++ return tryRide(player, hand); // Purpur - Ridables
+ }
drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
// Paper end - custom shear drops
- }
-diff --git a/net/minecraft/world/entity/animal/Ocelot.java b/net/minecraft/world/entity/animal/Ocelot.java
-index e193696b2e3eb1c1c689c05592ab4318a98772ad..d26a8658c8c56c3b0df4e5908de1ac23ac2dd351 100644
---- a/net/minecraft/world/entity/animal/Ocelot.java
-+++ b/net/minecraft/world/entity/animal/Ocelot.java
-@@ -62,6 +62,23 @@ public class Ocelot extends Animal {
- this.reassessTrustingGoals();
+@@ -175,7 +195,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
+ return InteractionResult.SUCCESS;
+ // Purpur end - Snowman drop and put back pumpkin
+ } else {
+- return InteractionResult.PASS;
++ return tryRide(player, hand); // Purpur - Ridables
+ }
+ }
+
+diff --git a/net/minecraft/world/entity/animal/happyghast/HappyGhast.java b/net/minecraft/world/entity/animal/happyghast/HappyGhast.java
+index 5a4a96895c1d2f7538bf644dd133645bc831b582..0a75d3790a4bf4812e4f3b27ec50d67fdccf812d 100644
+--- a/net/minecraft/world/entity/animal/happyghast/HappyGhast.java
++++ b/net/minecraft/world/entity/animal/happyghast/HappyGhast.java
+@@ -126,6 +126,13 @@ public class HappyGhast extends Animal {
+ this.removeAllGoals(goal -> true);
}
+ // Purpur start - Ridables
+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.ocelotRidable;
-+ }
-+
-+ @Override
+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ocelotRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.ocelotControllable;
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.happyGhastRidableInWater;
+ }
+ // Purpur end - Ridables
+
- public boolean isTrusting() {
- return this.entityData.get(DATA_TRUSTING);
- }
-@@ -93,12 +110,14 @@ public class Ocelot extends Animal {
- protected void registerGoals() {
- this.temptGoal = new Ocelot.OcelotTemptGoal(this, 0.6, itemStack -> itemStack.is(ItemTags.OCELOT_FOOD), true);
- this.goalSelector.addGoal(1, new FloatGoal(this));
-+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(3, this.temptGoal);
- this.goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3F));
- this.goalSelector.addGoal(8, new OcelotAttackGoal(this));
- this.goalSelector.addGoal(9, new BreedGoal(this, 0.8));
- this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 0.8, 1.0000001E-5F));
- this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0F));
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Chicken.class, false));
- this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR));
- }
-diff --git a/net/minecraft/world/entity/animal/Panda.java b/net/minecraft/world/entity/animal/Panda.java
-index 283ddf7d13a17c0a6df5a52b7fd26ed7b7a4826b..19aa39af6685a03eb584820853239a3f4fa1a515 100644
---- a/net/minecraft/world/entity/animal/Panda.java
-+++ b/net/minecraft/world/entity/animal/Panda.java
-@@ -105,6 +105,32 @@ public class Panda extends Animal {
+ @Override
+ protected void ageBoundaryReached() {
+ if (this.isBaby()) {
+diff --git a/net/minecraft/world/entity/animal/panda/Panda.java b/net/minecraft/world/entity/animal/panda/Panda.java
+index c5425b36e96e4f41f0ed7d468f53ea3de6b9ef17..93503f6b4eea2cb2ae6c01279e847c307920c35d 100644
+--- a/net/minecraft/world/entity/animal/panda/Panda.java
++++ b/net/minecraft/world/entity/animal/panda/Panda.java
+@@ -108,6 +108,32 @@ public class Panda extends Animal {
}
}
@@ -1241,7 +2079,7 @@ index 283ddf7d13a17c0a6df5a52b7fd26ed7b7a4826b..19aa39af6685a03eb584820853239a3f
@Override
protected boolean canDispenserEquipIntoSlot(EquipmentSlot slot) {
return slot == EquipmentSlot.MAINHAND && this.canPickUpLoot();
-@@ -258,6 +284,7 @@ public class Panda extends Animal {
+@@ -260,6 +286,7 @@ public class Panda extends Animal {
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
@@ -1249,15 +2087,15 @@ index 283ddf7d13a17c0a6df5a52b7fd26ed7b7a4826b..19aa39af6685a03eb584820853239a3f
this.goalSelector.addGoal(2, new Panda.PandaPanicGoal(this, 2.0));
this.goalSelector.addGoal(2, new Panda.PandaBreedGoal(this, 1.0));
this.goalSelector.addGoal(3, new Panda.PandaAttackGoal(this, 1.2F, true));
-@@ -273,6 +300,7 @@ public class Panda extends Animal {
+@@ -275,6 +302,7 @@ public class Panda extends Animal {
this.goalSelector.addGoal(12, new Panda.PandaRollGoal(this));
this.goalSelector.addGoal(13, new FollowParentGoal(this, 1.25));
this.goalSelector.addGoal(14, new WaterAvoidingRandomStrollGoal(this, 1.0));
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new Panda.PandaHurtByTargetGoal(this).setAlertOthers(new Class[0]));
+ this.targetSelector.addGoal(1, new Panda.PandaHurtByTargetGoal(this).setAlertOthers());
}
-@@ -616,7 +644,7 @@ public class Panda extends Animal {
+@@ -617,7 +645,7 @@ public class Panda extends Animal {
public InteractionResult mobInteract(Player player, InteractionHand hand) {
ItemStack itemInHand = player.getItemInHand(hand);
if (this.isScared()) {
@@ -1266,7 +2104,7 @@ index 283ddf7d13a17c0a6df5a52b7fd26ed7b7a4826b..19aa39af6685a03eb584820853239a3f
} else if (this.isOnBack()) {
this.setOnBack(false);
return InteractionResult.SUCCESS;
-@@ -652,7 +680,7 @@ public class Panda extends Animal {
+@@ -653,7 +681,7 @@ public class Panda extends Animal {
return InteractionResult.SUCCESS_SERVER;
} else {
@@ -1275,7 +2113,7 @@ index 283ddf7d13a17c0a6df5a52b7fd26ed7b7a4826b..19aa39af6685a03eb584820853239a3f
}
}
-@@ -964,7 +992,7 @@ public class Panda extends Animal {
+@@ -958,7 +986,7 @@ public class Panda extends Animal {
}
}
@@ -1284,7 +2122,7 @@ index 283ddf7d13a17c0a6df5a52b7fd26ed7b7a4826b..19aa39af6685a03eb584820853239a3f
private final Panda panda;
public PandaMoveControl(Panda mob) {
-@@ -973,9 +1001,9 @@ public class Panda extends Animal {
+@@ -967,9 +995,9 @@ public class Panda extends Animal {
}
@Override
@@ -1296,14 +2134,14 @@ index 283ddf7d13a17c0a6df5a52b7fd26ed7b7a4826b..19aa39af6685a03eb584820853239a3f
}
}
}
-diff --git a/net/minecraft/world/entity/animal/Parrot.java b/net/minecraft/world/entity/animal/Parrot.java
-index 1d840fe1c718ea4431c471e3cbbdee074ed53179..445614d09d2364daee5245c217baeb31e186c168 100644
---- a/net/minecraft/world/entity/animal/Parrot.java
-+++ b/net/minecraft/world/entity/animal/Parrot.java
-@@ -124,12 +124,68 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder entityType, Level level) {
- super(entityType, level);
+ public Parrot(EntityType extends Parrot> type, Level level) {
+ super(type, level);
- this.moveControl = new FlyingMoveControl(this, 10, false);
+ // Purpur start - Ridables
+ final org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD flyingController = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F);
@@ -1367,10 +2205,10 @@ index 1d840fe1c718ea4431c471e3cbbdee074ed53179..445614d09d2364daee5245c217baeb31
+ }
+ // Purpur end - Ridables
+
- @Nullable
@Override
- public SpawnGroupData finalizeSpawn(
-@@ -150,9 +206,11 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder itemStack.is(Items.CARROT_ON_A_STICK), false));
-diff --git a/net/minecraft/world/entity/animal/PolarBear.java b/net/minecraft/world/entity/animal/PolarBear.java
-index fbd35f074a3045d483aabd9bc7e1c9c4f10a3167..711ed0d753494a92a003fc683146f289505ed7f6 100644
---- a/net/minecraft/world/entity/animal/PolarBear.java
-+++ b/net/minecraft/world/entity/animal/PolarBear.java
-@@ -59,6 +59,7 @@ public class PolarBear extends Animal implements NeutralMob {
- private int remainingPersistentAngerTime;
- @Nullable
- private UUID persistentAngerTarget;
+diff --git a/net/minecraft/world/entity/animal/polarbear/PolarBear.java b/net/minecraft/world/entity/animal/polarbear/PolarBear.java
+index df4b4a4d32019ef3a667841a0ce4485a8325e897..718531a324c36ac65a93af5c12e0c0a3948606cb 100644
+--- a/net/minecraft/world/entity/animal/polarbear/PolarBear.java
++++ b/net/minecraft/world/entity/animal/polarbear/PolarBear.java
+@@ -61,6 +61,7 @@ public class PolarBear extends Animal implements NeutralMob {
+ private static final UniformInt PERSISTENT_ANGER_TIME = TimeUtil.rangeOfSeconds(20, 39);
+ private long persistentAngerEndTime;
+ private @Nullable EntityReference persistentAngerTarget;
+ private int standTimer = 0; // Purpur - Ridables
- public PolarBear(EntityType extends PolarBear> entityType, Level level) {
- super(entityType, level);
-@@ -87,6 +88,34 @@ public class PolarBear extends Animal implements NeutralMob {
+ public PolarBear(EntityType extends PolarBear> type, Level level) {
+ super(type, level);
+@@ -89,6 +90,34 @@ public class PolarBear extends Animal implements NeutralMob {
}
// Purpur end - Breedable Polar Bears
@@ -1459,10 +2297,10 @@ index fbd35f074a3045d483aabd9bc7e1c9c4f10a3167..711ed0d753494a92a003fc683146f289
+ }
+ // Purpur end - Ridables
+
- @Nullable
@Override
- public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
-@@ -102,6 +131,7 @@ public class PolarBear extends Animal implements NeutralMob {
+ public @Nullable AgeableMob getBreedOffspring(ServerLevel level, AgeableMob partner) {
+ return EntityType.POLAR_BEAR.create(level, EntitySpawnReason.BREEDING);
+@@ -103,6 +132,7 @@ public class PolarBear extends Animal implements NeutralMob {
protected void registerGoals() {
super.registerGoals();
this.goalSelector.addGoal(0, new FloatGoal(this));
@@ -1470,7 +2308,7 @@ index fbd35f074a3045d483aabd9bc7e1c9c4f10a3167..711ed0d753494a92a003fc683146f289
this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal());
this.goalSelector.addGoal(1, new PanicGoal(this, 2.0, mob -> mob.isBaby() ? DamageTypeTags.PANIC_CAUSES : DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES));
// Purpur start - Breedable Polar Bears
-@@ -114,6 +144,7 @@ public class PolarBear extends Animal implements NeutralMob {
+@@ -115,6 +145,7 @@ public class PolarBear extends Animal implements NeutralMob {
this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0));
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this));
@@ -1479,7 +2317,7 @@ index fbd35f074a3045d483aabd9bc7e1c9c4f10a3167..711ed0d753494a92a003fc683146f289
this.targetSelector.addGoal(2, new PolarBear.PolarBearAttackPlayersGoal());
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt));
@@ -232,6 +263,12 @@ public class PolarBear extends Animal implements NeutralMob {
- if (!this.level().isClientSide) {
+ if (!this.level().isClientSide()) {
this.updatePersistentAnger((ServerLevel)this.level(), true);
}
+
@@ -1499,43 +2337,20 @@ index fbd35f074a3045d483aabd9bc7e1c9c4f10a3167..711ed0d753494a92a003fc683146f289
}
public float getStandingAnimationScale(float partialTick) {
-diff --git a/net/minecraft/world/entity/animal/Pufferfish.java b/net/minecraft/world/entity/animal/Pufferfish.java
-index d94a7cfcd0f7a15ce97d3b12daa8b2c71acf997a..f7e9abf778186ad1c78dbe411980a83c5e68792e 100644
---- a/net/minecraft/world/entity/animal/Pufferfish.java
-+++ b/net/minecraft/world/entity/animal/Pufferfish.java
-@@ -45,6 +45,18 @@ public class Pufferfish extends AbstractFish {
- this.refreshDimensions();
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.pufferfishRidable;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.pufferfishControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/animal/Rabbit.java b/net/minecraft/world/entity/animal/Rabbit.java
-index b2cbe9f7a771dbfc381effa0821d44421c98b33e..8cac46951938c80fae3499e8b53709c25d86e9bd 100644
---- a/net/minecraft/world/entity/animal/Rabbit.java
-+++ b/net/minecraft/world/entity/animal/Rabbit.java
-@@ -83,6 +83,7 @@ public class Rabbit extends Animal implements VariantHolder {
+diff --git a/net/minecraft/world/entity/animal/rabbit/Rabbit.java b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+index d5e7599c23405eb5a4519e2dfd93ddbe2853fa3b..16fbee742f28cf4571effb66265daeee64bae9b7 100644
+--- a/net/minecraft/world/entity/animal/rabbit/Rabbit.java
++++ b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+@@ -94,6 +94,7 @@ public class Rabbit extends Animal {
private boolean wasOnGround;
private int jumpDelayTicks;
- public int moreCarrotTicks;
+ public int moreCarrotTicks = 0;
+ private boolean actualJump; // Purpur - Ridables
- public Rabbit(EntityType extends Rabbit> entityType, Level level) {
- super(entityType, level);
-@@ -91,9 +92,55 @@ public class Rabbit extends Animal implements VariantHolder {
- //this.setSpeedModifier(0.0); // CraftBukkit
+ public Rabbit(EntityType extends Rabbit> type, Level level) {
+ super(type, level);
+@@ -102,9 +103,55 @@ public class Rabbit extends Animal {
+ // this.setSpeedModifier(0.0); // CraftBukkit
}
+ // Purpur start - Ridables
@@ -1590,7 +2405,7 @@ index b2cbe9f7a771dbfc381effa0821d44421c98b33e..8cac46951938c80fae3499e8b53709c2
this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level()));
this.goalSelector.addGoal(1, new Rabbit.RabbitPanicGoal(this, 2.2));
this.goalSelector.addGoal(2, new BreedGoal(this, 0.8));
-@@ -108,6 +155,14 @@ public class Rabbit extends Animal implements VariantHolder {
+@@ -119,6 +166,14 @@ public class Rabbit extends Animal {
@Override
protected float getJumpPower() {
@@ -1605,7 +2420,7 @@ index b2cbe9f7a771dbfc381effa0821d44421c98b33e..8cac46951938c80fae3499e8b53709c2
float f = 0.3F;
if (this.moveControl.getSpeedModifier() <= 0.6) {
f = 0.2F;
-@@ -175,6 +230,12 @@ public class Rabbit extends Animal implements VariantHolder {
+@@ -186,6 +241,12 @@ public class Rabbit extends Animal {
@Override
public void customServerAiStep(ServerLevel level) {
@@ -1618,7 +2433,7 @@ index b2cbe9f7a771dbfc381effa0821d44421c98b33e..8cac46951938c80fae3499e8b53709c2
if (this.jumpDelayTicks > 0) {
this.jumpDelayTicks--;
}
-@@ -483,7 +544,7 @@ public class Rabbit extends Animal implements VariantHolder {
+@@ -511,7 +572,7 @@ public class Rabbit extends Animal {
}
}
@@ -1627,7 +2442,7 @@ index b2cbe9f7a771dbfc381effa0821d44421c98b33e..8cac46951938c80fae3499e8b53709c2
private final Rabbit rabbit;
private double nextJumpSpeed;
-@@ -493,14 +554,14 @@ public class Rabbit extends Animal implements VariantHolder {
+@@ -521,14 +582,14 @@ public class Rabbit extends Animal {
}
@Override
@@ -1644,35 +2459,12 @@ index b2cbe9f7a771dbfc381effa0821d44421c98b33e..8cac46951938c80fae3499e8b53709c2
}
@Override
-diff --git a/net/minecraft/world/entity/animal/Salmon.java b/net/minecraft/world/entity/animal/Salmon.java
-index 41366f7b9af176a33b20ea26dd53d50994d2c600..ebbd6d39c3f5d6c66445c2c743785ed369408389 100644
---- a/net/minecraft/world/entity/animal/Salmon.java
-+++ b/net/minecraft/world/entity/animal/Salmon.java
-@@ -35,6 +35,18 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder stack.is(ItemTags.SHEEP_FOOD), false));
-diff --git a/net/minecraft/world/entity/animal/SnowGolem.java b/net/minecraft/world/entity/animal/SnowGolem.java
-index 29427515b648b84248f486c156c5cd7a0995ba14..52de92b118b613217b8f92ff672c01ddf798a1fc 100644
---- a/net/minecraft/world/entity/animal/SnowGolem.java
-+++ b/net/minecraft/world/entity/animal/SnowGolem.java
-@@ -61,12 +61,31 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
+diff --git a/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
+index a4d60a0dddabd7981d2db28af6b1d88d64d6e806..3d5cf62bd9bd99a978b7dc535675178deb695af0 100644
+--- a/net/minecraft/world/entity/animal/sniffer/Sniffer.java
++++ b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
+@@ -89,6 +89,23 @@ public class Sniffer extends Animal {
+ this.setPathfindingMalus(PathType.DAMAGE_CAUTIOUS, -1.0F);
}
- // Purpur end - Summoner API
+ // Purpur start - Ridables
+ @Override
+ public boolean isRidable() {
-+ return level().purpurConfig.snowGolemRidable;
++ return level().purpurConfig.snifferRidable;
+ }
+
+ @Override
+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.snowGolemRidableInWater;
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.snifferRidableInWater;
+ }
+
+ @Override
+ public boolean isControllable() {
-+ return level().purpurConfig.snowGolemControllable;
++ return level().purpurConfig.snifferControllable;
+ }
+ // Purpur end - Ridables
+
@Override
- protected void registerGoals() {
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(1, new RangedAttackGoal(this, level().purpurConfig.snowGolemAttackDistance, level().purpurConfig.snowGolemSnowBallMin, level().purpurConfig.snowGolemSnowBallMax, level().purpurConfig.snowGolemSnowBallModifier)); // Purpur - Snow Golem rate of fire config
- this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D, 1.0000001E-5F));
- this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F));
- this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entity, level) -> entity instanceof Enemy));
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+@@ -467,6 +484,7 @@ public class Sniffer extends Animal {
+ protected void customServerAiStep(ServerLevel level) {
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("snifferBrain");
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
+ this.getBrain().tick(level, this);
+ profilerFiller.popPush("snifferActivityUpdate");
+ SnifferAi.updateActivity(this);
+diff --git a/net/minecraft/world/entity/animal/squid/GlowSquid.java b/net/minecraft/world/entity/animal/squid/GlowSquid.java
+index 2b1ece8ff62376a0851c18c39f43882abf2abaca..c5a8080aa0fa1014602ba76fb4d8ad69b926dbfa 100644
+--- a/net/minecraft/world/entity/animal/squid/GlowSquid.java
++++ b/net/minecraft/world/entity/animal/squid/GlowSquid.java
+@@ -37,6 +37,19 @@ public class GlowSquid extends Squid {
}
+ // Purpur end - Flying squids! Oh my!
-@@ -113,6 +132,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
- return;
- }
-
-+ if (getRider() != null && this.isControllable() && !level().purpurConfig.snowGolemLeaveTrailWhenRidden) return; // Purpur - don't leave snow trail when being ridden
- BlockState blockState = Blocks.SNOW.defaultBlockState();
-
- for (int i = 0; i < 4; i++) {
-@@ -155,7 +175,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
- org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops);
- if (event != null) {
- if (event.isCancelled()) {
-- return InteractionResult.PASS;
-+ return tryRide(player, hand); // Purpur - Ridables
- }
- drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
- // Paper end - custom shear drops
-@@ -176,7 +196,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
- return InteractionResult.SUCCESS;
- // Purpur end - Snowman drop and put back pumpkin
- } else {
-- return InteractionResult.PASS;
-+ return tryRide(player, hand); // Purpur - Ridables
- }
- }
-
-diff --git a/net/minecraft/world/entity/animal/Squid.java b/net/minecraft/world/entity/animal/Squid.java
-index c776d40896a6514ab9c66df206c93469ec682b23..e3f43e8c6ddbae289a82157cab4beb18f682dd75 100644
---- a/net/minecraft/world/entity/animal/Squid.java
-+++ b/net/minecraft/world/entity/animal/Squid.java
-@@ -69,9 +69,32 @@ public class Squid extends AgeableWaterCreature {
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.glowSquidRidable;
++ }
++
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.glowSquidControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected ParticleOptions getInkParticle() {
+ return ParticleTypes.GLOW_SQUID_INK;
+diff --git a/net/minecraft/world/entity/animal/squid/Squid.java b/net/minecraft/world/entity/animal/squid/Squid.java
+index 504573bf4cbdf1debfa9f9bd071fa40d443b860d..69d87bd27a95bb9e92cd24fb7973a9b06714567e 100644
+--- a/net/minecraft/world/entity/animal/squid/Squid.java
++++ b/net/minecraft/world/entity/animal/squid/Squid.java
+@@ -71,9 +71,32 @@ public class Squid extends AgeableWaterCreature {
}
// Purpur end - Flying squids! Oh my!
@@ -1799,7 +2589,7 @@ index c776d40896a6514ab9c66df206c93469ec682b23..e3f43e8c6ddbae289a82157cab4beb18
this.goalSelector.addGoal(1, new Squid.SquidFleeGoal());
}
-@@ -327,6 +350,37 @@ public class Squid extends AgeableWaterCreature {
+@@ -325,6 +348,37 @@ public class Squid extends AgeableWaterCreature {
@Override
public void tick() {
@@ -1837,34 +2627,11 @@ index c776d40896a6514ab9c66df206c93469ec682b23..e3f43e8c6ddbae289a82157cab4beb18
int noActionTime = this.squid.getNoActionTime();
if (noActionTime > 100) {
this.squid.movementVector = Vec3.ZERO;
-diff --git a/net/minecraft/world/entity/animal/TropicalFish.java b/net/minecraft/world/entity/animal/TropicalFish.java
-index fa5f7f7d54083f9ea2095dd44362069d00e0b9a5..1e31a39b276e1c5ae767da7af0b536007c87189e 100644
---- a/net/minecraft/world/entity/animal/TropicalFish.java
-+++ b/net/minecraft/world/entity/animal/TropicalFish.java
-@@ -67,6 +67,18 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.tropicalFishRidable;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.tropicalFishControllable;
-+ }
-+ // Purpur end - Ridables
-+
- public static String getPredefinedName(int variantId) {
- return "entity.minecraft.tropical_fish.predefined." + variantId;
- }
-diff --git a/net/minecraft/world/entity/animal/Turtle.java b/net/minecraft/world/entity/animal/Turtle.java
-index 354ec2b987882d8f40ef4ac5257183d2fda73bb8..98cb91574c8d2bdb6d180256f657ecc67987a6fe 100644
---- a/net/minecraft/world/entity/animal/Turtle.java
-+++ b/net/minecraft/world/entity/animal/Turtle.java
-@@ -84,6 +84,23 @@ public class Turtle extends Animal {
+diff --git a/net/minecraft/world/entity/animal/turtle/Turtle.java b/net/minecraft/world/entity/animal/turtle/Turtle.java
+index fdbc70322eb653d2cc576090c27d1cb67bfce1f6..7699967db327cf80940bf30d8e0c734b43fd1e8f 100644
+--- a/net/minecraft/world/entity/animal/turtle/Turtle.java
++++ b/net/minecraft/world/entity/animal/turtle/Turtle.java
+@@ -87,6 +87,23 @@ public class Turtle extends Animal {
this.moveControl = new Turtle.TurtleMoveControl(this);
}
@@ -1886,9 +2653,9 @@ index 354ec2b987882d8f40ef4ac5257183d2fda73bb8..98cb91574c8d2bdb6d180256f657ecc6
+ // Purpur end - Ridables
+
public void setHomePos(BlockPos homePos) {
- this.entityData.set(HOME_POS, homePos);
+ this.homePos = homePos;
}
-@@ -188,6 +205,7 @@ public class Turtle extends Animal {
+@@ -145,6 +162,7 @@ public class Turtle extends Animal {
@Override
protected void registerGoals() {
@@ -1896,7 +2663,7 @@ index 354ec2b987882d8f40ef4ac5257183d2fda73bb8..98cb91574c8d2bdb6d180256f657ecc6
this.goalSelector.addGoal(0, new Turtle.TurtlePanicGoal(this, 1.2));
this.goalSelector.addGoal(1, new Turtle.TurtleBreedGoal(this, 1.0));
this.goalSelector.addGoal(1, new Turtle.TurtleLayEggGoal(this, 1.0));
-@@ -539,12 +557,14 @@ public class Turtle extends Animal {
+@@ -485,12 +503,14 @@ public class Turtle extends Animal {
}
}
@@ -1912,7 +2679,7 @@ index 354ec2b987882d8f40ef4ac5257183d2fda73bb8..98cb91574c8d2bdb6d180256f657ecc6
}
private void updateSpeed() {
-@@ -563,7 +583,7 @@ public class Turtle extends Animal {
+@@ -509,7 +529,7 @@ public class Turtle extends Animal {
}
@Override
@@ -1921,7 +2688,7 @@ index 354ec2b987882d8f40ef4ac5257183d2fda73bb8..98cb91574c8d2bdb6d180256f657ecc6
this.updateSpeed();
if (this.operation == MoveControl.Operation.MOVE_TO && !this.turtle.getNavigation().isDone()) {
double d = this.wantedX - this.turtle.getX();
-@@ -577,7 +597,7 @@ public class Turtle extends Animal {
+@@ -523,7 +543,7 @@ public class Turtle extends Animal {
float f = (float)(Mth.atan2(d2, d) * 180.0F / (float)Math.PI) - 90.0F;
this.turtle.setYRot(this.rotlerp(this.turtle.getYRot(), f, 90.0F));
this.turtle.yBodyRot = this.turtle.getYRot();
@@ -1930,11 +2697,11 @@ index 354ec2b987882d8f40ef4ac5257183d2fda73bb8..98cb91574c8d2bdb6d180256f657ecc6
this.turtle.setSpeed(Mth.lerp(0.125F, this.turtle.getSpeed(), f1));
this.turtle.setDeltaMovement(this.turtle.getDeltaMovement().add(0.0, this.turtle.getSpeed() * d1 * 0.1, 0.0));
}
-diff --git a/net/minecraft/world/entity/animal/Wolf.java b/net/minecraft/world/entity/animal/Wolf.java
-index 6cc3893742b443ec84942252910cf444cdbf0c96..90609ff3060322110ece27630de0abae1a6370a8 100644
---- a/net/minecraft/world/entity/animal/Wolf.java
-+++ b/net/minecraft/world/entity/animal/Wolf.java
-@@ -180,9 +180,32 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder(this, Llama.class, 24.0F, 1.5, 1.5));
-@@ -195,6 +218,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder entityType, Level level) {
- super(entityType, level);
-- this.moveControl = new FlyingMoveControl(this, 20, true);
-+ // Purpur start - Ridables
-+ this.purpurController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.1F, 0.5F);
-+ this.moveControl = new FlyingMoveControl(this, 20, true) {
-+ @Override
-+ public void tick() {
-+ if (mob.getRider() != null && mob.isControllable()) {
-+ purpurController.purpurTick(mob.getRider());
-+ } else {
-+ super.tick();
-+ }
-+ }
-+ };
-+ // Purpur end - Ridables
- this.setCanPickUpLoot(this.canPickUpLoot());
- this.vibrationUser = new Allay.VibrationUser();
- this.vibrationData = new VibrationSystem.Data();
-@@ -138,6 +151,28 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
- }
- // CraftBukkit end
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.allayRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.allayRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.allayControllable;
-+ }
-+
-+ @Override
-+ protected void registerGoals() {
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected Brain.Provider brainProvider() {
- return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-@@ -247,6 +282,7 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
- protected void customServerAiStep(ServerLevel level) {
- ProfilerFiller profilerFiller = Profiler.get();
- profilerFiller.push("allayBrain");
-+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider
- this.getBrain().tick(level, this);
- profilerFiller.pop();
- profilerFiller.push("allayActivityUpdate");
-diff --git a/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/net/minecraft/world/entity/animal/armadillo/Armadillo.java
-index dfdbcb31458095a71c187efc2774ecc4945dd11b..87a190d8646d8bbed8c182f9f0f7d8c398e63d26 100644
---- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java
-+++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java
-@@ -80,6 +80,23 @@ public class Armadillo extends Animal {
- return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 12.0).add(Attributes.MOVEMENT_SPEED, 0.14);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.armadilloRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.armadilloRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.armadilloControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
-index 9faa929734035c167e54569ce34d841291856589..2054e4624da0c9b04ea69b9bf39443c4574d48be 100644
---- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java
-+++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
-@@ -115,6 +115,23 @@ public class Axolotl extends Animal implements VariantHolder, B
- this.lookControl = new Axolotl.AxolotlLookControl(this, 20);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.axolotlRidable;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.axolotlControllable;
-+ }
-+
-+ @Override
-+ protected void registerGoals() {
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- public float getWalkTargetValue(BlockPos pos, LevelReader level) {
- return 0.0F;
-@@ -304,6 +321,7 @@ public class Axolotl extends Animal implements VariantHolder, B
- protected void customServerAiStep(ServerLevel level) {
- ProfilerFiller profilerFiller = Profiler.get();
- profilerFiller.push("axolotlBrain");
-+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider
- this.getBrain().tick(level, this);
- profilerFiller.pop();
- profilerFiller.push("axolotlActivityUpdate");
-@@ -555,23 +573,31 @@ public class Axolotl extends Animal implements VariantHolder, B
- }
-
- @Override
-- public void tick() {
-+ public void vanillaTick() { // Purpur - Ridables
- if (!Axolotl.this.isPlayingDead()) {
-- super.tick();
-+ super.vanillaTick(); // Purpur - Ridables
- }
- }
- }
-
- static class AxolotlMoveControl extends SmoothSwimmingMoveControl {
- private final Axolotl axolotl;
-+ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterController; // Purpur - Ridables
-
- public AxolotlMoveControl(Axolotl axolotl) {
- super(axolotl, 85, 10, 0.1F, 0.5F, false);
- this.axolotl = axolotl;
-+ waterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(axolotl, 0.5D); // Purpur - Ridables
- }
-
- @Override
- public void tick() {
-+ // Purpur start - Ridables
-+ if (axolotl.getRider() != null && axolotl.isControllable()) {
-+ waterController.purpurTick(axolotl.getRider());
-+ return;
-+ }
-+ // Purpur end - Ridables
- if (!this.axolotl.isPlayingDead()) {
- super.tick();
- }
-diff --git a/net/minecraft/world/entity/animal/camel/Camel.java b/net/minecraft/world/entity/animal/camel/Camel.java
-index 3ac169f83c5619b5c00c866354a2e066a0a738cc..11311d2ec37d825e73e2218e60e2606dd3a25a1d 100644
---- a/net/minecraft/world/entity/animal/camel/Camel.java
-+++ b/net/minecraft/world/entity/animal/camel/Camel.java
-@@ -83,6 +83,13 @@ public class Camel extends AbstractHorse {
- groundPathNavigation.setCanWalkOverFences(true);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.camelRidableInWater;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
-diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java
-index 12c655b60087a2f6122ffa508b3224159d8777b0..9a400c8bf2b54aa5fbcbe65b61670cac5fbebf05 100644
---- a/net/minecraft/world/entity/animal/frog/Frog.java
-+++ b/net/minecraft/world/entity/animal/frog/Frog.java
-@@ -106,6 +106,8 @@ public class Frog extends Animal implements VariantHolder> {
- public final AnimationState croakAnimationState = new AnimationState();
- public final AnimationState tongueAnimationState = new AnimationState();
- public final AnimationState swimIdleAnimationState = new AnimationState();
-+ private org.purpurmc.purpur.controller.MoveControllerWASD purpurLandController; // Purpur - Ridables
-+ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurWaterController; // Purpur - Ridables
-
- public Frog(EntityType extends Animal> entityType, Level level) {
- super(entityType, level);
-@@ -113,7 +115,55 @@ public class Frog extends Animal implements VariantHolder> {
- this.setPathfindingMalus(PathType.WATER, 4.0F);
- this.setPathfindingMalus(PathType.TRAPDOOR, -1.0F);
- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true);
-+ // Purpur start - Ridables
-+ this.purpurLandController = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.2F);
-+ this.purpurWaterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F);
-+ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) {
-+ @Override
-+ public void tick() {
-+ net.minecraft.world.entity.player.Player rider = mob.getRider();
-+ if (rider != null && mob.isControllable()) {
-+ if (mob.isInWater()) {
-+ purpurWaterController.purpurTick(rider);
-+ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, -0.005D, 0.0D));
-+ } else {
-+ purpurLandController.purpurTick(rider);
-+ }
-+ } else {
-+ super.tick();
-+ }
-+ }
-+ };
-+ // Purpur end - Ridables
-+ }
-+
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.frogRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.frogRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.frogControllable;
-+ }
-+
-+ @Override
-+ protected void registerGoals() {
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-+ }
-+
-+ @Override
-+ public float getJumpPower() {
-+ return (getRider() != null && isControllable()) ? level().purpurConfig.frogRidableJumpHeight * this.getBlockJumpFactor() : super.getJumpPower();
- }
-+ // Purpur end - Ridables
-
- @Override
- protected Brain.Provider brainProvider() {
-@@ -188,6 +238,7 @@ public class Frog extends Animal implements VariantHolder> {
- protected void customServerAiStep(ServerLevel level) {
- ProfilerFiller profilerFiller = Profiler.get();
- profilerFiller.push("frogBrain");
-+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider
- this.getBrain().tick(level, this);
- profilerFiller.pop();
- profilerFiller.push("frogActivityUpdate");
-@@ -380,7 +431,7 @@ public class Frog extends Animal implements VariantHolder> {
- return level.getBlockState(pos.below()).is(BlockTags.FROGS_SPAWNABLE_ON) && isBrightEnoughToSpawn(level, pos);
- }
-
-- class FrogLookControl extends LookControl {
-+ class FrogLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables
- FrogLookControl(final Mob mob) {
- super(mob);
- }
-diff --git a/net/minecraft/world/entity/animal/frog/Tadpole.java b/net/minecraft/world/entity/animal/frog/Tadpole.java
-index 97adf8142cdd322c4873c420ed760e9dee34da23..e888e606b4b14fa6485de7426bc146b6005962af 100644
---- a/net/minecraft/world/entity/animal/frog/Tadpole.java
-+++ b/net/minecraft/world/entity/animal/frog/Tadpole.java
-@@ -63,13 +63,50 @@ public class Tadpole extends AbstractFish {
- MemoryModuleType.IS_PANICKING
- );
- public boolean ageLocked; // Paper
-+ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurController; // Purpur - Ridables
-
- public Tadpole(EntityType extends AbstractFish> entityType, Level level) {
- super(entityType, level);
-- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true);
-+ // Purpur start - Ridables
-+ this.purpurController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F);
-+ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) {
-+ @Override
-+ public void tick() {
-+ Player rider = mob.getRider();
-+ if (rider != null && mob.isControllable()) {
-+ purpurController.purpurTick(rider);
-+ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, 0.002D, 0.0D));
-+ } else {
-+ super.tick();
-+ }
-+ }
-+ };
-+ // Purpur end - Ridables
- this.lookControl = new SmoothSwimmingLookControl(this, 10);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.tadpoleRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.tadpoleRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.tadpoleControllable;
-+ }
-+
-+ @Override
-+ protected void registerGoals() {
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected PathNavigation createNavigation(Level level) {
- return new WaterBoundPathNavigation(this, level);
-@@ -99,6 +136,7 @@ public class Tadpole extends AbstractFish {
- protected void customServerAiStep(ServerLevel level) {
- ProfilerFiller profilerFiller = Profiler.get();
- profilerFiller.push("tadpoleBrain");
-+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider
- this.getBrain().tick(level, this);
- profilerFiller.pop();
- profilerFiller.push("tadpoleActivityUpdate");
-diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java
-index 7b73d4134d30ba8edb69785a2e2eb2d89b2341a7..302208b566038a3a352ca867dd70a61887bac104 100644
---- a/net/minecraft/world/entity/animal/goat/Goat.java
-+++ b/net/minecraft/world/entity/animal/goat/Goat.java
-@@ -111,6 +111,23 @@ public class Goat extends Animal {
- .orElseGet(() -> new ItemStack(Items.GOAT_HORN));
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.goatRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.goatRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.goatControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected Brain.Provider brainProvider() {
- return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-@@ -188,6 +205,7 @@ public class Goat extends Animal {
- protected void customServerAiStep(ServerLevel level) {
- ProfilerFiller profilerFiller = Profiler.get();
- profilerFiller.push("goatBrain");
-+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider
- this.getBrain().tick(level, this);
- profilerFiller.pop();
- profilerFiller.push("goatActivityUpdate");
-diff --git a/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/net/minecraft/world/entity/animal/horse/AbstractHorse.java
-index d52a8315f1e6876c26c732f4c4caa47bc6bebf6e..828406060e50ff62586929371aafb46ef7d81f92 100644
---- a/net/minecraft/world/entity/animal/horse/AbstractHorse.java
-+++ b/net/minecraft/world/entity/animal/horse/AbstractHorse.java
-@@ -206,11 +206,21 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
-
- protected AbstractHorse(EntityType extends AbstractHorse> entityType, Level level) {
- super(entityType, level);
-+ this.moveControl = new net.minecraft.world.entity.ai.control.MoveControl(this); // Purpur - use vanilla controller
-+ this.lookControl = new net.minecraft.world.entity.ai.control.LookControl(this); // Purpur - use vanilla controller
- this.createInventory();
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return false; // vanilla handles
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void registerGoals() {
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(1, new PanicGoal(this, 1.2));
- this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2));
- this.goalSelector.addGoal(2, new BreedGoal(this, 1.0, AbstractHorse.class));
-@@ -221,6 +231,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
- if (this.canPerformRearing()) {
- this.goalSelector.addGoal(9, new RandomStandGoal(this));
- }
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables
-
- this.addBehaviourGoals();
- }
-diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java
-index 9b97f3d3675f5051b18a68ff7fa056d859a283e9..ee3fa710e95f2e84f7f9bdce1159d1136815172d 100644
---- a/net/minecraft/world/entity/animal/horse/Donkey.java
-+++ b/net/minecraft/world/entity/animal/horse/Donkey.java
-@@ -16,6 +16,13 @@ public class Donkey extends AbstractChestedHorse {
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.donkeyRidableInWater;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected SoundEvent getAmbientSound() {
- return SoundEvents.DONKEY_AMBIENT;
-diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java
-index c6d0700f29d6c8123e96efe225faf2d99202ac81..361bf346153912bcbfcf962d7f716dfe12ae2a7b 100644
---- a/net/minecraft/world/entity/animal/horse/Horse.java
-+++ b/net/minecraft/world/entity/animal/horse/Horse.java
-@@ -43,6 +43,13 @@ public class Horse extends AbstractHorse implements VariantHolder {
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.horseRidableInWater;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void randomizeAttributes(RandomSource random) {
- this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt));
-diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java
-index 7d4aad3c45d710488aba540ee5a535098ddd27ee..164a429d432badcb315e8ece406e29e576a11265 100644
---- a/net/minecraft/world/entity/animal/horse/Llama.java
-+++ b/net/minecraft/world/entity/animal/horse/Llama.java
-@@ -78,7 +78,51 @@ public class Llama extends AbstractChestedHorse implements VariantHolder entityType, Level level) {
+ public EnderDragon(EntityType extends EnderDragon> type, Level level) {
super(EntityType.ENDER_DRAGON, level);
@@ -106,6 +107,37 @@ public class EnderDragon extends Mob implements Enemy {
this.noPhysics = true;
@@ -2705,7 +2808,7 @@ index f7e6866404af629ae0b20425202f592d76df4f3d..bc9564ee22ff9d7f6d819da9601c2d81
+ // Purpur end - Ridables
+
public static AttributeSupplier.Builder createAttributes() {
- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0);
+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0).add(Attributes.CAMERA_DISTANCE, 16.0);
}
@@ -169,6 +212,37 @@ public class EnderDragon extends Mob implements Enemy {
@@ -2743,7 +2846,7 @@ index f7e6866404af629ae0b20425202f592d76df4f3d..bc9564ee22ff9d7f6d819da9601c2d81
+ // Purpur end - Ridables
+
this.processFlappingMovement();
- if (this.level().isClientSide) {
+ if (this.level().isClientSide()) {
this.setHealth(this.getHealth());
@@ -197,6 +271,8 @@ public class EnderDragon extends Mob implements Enemy {
@@ -2775,7 +2878,7 @@ index f7e6866404af629ae0b20425202f592d76df4f3d..bc9564ee22ff9d7f6d819da9601c2d81
DragonPhaseInstance currentPhase = this.phaseManager.getCurrentPhase();
currentPhase.doServerTick(serverLevel1);
if (this.phaseManager.getCurrentPhase() != currentPhase) {
-@@ -298,7 +374,7 @@ public class EnderDragon extends Mob implements Enemy {
+@@ -294,7 +370,7 @@ public class EnderDragon extends Mob implements Enemy {
this.tickPart(this.body, sin1 * 0.5F, 0.0, -cos1 * 0.5F);
this.tickPart(this.wing1, cos1 * 4.5F, 2.0, sin1 * 4.5F);
this.tickPart(this.wing2, cos1 * -4.5F, 2.0, sin1 * -4.5F);
@@ -2784,7 +2887,7 @@ index f7e6866404af629ae0b20425202f592d76df4f3d..bc9564ee22ff9d7f6d819da9601c2d81
this.knockBack(
serverLevel2,
serverLevel2.getEntities(
-@@ -348,9 +424,9 @@ public class EnderDragon extends Mob implements Enemy {
+@@ -344,9 +420,9 @@ public class EnderDragon extends Mob implements Enemy {
}
if (this.level() instanceof ServerLevel serverLevel3) {
@@ -2796,11 +2899,29 @@ index f7e6866404af629ae0b20425202f592d76df4f3d..bc9564ee22ff9d7f6d819da9601c2d81
if (this.dragonFight != null) {
this.dragonFight.updateDragon(this);
}
+diff --git a/net/minecraft/world/entity/boss/enderdragon/EnderDragonPart.java b/net/minecraft/world/entity/boss/enderdragon/EnderDragonPart.java
+index 41200efbaa29ee487c0383b261122e0701413865..871adbd10f49a4d59820c089da149a47de424656 100644
+--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragonPart.java
++++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragonPart.java
+@@ -27,6 +27,13 @@ public class EnderDragonPart extends Entity {
+ this.name = name;
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public net.minecraft.world.InteractionResult interact(net.minecraft.world.entity.player.Player player, net.minecraft.world.InteractionHand hand) {
++ return parentMob.isAlive() ? parentMob.tryRide(player, hand) : net.minecraft.world.InteractionResult.PASS;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ }
diff --git a/net/minecraft/world/entity/boss/wither/WitherBoss.java b/net/minecraft/world/entity/boss/wither/WitherBoss.java
-index 95cf215e8804cc2d7b681723dfebd1dcb8cbaeee..5d97ae09292fb3209e7362df778e88dc508815a3 100644
+index f170db52921583050786050cf7fdaee439117bb8..dbf3c7049fae08dc5c4ac491a5fc8141ab177a22 100644
--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java
+++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java
-@@ -69,6 +69,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+@@ -72,6 +72,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
private final int[] nextHeadUpdate = new int[2];
private final int[] idleHeadUpdates = new int[2];
private int destroyBlocksTick;
@@ -2808,14 +2929,14 @@ index 95cf215e8804cc2d7b681723dfebd1dcb8cbaeee..5d97ae09292fb3209e7362df778e88dc
private boolean canPortal = false; // Paper
public final ServerBossEvent bossEvent = (ServerBossEvent)new ServerBossEvent(
this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS
-@@ -78,9 +79,23 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+@@ -81,9 +82,23 @@ public class WitherBoss extends Monster implements RangedAttackMob {
&& entity.attackable();
private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0).selector(LIVING_ENTITY_SELECTOR);
- @Nullable private java.util.UUID summoner; // Purpur - Summoner API
+ private java.util.@Nullable UUID summoner; // Purpur - Summoner API
+ private org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD purpurController; // Purpur - Ridables
- public WitherBoss(EntityType extends WitherBoss> entityType, Level level) {
- super(entityType, level);
+ public WitherBoss(EntityType extends WitherBoss> type, Level level) {
+ super(type, level);
+ // Purpur start - Ridables
+ this.purpurController = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.1F);
+ this.moveControl = new FlyingMoveControl(this, 10, false) {
@@ -2832,7 +2953,7 @@ index 95cf215e8804cc2d7b681723dfebd1dcb8cbaeee..5d97ae09292fb3209e7362df778e88dc
this.moveControl = new FlyingMoveControl(this, 10, false);
this.setHealth(this.getMaxHealth());
this.xpReward = 50;
-@@ -97,6 +112,105 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+@@ -99,6 +114,105 @@ public class WitherBoss extends Monster implements RangedAttackMob {
}
// Purpur end - Summoner API
@@ -2938,7 +3059,7 @@ index 95cf215e8804cc2d7b681723dfebd1dcb8cbaeee..5d97ae09292fb3209e7362df778e88dc
@Override
protected PathNavigation createNavigation(Level level) {
FlyingPathNavigation flyingPathNavigation = new FlyingPathNavigation(this, level);
-@@ -107,11 +221,13 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+@@ -109,11 +223,13 @@ public class WitherBoss extends Monster implements RangedAttackMob {
@Override
protected void registerGoals() {
@@ -2952,7 +3073,7 @@ index 95cf215e8804cc2d7b681723dfebd1dcb8cbaeee..5d97ae09292fb3209e7362df778e88dc
this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 0, false, false, LIVING_ENTITY_SELECTOR));
}
-@@ -271,6 +387,15 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+@@ -273,6 +389,15 @@ public class WitherBoss extends Monster implements RangedAttackMob {
@Override
protected void customServerAiStep(ServerLevel level) {
@@ -2968,7 +3089,7 @@ index 95cf215e8804cc2d7b681723dfebd1dcb8cbaeee..5d97ae09292fb3209e7362df778e88dc
if (this.getInvulnerableTicks() > 0) {
int i = this.getInvulnerableTicks() - 1;
this.bossEvent.setProgress(1.0F - i / 220.0F);
-@@ -577,11 +702,11 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+@@ -579,11 +704,11 @@ public class WitherBoss extends Monster implements RangedAttackMob {
}
public int getAlternativeTarget(int head) {
@@ -2982,38 +3103,19 @@ index 95cf215e8804cc2d7b681723dfebd1dcb8cbaeee..5d97ae09292fb3209e7362df778e88dc
}
public boolean isPowered() {
-diff --git a/net/minecraft/world/entity/monster/AbstractSkeleton.java b/net/minecraft/world/entity/monster/AbstractSkeleton.java
-index 1e97cb34aa22ad3150b598232dd339213b236f5c..e186aee80b052b7fc4bfe02763010bfb2d55ea35 100644
---- a/net/minecraft/world/entity/monster/AbstractSkeleton.java
-+++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java
-@@ -73,12 +73,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
-
- @Override
- protected void registerGoals() {
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(2, new RestrictSunGoal(this));
- this.goalSelector.addGoal(3, new FleeSunGoal(this, 1.0));
- this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Wolf.class, 6.0F, 1.0, 1.2));
- this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0));
- this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F));
- this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
- this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
diff --git a/net/minecraft/world/entity/monster/Blaze.java b/net/minecraft/world/entity/monster/Blaze.java
-index 419c729502ee708bba9e750f1b951450eca82695..201b08a75c42d90e657c3d56fc6691839e87199c 100644
+index f5539b27261755380312b392fee836cbaaff2e56..1febee23188d91e2a27c182b97502e8c7ab696a2 100644
--- a/net/minecraft/world/entity/monster/Blaze.java
+++ b/net/minecraft/world/entity/monster/Blaze.java
-@@ -33,6 +33,7 @@ public class Blaze extends Monster {
+@@ -34,6 +34,7 @@ public class Blaze extends Monster {
- public Blaze(EntityType extends Blaze> entityType, Level level) {
- super(entityType, level);
+ public Blaze(EntityType extends Blaze> type, Level level) {
+ super(type, level);
+ this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur - Ridables
this.setPathfindingMalus(PathType.WATER, -1.0F);
this.setPathfindingMalus(PathType.LAVA, 8.0F);
this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F);
-@@ -40,19 +41,55 @@ public class Blaze extends Monster {
+@@ -41,19 +42,55 @@ public class Blaze extends Monster {
this.xpReward = 10;
}
@@ -3070,7 +3172,7 @@ index 419c729502ee708bba9e750f1b951450eca82695..201b08a75c42d90e657c3d56fc669183
}
@Override
-@@ -117,6 +154,13 @@ public class Blaze extends Monster {
+@@ -118,6 +155,13 @@ public class Blaze extends Monster {
@Override
protected void customServerAiStep(ServerLevel level) {
@@ -3084,69 +3186,13 @@ index 419c729502ee708bba9e750f1b951450eca82695..201b08a75c42d90e657c3d56fc669183
this.nextHeightOffsetChangeTick--;
if (this.nextHeightOffsetChangeTick <= 0) {
this.nextHeightOffsetChangeTick = 100;
-diff --git a/net/minecraft/world/entity/monster/Bogged.java b/net/minecraft/world/entity/monster/Bogged.java
-index f01670f7106a39957c9b37839fcca0d9f29208f0..2b603c1242aac307f28bae5a85bcaad309f929f5 100644
---- a/net/minecraft/world/entity/monster/Bogged.java
-+++ b/net/minecraft/world/entity/monster/Bogged.java
-@@ -41,6 +41,23 @@ public class Bogged extends AbstractSkeleton implements Shearable {
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.boggedRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.boggedRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.boggedControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/monster/CaveSpider.java b/net/minecraft/world/entity/monster/CaveSpider.java
-index 2e32567fca7a2a4cd87bc078a6eeb30e3ffabfce..4873a3d8dd9c160ecdbda594ee546c35ec03a1e7 100644
---- a/net/minecraft/world/entity/monster/CaveSpider.java
-+++ b/net/minecraft/world/entity/monster/CaveSpider.java
-@@ -26,6 +26,23 @@ public class CaveSpider extends Spider {
- return Spider.createAttributes().add(Attributes.MAX_HEALTH, 12.0);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.caveSpiderRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.caveSpiderRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.caveSpiderControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- public boolean doHurtTarget(ServerLevel level, Entity source) {
- if (super.doHurtTarget(level, source)) {
diff --git a/net/minecraft/world/entity/monster/Creeper.java b/net/minecraft/world/entity/monster/Creeper.java
-index 9aff3c911a56885ab3c34bb34bb05e7b1c00d3bd..cdcee233ed0c272e4a68a2a709fe92b21bc6c22c 100644
+index 168003b7159b5e9ea3e3ca19d0b939ed1cfd2311..cfd09a5ff326cf4ecc248901696ce1f623a8e7c0 100644
--- a/net/minecraft/world/entity/monster/Creeper.java
+++ b/net/minecraft/world/entity/monster/Creeper.java
-@@ -51,21 +51,98 @@ public class Creeper extends Monster {
- private int droppedSkulls;
- public Entity entityIgniter; // CraftBukkit
+@@ -57,21 +57,98 @@ public class Creeper extends Monster {
+ public boolean droppedSkulls;
+ public @Nullable Entity entityIgniter; // CraftBukkit
private boolean exploding = false; // Purpur - Config to make Creepers explode on death
+ // Purpur start - Ridables
+ private int spacebarCharge = 0;
@@ -3154,8 +3200,8 @@ index 9aff3c911a56885ab3c34bb34bb05e7b1c00d3bd..cdcee233ed0c272e4a68a2a709fe92b2
+ private int powerToggleDelay = 0;
+ // Purpur end - Ridables
- public Creeper(EntityType extends Creeper> entityType, Level level) {
- super(entityType, level);
+ public Creeper(EntityType extends Creeper> type, Level level) {
+ super(type, level);
}
+ // Purpur start - Ridables
@@ -3243,7 +3289,7 @@ index 9aff3c911a56885ab3c34bb34bb05e7b1c00d3bd..cdcee233ed0c272e4a68a2a709fe92b2
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, true));
this.targetSelector.addGoal(2, new HurtByTargetGoal(this));
}
-@@ -312,6 +389,7 @@ public class Creeper extends Monster {
+@@ -314,6 +391,7 @@ public class Creeper extends Monster {
com.destroystokyo.paper.event.entity.CreeperIgniteEvent event = new com.destroystokyo.paper.event.entity.CreeperIgniteEvent((org.bukkit.entity.Creeper) getBukkitEntity(), ignited);
if (event.callEvent()) {
this.entityData.set(DATA_IS_IGNITED, event.isIgnited());
@@ -3251,72 +3297,8 @@ index 9aff3c911a56885ab3c34bb34bb05e7b1c00d3bd..cdcee233ed0c272e4a68a2a709fe92b2
}
}
}
-diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java
-index 6c1e816356243686f7d0bfa031badc75b54b215d..c1da9ebee7e870a9143e6224be9e9f4e62232459 100644
---- a/net/minecraft/world/entity/monster/Drowned.java
-+++ b/net/minecraft/world/entity/monster/Drowned.java
-@@ -75,6 +75,23 @@ public class Drowned extends Zombie implements RangedAttackMob {
- return Zombie.createAttributes().add(Attributes.STEP_HEIGHT, 1.0);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.drownedRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.drownedRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.drownedControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void addBehaviourGoals() {
- this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0));
-@@ -408,7 +425,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
- }
- }
-
-- static class DrownedMoveControl extends MoveControl {
-+ static class DrownedMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables
- private final Drowned drowned;
-
- public DrownedMoveControl(Drowned mob) {
-@@ -417,7 +434,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
- }
-
- @Override
-- public void tick() {
-+ public void vanillaTick() { // Purpur - Ridables
- LivingEntity target = this.drowned.getTarget();
- if (this.drowned.wantsToSwim() && this.drowned.isInWater()) {
- if (target != null && target.getY() > this.drowned.getY() || this.drowned.searchingForLand) {
-@@ -437,7 +454,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
- float f = (float)(Mth.atan2(d2, d) * 180.0F / (float)Math.PI) - 90.0F;
- this.drowned.setYRot(this.rotlerp(this.drowned.getYRot(), f, 90.0F));
- this.drowned.yBodyRot = this.drowned.getYRot();
-- float f1 = (float)(this.speedModifier * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED));
-+ float f1 = (float)(this.getSpeedModifier() * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables
- float f2 = Mth.lerp(0.125F, this.drowned.getSpeed(), f1);
- this.drowned.setSpeed(f2);
- this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(f2 * d * 0.005, f2 * d1 * 0.1, f2 * d2 * 0.005));
-@@ -446,7 +463,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
- this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(0.0, -0.008, 0.0));
- }
-
-- super.tick();
-+ super.vanillaTick(); // Purpur - Ridables
- }
- }
- }
diff --git a/net/minecraft/world/entity/monster/ElderGuardian.java b/net/minecraft/world/entity/monster/ElderGuardian.java
-index 4585b7c867685f8419c4d2b5b90af5946d337f90..c6eeaf7b460408acfdf89d988b47b08eab7df4c5 100644
+index 3a16eb269b733fcf1db5dbc2dfae13009e2278b5..e5d16ca14a40d520dce43dd3d9b6347aefbd25d7 100644
--- a/net/minecraft/world/entity/monster/ElderGuardian.java
+++ b/net/minecraft/world/entity/monster/ElderGuardian.java
@@ -31,6 +31,18 @@ public class ElderGuardian extends Guardian {
@@ -3339,10 +3321,10 @@ index 4585b7c867685f8419c4d2b5b90af5946d337f90..c6eeaf7b460408acfdf89d988b47b08e
return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.3F).add(Attributes.ATTACK_DAMAGE, 8.0).add(Attributes.MAX_HEALTH, 80.0);
}
diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
-index 8709588083fd5ca6a31d9a8d4096475d117915a1..cf511c78638e0d7aa652d1c880b3cd8172d5b3cf 100644
+index 2d903c77017ae356eb309df3c2c43b91c4e52f2f..bd78d8c3e8c1d9b581c751d336322fbfe20dacef 100644
--- a/net/minecraft/world/entity/monster/EnderMan.java
+++ b/net/minecraft/world/entity/monster/EnderMan.java
-@@ -90,9 +90,27 @@ public class EnderMan extends Monster implements NeutralMob {
+@@ -89,9 +89,27 @@ public class EnderMan extends Monster implements NeutralMob {
this.setPathfindingMalus(PathType.WATER, -1.0F);
}
@@ -3370,7 +3352,7 @@ index 8709588083fd5ca6a31d9a8d4096475d117915a1..cf511c78638e0d7aa652d1c880b3cd81
this.goalSelector.addGoal(1, new EnderMan.EndermanFreezeWhenLookedAt(this));
this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0, false));
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0, 0.0F));
-@@ -100,6 +118,7 @@ public class EnderMan extends Monster implements NeutralMob {
+@@ -99,6 +117,7 @@ public class EnderMan extends Monster implements NeutralMob {
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
this.goalSelector.addGoal(10, new EnderMan.EndermanLeaveBlockGoal(this));
this.goalSelector.addGoal(11, new EnderMan.EndermanTakeBlockGoal(this));
@@ -3378,28 +3360,28 @@ index 8709588083fd5ca6a31d9a8d4096475d117915a1..cf511c78638e0d7aa652d1c880b3cd81
this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt));
this.targetSelector.addGoal(2, new HurtByTargetGoal(this));
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, 10, true, false, (entityliving, ignored) -> entityliving.level().purpurConfig.endermanAggroEndermites && entityliving instanceof Endermite endermite && (!entityliving.level().purpurConfig.endermanAggroEndermitesOnlyIfPlayerSpawned || endermite.isPlayerSpawned()))); // Purpur
-@@ -272,7 +291,7 @@ public class EnderMan extends Monster implements NeutralMob {
+@@ -263,7 +282,7 @@ public class EnderMan extends Monster implements NeutralMob {
@Override
protected void customServerAiStep(ServerLevel level) {
-- if (level.isDay() && this.tickCount >= this.targetChangeTime + 600) {
-+ if ((getRider() == null || !this.isControllable()) && level.isDay() && this.tickCount >= this.targetChangeTime + 600) { // Purpur - Ridables - no random teleporting
+- if (level.isBrightOutside() && this.tickCount >= this.targetChangeTime + 600) {
++ if ((getRider() == null || !this.isControllable()) && level.isBrightOutside() && this.tickCount >= this.targetChangeTime + 600) { // Purpur - Ridables - no random teleporting
float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue();
if (lightLevelDependentMagicValue > 0.5F
&& level.canSeeSky(this.blockPosition())
-@@ -385,6 +404,7 @@ public class EnderMan extends Monster implements NeutralMob {
+@@ -375,6 +394,7 @@ public class EnderMan extends Monster implements NeutralMob {
public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) {
if (this.isInvulnerableTo(level, damageSource)) {
return false;
+ } else if (getRider() != null && this.isControllable()) { return super.hurtServer(level, damageSource, amount); // Purpur - no teleporting on damage
} else if (org.purpurmc.purpur.PurpurConfig.endermanShortHeight && damageSource.is(net.minecraft.world.damagesource.DamageTypes.IN_WALL)) { return false; // Purpur - no suffocation damage if short height - Short enderman height
} else {
- boolean flag = damageSource.getDirectEntity() instanceof ThrownPotion;
+ AbstractThrownPotion abstractThrownPotion1 = damageSource.getDirectEntity() instanceof AbstractThrownPotion abstractThrownPotion
diff --git a/net/minecraft/world/entity/monster/Endermite.java b/net/minecraft/world/entity/monster/Endermite.java
-index 4e00daa6ece386f70502c074084b7b1b64caac2f..f4ab2e984dd87d2372aa10d2cbfd03a3f6fb1249 100644
+index 980ec0e45581812c027bb2ce8cd25d74e5f10663..844ba943a2a752f9b25506b644a4b4abc981b4cb 100644
--- a/net/minecraft/world/entity/monster/Endermite.java
+++ b/net/minecraft/world/entity/monster/Endermite.java
-@@ -45,14 +45,33 @@ public class Endermite extends Monster {
+@@ -47,14 +47,33 @@ public class Endermite extends Monster {
}
// Purpur end - Add back player spawned endermite API
@@ -3433,53 +3415,12 @@ index 4e00daa6ece386f70502c074084b7b1b64caac2f..f4ab2e984dd87d2372aa10d2cbfd03a3
this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers());
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
}
-diff --git a/net/minecraft/world/entity/monster/Evoker.java b/net/minecraft/world/entity/monster/Evoker.java
-index b70ea1af39cada6bb17001c6b65502510e34c4b2..2eaeb0c0c0cb917506443ed1380b81f317961d53 100644
---- a/net/minecraft/world/entity/monster/Evoker.java
-+++ b/net/minecraft/world/entity/monster/Evoker.java
-@@ -50,10 +50,28 @@ public class Evoker extends SpellcasterIllager {
- this.xpReward = 10;
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.evokerRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.evokerRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.evokerControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new FloatGoal(this));
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(1, new Evoker.EvokerCastingSpellGoal());
- this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 0.6, 1.0));
- this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 0.6, 1.0));
-@@ -63,6 +81,7 @@ public class Evoker extends SpellcasterIllager {
- this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6));
- this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F));
- this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
- this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true).setUnseenMemoryTicks(300));
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false).setUnseenMemoryTicks(300));
diff --git a/net/minecraft/world/entity/monster/Ghast.java b/net/minecraft/world/entity/monster/Ghast.java
-index b97bbfbbc8c1a4f38b4b858ef4915b637cc8a627..00c05fb5736c90c94f6fe51793acf8b65b1d0505 100644
+index b8774eb91d21e9f154cc70c5d3bd26de25be41c4..451627153610f2c8db2403f73545c9af6dfd2e4b 100644
--- a/net/minecraft/world/entity/monster/Ghast.java
+++ b/net/minecraft/world/entity/monster/Ghast.java
-@@ -42,11 +42,47 @@ public class Ghast extends FlyingMob implements Enemy {
- this.moveControl = new Ghast.GhastMoveControl(this);
+@@ -53,11 +53,35 @@ public class Ghast extends Mob implements Enemy {
+ this.moveControl = new Ghast.GhastMoveControl(this, false, () -> false);
}
+ // Purpur start - Ridables
@@ -3502,18 +3443,6 @@ index b97bbfbbc8c1a4f38b4b858ef4915b637cc8a627..00c05fb5736c90c94f6fe51793acf8b6
+ public double getMaxY() {
+ return level().purpurConfig.ghastMaxY;
+ }
-+
-+ @Override
-+ public void travel(Vec3 vec3) {
-+ super.travel(vec3);
-+ if (getRider() != null && this.isControllable() && !onGround) {
-+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED);
-+ setSpeed(speed);
-+ Vec3 mot = getDeltaMovement();
-+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed));
-+ setDeltaMovement(mot.scale(0.9D));
-+ }
-+ }
+ // Purpur end - Ridables
+
@Override
@@ -3526,39 +3455,46 @@ index b97bbfbbc8c1a4f38b4b858ef4915b637cc8a627..00c05fb5736c90c94f6fe51793acf8b6
this.targetSelector
.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entity, level) -> Math.abs(entity.getY() - this.getY()) <= 4.0));
}
-@@ -101,7 +137,7 @@ public class Ghast extends FlyingMob implements Enemy {
- }
-
- public static AttributeSupplier.Builder createAttributes() {
-- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.FOLLOW_RANGE, 100.0);
-+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.FOLLOW_RANGE, 100.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - Ridables
+@@ -102,6 +126,15 @@ public class Ghast extends Mob implements Enemy {
+ @Override
+ public void travel(Vec3 travelVector) {
+ this.travelFlying(travelVector, 0.02F);
++ // Purpur start - Ridables
++ if (getRider() != null && this.isControllable() && !onGround) {
++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED);
++ setSpeed(speed);
++ Vec3 mot = getDeltaMovement();
++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed));
++ setDeltaMovement(mot.scale(0.9D));
++ }
++ // Purpur end - Ridables
}
@Override
-@@ -191,7 +227,7 @@ public class Ghast extends FlyingMob implements Enemy {
+@@ -237,7 +270,7 @@ public class Ghast extends Mob implements Enemy {
}
}
-- static class GhastMoveControl extends MoveControl {
-+ static class GhastMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - Ridables
- private final Ghast ghast;
+- public static class GhastMoveControl extends MoveControl {
++ public static class GhastMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - Ridables
+ private final Mob ghast;
private int floatDuration;
-
-@@ -201,7 +237,7 @@ public class Ghast extends FlyingMob implements Enemy {
+ private final boolean careful;
+@@ -251,7 +284,7 @@ public class Ghast extends Mob implements Enemy {
}
@Override
- public void tick() {
+ public void vanillaTick() { // Purpur - Ridables
- if (this.operation == MoveControl.Operation.MOVE_TO) {
- if (this.floatDuration-- <= 0) {
- this.floatDuration = this.floatDuration + this.ghast.getRandom().nextInt(5) + 2;
+ if (this.shouldBeStopped.getAsBoolean()) {
+ this.operation = MoveControl.Operation.WAIT;
+ this.ghast.stopInPlace();
diff --git a/net/minecraft/world/entity/monster/Giant.java b/net/minecraft/world/entity/monster/Giant.java
-index 969eb604851d1cce50f0f99ed479189061d5de0c..135f83484ac31db7dcc225ba6f94e2e4ca27eea8 100644
+index 0de6a20a3fed53bd11a0152de6953bfaecc85289..dcbe6bbce0baa4fad7fe180944beeb6ca4026f7d 100644
--- a/net/minecraft/world/entity/monster/Giant.java
+++ b/net/minecraft/world/entity/monster/Giant.java
@@ -12,6 +12,29 @@ public class Giant extends Monster {
- super(entityType, level);
+ super(type, level);
}
+ // Purpur start - Ridables
@@ -3585,13 +3521,13 @@ index 969eb604851d1cce50f0f99ed479189061d5de0c..135f83484ac31db7dcc225ba6f94e2e4
+ // Purpur end - Ridables
+
public static AttributeSupplier.Builder createAttributes() {
- return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0);
- }
+ return Monster.createMonsterAttributes()
+ .add(Attributes.MAX_HEALTH, 100.0)
diff --git a/net/minecraft/world/entity/monster/Guardian.java b/net/minecraft/world/entity/monster/Guardian.java
-index c8e249b8f7ee8e9c075169ec988f5a0d459a3767..c20c744522459d938c772077e542ba433bc4c80e 100644
+index 9c91fbfd39af513668bd94578810cef7e283abd9..4cf54e55de1ecc57061ad0c09e7966d6104f1cc2 100644
--- a/net/minecraft/world/entity/monster/Guardian.java
+++ b/net/minecraft/world/entity/monster/Guardian.java
-@@ -66,14 +66,35 @@ public class Guardian extends Monster {
+@@ -65,14 +65,35 @@ public class Guardian extends Monster {
this.xpReward = 10;
this.setPathfindingMalus(PathType.WATER, 0.0F);
this.moveControl = new Guardian.GuardianMoveControl(this);
@@ -3627,7 +3563,7 @@ index c8e249b8f7ee8e9c075169ec988f5a0d459a3767..c20c744522459d938c772077e542ba43
this.goalSelector.addGoal(4, this.guardianAttackGoal = new Guardian.GuardianAttackGoal(this)); // CraftBukkit - assign field
this.goalSelector.addGoal(5, moveTowardsRestrictionGoal);
this.goalSelector.addGoal(7, this.randomStrollGoal);
-@@ -82,6 +103,7 @@ public class Guardian extends Monster {
+@@ -81,6 +102,7 @@ public class Guardian extends Monster {
this.goalSelector.addGoal(9, new RandomLookAroundGoal(this));
this.randomStrollGoal.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
moveTowardsRestrictionGoal.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
@@ -3635,16 +3571,16 @@ index c8e249b8f7ee8e9c075169ec988f5a0d459a3767..c20c744522459d938c772077e542ba43
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 10, true, false, new Guardian.GuardianAttackSelector(this)));
}
-@@ -344,7 +366,7 @@ public class Guardian extends Monster {
+@@ -346,7 +368,7 @@ public class Guardian extends Monster {
+
@Override
- public void travel(Vec3 travelVector) {
- if (this.isControlledByLocalInstance() && this.isInWater()) {
-- this.moveRelative(0.1F, travelVector);
-+ this.moveRelative(getRider() != null && this.isControllable() ? getSpeed() : 0.1F, travelVector); // Purpur - Ridables
- this.move(MoverType.SELF, this.getDeltaMovement());
- this.setDeltaMovement(this.getDeltaMovement().scale(0.9));
- if (!this.isMoving() && this.getTarget() == null) {
-@@ -452,7 +474,7 @@ public class Guardian extends Monster {
+ protected void travelInWater(Vec3 travelVector, double gravity, boolean isFalling, double previousY) {
+- this.moveRelative(0.1F, travelVector);
++ this.moveRelative(getRider() != null && this.isControllable() ? getSpeed() : 0.1F, travelVector); // Purpur - Ridables
+ this.move(MoverType.SELF, this.getDeltaMovement());
+ this.setDeltaMovement(this.getDeltaMovement().scale(0.9));
+ if (!this.isMoving() && this.getTarget() == null) {
+@@ -451,7 +473,7 @@ public class Guardian extends Monster {
}
}
@@ -3653,7 +3589,7 @@ index c8e249b8f7ee8e9c075169ec988f5a0d459a3767..c20c744522459d938c772077e542ba43
private final Guardian guardian;
public GuardianMoveControl(Guardian mob) {
-@@ -460,8 +482,17 @@ public class Guardian extends Monster {
+@@ -459,8 +481,17 @@ public class Guardian extends Monster {
this.guardian = mob;
}
@@ -3672,7 +3608,7 @@ index c8e249b8f7ee8e9c075169ec988f5a0d459a3767..c20c744522459d938c772077e542ba43
if (this.operation == MoveControl.Operation.MOVE_TO && !this.guardian.getNavigation().isDone()) {
Vec3 vec3 = new Vec3(this.wantedX - this.guardian.getX(), this.wantedY - this.guardian.getY(), this.wantedZ - this.guardian.getZ());
double len = vec3.length();
-@@ -471,7 +502,7 @@ public class Guardian extends Monster {
+@@ -470,7 +501,7 @@ public class Guardian extends Monster {
float f = (float)(Mth.atan2(vec3.z, vec3.x) * 180.0F / (float)Math.PI) - 90.0F;
this.guardian.setYRot(this.rotlerp(this.guardian.getYRot(), f, 90.0F));
this.guardian.yBodyRot = this.guardian.getYRot();
@@ -3681,81 +3617,12 @@ index c8e249b8f7ee8e9c075169ec988f5a0d459a3767..c20c744522459d938c772077e542ba43
float f2 = Mth.lerp(0.125F, this.guardian.getSpeed(), f1);
this.guardian.setSpeed(f2);
double d3 = Math.sin((this.guardian.tickCount + this.guardian.getId()) * 0.5) * 0.05;
-diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java
-index 6155c544ad2722a49c5e41dd7d7b02fedc56474e..23936305045299352561e866b6a28aa515cd614a 100644
---- a/net/minecraft/world/entity/monster/Husk.java
-+++ b/net/minecraft/world/entity/monster/Husk.java
-@@ -21,6 +21,23 @@ public class Husk extends Zombie {
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.huskRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.huskRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.huskControllable;
-+ }
-+ // Purpur end - Ridables
-+
- public static boolean checkHuskSpawnRules(
- EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
- ) {
-diff --git a/net/minecraft/world/entity/monster/Illusioner.java b/net/minecraft/world/entity/monster/Illusioner.java
-index 40ca12e391b2adac6b132f1832b1427acb3748bc..bd0f4d77260f5b123856fc7e72d5f8e74bb45321 100644
---- a/net/minecraft/world/entity/monster/Illusioner.java
-+++ b/net/minecraft/world/entity/monster/Illusioner.java
-@@ -57,10 +57,28 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
- }
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.illusionerRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.illusionerRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.illusionerControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new FloatGoal(this));
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(1, new SpellcasterIllager.SpellcasterCastingSpellGoal());
- this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2));
- this.goalSelector.addGoal(4, new Illusioner.IllusionerMirrorSpellGoal());
-@@ -69,6 +87,7 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
- this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6));
- this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F));
- this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
- this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true).setUnseenMemoryTicks(300));
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false).setUnseenMemoryTicks(300));
diff --git a/net/minecraft/world/entity/monster/MagmaCube.java b/net/minecraft/world/entity/monster/MagmaCube.java
-index 905ecbd8b22c785ee4ea18004ac50eb1b7005d3f..f10b204c18b88e9110cebf050b60c23367ea3aa0 100644
+index 969736a46c85b2fcaa641c2863e6000b51611df5..a3cd6d4b999fc49893794838c73370c19c6a66b6 100644
--- a/net/minecraft/world/entity/monster/MagmaCube.java
+++ b/net/minecraft/world/entity/monster/MagmaCube.java
@@ -24,6 +24,28 @@ public class MagmaCube extends Slime {
- super(entityType, level);
+ super(type, level);
}
+ // Purpur start - Ridables
@@ -3783,19 +3650,19 @@ index 905ecbd8b22c785ee4ea18004ac50eb1b7005d3f..f10b204c18b88e9110cebf050b60c233
public static AttributeSupplier.Builder createAttributes() {
return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F);
}
-@@ -71,6 +93,7 @@ public class MagmaCube extends Slime {
+@@ -76,6 +98,7 @@ public class MagmaCube extends Slime {
float f = this.getSize() * 0.1F;
this.setDeltaMovement(deltaMovement.x, this.getJumpPower() + f, deltaMovement.z);
- this.hasImpulse = true;
+ this.needsSync = true;
+ this.actualJump = false; // Purpur - Ridables
}
@Override
diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
-index 9ea3acd5ff3d7751875d61861aa5f6c717d0b5e2..75c6a43a3ab4851a47990402bee49f7e8305cd60 100644
+index d26b7970490a2a108affee11c3fb74e38509d92b..64e55d48bc81d6237970e86e6e1cc719831902fd 100644
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
-@@ -60,6 +60,64 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -61,6 +61,52 @@ public class Phantom extends Mob implements Enemy {
this.lookControl = new Phantom.PhantomLookControl(this);
}
@@ -3820,18 +3687,6 @@ index 9ea3acd5ff3d7751875d61861aa5f6c717d0b5e2..75c6a43a3ab4851a47990402bee49f7e
+ return level().purpurConfig.phantomMaxY;
+ }
+
-+ @Override
-+ public void travel(Vec3 vec3) {
-+ super.travel(vec3);
-+ if (getRider() != null && this.isControllable() && !onGround) {
-+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED);
-+ setSpeed(speed);
-+ Vec3 mot = getDeltaMovement();
-+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed));
-+ setDeltaMovement(mot.scale(0.9D));
-+ }
-+ }
-+
+ public static net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder createAttributes() {
+ return Monster.createMonsterAttributes().add(Attributes.FLYING_SPEED, 3.0D);
+ }
@@ -3860,7 +3715,7 @@ index 9ea3acd5ff3d7751875d61861aa5f6c717d0b5e2..75c6a43a3ab4851a47990402bee49f7e
@Override
public boolean isFlapping() {
return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0;
-@@ -72,9 +130,11 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -73,9 +119,11 @@ public class Phantom extends Mob implements Enemy {
@Override
protected void registerGoals() {
@@ -3872,7 +3727,7 @@ index 9ea3acd5ff3d7751875d61861aa5f6c717d0b5e2..75c6a43a3ab4851a47990402bee49f7e
this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal());
}
-@@ -90,6 +150,7 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -91,6 +139,7 @@ public class Phantom extends Mob implements Enemy {
private void updatePhantomSizeInfo() {
this.refreshDimensions();
@@ -3880,15 +3735,23 @@ index 9ea3acd5ff3d7751875d61861aa5f6c717d0b5e2..75c6a43a3ab4851a47990402bee49f7e
this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(6 + this.getPhantomSize());
}
-@@ -147,6 +208,7 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -159,6 +208,15 @@ public class Phantom extends Mob implements Enemy {
@Override
- public void aiStep() {
- if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API
-+ if (getRider() == null || !this.isControllable()) // Purpur - Ridables
- this.igniteForSeconds(8.0F);
- }
+ public void travel(Vec3 travelVector) {
+ this.travelFlying(travelVector, 0.2F);
++ // Purpur start - Ridables
++ if (this.getRider() != null && this.isControllable() && !this.onGround) {
++ float speed = (float) this.getAttributeValue(Attributes.FLYING_SPEED);
++ this.setSpeed(speed);
++ Vec3 mot = this.getDeltaMovement();
++ this.move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed));
++ this.setDeltaMovement(mot.scale(0.9D));
++ }
++ // Purpur end - Ridables
+ }
-@@ -411,25 +473,42 @@ public class Phantom extends FlyingMob implements Enemy {
+ @Override
+@@ -412,25 +470,42 @@ public class Phantom extends Mob implements Enemy {
}
}
@@ -3935,51 +3798,11 @@ index 9ea3acd5ff3d7751875d61861aa5f6c717d0b5e2..75c6a43a3ab4851a47990402bee49f7e
if (Phantom.this.horizontalCollision) {
Phantom.this.setYRot(Phantom.this.getYRot() + 180.0F);
this.speed = 0.1F;
-diff --git a/net/minecraft/world/entity/monster/Pillager.java b/net/minecraft/world/entity/monster/Pillager.java
-index e855ebc5be2cef3b96e2c01a8c1d388e433c0d52..4e799981f04cd17a34f043dda82869adcf16ea98 100644
---- a/net/minecraft/world/entity/monster/Pillager.java
-+++ b/net/minecraft/world/entity/monster/Pillager.java
-@@ -63,16 +63,35 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.pillagerRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pillagerRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.pillagerControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new FloatGoal(this));
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2));
- this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F));
- this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0, 8.0F));
- this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6));
- this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 15.0F, 1.0F));
- this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 15.0F));
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
- this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false));
diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java
-index 6f0fad37a05e9cd53b6e15c119127da492737c95..fb4e91c4f37619ce273ada0909932b32ba3b53f5 100644
+index a10c693a8948d1b7c4bd06b957a08a9cea9170ad..f7807aac5a8f9c92ba77ac38c469ef14948197ac 100644
--- a/net/minecraft/world/entity/monster/Ravager.java
+++ b/net/minecraft/world/entity/monster/Ravager.java
-@@ -66,15 +66,40 @@ public class Ravager extends Raider {
+@@ -72,15 +72,40 @@ public class Ravager extends Raider {
this.setPathfindingMalus(PathType.LEAVES, 0.0F);
}
@@ -4010,7 +3833,7 @@ index 6f0fad37a05e9cd53b6e15c119127da492737c95..fb4e91c4f37619ce273ada0909932b32
protected void registerGoals() {
super.registerGoals();
this.goalSelector.addGoal(0, new FloatGoal(this));
- if (level().purpurConfig.ravagerAvoidRabbits) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, net.minecraft.world.entity.animal.Rabbit.class, 6.0F, 1.0D, 1.2D)); // Purpur - option to make ravagers afraid of rabbits
+ if (level().purpurConfig.ravagerAvoidRabbits) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, net.minecraft.world.entity.animal.rabbit.Rabbit.class, 6.0F, 1.0D, 1.2D)); // Purpur - option to make ravagers afraid of rabbits
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, true));
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.4));
@@ -4020,7 +3843,7 @@ index 6f0fad37a05e9cd53b6e15c119127da492737c95..fb4e91c4f37619ce273ada0909932b32
this.targetSelector.addGoal(2, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true));
this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true, (entity, level) -> !entity.isBaby()));
-@@ -131,7 +156,7 @@ public class Ravager extends Raider {
+@@ -137,7 +162,7 @@ public class Ravager extends Raider {
@Override
public void aiStep() {
super.aiStep();
@@ -4030,10 +3853,10 @@ index 6f0fad37a05e9cd53b6e15c119127da492737c95..fb4e91c4f37619ce273ada0909932b32
this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.0);
} else {
diff --git a/net/minecraft/world/entity/monster/Shulker.java b/net/minecraft/world/entity/monster/Shulker.java
-index 3f2668c79dd3d9e7973c1bba3e424b8220749682..e0a496a0c584e1f90967a8528a73536fd991e774 100644
+index 6e8400c4d523da8799d586c5c9019ae78710fbcb..9647741b67e1b4b7bbff0df22fc1bf3fb26afa73 100644
--- a/net/minecraft/world/entity/monster/Shulker.java
+++ b/net/minecraft/world/entity/monster/Shulker.java
-@@ -104,12 +104,31 @@ public class Shulker extends AbstractGolem implements VariantHolder(this, Player.class, true));
}
-diff --git a/net/minecraft/world/entity/monster/Skeleton.java b/net/minecraft/world/entity/monster/Skeleton.java
-index f0022458e3e01f6d01df0f8d69b2db73c77fb914..d4426daf3b8079a7e769013d43f44c72b0fce697 100644
---- a/net/minecraft/world/entity/monster/Skeleton.java
-+++ b/net/minecraft/world/entity/monster/Skeleton.java
-@@ -25,6 +25,23 @@ public class Skeleton extends AbstractSkeleton {
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.skeletonRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.skeletonRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.skeletonControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
diff --git a/net/minecraft/world/entity/monster/Slime.java b/net/minecraft/world/entity/monster/Slime.java
-index 8db4cba1be6d7a5538295ba8da1fdaf7a77a16d0..7d31d68ac0fce102af480a47db73409926611428 100644
+index e433eacd865f620a9c336a1976fd017b8053cf6a..0c56f9ae47b9263ac65fd3593911e2c8479fc157 100644
--- a/net/minecraft/world/entity/monster/Slime.java
+++ b/net/minecraft/world/entity/monster/Slime.java
-@@ -57,6 +57,7 @@ public class Slime extends Mob implements Enemy {
+@@ -60,6 +60,7 @@ public class Slime extends Mob implements Enemy {
public float oSquish;
- private boolean wasOnGround;
+ private boolean wasOnGround = false;
private boolean canWander = true; // Paper - Slime pathfinder events
+ protected boolean actualJump; // Purpur - Ridables
- public Slime(EntityType extends Slime> entityType, Level level) {
- super(entityType, level);
-@@ -64,12 +65,48 @@ public class Slime extends Mob implements Enemy {
+ public Slime(EntityType extends Slime> type, Level level) {
+ super(type, level);
+@@ -67,12 +68,48 @@ public class Slime extends Mob implements Enemy {
this.moveControl = new Slime.SlimeMoveControl(this);
}
@@ -4201,15 +3996,15 @@ index 8db4cba1be6d7a5538295ba8da1fdaf7a77a16d0..7d31d68ac0fce102af480a47db734099
this.targetSelector
.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entity, level) -> Math.abs(entity.getY() - this.getY()) <= 4.0));
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
-@@ -371,6 +408,7 @@ public class Slime extends Mob implements Enemy {
+@@ -359,6 +396,7 @@ public class Slime extends Mob implements Enemy {
Vec3 deltaMovement = this.getDeltaMovement();
this.setDeltaMovement(deltaMovement.x, this.getJumpPower(), deltaMovement.z);
- this.hasImpulse = true;
+ this.needsSync = true;
+ this.actualJump = false; // Purpur - Ridables
}
- @Nullable
-@@ -535,7 +573,7 @@ public class Slime extends Mob implements Enemy {
+ @Override
+@@ -522,7 +560,7 @@ public class Slime extends Mob implements Enemy {
}
}
@@ -4218,12 +4013,12 @@ index 8db4cba1be6d7a5538295ba8da1fdaf7a77a16d0..7d31d68ac0fce102af480a47db734099
private float yRot;
private int jumpDelay;
private final Slime slime;
-@@ -553,21 +591,33 @@ public class Slime extends Mob implements Enemy {
+@@ -540,21 +578,33 @@ public class Slime extends Mob implements Enemy {
}
- public void setWantedMovement(double speed) {
-- this.speedModifier = speed;
-+ this.setSpeedModifier(speed); // Purpur - Ridables
+ public void setWantedMovement(double speedModifier) {
+- this.speedModifier = speedModifier;
++ this.setSpeedModifier(speedModifier); // Purpur - Ridables
this.operation = MoveControl.Operation.MOVE_TO;
}
@@ -4255,7 +4050,7 @@ index 8db4cba1be6d7a5538295ba8da1fdaf7a77a16d0..7d31d68ac0fce102af480a47db734099
if (this.jumpDelay-- <= 0) {
this.jumpDelay = this.slime.getJumpDelay();
if (this.isAggressive) {
-@@ -584,7 +634,7 @@ public class Slime extends Mob implements Enemy {
+@@ -571,7 +621,7 @@ public class Slime extends Mob implements Enemy {
this.mob.setSpeed(0.0F);
}
} else {
@@ -4264,78 +4059,11 @@ index 8db4cba1be6d7a5538295ba8da1fdaf7a77a16d0..7d31d68ac0fce102af480a47db734099
}
}
}
-diff --git a/net/minecraft/world/entity/monster/Spider.java b/net/minecraft/world/entity/monster/Spider.java
-index af0305079a367899708ee2bbac82aefaa9129d2f..ea83335dd0d128b32d2fe513eab82e642b533b4c 100644
---- a/net/minecraft/world/entity/monster/Spider.java
-+++ b/net/minecraft/world/entity/monster/Spider.java
-@@ -50,15 +50,34 @@ public class Spider extends Monster {
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.spiderRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.spiderRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.spiderControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(1, new FloatGoal(this));
-+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Armadillo.class, 6.0F, 1.0, 1.2, livingEntity -> !((Armadillo)livingEntity).isScared()));
- this.goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4F));
- this.goalSelector.addGoal(4, new Spider.SpiderAttackGoal(this));
- this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8));
- this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F));
- this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
- this.targetSelector.addGoal(2, new Spider.SpiderTargetGoal<>(this, Player.class));
- this.targetSelector.addGoal(3, new Spider.SpiderTargetGoal<>(this, IronGolem.class));
-diff --git a/net/minecraft/world/entity/monster/Stray.java b/net/minecraft/world/entity/monster/Stray.java
-index 5fa2b7920a233afb3659b02cbd7ab82307ea9aaf..ed7ba19870a09ac78c1f069040a25e47c4b19d3a 100644
---- a/net/minecraft/world/entity/monster/Stray.java
-+++ b/net/minecraft/world/entity/monster/Stray.java
-@@ -22,6 +22,23 @@ public class Stray extends AbstractSkeleton {
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.strayRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.strayRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.strayControllable;
-+ }
-+ // Purpur end - Ridables
-+
- public static boolean checkStraySpawnRules(
- EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
- ) {
diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java
-index ce690b564ea8ee055823928169fe605893498f3d..78671f02ef28f4a3b796b357d21fb4c9b64c153e 100644
+index beaffb771e6c8d4b992437997ab27be218425c5a..46121b018c5dd87d888a3724df12a9af0d007772 100644
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
-@@ -94,6 +94,23 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
+@@ -92,6 +92,23 @@ public class Strider extends Animal implements ItemSteerable {
this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F);
}
@@ -4359,7 +4087,7 @@ index ce690b564ea8ee055823928169fe605893498f3d..78671f02ef28f4a3b796b357d21fb4c9
public static boolean checkStriderSpawnRules(
EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
) {
-@@ -156,6 +173,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
+@@ -138,6 +155,7 @@ public class Strider extends Animal implements ItemSteerable {
@Override
protected void registerGoals() {
this.goalSelector.addGoal(1, new PanicGoal(this, 1.65));
@@ -4367,17 +4095,17 @@ index ce690b564ea8ee055823928169fe605893498f3d..78671f02ef28f4a3b796b357d21fb4c9
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0));
this.temptGoal = new TemptGoal(this, 1.4, itemStack -> itemStack.is(ItemTags.STRIDER_TEMPT_ITEMS), false);
this.goalSelector.addGoal(3, this.temptGoal);
-@@ -437,7 +455,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
- InteractionResult interactionResult = super.mobInteract(player, hand);
- if (!interactionResult.consumesAction()) {
+@@ -414,7 +432,7 @@ public class Strider extends Animal implements ItemSteerable {
ItemStack itemInHand = player.getItemInHand(hand);
-- return (InteractionResult)(itemInHand.is(Items.SADDLE) ? itemInHand.interactLivingEntity(player, this, hand) : InteractionResult.PASS);
-+ return (InteractionResult)(itemInHand.is(Items.SADDLE) ? itemInHand.interactLivingEntity(player, this, hand) : tryRide(player, hand)); // Purpur - Ridables
+ return (InteractionResult)(this.isEquippableInSlot(itemInHand, EquipmentSlot.SADDLE)
+ ? itemInHand.interactLivingEntity(player, this, hand)
+- : InteractionResult.PASS);
++ : tryRide(player, hand)); // Purpur - Ridables
} else {
if (isFood && !this.isSilent()) {
this.level()
diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java
-index 7f1cdea810db24182f8f87076c42a19b1b43e98a..26528bc9a9cffb68f82917a3e70900cfb65304d7 100644
+index a6bfb39305732068c50ae99a28114b58b76d2cf7..d567e2b9843606c36a61c83a3a4e2d181f3eefd9 100644
--- a/net/minecraft/world/entity/monster/Vex.java
+++ b/net/minecraft/world/entity/monster/Vex.java
@@ -58,6 +58,50 @@ public class Vex extends Monster implements TraceableEntity {
@@ -4423,7 +4151,7 @@ index 7f1cdea810db24182f8f87076c42a19b1b43e98a..26528bc9a9cffb68f82917a3e70900cf
+ }
+
+ @Override
-+ public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) {
++ public boolean causeFallDamage(double fallDistance, float damageMultiplier, DamageSource damageSource) {
+ return false; // no fall damage please
+ }
+ // Purpur end - Ridables
@@ -4461,7 +4189,7 @@ index 7f1cdea810db24182f8f87076c42a19b1b43e98a..26528bc9a9cffb68f82917a3e70900cf
}
@Override
-@@ -301,13 +347,13 @@ public class Vex extends Monster implements TraceableEntity {
+@@ -293,13 +339,13 @@ public class Vex extends Monster implements TraceableEntity {
}
}
@@ -4477,7 +4205,7 @@ index 7f1cdea810db24182f8f87076c42a19b1b43e98a..26528bc9a9cffb68f82917a3e70900cf
if (this.operation == MoveControl.Operation.MOVE_TO) {
Vec3 vec3 = new Vec3(this.wantedX - Vex.this.getX(), this.wantedY - Vex.this.getY(), this.wantedZ - Vex.this.getZ());
double len = vec3.length();
-@@ -315,7 +361,7 @@ public class Vex extends Monster implements TraceableEntity {
+@@ -307,7 +353,7 @@ public class Vex extends Monster implements TraceableEntity {
this.operation = MoveControl.Operation.WAIT;
Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().scale(0.5));
} else {
@@ -4486,51 +4214,12 @@ index 7f1cdea810db24182f8f87076c42a19b1b43e98a..26528bc9a9cffb68f82917a3e70900cf
if (Vex.this.getTarget() == null) {
Vec3 deltaMovement = Vex.this.getDeltaMovement();
Vex.this.setYRot(-((float)Mth.atan2(deltaMovement.x, deltaMovement.z)) * (180.0F / (float)Math.PI));
-diff --git a/net/minecraft/world/entity/monster/Vindicator.java b/net/minecraft/world/entity/monster/Vindicator.java
-index 5e7506f64159ac4838eee8594c995387e2fceed0..c1a1bb0be8bc77a1c0f771924f3bb8b4936d367b 100644
---- a/net/minecraft/world/entity/monster/Vindicator.java
-+++ b/net/minecraft/world/entity/monster/Vindicator.java
-@@ -55,15 +55,34 @@ public class Vindicator extends AbstractIllager {
- super(entityType, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.vindicatorRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vindicatorRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.vindicatorControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new FloatGoal(this));
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2));
- this.goalSelector.addGoal(2, new Vindicator.VindicatorBreakDoorGoal(this));
- this.goalSelector.addGoal(3, new AbstractIllager.RaiderOpenDoorGoal(this));
- this.goalSelector.addGoal(4, new Raider.HoldGroundAttackGoal(this, 10.0F));
- this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0, false));
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
- this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true));
diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java
-index 9f5676b5fa0f369adb8643391738c5ae33911df7..0b3c78e646d68ef57a7cf5d7eb77a07c497bd216 100644
+index 38991c0c17554c0b58980759eaeb3e9fee774420..bcb136e71db2272dc107304b52be41f83d6772b7 100644
--- a/net/minecraft/world/entity/monster/Witch.java
+++ b/net/minecraft/world/entity/monster/Witch.java
-@@ -56,6 +56,23 @@ public class Witch extends Raider implements RangedAttackMob {
- super(entityType, level);
+@@ -57,6 +57,23 @@ public class Witch extends Raider implements RangedAttackMob {
+ super(type, level);
}
+ // Purpur start - Ridables
@@ -4553,7 +4242,7 @@ index 9f5676b5fa0f369adb8643391738c5ae33911df7..0b3c78e646d68ef57a7cf5d7eb77a07c
@Override
protected void registerGoals() {
super.registerGoals();
-@@ -64,10 +81,12 @@ public class Witch extends Raider implements RangedAttackMob {
+@@ -65,10 +82,12 @@ public class Witch extends Raider implements RangedAttackMob {
);
this.attackPlayersGoal = new NearestAttackableWitchTargetGoal<>(this, Player.class, 10, true, false, null);
this.goalSelector.addGoal(1, new FloatGoal(this));
@@ -4566,39 +4255,11 @@ index 9f5676b5fa0f369adb8643391738c5ae33911df7..0b3c78e646d68ef57a7cf5d7eb77a07c
this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class));
this.targetSelector.addGoal(2, this.healRaidersGoal);
this.targetSelector.addGoal(3, this.attackPlayersGoal);
-diff --git a/net/minecraft/world/entity/monster/WitherSkeleton.java b/net/minecraft/world/entity/monster/WitherSkeleton.java
-index eed8dbefd4d04082dc4e091c858e50309ed5c49b..b0f155564b11ff5fd2430694b937b7826df104ea 100644
---- a/net/minecraft/world/entity/monster/WitherSkeleton.java
-+++ b/net/minecraft/world/entity/monster/WitherSkeleton.java
-@@ -34,6 +34,23 @@ public class WitherSkeleton extends AbstractSkeleton {
- this.setPathfindingMalus(PathType.LAVA, 8.0F);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.witherSkeletonRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherSkeletonRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.witherSkeletonControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void registerGoals() {
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true));
diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java
-index 9b94e74f6317f835500225b087fe93487a7a0b22..b279e33bb14dfea4813bba770daf950f5343419d 100644
+index 201ccf4f20bd9e48ed8c1d59d70f843c74e5287f..c4f009357e416ed4052e058d8bf3b8c3e9dfd4ae 100644
--- a/net/minecraft/world/entity/monster/Zoglin.java
+++ b/net/minecraft/world/entity/monster/Zoglin.java
-@@ -85,6 +85,23 @@ public class Zoglin extends Monster implements HoglinBase {
+@@ -87,6 +87,23 @@ public class Zoglin extends Monster implements HoglinBase {
this.xpReward = 5;
}
@@ -4622,7 +4283,7 @@ index 9b94e74f6317f835500225b087fe93487a7a0b22..b279e33bb14dfea4813bba770daf950f
@Override
protected Brain.Provider brainProvider() {
return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-@@ -250,6 +267,7 @@ public class Zoglin extends Monster implements HoglinBase {
+@@ -251,6 +268,7 @@ public class Zoglin extends Monster implements HoglinBase {
protected void customServerAiStep(ServerLevel level) {
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push("zoglinBrain");
@@ -4630,102 +4291,23 @@ index 9b94e74f6317f835500225b087fe93487a7a0b22..b279e33bb14dfea4813bba770daf950f
this.getBrain().tick(level, this);
profilerFiller.pop();
this.updateActivity();
-diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
-index a60c7b828332fc214caea10be9bc1505e2b5d0a9..6c6806fd7204e3610142f0365d158aee33ef8b2c 100644
---- a/net/minecraft/world/entity/monster/Zombie.java
-+++ b/net/minecraft/world/entity/monster/Zombie.java
-@@ -100,11 +100,30 @@ public class Zombie extends Monster {
- this(EntityType.ZOMBIE, level);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.zombieRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.zombieControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void registerGoals() {
-+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0, 3)); // Paper - Add zombie targets turtle egg config
- this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F));
- this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
-+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.addBehaviourGoals();
- }
-
-diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java
-index 3608fbcd1998ddcdec8ec501dd5f6b80911104ee..33bb29bc03bce90750b3b9376a6ed848208a569d 100644
---- a/net/minecraft/world/entity/monster/ZombieVillager.java
-+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
-@@ -78,6 +78,23 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
- .ifPresent(profession -> this.setVillagerData(this.getVillagerData().setProfession(profession.value())));
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.zombieVillagerRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieVillagerRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.zombieVillagerControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-index f1e25786ef687b4680db1cca96a5ae6068e93946..369f1224ea787ae034d86d0e92696882304cb271 100644
---- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-+++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-@@ -63,6 +63,23 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
- this.setPathfindingMalus(PathType.LAVA, 8.0F);
- }
-
-+ // Purpur start - Ridables
-+ @Override
-+ public boolean isRidable() {
-+ return level().purpurConfig.zombifiedPiglinRidable;
-+ }
-+
-+ @Override
-+ public boolean dismountsUnderwater() {
-+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombifiedPiglinRidableInWater;
-+ }
-+
-+ @Override
-+ public boolean isControllable() {
-+ return level().purpurConfig.zombifiedPiglinControllable;
-+ }
-+ // Purpur end - Ridables
-+
- @Override
- public void setPersistentAngerTarget(@Nullable UUID target) {
- this.persistentAngerTarget = target;
+diff --git a/net/minecraft/world/entity/monster/breeze/Breeze.java b/net/minecraft/world/entity/monster/breeze/Breeze.java
+index d0019ebf0469f4070d323d03dbe54375b8d2ce73..6f22312d0a5ab38be4a07b93fdb29b7f36f67c71 100644
+--- a/net/minecraft/world/entity/monster/breeze/Breeze.java
++++ b/net/minecraft/world/entity/monster/breeze/Breeze.java
+@@ -236,6 +236,7 @@ public class Breeze extends Monster {
+ protected void customServerAiStep(ServerLevel level) {
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("breezeBrain");
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
+ this.getBrain().tick(level, this);
+ profilerFiller.popPush("breezeActivityUpdate");
+ BreezeAi.updateActivity(this);
diff --git a/net/minecraft/world/entity/monster/creaking/Creaking.java b/net/minecraft/world/entity/monster/creaking/Creaking.java
-index eba1e78352f956618b2796ce7cbe5d6f7e6591b6..57ac66c2de97c9b5940c1f0af663a1a26d2c8b73 100644
+index 6775e62ae5b133bc44d730924b4821e0c0b8497c..01d3d638e194ec5e812eea0ab96b100f4752ea18 100644
--- a/net/minecraft/world/entity/monster/creaking/Creaking.java
+++ b/net/minecraft/world/entity/monster/creaking/Creaking.java
-@@ -102,6 +102,29 @@ public class Creaking extends Monster {
+@@ -103,6 +103,29 @@ public class Creaking extends Monster {
return this.getHomePos() != null;
}
@@ -4755,7 +4337,7 @@ index eba1e78352f956618b2796ce7cbe5d6f7e6591b6..57ac66c2de97c9b5940c1f0af663a1a2
@Override
protected BodyRotationControl createBodyControl() {
return new Creaking.CreakingBodyRotationControl(this);
-@@ -580,28 +603,28 @@ public class Creaking extends Monster {
+@@ -547,28 +570,28 @@ public class Creaking extends Monster {
}
}
@@ -4791,10 +4373,10 @@ index eba1e78352f956618b2796ce7cbe5d6f7e6591b6..57ac66c2de97c9b5940c1f0af663a1a2
}
}
diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
-index 0ddc0fe06a1b701f88ed8f8041ecd68f7da6c86d..028e09e1d8a14d989b2c19ca62e6544a93e1f1c4 100644
+index d1749ac82cdbd73422e6229e98eb034978f50fc2..c84f009cb0498e9c1898e310f19cff80ec6989ea 100644
--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
-@@ -92,6 +92,23 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
+@@ -97,6 +97,23 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
this.xpReward = 5;
}
@@ -4818,19 +4400,180 @@ index 0ddc0fe06a1b701f88ed8f8041ecd68f7da6c86d..028e09e1d8a14d989b2c19ca62e6544a
@VisibleForTesting
public void setTimeInOverworld(int timeInOverworld) {
this.timeInOverworld = timeInOverworld;
-@@ -160,6 +177,7 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
+@@ -165,6 +182,7 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
protected void customServerAiStep(ServerLevel level) {
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push("hoglinBrain");
-+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
this.getBrain().tick(level, this);
profilerFiller.pop();
HoglinAi.updateActivity(this);
+diff --git a/net/minecraft/world/entity/monster/illager/Evoker.java b/net/minecraft/world/entity/monster/illager/Evoker.java
+index f291887c07fee2ad8d00bc79822e709777dc3fc3..e40434d24c7a9ffe76c3410601942d0c8a963e30 100644
+--- a/net/minecraft/world/entity/monster/illager/Evoker.java
++++ b/net/minecraft/world/entity/monster/illager/Evoker.java
+@@ -49,10 +49,28 @@ public class Evoker extends SpellcasterIllager {
+ this.xpReward = 10;
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.evokerRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.evokerRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.evokerControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+ this.goalSelector.addGoal(0, new FloatGoal(this));
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(1, new Evoker.EvokerCastingSpellGoal());
+ this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 0.6, 1.0));
+ this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 0.6, 1.0));
+@@ -62,6 +80,7 @@ public class Evoker extends SpellcasterIllager {
+ this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6));
+ this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F));
+ this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
+ this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true).setUnseenMemoryTicks(300));
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false).setUnseenMemoryTicks(300));
+diff --git a/net/minecraft/world/entity/monster/illager/Illusioner.java b/net/minecraft/world/entity/monster/illager/Illusioner.java
+index 1f80b1732ae809ce9ea26b0e8ddd507d0a96dbef..8a80c202752f56ba174c00531993795a4e621910 100644
+--- a/net/minecraft/world/entity/monster/illager/Illusioner.java
++++ b/net/minecraft/world/entity/monster/illager/Illusioner.java
+@@ -59,10 +59,28 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
+ }
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.illusionerRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.illusionerRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.illusionerControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+ this.goalSelector.addGoal(0, new FloatGoal(this));
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(1, new SpellcasterIllager.SpellcasterCastingSpellGoal());
+ this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2));
+ this.goalSelector.addGoal(4, new Illusioner.IllusionerMirrorSpellGoal());
+@@ -71,6 +89,7 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
+ this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6));
+ this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F));
+ this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
+ this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true).setUnseenMemoryTicks(300));
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false).setUnseenMemoryTicks(300));
+diff --git a/net/minecraft/world/entity/monster/illager/Pillager.java b/net/minecraft/world/entity/monster/illager/Pillager.java
+index e9207ed52cdf28bffcc6e6d9fc550285e1ee6294..0b97c4fe89c8549841cbb79ecb9383a9be7a44af 100644
+--- a/net/minecraft/world/entity/monster/illager/Pillager.java
++++ b/net/minecraft/world/entity/monster/illager/Pillager.java
+@@ -65,16 +65,35 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.pillagerRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pillagerRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.pillagerControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+ this.goalSelector.addGoal(0, new FloatGoal(this));
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2));
+ this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F));
+ this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0, 8.0F));
+ this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6));
+ this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 15.0F, 1.0F));
+ this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 15.0F));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
+ this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false));
+diff --git a/net/minecraft/world/entity/monster/illager/Vindicator.java b/net/minecraft/world/entity/monster/illager/Vindicator.java
+index 0cdc52cf3b1bb9c00e6ca8c8e564de60e195d6fc..4162e7ee482829f0c5276a31d44ed4c5ee24c3cf 100644
+--- a/net/minecraft/world/entity/monster/illager/Vindicator.java
++++ b/net/minecraft/world/entity/monster/illager/Vindicator.java
+@@ -57,15 +57,34 @@ public class Vindicator extends AbstractIllager {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.vindicatorRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vindicatorRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.vindicatorControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+ this.goalSelector.addGoal(0, new FloatGoal(this));
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2));
+ this.goalSelector.addGoal(2, new Vindicator.VindicatorBreakDoorGoal(this));
+ this.goalSelector.addGoal(3, new AbstractIllager.RaiderOpenDoorGoal(this));
+ this.goalSelector.addGoal(4, new Raider.HoldGroundAttackGoal(this, 10.0F));
+ this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0, false));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers());
+ this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true));
diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java
-index 0257eada48b35ea024520afe30596beae8a7ef1e..02d748ecb10c3e20aafc0c449b99ca5b6cd80e04 100644
+index fb2ff2b9712f95429bde04d35baddc2da3e3fb52..a42b84611836b970d0d7ddb602bd04d9ec850712 100644
--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
-@@ -151,6 +151,23 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
+@@ -141,6 +141,23 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
this.xpReward = 5;
}
@@ -4852,18 +4595,18 @@ index 0257eada48b35ea024520afe30596beae8a7ef1e..02d748ecb10c3e20aafc0c449b99ca5b
+ // Purpur end - Ridables
+
@Override
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
-@@ -346,6 +363,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
+@@ -319,6 +336,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
protected void customServerAiStep(ServerLevel level) {
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push("piglinBrain");
-+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
this.getBrain().tick(level, this);
profilerFiller.pop();
PiglinAi.updateActivity(this);
diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
-index 0964b138e87357b7601ddfe937a2b9132afd5478..97241682311797faa93927e0477a7646ce53b2c8 100644
+index d33c4d32c99b0b4553ce89746b443820f586ce73..e33809e9ccc4a65909f1c12ec4b0fdc4050aeee7 100644
--- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
+++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
@@ -65,6 +65,23 @@ public class PiglinBrute extends AbstractPiglin {
@@ -4890,7 +4633,7 @@ index 0964b138e87357b7601ddfe937a2b9132afd5478..97241682311797faa93927e0477a7646
public static AttributeSupplier.Builder createAttributes() {
return Monster.createMonsterAttributes()
.add(Attributes.MAX_HEALTH, 50.0)
-@@ -117,6 +134,7 @@ public class PiglinBrute extends AbstractPiglin {
+@@ -116,6 +133,7 @@ public class PiglinBrute extends AbstractPiglin {
protected void customServerAiStep(ServerLevel level) {
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push("piglinBruteBrain");
@@ -4898,11 +4641,209 @@ index 0964b138e87357b7601ddfe937a2b9132afd5478..97241682311797faa93927e0477a7646
this.getBrain().tick(level, this);
profilerFiller.pop();
PiglinBruteAi.updateActivity(this);
+diff --git a/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java b/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java
+index 1ba7777164c7fd8516c97e1bd964183df37c029f..1ab860be69bcc1ab5cc07418c2d7e733afdc482b 100644
+--- a/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java
+@@ -75,12 +75,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
+
+ @Override
+ protected void registerGoals() {
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(2, new RestrictSunGoal(this));
+ this.goalSelector.addGoal(3, new FleeSunGoal(this, 1.0));
+ this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Wolf.class, 6.0F, 1.0, 1.2));
+ this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0));
+ this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F));
+ this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
+ this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
+diff --git a/net/minecraft/world/entity/monster/skeleton/Bogged.java b/net/minecraft/world/entity/monster/skeleton/Bogged.java
+index c54ad2d6a271d70cc9eeb284f13e5d143f81a084..10e66643a918184d858a4e6c9de7a6c2664fbcaf 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Bogged.java
++++ b/net/minecraft/world/entity/monster/skeleton/Bogged.java
+@@ -41,6 +41,23 @@ public class Bogged extends AbstractSkeleton implements Shearable {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.boggedRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.boggedRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.boggedControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/monster/skeleton/Skeleton.java b/net/minecraft/world/entity/monster/skeleton/Skeleton.java
+index d995572427844540a98d76b2926eb15a018230fa..7f8298892565b073373ad68f9c1399a9c565c29a 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Skeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/Skeleton.java
+@@ -26,6 +26,23 @@ public class Skeleton extends AbstractSkeleton {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.skeletonRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.skeletonRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.skeletonControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/monster/skeleton/Stray.java b/net/minecraft/world/entity/monster/skeleton/Stray.java
+index 24ae7263b2661899e7824ab5877f9b1c9f04d80f..23ceecffe8f1b758433e02b61cae421c518cc841 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Stray.java
++++ b/net/minecraft/world/entity/monster/skeleton/Stray.java
+@@ -23,6 +23,23 @@ public class Stray extends AbstractSkeleton {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.strayRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.strayRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.strayControllable;
++ }
++ // Purpur end - Ridables
++
+ public static boolean checkStraySpawnRules(
+ EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
+diff --git a/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java b/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
+index 79326303fc1adf5a35343847a2401d193368b64f..d49200718e7fab29ce5e55278b7584458bfb10e7 100644
+--- a/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
+@@ -34,6 +34,23 @@ public class WitherSkeleton extends AbstractSkeleton {
+ this.setPathfindingMalus(PathType.LAVA, 8.0F);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.witherSkeletonRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherSkeletonRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.witherSkeletonControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void registerGoals() {
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true));
+diff --git a/net/minecraft/world/entity/monster/spider/CaveSpider.java b/net/minecraft/world/entity/monster/spider/CaveSpider.java
+index 6a1714d093fc35e6ca840b769723f7bffaea7ba6..17a9b046ccd8de37aa79501f7556a5a816dfa90f 100644
+--- a/net/minecraft/world/entity/monster/spider/CaveSpider.java
++++ b/net/minecraft/world/entity/monster/spider/CaveSpider.java
+@@ -26,6 +26,23 @@ public class CaveSpider extends Spider {
+ return Spider.createAttributes().add(Attributes.MAX_HEALTH, 12.0);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.caveSpiderRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.caveSpiderRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.caveSpiderControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ public boolean doHurtTarget(ServerLevel level, Entity target) {
+ if (super.doHurtTarget(level, target)) {
+diff --git a/net/minecraft/world/entity/monster/spider/Spider.java b/net/minecraft/world/entity/monster/spider/Spider.java
+index 64a84f73d48deb254345a5c25f3fe650591e64a1..7a8b9c83490a05629e4996844a575ba4c7e9f156 100644
+--- a/net/minecraft/world/entity/monster/spider/Spider.java
++++ b/net/minecraft/world/entity/monster/spider/Spider.java
+@@ -52,15 +52,34 @@ public class Spider extends Monster {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.spiderRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.spiderRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.spiderControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
++ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Armadillo.class, 6.0F, 1.0, 1.2, livingEntity -> !((Armadillo)livingEntity).isScared()));
+ this.goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4F));
+ this.goalSelector.addGoal(4, new Spider.SpiderAttackGoal(this));
+ this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8));
+ this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F));
+ this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
+ this.targetSelector.addGoal(2, new Spider.SpiderTargetGoal<>(this, Player.class));
+ this.targetSelector.addGoal(3, new Spider.SpiderTargetGoal<>(this, IronGolem.class));
diff --git a/net/minecraft/world/entity/monster/warden/Warden.java b/net/minecraft/world/entity/monster/warden/Warden.java
-index 9f476e587d7df797129e49738f101cccca7e10b7..f968e5c99bdb23b268bc34ea1ba5d54ae9ad0ff9 100644
+index 3b931c6105ea14add0d2a60dc19cc3601a092a3b..4f4bf16cfa1390f19a7e8745d86e42e24ffb3bbc 100644
--- a/net/minecraft/world/entity/monster/warden/Warden.java
+++ b/net/minecraft/world/entity/monster/warden/Warden.java
-@@ -129,8 +129,32 @@ public class Warden extends Monster implements VibrationSystem {
+@@ -124,8 +124,32 @@ public class Warden extends Monster implements VibrationSystem {
this.setPathfindingMalus(PathType.LAVA, 8.0F);
this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F);
this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F);
@@ -4935,7 +4876,15 @@ index 9f476e587d7df797129e49738f101cccca7e10b7..f968e5c99bdb23b268bc34ea1ba5d54a
@Override
public Packet getAddEntityPacket(ServerEntity entity) {
return new ClientboundAddEntityPacket(this, entity, this.hasPose(Pose.EMERGING) ? 1 : 0);
-@@ -394,6 +418,7 @@ public class Warden extends Monster implements VibrationSystem {
+@@ -280,6 +304,7 @@ public class Warden extends Monster implements VibrationSystem {
+ protected void customServerAiStep(ServerLevel level) {
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("wardenBrain");
++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider
+ this.getBrain().tick(level, this);
+ profilerFiller.pop();
+ super.customServerAiStep(level);
+@@ -382,6 +407,7 @@ public class Warden extends Monster implements VibrationSystem {
@Contract("null->false")
public boolean canTargetEntity(@Nullable Entity entity) {
@@ -4943,11 +4892,194 @@ index 9f476e587d7df797129e49738f101cccca7e10b7..f968e5c99bdb23b268bc34ea1ba5d54a
return entity instanceof LivingEntity livingEntity
&& this.level() == entity.level()
&& EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity)
-diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
-index 7eb291323dfc71189ac4a160d3cb43506957aa9e..a7424ad414b72d2adaf0863bf1055f3eff5e2989 100644
---- a/net/minecraft/world/entity/npc/Villager.java
-+++ b/net/minecraft/world/entity/npc/Villager.java
-@@ -246,6 +246,28 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+diff --git a/net/minecraft/world/entity/monster/zombie/Drowned.java b/net/minecraft/world/entity/monster/zombie/Drowned.java
+index 604d5e6a4962de61fb97988a2f3de2965908bada..03c801d5982eed73fd8f56f63ccab570e83b8a53 100644
+--- a/net/minecraft/world/entity/monster/zombie/Drowned.java
++++ b/net/minecraft/world/entity/monster/zombie/Drowned.java
+@@ -74,6 +74,23 @@ public class Drowned extends Zombie implements RangedAttackMob {
+ return Zombie.createAttributes().add(Attributes.STEP_HEIGHT, 1.0);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.drownedRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.drownedRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.drownedControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected PathNavigation createNavigation(Level level) {
+ return new AmphibiousPathNavigation(this, level);
+@@ -433,7 +450,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
+ }
+ }
+
+- static class DrownedMoveControl extends MoveControl {
++ static class DrownedMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables
+ private final Drowned drowned;
+
+ public DrownedMoveControl(Drowned mob) {
+@@ -442,7 +459,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
+ }
+
+ @Override
+- public void tick() {
++ public void vanillaTick() { // Purpur - Ridables
+ LivingEntity target = this.drowned.getTarget();
+ if (this.drowned.wantsToSwim() && this.drowned.isInWater()) {
+ if (target != null && target.getY() > this.drowned.getY() || this.drowned.searchingForLand) {
+@@ -462,7 +479,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
+ float f = (float)(Mth.atan2(d2, d) * 180.0F / (float)Math.PI) - 90.0F;
+ this.drowned.setYRot(this.rotlerp(this.drowned.getYRot(), f, 90.0F));
+ this.drowned.yBodyRot = this.drowned.getYRot();
+- float f1 = (float)(this.speedModifier * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED));
++ float f1 = (float)(this.getSpeedModifier() * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables
+ float f2 = Mth.lerp(0.125F, this.drowned.getSpeed(), f1);
+ this.drowned.setSpeed(f2);
+ this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(f2 * d * 0.005, f2 * d1 * 0.1, f2 * d2 * 0.005));
+@@ -471,7 +488,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
+ this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(0.0, -0.008, 0.0));
+ }
+
+- super.tick();
++ super.vanillaTick(); // Purpur - Ridables
+ }
+ }
+ }
+diff --git a/net/minecraft/world/entity/monster/zombie/Husk.java b/net/minecraft/world/entity/monster/zombie/Husk.java
+index f36d92f0f62354be5f4e39e768aabb1369cfe18c..f18ac33d31ae23db02654658840b89ba03736bf3 100644
+--- a/net/minecraft/world/entity/monster/zombie/Husk.java
++++ b/net/minecraft/world/entity/monster/zombie/Husk.java
+@@ -29,6 +29,23 @@ public class Husk extends Zombie {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.huskRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.huskRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.huskControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ public boolean isSunSensitive() {
+ return false;
+diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
+index c86fb77485a038b600877432c828dc7940cf26f4..b2d322bee9343079c0c21cc7b47493df9cfd861e 100644
+--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
++++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
+@@ -103,11 +103,30 @@ public class Zombie extends Monster {
+ this(EntityType.ZOMBIE, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.zombieRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.zombieControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void registerGoals() {
++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0, 3)); // Paper - Add zombie targets turtle egg config
+ this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F));
+ this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+ this.addBehaviourGoals();
+ }
+
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+index c73419613c67685dd78d7aa0a959267b4b9c1ae8..d91a1aec302a93326a357311f1743fa87ec92fa3 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+@@ -85,6 +85,23 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
+ super(type, level);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.zombieVillagerRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieVillagerRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.zombieVillagerControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+index ef6a4aff03c1a85535b15e653714751e79f61090..e2c5301a465e28cea057f9afec7e9d78090e1c9e 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+@@ -64,6 +64,23 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
+ this.setPathfindingMalus(PathType.LAVA, 8.0F);
+ }
+
++ // Purpur start - Ridables
++ @Override
++ public boolean isRidable() {
++ return level().purpurConfig.zombifiedPiglinRidable;
++ }
++
++ @Override
++ public boolean dismountsUnderwater() {
++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombifiedPiglinRidableInWater;
++ }
++
++ @Override
++ public boolean isControllable() {
++ return level().purpurConfig.zombifiedPiglinControllable;
++ }
++ // Purpur end - Ridables
++
+ @Override
+ protected void addBehaviourGoals() {
+ this.goalSelector.addGoal(1, new SpearUseGoal<>(this, 1.0, 1.0, 10.0F, 2.0F));
+diff --git a/net/minecraft/world/entity/npc/villager/Villager.java b/net/minecraft/world/entity/npc/villager/Villager.java
+index e117ae1b114c7e2ca314a00335473efc41137f7f..6d4ef7b5d64639eb7fe400b2ed612c3b3552aa52 100644
+--- a/net/minecraft/world/entity/npc/villager/Villager.java
++++ b/net/minecraft/world/entity/npc/villager/Villager.java
+@@ -250,6 +250,28 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
// Purpur end - Lobotomize stuck villagers
@@ -4976,25 +5108,25 @@ index 7eb291323dfc71189ac4a160d3cb43506957aa9e..a7424ad414b72d2adaf0863bf1055f3e
@Override
public Brain getBrain() {
return (Brain)super.getBrain();
-@@ -355,7 +377,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+@@ -357,7 +379,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+ } else {
+ this.isLobotomized = false;
}
- // Purpur end - Lobotomize stuck villagers
- // Pufferfish start
-- if (!inactive /*&& this.behaviorTick++ % this.activatedPriority == 0*/) {
-+ if (!inactive && (getRider() == null || !this.isControllable()) /*&& this.behaviorTick++ % this.activatedPriority == 0*/) { // Purpur - Ridables
+- if (!inactive) {
++ if (!inactive && (getRider() == null || !this.isControllable())) { // Purpur - Ridables
this.getBrain().tick(level, this); // Paper - EAR 2
}
- else if (this.isLobotomized && shouldRestock()) restock(); // Purpur - Lobotomize stuck villagers
-@@ -415,7 +437,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+ else if (this.isLobotomized && shouldRestock(level)) restock();
+@@ -417,7 +439,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
return super.mobInteract(player, hand);
} else if (this.isBaby()) {
this.setUnhappy();
- return InteractionResult.SUCCESS;
+ return tryRide(player, hand, InteractionResult.SUCCESS); // Purpur - Ridables
} else {
- if (!this.level().isClientSide) {
+ if (!this.level().isClientSide()) {
boolean isEmpty = this.getOffers().isEmpty();
-@@ -428,9 +450,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+@@ -430,9 +452,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
if (isEmpty) {
@@ -5007,11 +5139,11 @@ index 7eb291323dfc71189ac4a160d3cb43506957aa9e..a7424ad414b72d2adaf0863bf1055f3e
if (this.level().purpurConfig.villagerAllowTrading) // Purpur - Add config for villager trading
this.startTrading(player);
}
-diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java
-index fab309dc34eb88f2b9c844078f167885121675c1..0f8ec3abead11c46205cd21290c65ec2b859efdc 100644
---- a/net/minecraft/world/entity/npc/WanderingTrader.java
-+++ b/net/minecraft/world/entity/npc/WanderingTrader.java
-@@ -76,6 +76,23 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
+diff --git a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+index aceeb9919473f5ff1b84efe950d10aa4dbc10121..5c7da654ef967356173a9d85a8675a7dc61ef395 100644
+--- a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
++++ b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+@@ -68,6 +68,23 @@ public class WanderingTrader extends AbstractVillager implements Consumable.Over
}
// Purpur end - Allow leashing villagers
@@ -5035,9 +5167,9 @@ index fab309dc34eb88f2b9c844078f167885121675c1..0f8ec3abead11c46205cd21290c65ec2
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
-@@ -137,8 +154,9 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
+@@ -128,8 +145,9 @@ public class WanderingTrader extends AbstractVillager implements Consumable.Over
- if (!this.level().isClientSide) {
+ if (!this.level().isClientSide()) {
if (this.getOffers().isEmpty()) {
- return InteractionResult.CONSUME;
+ return tryRide(player, hand, InteractionResult.CONSUME); // Purpur - Ridables
@@ -5047,10 +5179,10 @@ index fab309dc34eb88f2b9c844078f167885121675c1..0f8ec3abead11c46205cd21290c65ec2
if (this.level().purpurConfig.wanderingTraderAllowTrading) { // Purpur - Add config for villager trading
this.setTradingPlayer(player);
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
-index 3ca4dd7fdb3b8205d72593c13a0fe76e86f76095..ca998a8a480af63d4a5f58a1f4490528a7b33c69 100644
+index f5d3aa7c1e008377f9ac06401e88dae8c671ec13..eee303b4e0fa22a3d037e5fb3bf31946f41744cf 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
-@@ -220,6 +220,19 @@ public abstract class Player extends LivingEntity {
+@@ -199,6 +199,19 @@ public abstract class Player extends Avatar implements ContainerUser {
}
// CraftBukkit end
@@ -5067,11 +5199,11 @@ index 3ca4dd7fdb3b8205d72593c13a0fe76e86f76095..ca998a8a480af63d4a5f58a1f4490528
+ }
+ // Purpur end - Ridables
+
- public Player(Level level, BlockPos pos, float yRot, GameProfile gameProfile) {
+ public Player(Level level, GameProfile gameProfile) {
super(EntityType.PLAYER, level);
- this.setUUID(gameProfile.getId());
+ this.setUUID(gameProfile.id());
diff --git a/net/minecraft/world/entity/projectile/LlamaSpit.java b/net/minecraft/world/entity/projectile/LlamaSpit.java
-index 4880db97135d54fa72f64c108b2bd4ded096438b..bc102b049047d6e2a1d29e10f92cdf5ae2c140bd 100644
+index b8e3616de5f07e49a8bbab314329157e4268fb1e..56d78249c3fd7da0ff963712fe3a5c722b907c09 100644
--- a/net/minecraft/world/entity/projectile/LlamaSpit.java
+++ b/net/minecraft/world/entity/projectile/LlamaSpit.java
@@ -33,6 +33,12 @@ public class LlamaSpit extends Projectile {
@@ -5087,10 +5219,10 @@ index 4880db97135d54fa72f64c108b2bd4ded096438b..bc102b049047d6e2a1d29e10f92cdf5a
@Override
protected double getDefaultGravity() {
return 0.06;
-diff --git a/net/minecraft/world/entity/projectile/WitherSkull.java b/net/minecraft/world/entity/projectile/WitherSkull.java
-index c7a76d45b5749cf054607808610eb710493f80ea..9af37bd40649f602d700fc7b683c646ae9189eb9 100644
---- a/net/minecraft/world/entity/projectile/WitherSkull.java
-+++ b/net/minecraft/world/entity/projectile/WitherSkull.java
+diff --git a/net/minecraft/world/entity/projectile/hurtingprojectile/WitherSkull.java b/net/minecraft/world/entity/projectile/hurtingprojectile/WitherSkull.java
+index 1020e835f24bc25e032335f739d526bc0bd4ecc4..fced6e9df3239ffff9f297706c764cb9675c0ebb 100644
+--- a/net/minecraft/world/entity/projectile/hurtingprojectile/WitherSkull.java
++++ b/net/minecraft/world/entity/projectile/hurtingprojectile/WitherSkull.java
@@ -110,6 +110,14 @@ public class WitherSkull extends AbstractHurtingProjectile {
}
// Purpur end - Add canSaveToDisk to Entity
diff --git a/purpur-server/minecraft-patches/features/0002-Configurable-entity-base-attributes.patch b/purpur-server/minecraft-patches/features/0002-Configurable-entity-base-attributes.patch
index c1b6fbad3..c0346feeb 100644
--- a/purpur-server/minecraft-patches/features/0002-Configurable-entity-base-attributes.patch
+++ b/purpur-server/minecraft-patches/features/0002-Configurable-entity-base-attributes.patch
@@ -4,38 +4,20 @@ Date: Thu, 10 Dec 2020 16:44:54 -0600
Subject: [PATCH] Configurable entity base attributes
-diff --git a/net/minecraft/world/entity/GlowSquid.java b/net/minecraft/world/entity/GlowSquid.java
-index d0313fd5368baa53ec511c8c07fc78a1f1ecec4e..898b1e01026ec1f44cfe60e9f18a997c86e30594 100644
---- a/net/minecraft/world/entity/GlowSquid.java
-+++ b/net/minecraft/world/entity/GlowSquid.java
-@@ -45,6 +45,13 @@ public class GlowSquid extends Squid {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.glowSquidMaxHealth);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected ParticleOptions getInkParticle() {
- return ParticleTypes.GLOW_SQUID_INK;
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
-index 8c2bdb1775f7c4110c5f967b1052eba6a8fcbbfa..d1f7da0f4adc4609247c349d7ccdb0e6bba9b8f8 100644
+index 6e0a2741db06f93f31349515d1d13181b70e08ed..42dcad656dff5ba1e7fa8aced86628ac28f300af 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
-@@ -311,6 +311,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
- protected LivingEntity(EntityType extends LivingEntity> entityType, Level level) {
- super(entityType, level);
- this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entityType), this); // Purpur - Ridables
+@@ -295,6 +295,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ protected LivingEntity(EntityType extends LivingEntity> type, Level level) {
+ super(type, level);
+ this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type), this); // Purpur - Ridables
+ this.initAttributes(); // Purpur - Configurable entity base attributes
- this.craftAttributes = new CraftAttributeMap(this.attributes); // CraftBukkit
+ this.craftAttributes = new org.bukkit.craftbukkit.attribute.CraftAttributeMap(this.attributes); // CraftBukkit
// CraftBukkit - this.setHealth(this.getMaxHealth()) inlined and simplified to skip the instanceof check for Player, as getBukkitEntity() is not initialized in constructor
this.entityData.set(LivingEntity.DATA_HEALTH_ID, this.getMaxHealth());
-@@ -324,6 +325,8 @@ public abstract class LivingEntity extends Entity implements Attackable {
- this.brain = this.makeBrain(new Dynamic<>(nbtOps, nbtOps.createMap(ImmutableMap.of(nbtOps.createString("memories"), nbtOps.emptyMap()))));
+@@ -316,6 +317,8 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ return new EntityEquipment();
}
+ protected void initAttributes() {}// Purpur - Configurable entity base attributes
@@ -44,7 +26,7 @@ index 8c2bdb1775f7c4110c5f967b1052eba6a8fcbbfa..d1f7da0f4adc4609247c349d7ccdb0e6
return this.brain;
}
diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java
-index e7ea944e77175ee4051b8e7361c502d0cc2115d5..ecbec552e5cd1935f57872d2fb502d3e9743e3d8 100644
+index 2cfcf1f7473d8612777ca0752f6d1521c231ef42..a09b5035e91d50e12f613a7a1211c6869fbbf4df 100644
--- a/net/minecraft/world/entity/ambient/Bat.java
+++ b/net/minecraft/world/entity/ambient/Bat.java
@@ -94,6 +94,21 @@ public class Bat extends AmbientCreature {
@@ -69,457 +51,11 @@ index e7ea944e77175ee4051b8e7361c502d0cc2115d5..ecbec552e5cd1935f57872d2fb502d3e
@Override
public boolean isFlapping() {
return !this.isResting() && this.tickCount % 10.0F == 0.0F;
-diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java
-index af0cf64b4c74d290dec8032f8a6127867e301130..3cdfded14a2fb74e3f345e893e60364b6b810075 100644
---- a/net/minecraft/world/entity/animal/Bee.java
-+++ b/net/minecraft/world/entity/animal/Bee.java
-@@ -472,6 +472,14 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
- return beehiveBlockEntity != null && beehiveBlockEntity.isFireNearby();
- }
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.beeMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.beeScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- public int getRemainingPersistentAngerTime() {
- return this.entityData.get(DATA_REMAINING_ANGER_TIME);
-diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java
-index f066b0acfa0e954f6d71e62962c76afa1f05a4a5..98ce277c5b27591e22daa3c85241be1b8689bfae 100644
---- a/net/minecraft/world/entity/animal/Cat.java
-+++ b/net/minecraft/world/entity/animal/Cat.java
-@@ -118,6 +118,14 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true);
-diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java
-index aba1bf732bb78a24dba1f063d65894fde92789ef..509163f409a5b8988a484aedb2f3ddf042d5eb13 100644
---- a/net/minecraft/world/entity/animal/Chicken.java
-+++ b/net/minecraft/world/entity/animal/Chicken.java
-@@ -68,6 +68,14 @@ public class Chicken extends Animal {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.chickenMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.chickenScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Cod.java b/net/minecraft/world/entity/animal/Cod.java
-index 6a19086e272363701260801f3c6db9b5c91b8ef5..434e1fabf2e360a8f5f4eefed96e3883aa786d10 100644
---- a/net/minecraft/world/entity/animal/Cod.java
-+++ b/net/minecraft/world/entity/animal/Cod.java
-@@ -25,6 +25,13 @@ public class Cod extends AbstractSchoolingFish {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.codMaxHealth);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- public ItemStack getBucketItemStack() {
- return new ItemStack(Items.COD_BUCKET);
-diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java
-index 656babc0c8810a85eb9f78ced1f3ad9551fdc286..d2a4bfa5334f7361067e4adac36ba5a4a4fa6ad8 100644
---- a/net/minecraft/world/entity/animal/Cow.java
-+++ b/net/minecraft/world/entity/animal/Cow.java
-@@ -55,6 +55,14 @@ public class Cow extends Animal {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.cowMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.cowScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java
-index 35bce598bb5857356823594d2a001006ce19f835..5b764c686e8759a7b04a7b50708c69629be02c04 100644
---- a/net/minecraft/world/entity/animal/Dolphin.java
-+++ b/net/minecraft/world/entity/animal/Dolphin.java
-@@ -148,6 +148,14 @@ public class Dolphin extends AgeableWaterCreature {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.dolphinMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.dolphinScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Nullable
- @Override
- public SpawnGroupData finalizeSpawn(
-diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java
-index 8b0a813f9dd001c6dd108ba7aac04d134a20fbc1..8bf893837586ae2a9b4ef7564d242e16e4863b5d 100644
---- a/net/minecraft/world/entity/animal/Fox.java
-+++ b/net/minecraft/world/entity/animal/Fox.java
-@@ -167,6 +167,14 @@ public class Fox extends Animal implements VariantHolder {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.foxMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.foxScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/animal/IronGolem.java b/net/minecraft/world/entity/animal/IronGolem.java
-index 223c4796f659a24062a719045e484a22d31ab2f0..37a353cbb0e9b16e0fc92bd1bc8194cb4cd3c13a 100644
---- a/net/minecraft/world/entity/animal/IronGolem.java
-+++ b/net/minecraft/world/entity/animal/IronGolem.java
-@@ -90,6 +90,14 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ironGolemMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.ironGolemScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void registerGoals() {
- if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options
-diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java
-index 1292146341022483f78a9128ef9d7a88089274a0..990723c31aa1040a4e45b9857a18d86287ef91b4 100644
---- a/net/minecraft/world/entity/animal/MushroomCow.java
-+++ b/net/minecraft/world/entity/animal/MushroomCow.java
-@@ -72,6 +72,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.rabbitMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.rabbitScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- public void registerGoals() {
- this.goalSelector.addGoal(1, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Salmon.java b/net/minecraft/world/entity/animal/Salmon.java
-index ebbd6d39c3f5d6c66445c2c743785ed369408389..93eb3cc3605f694337c1604e2db63fed04693617 100644
---- a/net/minecraft/world/entity/animal/Salmon.java
-+++ b/net/minecraft/world/entity/animal/Salmon.java
-@@ -47,6 +47,13 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder brainProvider() {
return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
diff --git a/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/net/minecraft/world/entity/animal/armadillo/Armadillo.java
-index 87a190d8646d8bbed8c182f9f0f7d8c398e63d26..c10ebb66dec26b6ccc223e98effa0b9a68363626 100644
+index 767a730baa8a7694ed7d5f05b70118da1f4288cc..1f6b28531127ea2e5b291583f6bb6a236868fbf0 100644
--- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java
+++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java
-@@ -97,6 +97,14 @@ public class Armadillo extends Animal {
+@@ -99,6 +99,14 @@ public class Armadillo extends Animal {
}
// Purpur end - Ridables
@@ -554,10 +90,10 @@ index 87a190d8646d8bbed8c182f9f0f7d8c398e63d26..c10ebb66dec26b6ccc223e98effa0b9a
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
diff --git a/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
-index 2054e4624da0c9b04ea69b9bf39443c4574d48be..f2f09a529e9db88784ff4299fdf3966046c736ab 100644
+index 3837397563bf3d568c120ae4e4e38d1a6dc7a8b2..3f9e15685ba52a5b9bd4282ba6de6751296975bf 100644
--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java
+++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
-@@ -132,6 +132,14 @@ public class Axolotl extends Animal implements VariantHolder, B
+@@ -138,6 +138,14 @@ public class Axolotl extends Animal implements Bucketable {
}
// Purpur end - Ridables
@@ -572,11 +108,30 @@ index 2054e4624da0c9b04ea69b9bf39443c4574d48be..f2f09a529e9db88784ff4299fdf39660
@Override
public float getWalkTargetValue(BlockPos pos, LevelReader level) {
return 0.0F;
+diff --git a/net/minecraft/world/entity/animal/bee/Bee.java b/net/minecraft/world/entity/animal/bee/Bee.java
+index bd3dc923058b884afcfad08062230182810c65a2..7d7ab4c5092ac085e8cd6d3a432feb683db5a282 100644
+--- a/net/minecraft/world/entity/animal/bee/Bee.java
++++ b/net/minecraft/world/entity/animal/bee/Bee.java
+@@ -477,6 +477,14 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+ return beehiveBlockEntity != null && beehiveBlockEntity.isFireNearby();
+ }
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.beeMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.beeScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ public long getPersistentAngerEndTime() {
+ return this.entityData.get(DATA_ANGER_END_TIME);
diff --git a/net/minecraft/world/entity/animal/camel/Camel.java b/net/minecraft/world/entity/animal/camel/Camel.java
-index 11311d2ec37d825e73e2218e60e2606dd3a25a1d..1d7e2358bac193af48dc4b7f5b0295e3bffa152b 100644
+index a6a66084323435697b3185d7b86acaf5c7453719..95e86330e1e973c43e50bd4ac310212b8a057430 100644
--- a/net/minecraft/world/entity/animal/camel/Camel.java
+++ b/net/minecraft/world/entity/animal/camel/Camel.java
-@@ -322,6 +322,23 @@ public class Camel extends AbstractHorse {
+@@ -343,6 +343,23 @@ public class Camel extends AbstractHorse {
return this.dashCooldown;
}
@@ -598,13 +153,88 @@ index 11311d2ec37d825e73e2218e60e2606dd3a25a1d..1d7e2358bac193af48dc4b7f5b0295e3
+ // Purpur end - Configurable entity base attributes
+
@Override
- protected SoundEvent getAmbientSound() {
+ public SoundEvent getAmbientSound() {
return SoundEvents.CAMEL_AMBIENT;
-diff --git a/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/net/minecraft/world/entity/animal/horse/AbstractHorse.java
-index 828406060e50ff62586929371aafb46ef7d81f92..56dc7011ed07f0bd5870fbadde2b5c0c630c5edd 100644
---- a/net/minecraft/world/entity/animal/horse/AbstractHorse.java
-+++ b/net/minecraft/world/entity/animal/horse/AbstractHorse.java
-@@ -218,6 +218,46 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
+diff --git a/net/minecraft/world/entity/animal/chicken/Chicken.java b/net/minecraft/world/entity/animal/chicken/Chicken.java
+index 4961bb85b91f68075cf0d22440d6377d9fcb7721..bfc5c6639ef1005d2752d5164f3613ddacc46bf1 100644
+--- a/net/minecraft/world/entity/animal/chicken/Chicken.java
++++ b/net/minecraft/world/entity/animal/chicken/Chicken.java
+@@ -90,6 +90,14 @@ public class Chicken extends Animal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.chickenMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.chickenScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/animal/cow/Cow.java b/net/minecraft/world/entity/animal/cow/Cow.java
+index 0268063bb0db8c30c594a7d75d0d11f7236c3a68..5e5b239ebc774ae66f8c35a725ea917993239ef2 100644
+--- a/net/minecraft/world/entity/animal/cow/Cow.java
++++ b/net/minecraft/world/entity/animal/cow/Cow.java
+@@ -46,6 +46,14 @@ public class Cow extends AbstractCow {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.cowMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.cowScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/cow/MushroomCow.java b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+index 1a9f5f17e46af831bc6621c83c57e5436397dbc2..85ad44eb3e64232cf1ea326257078c46288a613a 100644
+--- a/net/minecraft/world/entity/animal/cow/MushroomCow.java
++++ b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+@@ -78,6 +78,13 @@ public class MushroomCow extends AbstractCow implements Shearable {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.mooshroomMaxHealth);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ public float getWalkTargetValue(BlockPos pos, LevelReader level) {
+ return level.getBlockState(pos.below()).is(Blocks.MYCELIUM) ? 10.0F : level.getPathfindingCostFromLightLevels(pos);
+diff --git a/net/minecraft/world/entity/animal/dolphin/Dolphin.java b/net/minecraft/world/entity/animal/dolphin/Dolphin.java
+index 656335a3bd021efc538ab407673c09a83178ed7c..94f92080de46f2af67e1d28753208691da534ddf 100644
+--- a/net/minecraft/world/entity/animal/dolphin/Dolphin.java
++++ b/net/minecraft/world/entity/animal/dolphin/Dolphin.java
+@@ -152,6 +152,14 @@ public class Dolphin extends AgeableWaterCreature {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.dolphinMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.dolphinScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ public @Nullable SpawnGroupData finalizeSpawn(
+ ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
+diff --git a/net/minecraft/world/entity/animal/equine/AbstractHorse.java b/net/minecraft/world/entity/animal/equine/AbstractHorse.java
+index a1dce0a5ce1fcd0a2ff7104b3592ffd5c948db34..5bd1e0f20a9553ae20db1d72d0b2a88bd92db723 100644
+--- a/net/minecraft/world/entity/animal/equine/AbstractHorse.java
++++ b/net/minecraft/world/entity/animal/equine/AbstractHorse.java
+@@ -140,6 +140,46 @@ public abstract class AbstractHorse extends Animal implements HasCustomInventory
}
// Purpur end - Ridables
@@ -651,7 +281,7 @@ index 828406060e50ff62586929371aafb46ef7d81f92..56dc7011ed07f0bd5870fbadde2b5c0c
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables
-@@ -1218,7 +1258,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
+@@ -1050,7 +1090,7 @@ public abstract class AbstractHorse extends Animal implements HasCustomInventory
spawnGroupData = new AgeableMob.AgeableMobGroupData(0.2F);
}
@@ -660,10 +290,10 @@ index 828406060e50ff62586929371aafb46ef7d81f92..56dc7011ed07f0bd5870fbadde2b5c0c
return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
}
-diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java
-index ee3fa710e95f2e84f7f9bdce1159d1136815172d..223f1d109680e3643ab2c8343be22713e89755fd 100644
---- a/net/minecraft/world/entity/animal/horse/Donkey.java
-+++ b/net/minecraft/world/entity/animal/horse/Donkey.java
+diff --git a/net/minecraft/world/entity/animal/equine/Donkey.java b/net/minecraft/world/entity/animal/equine/Donkey.java
+index 8aec9f254c82993632e68368d37b8c9bee7869cc..b85d967c7c809683e4576be30ed855941c6e68cc 100644
+--- a/net/minecraft/world/entity/animal/equine/Donkey.java
++++ b/net/minecraft/world/entity/animal/equine/Donkey.java
@@ -23,6 +23,23 @@ public class Donkey extends AbstractChestedHorse {
}
// Purpur end - Ridables
@@ -686,13 +316,13 @@ index ee3fa710e95f2e84f7f9bdce1159d1136815172d..223f1d109680e3643ab2c8343be22713
+ // Purpur end - Configurable entity base attributes
+
@Override
- protected SoundEvent getAmbientSound() {
+ public SoundEvent getAmbientSound() {
return SoundEvents.DONKEY_AMBIENT;
-diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java
-index 361bf346153912bcbfcf962d7f716dfe12ae2a7b..8bd118e82da9e4d4153de0a3efaf6d69e3c4c540 100644
---- a/net/minecraft/world/entity/animal/horse/Horse.java
-+++ b/net/minecraft/world/entity/animal/horse/Horse.java
-@@ -50,6 +50,23 @@ public class Horse extends AbstractHorse implements VariantHolder {
+diff --git a/net/minecraft/world/entity/animal/equine/Horse.java b/net/minecraft/world/entity/animal/equine/Horse.java
+index cc50151ce6e6daffc1ecd41eb89a0d2f159f651e..9a97cd588fb2dc0f393b2c8768f4e45066a34850 100644
+--- a/net/minecraft/world/entity/animal/equine/Horse.java
++++ b/net/minecraft/world/entity/animal/equine/Horse.java
+@@ -57,6 +57,23 @@ public class Horse extends AbstractHorse {
}
// Purpur end - Ridables
@@ -716,11 +346,11 @@ index 361bf346153912bcbfcf962d7f716dfe12ae2a7b..8bd118e82da9e4d4153de0a3efaf6d69
@Override
protected void randomizeAttributes(RandomSource random) {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt));
-diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java
-index 164a429d432badcb315e8ece406e29e576a11265..58e726dd33f572a31b4910b9ff666c4252fb03a9 100644
---- a/net/minecraft/world/entity/animal/horse/Llama.java
-+++ b/net/minecraft/world/entity/animal/horse/Llama.java
-@@ -124,6 +124,23 @@ public class Llama extends AbstractChestedHorse implements VariantHolder stack.is(ItemTags.CAT_FOOD), true);
+diff --git a/net/minecraft/world/entity/animal/feline/Ocelot.java b/net/minecraft/world/entity/animal/feline/Ocelot.java
+index 22fa29aa785eda8fb4a895d36413626da8a49a0e..c9a8dcfd1e46f97dee0393db3205049c0db1cefb 100644
+--- a/net/minecraft/world/entity/animal/feline/Ocelot.java
++++ b/net/minecraft/world/entity/animal/feline/Ocelot.java
+@@ -83,6 +83,14 @@ public class Ocelot extends Animal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ocelotMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.ocelotScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ public boolean isTrusting() {
+ return this.entityData.get(DATA_TRUSTING);
+ }
+diff --git a/net/minecraft/world/entity/animal/fish/Cod.java b/net/minecraft/world/entity/animal/fish/Cod.java
+index f73b3f5ae65f7793ff25145c72fb35e3daec8494..e00e623d7df9e179d8bb5ee4812538578c5f4c08 100644
+--- a/net/minecraft/world/entity/animal/fish/Cod.java
++++ b/net/minecraft/world/entity/animal/fish/Cod.java
+@@ -25,6 +25,13 @@ public class Cod extends AbstractSchoolingFish {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.codMaxHealth);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ public ItemStack getBucketItemStack() {
+ return new ItemStack(Items.COD_BUCKET);
+diff --git a/net/minecraft/world/entity/animal/fish/Pufferfish.java b/net/minecraft/world/entity/animal/fish/Pufferfish.java
+index 1eaa5e5fb65b18e5042d69b5dbfea15a7271c0aa..b2932aeb6000a4e268db12cb7b05be746788569c 100644
+--- a/net/minecraft/world/entity/animal/fish/Pufferfish.java
++++ b/net/minecraft/world/entity/animal/fish/Pufferfish.java
+@@ -59,6 +59,13 @@ public class Pufferfish extends AbstractFish {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pufferfishMaxHealth);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/fish/Salmon.java b/net/minecraft/world/entity/animal/fish/Salmon.java
+index b362ce156765ad45b8c29b5dc2c6d9d99d2e1474..97194d5c844bf96ba431c12ccc1a82cb8944c52b 100644
+--- a/net/minecraft/world/entity/animal/fish/Salmon.java
++++ b/net/minecraft/world/entity/animal/fish/Salmon.java
+@@ -52,6 +52,13 @@ public class Salmon extends AbstractSchoolingFish {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.salmonMaxHealth);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ public int getMaxSchoolSize() {
+ return 5;
+diff --git a/net/minecraft/world/entity/animal/fish/TropicalFish.java b/net/minecraft/world/entity/animal/fish/TropicalFish.java
+index 3281e75c48fb6cafdba088254009e5b4285b3819..8ffb253c114d882c9459f74a27bd8a086ae82f01 100644
+--- a/net/minecraft/world/entity/animal/fish/TropicalFish.java
++++ b/net/minecraft/world/entity/animal/fish/TropicalFish.java
+@@ -89,6 +89,13 @@ public class TropicalFish extends AbstractSchoolingFish {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.tropicalFishMaxHealth);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ public static String getPredefinedName(int variantId) {
+ return "entity.minecraft.tropical_fish.predefined." + variantId;
+ }
+diff --git a/net/minecraft/world/entity/animal/fox/Fox.java b/net/minecraft/world/entity/animal/fox/Fox.java
+index bf00cf5e6fd8b9143e1b327ef7b90ae055d264ff..6819bcb15ad6c85f41a098a9fdb73ce5a7987d8f 100644
+--- a/net/minecraft/world/entity/animal/fox/Fox.java
++++ b/net/minecraft/world/entity/animal/fox/Fox.java
+@@ -189,6 +189,14 @@ public class Fox extends Animal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.foxMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.foxScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/golem/CopperGolem.java b/net/minecraft/world/entity/animal/golem/CopperGolem.java
+index 4dc1ce5e07e23134cf3ed68e78a055c3b75fdc83..e3c5b6fe7d6cdb674fbf5ac22001c3d917bf91ec 100644
+--- a/net/minecraft/world/entity/animal/golem/CopperGolem.java
++++ b/net/minecraft/world/entity/animal/golem/CopperGolem.java
+@@ -130,6 +130,16 @@ public class CopperGolem extends AbstractGolem implements ContainerUser, Shearab
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.copperGolemMaxHealth);
++ this.getAttribute(Attributes.STEP_HEIGHT).setBaseValue(this.level().purpurConfig.copperGolemStepHeight);
++ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.copperGolemMovementSpeed);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.copperGolemScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F).add(Attributes.STEP_HEIGHT, 1.0).add(Attributes.MAX_HEALTH, 12.0);
+ }
+diff --git a/net/minecraft/world/entity/animal/golem/IronGolem.java b/net/minecraft/world/entity/animal/golem/IronGolem.java
+index 363bf7781c8785bc6fdbc65941794a5a02f8a57a..677f584b38aeb6805db0bb867f62d5617e309f5e 100644
+--- a/net/minecraft/world/entity/animal/golem/IronGolem.java
++++ b/net/minecraft/world/entity/animal/golem/IronGolem.java
+@@ -91,6 +91,14 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ironGolemMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.ironGolemScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options
+diff --git a/net/minecraft/world/entity/animal/golem/SnowGolem.java b/net/minecraft/world/entity/animal/golem/SnowGolem.java
+index d8a3b7d329757bb84ee4d53671c89f211e8581ab..ab44bc401438d589696d9f25ebaca0fc39648bed 100644
+--- a/net/minecraft/world/entity/animal/golem/SnowGolem.java
++++ b/net/minecraft/world/entity/animal/golem/SnowGolem.java
+@@ -79,6 +79,14 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.snowGolemMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.snowGolemScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+diff --git a/net/minecraft/world/entity/animal/happyghast/HappyGhast.java b/net/minecraft/world/entity/animal/happyghast/HappyGhast.java
+index 0a75d3790a4bf4812e4f3b27ec50d67fdccf812d..cd888e070a72ff46d35a4425a0013c617b31e159 100644
+--- a/net/minecraft/world/entity/animal/happyghast/HappyGhast.java
++++ b/net/minecraft/world/entity/animal/happyghast/HappyGhast.java
+@@ -133,6 +133,19 @@ public class HappyGhast extends Animal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.happyGhastMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.happyGhastScale);
++ this.getAttribute(Attributes.TEMPT_RANGE).setBaseValue(this.level().purpurConfig.happyGhastTemptRange);
++ this.getAttribute(Attributes.FLYING_SPEED).setBaseValue(this.level().purpurConfig.happyGhastFlyingSpeed);
++ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.happyGhastMovementSpeed);
++ this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(this.level().purpurConfig.happyGhastFollowRange);
++ this.getAttribute(Attributes.CAMERA_DISTANCE).setBaseValue(this.level().purpurConfig.happyGhastCameraDistance);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void ageBoundaryReached() {
+ if (this.isBaby()) {
+@@ -156,7 +169,7 @@ public class HappyGhast extends Animal {
+
+ @Override
+ protected float sanitizeScale(float scale) {
+- return Math.min(scale, 1.0F);
++ return Math.min(scale, 1.0F); // Purpur - Configurable entity base attributes
+ }
+
+ @Override
+diff --git a/net/minecraft/world/entity/animal/nautilus/Nautilus.java b/net/minecraft/world/entity/animal/nautilus/Nautilus.java
+index a02a4b47cf02cd7eaa76d25af2dccb50ad884504..a32ac3907883f65c2a00173128a4a011fd552932 100644
+--- a/net/minecraft/world/entity/animal/nautilus/Nautilus.java
++++ b/net/minecraft/world/entity/animal/nautilus/Nautilus.java
+@@ -21,6 +21,17 @@ public class Nautilus extends AbstractNautilus {
+ super(type, level);
+ }
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.nautilusMaxHealth);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.nautilusMovementSpeed);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.nautilusAttackDamage);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.KNOCKBACK_RESISTANCE).setBaseValue(this.level().purpurConfig.nautilusKnockbackResistance);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SCALE).setBaseValue(this.level().purpurConfig.nautilusScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected Brain.Provider brainProvider() {
+ return NautilusAi.brainProvider();
+diff --git a/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java b/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java
+index 83c16a44b230efd010e06cabb428954d157cea47..7ef4a15ba2b315a41480484572a6c6898340466b 100644
+--- a/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java
++++ b/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java
+@@ -43,6 +43,17 @@ public class ZombieNautilus extends AbstractNautilus {
+ super(type, level);
+ }
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieNautilusMaxHealth);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.zombieNautilusMovementSpeed);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.zombieNautilusAttackDamage);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.KNOCKBACK_RESISTANCE).setBaseValue(this.level().purpurConfig.zombieNautilusKnockbackResistance);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SCALE).setBaseValue(this.level().purpurConfig.zombieNautilusScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return AbstractNautilus.createAttributes().add(Attributes.MOVEMENT_SPEED, 1.1F);
+ }
+diff --git a/net/minecraft/world/entity/animal/panda/Panda.java b/net/minecraft/world/entity/animal/panda/Panda.java
+index 93503f6b4eea2cb2ae6c01279e847c307920c35d..d5060fb8e9a711e6230f2c4950521d8b4f5c01d2 100644
+--- a/net/minecraft/world/entity/animal/panda/Panda.java
++++ b/net/minecraft/world/entity/animal/panda/Panda.java
+@@ -134,6 +134,15 @@ public class Panda extends Animal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pandaMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.pandaScale);
++ setAttributes();
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected boolean canDispenserEquipIntoSlot(EquipmentSlot slot) {
+ return slot == EquipmentSlot.MAINHAND && this.canPickUpLoot();
+@@ -625,7 +634,11 @@ public class Panda extends Animal {
+
+ public void setAttributes() {
+ if (this.isWeak()) {
+- this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(10.0);
++ // Purpur start - Configurable entity base attributes
++ net.minecraft.world.entity.ai.attributes.AttributeInstance maxHealth = this.getAttribute(Attributes.MAX_HEALTH);
++ maxHealth.setBaseValue(maxHealth.getValue() / 2);
++ // Purpur end - Configurable entity base attributes
++
+ }
+
+ if (this.isLazy()) {
+diff --git a/net/minecraft/world/entity/animal/parrot/Parrot.java b/net/minecraft/world/entity/animal/parrot/Parrot.java
+index 6a4d170cd1e4dde2af30895f9fbac9dd599d0602..7480a491533a47882eaf4b36c320adf45ebfb190 100644
+--- a/net/minecraft/world/entity/animal/parrot/Parrot.java
++++ b/net/minecraft/world/entity/animal/parrot/Parrot.java
+@@ -199,6 +199,14 @@ public class Parrot extends ShoulderRidingEntity implements FlyingAnimal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.parrotMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.parrotScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ public @Nullable SpawnGroupData finalizeSpawn(
+ ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
+diff --git a/net/minecraft/world/entity/animal/pig/Pig.java b/net/minecraft/world/entity/animal/pig/Pig.java
+index 2a3fc6ad3a12a3cc9815b66b659e3c9ce2afa7a8..aeb9e57db2233bff20fa5208a679ac9bcb8d5026 100644
+--- a/net/minecraft/world/entity/animal/pig/Pig.java
++++ b/net/minecraft/world/entity/animal/pig/Pig.java
+@@ -80,6 +80,14 @@ public class Pig extends Animal implements ItemSteerable {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pigMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.pigScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/animal/polarbear/PolarBear.java b/net/minecraft/world/entity/animal/polarbear/PolarBear.java
+index 718531a324c36ac65a93af5c12e0c0a3948606cb..904e4c641f1892220f263528c65f6f81708399cd 100644
+--- a/net/minecraft/world/entity/animal/polarbear/PolarBear.java
++++ b/net/minecraft/world/entity/animal/polarbear/PolarBear.java
+@@ -118,6 +118,14 @@ public class PolarBear extends Animal implements NeutralMob {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.polarBearMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.polarBearScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ public @Nullable AgeableMob getBreedOffspring(ServerLevel level, AgeableMob partner) {
+ return EntityType.POLAR_BEAR.create(level, EntitySpawnReason.BREEDING);
+diff --git a/net/minecraft/world/entity/animal/rabbit/Rabbit.java b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+index 16fbee742f28cf4571effb66265daeee64bae9b7..cfbab57dd0527c5e2f17718f3974059eb881c2ea 100644
+--- a/net/minecraft/world/entity/animal/rabbit/Rabbit.java
++++ b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+@@ -148,6 +148,14 @@ public class Rabbit extends Animal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.rabbitMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.rabbitScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ public void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/animal/sheep/Sheep.java b/net/minecraft/world/entity/animal/sheep/Sheep.java
+index a33800517d5fb5ab008e22b77be2f079901c1a99..1d60d35c1330418009f7d1d0b60d263559b68b7f 100644
+--- a/net/minecraft/world/entity/animal/sheep/Sheep.java
++++ b/net/minecraft/world/entity/animal/sheep/Sheep.java
+@@ -80,6 +80,14 @@ public class Sheep extends Animal implements Shearable {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.sheepMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.sheepScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ this.eatBlockGoal = new EatBlockGoal(this);
diff --git a/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
-index 151c2435810798708544f9cf20bcf77f5e384962..a5ff61a3697e2299c96288b6f8d7c6f2511d86d5 100644
+index 3d5cf62bd9bd99a978b7dc535675178deb695af0..eb6675394ecc5bba67e0f8bb0220ad92ef2b5e4f 100644
--- a/net/minecraft/world/entity/animal/sniffer/Sniffer.java
+++ b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
-@@ -105,6 +105,14 @@ public class Sniffer extends Animal {
+@@ -106,6 +106,14 @@ public class Sniffer extends Animal {
}
// Purpur end - Ridables
@@ -875,8 +898,83 @@ index 151c2435810798708544f9cf20bcf77f5e384962..a5ff61a3697e2299c96288b6f8d7c6f2
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/squid/GlowSquid.java b/net/minecraft/world/entity/animal/squid/GlowSquid.java
+index c5a8080aa0fa1014602ba76fb4d8ad69b926dbfa..7d41aaa0546a9ca02e46ce46e61ecc57120bfca9 100644
+--- a/net/minecraft/world/entity/animal/squid/GlowSquid.java
++++ b/net/minecraft/world/entity/animal/squid/GlowSquid.java
+@@ -50,6 +50,13 @@ public class GlowSquid extends Squid {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.glowSquidMaxHealth);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected ParticleOptions getInkParticle() {
+ return ParticleTypes.GLOW_SQUID_INK;
+diff --git a/net/minecraft/world/entity/animal/squid/Squid.java b/net/minecraft/world/entity/animal/squid/Squid.java
+index 69d87bd27a95bb9e92cd24fb7973a9b06714567e..5e4181f95711c6b0299f28de14d95da421dda373 100644
+--- a/net/minecraft/world/entity/animal/squid/Squid.java
++++ b/net/minecraft/world/entity/animal/squid/Squid.java
+@@ -93,6 +93,14 @@ public class Squid extends AgeableWaterCreature {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.squidMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.squidScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this));
+diff --git a/net/minecraft/world/entity/animal/turtle/Turtle.java b/net/minecraft/world/entity/animal/turtle/Turtle.java
+index 7699967db327cf80940bf30d8e0c734b43fd1e8f..8d9a1fe887c39588e43e4ccfc46151a033c8ccb7 100644
+--- a/net/minecraft/world/entity/animal/turtle/Turtle.java
++++ b/net/minecraft/world/entity/animal/turtle/Turtle.java
+@@ -104,6 +104,14 @@ public class Turtle extends Animal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.turtleMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.turtleScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ public void setHomePos(BlockPos homePos) {
+ this.homePos = homePos;
+ }
+diff --git a/net/minecraft/world/entity/animal/wolf/Wolf.java b/net/minecraft/world/entity/animal/wolf/Wolf.java
+index 44b650de646ea605e41f39f3d99d8f550c9a8e19..7bccee8b5dd689bbff18f34d3afac52bfe34aa42 100644
+--- a/net/minecraft/world/entity/animal/wolf/Wolf.java
++++ b/net/minecraft/world/entity/animal/wolf/Wolf.java
+@@ -208,6 +208,14 @@ public class Wolf extends TamableAnimal implements NeutralMob {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.wolfMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.wolfScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
diff --git a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
-index bc9564ee22ff9d7f6d819da9601c2d8162d304e1..ca900bb646e16c7b4342f23c3ffae786eab28145 100644
+index b8ddcc460ff1ae1cbfde70d3d8c16486bb2d3f8c..844c989fc4e0d131d823bf8a59951f35f30b7641 100644
--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
@@ -163,6 +163,13 @@ public class EnderDragon extends Mob implements Enemy {
@@ -891,9 +989,9 @@ index bc9564ee22ff9d7f6d819da9601c2d8162d304e1..ca900bb646e16c7b4342f23c3ffae786
+ // Purpur end - Configurable entity base attributes
+
public static AttributeSupplier.Builder createAttributes() {
- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0);
+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0).add(Attributes.CAMERA_DISTANCE, 16.0);
}
-@@ -1076,7 +1083,7 @@ public class EnderDragon extends Mob implements Enemy {
+@@ -1059,7 +1066,7 @@ public class EnderDragon extends Mob implements Enemy {
@Override
protected float sanitizeScale(float scale) {
@@ -903,10 +1001,10 @@ index bc9564ee22ff9d7f6d819da9601c2d8162d304e1..ca900bb646e16c7b4342f23c3ffae786
// CraftBukkit start - SPIGOT-2420: Special case, the ender dragon drops 12000 xp for the first kill and 500 xp for every other kill and this over time.
diff --git a/net/minecraft/world/entity/boss/wither/WitherBoss.java b/net/minecraft/world/entity/boss/wither/WitherBoss.java
-index 5d97ae09292fb3209e7362df778e88dc508815a3..60e666aa8afe14b519010b6d137a89e3d22f6c81 100644
+index dbf3c7049fae08dc5c4ac491a5fc8141ab177a22..612df8799b80f1793ab9781212442098633e9d65 100644
--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java
+++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java
-@@ -211,6 +211,14 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+@@ -213,6 +213,14 @@ public class WitherBoss extends Monster implements RangedAttackMob {
}
// Purpur end - Ridables
@@ -921,7 +1019,7 @@ index 5d97ae09292fb3209e7362df778e88dc508815a3..60e666aa8afe14b519010b6d137a89e3
@Override
protected PathNavigation createNavigation(Level level) {
FlyingPathNavigation flyingPathNavigation = new FlyingPathNavigation(this, level);
-@@ -433,7 +441,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+@@ -435,7 +443,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
this.setInvulnerableTicks(i);
if (this.tickCount % 10 == 0) {
@@ -931,10 +1029,10 @@ index 5d97ae09292fb3209e7362df778e88dc508815a3..60e666aa8afe14b519010b6d137a89e3
} else {
super.customServerAiStep(level);
diff --git a/net/minecraft/world/entity/monster/Blaze.java b/net/minecraft/world/entity/monster/Blaze.java
-index 201b08a75c42d90e657c3d56fc6691839e87199c..ece9e3e18c60d5ca9b4a8bd8899556c90cc8d039 100644
+index 1febee23188d91e2a27c182b97502e8c7ab696a2..4cd7975a8e9e55d6b6ded0b7e13d8da436e49c6c 100644
--- a/net/minecraft/world/entity/monster/Blaze.java
+++ b/net/minecraft/world/entity/monster/Blaze.java
-@@ -75,6 +75,14 @@ public class Blaze extends Monster {
+@@ -76,6 +76,14 @@ public class Blaze extends Monster {
}
// Purpur end - Ridables
@@ -949,49 +1047,11 @@ index 201b08a75c42d90e657c3d56fc6691839e87199c..ece9e3e18c60d5ca9b4a8bd8899556c9
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-diff --git a/net/minecraft/world/entity/monster/Bogged.java b/net/minecraft/world/entity/monster/Bogged.java
-index 2b603c1242aac307f28bae5a85bcaad309f929f5..2774602455b92745e789d83f17480c141eb89abf 100644
---- a/net/minecraft/world/entity/monster/Bogged.java
-+++ b/net/minecraft/world/entity/monster/Bogged.java
-@@ -58,6 +58,14 @@ public class Bogged extends AbstractSkeleton implements Shearable {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.boggedMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.boggedScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/monster/CaveSpider.java b/net/minecraft/world/entity/monster/CaveSpider.java
-index 4873a3d8dd9c160ecdbda594ee546c35ec03a1e7..64eecd8d1acd318743800c1daa77cd97097a0f7c 100644
---- a/net/minecraft/world/entity/monster/CaveSpider.java
-+++ b/net/minecraft/world/entity/monster/CaveSpider.java
-@@ -43,6 +43,14 @@ public class CaveSpider extends Spider {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.caveSpiderMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.caveSpiderScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- public boolean doHurtTarget(ServerLevel level, Entity source) {
- if (super.doHurtTarget(level, source)) {
diff --git a/net/minecraft/world/entity/monster/Creeper.java b/net/minecraft/world/entity/monster/Creeper.java
-index cdcee233ed0c272e4a68a2a709fe92b21bc6c22c..31ede62a19321970d26f302399a60947b8d88b37 100644
+index cfd09a5ff326cf4ecc248901696ce1f623a8e7c0..ed1ccd712a2fe00740beeee4fe615976258f5c6c 100644
--- a/net/minecraft/world/entity/monster/Creeper.java
+++ b/net/minecraft/world/entity/monster/Creeper.java
-@@ -131,6 +131,14 @@ public class Creeper extends Monster {
+@@ -137,6 +137,14 @@ public class Creeper extends Monster {
}
// Purpur end - Ridables
@@ -1006,32 +1066,8 @@ index cdcee233ed0c272e4a68a2a709fe92b21bc6c22c..31ede62a19321970d26f302399a60947
@Override
protected void registerGoals() {
this.goalSelector.addGoal(1, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java
-index c1da9ebee7e870a9143e6224be9e9f4e62232459..9c328f67260606d9252547848d5916cab4290e74 100644
---- a/net/minecraft/world/entity/monster/Drowned.java
-+++ b/net/minecraft/world/entity/monster/Drowned.java
-@@ -92,6 +92,19 @@ public class Drowned extends Zombie implements RangedAttackMob {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.drownedMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.drownedScale);
-+ }
-+
-+ @Override
-+ protected void randomizeReinforcementsChance() {
-+ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.drownedSpawnReinforcements);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void addBehaviourGoals() {
- this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0));
diff --git a/net/minecraft/world/entity/monster/ElderGuardian.java b/net/minecraft/world/entity/monster/ElderGuardian.java
-index c6eeaf7b460408acfdf89d988b47b08eab7df4c5..148ae4bca77874545a2a05fb7f29f9ac284feff6 100644
+index e5d16ca14a40d520dce43dd3d9b6347aefbd25d7..57fb334f670d35aa181b13e12fa2c5f36da1dda6 100644
--- a/net/minecraft/world/entity/monster/ElderGuardian.java
+++ b/net/minecraft/world/entity/monster/ElderGuardian.java
@@ -43,6 +43,14 @@ public class ElderGuardian extends Guardian {
@@ -1050,10 +1086,10 @@ index c6eeaf7b460408acfdf89d988b47b08eab7df4c5..148ae4bca77874545a2a05fb7f29f9ac
return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.3F).add(Attributes.ATTACK_DAMAGE, 8.0).add(Attributes.MAX_HEALTH, 80.0);
}
diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
-index cf511c78638e0d7aa652d1c880b3cd8172d5b3cf..f8d6935439b4e672ed655b2a458451d4b1fa8ffd 100644
+index bd78d8c3e8c1d9b581c751d336322fbfe20dacef..29570047bfc78a8993b0bbd7168cb4fe318a6be6 100644
--- a/net/minecraft/world/entity/monster/EnderMan.java
+++ b/net/minecraft/world/entity/monster/EnderMan.java
-@@ -107,6 +107,14 @@ public class EnderMan extends Monster implements NeutralMob {
+@@ -106,6 +106,14 @@ public class EnderMan extends Monster implements NeutralMob {
}
// Purpur end - Ridables
@@ -1069,10 +1105,10 @@ index cf511c78638e0d7aa652d1c880b3cd8172d5b3cf..f8d6935439b4e672ed655b2a458451d4
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
diff --git a/net/minecraft/world/entity/monster/Endermite.java b/net/minecraft/world/entity/monster/Endermite.java
-index f4ab2e984dd87d2372aa10d2cbfd03a3f6fb1249..2ea45eba13d0b0ea2d3c1d1a3666d6e2e027a3ef 100644
+index 844ba943a2a752f9b25506b644a4b4abc981b4cb..c6ae00f6ab83743b9ce43d9e55f04ba23b0de0f1 100644
--- a/net/minecraft/world/entity/monster/Endermite.java
+++ b/net/minecraft/world/entity/monster/Endermite.java
-@@ -62,6 +62,14 @@ public class Endermite extends Monster {
+@@ -64,6 +64,14 @@ public class Endermite extends Monster {
}
// Purpur end - Ridables
@@ -1087,30 +1123,11 @@ index f4ab2e984dd87d2372aa10d2cbfd03a3f6fb1249..2ea45eba13d0b0ea2d3c1d1a3666d6e2
@Override
protected void registerGoals() {
this.goalSelector.addGoal(1, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/monster/Evoker.java b/net/minecraft/world/entity/monster/Evoker.java
-index 2eaeb0c0c0cb917506443ed1380b81f317961d53..d3d7e11a12af404d83e81888a9a633dfb93412ec 100644
---- a/net/minecraft/world/entity/monster/Evoker.java
-+++ b/net/minecraft/world/entity/monster/Evoker.java
-@@ -67,6 +67,14 @@ public class Evoker extends SpellcasterIllager {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.evokerMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.evokerScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Ghast.java b/net/minecraft/world/entity/monster/Ghast.java
-index 00c05fb5736c90c94f6fe51793acf8b65b1d0505..c5987f50b343ded580b3d3f264498d3893433f92 100644
+index 451627153610f2c8db2403f73545c9af6dfd2e4b..7d97c00ae49629b97104631317aa6174741cdd5e 100644
--- a/net/minecraft/world/entity/monster/Ghast.java
+++ b/net/minecraft/world/entity/monster/Ghast.java
-@@ -76,6 +76,14 @@ public class Ghast extends FlyingMob implements Enemy {
+@@ -75,6 +75,14 @@ public class Ghast extends Mob implements Enemy {
}
// Purpur end - Ridables
@@ -1126,7 +1143,7 @@ index 00c05fb5736c90c94f6fe51793acf8b65b1d0505..c5987f50b343ded580b3d3f264498d38
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
diff --git a/net/minecraft/world/entity/monster/Giant.java b/net/minecraft/world/entity/monster/Giant.java
-index 135f83484ac31db7dcc225ba6f94e2e4ca27eea8..13021800af7cc9263ef4f393f9cfbda5061a32ae 100644
+index dcbe6bbce0baa4fad7fe180944beeb6ca4026f7d..416bb85fc87b5f9e372f33df8fe27f12e83834b9 100644
--- a/net/minecraft/world/entity/monster/Giant.java
+++ b/net/minecraft/world/entity/monster/Giant.java
@@ -35,6 +35,16 @@ public class Giant extends Monster {
@@ -1144,13 +1161,13 @@ index 135f83484ac31db7dcc225ba6f94e2e4ca27eea8..13021800af7cc9263ef4f393f9cfbda5
+ // Purpur end - Configurable entity base attributes
+
public static AttributeSupplier.Builder createAttributes() {
- return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0);
- }
+ return Monster.createMonsterAttributes()
+ .add(Attributes.MAX_HEALTH, 100.0)
diff --git a/net/minecraft/world/entity/monster/Guardian.java b/net/minecraft/world/entity/monster/Guardian.java
-index c20c744522459d938c772077e542ba433bc4c80e..546a4fe6d038d04c0be500e76ff4aebb02c3681a 100644
+index 4cf54e55de1ecc57061ad0c09e7966d6104f1cc2..1eaa4f255b01eddc93ddbc5615ad05e7d8273581 100644
--- a/net/minecraft/world/entity/monster/Guardian.java
+++ b/net/minecraft/world/entity/monster/Guardian.java
-@@ -90,6 +90,14 @@ public class Guardian extends Monster {
+@@ -89,6 +89,14 @@ public class Guardian extends Monster {
}
// Purpur end - Ridables
@@ -1165,52 +1182,8 @@ index c20c744522459d938c772077e542ba433bc4c80e..546a4fe6d038d04c0be500e76ff4aebb
@Override
protected void registerGoals() {
MoveTowardsRestrictionGoal moveTowardsRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0);
-diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java
-index 23936305045299352561e866b6a28aa515cd614a..c2365ae1cf6f98e262f302a117c4647c383dfbb5 100644
---- a/net/minecraft/world/entity/monster/Husk.java
-+++ b/net/minecraft/world/entity/monster/Husk.java
-@@ -38,6 +38,18 @@ public class Husk extends Zombie {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.huskMaxHealth);
-+ }
-+
-+ @Override
-+ protected void randomizeReinforcementsChance() {
-+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.huskSpawnReinforcements);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- public static boolean checkHuskSpawnRules(
- EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
- ) {
-diff --git a/net/minecraft/world/entity/monster/Illusioner.java b/net/minecraft/world/entity/monster/Illusioner.java
-index bd0f4d77260f5b123856fc7e72d5f8e74bb45321..1d1cf8748e3fba2e2963ad2fa153fbfe990f5087 100644
---- a/net/minecraft/world/entity/monster/Illusioner.java
-+++ b/net/minecraft/world/entity/monster/Illusioner.java
-@@ -74,6 +74,16 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ protected void initAttributes() {
-+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.illusionerMovementSpeed);
-+ this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(this.level().purpurConfig.illusionerFollowRange);
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.illusionerMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.illusionerScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/MagmaCube.java b/net/minecraft/world/entity/monster/MagmaCube.java
-index f10b204c18b88e9110cebf050b60c23367ea3aa0..2c6b0fd46d9ed6a8d1ca7e90ebf596dd3f310f0e 100644
+index a3cd6d4b999fc49893794838c73370c19c6a66b6..e0fda9a975e00c49ba09db65d7b3fba8fa434757 100644
--- a/net/minecraft/world/entity/monster/MagmaCube.java
+++ b/net/minecraft/world/entity/monster/MagmaCube.java
@@ -46,6 +46,28 @@ public class MagmaCube extends Slime {
@@ -1243,10 +1216,10 @@ index f10b204c18b88e9110cebf050b60c23367ea3aa0..2c6b0fd46d9ed6a8d1ca7e90ebf596dd
return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F);
}
diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
-index 75c6a43a3ab4851a47990402bee49f7e8305cd60..08fc2dc0fecfa370c99e877d502149a8ea147e5f 100644
+index 64e55d48bc81d6237970e86e6e1cc719831902fd..046d6d3b665d0dbb5403ebe91d18503ec7613936 100644
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
-@@ -151,7 +151,10 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -140,7 +140,10 @@ public class Phantom extends Mob implements Enemy {
private void updatePhantomSizeInfo() {
this.refreshDimensions();
if (level().purpurConfig.phantomFlamesOnSwoop && attackPhase == AttackPhase.SWOOP) shoot(); // Purpur - Ridables - Phantom flames on swoop
@@ -1258,8 +1231,8 @@ index 75c6a43a3ab4851a47990402bee49f7e8305cd60..08fc2dc0fecfa370c99e877d502149a8
}
public int getPhantomSize() {
-@@ -176,6 +179,23 @@ public class Phantom extends FlyingMob implements Enemy {
- return true;
+@@ -160,6 +163,23 @@ public class Phantom extends Mob implements Enemy {
+ return this.getId() * 3;
}
+ // Purpur start - Configurable entity base attributes
@@ -1282,30 +1255,11 @@ index 75c6a43a3ab4851a47990402bee49f7e8305cd60..08fc2dc0fecfa370c99e877d502149a8
@Override
public void tick() {
super.tick();
-diff --git a/net/minecraft/world/entity/monster/Pillager.java b/net/minecraft/world/entity/monster/Pillager.java
-index 4e799981f04cd17a34f043dda82869adcf16ea98..9586aa3f3eb61fb0c1224df9d0104da69d7fa6bb 100644
---- a/net/minecraft/world/entity/monster/Pillager.java
-+++ b/net/minecraft/world/entity/monster/Pillager.java
-@@ -80,6 +80,14 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pillagerMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.pillagerScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java
-index fb4e91c4f37619ce273ada0909932b32ba3b53f5..36ebfc1102a18e4050eb9a2441d75bafcf3784b8 100644
+index f7807aac5a8f9c92ba77ac38c469ef14948197ac..86c55955ff6c0a411cde34999c7bd6ad07be5d4e 100644
--- a/net/minecraft/world/entity/monster/Ravager.java
+++ b/net/minecraft/world/entity/monster/Ravager.java
-@@ -89,6 +89,14 @@ public class Ravager extends Raider {
+@@ -95,6 +95,14 @@ public class Ravager extends Raider {
}
// Purpur end - Ridables
@@ -1321,10 +1275,10 @@ index fb4e91c4f37619ce273ada0909932b32ba3b53f5..36ebfc1102a18e4050eb9a2441d75baf
protected void registerGoals() {
super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Shulker.java b/net/minecraft/world/entity/monster/Shulker.java
-index e0a496a0c584e1f90967a8528a73536fd991e774..03db684c122a07176aa1365550da935cdb66a1b9 100644
+index 9647741b67e1b4b7bbff0df22fc1bf3fb26afa73..30f2503ebd045b05f5594cef28389a694338d13a 100644
--- a/net/minecraft/world/entity/monster/Shulker.java
+++ b/net/minecraft/world/entity/monster/Shulker.java
-@@ -121,6 +121,14 @@ public class Shulker extends AbstractGolem implements VariantHolder variant) {
diff --git a/net/minecraft/world/entity/monster/Silverfish.java b/net/minecraft/world/entity/monster/Silverfish.java
-index 2e96d3de312c49fafc173e6d0c69ada1b11ae4ef..d3befe91bc65bbc2bc0d8651b78e8c9576cd0f75 100644
+index cf305d4a0a71f91caa31757dcd8ca5be84fc3f03..1df006a0a49038f1e737194e7da8e0b27e6eeb95 100644
--- a/net/minecraft/world/entity/monster/Silverfish.java
+++ b/net/minecraft/world/entity/monster/Silverfish.java
-@@ -56,6 +56,16 @@ public class Silverfish extends Monster {
+@@ -55,6 +55,16 @@ public class Silverfish extends Monster {
}
// Purpur end - Ridables
@@ -1369,29 +1323,11 @@ index 2e96d3de312c49fafc173e6d0c69ada1b11ae4ef..d3befe91bc65bbc2bc0d8651b78e8c95
@Override
protected void registerGoals() {
this.friendsGoal = new Silverfish.SilverfishWakeUpFriendsGoal(this);
-diff --git a/net/minecraft/world/entity/monster/Skeleton.java b/net/minecraft/world/entity/monster/Skeleton.java
-index d4426daf3b8079a7e769013d43f44c72b0fce697..ccd8a9867acd76e5a00d43e55e1fe64d8259de10 100644
---- a/net/minecraft/world/entity/monster/Skeleton.java
-+++ b/net/minecraft/world/entity/monster/Skeleton.java
-@@ -42,6 +42,13 @@ public class Skeleton extends AbstractSkeleton {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.skeletonMaxHealth);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
diff --git a/net/minecraft/world/entity/monster/Slime.java b/net/minecraft/world/entity/monster/Slime.java
-index 7d31d68ac0fce102af480a47db73409926611428..a6613f006521cbe93fee2eff3c348913b5939969 100644
+index 0c56f9ae47b9263ac65fd3593911e2c8479fc157..f93a2c58b5835e9ce8318d28e944533ef69df8ef 100644
--- a/net/minecraft/world/entity/monster/Slime.java
+++ b/net/minecraft/world/entity/monster/Slime.java
-@@ -99,6 +99,39 @@ public class Slime extends Mob implements Enemy {
+@@ -102,6 +102,39 @@ public class Slime extends Mob implements Enemy {
}
// Purpur end - Ridables
@@ -1431,7 +1367,7 @@ index 7d31d68ac0fce102af480a47db73409926611428..a6613f006521cbe93fee2eff3c348913
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-@@ -129,9 +162,9 @@ public class Slime extends Mob implements Enemy {
+@@ -132,9 +165,9 @@ public class Slime extends Mob implements Enemy {
this.entityData.set(ID_SIZE, i);
this.reapplyPosition();
this.refreshDimensions();
@@ -1443,48 +1379,11 @@ index 7d31d68ac0fce102af480a47db73409926611428..a6613f006521cbe93fee2eff3c348913
if (resetHealth) {
this.setHealth(this.getMaxHealth());
}
-diff --git a/net/minecraft/world/entity/monster/Spider.java b/net/minecraft/world/entity/monster/Spider.java
-index ea83335dd0d128b32d2fe513eab82e642b533b4c..38d75a0a024fa1e7b12bfc5e3ab0ec8bb98cb17a 100644
---- a/net/minecraft/world/entity/monster/Spider.java
-+++ b/net/minecraft/world/entity/monster/Spider.java
-@@ -67,6 +67,14 @@ public class Spider extends Monster {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.spiderMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.spiderScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(1, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/monster/Stray.java b/net/minecraft/world/entity/monster/Stray.java
-index ed7ba19870a09ac78c1f069040a25e47c4b19d3a..0323456fca18450c22bf3999df97ff148a89e4c5 100644
---- a/net/minecraft/world/entity/monster/Stray.java
-+++ b/net/minecraft/world/entity/monster/Stray.java
-@@ -39,6 +39,13 @@ public class Stray extends AbstractSkeleton {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.strayMaxHealth);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- public static boolean checkStraySpawnRules(
- EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
- ) {
diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java
-index 78671f02ef28f4a3b796b357d21fb4c9b64c153e..be0dc92bf5ae3da1368a649e9c4e7ff5dbb1c67c 100644
+index 46121b018c5dd87d888a3724df12a9af0d007772..3308e954c8f6deff89c6df0af01f7774e36b0385 100644
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
-@@ -111,6 +111,14 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
+@@ -109,6 +109,14 @@ public class Strider extends Animal implements ItemSteerable {
}
// Purpur end - Ridables
@@ -1500,7 +1399,7 @@ index 78671f02ef28f4a3b796b357d21fb4c9b64c153e..be0dc92bf5ae3da1368a649e9c4e7ff5
EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
) {
diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java
-index 26528bc9a9cffb68f82917a3e70900cfb65304d7..8356906b2c0707e21021bb05f9ca01a95682880a 100644
+index d567e2b9843606c36a61c83a3a4e2d181f3eefd9..32759864a8ff0c4e28ce80ae8906cbcf1927094e 100644
--- a/net/minecraft/world/entity/monster/Vex.java
+++ b/net/minecraft/world/entity/monster/Vex.java
@@ -102,6 +102,14 @@ public class Vex extends Monster implements TraceableEntity {
@@ -1518,30 +1417,11 @@ index 26528bc9a9cffb68f82917a3e70900cfb65304d7..8356906b2c0707e21021bb05f9ca01a9
@Override
public boolean isFlapping() {
return this.tickCount % TICKS_PER_FLAP == 0;
-diff --git a/net/minecraft/world/entity/monster/Vindicator.java b/net/minecraft/world/entity/monster/Vindicator.java
-index c1a1bb0be8bc77a1c0f771924f3bb8b4936d367b..0fc1b458101ba9d98d25c9637337caf0949bb893 100644
---- a/net/minecraft/world/entity/monster/Vindicator.java
-+++ b/net/minecraft/world/entity/monster/Vindicator.java
-@@ -72,6 +72,14 @@ public class Vindicator extends AbstractIllager {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vindicatorMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.vindicatorScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java
-index 0b3c78e646d68ef57a7cf5d7eb77a07c497bd216..ff8380246f6c6c805b222a91ac6a1eb0d130558d 100644
+index bcb136e71db2272dc107304b52be41f83d6772b7..3c3c258d4cc7cf7376d0d3ad0794ec3611ab81ce 100644
--- a/net/minecraft/world/entity/monster/Witch.java
+++ b/net/minecraft/world/entity/monster/Witch.java
-@@ -73,6 +73,14 @@ public class Witch extends Raider implements RangedAttackMob {
+@@ -74,6 +74,14 @@ public class Witch extends Raider implements RangedAttackMob {
}
// Purpur end - Ridables
@@ -1556,10 +1436,238 @@ index 0b3c78e646d68ef57a7cf5d7eb77a07c497bd216..ff8380246f6c6c805b222a91ac6a1eb0
@Override
protected void registerGoals() {
super.registerGoals();
-diff --git a/net/minecraft/world/entity/monster/WitherSkeleton.java b/net/minecraft/world/entity/monster/WitherSkeleton.java
-index b0f155564b11ff5fd2430694b937b7826df104ea..3342f2d92830049837636ff10b5e52f0d85fbd2c 100644
---- a/net/minecraft/world/entity/monster/WitherSkeleton.java
-+++ b/net/minecraft/world/entity/monster/WitherSkeleton.java
+diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java
+index c4f009357e416ed4052e058d8bf3b8c3e9dfd4ae..e0192a13b8d7131024471569bf34329ba0f28287 100644
+--- a/net/minecraft/world/entity/monster/Zoglin.java
++++ b/net/minecraft/world/entity/monster/Zoglin.java
+@@ -104,6 +104,14 @@ public class Zoglin extends Monster implements HoglinBase {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zoglinMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zoglinScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected Brain.Provider brainProvider() {
+ return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
+diff --git a/net/minecraft/world/entity/monster/creaking/Creaking.java b/net/minecraft/world/entity/monster/creaking/Creaking.java
+index 01d3d638e194ec5e812eea0ab96b100f4752ea18..a84edd4953e59daed6816531545a6ec1c914bce6 100644
+--- a/net/minecraft/world/entity/monster/creaking/Creaking.java
++++ b/net/minecraft/world/entity/monster/creaking/Creaking.java
+@@ -126,6 +126,14 @@ public class Creaking extends Monster {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.creakingMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.creakingScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected BodyRotationControl createBodyControl() {
+ return new Creaking.CreakingBodyRotationControl(this);
+diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+index c84f009cb0498e9c1898e310f19cff80ec6989ea..baf81e1919e64af9d6da0a49b19e5f34cf962a79 100644
+--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java
++++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+@@ -114,6 +114,14 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.hoglinMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.hoglinScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @VisibleForTesting
+ public void setTimeInOverworld(int timeInOverworld) {
+ this.timeInOverworld = timeInOverworld;
+diff --git a/net/minecraft/world/entity/monster/illager/Evoker.java b/net/minecraft/world/entity/monster/illager/Evoker.java
+index e40434d24c7a9ffe76c3410601942d0c8a963e30..46f79ed345ec51125364b49b244d6d005a3e64ae 100644
+--- a/net/minecraft/world/entity/monster/illager/Evoker.java
++++ b/net/minecraft/world/entity/monster/illager/Evoker.java
+@@ -66,6 +66,14 @@ public class Evoker extends SpellcasterIllager {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.evokerMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.evokerScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/illager/Illusioner.java b/net/minecraft/world/entity/monster/illager/Illusioner.java
+index 8a80c202752f56ba174c00531993795a4e621910..8fa53cccb73b2d8c599c898f298681735007d2a0 100644
+--- a/net/minecraft/world/entity/monster/illager/Illusioner.java
++++ b/net/minecraft/world/entity/monster/illager/Illusioner.java
+@@ -76,6 +76,16 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ protected void initAttributes() {
++ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.illusionerMovementSpeed);
++ this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(this.level().purpurConfig.illusionerFollowRange);
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.illusionerMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.illusionerScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/illager/Pillager.java b/net/minecraft/world/entity/monster/illager/Pillager.java
+index 0b97c4fe89c8549841cbb79ecb9383a9be7a44af..1e43c69366287c7a191a6f8e3a7d5459743f07a2 100644
+--- a/net/minecraft/world/entity/monster/illager/Pillager.java
++++ b/net/minecraft/world/entity/monster/illager/Pillager.java
+@@ -82,6 +82,14 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pillagerMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.pillagerScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/illager/Vindicator.java b/net/minecraft/world/entity/monster/illager/Vindicator.java
+index 4162e7ee482829f0c5276a31d44ed4c5ee24c3cf..5f3857186e86e27fe237c62cec4af13ebf58debe 100644
+--- a/net/minecraft/world/entity/monster/illager/Vindicator.java
++++ b/net/minecraft/world/entity/monster/illager/Vindicator.java
+@@ -74,6 +74,14 @@ public class Vindicator extends AbstractIllager {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vindicatorMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.vindicatorScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java
+index a42b84611836b970d0d7ddb602bd04d9ec850712..98241af88cc961470e07df47d128d8912338bd44 100644
+--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
++++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
+@@ -158,6 +158,14 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.piglinScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
+diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
+index e33809e9ccc4a65909f1c12ec4b0fdc4050aeee7..3d34bef7ffe9e66e77e3fc10b2c5869d98a4a5c9 100644
+--- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
++++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
+@@ -82,6 +82,14 @@ public class PiglinBrute extends AbstractPiglin {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinBruteMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.piglinBruteScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return Monster.createMonsterAttributes()
+ .add(Attributes.MAX_HEALTH, 50.0)
+diff --git a/net/minecraft/world/entity/monster/skeleton/Bogged.java b/net/minecraft/world/entity/monster/skeleton/Bogged.java
+index 10e66643a918184d858a4e6c9de7a6c2664fbcaf..f1e9cec85ce911a50bb83eff9228d6b98aa00d44 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Bogged.java
++++ b/net/minecraft/world/entity/monster/skeleton/Bogged.java
+@@ -58,6 +58,14 @@ public class Bogged extends AbstractSkeleton implements Shearable {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.boggedMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.boggedScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/monster/skeleton/Skeleton.java b/net/minecraft/world/entity/monster/skeleton/Skeleton.java
+index 7f8298892565b073373ad68f9c1399a9c565c29a..96d989cffc6ff72954ed92e2535c72992d489372 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Skeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/Skeleton.java
+@@ -43,6 +43,13 @@ public class Skeleton extends AbstractSkeleton {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.skeletonMaxHealth);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/monster/skeleton/Stray.java b/net/minecraft/world/entity/monster/skeleton/Stray.java
+index 23ceecffe8f1b758433e02b61cae421c518cc841..575f30cc9a6166a4e0733cc33e8b5814acb92660 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Stray.java
++++ b/net/minecraft/world/entity/monster/skeleton/Stray.java
+@@ -40,6 +40,13 @@ public class Stray extends AbstractSkeleton {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.strayMaxHealth);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ public static boolean checkStraySpawnRules(
+ EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
+diff --git a/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java b/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
+index d49200718e7fab29ce5e55278b7584458bfb10e7..f38bb54c0f5d7797179e5e75eb8092baea7b9dcb 100644
+--- a/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
@@ -51,6 +51,14 @@ public class WitherSkeleton extends AbstractSkeleton {
}
// Purpur end - Ridables
@@ -1575,30 +1683,96 @@ index b0f155564b11ff5fd2430694b937b7826df104ea..3342f2d92830049837636ff10b5e52f0
@Override
protected void registerGoals() {
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true));
-diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java
-index b279e33bb14dfea4813bba770daf950f5343419d..132b38d717ac3c5acc64a5ec519f345ac57021d8 100644
---- a/net/minecraft/world/entity/monster/Zoglin.java
-+++ b/net/minecraft/world/entity/monster/Zoglin.java
-@@ -102,6 +102,14 @@ public class Zoglin extends Monster implements HoglinBase {
+diff --git a/net/minecraft/world/entity/monster/spider/CaveSpider.java b/net/minecraft/world/entity/monster/spider/CaveSpider.java
+index 17a9b046ccd8de37aa79501f7556a5a816dfa90f..a1391173cc4997df723c59f176726dde88491978 100644
+--- a/net/minecraft/world/entity/monster/spider/CaveSpider.java
++++ b/net/minecraft/world/entity/monster/spider/CaveSpider.java
+@@ -43,6 +43,14 @@ public class CaveSpider extends Spider {
}
// Purpur end - Ridables
+ // Purpur start - Configurable entity base attributes
+ @Override
+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zoglinMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zoglinScale);
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.caveSpiderMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.caveSpiderScale);
+ }
+ // Purpur end - Configurable entity base attributes
+
@Override
- protected Brain.Provider brainProvider() {
- return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
-index 6c6806fd7204e3610142f0365d158aee33ef8b2c..8886aa0da372223ecd4d1a17c60971e167ced886 100644
---- a/net/minecraft/world/entity/monster/Zombie.java
-+++ b/net/minecraft/world/entity/monster/Zombie.java
-@@ -117,6 +117,14 @@ public class Zombie extends Monster {
+ public boolean doHurtTarget(ServerLevel level, Entity target) {
+ if (super.doHurtTarget(level, target)) {
+diff --git a/net/minecraft/world/entity/monster/spider/Spider.java b/net/minecraft/world/entity/monster/spider/Spider.java
+index 7a8b9c83490a05629e4996844a575ba4c7e9f156..6a9c807ed50dab4b65787d9f7269385103fa5f26 100644
+--- a/net/minecraft/world/entity/monster/spider/Spider.java
++++ b/net/minecraft/world/entity/monster/spider/Spider.java
+@@ -69,6 +69,14 @@ public class Spider extends Monster {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.spiderMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.spiderScale);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/monster/zombie/Drowned.java b/net/minecraft/world/entity/monster/zombie/Drowned.java
+index 03c801d5982eed73fd8f56f63ccab570e83b8a53..b5d3bfb68d8f167e5d6439d15024597d7d2a40a7 100644
+--- a/net/minecraft/world/entity/monster/zombie/Drowned.java
++++ b/net/minecraft/world/entity/monster/zombie/Drowned.java
+@@ -96,6 +96,19 @@ public class Drowned extends Zombie implements RangedAttackMob {
+ return new AmphibiousPathNavigation(this, level);
+ }
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.drownedMaxHealth);
++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.drownedScale);
++ }
++
++ @Override
++ protected void randomizeReinforcementsChance() {
++ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.drownedSpawnReinforcements);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ protected void addBehaviourGoals() {
+ this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0));
+diff --git a/net/minecraft/world/entity/monster/zombie/Husk.java b/net/minecraft/world/entity/monster/zombie/Husk.java
+index f18ac33d31ae23db02654658840b89ba03736bf3..03270138e6fae7ee28f958cafee5b74b18dce355 100644
+--- a/net/minecraft/world/entity/monster/zombie/Husk.java
++++ b/net/minecraft/world/entity/monster/zombie/Husk.java
+@@ -46,6 +46,18 @@ public class Husk extends Zombie {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Configurable entity base attributes
++ @Override
++ public void initAttributes() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.huskMaxHealth);
++ }
++
++ @Override
++ protected void randomizeReinforcementsChance() {
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.huskSpawnReinforcements);
++ }
++ // Purpur end - Configurable entity base attributes
++
+ @Override
+ public boolean isSunSensitive() {
+ return false;
+diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
+index b2d322bee9343079c0c21cc7b47493df9cfd861e..d873ca9873e95f3a5869cb63a93b0643a9c867dc 100644
+--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
++++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
+@@ -120,6 +120,14 @@ public class Zombie extends Monster {
}
// Purpur end - Ridables
@@ -1613,7 +1787,7 @@ index 6c6806fd7204e3610142f0365d158aee33ef8b2c..8886aa0da372223ecd4d1a17c60971e1
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-@@ -631,7 +639,7 @@ public class Zombie extends Monster {
+@@ -604,7 +612,7 @@ public class Zombie extends Monster {
}
protected void randomizeReinforcementsChance() {
@@ -1621,12 +1795,12 @@ index 6c6806fd7204e3610142f0365d158aee33ef8b2c..8886aa0da372223ecd4d1a17c60971e1
+ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombieSpawnReinforcements); // Purpur - Configurable entity base attributes
}
- @Override
-diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java
-index 33bb29bc03bce90750b3b9376a6ed848208a569d..578cfc33a493b5ebc2ed42733577129a8953a461 100644
---- a/net/minecraft/world/entity/monster/ZombieVillager.java
-+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
-@@ -95,6 +95,18 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
+ class ZombieAttackTurtleEggGoal extends RemoveBlockGoal {
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+index d91a1aec302a93326a357311f1743fa87ec92fa3..0a02684ec00540b91a2a68e5787e51d15b3743a7 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+@@ -102,6 +102,18 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
}
// Purpur end - Ridables
@@ -1645,11 +1819,11 @@ index 33bb29bc03bce90750b3b9376a6ed848208a569d..578cfc33a493b5ebc2ed42733577129a
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-index 369f1224ea787ae034d86d0e92696882304cb271..1424954f5b4cf0fbe821425cd741b4b5c1bfed50 100644
---- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-+++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-@@ -80,6 +80,14 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+index e2c5301a465e28cea057f9afec7e9d78090e1c9e..3ff8c95075f9d25c3a2e4160ee6d18057838a7b5 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+@@ -81,6 +81,14 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
}
// Purpur end - Ridables
@@ -1662,9 +1836,9 @@ index 369f1224ea787ae034d86d0e92696882304cb271..1424954f5b4cf0fbe821425cd741b4b5
+ // Purpur end - Configurable entity base attributes
+
@Override
- public void setPersistentAngerTarget(@Nullable UUID target) {
- this.persistentAngerTarget = target;
-@@ -262,7 +270,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
+ protected void addBehaviourGoals() {
+ this.goalSelector.addGoal(1, new SpearUseGoal<>(this, 1.0, 1.0, 10.0F, 2.0F));
+@@ -267,7 +275,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
@Override
protected void randomizeReinforcementsChance() {
@@ -1672,88 +1846,12 @@ index 369f1224ea787ae034d86d0e92696882304cb271..1424954f5b4cf0fbe821425cd741b4b5
+ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombifiedPiglinSpawnReinforcements); // Purpur - Configurable entity base attributes
}
- @Nullable
-diff --git a/net/minecraft/world/entity/monster/creaking/Creaking.java b/net/minecraft/world/entity/monster/creaking/Creaking.java
-index 57ac66c2de97c9b5940c1f0af663a1a26d2c8b73..887a81ea82b86edceaa46eb2032f53fccb84e158 100644
---- a/net/minecraft/world/entity/monster/creaking/Creaking.java
-+++ b/net/minecraft/world/entity/monster/creaking/Creaking.java
-@@ -125,6 +125,14 @@ public class Creaking extends Monster {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.creakingMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.creakingScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
@Override
- protected BodyRotationControl createBodyControl() {
- return new Creaking.CreakingBodyRotationControl(this);
-diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
-index 028e09e1d8a14d989b2c19ca62e6544a93e1f1c4..54924cd7c84cbcd22ffc0bd37fc24f24e73c18bc 100644
---- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java
-+++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
-@@ -109,6 +109,14 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.hoglinMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.hoglinScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @VisibleForTesting
- public void setTimeInOverworld(int timeInOverworld) {
- this.timeInOverworld = timeInOverworld;
-diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java
-index 02d748ecb10c3e20aafc0c449b99ca5b6cd80e04..897c57263ab7347987b289016a71d11f693bc8b2 100644
---- a/net/minecraft/world/entity/monster/piglin/Piglin.java
-+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
-@@ -168,6 +168,14 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.piglinScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- @Override
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
-diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
-index 97241682311797faa93927e0477a7646ce53b2c8..eb82252cd87797927e153974b9280b5eaa251080 100644
---- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
-+++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
-@@ -82,6 +82,14 @@ public class PiglinBrute extends AbstractPiglin {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Configurable entity base attributes
-+ @Override
-+ public void initAttributes() {
-+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinBruteMaxHealth);
-+ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.piglinBruteScale);
-+ }
-+ // Purpur end - Configurable entity base attributes
-+
- public static AttributeSupplier.Builder createAttributes() {
- return Monster.createMonsterAttributes()
- .add(Attributes.MAX_HEALTH, 50.0)
-diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
-index a7424ad414b72d2adaf0863bf1055f3eff5e2989..c4ce3a2f03bb7665beb131892288d8e4f722a4b5 100644
---- a/net/minecraft/world/entity/npc/Villager.java
-+++ b/net/minecraft/world/entity/npc/Villager.java
-@@ -268,6 +268,14 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+diff --git a/net/minecraft/world/entity/npc/villager/Villager.java b/net/minecraft/world/entity/npc/villager/Villager.java
+index 6d4ef7b5d64639eb7fe400b2ed612c3b3552aa52..6f9658af51f1f30434756f871cf6ab5cd2f3a7ea 100644
+--- a/net/minecraft/world/entity/npc/villager/Villager.java
++++ b/net/minecraft/world/entity/npc/villager/Villager.java
+@@ -272,6 +272,14 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
// Purpur end - Ridables
@@ -1768,11 +1866,11 @@ index a7424ad414b72d2adaf0863bf1055f3eff5e2989..c4ce3a2f03bb7665beb131892288d8e4
@Override
public Brain getBrain() {
return (Brain)super.getBrain();
-diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java
-index 0f8ec3abead11c46205cd21290c65ec2b859efdc..5d5fa6b4ad18b4213f5098e4d708f3301a6f59c6 100644
---- a/net/minecraft/world/entity/npc/WanderingTrader.java
-+++ b/net/minecraft/world/entity/npc/WanderingTrader.java
-@@ -93,6 +93,13 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
+diff --git a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+index 5c7da654ef967356173a9d85a8675a7dc61ef395..9d5dbaeafd899594425547fc58b87a1d0a52066e 100644
+--- a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
++++ b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+@@ -85,6 +85,13 @@ public class WanderingTrader extends AbstractVillager implements Consumable.Over
}
// Purpur end - Ridables
diff --git a/purpur-server/minecraft-patches/features/0003-Barrels-and-enderchests-6-rows.patch b/purpur-server/minecraft-patches/features/0003-Barrels-and-enderchests-6-rows.patch
index af661d0d6..638bae2f4 100644
--- a/purpur-server/minecraft-patches/features/0003-Barrels-and-enderchests-6-rows.patch
+++ b/purpur-server/minecraft-patches/features/0003-Barrels-and-enderchests-6-rows.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Barrels and enderchests 6 rows
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
-index 2d09f2a2c97f29ac0d941b7a3fb941102a5d545e..94abb9d8f6381aee000dbd0720477db8b7ca279c 100644
+index 80986de9222010f01982cfdab58649429d457778..22f768d805bfc1c6e6e50449e1d275c3195036ad 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
-@@ -1027,6 +1027,27 @@ public abstract class PlayerList {
+@@ -887,6 +887,27 @@ public abstract class PlayerList {
player.getBukkitEntity().recalculatePermissions(); // CraftBukkit
this.server.getCommands().sendCommands(player);
} // Paper - Add sendOpLevel API
@@ -35,12 +35,12 @@ index 2d09f2a2c97f29ac0d941b7a3fb941102a5d545e..94abb9d8f6381aee000dbd0720477db8
+ // Purpur end - Barrels and enderchests 6 rows
}
- public boolean isWhiteListed(GameProfile profile) {
+ // Paper start - whitelist verify event / login event
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
-index ca998a8a480af63d4a5f58a1f4490528a7b33c69..43657822f0660613078e9afa512000b5255a1537 100644
+index 4bf98783e7199bc5c7c05c953729523b0b75b2b5..c4039b1ba46ea72c7cd1cbed9e8edbffc5d5e1cc 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
-@@ -202,6 +202,7 @@ public abstract class Player extends LivingEntity {
+@@ -181,6 +181,7 @@ public abstract class Player extends Avatar implements ContainerUser {
public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage
public int burpDelay = 0; // Purpur - Burp delay
public boolean canPortalInstant = false; // Purpur - Add portal permission bypass
@@ -49,7 +49,7 @@ index ca998a8a480af63d4a5f58a1f4490528a7b33c69..43657822f0660613078e9afa512000b5
// CraftBukkit start
public boolean fauxSleeping;
diff --git a/net/minecraft/world/inventory/ChestMenu.java b/net/minecraft/world/inventory/ChestMenu.java
-index 280169afbd637eeb67ddf7eaeb4eecd464a128d5..ba7730a24831efa33de4c5ffce57bfa7177f89d6 100644
+index 1fb3a34ea872dec73658fac59743e46ef8db5151..4c3b8d7ba777916ffc5ad0feccffbc7634bffe8d 100644
--- a/net/minecraft/world/inventory/ChestMenu.java
+++ b/net/minecraft/world/inventory/ChestMenu.java
@@ -66,10 +66,30 @@ public class ChestMenu extends AbstractContainerMenu {
@@ -84,10 +84,10 @@ index 280169afbd637eeb67ddf7eaeb4eecd464a128d5..ba7730a24831efa33de4c5ffce57bfa7
return new ChestMenu(MenuType.GENERIC_9x6, containerId, playerInventory, container, 6);
}
diff --git a/net/minecraft/world/inventory/PlayerEnderChestContainer.java b/net/minecraft/world/inventory/PlayerEnderChestContainer.java
-index a6a359bab2a727f4631b633a8bb370dd40decc75..d2d75e5c34c97300ce5da8c7ea70958aba31fa4a 100644
+index 9749909b8253b432bb2f7fba2cd8ff17a8579b30..2c65c6428cb5925f8505cb0836b359f7e18c64eb 100644
--- a/net/minecraft/world/inventory/PlayerEnderChestContainer.java
+++ b/net/minecraft/world/inventory/PlayerEnderChestContainer.java
-@@ -25,11 +25,18 @@ public class PlayerEnderChestContainer extends SimpleContainer {
+@@ -26,11 +26,18 @@ public class PlayerEnderChestContainer extends SimpleContainer {
}
public PlayerEnderChestContainer(Player owner) {
@@ -108,7 +108,7 @@ index a6a359bab2a727f4631b633a8bb370dd40decc75..d2d75e5c34c97300ce5da8c7ea70958a
this.activeChest = enderChestBlockEntity;
}
diff --git a/net/minecraft/world/level/block/EnderChestBlock.java b/net/minecraft/world/level/block/EnderChestBlock.java
-index f5533960708bdbaf2eacefbc7c7c3123b7d26502..17aa27885b4431bf7b98799e02d080b5a0ecbbf1 100644
+index 383e8285d366c7f594b0b4ff55b367970c9b69e4..077edf449d4faa41abafb94ac41dfe822f449d04 100644
--- a/net/minecraft/world/level/block/EnderChestBlock.java
+++ b/net/minecraft/world/level/block/EnderChestBlock.java
@@ -85,8 +85,8 @@ public class EnderChestBlock extends AbstractChestBlock i
@@ -159,13 +159,13 @@ index f5533960708bdbaf2eacefbc7c7c3123b7d26502..17aa27885b4431bf7b98799e02d080b5
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new EnderChestBlockEntity(pos, state);
diff --git a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
-index 0f808855f58281578c2758513787f0f7330c9291..9f6063089f0aa3a68d26ae7cfe39379123ab2f47 100644
+index 75c09a2079c89f9346391abdd01ef8790b9cbb13..04f6b3c328377091734a111f5a219379e32b5640 100644
--- a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
-@@ -55,7 +55,17 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
- this.maxStack = i;
+@@ -59,7 +59,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
}
// CraftBukkit end
+ private static final Component DEFAULT_NAME = Component.translatable("container.barrel");
- private NonNullList items = NonNullList.withSize(27, ItemStack.EMPTY);
+ // Purpur start - Barrels and enderchests 6 rows
+ private NonNullList items = NonNullList.withSize(switch (org.purpurmc.purpur.PurpurConfig.barrelRows) {
@@ -177,11 +177,10 @@ index 0f808855f58281578c2758513787f0f7330c9291..9f6063089f0aa3a68d26ae7cfe393791
+ default -> 27;
+ }, ItemStack.EMPTY);
+ // Purpur end - Barrels and enderchests 6 rows
-+
public final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() {
@Override
protected void onOpen(Level level, BlockPos pos, BlockState state) {
-@@ -107,7 +117,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
+@@ -111,7 +120,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
@Override
public int getContainerSize() {
@@ -199,7 +198,7 @@ index 0f808855f58281578c2758513787f0f7330c9291..9f6063089f0aa3a68d26ae7cfe393791
}
@Override
-@@ -127,7 +146,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
+@@ -131,7 +149,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
@Override
protected AbstractContainerMenu createMenu(int id, Inventory player) {
diff --git a/purpur-server/minecraft-patches/features/0004-Giants-AI-settings.patch b/purpur-server/minecraft-patches/features/0004-Giants-AI-settings.patch
index 0418b7349..3ca516628 100644
--- a/purpur-server/minecraft-patches/features/0004-Giants-AI-settings.patch
+++ b/purpur-server/minecraft-patches/features/0004-Giants-AI-settings.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Giants AI settings
diff --git a/net/minecraft/world/entity/monster/Giant.java b/net/minecraft/world/entity/monster/Giant.java
-index 13021800af7cc9263ef4f393f9cfbda5061a32ae..73da18c4b54e250c434fd75971ef0a8f7c8cf6a3 100644
+index 416bb85fc87b5f9e372f33df8fe27f12e83834b9..40cf8f44a6b01d45306dab4ba4f9a7ea7c6590a9 100644
--- a/net/minecraft/world/entity/monster/Giant.java
+++ b/net/minecraft/world/entity/monster/Giant.java
@@ -30,8 +30,25 @@ public class Giant extends Monster {
@@ -25,19 +25,19 @@ index 13021800af7cc9263ef4f393f9cfbda5061a32ae..73da18c4b54e250c434fd75971ef0a8f
+ if (level().purpurConfig.giantHaveHostileAI) {
+ this.goalSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.0D, false));
+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this));
-+ this.targetSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class));
++ this.targetSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal(this).setAlertOthers(net.minecraft.world.entity.monster.zombie.ZombifiedPiglin.class));
+ this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.player.Player.class, true));
-+ this.targetSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.npc.Villager.class, false));
-+ this.targetSelector.addGoal(4, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.animal.IronGolem.class, true));
-+ this.targetSelector.addGoal(5, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.animal.Turtle.class, true));
++ this.targetSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.npc.villager.Villager.class, false));
++ this.targetSelector.addGoal(4, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.animal.golem.IronGolem.class, true));
++ this.targetSelector.addGoal(5, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.animal.turtle.Turtle.class, true));
+ }
+ }
+ // Purpur end - Giants AI settings
}
// Purpur end - Ridables
-@@ -49,8 +66,36 @@ public class Giant extends Monster {
- return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0);
+@@ -53,8 +70,36 @@ public class Giant extends Monster {
+ .add(Attributes.CAMERA_DISTANCE, 16.0);
}
+ // Purpur - Giants AI settings
diff --git a/purpur-server/minecraft-patches/features/0005-Chickens-can-retaliate.patch b/purpur-server/minecraft-patches/features/0005-Chickens-can-retaliate.patch
index 9156be5d5..deaa95d09 100644
--- a/purpur-server/minecraft-patches/features/0005-Chickens-can-retaliate.patch
+++ b/purpur-server/minecraft-patches/features/0005-Chickens-can-retaliate.patch
@@ -4,11 +4,11 @@ Date: Sun, 12 Apr 2020 13:19:34 -0500
Subject: [PATCH] Chickens can retaliate
-diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java
-index 509163f409a5b8988a484aedb2f3ddf042d5eb13..d718f0ed362c49803260dceed64bd93e2b6744fc 100644
---- a/net/minecraft/world/entity/animal/Chicken.java
-+++ b/net/minecraft/world/entity/animal/Chicken.java
-@@ -73,6 +73,11 @@ public class Chicken extends Animal {
+diff --git a/net/minecraft/world/entity/animal/chicken/Chicken.java b/net/minecraft/world/entity/animal/chicken/Chicken.java
+index bfc5c6639ef1005d2752d5164f3613ddacc46bf1..52a0bf792337e2f1cf11e215b033caae21ee774b 100644
+--- a/net/minecraft/world/entity/animal/chicken/Chicken.java
++++ b/net/minecraft/world/entity/animal/chicken/Chicken.java
+@@ -95,6 +95,11 @@ public class Chicken extends Animal {
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.chickenMaxHealth);
this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.chickenScale);
@@ -20,7 +20,7 @@ index 509163f409a5b8988a484aedb2f3ddf042d5eb13..d718f0ed362c49803260dceed64bd93e
}
// Purpur end - Configurable entity base attributes
-@@ -80,13 +85,21 @@ public class Chicken extends Animal {
+@@ -102,13 +107,21 @@ public class Chicken extends Animal {
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
@@ -43,7 +43,7 @@ index 509163f409a5b8988a484aedb2f3ddf042d5eb13..d718f0ed362c49803260dceed64bd93e
}
@Override
-@@ -95,7 +108,7 @@ public class Chicken extends Animal {
+@@ -117,7 +130,7 @@ public class Chicken extends Animal {
}
public static AttributeSupplier.Builder createAttributes() {
diff --git a/purpur-server/minecraft-patches/features/0006-Minecart-settings-and-WASD-controls.patch b/purpur-server/minecraft-patches/features/0006-Minecart-settings-and-WASD-controls.patch
index bdc45a90d..790c8a321 100644
--- a/purpur-server/minecraft-patches/features/0006-Minecart-settings-and-WASD-controls.patch
+++ b/purpur-server/minecraft-patches/features/0006-Minecart-settings-and-WASD-controls.patch
@@ -5,29 +5,29 @@ Subject: [PATCH] Minecart settings and WASD controls
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
-index d77381237f8a7d1b2f280a5032f5e1c8f0ab8f94..9a88ca440fad04b5941cda125c6a39d24adf6d37 100644
+index 2eba1b0ac8b4a0bb34d04b81c4c279db6e716b3b..01efe1fbd185ebd3a60c6bbb7aa2d82817506e7d 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
-@@ -1240,6 +1240,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
+@@ -1311,6 +1311,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
} else {
// Purpur start - Add boat fall damage config
if (damageSource.is(net.minecraft.tags.DamageTypeTags.IS_FALL)) {
+ // Purpur start - Minecart settings and WASD controls
-+ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.AbstractMinecart && level().purpurConfig.minecartControllable && !level().purpurConfig.minecartControllableFallDamage) {
++ if (getRootVehicle() instanceof AbstractMinecart && level().purpurConfig.minecartControllable && !level().purpurConfig.minecartControllableFallDamage) {
+ return false;
+ }
+ // Purpur end - Minecart settings and WASD controls
- if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.Boat && !level().purpurConfig.boatsDoFallDamage) {
+ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.boat.Boat && !level().purpurConfig.boatsDoFallDamage) {
return false;
}
-diff --git a/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/net/minecraft/world/entity/vehicle/AbstractMinecart.java
-index 9e15e7159cf98b3928110df9eae6de93793bf44e..6df4d736d94b9e49a3eb3d59a329e37127aa64cd 100644
---- a/net/minecraft/world/entity/vehicle/AbstractMinecart.java
-+++ b/net/minecraft/world/entity/vehicle/AbstractMinecart.java
-@@ -83,6 +83,10 @@ public abstract class AbstractMinecart extends VehicleEntity {
+diff --git a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java
+index 1123ec0038552e0b40774f4a433ff325695ea071..48099ae66045b6e78ec52832e3b972ac9c9bc246 100644
+--- a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java
++++ b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java
+@@ -105,6 +105,10 @@ public abstract class AbstractMinecart extends VehicleEntity {
private double flyingY = 0.95;
private double flyingZ = 0.95;
- public Double maxSpeed;
+ public @Nullable Double maxSpeed;
+ // Purpur start - Minecart settings and WASD controls
+ public double storedMaxSpeed;
+ public boolean isNewBehavior;
@@ -35,7 +35,7 @@ index 9e15e7159cf98b3928110df9eae6de93793bf44e..6df4d736d94b9e49a3eb3d59a329e371
public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API
// CraftBukkit end
-@@ -91,8 +95,13 @@ public abstract class AbstractMinecart extends VehicleEntity {
+@@ -113,8 +117,13 @@ public abstract class AbstractMinecart extends VehicleEntity {
this.blocksBuilding = true;
if (useExperimentalMovement(level)) {
this.behavior = new NewMinecartBehavior(this);
@@ -49,7 +49,7 @@ index 9e15e7159cf98b3928110df9eae6de93793bf44e..6df4d736d94b9e49a3eb3d59a329e371
}
}
-@@ -258,6 +267,14 @@ public abstract class AbstractMinecart extends VehicleEntity {
+@@ -278,6 +287,14 @@ public abstract class AbstractMinecart extends VehicleEntity {
@Override
public void tick() {
@@ -64,7 +64,7 @@ index 9e15e7159cf98b3928110df9eae6de93793bf44e..6df4d736d94b9e49a3eb3d59a329e371
// CraftBukkit start
double prevX = this.getX();
double prevY = this.getY();
-@@ -394,15 +411,61 @@ public abstract class AbstractMinecart extends VehicleEntity {
+@@ -392,15 +409,61 @@ public abstract class AbstractMinecart extends VehicleEntity {
this.behavior.moveAlongTrack(level);
}
@@ -127,7 +127,7 @@ index 9e15e7159cf98b3928110df9eae6de93793bf44e..6df4d736d94b9e49a3eb3d59a329e371
this.move(MoverType.SELF, this.getDeltaMovement());
if (!this.onGround()) {
diff --git a/net/minecraft/world/item/MinecartItem.java b/net/minecraft/world/item/MinecartItem.java
-index 620069daba04d48b57fc933328eda77f6ca9333e..0403b9b01994269d394820e8c8710ba1b9808bf0 100644
+index 3b511139985ea1646661ae0a6bcd1f0e386561e7..3a65e1a0b914d113feb727833803ece8f3b2e020 100644
--- a/net/minecraft/world/item/MinecartItem.java
+++ b/net/minecraft/world/item/MinecartItem.java
@@ -30,8 +30,9 @@ public class MinecartItem extends Item {
diff --git a/purpur-server/minecraft-patches/features/0007-Villagers-follow-emerald-blocks.patch b/purpur-server/minecraft-patches/features/0007-Villagers-follow-emerald-blocks.patch
index 50933fa27..cb6f356d1 100644
--- a/purpur-server/minecraft-patches/features/0007-Villagers-follow-emerald-blocks.patch
+++ b/purpur-server/minecraft-patches/features/0007-Villagers-follow-emerald-blocks.patch
@@ -5,49 +5,48 @@ Subject: [PATCH] Villagers follow emerald blocks
diff --git a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
-index 61ed4d687120fcbb7b91863e400f3657ebcde687..e773c426567964fc8269237d71c3434a5473985c 100644
+index 686776bb00560f9da8838bd5f8dd64aaddfa7a2b..ccdd439a89b7e7e10ee960cfe1e5e119d5367799 100644
--- a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
+++ b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
-@@ -162,7 +162,7 @@ public class DefaultAttributes {
+@@ -173,7 +173,7 @@ public class DefaultAttributes {
.put(EntityType.VILLAGER, Villager.createAttributes().build())
.put(EntityType.VINDICATOR, Vindicator.createAttributes().build())
.put(EntityType.WARDEN, Warden.createAttributes().build())
- .put(EntityType.WANDERING_TRADER, Mob.createMobAttributes().build())
-+ .put(EntityType.WANDERING_TRADER, net.minecraft.world.entity.npc.WanderingTrader.createAttributes().build()) // Purpur - Villagers follow emerald blocks
++ .put(EntityType.WANDERING_TRADER, net.minecraft.world.entity.npc.wanderingtrader.WanderingTrader.createAttributes().build()) // Purpur - Villagers follow emerald blocks
.put(EntityType.WITCH, Witch.createAttributes().build())
.put(EntityType.WITHER, WitherBoss.createAttributes().build())
.put(EntityType.WITHER_SKELETON, AbstractSkeleton.createAttributes().build())
diff --git a/net/minecraft/world/entity/ai/goal/TemptGoal.java b/net/minecraft/world/entity/ai/goal/TemptGoal.java
-index 438d6347778a94b4fe430320b268a2d67afa209a..f88f618d34fb343b31de3af1a875d6633703df71 100644
+index 18030dc04eb7d7971e457637b5320b1e41665658..60ebd57de496eba6ad307195ffacd3b7fc4149ff 100644
--- a/net/minecraft/world/entity/ai/goal/TemptGoal.java
+++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java
-@@ -58,7 +58,7 @@ public class TemptGoal extends Goal {
+@@ -70,7 +70,7 @@ public class TemptGoal extends Goal {
}
private boolean shouldFollow(LivingEntity entity) {
- return this.items.test(entity.getMainHandItem()) || this.items.test(entity.getOffhandItem());
-+ return (this.items.test(entity.getMainHandItem()) || this.items.test(entity.getOffhandItem())) && (!(this.mob instanceof net.minecraft.world.entity.npc.Villager villager) || !villager.isSleeping()); // Purpur - Villagers follow emerald blocks
++ return (this.items.test(entity.getMainHandItem()) || this.items.test(entity.getOffhandItem())) && (!(this.mob instanceof net.minecraft.world.entity.npc.villager.Villager villager) || !villager.isSleeping()); // Purpur - Villagers follow emerald blocks
}
@Override
-diff --git a/net/minecraft/world/entity/npc/AbstractVillager.java b/net/minecraft/world/entity/npc/AbstractVillager.java
-index a71d16d968bb90fd7aca6f01a3dd56df4f9a7ce6..b4e79cac5611942240ce85120f7bbee329ae2fb8 100644
---- a/net/minecraft/world/entity/npc/AbstractVillager.java
-+++ b/net/minecraft/world/entity/npc/AbstractVillager.java
-@@ -45,6 +45,8 @@ import org.bukkit.event.entity.VillagerAcquireTradeEvent;
- // CraftBukkit end
+diff --git a/net/minecraft/world/entity/npc/villager/AbstractVillager.java b/net/minecraft/world/entity/npc/villager/AbstractVillager.java
+index fa8f1ea38192f9ad0a961a53399f295d83af7721..05d1a859e1aee639ad9572f2369e6db3c3d7a111 100644
+--- a/net/minecraft/world/entity/npc/villager/AbstractVillager.java
++++ b/net/minecraft/world/entity/npc/villager/AbstractVillager.java
+@@ -38,6 +38,7 @@ import net.minecraft.world.phys.Vec3;
+ import org.jspecify.annotations.Nullable;
public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, Npc, Merchant {
-+ static final net.minecraft.world.item.crafting.Ingredient TEMPT_ITEMS = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.level.block.Blocks.EMERALD_BLOCK.asItem()); // Purpur - Villagers follow emerald blocks
-+
- // CraftBukkit start
- @Override
- public CraftMerchant getCraftMerchant() {
-diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
-index c4ce3a2f03bb7665beb131892288d8e4f722a4b5..ff07cfe07200be23f17310522d737fca3251a580 100644
---- a/net/minecraft/world/entity/npc/Villager.java
-+++ b/net/minecraft/world/entity/npc/Villager.java
-@@ -265,6 +265,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
++ public static final net.minecraft.world.item.crafting.Ingredient TEMPT_ITEMS = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.level.block.Blocks.EMERALD_BLOCK.asItem()); // Purpur - Villagers follow emerald blocks
+ private static final EntityDataAccessor DATA_UNHAPPY_COUNTER = SynchedEntityData.defineId(AbstractVillager.class, EntityDataSerializers.INT);
+ public static final int VILLAGER_SLOT_OFFSET = 300;
+ private static final int VILLAGER_INVENTORY_SIZE = 8;
+diff --git a/net/minecraft/world/entity/npc/villager/Villager.java b/net/minecraft/world/entity/npc/villager/Villager.java
+index 6f9658af51f1f30434756f871cf6ab5cd2f3a7ea..02836bd2e8fda563877d3014ab839734aebc7457 100644
+--- a/net/minecraft/world/entity/npc/villager/Villager.java
++++ b/net/minecraft/world/entity/npc/villager/Villager.java
+@@ -269,6 +269,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this));
@@ -55,7 +54,7 @@ index c4ce3a2f03bb7665beb131892288d8e4f722a4b5..ff07cfe07200be23f17310522d737fca
}
// Purpur end - Ridables
-@@ -273,6 +274,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+@@ -277,6 +278,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.villagerMaxHealth);
this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.villagerScale);
@@ -63,7 +62,7 @@ index c4ce3a2f03bb7665beb131892288d8e4f722a4b5..ff07cfe07200be23f17310522d737fca
}
// Purpur end - Configurable entity base attributes
-@@ -341,7 +343,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+@@ -345,7 +347,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
public static AttributeSupplier.Builder createAttributes() {
@@ -72,11 +71,11 @@ index c4ce3a2f03bb7665beb131892288d8e4f722a4b5..ff07cfe07200be23f17310522d737fca
}
public boolean assignProfessionWhenSpawned() {
-diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java
-index 5d5fa6b4ad18b4213f5098e4d708f3301a6f59c6..4ba2921dd99f674344fe3371332c9b23365d3aa2 100644
---- a/net/minecraft/world/entity/npc/WanderingTrader.java
-+++ b/net/minecraft/world/entity/npc/WanderingTrader.java
-@@ -97,9 +97,16 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
+diff --git a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+index 9d5dbaeafd899594425547fc58b87a1d0a52066e..c6c4f4f2a970db7e782181eaca312931b192b0d5 100644
+--- a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
++++ b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+@@ -89,9 +89,16 @@ public class WanderingTrader extends AbstractVillager implements Consumable.Over
@Override
public void initAttributes() {
this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.wanderingTraderMaxHealth);
@@ -93,7 +92,7 @@ index 5d5fa6b4ad18b4213f5098e4d708f3301a6f59c6..4ba2921dd99f674344fe3371332c9b23
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
-@@ -134,6 +141,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
+@@ -126,6 +133,7 @@ public class WanderingTrader extends AbstractVillager implements Consumable.Over
this.goalSelector.addGoal(1, new PanicGoal(this, 0.5));
this.goalSelector.addGoal(1, new LookAtTradingPlayerGoal(this));
this.goalSelector.addGoal(2, new WanderingTrader.WanderToPositionGoal(this, 2.0, 0.35));
diff --git a/purpur-server/minecraft-patches/features/0009-Implement-elytra-settings.patch b/purpur-server/minecraft-patches/features/0008-Implement-elytra-settings.patch
similarity index 67%
rename from purpur-server/minecraft-patches/features/0009-Implement-elytra-settings.patch
rename to purpur-server/minecraft-patches/features/0008-Implement-elytra-settings.patch
index c3e530309..1384c26ae 100644
--- a/purpur-server/minecraft-patches/features/0009-Implement-elytra-settings.patch
+++ b/purpur-server/minecraft-patches/features/0008-Implement-elytra-settings.patch
@@ -5,12 +5,12 @@ Subject: [PATCH] Implement elytra settings
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
-index d1f7da0f4adc4609247c349d7ccdb0e6bba9b8f8..6de5f527c018201d874e06a45c9509fa12125766 100644
+index 983aea0bb8c581f06030adf74f0f7962f99c3c2a..c0a686ba573642f8f666db7c1636e29a770e9c05 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
-@@ -3595,7 +3595,18 @@ public abstract class LivingEntity extends Entity implements Attackable {
- if (i1 % 2 == 0) {
- List list = EquipmentSlot.VALUES.stream().filter(slot -> canGlideUsing(this.getItemBySlot(slot), slot)).toList();
+@@ -3883,7 +3883,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ .filter(equipmentSlot1 -> canGlideUsing(this.getItemBySlot(equipmentSlot1), equipmentSlot1))
+ .toList();
EquipmentSlot equipmentSlot = Util.getRandom(list, this.random);
- this.getItemBySlot(equipmentSlot).hurtAndBreak(1, this, equipmentSlot);
+
@@ -29,18 +29,17 @@ index d1f7da0f4adc4609247c349d7ccdb0e6bba9b8f8..6de5f527c018201d874e06a45c9509fa
this.gameEvent(GameEvent.ELYTRA_GLIDE);
diff --git a/net/minecraft/world/item/FireworkRocketItem.java b/net/minecraft/world/item/FireworkRocketItem.java
-index 75a9bd205f32b77c5d242cb9fac0f571ce36045a..b03f182c62c699cc222e67c1ae6eadf99c45d48d 100644
+index 2c597e20c1ff587f2eadef600bedb9e01b999bbf..e548f7161f14d7dc02d6882c3639ff65d59d7b37 100644
--- a/net/minecraft/world/item/FireworkRocketItem.java
+++ b/net/minecraft/world/item/FireworkRocketItem.java
-@@ -66,6 +66,19 @@ public class FireworkRocketItem extends Item implements ProjectileItem {
- com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Firework) delayed.projectile().getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand));
- if (event.callEvent() && delayed.attemptSpawn()) {
- player.awardStat(Stats.ITEM_USED.get(this)); // Moved up from below
-+
+@@ -73,6 +73,17 @@ public class FireworkRocketItem extends Item implements ProjectileItem {
+ if (player.dropAllLeashConnections(null)) {
+ level.playSound(null, player, SoundEvents.LEAD_BREAK, SoundSource.NEUTRAL, 1.0F, 1.0F);
+ }
+ // Purpur start - Implement elytra settings
+ if (level.purpurConfig.elytraDamagePerFireworkBoost > 0) {
-+ List list = net.minecraft.world.entity.EquipmentSlot.VALUES.stream().filter((enumitemslot) -> net.minecraft.world.entity.LivingEntity.canGlideUsing(player.getItemBySlot(enumitemslot), enumitemslot)).toList();
-+ net.minecraft.world.entity.EquipmentSlot enumitemslot = net.minecraft.Util.getRandom(list, player.random);
++ java.util.List list = net.minecraft.world.entity.EquipmentSlot.VALUES.stream().filter((enumitemslot) -> net.minecraft.world.entity.LivingEntity.canGlideUsing(player.getItemBySlot(enumitemslot), enumitemslot)).toList();
++ net.minecraft.world.entity.EquipmentSlot enumitemslot = net.minecraft.util.Util.getRandom(list, player.random);
+
+ ItemStack glideItem = player.getItemBySlot(enumitemslot);
+ if (player.canGlide()) {
@@ -48,15 +47,14 @@ index 75a9bd205f32b77c5d242cb9fac0f571ce36045a..b03f182c62c699cc222e67c1ae6eadf9
+ }
+ }
+ // Purpur end - Implement elytra settings
-+
if (event.shouldConsume() && !player.hasInfiniteMaterials()) {
itemInHand.shrink(1); // Moved up from below
} else {
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
-index c5426585f53a3139dc9d188a73e3a7ff4cb2e492..264b713e8b7c3d5f7d8e1facc90a60349f2cf414 100644
+index b8e38ce9b5c4b11e5bcbe6cf5603d6d39454759c..fd90ba8eba88c8d4fa372cb1047e0af8528f914d 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
-@@ -733,6 +733,14 @@ public final class ItemStack implements DataComponentHolder {
+@@ -702,6 +702,14 @@ public final class ItemStack implements DataComponentHolder {
org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent(serverPlayer, this); // Paper - Add EntityDamageItemEvent
}
// CraftBukkit end
@@ -72,18 +70,17 @@ index c5426585f53a3139dc9d188a73e3a7ff4cb2e492..264b713e8b7c3d5f7d8e1facc90a6034
onBreak.accept(item);
}
diff --git a/net/minecraft/world/item/TridentItem.java b/net/minecraft/world/item/TridentItem.java
-index 07f8c7644a112bb1ba283d1eadd8661010e888a4..7ea7db834e7b627a1d7d37ca87cd43eb61408565 100644
+index b87861c089f849e855d10c15ede53fd7c9e6a47c..633bb1a6d69b55717a9a07978b92f625ff5d066a 100644
--- a/net/minecraft/world/item/TridentItem.java
+++ b/net/minecraft/world/item/TridentItem.java
-@@ -133,6 +133,18 @@ public class TridentItem extends Item implements ProjectileItem {
+@@ -126,6 +126,17 @@ public class TridentItem extends Item implements ProjectileItem {
f1 *= tridentSpinAttackStrength / squareRoot;
f2 *= tridentSpinAttackStrength / squareRoot;
- org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(player, stack, f, f1, f2); // CraftBukkit
-+
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(player, stack, f, f1, f2)) return false; // Paper - Add player riptide event
+ // Purpur start - Implement elytra settings
-+ List list = EquipmentSlot.VALUES.stream().filter((enumitemslot) -> LivingEntity.canGlideUsing(entity.getItemBySlot(enumitemslot), enumitemslot)).toList();
++ List list = net.minecraft.world.entity.EquipmentSlot.VALUES.stream().filter((enumitemslot) -> LivingEntity.canGlideUsing(entity.getItemBySlot(enumitemslot), enumitemslot)).toList();
+ if (!list.isEmpty()) {
-+ EquipmentSlot enumitemslot = net.minecraft.Util.getRandom(list, entity.random);
++ net.minecraft.world.entity.EquipmentSlot enumitemslot = net.minecraft.util.Util.getRandom(list, entity.random);
+ ItemStack glideItem = entity.getItemBySlot(enumitemslot);
+ if (glideItem.has(net.minecraft.core.component.DataComponents.GLIDER) && level.purpurConfig.elytraDamagePerTridentBoost > 0) {
+ glideItem.hurtAndBreak(level.purpurConfig.elytraDamagePerTridentBoost, entity, enumitemslot);
diff --git a/purpur-server/minecraft-patches/features/0010-Configurable-jockey-options.patch b/purpur-server/minecraft-patches/features/0009-Configurable-jockey-options.patch
similarity index 67%
rename from purpur-server/minecraft-patches/features/0010-Configurable-jockey-options.patch
rename to purpur-server/minecraft-patches/features/0009-Configurable-jockey-options.patch
index 4a4f5728f..0857bb625 100644
--- a/purpur-server/minecraft-patches/features/0010-Configurable-jockey-options.patch
+++ b/purpur-server/minecraft-patches/features/0009-Configurable-jockey-options.patch
@@ -4,11 +4,11 @@ Date: Thu, 26 Mar 2020 21:39:32 -0500
Subject: [PATCH] Configurable jockey options
-diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java
-index 9c328f67260606d9252547848d5916cab4290e74..83fc978a94be4655e8c47ee634b8cd280d2a6fde 100644
---- a/net/minecraft/world/entity/monster/Drowned.java
-+++ b/net/minecraft/world/entity/monster/Drowned.java
-@@ -105,6 +105,23 @@ public class Drowned extends Zombie implements RangedAttackMob {
+diff --git a/net/minecraft/world/entity/monster/zombie/Drowned.java b/net/minecraft/world/entity/monster/zombie/Drowned.java
+index 0b6d2bcec8506686eb6e0aaeb14870c14bd84e9d..3b1e3e7c1218cbfdfe48db3fad15280f43fd3311 100644
+--- a/net/minecraft/world/entity/monster/zombie/Drowned.java
++++ b/net/minecraft/world/entity/monster/zombie/Drowned.java
+@@ -109,6 +109,23 @@ public class Drowned extends Zombie implements RangedAttackMob {
}
// Purpur end - Configurable entity base attributes
@@ -32,11 +32,11 @@ index 9c328f67260606d9252547848d5916cab4290e74..83fc978a94be4655e8c47ee634b8cd28
@Override
protected void addBehaviourGoals() {
this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0));
-diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java
-index c2365ae1cf6f98e262f302a117c4647c383dfbb5..7a8951f93e65c6df145e30d44b9d928dd0c39189 100644
---- a/net/minecraft/world/entity/monster/Husk.java
-+++ b/net/minecraft/world/entity/monster/Husk.java
-@@ -50,6 +50,23 @@ public class Husk extends Zombie {
+diff --git a/net/minecraft/world/entity/monster/zombie/Husk.java b/net/minecraft/world/entity/monster/zombie/Husk.java
+index 03270138e6fae7ee28f958cafee5b74b18dce355..d31145fee0f646d734e90199288b29f07854d066 100644
+--- a/net/minecraft/world/entity/monster/zombie/Husk.java
++++ b/net/minecraft/world/entity/monster/zombie/Husk.java
+@@ -58,6 +58,23 @@ public class Husk extends Zombie {
}
// Purpur end - Configurable entity base attributes
@@ -57,14 +57,14 @@ index c2365ae1cf6f98e262f302a117c4647c383dfbb5..7a8951f93e65c6df145e30d44b9d928d
+ }
+ // Purpur end - Configurable jockey options
+
- public static boolean checkHuskSpawnRules(
- EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
- ) {
-diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
-index 8886aa0da372223ecd4d1a17c60971e167ced886..63446c874e7153dcfb99133145c8b5311d7d86cd 100644
---- a/net/minecraft/world/entity/monster/Zombie.java
-+++ b/net/minecraft/world/entity/monster/Zombie.java
-@@ -125,6 +125,20 @@ public class Zombie extends Monster {
+ @Override
+ public boolean isSunSensitive() {
+ return false;
+diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
+index d873ca9873e95f3a5869cb63a93b0643a9c867dc..638642628c3dc9fa25d25c589029219c23d1e602 100644
+--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
++++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
+@@ -128,6 +128,20 @@ public class Zombie extends Monster {
}
// Purpur end - Configurable entity base attributes
@@ -85,7 +85,7 @@ index 8886aa0da372223ecd4d1a17c60971e167ced886..63446c874e7153dcfb99133145c8b531
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-@@ -556,19 +570,18 @@ public class Zombie extends Monster {
+@@ -531,19 +545,18 @@ public class Zombie extends Monster {
}
if (spawnGroupData instanceof Zombie.ZombieGroupData zombieGroupData) {
@@ -104,26 +104,26 @@ index 8886aa0da372223ecd4d1a17c60971e167ced886..63446c874e7153dcfb99133145c8b531
if (!entitiesOfClass.isEmpty()) {
Chicken chicken = entitiesOfClass.get(0);
chicken.setChickenJockey(true);
- this.startRiding(chicken);
+ this.startRiding(chicken, false, false);
- }
- } else if (random.nextFloat() < 0.05) {
+ } else { // Purpur - Configurable jockey options
Chicken chicken1 = EntityType.CHICKEN.create(this.level(), EntitySpawnReason.JOCKEY);
if (chicken1 != null) {
- chicken1.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F);
-@@ -577,6 +590,7 @@ public class Zombie extends Monster {
- this.startRiding(chicken1);
+ chicken1.snapTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F);
+@@ -552,6 +565,7 @@ public class Zombie extends Monster {
+ this.startRiding(chicken1, false, false);
level.addFreshEntity(chicken1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit
}
+ } // Purpur - Configurable jockey options
}
}
}
-diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java
-index 578cfc33a493b5ebc2ed42733577129a8953a461..f1e9bf75c50f353bd377051be82a391f97d952fd 100644
---- a/net/minecraft/world/entity/monster/ZombieVillager.java
-+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
-@@ -107,6 +107,23 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+index 0a02684ec00540b91a2a68e5787e51d15b3743a7..62f55763d95e496da8b8fcf7d95752777e323b48 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+@@ -114,6 +114,23 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
}
// Purpur end - Configurable entity base attributes
@@ -147,11 +147,11 @@ index 578cfc33a493b5ebc2ed42733577129a8953a461..f1e9bf75c50f353bd377051be82a391f
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-index 1424954f5b4cf0fbe821425cd741b4b5c1bfed50..9603589e0501feee900cd21b04eb84b02bb45de2 100644
---- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-+++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-@@ -88,6 +88,23 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+index 3ff8c95075f9d25c3a2e4160ee6d18057838a7b5..ec39ad6740361774f9ecfda7186cab9d8fac90f2 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+@@ -89,6 +89,23 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
}
// Purpur end - Configurable entity base attributes
@@ -173,5 +173,5 @@ index 1424954f5b4cf0fbe821425cd741b4b5c1bfed50..9603589e0501feee900cd21b04eb84b0
+ // Purpur end - Configurable jockey options
+
@Override
- public void setPersistentAngerTarget(@Nullable UUID target) {
- this.persistentAngerTarget = target;
+ protected void addBehaviourGoals() {
+ this.goalSelector.addGoal(1, new SpearUseGoal<>(this, 1.0, 1.0, 10.0F, 2.0F));
diff --git a/purpur-server/minecraft-patches/features/0011-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch b/purpur-server/minecraft-patches/features/0010-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch
similarity index 91%
rename from purpur-server/minecraft-patches/features/0011-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch
rename to purpur-server/minecraft-patches/features/0010-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch
index beeba7f4c..b49a87897 100644
--- a/purpur-server/minecraft-patches/features/0011-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch
+++ b/purpur-server/minecraft-patches/features/0010-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch
@@ -5,11 +5,11 @@ Subject: [PATCH] Phantoms attracted to crystals and crystals shoot phantoms
diff --git a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
-index 67711964552a8e32d3590a64aff78e1db768b026..d58829c88b86358a0c06a982b302fc9a31c15853 100644
+index d1c593ccfab7bee4366ee7c56606a230964e3fb7..21d678008fac473dff4c3e10890882ab94d0087c 100644
--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
+++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
-@@ -26,6 +26,12 @@ public class EndCrystal extends Entity {
- private static final EntityDataAccessor DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN);
+@@ -27,6 +27,12 @@ public class EndCrystal extends Entity {
+ private static final boolean DEFAULT_SHOW_BOTTOM = true;
public int time;
public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals
+ // Purpur start - Phantoms attracted to crystals and crystals shoot phantoms
@@ -19,9 +19,9 @@ index 67711964552a8e32d3590a64aff78e1db768b026..d58829c88b86358a0c06a982b302fc9a
+ private int idleCooldown = 0;
+ // Purpur end - Phantoms attracted to crystals and crystals shoot phantoms
- public EndCrystal(EntityType extends EndCrystal> entityType, Level level) {
- super(entityType, level);
-@@ -94,6 +100,49 @@ public class EndCrystal extends Entity {
+ public EndCrystal(EntityType extends EndCrystal> type, Level level) {
+ super(type, level);
+@@ -95,6 +101,49 @@ public class EndCrystal extends Entity {
// Paper end - Fix invulnerable end crystals
if (this.level().purpurConfig.endCrystalCramming > 0 && this.level().getEntitiesOfClass(EndCrystal.class, getBoundingBox()).size() > this.level().purpurConfig.endCrystalCramming) this.hurt(this.damageSources().cramming(), 6.0F); // Purpur - End Crystal Cramming
@@ -72,18 +72,18 @@ index 67711964552a8e32d3590a64aff78e1db768b026..d58829c88b86358a0c06a982b302fc9a
@Override
diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
-index 08fc2dc0fecfa370c99e877d502149a8ea147e5f..aea7b608d88d243113f67665844841ac879c3f88 100644
+index 046d6d3b665d0dbb5403ebe91d18503ec7613936..7077beafe2251fcc4e37578091bfaa02714268b9 100644
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
-@@ -47,6 +47,7 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -49,6 +49,7 @@ public class Phantom extends Mob implements Enemy {
Vec3 moveTargetPoint = Vec3.ZERO;
- public BlockPos anchorPoint = BlockPos.ZERO;
+ @Nullable public BlockPos anchorPoint;
Phantom.AttackPhase attackPhase = Phantom.AttackPhase.CIRCLE;
+ Vec3 crystalPosition; // Purpur - Phantoms attracted to crystals and crystals shoot phantoms
// Paper start
- @Nullable
- public java.util.UUID spawningEntity;
-@@ -118,6 +119,25 @@ public class Phantom extends FlyingMob implements Enemy {
+ public java.util.@Nullable UUID spawningEntity;
+ public boolean shouldBurnInDay = true;
+@@ -107,6 +108,25 @@ public class Phantom extends Mob implements Enemy {
}
// Purpur end - Ridables
@@ -109,7 +109,7 @@ index 08fc2dc0fecfa370c99e877d502149a8ea147e5f..aea7b608d88d243113f67665844841ac
@Override
public boolean isFlapping() {
return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0;
-@@ -131,9 +151,15 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -120,9 +140,15 @@ public class Phantom extends Mob implements Enemy {
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
@@ -128,7 +128,7 @@ index 08fc2dc0fecfa370c99e877d502149a8ea147e5f..aea7b608d88d243113f67665844841ac
this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal());
}
-@@ -509,6 +535,124 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -506,6 +532,124 @@ public class Phantom extends Mob implements Enemy {
}
}
diff --git a/purpur-server/minecraft-patches/features/0012-Phantoms-burn-in-light.patch b/purpur-server/minecraft-patches/features/0011-Phantoms-burn-in-light.patch
similarity index 67%
rename from purpur-server/minecraft-patches/features/0012-Phantoms-burn-in-light.patch
rename to purpur-server/minecraft-patches/features/0011-Phantoms-burn-in-light.patch
index 34631ae4b..0e9dd06e4 100644
--- a/purpur-server/minecraft-patches/features/0012-Phantoms-burn-in-light.patch
+++ b/purpur-server/minecraft-patches/features/0011-Phantoms-burn-in-light.patch
@@ -5,31 +5,31 @@ Subject: [PATCH] Phantoms burn in light
diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
-index aea7b608d88d243113f67665844841ac879c3f88..4cc1c8d8967b1e9ee5b0b1c50d887f3de3e8a882 100644
+index 7077beafe2251fcc4e37578091bfaa02714268b9..6e8fe1b694ade45ffbf0b9bb39b954deffeb2402 100644
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
-@@ -53,6 +53,7 @@ public class Phantom extends FlyingMob implements Enemy {
- public java.util.UUID spawningEntity;
+@@ -54,6 +54,7 @@ public class Phantom extends Mob implements Enemy {
+ public java.util.@Nullable UUID spawningEntity;
public boolean shouldBurnInDay = true;
// Paper end
+ private static final net.minecraft.world.item.crafting.Ingredient TORCH = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.item.Items.TORCH, net.minecraft.world.item.Items.SOUL_TORCH); // Purpur - Phantoms burn in light
- public Phantom(EntityType extends Phantom> entityType, Level level) {
- super(entityType, level);
-@@ -253,7 +254,11 @@ public class Phantom extends FlyingMob implements Enemy {
-
+ public Phantom(EntityType extends Phantom> type, Level level) {
+ super(type, level);
+@@ -238,7 +239,11 @@ public class Phantom extends Mob implements Enemy {
+ // Paper start
@Override
- public void aiStep() {
-- if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API
-+ // Purpur start - Phantoms burn in light
-+ boolean burnFromDaylight = this.shouldBurnInDay && this.isSunBurnTick() && this.level().purpurConfig.phantomBurnInDaylight;
+ public boolean isSunBurnTick() {
+- return this.shouldBurnInDay && super.isSunBurnTick();
++ // Purpur start - API for any mob to burn daylight
++ boolean burnFromDaylight = this.shouldBurnInDay && super.isSunBurnTick() && this.level().purpurConfig.phantomBurnInDaylight;
+ boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight;
-+ if (this.isAlive() && (burnFromDaylight || burnFromLightSource)) { // Paper - shouldBurnInDay API
-+ // Purpur end - Phantoms burn in light
- if (getRider() == null || !this.isControllable()) // Purpur - Ridables
- this.igniteForSeconds(8.0F);
- }
-@@ -374,6 +379,7 @@ public class Phantom extends FlyingMob implements Enemy {
++ return burnFromDaylight || burnFromLightSource;
++ // Purpur end - API for any mob to burn daylight
+ }
+ // Paper end
+
+@@ -366,6 +371,7 @@ public class Phantom extends Mob implements Enemy {
List nearbyPlayers = serverLevel.getNearbyPlayers(
this.attackTargeting, Phantom.this, Phantom.this.getBoundingBox().inflate(16.0, 64.0, 16.0)
);
@@ -37,7 +37,7 @@ index aea7b608d88d243113f67665844841ac879c3f88..4cc1c8d8967b1e9ee5b0b1c50d887f3d
if (!nearbyPlayers.isEmpty()) {
nearbyPlayers.sort(Comparator.comparing(Entity::getY).reversed());
-@@ -739,6 +745,12 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -736,6 +742,12 @@ public class Phantom extends Mob implements Enemy {
return false;
} else if (!target.isAlive()) {
return false;
diff --git a/purpur-server/minecraft-patches/features/0013-Make-entity-breeding-times-configurable.patch b/purpur-server/minecraft-patches/features/0012-Make-entity-breeding-times-configurable.patch
similarity index 52%
rename from purpur-server/minecraft-patches/features/0013-Make-entity-breeding-times-configurable.patch
rename to purpur-server/minecraft-patches/features/0012-Make-entity-breeding-times-configurable.patch
index 87761065c..2e0ef55a0 100644
--- a/purpur-server/minecraft-patches/features/0013-Make-entity-breeding-times-configurable.patch
+++ b/purpur-server/minecraft-patches/features/0012-Make-entity-breeding-times-configurable.patch
@@ -5,13 +5,13 @@ Subject: [PATCH] Make entity breeding times configurable
diff --git a/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java b/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java
-index 4fb63e58eac5d67fcd31c3233dca1dae72b98bc4..dd8d315eba203db121e24e3402f2117fc0f3043f 100644
+index 35aec6c3aa2f09f13954fda67902b3c975f566e3..fff139abc9341f3ab2dac568a922235dc5e81b3e 100644
--- a/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java
+++ b/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java
@@ -118,8 +118,10 @@ public class VillagerMakeLove extends Behavior {
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(breedOffspring, parent, partner, null, null, 0).isCancelled()) {
return Optional.empty();
}
- // Move age setting down
- parent.setAge(6000);
- partner.setAge(6000);
+ // Purpur start - Make entity breeding times configurable
@@ -19,24 +19,24 @@ index 4fb63e58eac5d67fcd31c3233dca1dae72b98bc4..dd8d315eba203db121e24e3402f2117f
+ partner.setAge(level.purpurConfig.villagerBreedingTicks);
+ // Purpur end - Make entity breeding times configurable
level.addFreshEntityWithPassengers(breedOffspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING);
- // CraftBukkit end
- level.broadcastEntityEvent(breedOffspring, (byte)12);
+ // CraftBukkit end - call EntityBreedEvent
+ level.broadcastEntityEvent(breedOffspring, EntityEvent.LOVE_HEARTS);
diff --git a/net/minecraft/world/entity/animal/Animal.java b/net/minecraft/world/entity/animal/Animal.java
-index 33c3752be451508343cad83766da7c3be1822d02..fa34e7f1c20dfd569b52a9c8e0a8d4d5e659ce20 100644
+index 2e7e7c1913f5cbc20ce116c5ae3e185fc83094c0..53d04c412d36015a30ae2680f61651db6acbf2f2 100644
--- a/net/minecraft/world/entity/animal/Animal.java
+++ b/net/minecraft/world/entity/animal/Animal.java
-@@ -40,6 +40,7 @@ public abstract class Animal extends AgeableMob {
- @Nullable
- public UUID loveCause;
- public ItemStack breedItem; // CraftBukkit - Add breedItem variable
+@@ -46,6 +46,7 @@ public abstract class Animal extends AgeableMob {
+ public int inLove = 0;
+ public @Nullable EntityReference loveCause;
+ public @Nullable ItemStack breedItem; // CraftBukkit - Add breedItem variable
+ public abstract int getPurpurBreedTime(); // Purpur - Make entity breeding times configurable
- protected Animal(EntityType extends Animal> entityType, Level level) {
- super(entityType, level);
-@@ -279,8 +280,10 @@ public abstract class Animal extends AgeableMob {
+ protected Animal(EntityType extends Animal> type, Level level) {
+ super(type, level);
+@@ -271,8 +272,10 @@ public abstract class Animal extends AgeableMob {
player.awardStat(Stats.ANIMALS_BRED);
CriteriaTriggers.BRED_ANIMALS.trigger(player, this, animal, baby);
- } // Paper
+ } // Paper - Call EntityBreedEvent
- this.setAge(6000);
- animal.setAge(6000);
+ // Purpur start - Make entity breeding times configurable
@@ -45,295 +45,12 @@ index 33c3752be451508343cad83766da7c3be1822d02..fa34e7f1c20dfd569b52a9c8e0a8d4d5
+ // Purpur end - Make entity breeding times configurable
this.resetLove();
animal.resetLove();
- level.broadcastEntityEvent(this, (byte)18);
-diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java
-index 3cdfded14a2fb74e3f345e893e60364b6b810075..199bd7e9b053a2eac76987ceb5caebc088d1071d 100644
---- a/net/minecraft/world/entity/animal/Bee.java
-+++ b/net/minecraft/world/entity/animal/Bee.java
-@@ -480,6 +480,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Make entity breeding times configurable
-+ @Override
-+ public int getPurpurBreedTime() {
-+ return this.level().purpurConfig.beeBreedingTicks;
-+ }
-+ // Purpur end - Make entity breeding times configurable
-+
- @Override
- public int getRemainingPersistentAngerTime() {
- return this.entityData.get(DATA_REMAINING_ANGER_TIME);
-diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java
-index 98ce277c5b27591e22daa3c85241be1b8689bfae..584568cef949cee24aa7850d2ff99d47cd089a6e 100644
---- a/net/minecraft/world/entity/animal/Cat.java
-+++ b/net/minecraft/world/entity/animal/Cat.java
-@@ -126,6 +126,13 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true);
-diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java
-index d718f0ed362c49803260dceed64bd93e2b6744fc..39ad1729ef03fc35a6365ee215be214eccfd959a 100644
---- a/net/minecraft/world/entity/animal/Chicken.java
-+++ b/net/minecraft/world/entity/animal/Chicken.java
-@@ -81,6 +81,13 @@ public class Chicken extends Animal {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Make entity breeding times configurable
-+ @Override
-+ public int getPurpurBreedTime() {
-+ return this.level().purpurConfig.chickenBreedingTicks;
-+ }
-+ // Purpur end - Make entity breeding times configurable
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java
-index d2a4bfa5334f7361067e4adac36ba5a4a4fa6ad8..e4965300eb41512d03a0b111422c98627cf29a54 100644
---- a/net/minecraft/world/entity/animal/Cow.java
-+++ b/net/minecraft/world/entity/animal/Cow.java
-@@ -63,6 +63,13 @@ public class Cow extends Animal {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Make entity breeding times configurable
-+ @Override
-+ public int getPurpurBreedTime() {
-+ return this.level().purpurConfig.cowBreedingTicks;
-+ }
-+ // Purpur end - Make entity breeding times configurable
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java
-index 8bf893837586ae2a9b4ef7564d242e16e4863b5d..1acf9b8c9e6a5915b3f095e83d3f209708947093 100644
---- a/net/minecraft/world/entity/animal/Fox.java
-+++ b/net/minecraft/world/entity/animal/Fox.java
-@@ -175,6 +175,13 @@ public class Fox extends Animal implements VariantHolder {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Make entity breeding times configurable
-+ @Override
-+ public int getPurpurBreedTime() {
-+ return this.level().purpurConfig.foxBreedingTicks;
-+ }
-+ // Purpur end - Make entity breeding times configurable
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-@@ -969,8 +976,10 @@ public class Fox extends Animal implements VariantHolder {
- CriteriaTriggers.BRED_ANIMALS.trigger(serverPlayer, this.animal, this.partner, fox);
- }
-
-- this.animal.setAge(6000);
-- this.partner.setAge(6000);
-+ // Purpur start - Make entity breeding times configurable
-+ this.animal.setAge(this.animal.getPurpurBreedTime());
-+ this.partner.setAge(this.partner.getPurpurBreedTime());
-+ // Purpur end - Make entity breeding times configurable
- this.animal.resetLove();
- this.partner.resetLove();
- serverLevel.addFreshEntityWithPassengers(fox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason
-diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java
-index 990723c31aa1040a4e45b9857a18d86287ef91b4..a64b609bf5ce38a252bfa1bcff869f88e14389b5 100644
---- a/net/minecraft/world/entity/animal/MushroomCow.java
-+++ b/net/minecraft/world/entity/animal/MushroomCow.java
-@@ -79,6 +79,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Make entity breeding times configurable
-+ @Override
-+ public int getPurpurBreedTime() {
-+ return this.level().purpurConfig.rabbitBreedingTicks;
-+ }
-+ // Purpur end - Make entity breeding times configurable
-+
- @Override
- public void registerGoals() {
- this.goalSelector.addGoal(1, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Sheep.java b/net/minecraft/world/entity/animal/Sheep.java
-index b66440f5cfbd714c6d2f5b7f66b4e755602b4521..882c799cb66a2acada33ff24f3adb7eb611f89c1 100644
---- a/net/minecraft/world/entity/animal/Sheep.java
-+++ b/net/minecraft/world/entity/animal/Sheep.java
-@@ -106,6 +106,13 @@ public class Sheep extends Animal implements Shearable {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Make entity breeding times configurable
-+ @Override
-+ public int getPurpurBreedTime() {
-+ return this.level().purpurConfig.sheepBreedingTicks;
-+ }
-+ // Purpur end - Make entity breeding times configurable
-+
- @Override
- protected void registerGoals() {
- this.eatBlockGoal = new EatBlockGoal(this);
-diff --git a/net/minecraft/world/entity/animal/Turtle.java b/net/minecraft/world/entity/animal/Turtle.java
-index 4f0fbbb2caeda6d1477d3297fd68f802e4f3a9ca..edbccb7ca27aa8a1917eb8b35b3ba8600c91111a 100644
---- a/net/minecraft/world/entity/animal/Turtle.java
-+++ b/net/minecraft/world/entity/animal/Turtle.java
-@@ -109,6 +109,13 @@ public class Turtle extends Animal {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Make entity breeding times configurable
-+ @Override
-+ public int getPurpurBreedTime() {
-+ return this.level().purpurConfig.turtleBreedingTicks;
-+ }
-+ // Purpur end - Make entity breeding times configurable
-+
- public void setHomePos(BlockPos homePos) {
- this.entityData.set(HOME_POS, homePos);
- }
-diff --git a/net/minecraft/world/entity/animal/Wolf.java b/net/minecraft/world/entity/animal/Wolf.java
-index afc12968313a408e8a71a20c2c0defde52605c4e..9d79946497cfc92ff11160b86d5064d86916af36 100644
---- a/net/minecraft/world/entity/animal/Wolf.java
-+++ b/net/minecraft/world/entity/animal/Wolf.java
-@@ -210,6 +210,13 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder, B
+@@ -146,6 +146,13 @@ public class Axolotl extends Animal implements Bucketable {
}
// Purpur end - Configurable entity base attributes
@@ -365,11 +82,29 @@ index f2f09a529e9db88784ff4299fdf3966046c736ab..07eee1f82331a2172aede02219a7eae8
@Override
public float getWalkTargetValue(BlockPos pos, LevelReader level) {
return 0.0F;
+diff --git a/net/minecraft/world/entity/animal/bee/Bee.java b/net/minecraft/world/entity/animal/bee/Bee.java
+index 7d7ab4c5092ac085e8cd6d3a432feb683db5a282..473aa29e3075fcab44a14c2bc14d3f222b55cbad 100644
+--- a/net/minecraft/world/entity/animal/bee/Bee.java
++++ b/net/minecraft/world/entity/animal/bee/Bee.java
+@@ -485,6 +485,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.beeBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ public long getPersistentAngerEndTime() {
+ return this.entityData.get(DATA_ANGER_END_TIME);
diff --git a/net/minecraft/world/entity/animal/camel/Camel.java b/net/minecraft/world/entity/animal/camel/Camel.java
-index 1d7e2358bac193af48dc4b7f5b0295e3bffa152b..1d7ae2a08968860636918e7c66b60139a9d761b4 100644
+index 95e86330e1e973c43e50bd4ac310212b8a057430..842b20242c323572d4c04d3a2d5fe21a54d53ed4 100644
--- a/net/minecraft/world/entity/animal/camel/Camel.java
+++ b/net/minecraft/world/entity/animal/camel/Camel.java
-@@ -90,6 +90,13 @@ public class Camel extends AbstractHorse {
+@@ -97,6 +97,13 @@ public class Camel extends AbstractHorse {
}
// Purpur end - Ridables
@@ -381,47 +116,66 @@ index 1d7e2358bac193af48dc4b7f5b0295e3bffa152b..1d7ae2a08968860636918e7c66b60139
+ // Purpur end - Make entity breeding times configurable
+
@Override
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
-diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java
-index 9a400c8bf2b54aa5fbcbe65b61670cac5fbebf05..c4ea9485294b7dec2582c638802f003ad70659b6 100644
---- a/net/minecraft/world/entity/animal/frog/Frog.java
-+++ b/net/minecraft/world/entity/animal/frog/Frog.java
-@@ -165,6 +165,12 @@ public class Frog extends Animal implements VariantHolder> {
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
+diff --git a/net/minecraft/world/entity/animal/chicken/Chicken.java b/net/minecraft/world/entity/animal/chicken/Chicken.java
+index 52a0bf792337e2f1cf11e215b033caae21ee774b..029fe4ac952d9f56824de346d98b341bd0b9b65f 100644
+--- a/net/minecraft/world/entity/animal/chicken/Chicken.java
++++ b/net/minecraft/world/entity/animal/chicken/Chicken.java
+@@ -103,6 +103,13 @@ public class Chicken extends Animal {
}
- // Purpur end - Ridables
+ // Purpur end - Configurable entity base attributes
+ // Purpur start - Make entity breeding times configurable
+ @Override
+ public int getPurpurBreedTime() {
-+ return this.level().purpurConfig.frogBreedingTicks;
-+ }
-+ // Purpur end - Make entity breeding times configurable
- @Override
- protected Brain.Provider brainProvider() {
- return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java
-index 302208b566038a3a352ca867dd70a61887bac104..0a018dbfe3750cf91892d8cfb5c0eac18e83d587 100644
---- a/net/minecraft/world/entity/animal/goat/Goat.java
-+++ b/net/minecraft/world/entity/animal/goat/Goat.java
-@@ -128,6 +128,13 @@ public class Goat extends Animal {
- }
- // Purpur end - Ridables
-
-+ // Purpur start - Make entity breeding times configurable
-+ @Override
-+ public int getPurpurBreedTime() {
-+ return this.level().purpurConfig.goatBreedingTicks;
++ return this.level().purpurConfig.chickenBreedingTicks;
+ }
+ // Purpur end - Make entity breeding times configurable
+
@Override
- protected Brain.Provider brainProvider() {
- return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java
-index 223f1d109680e3643ab2c8343be22713e89755fd..b977597785df5665176ab2f330633ec61b7c9feb 100644
---- a/net/minecraft/world/entity/animal/horse/Donkey.java
-+++ b/net/minecraft/world/entity/animal/horse/Donkey.java
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/animal/cow/Cow.java b/net/minecraft/world/entity/animal/cow/Cow.java
+index 5e5b239ebc774ae66f8c35a725ea917993239ef2..400b0a0a99590e3590cb66724acdc5ba9170f2c4 100644
+--- a/net/minecraft/world/entity/animal/cow/Cow.java
++++ b/net/minecraft/world/entity/animal/cow/Cow.java
+@@ -54,6 +54,13 @@ public class Cow extends AbstractCow {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.cowBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/cow/MushroomCow.java b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+index 85ad44eb3e64232cf1ea326257078c46288a613a..e2aa027dc7a39fa8a8868a7d153e838113fcf97b 100644
+--- a/net/minecraft/world/entity/animal/cow/MushroomCow.java
++++ b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+@@ -85,6 +85,13 @@ public class MushroomCow extends AbstractCow implements Shearable {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.mooshroomBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ public float getWalkTargetValue(BlockPos pos, LevelReader level) {
+ return level.getBlockState(pos.below()).is(Blocks.MYCELIUM) ? 10.0F : level.getPathfindingCostFromLightLevels(pos);
+diff --git a/net/minecraft/world/entity/animal/equine/Donkey.java b/net/minecraft/world/entity/animal/equine/Donkey.java
+index b85d967c7c809683e4576be30ed855941c6e68cc..d74a5cc2a43ef41fd00676bbd17fe4df9edb67ff 100644
+--- a/net/minecraft/world/entity/animal/equine/Donkey.java
++++ b/net/minecraft/world/entity/animal/equine/Donkey.java
@@ -40,6 +40,13 @@ public class Donkey extends AbstractChestedHorse {
}
// Purpur end - Configurable entity base attributes
@@ -434,13 +188,13 @@ index 223f1d109680e3643ab2c8343be22713e89755fd..b977597785df5665176ab2f330633ec6
+ // Purpur end - Make entity breeding times configurable
+
@Override
- protected SoundEvent getAmbientSound() {
+ public SoundEvent getAmbientSound() {
return SoundEvents.DONKEY_AMBIENT;
-diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java
-index 8bd118e82da9e4d4153de0a3efaf6d69e3c4c540..0339ab08b3029a9ffc102c5b865e411aca2a863c 100644
---- a/net/minecraft/world/entity/animal/horse/Horse.java
-+++ b/net/minecraft/world/entity/animal/horse/Horse.java
-@@ -67,6 +67,13 @@ public class Horse extends AbstractHorse implements VariantHolder {
+diff --git a/net/minecraft/world/entity/animal/equine/Horse.java b/net/minecraft/world/entity/animal/equine/Horse.java
+index 9a97cd588fb2dc0f393b2c8768f4e45066a34850..ba9df659ed019f9e58991059fe99c1471bfc94d8 100644
+--- a/net/minecraft/world/entity/animal/equine/Horse.java
++++ b/net/minecraft/world/entity/animal/equine/Horse.java
+@@ -74,6 +74,13 @@ public class Horse extends AbstractHorse {
}
// Purpur end - Configurable entity base attributes
@@ -454,11 +208,11 @@ index 8bd118e82da9e4d4153de0a3efaf6d69e3c4c540..0339ab08b3029a9ffc102c5b865e411a
@Override
protected void randomizeAttributes(RandomSource random) {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt));
-diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java
-index 58e726dd33f572a31b4910b9ff666c4252fb03a9..6efe52edb6909ed2b38210ce6a0334eddc55f261 100644
---- a/net/minecraft/world/entity/animal/horse/Llama.java
-+++ b/net/minecraft/world/entity/animal/horse/Llama.java
-@@ -141,6 +141,13 @@ public class Llama extends AbstractChestedHorse implements VariantHolder stack.is(ItemTags.CAT_FOOD), true);
+diff --git a/net/minecraft/world/entity/animal/feline/Ocelot.java b/net/minecraft/world/entity/animal/feline/Ocelot.java
+index c9a8dcfd1e46f97dee0393db3205049c0db1cefb..bf281fd4c050b87fd277ab68e812ab2dcd3d06aa 100644
+--- a/net/minecraft/world/entity/animal/feline/Ocelot.java
++++ b/net/minecraft/world/entity/animal/feline/Ocelot.java
+@@ -91,6 +91,13 @@ public class Ocelot extends Animal {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.ocelotBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ public boolean isTrusting() {
+ return this.entityData.get(DATA_TRUSTING);
+ }
+diff --git a/net/minecraft/world/entity/animal/fox/Fox.java b/net/minecraft/world/entity/animal/fox/Fox.java
+index 6819bcb15ad6c85f41a098a9fdb73ce5a7987d8f..3c2f5e711c013a6f51093e94bc4b5518263607a2 100644
+--- a/net/minecraft/world/entity/animal/fox/Fox.java
++++ b/net/minecraft/world/entity/animal/fox/Fox.java
+@@ -197,6 +197,13 @@ public class Fox extends Animal {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.foxBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+@@ -997,8 +1004,10 @@ public class Fox extends Animal {
+ CriteriaTriggers.BRED_ANIMALS.trigger(serverPlayer, this.animal, this.partner, fox);
+ }
+
+- this.animal.setAge(6000);
+- this.partner.setAge(6000);
++ // Purpur start - Make entity breeding times configurable
++ this.animal.setAge(this.animal.getPurpurBreedTime());
++ this.partner.setAge(this.partner.getPurpurBreedTime());
++ // Purpur end - Make entity breeding times configurable
+ this.animal.resetLove();
+ this.partner.resetLove();
+ this.level.addFreshEntityWithPassengers(fox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason
+diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java
+index 5b4bb6fd100abc569c5da167735a220014bf5d8c..7d6dbdef68b25e774b5a83bb8aeb2535246459aa 100644
+--- a/net/minecraft/world/entity/animal/frog/Frog.java
++++ b/net/minecraft/world/entity/animal/frog/Frog.java
+@@ -164,6 +164,13 @@ public class Frog extends Animal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.frogBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected Brain.Provider brainProvider() {
+ return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
+diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java
+index 6e4d611c959960e8d13f79704c176b41ea5c12c4..07ba57ae845024e0f2fa03a68e126ec79bfc6b15 100644
+--- a/net/minecraft/world/entity/animal/goat/Goat.java
++++ b/net/minecraft/world/entity/animal/goat/Goat.java
+@@ -132,6 +132,13 @@ public class Goat extends Animal {
+ }
+ // Purpur end - Ridables
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.goatBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected Brain.Provider brainProvider() {
+ return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
+diff --git a/net/minecraft/world/entity/animal/happyghast/HappyGhast.java b/net/minecraft/world/entity/animal/happyghast/HappyGhast.java
+index cd888e070a72ff46d35a4425a0013c617b31e159..30204224ed83f6d3cfd64640b332b23cb74d379f 100644
+--- a/net/minecraft/world/entity/animal/happyghast/HappyGhast.java
++++ b/net/minecraft/world/entity/animal/happyghast/HappyGhast.java
+@@ -146,6 +146,13 @@ public class HappyGhast extends Animal {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return 6000;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected void ageBoundaryReached() {
+ if (this.isBaby()) {
+diff --git a/net/minecraft/world/entity/animal/nautilus/Nautilus.java b/net/minecraft/world/entity/animal/nautilus/Nautilus.java
+index a32ac3907883f65c2a00173128a4a011fd552932..98199869b70c7c0f2b744ac74961c77d473617ca 100644
+--- a/net/minecraft/world/entity/animal/nautilus/Nautilus.java
++++ b/net/minecraft/world/entity/animal/nautilus/Nautilus.java
+@@ -32,6 +32,13 @@ public class Nautilus extends AbstractNautilus {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.nautilusBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected Brain.Provider brainProvider() {
+ return NautilusAi.brainProvider();
+diff --git a/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java b/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java
+index 7ef4a15ba2b315a41480484572a6c6898340466b..94383c5020b6631203ddc4e0a58a222729ffe9a2 100644
+--- a/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java
++++ b/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java
+@@ -54,6 +54,13 @@ public class ZombieNautilus extends AbstractNautilus {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return 6000;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return AbstractNautilus.createAttributes().add(Attributes.MOVEMENT_SPEED, 1.1F);
+ }
+diff --git a/net/minecraft/world/entity/animal/panda/Panda.java b/net/minecraft/world/entity/animal/panda/Panda.java
+index d5060fb8e9a711e6230f2c4950521d8b4f5c01d2..163fe697f57459b36885fa3a18f41370347cab38 100644
+--- a/net/minecraft/world/entity/animal/panda/Panda.java
++++ b/net/minecraft/world/entity/animal/panda/Panda.java
+@@ -143,6 +143,13 @@ public class Panda extends Animal {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.pandaBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected boolean canDispenserEquipIntoSlot(EquipmentSlot slot) {
+ return slot == EquipmentSlot.MAINHAND && this.canPickUpLoot();
+diff --git a/net/minecraft/world/entity/animal/parrot/Parrot.java b/net/minecraft/world/entity/animal/parrot/Parrot.java
+index 7480a491533a47882eaf4b36c320adf45ebfb190..0d62046cb33ed750ab27229fe4f0b43c3a1dd5f4 100644
+--- a/net/minecraft/world/entity/animal/parrot/Parrot.java
++++ b/net/minecraft/world/entity/animal/parrot/Parrot.java
+@@ -207,6 +207,13 @@ public class Parrot extends ShoulderRidingEntity implements FlyingAnimal {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return 6000;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ public @Nullable SpawnGroupData finalizeSpawn(
+ ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
+diff --git a/net/minecraft/world/entity/animal/pig/Pig.java b/net/minecraft/world/entity/animal/pig/Pig.java
+index aeb9e57db2233bff20fa5208a679ac9bcb8d5026..0cb09a058c2d21b10677482792b230464ed9f951 100644
+--- a/net/minecraft/world/entity/animal/pig/Pig.java
++++ b/net/minecraft/world/entity/animal/pig/Pig.java
+@@ -88,6 +88,13 @@ public class Pig extends Animal implements ItemSteerable {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.pigBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/animal/polarbear/PolarBear.java b/net/minecraft/world/entity/animal/polarbear/PolarBear.java
+index 904e4c641f1892220f263528c65f6f81708399cd..97edd950e2142e73ad947590c99d6d5529cbd44c 100644
+--- a/net/minecraft/world/entity/animal/polarbear/PolarBear.java
++++ b/net/minecraft/world/entity/animal/polarbear/PolarBear.java
+@@ -126,6 +126,13 @@ public class PolarBear extends Animal implements NeutralMob {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.polarBearBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ public @Nullable AgeableMob getBreedOffspring(ServerLevel level, AgeableMob partner) {
+ return EntityType.POLAR_BEAR.create(level, EntitySpawnReason.BREEDING);
+diff --git a/net/minecraft/world/entity/animal/rabbit/Rabbit.java b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+index cfbab57dd0527c5e2f17718f3974059eb881c2ea..061418a25d359574c4ff44327082b08b4094ee1c 100644
+--- a/net/minecraft/world/entity/animal/rabbit/Rabbit.java
++++ b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+@@ -156,6 +156,13 @@ public class Rabbit extends Animal {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.rabbitBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ public void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/animal/sheep/Sheep.java b/net/minecraft/world/entity/animal/sheep/Sheep.java
+index 1d60d35c1330418009f7d1d0b60d263559b68b7f..0e4505474a50d57338c16648cb6049d35455fdc6 100644
+--- a/net/minecraft/world/entity/animal/sheep/Sheep.java
++++ b/net/minecraft/world/entity/animal/sheep/Sheep.java
+@@ -88,6 +88,13 @@ public class Sheep extends Animal implements Shearable {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.sheepBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected void registerGoals() {
+ this.eatBlockGoal = new EatBlockGoal(this);
diff --git a/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
-index a5ff61a3697e2299c96288b6f8d7c6f2511d86d5..11a5da22149a61ca48bbb0a8ed10b71e91a5cc98 100644
+index eb6675394ecc5bba67e0f8bb0220ad92ef2b5e4f..7ef3c94f63c8a25d09e69b818ecdf79795803570 100644
--- a/net/minecraft/world/entity/animal/sniffer/Sniffer.java
+++ b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
-@@ -113,6 +113,13 @@ public class Sniffer extends Animal {
+@@ -114,6 +114,13 @@ public class Sniffer extends Animal {
}
// Purpur end - Configurable entity base attributes
@@ -562,11 +581,60 @@ index a5ff61a3697e2299c96288b6f8d7c6f2511d86d5..11a5da22149a61ca48bbb0a8ed10b71e
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/turtle/Turtle.java b/net/minecraft/world/entity/animal/turtle/Turtle.java
+index 8d9a1fe887c39588e43e4ccfc46151a033c8ccb7..fce1b1a22e091a1c05650c72e1ceb83e1a1d1ed1 100644
+--- a/net/minecraft/world/entity/animal/turtle/Turtle.java
++++ b/net/minecraft/world/entity/animal/turtle/Turtle.java
+@@ -112,6 +112,13 @@ public class Turtle extends Animal {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.turtleBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ public void setHomePos(BlockPos homePos) {
+ this.homePos = homePos;
+ }
+@@ -343,8 +350,10 @@ public class Turtle extends Animal {
+ }
+
+ this.turtle.setHasEgg(true);
+- this.animal.setAge(6000);
+- this.partner.setAge(6000);
++ // Purpur start - Make entity breeding times configurable
++ this.animal.setAge(this.animal.getPurpurBreedTime());
++ this.partner.setAge(this.partner.getPurpurBreedTime());
++ // Purpur end - Make entity breeding times configurable
+ this.animal.resetLove();
+ this.partner.resetLove();
+ RandomSource random = this.animal.getRandom();
+diff --git a/net/minecraft/world/entity/animal/wolf/Wolf.java b/net/minecraft/world/entity/animal/wolf/Wolf.java
+index 7bccee8b5dd689bbff18f34d3afac52bfe34aa42..08a1bafa0e45dbdbf8bdc4d5cb654d080590707d 100644
+--- a/net/minecraft/world/entity/animal/wolf/Wolf.java
++++ b/net/minecraft/world/entity/animal/wolf/Wolf.java
+@@ -216,6 +216,13 @@ public class Wolf extends TamableAnimal implements NeutralMob {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Make entity breeding times configurable
++ @Override
++ public int getPurpurBreedTime() {
++ return this.level().purpurConfig.wolfBreedingTicks;
++ }
++ // Purpur end - Make entity breeding times configurable
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java
-index be0dc92bf5ae3da1368a649e9c4e7ff5dbb1c67c..f36e94437b4e21961532ac9ab91767617f9c3c32 100644
+index 3308e954c8f6deff89c6df0af01f7774e36b0385..ad6515c2dcde0079095c6777f56319e9901850f8 100644
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
-@@ -119,6 +119,13 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
+@@ -117,6 +117,13 @@ public class Strider extends Animal implements ItemSteerable {
}
// Purpur end - Configurable entity base attributes
@@ -581,12 +649,12 @@ index be0dc92bf5ae3da1368a649e9c4e7ff5dbb1c67c..f36e94437b4e21961532ac9ab9176761
EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
) {
diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
-index 54924cd7c84cbcd22ffc0bd37fc24f24e73c18bc..266d1838e6602ef6322c15732f2693a865911f2e 100644
+index baf81e1919e64af9d6da0a49b19e5f34cf962a79..4498fe26dff2cdec8e90d6559a66ebe7859195bb 100644
--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
@@ -122,6 +122,13 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
- this.timeInOverworld = timeInOverworld;
}
+ // Purpur end - Configurable entity base attributes
+ // Purpur start - Make entity breeding times configurable
+ @Override
@@ -595,6 +663,6 @@ index 54924cd7c84cbcd22ffc0bd37fc24f24e73c18bc..266d1838e6602ef6322c15732f2693a8
+ }
+ // Purpur end - Make entity breeding times configurable
+
- @Override
- public boolean canBeLeashed() {
- return true;
+ @VisibleForTesting
+ public void setTimeInOverworld(int timeInOverworld) {
+ this.timeInOverworld = timeInOverworld;
diff --git a/purpur-server/minecraft-patches/features/0014-Apply-display-names-from-item-forms-of-entities-to-e.patch b/purpur-server/minecraft-patches/features/0013-Apply-display-names-from-item-forms-of-entities-to-e.patch
similarity index 72%
rename from purpur-server/minecraft-patches/features/0014-Apply-display-names-from-item-forms-of-entities-to-e.patch
rename to purpur-server/minecraft-patches/features/0013-Apply-display-names-from-item-forms-of-entities-to-e.patch
index 15d244724..6095f7e7c 100644
--- a/purpur-server/minecraft-patches/features/0014-Apply-display-names-from-item-forms-of-entities-to-e.patch
+++ b/purpur-server/minecraft-patches/features/0013-Apply-display-names-from-item-forms-of-entities-to-e.patch
@@ -6,10 +6,10 @@ Subject: [PATCH] Apply display names from item forms of entities to entities
diff --git a/net/minecraft/world/entity/decoration/ArmorStand.java b/net/minecraft/world/entity/decoration/ArmorStand.java
-index d368b1971b270c44efc849464a100832bc29a679..8c0ab32487c56e2caf42404184f86c9bcf5f8b41 100644
+index 959037a01841de06767522512b92e96be7c72b56..c7be4713a526171d2c4b9642d28f1a246e294ff7 100644
--- a/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/net/minecraft/world/entity/decoration/ArmorStand.java
-@@ -564,6 +564,7 @@ public class ArmorStand extends LivingEntity {
+@@ -451,6 +451,7 @@ public class ArmorStand extends LivingEntity {
private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(ServerLevel level, DamageSource damageSource) { // Paper
ItemStack itemStack = new ItemStack(Items.ARMOR_STAND);
@@ -18,10 +18,10 @@ index d368b1971b270c44efc849464a100832bc29a679..8c0ab32487c56e2caf42404184f86c9b
this.drops.add(new DefaultDrop(itemStack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior
return this.brokenByAnything(level, damageSource); // Paper
diff --git a/net/minecraft/world/entity/decoration/ItemFrame.java b/net/minecraft/world/entity/decoration/ItemFrame.java
-index 65e1d7c5ac94b1cfb921fa009be59d3e5872f0b5..3ee1d8798db666ee8d83556047e40ff217cda732 100644
+index 5f518a7469953f50135ec53d7c6b77b9acbafed9..d5fec174e6accbf93fd70ed1ba64135fb879d0b2 100644
--- a/net/minecraft/world/entity/decoration/ItemFrame.java
+++ b/net/minecraft/world/entity/decoration/ItemFrame.java
-@@ -223,7 +223,11 @@ public class ItemFrame extends HangingEntity {
+@@ -246,7 +246,11 @@ public class ItemFrame extends HangingEntity {
this.removeFramedMap(item);
} else {
if (dropItem) {
@@ -34,12 +34,12 @@ index 65e1d7c5ac94b1cfb921fa009be59d3e5872f0b5..3ee1d8798db666ee8d83556047e40ff2
}
if (!item.isEmpty()) {
-diff --git a/net/minecraft/world/entity/decoration/Painting.java b/net/minecraft/world/entity/decoration/Painting.java
-index 5b905a4d49c44b04d5795c2bf297f3c69d183d7c..b6429a2bbb6fc1e08610ab20e50f8f0414f0ad26 100644
---- a/net/minecraft/world/entity/decoration/Painting.java
-+++ b/net/minecraft/world/entity/decoration/Painting.java
-@@ -162,7 +162,11 @@ public class Painting extends HangingEntity implements VariantHoldercreateDefaultStackConfig(level, itemInHand, player).accept(hangingEntity);
++ EntityType.appendDefaultStackConfig(entity -> {if (!level.purpurConfig.persistentDroppableEntityDisplayNames) entity.setCustomName(null);}, level, itemInHand, player).accept(hangingEntity); // Purpur - Apply display names from item forms of entities to entities and vice versa
if (hangingEntity.survives()) {
+ if (!level.isClientSide()) {
+ // CraftBukkit start - fire HangingPlaceEvent
diff --git a/purpur-server/minecraft-patches/features/0015-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch b/purpur-server/minecraft-patches/features/0014-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch
similarity index 64%
rename from purpur-server/minecraft-patches/features/0015-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch
rename to purpur-server/minecraft-patches/features/0014-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch
index f196a03cf..5376bc221 100644
--- a/purpur-server/minecraft-patches/features/0015-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch
+++ b/purpur-server/minecraft-patches/features/0014-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch
@@ -8,10 +8,10 @@ farm Nether Wart. Reimplemented based on a feature of the carpet-extra
mod.
diff --git a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
-index 4106549bd4dec1cc47d8765be8f5d119fe33bf56..e98fac58b29f78cb63bd868811cca41e1644e9ac 100644
+index 23c9363f03a74a2ddd15ffa1da4e0910dcfe2eb4..83aac5dcc51fbc2cc9ee45c155fb2b5b67293a96 100644
--- a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
+++ b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
-@@ -32,6 +32,7 @@ public class HarvestFarmland extends Behavior {
+@@ -31,6 +31,7 @@ public class HarvestFarmland extends Behavior {
private long nextOkStartTime;
private int timeWorkedSoFar;
private final List validFarmlandAroundVillager = Lists.newArrayList();
@@ -19,27 +19,27 @@ index 4106549bd4dec1cc47d8765be8f5d119fe33bf56..e98fac58b29f78cb63bd868811cca41e
public HarvestFarmland() {
super(
-@@ -50,9 +51,10 @@ public class HarvestFarmland extends Behavior {
+@@ -49,9 +50,10 @@ public class HarvestFarmland extends Behavior {
protected boolean checkExtraStartConditions(ServerLevel level, Villager owner) {
- if (!level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
+ if (!level.getGameRules().get(GameRules.MOB_GRIEFING)) {
return false;
-- } else if (owner.getVillagerData().getProfession() != VillagerProfession.FARMER) {
-+ } else if (owner.getVillagerData().getProfession() != VillagerProfession.FARMER && !(level.purpurConfig.villagerClericsFarmWarts && owner.getVillagerData().getProfession() == VillagerProfession.CLERIC)) { // Purpur - Option for Villager Clerics to farm Nether Wart
+- } else if (!owner.getVillagerData().profession().is(VillagerProfession.FARMER)) {
++ } else if (!owner.getVillagerData().profession().is(VillagerProfession.FARMER) && !(level.purpurConfig.villagerClericsFarmWarts && owner.getVillagerData().profession().is(VillagerProfession.CLERIC))) { // Purpur - Option for Villager Clerics to farm Nether Wart
return false;
} else {
-+ if (!this.clericWartFarmer && owner.getVillagerData().getProfession() == VillagerProfession.CLERIC) this.clericWartFarmer = true; // Purpur - Option for Villager Clerics to farm Nether Wart
++ if (!this.clericWartFarmer && owner.getVillagerData().profession().is(VillagerProfession.CLERIC)) this.clericWartFarmer = true; // Purpur - Option for Villager Clerics to farm Nether Wart
BlockPos.MutableBlockPos mutableBlockPos = owner.blockPosition().mutable();
this.validFarmlandAroundVillager.clear();
-@@ -83,6 +85,7 @@ public class HarvestFarmland extends Behavior {
- BlockState blockState = serverLevel.getBlockState(pos);
+@@ -81,6 +83,7 @@ public class HarvestFarmland extends Behavior {
+ BlockState blockState = level.getBlockState(pos);
Block block = blockState.getBlock();
- Block block1 = serverLevel.getBlockState(pos.below()).getBlock();
+ Block block1 = level.getBlockState(pos.below()).getBlock();
+ if (this.clericWartFarmer) return block == net.minecraft.world.level.block.Blocks.NETHER_WART && blockState.getValue(net.minecraft.world.level.block.NetherWartBlock.AGE) == 3 || blockState.isAir() && block1 == net.minecraft.world.level.block.Blocks.SOUL_SAND; // Purpur - Option for Villager Clerics to farm Nether Wart
return block instanceof CropBlock && ((CropBlock)block).isMaxAge(blockState) || blockState.isAir() && block1 instanceof FarmBlock;
}
-@@ -109,19 +112,19 @@ public class HarvestFarmland extends Behavior {
+@@ -107,19 +110,19 @@ public class HarvestFarmland extends Behavior {
BlockState blockState = level.getBlockState(this.aboveFarmlandPos);
Block block = blockState.getBlock();
Block block1 = level.getBlockState(this.aboveFarmlandPos.below()).getBlock();
@@ -62,7 +62,7 @@ index 4106549bd4dec1cc47d8765be8f5d119fe33bf56..e98fac58b29f78cb63bd868811cca41e
BlockState blockState1 = blockItem.getBlock().defaultBlockState();
if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(owner, this.aboveFarmlandPos, blockState1)) { // CraftBukkit
level.setBlockAndUpdate(this.aboveFarmlandPos, blockState1);
-@@ -136,7 +139,7 @@ public class HarvestFarmland extends Behavior {
+@@ -134,7 +137,7 @@ public class HarvestFarmland extends Behavior {
this.aboveFarmlandPos.getX(),
this.aboveFarmlandPos.getY(),
this.aboveFarmlandPos.getZ(),
@@ -72,7 +72,7 @@ index 4106549bd4dec1cc47d8765be8f5d119fe33bf56..e98fac58b29f78cb63bd868811cca41e
1.0F,
1.0F
diff --git a/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java b/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java
-index 243ac036f95794e7766aefb4630b635681ae5a5f..4d8523a43d60cd6b4fd5546ffb3a61417b2c475b 100644
+index 256fb863683d66235db4fb2b65fb1495672a67bf..81145178ba1ef75c441a09ab5f376d0528299ad3 100644
--- a/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java
+++ b/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java
@@ -59,6 +59,12 @@ public class TradeWithVillager extends Behavior {
@@ -80,7 +80,7 @@ index 243ac036f95794e7766aefb4630b635681ae5a5f..4d8523a43d60cd6b4fd5546ffb3a6141
}
+ // Purpur start - Option for Villager Clerics to farm Nether Wart
-+ if (level.purpurConfig.villagerClericsFarmWarts && level.purpurConfig.villagerClericFarmersThrowWarts && owner.getVillagerData().getProfession() == VillagerProfession.CLERIC && owner.getInventory().countItem(Items.NETHER_WART) > Items.NETHER_WART.getDefaultMaxStackSize() / 2) {
++ if (level.purpurConfig.villagerClericsFarmWarts && level.purpurConfig.villagerClericFarmersThrowWarts && owner.getVillagerData().profession().is(VillagerProfession.CLERIC) && owner.getInventory().countItem(Items.NETHER_WART) > Items.NETHER_WART.getDefaultMaxStackSize() / 2) {
+ throwHalfStack(owner, ImmutableSet.of(Items.NETHER_WART), villager);
+ }
+ // Purpur end - Option for Villager Clerics to farm Nether Wart
@@ -89,26 +89,26 @@ index 243ac036f95794e7766aefb4630b635681ae5a5f..4d8523a43d60cd6b4fd5546ffb3a6141
throwHalfStack(owner, this.trades, villager);
}
diff --git a/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java b/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
-index 84afd8646b05409c582f29d73f9fea4b09feb603..32779b121322688a4b14e460b1f902ef67770b32 100644
+index bb3ac5297860c8af6e213d10fdf5144086e9474b..0e72601781235119d62fe74420153b98edb5ce23 100644
--- a/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
+++ b/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
-@@ -74,8 +74,13 @@ public class VillagerGoalPackages {
- }
-
- public static ImmutableList>> getWorkPackage(VillagerProfession profession, float speedModifier) {
+@@ -79,8 +79,13 @@ public class VillagerGoalPackages {
+ public static ImmutableList>> getWorkPackage(
+ Holder profession, float speedModifier
+ ) {
+ // Purpur start - Option for Villager Clerics to farm Nether Wart
+ return getWorkPackage(profession, speedModifier, false);
+ }
-+ public static ImmutableList>> getWorkPackage(VillagerProfession profession, float speedModifier, boolean clericsFarmWarts) {
++ public static ImmutableList>> getWorkPackage(Holder profession, float speedModifier, boolean clericsFarmWarts) {
+ // Purpur end - Option for Villager Clerics to farm Nether Wart
WorkAtPoi workAtPoi;
-- if (profession == VillagerProfession.FARMER) {
-+ if (profession == VillagerProfession.FARMER || (clericsFarmWarts && profession == VillagerProfession.CLERIC)) { // Purpur - Option for Villager Clerics to farm Nether Wart
+- if (profession.is(VillagerProfession.FARMER)) {
++ if (profession.is(VillagerProfession.FARMER) || (clericsFarmWarts && profession.is(VillagerProfession.CLERIC))) { // Purpur - Option for Villager Clerics to farm Nether Wart
workAtPoi = new WorkAtComposter();
} else {
workAtPoi = new WorkAtPoi();
diff --git a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
-index 6b99afb4f237b5d6def98f3e03492975b795bc95..234e9d4aca14bc2a2e138918be1430516d710060 100644
+index 39a9e9a6f6dfddbf47a7f96150ef832efe61f89e..c268817b170bd54898bb5f8c2e2e12c0faa7eb1e 100644
--- a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
@@ -22,6 +22,13 @@ public class SecondaryPoiSensor extends Sensor {
@@ -117,7 +117,7 @@ index 6b99afb4f237b5d6def98f3e03492975b795bc95..234e9d4aca14bc2a2e138918be143051
protected void doTick(ServerLevel level, Villager entity) {
+ // Purpur start - Option for Villager Clerics to farm Nether Wart - make sure clerics don't wander to soul sand when the option is off
+ Brain> brain = entity.getBrain();
-+ if (!level.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().getProfession() == net.minecraft.world.entity.npc.VillagerProfession.CLERIC) {
++ if (!level.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().profession().is(net.minecraft.world.entity.npc.villager.VillagerProfession.CLERIC)) {
+ brain.eraseMemory(MemoryModuleType.SECONDARY_JOB_SITE);
+ return;
+ }
@@ -134,38 +134,38 @@ index 6b99afb4f237b5d6def98f3e03492975b795bc95..234e9d4aca14bc2a2e138918be143051
if (!list.isEmpty()) {
brain.setMemory(MemoryModuleType.SECONDARY_JOB_SITE, list);
} else {
-diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
-index ff07cfe07200be23f17310522d737fca3251a580..017b54e0b8dec8996c90a3c6651867277dd516df 100644
---- a/net/minecraft/world/entity/npc/Villager.java
-+++ b/net/minecraft/world/entity/npc/Villager.java
-@@ -311,7 +311,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
- villagerBrain.setSchedule(Schedule.VILLAGER_DEFAULT);
+diff --git a/net/minecraft/world/entity/npc/villager/Villager.java b/net/minecraft/world/entity/npc/villager/Villager.java
+index 02836bd2e8fda563877d3014ab839734aebc7457..ed6642023fccbc8f825d7c5c206d73ffd666f0f9 100644
+--- a/net/minecraft/world/entity/npc/villager/Villager.java
++++ b/net/minecraft/world/entity/npc/villager/Villager.java
+@@ -315,7 +315,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+ villagerBrain.setSchedule(EnvironmentAttributes.VILLAGER_ACTIVITY);
villagerBrain.addActivityWithConditions(
Activity.WORK,
-- VillagerGoalPackages.getWorkPackage(profession, 0.5F),
-+ VillagerGoalPackages.getWorkPackage(profession, 0.5F, this.level().purpurConfig.villagerClericsFarmWarts), // Purpur - Option for Villager Clerics to farm Nether Wart
+- VillagerGoalPackages.getWorkPackage(holder, 0.5F),
++ VillagerGoalPackages.getWorkPackage(holder, 0.5F, this.level().purpurConfig.villagerClericsFarmWarts), // Purpur - Option for Villager Clerics to farm Nether Wart
ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT))
);
}
-@@ -977,7 +977,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+@@ -956,7 +956,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
public boolean hasFarmSeeds() {
-- return this.getInventory().hasAnyMatching(itemStack -> itemStack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS));
-+ return this.getInventory().hasAnyMatching(itemStack -> this.level().purpurConfig.villagerClericsFarmWarts && this.getVillagerData().getProfession() == VillagerProfession.CLERIC ? itemStack.is(Items.NETHER_WART) : itemStack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS)); // Purpur - Option for Villager Clerics to farm Nether Wart
+- return this.getInventory().hasAnyMatching(stack -> stack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS));
++ return this.getInventory().hasAnyMatching(stack -> this.level().purpurConfig.villagerClericsFarmWarts && this.getVillagerData().profession().is(VillagerProfession.CLERIC) ? stack.is(Items.NETHER_WART) : stack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS)); // Purpur - Option for Villager Clerics to farm Nether Wart
}
@Override
-diff --git a/net/minecraft/world/entity/npc/VillagerProfession.java b/net/minecraft/world/entity/npc/VillagerProfession.java
-index 1ec8ad124c76483d11057eb97fcfb9aebee0c301..f783d058a080408d572938d36ba031f33a08e9af 100644
---- a/net/minecraft/world/entity/npc/VillagerProfession.java
-+++ b/net/minecraft/world/entity/npc/VillagerProfession.java
-@@ -31,7 +31,7 @@ public record VillagerProfession(
- public static final VillagerProfession ARMORER = register("armorer", PoiTypes.ARMORER, SoundEvents.VILLAGER_WORK_ARMORER);
- public static final VillagerProfession BUTCHER = register("butcher", PoiTypes.BUTCHER, SoundEvents.VILLAGER_WORK_BUTCHER);
- public static final VillagerProfession CARTOGRAPHER = register("cartographer", PoiTypes.CARTOGRAPHER, SoundEvents.VILLAGER_WORK_CARTOGRAPHER);
-- public static final VillagerProfession CLERIC = register("cleric", PoiTypes.CLERIC, SoundEvents.VILLAGER_WORK_CLERIC);
-+ public static final VillagerProfession CLERIC = register("cleric", PoiTypes.CLERIC, ImmutableSet.of(Items.NETHER_WART), ImmutableSet.of(Blocks.SOUL_SAND), SoundEvents.VILLAGER_WORK_CLERIC); // Purpur - Option for Villager Clerics to farm Nether Wart
- public static final VillagerProfession FARMER = register(
- "farmer",
- PoiTypes.FARMER,
+diff --git a/net/minecraft/world/entity/npc/villager/VillagerProfession.java b/net/minecraft/world/entity/npc/villager/VillagerProfession.java
+index 0acfa8f9d2eab00cf0d8b4bc65c3af52046272bd..8f2edbe693a793d31295d035bc01e4c2b7742b4e 100644
+--- a/net/minecraft/world/entity/npc/villager/VillagerProfession.java
++++ b/net/minecraft/world/entity/npc/villager/VillagerProfession.java
+@@ -103,7 +103,7 @@ public record VillagerProfession(
+ register(registry, ARMORER, PoiTypes.ARMORER, SoundEvents.VILLAGER_WORK_ARMORER);
+ register(registry, BUTCHER, PoiTypes.BUTCHER, SoundEvents.VILLAGER_WORK_BUTCHER);
+ register(registry, CARTOGRAPHER, PoiTypes.CARTOGRAPHER, SoundEvents.VILLAGER_WORK_CARTOGRAPHER);
+- register(registry, CLERIC, PoiTypes.CLERIC, SoundEvents.VILLAGER_WORK_CLERIC);
++ register(registry, CLERIC, PoiTypes.CLERIC, ImmutableSet.of(Items.NETHER_WART), ImmutableSet.of(Blocks.SOUL_SAND), SoundEvents.VILLAGER_WORK_CLERIC); // Purpur - Option for Villager Clerics to farm Nether Wart
+ register(
+ registry,
+ FARMER,
diff --git a/purpur-server/minecraft-patches/features/0015-Add-mobGriefing-override-to-everything-affected.patch b/purpur-server/minecraft-patches/features/0015-Add-mobGriefing-override-to-everything-affected.patch
new file mode 100644
index 000000000..97f514e50
--- /dev/null
+++ b/purpur-server/minecraft-patches/features/0015-Add-mobGriefing-override-to-everything-affected.patch
@@ -0,0 +1,378 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Encode42
+Date: Tue, 5 Jan 2021 22:21:56 -0500
+Subject: [PATCH] Add mobGriefing override to everything affected
+
+
+diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
+index e04320155173caa8ce8f998477f36a6b36de935c..34d5283bbc76b4b6c335de354fc2edc1046dcfd1 100644
+--- a/net/minecraft/world/entity/LivingEntity.java
++++ b/net/minecraft/world/entity/LivingEntity.java
+@@ -1961,7 +1961,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ if (this.level() instanceof ServerLevel serverLevel) {
+ boolean var6 = false;
+ if (this.dead && entitySource instanceof WitherBoss) { // Paper
+- if (serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) {
++ if (serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.witherMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ BlockPos blockPos = this.blockPosition();
+ BlockState blockState = Blocks.WITHER_ROSE.defaultBlockState();
+ if (this.level().getBlockState(blockPos).isAir() && blockState.canSurvive(this.level(), blockPos)) {
+diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
+index a3569262099dce237c3feb5e29d24bf47f4c1e38..70807b4a6c94b0231eb541c7121d925d88022ac6 100644
+--- a/net/minecraft/world/entity/Mob.java
++++ b/net/minecraft/world/entity/Mob.java
+@@ -554,7 +554,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
+ && this.canPickUpLoot()
+ && this.isAlive()
+ && !this.dead
+- && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) {
++ && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.entitiesPickUpLootMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ Vec3i pickupReach = this.getPickupReach();
+
+ for (ItemEntity itemEntity : this.level()
+diff --git a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
+index 83aac5dcc51fbc2cc9ee45c155fb2b5b67293a96..c68399986583a215da156b9057a61f22cbf6143d 100644
+--- a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
++++ b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
+@@ -48,7 +48,7 @@ public class HarvestFarmland extends Behavior {
+
+ @Override
+ protected boolean checkExtraStartConditions(ServerLevel level, Villager owner) {
+- if (!level.getGameRules().get(GameRules.MOB_GRIEFING)) {
++ if (!level.getGameRules().get(GameRules.MOB_GRIEFING, level.purpurConfig.villagerMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ return false;
+ } else if (!owner.getVillagerData().profession().is(VillagerProfession.FARMER) && !(level.purpurConfig.villagerClericsFarmWarts && owner.getVillagerData().profession().is(VillagerProfession.CLERIC))) { // Purpur - Option for Villager Clerics to farm Nether Wart
+ return false;
+diff --git a/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
+index 3da917a428b9300d839df610e0e9dceb1d0f0668..a43c0d99458e8aff6a0b0a9eee60ed82b75ffdda 100644
+--- a/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
++++ b/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
+@@ -31,7 +31,7 @@ public class BreakDoorGoal extends DoorInteractGoal {
+ @Override
+ public boolean canUse() {
+ return super.canUse()
+- && getServerLevel(this.mob).getGameRules().get(GameRules.MOB_GRIEFING)
++ && getServerLevel(this.mob).getGameRules().get(GameRules.MOB_GRIEFING, this.mob.level().purpurConfig.zombieMobGriefingOverride) // Purpur - Add mobGriefing override to everything affected
+ && this.isValidDifficulty(this.mob.level().getDifficulty())
+ && !this.isOpen();
+ }
+diff --git a/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
+index 087861886eeb55324ffe54bda78e19f83bf33e72..0f0311eb836b8da39651ece499fe4bda44bce178 100644
+--- a/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
++++ b/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
+@@ -64,7 +64,7 @@ public class EatBlockGoal extends Goal {
+ BlockPos blockPos = this.mob.blockPosition();
+ final BlockState blockState = this.level.getBlockState(blockPos); // Paper - fix wrong block state
+ if (IS_EDIBLE.test(blockState)) { // Paper - fix wrong block state
+- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING))) { // CraftBukkit // Paper - fix wrong block state
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING, getServerLevel(this.level).purpurConfig.sheepMobGriefingOverride))) { // CraftBukkit // Paper - fix wrong block state // Purpur - Add mobGriefing override to everything affected
+ this.level.destroyBlock(blockPos, false);
+ }
+
+@@ -72,7 +72,7 @@ public class EatBlockGoal extends Goal {
+ } else {
+ BlockPos blockPos1 = blockPos.below();
+ if (this.level.getBlockState(blockPos1).is(Blocks.GRASS_BLOCK)) {
+- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING))) { // CraftBukkit // Paper - Fix wrong block state
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING, getServerLevel(this.level).purpurConfig.sheepMobGriefingOverride))) { // CraftBukkit // Paper - Fix wrong block state // Purpur - Add mobGriefing override to everything affected
+ this.level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, blockPos1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState()));
+ this.level.setBlock(blockPos1, Blocks.DIRT.defaultBlockState(), Block.UPDATE_CLIENTS);
+ }
+diff --git a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
+index 50cc4c462640a9d40abef6245439d71e8c593ae6..83be00350765db043b6bf32e7814d9c7119eacc5 100644
+--- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
++++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
+@@ -35,7 +35,7 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
+
+ @Override
+ public boolean canUse() {
+- if (!getServerLevel(this.removerMob).getGameRules().get(GameRules.MOB_GRIEFING)) {
++ if (!getServerLevel(this.removerMob).getGameRules().get(GameRules.MOB_GRIEFING, getServerLevel(this.removerMob).purpurConfig.zombieMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ return false;
+ } else if (this.nextStartTick > 0) {
+ this.nextStartTick--;
+diff --git a/net/minecraft/world/entity/animal/fox/Fox.java b/net/minecraft/world/entity/animal/fox/Fox.java
+index 3c2f5e711c013a6f51093e94bc4b5518263607a2..a0ed30e8ccd41729de8e0ff977a61fa607386640 100644
+--- a/net/minecraft/world/entity/animal/fox/Fox.java
++++ b/net/minecraft/world/entity/animal/fox/Fox.java
+@@ -1062,7 +1062,7 @@ public class Fox extends Animal {
+ }
+
+ protected void onReachedTarget() {
+- if (getServerLevel(Fox.this.level()).getGameRules().get(GameRules.MOB_GRIEFING)) {
++ if (getServerLevel(Fox.this.level()).getGameRules().get(GameRules.MOB_GRIEFING, getServerLevel(Fox.this.level()).purpurConfig.foxMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ BlockState blockState = Fox.this.level().getBlockState(this.blockPos);
+ if (blockState.is(Blocks.SWEET_BERRY_BUSH)) {
+ this.pickSweetBerries(blockState);
+diff --git a/net/minecraft/world/entity/animal/golem/SnowGolem.java b/net/minecraft/world/entity/animal/golem/SnowGolem.java
+index ab44bc401438d589696d9f25ebaca0fc39648bed..f011369a67809d54230984a22a909bfea44f47f3 100644
+--- a/net/minecraft/world/entity/animal/golem/SnowGolem.java
++++ b/net/minecraft/world/entity/animal/golem/SnowGolem.java
+@@ -135,7 +135,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
+ this.hurtServer(serverLevel, this.damageSources().onFire().knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.MELTING), 1.0F); // CraftBukkit
+ }
+
+- if (!serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) {
++ if (!serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.snowGolemMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ return;
+ }
+
+diff --git a/net/minecraft/world/entity/animal/rabbit/Rabbit.java b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+index 061418a25d359574c4ff44327082b08b4094ee1c..66fda64006c0a70ab4502f088637bb6871c3bb37 100644
+--- a/net/minecraft/world/entity/animal/rabbit/Rabbit.java
++++ b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+@@ -648,7 +648,7 @@ public class Rabbit extends Animal {
+ @Override
+ public boolean canUse() {
+ if (this.nextStartTick <= 0) {
+- if (!getServerLevel(this.rabbit).getGameRules().get(GameRules.MOB_GRIEFING)) {
++ if (!getServerLevel(this.rabbit).getGameRules().get(GameRules.MOB_GRIEFING, getServerLevel(this.rabbit).purpurConfig.rabbitMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ return false;
+ }
+
+diff --git a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+index 844c989fc4e0d131d823bf8a59951f35f30b7641..e14347ccc7b21213801e59fa2e0e47964bc943ad 100644
+--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
++++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+@@ -542,7 +542,7 @@ public class EnderDragon extends Mob implements Enemy {
+ BlockPos blockPos = new BlockPos(i, i1, i2);
+ BlockState blockState = level.getBlockState(blockPos);
+ if (!blockState.isAir() && !blockState.is(BlockTags.DRAGON_TRANSPARENT)) {
+- if (level.getGameRules().get(GameRules.MOB_GRIEFING) && !blockState.is(BlockTags.DRAGON_IMMUNE)) {
++ if (level.getGameRules().get(GameRules.MOB_GRIEFING, level.purpurConfig.enderDragonMobGriefingOverride) && !blockState.is(BlockTags.DRAGON_IMMUNE)) { // Purpur - Add mobGriefing override to everything affected
+ // CraftBukkit start - Add blocks to list rather than destroying them
+ //flag1 = level.removeBlock(blockPos, false) || flag1;
+ flag1 = true;
+diff --git a/net/minecraft/world/entity/boss/wither/WitherBoss.java b/net/minecraft/world/entity/boss/wither/WitherBoss.java
+index 612df8799b80f1793ab9781212442098633e9d65..73dbc5ae28c5af00a36528e0397ad1c2eed14f2c 100644
+--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java
++++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java
+@@ -495,7 +495,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+
+ if (this.destroyBlocksTick > 0) {
+ this.destroyBlocksTick--;
+- if (this.destroyBlocksTick == 0 && level.getGameRules().get(GameRules.MOB_GRIEFING)) {
++ if (this.destroyBlocksTick == 0 && level.getGameRules().get(GameRules.MOB_GRIEFING, level.purpurConfig.witherMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ boolean flag = false;
+ int alternativeTarget = Mth.floor(this.getBbWidth() / 2.0F + 1.0F);
+ int floor = Mth.floor(this.getBbHeight());
+diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
+index 29570047bfc78a8993b0bbd7168cb4fe318a6be6..79a1d8f67a22a8fa4a6c3b657e44bb9503687c27 100644
+--- a/net/minecraft/world/entity/monster/EnderMan.java
++++ b/net/minecraft/world/entity/monster/EnderMan.java
+@@ -509,7 +509,7 @@ public class EnderMan extends Monster implements NeutralMob {
+ public boolean canUse() {
+ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls
+ return this.enderman.getCarriedBlock() != null
+- && getServerLevel(this.enderman).getGameRules().get(GameRules.MOB_GRIEFING)
++ && getServerLevel(this.enderman).getGameRules().get(GameRules.MOB_GRIEFING, this.enderman.level().purpurConfig.endermanMobGriefingOverride) // Purpur - Add mobGriefing override to everything affected
+ && this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0;
+ }
+
+@@ -658,7 +658,7 @@ public class EnderMan extends Monster implements NeutralMob {
+ public boolean canUse() {
+ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls
+ return this.enderman.getCarriedBlock() == null
+- && getServerLevel(this.enderman).getGameRules().get(GameRules.MOB_GRIEFING)
++ && getServerLevel(this.enderman).getGameRules().get(GameRules.MOB_GRIEFING, this.enderman.level().purpurConfig.endermanMobGriefingOverride) // Purpur - Add mobGriefing override to everything affected
+ && this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0;
+ }
+
+diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java
+index c3546b0841aff52ef758b0e8e48c9a70726f412d..c1ae9826d15456762ac0c0ab7380763242fa48de 100644
+--- a/net/minecraft/world/entity/monster/Ravager.java
++++ b/net/minecraft/world/entity/monster/Ravager.java
+@@ -179,7 +179,7 @@ public class Ravager extends Raider {
+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(Mth.lerp(0.1, baseValue, d));
+ }
+
+- if (this.level() instanceof ServerLevel serverLevel && this.horizontalCollision && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) {
++ if (this.level() instanceof ServerLevel serverLevel && this.horizontalCollision && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.ravagerMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ boolean flag = false;
+ AABB aabb = this.getBoundingBox().inflate(0.2);
+
+diff --git a/net/minecraft/world/entity/monster/Silverfish.java b/net/minecraft/world/entity/monster/Silverfish.java
+index 1df006a0a49038f1e737194e7da8e0b27e6eeb95..3e8e3a6018120576b0773769db7b2037148fae96 100644
+--- a/net/minecraft/world/entity/monster/Silverfish.java
++++ b/net/minecraft/world/entity/monster/Silverfish.java
+@@ -168,7 +168,7 @@ public class Silverfish extends Monster {
+ return false;
+ } else {
+ RandomSource random = this.mob.getRandom();
+- if (getServerLevel(this.mob).getGameRules().get(GameRules.MOB_GRIEFING) && random.nextInt(reducedTickDelay(10)) == 0) {
++ if (getServerLevel(this.mob).getGameRules().get(GameRules.MOB_GRIEFING, getServerLevel(this.mob).purpurConfig.silverfishMobGriefingOverride) && random.nextInt(reducedTickDelay(10)) == 0) { // Purpur - Add mobGriefing override to everything affected
+ this.selectedDirection = Direction.getRandom(random);
+ BlockPos blockPos = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5, this.mob.getZ()).relative(this.selectedDirection);
+ BlockState blockState = this.mob.level().getBlockState(blockPos);
+@@ -245,7 +245,7 @@ public class Silverfish extends Monster {
+ Block block = blockState.getBlock();
+ if (block instanceof InfestedBlock) {
+ // CraftBukkit start
+- BlockState afterState = getServerLevel(level).getGameRules().get(GameRules.MOB_GRIEFING) ? blockState.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(level.getBlockState(blockPos1)); // Paper - fix wrong block state
++ BlockState afterState = getServerLevel(level).getGameRules().get(GameRules.MOB_GRIEFING, getServerLevel(level).purpurConfig.silverfishMobGriefingOverride) ? blockState.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(level.getBlockState(blockPos1)); // Paper - fix wrong block state // Purpur - Add mobGriefing override to everything affected
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockPos1, afterState)) { // Paper - fix wrong block state
+ continue;
+ }
+diff --git a/net/minecraft/world/entity/monster/illager/Evoker.java b/net/minecraft/world/entity/monster/illager/Evoker.java
+index 46f79ed345ec51125364b49b244d6d005a3e64ae..334786b2c358c41058f2ac4b1fa4b185833cbd84 100644
+--- a/net/minecraft/world/entity/monster/illager/Evoker.java
++++ b/net/minecraft/world/entity/monster/illager/Evoker.java
+@@ -306,7 +306,7 @@ public class Evoker extends SpellcasterIllager {
+ return false;
+ } else {
+ ServerLevel serverLevel = getServerLevel(Evoker.this.level());
+- if (!serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) {
++ if (!serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.evokerMobGriefingOverride)) { // Purpur - Add mobGriefing override to everything affected
+ return false;
+ } else {
+ List nearbyEntities = serverLevel.getNearbyEntities(
+diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java
+index 98241af88cc961470e07df47d128d8912338bd44..4fccd122a227e5fe80965c37afaa031c4a673978 100644
+--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
++++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
+@@ -448,7 +448,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
+
+ @Override
+ public boolean wantsToPickUp(ServerLevel level, ItemStack stack) {
+- return level.getGameRules().get(GameRules.MOB_GRIEFING) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack);
++ return level.getGameRules().get(GameRules.MOB_GRIEFING, level.purpurConfig.piglinMobGriefingOverride) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack); // Purpur - Add mobGriefing override to everything affected
+ }
+
+ protected boolean canReplaceCurrentItem(ItemStack candidate) {
+diff --git a/net/minecraft/world/entity/projectile/Projectile.java b/net/minecraft/world/entity/projectile/Projectile.java
+index 6298e6de25f1dd9ff880a9ad2882dc7ccb2f100c..36479ed544ce812113c9a9c982a74a950cb9b26a 100644
+--- a/net/minecraft/world/entity/projectile/Projectile.java
++++ b/net/minecraft/world/entity/projectile/Projectile.java
+@@ -434,7 +434,7 @@ public abstract class Projectile extends Entity implements TraceableEntity {
+ @Override
+ public boolean mayInteract(ServerLevel level, BlockPos pos) {
+ Entity owner = this.getOwner();
+- return owner instanceof Player ? owner.mayInteract(level, pos) : owner == null || level.getGameRules().get(GameRules.MOB_GRIEFING);
++ return owner instanceof Player ? owner.mayInteract(level, pos) : owner == null || level.getGameRules().get(GameRules.MOB_GRIEFING, level.purpurConfig.projectilesMobGriefingOverride); // Purpur - Add mobGriefing override to everything affected
+ }
+
+ public boolean mayBreak(ServerLevel level) {
+diff --git a/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java b/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java
+index de0f086da9fe4afa14d2b77f6b0a2c0910745b94..775aa79a0d503217dbe42268f4feccbc2d3e1edb 100644
+--- a/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java
++++ b/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java
+@@ -20,20 +20,20 @@ public class LargeFireball extends Fireball {
+
+ public LargeFireball(EntityType extends LargeFireball> type, Level level) {
+ super(type, level);
+- this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); // CraftBukkit
++ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.fireballsMobGriefingOverride); // CraftBukkit // Purpur - Add mobGriefing override to everything affected
+ }
+
+ public LargeFireball(Level level, LivingEntity owner, Vec3 movement, int explosionPower) {
+ super(EntityType.FIREBALL, owner, movement, level);
+ this.explosionPower = explosionPower;
+- this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); // CraftBukkit
++ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.fireballsMobGriefingOverride); // CraftBukkit // Purpur - Add mobGriefing override to everything affected
+ }
+
+ @Override
+ protected void onHit(HitResult result) {
+ super.onHit(result);
+ if (this.level() instanceof ServerLevel serverLevel) {
+- // boolean flag = serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); // CraftBukkit - baked into fields (see constructor)
++ // boolean flag = serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.fireballsMobGriefingOverride); // CraftBukkit - baked into fields (see constructor) // Purpur - Add mobGriefing override to everything affected
+ // CraftBukkit start - fire ExplosionPrimeEvent
+ org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity());
+ if (event.callEvent()) {
+diff --git a/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java b/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java
+index 043ddaa0e8718f50881d16892eab188aed70f67f..a10617c29098f28c5b5586a43071a47ef17e5744 100644
+--- a/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java
++++ b/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java
+@@ -25,7 +25,7 @@ public class SmallFireball extends Fireball {
+ super(EntityType.SMALL_FIREBALL, owner, movement, level);
+ // CraftBukkit start
+ if (this.getOwner() != null && this.getOwner() instanceof Mob) {
+- this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING);
++ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.fireballsMobGriefingOverride); // Purpur - Add mobGriefing override to everything affected
+ }
+ // CraftBukkit end
+ }
+diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
+index 298d6749bdd5b6f09530096f8f546d9f46910b19..b03faa7600f182a12c3a739deefc38028cf45615 100644
+--- a/net/minecraft/world/entity/raid/Raider.java
++++ b/net/minecraft/world/entity/raid/Raider.java
+@@ -396,7 +396,7 @@ public abstract class Raider extends PatrollingMonster {
+ }
+
+ private boolean cannotPickUpBanner() {
+- if (!getServerLevel(this.mob).getGameRules().get(net.minecraft.world.level.gamerules.GameRules.MOB_GRIEFING)) return true; // Paper - respect game and entity rules for picking up items
++ if (!getServerLevel(this.mob).getGameRules().get(net.minecraft.world.level.gamerules.GameRules.MOB_GRIEFING, this.mob.level().purpurConfig.pillagerMobGriefingOverride)) return true; // Paper - respect game and entity rules for picking up items // Purpur - Add mobGriefing override to everything affected
+ if (!this.mob.hasActiveRaid()) {
+ return true;
+ } else if (this.mob.getCurrentRaid().isOver()) {
+diff --git a/net/minecraft/world/level/block/CropBlock.java b/net/minecraft/world/level/block/CropBlock.java
+index 4ad9b4afeb6958cba98d8413b3371754730741e5..0b748fac353d6a8b5351ad67df7d239d3efa43b0 100644
+--- a/net/minecraft/world/level/block/CropBlock.java
++++ b/net/minecraft/world/level/block/CropBlock.java
+@@ -169,7 +169,7 @@ public class CropBlock extends VegetationBlock implements BonemealableBlock {
+ @Override
+ protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) {
+ if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
+- if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.purpurConfig.ravagerGriefableBlocks.contains(serverLevel.getBlockState(pos).getBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.getGameRules().get(GameRules.MOB_GRIEFING))) { // CraftBukkit // Purpur - Configurable ravager griefable blocks list
++ if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.purpurConfig.ravagerGriefableBlocks.contains(serverLevel.getBlockState(pos).getBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.ravagerMobGriefingOverride))) { // CraftBukkit // Purpur - Configurable ravager griefable blocks list // Purpur - Add mobGriefing override to everything affected
+ serverLevel.destroyBlock(pos, true, entity);
+ }
+
+diff --git a/net/minecraft/world/level/block/FarmBlock.java b/net/minecraft/world/level/block/FarmBlock.java
+index cd90b5151cae59a63836e88c6457c2954e24a345..3fd6a259788503f2a6d33d29a9247796f75e719a 100644
+--- a/net/minecraft/world/level/block/FarmBlock.java
++++ b/net/minecraft/world/level/block/FarmBlock.java
+@@ -114,7 +114,7 @@ public class FarmBlock extends Block {
+ if (level instanceof ServerLevel serverLevel
+ && (serverLevel.purpurConfig.farmlandTrampleHeight >= 0D ? fallDistance >= serverLevel.purpurConfig.farmlandTrampleHeight : level.random.nextFloat() < fallDistance - 0.5) // Purpur - Configurable farmland trample height
+ && entity instanceof LivingEntity
+- && (entity instanceof Player || serverLevel.getGameRules().get(GameRules.MOB_GRIEFING))
++ && (entity instanceof Player || serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.farmlandMobGriefingOverride)) // Purpur - Add mobGriefing override to everything affected
+ && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) {
+ // CraftBukkit start - Interact soil
+ org.bukkit.event.Cancellable cancellable;
+diff --git a/net/minecraft/world/level/block/PowderSnowBlock.java b/net/minecraft/world/level/block/PowderSnowBlock.java
+index f3a9117bd066861a1b447e8a13108ad212cc499f..b0165c839b145e82af38fe8f61bbd0161015d867 100644
+--- a/net/minecraft/world/level/block/PowderSnowBlock.java
++++ b/net/minecraft/world/level/block/PowderSnowBlock.java
+@@ -96,7 +96,7 @@ public class PowderSnowBlock extends Block implements BucketPickup {
+ // CraftBukkit - move down
+ && entity1.mayInteract(serverLevel, blockPos)) {
+ // CraftBukkit start
+- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity1, pos, Blocks.AIR.defaultBlockState(), !(serverLevel.getGameRules().get(GameRules.MOB_GRIEFING) || entity1 instanceof Player))) {
++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity1, pos, Blocks.AIR.defaultBlockState(), !(serverLevel.getGameRules().get(GameRules.MOB_GRIEFING, serverLevel.purpurConfig.powderSnowMobGriefingOverride) || entity1 instanceof Player))) { // Purpur - Add mobGriefing override to everything affected
+ return;
+ }
+ // CraftBukkit end
+diff --git a/net/minecraft/world/level/block/TurtleEggBlock.java b/net/minecraft/world/level/block/TurtleEggBlock.java
+index 77c2fb39c961180cd8280b97205273a5562481f7..f10a56052c51509784fb1f3851e41548c04d6a3c 100644
+--- a/net/minecraft/world/level/block/TurtleEggBlock.java
++++ b/net/minecraft/world/level/block/TurtleEggBlock.java
+@@ -214,7 +214,7 @@ public class TurtleEggBlock extends Block {
+ // Purpur end - Option to disable turtle egg trampling with feather falling
+ if (entity instanceof Player) return true;
+
+- return level.getGameRules().get(GameRules.MOB_GRIEFING);
++ return level.getGameRules().get(GameRules.MOB_GRIEFING, level.purpurConfig.turtleEggsMobGriefingOverride); // Purpur - Add mobGriefing override to everything affected
+ // Purpur end - Add turtle egg block options
+ }
+ }
+diff --git a/net/minecraft/world/level/gamerules/GameRules.java b/net/minecraft/world/level/gamerules/GameRules.java
+index e71a9ffdb6c081baa79113f34b179671c179152d..746bc21fc09644366caa8bfd309f596c3cac59ec 100644
+--- a/net/minecraft/world/level/gamerules/GameRules.java
++++ b/net/minecraft/world/level/gamerules/GameRules.java
+@@ -113,6 +113,13 @@ public class GameRules {
+ return this.rules.keySet().stream();
+ }
+
++ public boolean get(GameRule rule, Boolean gameRuleOverride) {
++ if (gameRuleOverride != null) {
++ return gameRuleOverride;
++ }
++ return (Boolean) this.get(rule);
++ }
++
+ public T get(GameRule rule) {
+ T object = this.rules.get(rule);
+ if (object == null) {
diff --git a/purpur-server/minecraft-patches/features/0016-Add-mobGriefing-bypass-to-everything-affected.patch b/purpur-server/minecraft-patches/features/0016-Add-mobGriefing-bypass-to-everything-affected.patch
deleted file mode 100644
index 4e21dcf5d..000000000
--- a/purpur-server/minecraft-patches/features/0016-Add-mobGriefing-bypass-to-everything-affected.patch
+++ /dev/null
@@ -1,360 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Encode42
-Date: Tue, 5 Jan 2021 22:21:56 -0500
-Subject: [PATCH] Add mobGriefing bypass to everything affected
-
-
-diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
-index 6de5f527c018201d874e06a45c9509fa12125766..2dc588e2d503c16ccd2589ce18abd2ecebbc8e74 100644
---- a/net/minecraft/world/entity/LivingEntity.java
-+++ b/net/minecraft/world/entity/LivingEntity.java
-@@ -1818,7 +1818,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
- if (this.level() instanceof ServerLevel serverLevel) {
- boolean var6 = false;
- if (this.dead && entitySource instanceof WitherBoss) { // Paper
-- if (serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ if (serverLevel.purpurConfig.witherBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- BlockPos blockPos = this.blockPosition();
- BlockState blockState = Blocks.WITHER_ROSE.defaultBlockState();
- if (this.level().getBlockState(blockPos).isAir() && blockState.canSurvive(this.level(), blockPos)) {
-diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
-index c431f28c3f4f6cec946048f5752c364429af5ba1..d93584c6793818463e8883ffe399bf16b03263a9 100644
---- a/net/minecraft/world/entity/Mob.java
-+++ b/net/minecraft/world/entity/Mob.java
-@@ -648,7 +648,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
- && this.canPickUpLoot()
- && this.isAlive()
- && !this.dead
-- && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ && serverLevel.purpurConfig.entitiesPickUpLootBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- Vec3i pickupReach = this.getPickupReach();
-
- for (ItemEntity itemEntity : this.level()
-diff --git a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
-index e98fac58b29f78cb63bd868811cca41e1644e9ac..56d49bc71cb0cb0a08ff771991fd77ab774b4b59 100644
---- a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
-+++ b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
-@@ -49,7 +49,7 @@ public class HarvestFarmland extends Behavior {
-
- @Override
- protected boolean checkExtraStartConditions(ServerLevel level, Villager owner) {
-- if (!level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ if (!level.purpurConfig.villagerBypassMobGriefing == !level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- return false;
- } else if (owner.getVillagerData().getProfession() != VillagerProfession.FARMER && !(level.purpurConfig.villagerClericsFarmWarts && owner.getVillagerData().getProfession() == VillagerProfession.CLERIC)) { // Purpur - Option for Villager Clerics to farm Nether Wart
- return false;
-diff --git a/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
-index e026e07ca86700c864a3dceda6817fb7b6cb11e9..f1dfe0bf047e7d331b2379a672ff7b8eae4c9c90 100644
---- a/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
-+++ b/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
-@@ -30,7 +30,7 @@ public class BreakDoorGoal extends DoorInteractGoal {
- @Override
- public boolean canUse() {
- return super.canUse()
-- && getServerLevel(this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)
-+ && this.mob.level().purpurConfig.zombieBypassMobGriefing == !getServerLevel(this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) // Purpur - Add mobGriefing bypass to everything affected
- && this.isValidDifficulty(this.mob.level().getDifficulty())
- && !this.isOpen();
- }
-diff --git a/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
-index e84893780b533b1ecb3675606b5c2daf7339b861..65eb4d8001b07cb3f7cda17565eea10a88a9c47c 100644
---- a/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
-+++ b/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
-@@ -67,7 +67,7 @@ public class EatBlockGoal extends Goal {
- BlockPos blockPos = this.mob.blockPosition();
- final BlockState blockState = this.level.getBlockState(blockPos); // Paper - fix wrong block state
- if (IS_TALL_GRASS.test(blockState)) { // Paper - fix wrong block state
-- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state
-+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).purpurConfig.sheepBypassMobGriefing == !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state // Purpur - Add mobGriefing bypass to everything affected
- this.level.destroyBlock(blockPos, false);
- }
-
-@@ -75,7 +75,7 @@ public class EatBlockGoal extends Goal {
- } else {
- BlockPos blockPos1 = blockPos.below();
- if (this.level.getBlockState(blockPos1).is(Blocks.GRASS_BLOCK)) {
-- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state
-+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).purpurConfig.sheepBypassMobGriefing == !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state // Purpur - Add mobGriefing bypass to everything affected
- this.level.levelEvent(2001, blockPos1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState()));
- this.level.setBlock(blockPos1, Blocks.DIRT.defaultBlockState(), 2);
- }
-diff --git a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
-index 579ca031d461ed4327fe4fb45c5289565322e64e..95fa516910a3834bbd4db6d11279e13a1f0dac41 100644
---- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
-+++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
-@@ -35,7 +35,7 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
-
- @Override
- public boolean canUse() {
-- if (!getServerLevel(this.removerMob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ if (!getServerLevel(this.removerMob).purpurConfig.zombieBypassMobGriefing == !getServerLevel(this.removerMob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- return false;
- } else if (this.nextStartTick > 0) {
- this.nextStartTick--;
-diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java
-index 1acf9b8c9e6a5915b3f095e83d3f209708947093..3d94d5c9ecab0fe7332daf4cdac879385159eaa1 100644
---- a/net/minecraft/world/entity/animal/Fox.java
-+++ b/net/minecraft/world/entity/animal/Fox.java
-@@ -1038,7 +1038,7 @@ public class Fox extends Animal implements VariantHolder {
- }
-
- protected void onReachedTarget() {
-- if (getServerLevel(Fox.this.level()).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ if (getServerLevel(Fox.this.level()).purpurConfig.foxBypassMobGriefing ^ getServerLevel(Fox.this.level()).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- BlockState blockState = Fox.this.level().getBlockState(this.blockPos);
- if (blockState.is(Blocks.SWEET_BERRY_BUSH)) {
- this.pickSweetBerries(blockState);
-diff --git a/net/minecraft/world/entity/animal/Rabbit.java b/net/minecraft/world/entity/animal/Rabbit.java
-index bbdd06002b07699fffebdf6ed8148abdb69c24cc..7379def14f3f700fb8a746dc89d89e249e93b7b9 100644
---- a/net/minecraft/world/entity/animal/Rabbit.java
-+++ b/net/minecraft/world/entity/animal/Rabbit.java
-@@ -620,7 +620,7 @@ public class Rabbit extends Animal implements VariantHolder {
- @Override
- public boolean canUse() {
- if (this.nextStartTick <= 0) {
-- if (!getServerLevel(this.rabbit).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ if (!getServerLevel(this.rabbit).purpurConfig.rabbitBypassMobGriefing == !getServerLevel(this.rabbit).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- return false;
- }
-
-diff --git a/net/minecraft/world/entity/animal/SnowGolem.java b/net/minecraft/world/entity/animal/SnowGolem.java
-index d97a297db3bec0c86c6a82ef1c353015df2115f7..6ee73b798ab306f7c828c9f06ca5b1a96bd96139 100644
---- a/net/minecraft/world/entity/animal/SnowGolem.java
-+++ b/net/minecraft/world/entity/animal/SnowGolem.java
-@@ -136,7 +136,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
- this.hurtServer(serverLevel, this.damageSources().melting(), 1.0F); // CraftBukkit - DamageSources.ON_FIRE -> CraftEventFactory.MELTING
- }
-
-- if (!serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ if (!serverLevel.purpurConfig.snowGolemBypassMobGriefing == !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- return;
- }
-
-diff --git a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
-index ca900bb646e16c7b4342f23c3ffae786eab28145..724d259d4b793f2043e63dda9022bdfddc4dca38 100644
---- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
-+++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
-@@ -547,7 +547,7 @@ public class EnderDragon extends Mob implements Enemy {
- BlockPos blockPos = new BlockPos(i, i1, i2);
- BlockState blockState = level.getBlockState(blockPos);
- if (!blockState.isAir() && !blockState.is(BlockTags.DRAGON_TRANSPARENT)) {
-- if (level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !blockState.is(BlockTags.DRAGON_IMMUNE)) {
-+ if (level.purpurConfig.enderDragonBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !blockState.is(BlockTags.DRAGON_IMMUNE)) { // Purpur - Add mobGriefing bypass to everything affected
- // CraftBukkit start - Add blocks to list rather than destroying them
- //flag1 = level.removeBlock(blockPos, false) || flag1;
- flag1 = true;
-diff --git a/net/minecraft/world/entity/boss/wither/WitherBoss.java b/net/minecraft/world/entity/boss/wither/WitherBoss.java
-index 60e666aa8afe14b519010b6d137a89e3d22f6c81..a325fa87e149e7f354ed4cf3dbb30a002c4ce32a 100644
---- a/net/minecraft/world/entity/boss/wither/WitherBoss.java
-+++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java
-@@ -493,7 +493,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
-
- if (this.destroyBlocksTick > 0) {
- this.destroyBlocksTick--;
-- if (this.destroyBlocksTick == 0 && level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ if (this.destroyBlocksTick == 0 && level.purpurConfig.witherBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- boolean flag = false;
- int alternativeTarget = Mth.floor(this.getBbWidth() / 2.0F + 1.0F);
- int floor = Mth.floor(this.getBbHeight());
-diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
-index f8d6935439b4e672ed655b2a458451d4b1fa8ffd..7b74322aef3d7d45a322abccc71d9168b3c0911b 100644
---- a/net/minecraft/world/entity/monster/EnderMan.java
-+++ b/net/minecraft/world/entity/monster/EnderMan.java
-@@ -516,7 +516,7 @@ public class EnderMan extends Monster implements NeutralMob {
- public boolean canUse() {
- if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls
- return this.enderman.getCarriedBlock() != null
-- && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)
-+ && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) == !this.enderman.level().purpurConfig.endermanBypassMobGriefing // Purpur - Add mobGriefing bypass to everything affected
- && this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0;
- }
-
-@@ -666,7 +666,7 @@ public class EnderMan extends Monster implements NeutralMob {
- public boolean canUse() {
- if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls
- return this.enderman.getCarriedBlock() == null
-- && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)
-+ && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) == !this.enderman.level().purpurConfig.endermanBypassMobGriefing // Purpur - Add mobGriefing bypass to everything affected
- && this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0;
- }
-
-diff --git a/net/minecraft/world/entity/monster/Evoker.java b/net/minecraft/world/entity/monster/Evoker.java
-index d3d7e11a12af404d83e81888a9a633dfb93412ec..91574baf7ca095eae909e8e7225ad500bde15af2 100644
---- a/net/minecraft/world/entity/monster/Evoker.java
-+++ b/net/minecraft/world/entity/monster/Evoker.java
-@@ -323,7 +323,7 @@ public class Evoker extends SpellcasterIllager {
- return false;
- } else {
- ServerLevel serverLevel = getServerLevel(Evoker.this.level());
-- if (!serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ if (!serverLevel.purpurConfig.evokerBypassMobGriefing == !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- return false;
- } else {
- List nearbyEntities = serverLevel.getNearbyEntities(
-diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java
-index 36ebfc1102a18e4050eb9a2441d75bafcf3784b8..3449628fb87fd760abd730d84699c3a09c6ec761 100644
---- a/net/minecraft/world/entity/monster/Ravager.java
-+++ b/net/minecraft/world/entity/monster/Ravager.java
-@@ -175,7 +175,7 @@ public class Ravager extends Raider {
-
- if (this.level() instanceof ServerLevel serverLevel
- && this.horizontalCollision
-- && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-+ && serverLevel.purpurConfig.ravagerBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected
- boolean flag = false;
- AABB aabb = this.getBoundingBox().inflate(0.2);
-
-diff --git a/net/minecraft/world/entity/monster/Silverfish.java b/net/minecraft/world/entity/monster/Silverfish.java
-index d3befe91bc65bbc2bc0d8651b78e8c9576cd0f75..0d3b8b64a23a19d67a1a4a01faaf6649a59f54ad 100644
---- a/net/minecraft/world/entity/monster/Silverfish.java
-+++ b/net/minecraft/world/entity/monster/Silverfish.java
-@@ -170,7 +170,7 @@ public class Silverfish extends Monster {
- return false;
- } else {
- RandomSource random = this.mob.getRandom();
-- if (getServerLevel(this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && random.nextInt(reducedTickDelay(10)) == 0) {
-+ if (getServerLevel(this.mob).purpurConfig.silverfishBypassMobGriefing ^ getServerLevel(this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && random.nextInt(reducedTickDelay(10)) == 0) { // Purpur - Add mobGriefing bypass to everything affected
- this.selectedDirection = Direction.getRandom(random);
- BlockPos blockPos = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5, this.mob.getZ()).relative(this.selectedDirection);
- BlockState blockState = this.mob.level().getBlockState(blockPos);
-@@ -247,7 +247,7 @@ public class Silverfish extends Monster {
- Block block = blockState.getBlock();
- if (block instanceof InfestedBlock) {
- // CraftBukkit start
-- BlockState afterState = getServerLevel(level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? blockState.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(level.getBlockState(blockPos1)); // Paper - fix wrong block state
-+ BlockState afterState = getServerLevel(level).purpurConfig.silverfishBypassMobGriefing ^ getServerLevel(level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? blockState.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(level.getBlockState(blockPos1)); // Paper - fix wrong block state // Purpur - Add mobGriefing bypass to everything affected
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockPos1, afterState)) { // Paper - fix wrong block state
- continue;
- }
-diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java
-index 897c57263ab7347987b289016a71d11f693bc8b2..d923a424e2b33b7d4e9e4ecdce8e0a8c825038de 100644
---- a/net/minecraft/world/entity/monster/piglin/Piglin.java
-+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
-@@ -473,7 +473,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
-
- @Override
- public boolean wantsToPickUp(ServerLevel level, ItemStack stack) {
-- return level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack);
-+ return level.purpurConfig.piglinBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack); // Purpur - Add mobGriefing bypass to everything affected
- }
-
- protected boolean canReplaceCurrentItem(ItemStack candidate) {
-diff --git a/net/minecraft/world/entity/projectile/LargeFireball.java b/net/minecraft/world/entity/projectile/LargeFireball.java
-index 4a752ace041228f095af7b1b4878a03c5ed2381f..3e8b5d042eddb817dee2504ff9aa263f6195b1c7 100644
---- a/net/minecraft/world/entity/projectile/LargeFireball.java
-+++ b/net/minecraft/world/entity/projectile/LargeFireball.java
-@@ -18,20 +18,20 @@ public class LargeFireball extends Fireball {
-
- public LargeFireball(EntityType extends LargeFireball> entityType, Level level) {
- super(entityType, level);
-- this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit
-+ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.purpurConfig.fireballsBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit // Purpur - Add mobGriefing bypass to everything affected
- }
-
- public LargeFireball(Level level, LivingEntity owner, Vec3 movement, int explosionPower) {
- super(EntityType.FIREBALL, owner, movement, level);
- this.explosionPower = explosionPower;
-- this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit
-+ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.purpurConfig.fireballsBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit // Purpur - Add mobGriefing bypass to everything affected
- }
-
- @Override
- protected void onHit(HitResult result) {
- super.onHit(result);
- if (this.level() instanceof ServerLevel serverLevel) {
-- boolean _boolean = serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
-+ boolean _boolean = serverLevel.purpurConfig.fireballsBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - Add mobGriefing bypass to everything affected
- // CraftBukkit start - fire ExplosionPrimeEvent
- org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity());
- this.level().getCraftServer().getPluginManager().callEvent(event);
-diff --git a/net/minecraft/world/entity/projectile/Projectile.java b/net/minecraft/world/entity/projectile/Projectile.java
-index ad0bb896d6ea669ce88bfe6490319e8ba7a29001..843f1396a6567672e5e8002d7e48fb18cf39d5de 100644
---- a/net/minecraft/world/entity/projectile/Projectile.java
-+++ b/net/minecraft/world/entity/projectile/Projectile.java
-@@ -454,7 +454,7 @@ public abstract class Projectile extends Entity implements TraceableEntity {
- @Override
- public boolean mayInteract(ServerLevel level, BlockPos pos) {
- Entity owner = this.getOwner();
-- return owner instanceof Player ? owner.mayInteract(level, pos) : owner == null || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
-+ return owner instanceof Player ? owner.mayInteract(level, pos) : owner == null || level.purpurConfig.projectilesBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - Add mobGriefing bypass to everything affected
- }
-
- public boolean mayBreak(ServerLevel level) {
-diff --git a/net/minecraft/world/entity/projectile/SmallFireball.java b/net/minecraft/world/entity/projectile/SmallFireball.java
-index 8c84cea43fc0e42a576004663670977eac99f1a6..808aa5dcb27c87b6ba5c1eee639486067447e370 100644
---- a/net/minecraft/world/entity/projectile/SmallFireball.java
-+++ b/net/minecraft/world/entity/projectile/SmallFireball.java
-@@ -25,7 +25,7 @@ public class SmallFireball extends Fireball {
- super(EntityType.SMALL_FIREBALL, owner, movement, level);
- // CraftBukkit start
- if (this.getOwner() != null && this.getOwner() instanceof Mob) {
-- this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
-+ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.purpurConfig.fireballsBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - Add mobGriefing bypass to everything affected
- }
- // CraftBukkit end
- }
-diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
-index 8270d76a753bfd26a4c8ef6610bee5c24ee59cfe..c06b589e669b055a26f662df60070d5908256220 100644
---- a/net/minecraft/world/entity/raid/Raider.java
-+++ b/net/minecraft/world/entity/raid/Raider.java
-@@ -399,7 +399,7 @@ public abstract class Raider extends PatrollingMonster {
- }
-
- private boolean cannotPickUpBanner() {
-- if (!getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items
-+ if (!this.mob.level().purpurConfig.pillagerBypassMobGriefing == !getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items // Purpur - Add mobGriefing bypass to everything affected
- if (!this.mob.hasActiveRaid()) {
- return true;
- } else if (this.mob.getCurrentRaid().isOver()) {
-diff --git a/net/minecraft/world/level/block/CropBlock.java b/net/minecraft/world/level/block/CropBlock.java
-index b43f16297ac4441d78d0dc1fadb555698b0c3f6d..27f0c5c886a3f8b14ef9a00e2aaaabf4bf09c7db 100644
---- a/net/minecraft/world/level/block/CropBlock.java
-+++ b/net/minecraft/world/level/block/CropBlock.java
-@@ -182,7 +182,7 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
- @Override
- protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
- if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
-- if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.purpurConfig.ravagerGriefableBlocks.contains(serverLevel.getBlockState(pos).getBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Purpur - Configurable ravager griefable blocks list
-+ if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.purpurConfig.ravagerGriefableBlocks.contains(serverLevel.getBlockState(pos).getBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.purpurConfig.ravagerBypassMobGriefing == !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Purpur - Configurable ravager griefable blocks list // Purpur - Add mobGriefing bypass to everything affected
- serverLevel.destroyBlock(pos, true, entity);
- }
-
-diff --git a/net/minecraft/world/level/block/FarmBlock.java b/net/minecraft/world/level/block/FarmBlock.java
-index 6ab9a1188ce60e114ef35e393d9f2f46d490af83..9a7ca836e54cc3f58001c85f0079747f4d4941ad 100644
---- a/net/minecraft/world/level/block/FarmBlock.java
-+++ b/net/minecraft/world/level/block/FarmBlock.java
-@@ -114,7 +114,7 @@ public class FarmBlock extends Block {
- if (level instanceof ServerLevel serverLevel
- && (serverLevel.purpurConfig.farmlandTrampleHeight >= 0D ? fallDistance >= serverLevel.purpurConfig.farmlandTrampleHeight : level.random.nextFloat() < fallDistance - 0.5F) // // Purpur - Configurable farmland trample height
- && entity instanceof LivingEntity
-- && (entity instanceof Player || serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))
-+ && (entity instanceof Player || serverLevel.purpurConfig.farmlandBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))
- && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) {
- // CraftBukkit start - Interact soil
- org.bukkit.event.Cancellable cancellable;
-diff --git a/net/minecraft/world/level/block/PowderSnowBlock.java b/net/minecraft/world/level/block/PowderSnowBlock.java
-index 9c0ded7ae7e3a520704033a866f80743ae85d772..4f3646961beb877520e257e11224c3045467d351 100644
---- a/net/minecraft/world/level/block/PowderSnowBlock.java
-+++ b/net/minecraft/world/level/block/PowderSnowBlock.java
-@@ -84,7 +84,7 @@ public class PowderSnowBlock extends Block implements BucketPickup {
- // CraftBukkit - move down
- && entity.mayInteract(serverLevel, pos)) {
- // CraftBukkit start
-- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !(serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || entity instanceof Player))) {
-+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !(serverLevel.purpurConfig.powderSnowBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || entity instanceof Player))) {
- return;
- }
- // CraftBukkit end
-diff --git a/net/minecraft/world/level/block/TurtleEggBlock.java b/net/minecraft/world/level/block/TurtleEggBlock.java
-index c97d5bd7b4c1b6f8eccbe2d123292e913a285ef2..a3a093d95306baac22e5cf720f5b14f733b548d4 100644
---- a/net/minecraft/world/level/block/TurtleEggBlock.java
-+++ b/net/minecraft/world/level/block/TurtleEggBlock.java
-@@ -216,7 +216,7 @@ public class TurtleEggBlock extends Block {
- // Purpur end - Option to disable turtle egg trampling with feather falling
- if (entity instanceof Player) return true;
-
-- return level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
-+ return level.purpurConfig.turtleEggsBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - Add mobGriefing bypass to everything affected
- // Purpur end - Add turtle egg block options
- }
- }
diff --git a/purpur-server/minecraft-patches/features/0018-Toggle-for-water-sensitive-mob-damage.patch b/purpur-server/minecraft-patches/features/0016-Toggle-for-water-sensitive-mob-damage.patch
similarity index 59%
rename from purpur-server/minecraft-patches/features/0018-Toggle-for-water-sensitive-mob-damage.patch
rename to purpur-server/minecraft-patches/features/0016-Toggle-for-water-sensitive-mob-damage.patch
index bdc613a79..3d05d0bdd 100644
--- a/purpur-server/minecraft-patches/features/0018-Toggle-for-water-sensitive-mob-damage.patch
+++ b/purpur-server/minecraft-patches/features/0016-Toggle-for-water-sensitive-mob-damage.patch
@@ -4,26 +4,8 @@ Date: Fri, 5 Feb 2021 01:11:22 +0100
Subject: [PATCH] Toggle for water sensitive mob damage
-diff --git a/net/minecraft/world/entity/GlowSquid.java b/net/minecraft/world/entity/GlowSquid.java
-index 898b1e01026ec1f44cfe60e9f18a997c86e30594..e717c063c8f9623b8c4b4ea3843d05fd79af3653 100644
---- a/net/minecraft/world/entity/GlowSquid.java
-+++ b/net/minecraft/world/entity/GlowSquid.java
-@@ -52,6 +52,13 @@ public class GlowSquid extends Squid {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.glowSquidTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected ParticleOptions getInkParticle() {
- return ParticleTypes.GLOW_SQUID_INK;
diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java
-index ecbec552e5cd1935f57872d2fb502d3e9743e3d8..4fa526496265a85b637136f0fd0692ef4f570ad6 100644
+index a09b5035e91d50e12f613a7a1211c6869fbbf4df..e83900f8d6adbe8a48294f250bd6cc6e3fad8160 100644
--- a/net/minecraft/world/entity/ambient/Bat.java
+++ b/net/minecraft/world/entity/ambient/Bat.java
@@ -109,6 +109,13 @@ public class Bat extends AmbientCreature {
@@ -40,54 +22,56 @@ index ecbec552e5cd1935f57872d2fb502d3e9743e3d8..4fa526496265a85b637136f0fd0692ef
@Override
public boolean isFlapping() {
return !this.isResting() && this.tickCount % 10.0F == 0.0F;
-diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java
-index 199bd7e9b053a2eac76987ceb5caebc088d1071d..636ff0f4f8415b6ce23d2676781503443c854cfe 100644
---- a/net/minecraft/world/entity/animal/Bee.java
-+++ b/net/minecraft/world/entity/animal/Bee.java
-@@ -177,7 +177,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
- // Paper end - Fix MC-167279
- this.lookControl = new Bee.BeeLookControl(this);
- this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
-- this.setPathfindingMalus(PathType.WATER, -1.0F);
-+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - Toggle for water sensitive mob damage
- this.setPathfindingMalus(PathType.WATER_BORDER, 16.0F);
- this.setPathfindingMalus(PathType.COCOA, -1.0F);
- this.setPathfindingMalus(PathType.FENCE, -1.0F);
-@@ -487,6 +487,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
- }
- // Purpur end - Make entity breeding times configurable
-
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.beeTakeDamageFromWater;
-+ }
-+
- @Override
- public int getRemainingPersistentAngerTime() {
- return this.entityData.get(DATA_REMAINING_ANGER_TIME);
-diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java
-index 584568cef949cee24aa7850d2ff99d47cd089a6e..b41ca04043e65f107edaebc49d398650898e35fb 100644
---- a/net/minecraft/world/entity/animal/Cat.java
-+++ b/net/minecraft/world/entity/animal/Cat.java
-@@ -133,6 +133,13 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true);
-diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java
-index 39ad1729ef03fc35a6365ee215be214eccfd959a..2364596156c21e82879f5bf4fd873b9d90b1c308 100644
---- a/net/minecraft/world/entity/animal/Chicken.java
-+++ b/net/minecraft/world/entity/animal/Chicken.java
-@@ -88,6 +88,13 @@ public class Chicken extends Animal {
+ public float getWalkTargetValue(BlockPos pos, LevelReader level) {
+ return 0.0F;
+diff --git a/net/minecraft/world/entity/animal/bee/Bee.java b/net/minecraft/world/entity/animal/bee/Bee.java
+index 473aa29e3075fcab44a14c2bc14d3f222b55cbad..e57200d6560a38cbecd681a30b75409412fce170 100644
+--- a/net/minecraft/world/entity/animal/bee/Bee.java
++++ b/net/minecraft/world/entity/animal/bee/Bee.java
+@@ -185,7 +185,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+ // Paper end - Fix MC-167279
+ this.lookControl = new Bee.BeeLookControl(this);
+ this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
+- if (this.level().purpurConfig.beeCanInstantlyStartDrowning) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - bee can instantly start drowning in water option
++ if (this.level().purpurConfig.beeCanInstantlyStartDrowning || isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - bee can instantly start drowning in water option // Purpur - Toggle for water sensitive mob damage
+ this.setPathfindingMalus(PathType.WATER_BORDER, 16.0F);
+ this.setPathfindingMalus(PathType.COCOA, -1.0F);
+ this.setPathfindingMalus(PathType.FENCE, -1.0F);
+@@ -492,6 +492,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.beeTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ public long getPersistentAngerEndTime() {
+ return this.entityData.get(DATA_ANGER_END_TIME);
+diff --git a/net/minecraft/world/entity/animal/chicken/Chicken.java b/net/minecraft/world/entity/animal/chicken/Chicken.java
+index 029fe4ac952d9f56824de346d98b341bd0b9b65f..6308bb606b34d781e315f56a55e6544b3c156d85 100644
+--- a/net/minecraft/world/entity/animal/chicken/Chicken.java
++++ b/net/minecraft/world/entity/animal/chicken/Chicken.java
+@@ -110,6 +110,13 @@ public class Chicken extends Animal {
}
// Purpur end - Make entity breeding times configurable
@@ -101,10 +85,226 @@ index 39ad1729ef03fc35a6365ee215be214eccfd959a..2364596156c21e82879f5bf4fd873b9d
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Cod.java b/net/minecraft/world/entity/animal/Cod.java
-index 434e1fabf2e360a8f5f4eefed96e3883aa786d10..ac7259cfc8428131f90956d7f76f2227049ffae3 100644
---- a/net/minecraft/world/entity/animal/Cod.java
-+++ b/net/minecraft/world/entity/animal/Cod.java
+diff --git a/net/minecraft/world/entity/animal/cow/Cow.java b/net/minecraft/world/entity/animal/cow/Cow.java
+index 400b0a0a99590e3590cb66724acdc5ba9170f2c4..bb8c75d20e6a1300d68ae75233962bdc26736c77 100644
+--- a/net/minecraft/world/entity/animal/cow/Cow.java
++++ b/net/minecraft/world/entity/animal/cow/Cow.java
+@@ -61,6 +61,13 @@ public class Cow extends AbstractCow {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.cowTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/animal/cow/MushroomCow.java b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+index e2aa027dc7a39fa8a8868a7d153e838113fcf97b..a8e6e703a51130066547724dd08bdfe5e11c99e5 100644
+--- a/net/minecraft/world/entity/animal/cow/MushroomCow.java
++++ b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+@@ -92,6 +92,13 @@ public class MushroomCow extends AbstractCow implements Shearable {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.mooshroomTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ public float getWalkTargetValue(BlockPos pos, LevelReader level) {
+ return level.getBlockState(pos.below()).is(Blocks.MYCELIUM) ? 10.0F : level.getPathfindingCostFromLightLevels(pos);
+diff --git a/net/minecraft/world/entity/animal/dolphin/Dolphin.java b/net/minecraft/world/entity/animal/dolphin/Dolphin.java
+index 94f92080de46f2af67e1d28753208691da534ddf..d73789bb8ce0f65be94437484c3ed41e26cd7510 100644
+--- a/net/minecraft/world/entity/animal/dolphin/Dolphin.java
++++ b/net/minecraft/world/entity/animal/dolphin/Dolphin.java
+@@ -160,6 +160,13 @@ public class Dolphin extends AgeableWaterCreature {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.dolphinTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ public @Nullable SpawnGroupData finalizeSpawn(
+ ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
+diff --git a/net/minecraft/world/entity/animal/equine/Donkey.java b/net/minecraft/world/entity/animal/equine/Donkey.java
+index d74a5cc2a43ef41fd00676bbd17fe4df9edb67ff..6cf6853c244b7589d2a57e7ae77933d4a1503ccd 100644
+--- a/net/minecraft/world/entity/animal/equine/Donkey.java
++++ b/net/minecraft/world/entity/animal/equine/Donkey.java
+@@ -47,6 +47,13 @@ public class Donkey extends AbstractChestedHorse {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.donkeyTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ public SoundEvent getAmbientSound() {
+ return SoundEvents.DONKEY_AMBIENT;
+diff --git a/net/minecraft/world/entity/animal/equine/Horse.java b/net/minecraft/world/entity/animal/equine/Horse.java
+index ba9df659ed019f9e58991059fe99c1471bfc94d8..1c17ab94901ce1c6370670c06bf0801ee6b5b393 100644
+--- a/net/minecraft/world/entity/animal/equine/Horse.java
++++ b/net/minecraft/world/entity/animal/equine/Horse.java
+@@ -81,6 +81,13 @@ public class Horse extends AbstractHorse {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.horseTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void randomizeAttributes(RandomSource random) {
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt));
+diff --git a/net/minecraft/world/entity/animal/equine/Llama.java b/net/minecraft/world/entity/animal/equine/Llama.java
+index 960e48f5ae63d8c86758d2573510bf481ca4bca0..eb2fc0e6d497241f1b4f3971155b10d14f5427f8 100644
+--- a/net/minecraft/world/entity/animal/equine/Llama.java
++++ b/net/minecraft/world/entity/animal/equine/Llama.java
+@@ -159,6 +159,13 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.llamaTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ public boolean isTraderLlama() {
+ return false;
+ }
+diff --git a/net/minecraft/world/entity/animal/equine/Mule.java b/net/minecraft/world/entity/animal/equine/Mule.java
+index 180a807026437e949e3f7c3d59864ea328f6f03f..9bafe3e204b3e4624a95b130552c8230c0835a30 100644
+--- a/net/minecraft/world/entity/animal/equine/Mule.java
++++ b/net/minecraft/world/entity/animal/equine/Mule.java
+@@ -46,6 +46,13 @@ public class Mule extends AbstractChestedHorse {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.muleTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ public SoundEvent getAmbientSound() {
+ return SoundEvents.MULE_AMBIENT;
+diff --git a/net/minecraft/world/entity/animal/equine/SkeletonHorse.java b/net/minecraft/world/entity/animal/equine/SkeletonHorse.java
+index af0e326f5ff8fcb82353bac3143103928a6a08e6..3865937e4a56636cde44f7d8f16873ae16512323 100644
+--- a/net/minecraft/world/entity/animal/equine/SkeletonHorse.java
++++ b/net/minecraft/world/entity/animal/equine/SkeletonHorse.java
+@@ -74,6 +74,13 @@ public class SkeletonHorse extends AbstractHorse {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.skeletonHorseTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0).add(Attributes.MOVEMENT_SPEED, 0.2F);
+ }
+diff --git a/net/minecraft/world/entity/animal/equine/TraderLlama.java b/net/minecraft/world/entity/animal/equine/TraderLlama.java
+index 65ac46335d642d5dd8c01623721257a4fd53441d..4c07cd57aa3518adb4bc9b1213cc572a5b81f935 100644
+--- a/net/minecraft/world/entity/animal/equine/TraderLlama.java
++++ b/net/minecraft/world/entity/animal/equine/TraderLlama.java
+@@ -77,6 +77,13 @@ public class TraderLlama extends Llama {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.traderLlamaTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ public boolean isTraderLlama() {
+ return true;
+diff --git a/net/minecraft/world/entity/animal/equine/ZombieHorse.java b/net/minecraft/world/entity/animal/equine/ZombieHorse.java
+index fa2f18470123f98e336ab5c94bc791e9333356cb..b770d3118452b0b7a362b1f541bb602f4d3cbcec 100644
+--- a/net/minecraft/world/entity/animal/equine/ZombieHorse.java
++++ b/net/minecraft/world/entity/animal/equine/ZombieHorse.java
+@@ -88,6 +88,13 @@ public class ZombieHorse extends AbstractHorse {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.zombieHorseTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 25.0);
+ }
+diff --git a/net/minecraft/world/entity/animal/feline/Cat.java b/net/minecraft/world/entity/animal/feline/Cat.java
+index d0aa698ef99cf3b1926018314b4067cc1cd8ac2a..92b67565485b2fade3e80fb4b944edfc12d9e0a2 100644
+--- a/net/minecraft/world/entity/animal/feline/Cat.java
++++ b/net/minecraft/world/entity/animal/feline/Cat.java
+@@ -135,6 +135,13 @@ public class Cat extends TamableAnimal {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.catTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void registerGoals() {
+ this.temptGoal = new Cat.CatTemptGoal(this, 0.6, stack -> stack.is(ItemTags.CAT_FOOD), true);
+diff --git a/net/minecraft/world/entity/animal/feline/Ocelot.java b/net/minecraft/world/entity/animal/feline/Ocelot.java
+index bf281fd4c050b87fd277ab68e812ab2dcd3d06aa..13272516003f763d2c69dc599c8ff7696bec718b 100644
+--- a/net/minecraft/world/entity/animal/feline/Ocelot.java
++++ b/net/minecraft/world/entity/animal/feline/Ocelot.java
+@@ -98,6 +98,13 @@ public class Ocelot extends Animal {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.ocelotTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ public boolean isTrusting() {
+ return this.entityData.get(DATA_TRUSTING);
+ }
+diff --git a/net/minecraft/world/entity/animal/fish/Cod.java b/net/minecraft/world/entity/animal/fish/Cod.java
+index e00e623d7df9e179d8bb5ee4812538578c5f4c08..8655aae805f239cbd049065232293854b18c73cf 100644
+--- a/net/minecraft/world/entity/animal/fish/Cod.java
++++ b/net/minecraft/world/entity/animal/fish/Cod.java
@@ -32,6 +32,13 @@ public class Cod extends AbstractSchoolingFish {
}
// Purpur end - Configurable entity base attributes
@@ -119,191 +319,11 @@ index 434e1fabf2e360a8f5f4eefed96e3883aa786d10..ac7259cfc8428131f90956d7f76f2227
@Override
public ItemStack getBucketItemStack() {
return new ItemStack(Items.COD_BUCKET);
-diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java
-index e4965300eb41512d03a0b111422c98627cf29a54..a8c76fcbbaa4afd2d0bd568874995b91d8d67c03 100644
---- a/net/minecraft/world/entity/animal/Cow.java
-+++ b/net/minecraft/world/entity/animal/Cow.java
-@@ -70,6 +70,13 @@ public class Cow extends Animal {
- }
- // Purpur end - Make entity breeding times configurable
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.cowTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java
-index 5b764c686e8759a7b04a7b50708c69629be02c04..e104058b3c01bea4cc8a77de2ad4378465903b34 100644
---- a/net/minecraft/world/entity/animal/Dolphin.java
-+++ b/net/minecraft/world/entity/animal/Dolphin.java
-@@ -156,6 +156,13 @@ public class Dolphin extends AgeableWaterCreature {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.dolphinTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Nullable
- @Override
- public SpawnGroupData finalizeSpawn(
-diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java
-index 3d94d5c9ecab0fe7332daf4cdac879385159eaa1..22a70c6af965114e272bb56cb217f975a3cd1bd4 100644
---- a/net/minecraft/world/entity/animal/Fox.java
-+++ b/net/minecraft/world/entity/animal/Fox.java
-@@ -182,6 +182,13 @@ public class Fox extends Animal implements VariantHolder {
- }
- // Purpur end - Make entity breeding times configurable
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.foxTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/animal/IronGolem.java b/net/minecraft/world/entity/animal/IronGolem.java
-index 37a353cbb0e9b16e0fc92bd1bc8194cb4cd3c13a..23108729ce65ef8b7b215b82f29347513cfd4ebf 100644
---- a/net/minecraft/world/entity/animal/IronGolem.java
-+++ b/net/minecraft/world/entity/animal/IronGolem.java
-@@ -98,6 +98,13 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.ironGolemTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void registerGoals() {
- if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options
-diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java
-index a64b609bf5ce38a252bfa1bcff869f88e14389b5..5e9795f447e88a42909730d383eaa36acfaf18f5 100644
---- a/net/minecraft/world/entity/animal/MushroomCow.java
-+++ b/net/minecraft/world/entity/animal/MushroomCow.java
-@@ -86,6 +86,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder {
- }
- // Purpur end - Make entity breeding times configurable
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.rabbitTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- public void registerGoals() {
- this.goalSelector.addGoal(1, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Salmon.java b/net/minecraft/world/entity/animal/Salmon.java
-index 93eb3cc3605f694337c1604e2db63fed04693617..8bd4b2b29438bff65ed00a42bbc9639111af181f 100644
---- a/net/minecraft/world/entity/animal/Salmon.java
-+++ b/net/minecraft/world/entity/animal/Salmon.java
-@@ -54,6 +54,13 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder, B
- }
- // Purpur end - Make entity breeding times configurable
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.axolotlTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- public float getWalkTargetValue(BlockPos pos, LevelReader level) {
- return 0.0F;
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java
-index 0a018dbfe3750cf91892d8cfb5c0eac18e83d587..0c357ffacfe4dd982a58e6cf2338c7e6b24610f5 100644
+index 07ba57ae845024e0f2fa03a68e126ec79bfc6b15..e5f5bc2c4b4f36e0e911b2c5ef67ef6e0d4cd0b1 100644
--- a/net/minecraft/world/entity/animal/goat/Goat.java
+++ b/net/minecraft/world/entity/animal/goat/Goat.java
-@@ -135,6 +135,13 @@ public class Goat extends Animal {
+@@ -139,6 +139,13 @@ public class Goat extends Animal {
}
// Purpur end - Make entity breeding times configurable
@@ -492,134 +409,255 @@ index 0a018dbfe3750cf91892d8cfb5c0eac18e83d587..0c357ffacfe4dd982a58e6cf2338c7e6
@Override
protected Brain.Provider brainProvider() {
return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java
-index b977597785df5665176ab2f330633ec61b7c9feb..1db6ccdc6c83c704aa84a46ee2751a17125bf457 100644
---- a/net/minecraft/world/entity/animal/horse/Donkey.java
-+++ b/net/minecraft/world/entity/animal/horse/Donkey.java
-@@ -47,6 +47,13 @@ public class Donkey extends AbstractChestedHorse {
+diff --git a/net/minecraft/world/entity/animal/golem/CopperGolem.java b/net/minecraft/world/entity/animal/golem/CopperGolem.java
+index e3c5b6fe7d6cdb674fbf5ac22001c3d917bf91ec..2d0ce5d420f88a95eda34a3fe81c815999bde300 100644
+--- a/net/minecraft/world/entity/animal/golem/CopperGolem.java
++++ b/net/minecraft/world/entity/animal/golem/CopperGolem.java
+@@ -140,6 +140,13 @@ public class CopperGolem extends AbstractGolem implements ContainerUser, Shearab
}
- // Purpur end - Make entity breeding times configurable
+ // Purpur end - Configurable entity base attributes
+ // Purpur start - Toggle for water sensitive mob damage
+ @Override
+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.donkeyTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected SoundEvent getAmbientSound() {
- return SoundEvents.DONKEY_AMBIENT;
-diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java
-index 0339ab08b3029a9ffc102c5b865e411aca2a863c..f257d549570918381925cef98734fc0aa605f8f2 100644
---- a/net/minecraft/world/entity/animal/horse/Horse.java
-+++ b/net/minecraft/world/entity/animal/horse/Horse.java
-@@ -74,6 +74,13 @@ public class Horse extends AbstractHorse implements VariantHolder {
- }
- // Purpur end - Make entity breeding times configurable
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.horseTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void randomizeAttributes(RandomSource random) {
- this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt));
-diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java
-index 6efe52edb6909ed2b38210ce6a0334eddc55f261..872a54186a20fd855fe7981f3ff1c867f4c64d19 100644
---- a/net/minecraft/world/entity/animal/horse/Llama.java
-+++ b/net/minecraft/world/entity/animal/horse/Llama.java
-@@ -148,6 +148,13 @@ public class Llama extends AbstractChestedHorse implements VariantHolder entityType, Level level) {
- super(entityType, level);
+@@ -35,7 +35,7 @@ public class Blaze extends Monster {
+ public Blaze(EntityType extends Blaze> type, Level level) {
+ super(type, level);
this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur - Ridables
- this.setPathfindingMalus(PathType.WATER, -1.0F);
+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - Toggle for water sensitive mob damage
this.setPathfindingMalus(PathType.LAVA, 8.0F);
this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F);
this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F);
-@@ -157,7 +157,7 @@ public class Blaze extends Monster {
+@@ -158,7 +158,7 @@ public class Blaze extends Monster {
@Override
public boolean isSensitiveToWater() {
@@ -676,29 +714,11 @@ index ece9e3e18c60d5ca9b4a8bd8899556c90cc8d039..1ea964b3a3b9403ad3a500bf1c4b8d69
}
@Override
-diff --git a/net/minecraft/world/entity/monster/CaveSpider.java b/net/minecraft/world/entity/monster/CaveSpider.java
-index 64eecd8d1acd318743800c1daa77cd97097a0f7c..420fe0d01d0b173a6a541f77e1aaca3f3bb565e7 100644
---- a/net/minecraft/world/entity/monster/CaveSpider.java
-+++ b/net/minecraft/world/entity/monster/CaveSpider.java
-@@ -51,6 +51,13 @@ public class CaveSpider extends Spider {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.caveSpiderTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- public boolean doHurtTarget(ServerLevel level, Entity source) {
- if (super.doHurtTarget(level, source)) {
diff --git a/net/minecraft/world/entity/monster/Creeper.java b/net/minecraft/world/entity/monster/Creeper.java
-index 31ede62a19321970d26f302399a60947b8d88b37..6d9995d5f38b2f94a2d3362da7861b3e90e4fb6f 100644
+index ed1ccd712a2fe00740beeee4fe615976258f5c6c..b0ed96c243f9abb3868d92bb513ad1620aa8e269 100644
--- a/net/minecraft/world/entity/monster/Creeper.java
+++ b/net/minecraft/world/entity/monster/Creeper.java
-@@ -267,6 +267,13 @@ public class Creeper extends Monster {
+@@ -266,6 +266,13 @@ public class Creeper extends Monster {
}
// Purpur end - Config to make Creepers explode on death
@@ -710,28 +730,10 @@ index 31ede62a19321970d26f302399a60947b8d88b37..6d9995d5f38b2f94a2d3362da7861b3e
+ // Purpur end - Toggle for water sensitive mob damage
+
@Override
- protected SoundEvent getHurtSound(DamageSource damageSource) {
+ public SoundEvent getHurtSound(DamageSource damageSource) {
return SoundEvents.CREEPER_HURT;
-diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java
-index 83fc978a94be4655e8c47ee634b8cd280d2a6fde..0a1a78e65b6472b713835262b5937bc7ea67b95c 100644
---- a/net/minecraft/world/entity/monster/Drowned.java
-+++ b/net/minecraft/world/entity/monster/Drowned.java
-@@ -122,6 +122,13 @@ public class Drowned extends Zombie implements RangedAttackMob {
- }
- // Purpur end - Configurable jockey options
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.drownedTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void addBehaviourGoals() {
- this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0));
diff --git a/net/minecraft/world/entity/monster/ElderGuardian.java b/net/minecraft/world/entity/monster/ElderGuardian.java
-index 148ae4bca77874545a2a05fb7f29f9ac284feff6..2b1d33f4938b978c5b04ede7562bdecb5fbd2245 100644
+index 57fb334f670d35aa181b13e12fa2c5f36da1dda6..1ea323a17440abbe36c9528e80e169816267005b 100644
--- a/net/minecraft/world/entity/monster/ElderGuardian.java
+++ b/net/minecraft/world/entity/monster/ElderGuardian.java
@@ -51,6 +51,13 @@ public class ElderGuardian extends Guardian {
@@ -749,19 +751,19 @@ index 148ae4bca77874545a2a05fb7f29f9ac284feff6..2b1d33f4938b978c5b04ede7562bdecb
return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.3F).add(Attributes.ATTACK_DAMAGE, 8.0).add(Attributes.MAX_HEALTH, 80.0);
}
diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
-index 7b74322aef3d7d45a322abccc71d9168b3c0911b..6fccfb243c26c27b665df57e5e19eb3350c52ddf 100644
+index 79a1d8f67a22a8fa4a6c3b657e44bb9503687c27..47c621f01658f3392b58f3f5c1f31bd539f63dd6 100644
--- a/net/minecraft/world/entity/monster/EnderMan.java
+++ b/net/minecraft/world/entity/monster/EnderMan.java
-@@ -87,7 +87,7 @@ public class EnderMan extends Monster implements NeutralMob {
+@@ -86,7 +86,7 @@ public class EnderMan extends Monster implements NeutralMob {
- public EnderMan(EntityType extends EnderMan> entityType, Level level) {
- super(entityType, level);
+ public EnderMan(EntityType extends EnderMan> type, Level level) {
+ super(type, level);
- this.setPathfindingMalus(PathType.WATER, -1.0F);
+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - Toggle for water sensitive mob damage
}
// Purpur start - Ridables
-@@ -294,7 +294,7 @@ public class EnderMan extends Monster implements NeutralMob {
+@@ -285,7 +285,7 @@ public class EnderMan extends Monster implements NeutralMob {
@Override
public boolean isSensitiveToWater() {
@@ -771,10 +773,10 @@ index 7b74322aef3d7d45a322abccc71d9168b3c0911b..6fccfb243c26c27b665df57e5e19eb33
@Override
diff --git a/net/minecraft/world/entity/monster/Endermite.java b/net/minecraft/world/entity/monster/Endermite.java
-index 2ea45eba13d0b0ea2d3c1d1a3666d6e2e027a3ef..38e3b3ed2c003fe7bbb476f7bf9a882ea2de792a 100644
+index c6ae00f6ab83743b9ce43d9e55f04ba23b0de0f1..c79c689cb99ad2a6cab88cf8b583ff0f9e91b115 100644
--- a/net/minecraft/world/entity/monster/Endermite.java
+++ b/net/minecraft/world/entity/monster/Endermite.java
-@@ -70,6 +70,13 @@ public class Endermite extends Monster {
+@@ -72,6 +72,13 @@ public class Endermite extends Monster {
}
// Purpur end - Configurable entity base attributes
@@ -788,29 +790,11 @@ index 2ea45eba13d0b0ea2d3c1d1a3666d6e2e027a3ef..38e3b3ed2c003fe7bbb476f7bf9a882e
@Override
protected void registerGoals() {
this.goalSelector.addGoal(1, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/monster/Evoker.java b/net/minecraft/world/entity/monster/Evoker.java
-index 91574baf7ca095eae909e8e7225ad500bde15af2..61ed6606948cc5f8af543eb9ae05f9aeb4e73b89 100644
---- a/net/minecraft/world/entity/monster/Evoker.java
-+++ b/net/minecraft/world/entity/monster/Evoker.java
-@@ -75,6 +75,13 @@ public class Evoker extends SpellcasterIllager {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.evokerTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Ghast.java b/net/minecraft/world/entity/monster/Ghast.java
-index c5987f50b343ded580b3d3f264498d3893433f92..68debfa8c6d0fc3ff536d2b4d89c131fd6aca935 100644
+index 7d97c00ae49629b97104631317aa6174741cdd5e..443eb9f12d6df950c59c9d4db4853087fd23d24e 100644
--- a/net/minecraft/world/entity/monster/Ghast.java
+++ b/net/minecraft/world/entity/monster/Ghast.java
-@@ -84,6 +84,13 @@ public class Ghast extends FlyingMob implements Enemy {
+@@ -83,6 +83,13 @@ public class Ghast extends Mob implements Enemy {
}
// Purpur end - Configurable entity base attributes
@@ -825,7 +809,7 @@ index c5987f50b343ded580b3d3f264498d3893433f92..68debfa8c6d0fc3ff536d2b4d89c131f
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
diff --git a/net/minecraft/world/entity/monster/Giant.java b/net/minecraft/world/entity/monster/Giant.java
-index 73da18c4b54e250c434fd75971ef0a8f7c8cf6a3..009b8a8b1b9aabc0aef1c12a0c0f65f9ccfcd306 100644
+index 40cf8f44a6b01d45306dab4ba4f9a7ea7c6590a9..f1176f73d4468b2f39e48fe5454c5f5bf481afd9 100644
--- a/net/minecraft/world/entity/monster/Giant.java
+++ b/net/minecraft/world/entity/monster/Giant.java
@@ -62,6 +62,13 @@ public class Giant extends Monster {
@@ -840,13 +824,13 @@ index 73da18c4b54e250c434fd75971ef0a8f7c8cf6a3..009b8a8b1b9aabc0aef1c12a0c0f65f9
+ // Purpur end - Toggle for water sensitive mob damage
+
public static AttributeSupplier.Builder createAttributes() {
- return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0);
- }
+ return Monster.createMonsterAttributes()
+ .add(Attributes.MAX_HEALTH, 100.0)
diff --git a/net/minecraft/world/entity/monster/Guardian.java b/net/minecraft/world/entity/monster/Guardian.java
-index 546a4fe6d038d04c0be500e76ff4aebb02c3681a..819679a224ffe33e03d8e6b429c8e31b67c769fa 100644
+index 1eaa4f255b01eddc93ddbc5615ad05e7d8273581..9948511659de9222a19f6b9f660e4441ea98a4a9 100644
--- a/net/minecraft/world/entity/monster/Guardian.java
+++ b/net/minecraft/world/entity/monster/Guardian.java
-@@ -98,6 +98,13 @@ public class Guardian extends Monster {
+@@ -97,6 +97,13 @@ public class Guardian extends Monster {
}
// Purpur end - Configurable entity base attributes
@@ -860,44 +844,8 @@ index 546a4fe6d038d04c0be500e76ff4aebb02c3681a..819679a224ffe33e03d8e6b429c8e31b
@Override
protected void registerGoals() {
MoveTowardsRestrictionGoal moveTowardsRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0);
-diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java
-index 7a8951f93e65c6df145e30d44b9d928dd0c39189..31eef2869945d9de565d627cac3fc1a5db380a2a 100644
---- a/net/minecraft/world/entity/monster/Husk.java
-+++ b/net/minecraft/world/entity/monster/Husk.java
-@@ -67,6 +67,13 @@ public class Husk extends Zombie {
- }
- // Purpur end - Configurable jockey options
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.huskTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- public static boolean checkHuskSpawnRules(
- EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
- ) {
-diff --git a/net/minecraft/world/entity/monster/Illusioner.java b/net/minecraft/world/entity/monster/Illusioner.java
-index 1d1cf8748e3fba2e2963ad2fa153fbfe990f5087..ad661f2bf8957644605b52a469d6a7cf8e064398 100644
---- a/net/minecraft/world/entity/monster/Illusioner.java
-+++ b/net/minecraft/world/entity/monster/Illusioner.java
-@@ -84,6 +84,13 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.illusionerTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/MagmaCube.java b/net/minecraft/world/entity/monster/MagmaCube.java
-index 2c6b0fd46d9ed6a8d1ca7e90ebf596dd3f310f0e..bf26f5f6017c60d5991d5f6c87da2acbd95ef5bb 100644
+index e0fda9a975e00c49ba09db65d7b3fba8fa434757..1bf9d04e5e44272b02753290995795f194cbdae1 100644
--- a/net/minecraft/world/entity/monster/MagmaCube.java
+++ b/net/minecraft/world/entity/monster/MagmaCube.java
@@ -68,6 +68,13 @@ public class MagmaCube extends Slime {
@@ -915,10 +863,10 @@ index 2c6b0fd46d9ed6a8d1ca7e90ebf596dd3f310f0e..bf26f5f6017c60d5991d5f6c87da2acb
return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F);
}
diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
-index 4cc1c8d8967b1e9ee5b0b1c50d887f3de3e8a882..32b7c34d3c68dcfa936b628b2d038524204129a3 100644
+index 6e8fe1b694ade45ffbf0b9bb39b954deffeb2402..2fa22088ac507eceb36f3c77f24a733076641d8f 100644
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
-@@ -139,6 +139,13 @@ public class Phantom extends FlyingMob implements Enemy {
+@@ -128,6 +128,13 @@ public class Phantom extends Mob implements Enemy {
}
// Purpur end - Phantoms attracted to crystals and crystals shoot phantoms
@@ -932,29 +880,11 @@ index 4cc1c8d8967b1e9ee5b0b1c50d887f3de3e8a882..32b7c34d3c68dcfa936b628b2d038524
@Override
public boolean isFlapping() {
return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0;
-diff --git a/net/minecraft/world/entity/monster/Pillager.java b/net/minecraft/world/entity/monster/Pillager.java
-index 9586aa3f3eb61fb0c1224df9d0104da69d7fa6bb..869a1007de13f3f5d757968d0f84cbf43786c870 100644
---- a/net/minecraft/world/entity/monster/Pillager.java
-+++ b/net/minecraft/world/entity/monster/Pillager.java
-@@ -88,6 +88,13 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.pillagerTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java
-index 3449628fb87fd760abd730d84699c3a09c6ec761..3d9eae0403875a99c25ccb47888dc591f051e744 100644
+index 7c69423eee05992b9c70321d528cc9d73b3e63ea..ad2913b02ded9b5087c69ba279cebfd81d9ef75e 100644
--- a/net/minecraft/world/entity/monster/Ravager.java
+++ b/net/minecraft/world/entity/monster/Ravager.java
-@@ -97,6 +97,13 @@ public class Ravager extends Raider {
+@@ -103,6 +103,13 @@ public class Ravager extends Raider {
}
// Purpur end - Configurable entity base attributes
@@ -969,10 +899,10 @@ index 3449628fb87fd760abd730d84699c3a09c6ec761..3d9eae0403875a99c25ccb47888dc591
protected void registerGoals() {
super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Shulker.java b/net/minecraft/world/entity/monster/Shulker.java
-index 03db684c122a07176aa1365550da935cdb66a1b9..c26e4858a14571d58e439cabd5f2593da4ee2634 100644
+index 30f2503ebd045b05f5594cef28389a694338d13a..0a5a6f23cd8e4317db4e7c0ba8883e99f3aff148 100644
--- a/net/minecraft/world/entity/monster/Shulker.java
+++ b/net/minecraft/world/entity/monster/Shulker.java
-@@ -129,6 +129,13 @@ public class Shulker extends AbstractGolem implements VariantHolder entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
- ) {
diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java
-index f36e94437b4e21961532ac9ab91767617f9c3c32..d01bc46d77340b10b23d0c0d50bddc37657028c8 100644
+index ad6515c2dcde0079095c6777f56319e9901850f8..758887f3fcec2bf0946cddb184e19a1c9b64eee3 100644
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
-@@ -88,7 +88,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
- public Strider(EntityType extends Strider> entityType, Level level) {
- super(entityType, level);
+@@ -86,7 +86,7 @@ public class Strider extends Animal implements ItemSteerable {
+ public Strider(EntityType extends Strider> type, Level level) {
+ super(type, level);
this.blocksBuilding = true;
- this.setPathfindingMalus(PathType.WATER, -1.0F);
+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - Toggle for water sensitive mob damage
this.setPathfindingMalus(PathType.LAVA, 0.0F);
this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F);
this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F);
-@@ -403,7 +403,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
+@@ -388,7 +388,7 @@ public class Strider extends Animal implements ItemSteerable {
@Override
public boolean isSensitiveToWater() {
@@ -1099,7 +975,7 @@ index f36e94437b4e21961532ac9ab91767617f9c3c32..d01bc46d77340b10b23d0c0d50bddc37
@Override
diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java
-index 8356906b2c0707e21021bb05f9ca01a95682880a..ffdb200d9716104f8df91dbeef590b2264e587b8 100644
+index 32759864a8ff0c4e28ce80ae8906cbcf1927094e..6ead673c44891c6b1c1688f80bf299527d7bc777 100644
--- a/net/minecraft/world/entity/monster/Vex.java
+++ b/net/minecraft/world/entity/monster/Vex.java
@@ -110,6 +110,13 @@ public class Vex extends Monster implements TraceableEntity {
@@ -1116,29 +992,11 @@ index 8356906b2c0707e21021bb05f9ca01a95682880a..ffdb200d9716104f8df91dbeef590b22
@Override
public boolean isFlapping() {
return this.tickCount % TICKS_PER_FLAP == 0;
-diff --git a/net/minecraft/world/entity/monster/Vindicator.java b/net/minecraft/world/entity/monster/Vindicator.java
-index 0fc1b458101ba9d98d25c9637337caf0949bb893..5f68d73460adfac2ead57d168156a2784af979ae 100644
---- a/net/minecraft/world/entity/monster/Vindicator.java
-+++ b/net/minecraft/world/entity/monster/Vindicator.java
-@@ -80,6 +80,13 @@ public class Vindicator extends AbstractIllager {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.vindicatorTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java
-index ff8380246f6c6c805b222a91ac6a1eb0d130558d..96ba35f3530ab405a960c79955699666deb6b845 100644
+index 3c3c258d4cc7cf7376d0d3ad0794ec3611ab81ce..86d9952ed0f692e8f229b0c0bcb6cacf53a00c8b 100644
--- a/net/minecraft/world/entity/monster/Witch.java
+++ b/net/minecraft/world/entity/monster/Witch.java
-@@ -81,6 +81,13 @@ public class Witch extends Raider implements RangedAttackMob {
+@@ -82,6 +82,13 @@ public class Witch extends Raider implements RangedAttackMob {
}
// Purpur end - Configurable entity base attributes
@@ -1152,29 +1010,11 @@ index ff8380246f6c6c805b222a91ac6a1eb0d130558d..96ba35f3530ab405a960c79955699666
@Override
protected void registerGoals() {
super.registerGoals();
-diff --git a/net/minecraft/world/entity/monster/WitherSkeleton.java b/net/minecraft/world/entity/monster/WitherSkeleton.java
-index 3342f2d92830049837636ff10b5e52f0d85fbd2c..a4dc9b7fbde19b08eb389dc42df21aa5df94e703 100644
---- a/net/minecraft/world/entity/monster/WitherSkeleton.java
-+++ b/net/minecraft/world/entity/monster/WitherSkeleton.java
-@@ -59,6 +59,13 @@ public class WitherSkeleton extends AbstractSkeleton {
- }
- // Purpur end - Configurable entity base attributes
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.witherSkeletonTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void registerGoals() {
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true));
diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java
-index 132b38d717ac3c5acc64a5ec519f345ac57021d8..79a4a3f4e10e1f9c1a6100060a95636075fc8236 100644
+index e0192a13b8d7131024471569bf34329ba0f28287..e2708eb836d60588c1bedb75c520e5007185034a 100644
--- a/net/minecraft/world/entity/monster/Zoglin.java
+++ b/net/minecraft/world/entity/monster/Zoglin.java
-@@ -110,6 +110,13 @@ public class Zoglin extends Monster implements HoglinBase {
+@@ -112,6 +112,13 @@ public class Zoglin extends Monster implements HoglinBase {
}
// Purpur end - Configurable entity base attributes
@@ -1188,62 +1028,8 @@ index 132b38d717ac3c5acc64a5ec519f345ac57021d8..79a4a3f4e10e1f9c1a6100060a956360
@Override
protected Brain.Provider brainProvider() {
return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
-index 63446c874e7153dcfb99133145c8b5311d7d86cd..bb8c37c8348172947efe14d48ed9ae203409affa 100644
---- a/net/minecraft/world/entity/monster/Zombie.java
-+++ b/net/minecraft/world/entity/monster/Zombie.java
-@@ -139,6 +139,13 @@ public class Zombie extends Monster {
- }
- // Purpur end - Configurable jockey options
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.zombieTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java
-index f1e9bf75c50f353bd377051be82a391f97d952fd..94b9abc765b78a40a7ecbf4cbd775b778d49c815 100644
---- a/net/minecraft/world/entity/monster/ZombieVillager.java
-+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
-@@ -124,6 +124,13 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
- }
- // Purpur end - Configurable jockey options
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.zombieVillagerTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-index 9603589e0501feee900cd21b04eb84b02bb45de2..09c991d8e344f11bc84dea453042ee35c39e580e 100644
---- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-+++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-@@ -105,6 +105,13 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
- }
- // Purpur end - Configurable jockey options
-
-+ // Purpur start - Toggle for water sensitive mob damage
-+ @Override
-+ public boolean isSensitiveToWater() {
-+ return this.level().purpurConfig.zombifiedPiglinTakeDamageFromWater;
-+ }
-+ // Purpur end - Toggle for water sensitive mob damage
-+
- @Override
- public void setPersistentAngerTarget(@Nullable UUID target) {
- this.persistentAngerTarget = target;
diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
-index 266d1838e6602ef6322c15732f2693a865911f2e..896bd531a5333d6dc8996bbdfc5c878b1a7d2da0 100644
+index 4498fe26dff2cdec8e90d6559a66ebe7859195bb..5e3f7005a7167c786038823a8437ad2e90a41d2c 100644
--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
@@ -129,6 +129,13 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
@@ -1256,15 +1042,87 @@ index 266d1838e6602ef6322c15732f2693a865911f2e..896bd531a5333d6dc8996bbdfc5c878b
+ return this.level().purpurConfig.hoglinTakeDamageFromWater;
+ }
+ // Purpur end - Toggle for water sensitive mob damage
++
+ @VisibleForTesting
+ public void setTimeInOverworld(int timeInOverworld) {
+ this.timeInOverworld = timeInOverworld;
+diff --git a/net/minecraft/world/entity/monster/illager/Evoker.java b/net/minecraft/world/entity/monster/illager/Evoker.java
+index 334786b2c358c41058f2ac4b1fa4b185833cbd84..c4f45f6303a46ad54991c9013608a4e5ba8b9fee 100644
+--- a/net/minecraft/world/entity/monster/illager/Evoker.java
++++ b/net/minecraft/world/entity/monster/illager/Evoker.java
+@@ -74,6 +74,13 @@ public class Evoker extends SpellcasterIllager {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.evokerTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
+
@Override
- public boolean canBeLeashed() {
- return true;
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/illager/Illusioner.java b/net/minecraft/world/entity/monster/illager/Illusioner.java
+index 8fa53cccb73b2d8c599c898f298681735007d2a0..32278f51f4973d1294e52f0775697e9f5b295ee0 100644
+--- a/net/minecraft/world/entity/monster/illager/Illusioner.java
++++ b/net/minecraft/world/entity/monster/illager/Illusioner.java
+@@ -86,6 +86,13 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.illusionerTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/illager/Pillager.java b/net/minecraft/world/entity/monster/illager/Pillager.java
+index 1e43c69366287c7a191a6f8e3a7d5459743f07a2..6190286ab2f454382d497b4fce47632e6f771215 100644
+--- a/net/minecraft/world/entity/monster/illager/Pillager.java
++++ b/net/minecraft/world/entity/monster/illager/Pillager.java
+@@ -90,6 +90,13 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.pillagerTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/illager/Vindicator.java b/net/minecraft/world/entity/monster/illager/Vindicator.java
+index 5f3857186e86e27fe237c62cec4af13ebf58debe..86b463a16e8630af4918ea43a2546995aa00244f 100644
+--- a/net/minecraft/world/entity/monster/illager/Vindicator.java
++++ b/net/minecraft/world/entity/monster/illager/Vindicator.java
+@@ -82,6 +82,13 @@ public class Vindicator extends AbstractIllager {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.vindicatorTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java
-index d923a424e2b33b7d4e9e4ecdce8e0a8c825038de..55ebfa5df06a59203248514d10dced9660ebf215 100644
+index 4fccd122a227e5fe80965c37afaa031c4a673978..d6c834914ddea76280466bf0f7d001a76af34f08 100644
--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
-@@ -176,6 +176,13 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
+@@ -166,6 +166,13 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
}
// Purpur end - Configurable entity base attributes
@@ -1276,10 +1134,10 @@ index d923a424e2b33b7d4e9e4ecdce8e0a8c825038de..55ebfa5df06a59203248514d10dced96
+ // Purpur end - Toggle for water sensitive mob damage
+
@Override
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
-index eb82252cd87797927e153974b9280b5eaa251080..2237681f298113bda0556699e19e880f4b04a853 100644
+index 3d34bef7ffe9e66e77e3fc10b2c5869d98a4a5c9..4bf2038fea712e65f420ade915a18470b79318fc 100644
--- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
+++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
@@ -90,6 +90,13 @@ public class PiglinBrute extends AbstractPiglin {
@@ -1296,11 +1154,191 @@ index eb82252cd87797927e153974b9280b5eaa251080..2237681f298113bda0556699e19e880f
public static AttributeSupplier.Builder createAttributes() {
return Monster.createMonsterAttributes()
.add(Attributes.MAX_HEALTH, 50.0)
-diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
-index 017b54e0b8dec8996c90a3c6651867277dd516df..97e5bb0cc335b23211e78044919282bfabad26a5 100644
---- a/net/minecraft/world/entity/npc/Villager.java
-+++ b/net/minecraft/world/entity/npc/Villager.java
-@@ -278,6 +278,13 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+diff --git a/net/minecraft/world/entity/monster/skeleton/Skeleton.java b/net/minecraft/world/entity/monster/skeleton/Skeleton.java
+index 96d989cffc6ff72954ed92e2535c72992d489372..30d79be765118a50e2e2c5bfde6bf6bbc957cf40 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Skeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/Skeleton.java
+@@ -50,6 +50,13 @@ public class Skeleton extends AbstractSkeleton {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.skeletonTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/monster/skeleton/Stray.java b/net/minecraft/world/entity/monster/skeleton/Stray.java
+index 575f30cc9a6166a4e0733cc33e8b5814acb92660..ec19c49d195daff5839c991cce63b1ffc15a7e0b 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Stray.java
++++ b/net/minecraft/world/entity/monster/skeleton/Stray.java
+@@ -47,6 +47,13 @@ public class Stray extends AbstractSkeleton {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.strayTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ public static boolean checkStraySpawnRules(
+ EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
+diff --git a/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java b/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
+index f38bb54c0f5d7797179e5e75eb8092baea7b9dcb..3e8cc658b333f1259784e1426896ac8b8c1537fa 100644
+--- a/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
+@@ -59,6 +59,13 @@ public class WitherSkeleton extends AbstractSkeleton {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.witherSkeletonTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void registerGoals() {
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true));
+diff --git a/net/minecraft/world/entity/monster/spider/CaveSpider.java b/net/minecraft/world/entity/monster/spider/CaveSpider.java
+index a1391173cc4997df723c59f176726dde88491978..fad3e951e443f04f5bf0423cde42c0ae299a4236 100644
+--- a/net/minecraft/world/entity/monster/spider/CaveSpider.java
++++ b/net/minecraft/world/entity/monster/spider/CaveSpider.java
+@@ -51,6 +51,13 @@ public class CaveSpider extends Spider {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.caveSpiderTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ public boolean doHurtTarget(ServerLevel level, Entity target) {
+ if (super.doHurtTarget(level, target)) {
+diff --git a/net/minecraft/world/entity/monster/spider/Spider.java b/net/minecraft/world/entity/monster/spider/Spider.java
+index 6a9c807ed50dab4b65787d9f7269385103fa5f26..81c500de41b11d4aa6c52dc290f132ad2c23f009 100644
+--- a/net/minecraft/world/entity/monster/spider/Spider.java
++++ b/net/minecraft/world/entity/monster/spider/Spider.java
+@@ -77,6 +77,13 @@ public class Spider extends Monster {
+ }
+ // Purpur end - Configurable entity base attributes
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.spiderTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/monster/zombie/Drowned.java b/net/minecraft/world/entity/monster/zombie/Drowned.java
+index 327086c972423e4f73402ea2e64519a355fa7b5a..ec36b854dccae7cef905aeb2fcd4ec177828139c 100644
+--- a/net/minecraft/world/entity/monster/zombie/Drowned.java
++++ b/net/minecraft/world/entity/monster/zombie/Drowned.java
+@@ -126,6 +126,13 @@ public class Drowned extends Zombie implements RangedAttackMob {
+ }
+ // Purpur end - Configurable jockey options
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.drownedTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void addBehaviourGoals() {
+ this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0));
+diff --git a/net/minecraft/world/entity/monster/zombie/Husk.java b/net/minecraft/world/entity/monster/zombie/Husk.java
+index d31145fee0f646d734e90199288b29f07854d066..928e2c95146bc3fc9b8c41c5b6c3970fc919bb15 100644
+--- a/net/minecraft/world/entity/monster/zombie/Husk.java
++++ b/net/minecraft/world/entity/monster/zombie/Husk.java
+@@ -75,6 +75,13 @@ public class Husk extends Zombie {
+ }
+ // Purpur end - Configurable jockey options
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.huskTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ public boolean isSunSensitive() {
+ return false;
+diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
+index 638642628c3dc9fa25d25c589029219c23d1e602..dfdf9ee98a25ec1f7a1f41326c98155131494d93 100644
+--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
++++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
+@@ -142,6 +142,13 @@ public class Zombie extends Monster {
+ }
+ // Purpur end - Configurable jockey options
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.zombieTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+index 62f55763d95e496da8b8fcf7d95752777e323b48..3da4f757d879f8b855c5d36688f1f5dd50fc88a0 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+@@ -131,6 +131,13 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
+ }
+ // Purpur end - Configurable jockey options
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.zombieVillagerTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+index ec39ad6740361774f9ecfda7186cab9d8fac90f2..9a1da88752b0dd708365dd41a074cc0e90f36e1c 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+@@ -106,6 +106,13 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
+ }
+ // Purpur end - Configurable jockey options
+
++ // Purpur start - Toggle for water sensitive mob damage
++ @Override
++ public boolean isSensitiveToWater() {
++ return this.level().purpurConfig.zombifiedPiglinTakeDamageFromWater;
++ }
++ // Purpur end - Toggle for water sensitive mob damage
++
+ @Override
+ protected void addBehaviourGoals() {
+ this.goalSelector.addGoal(1, new SpearUseGoal<>(this, 1.0, 1.0, 10.0F, 2.0F));
+diff --git a/net/minecraft/world/entity/npc/villager/Villager.java b/net/minecraft/world/entity/npc/villager/Villager.java
+index ed6642023fccbc8f825d7c5c206d73ffd666f0f9..b6bfe06a2ad8e4219d99de050b30ce1ad15b8b34 100644
+--- a/net/minecraft/world/entity/npc/villager/Villager.java
++++ b/net/minecraft/world/entity/npc/villager/Villager.java
+@@ -282,6 +282,13 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
// Purpur end - Configurable entity base attributes
@@ -1314,11 +1352,11 @@ index 017b54e0b8dec8996c90a3c6651867277dd516df..97e5bb0cc335b23211e78044919282bf
@Override
public Brain getBrain() {
return (Brain)super.getBrain();
-diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java
-index 4ba2921dd99f674344fe3371332c9b23365d3aa2..8046a2d640e7c4d59cb5b9c6dff3bf5f026c7153 100644
---- a/net/minecraft/world/entity/npc/WanderingTrader.java
-+++ b/net/minecraft/world/entity/npc/WanderingTrader.java
-@@ -107,6 +107,13 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
+diff --git a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+index c6c4f4f2a970db7e782181eaca312931b192b0d5..cabebbc25788a8c41912f97dac85af41c9433b68 100644
+--- a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
++++ b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+@@ -99,6 +99,13 @@ public class WanderingTrader extends AbstractVillager implements Consumable.Over
}
// Purpur end - Villagers follow emerald blocks
diff --git a/purpur-server/minecraft-patches/features/0017-API-for-any-mob-to-burn-daylight.patch b/purpur-server/minecraft-patches/features/0017-API-for-any-mob-to-burn-daylight.patch
new file mode 100644
index 000000000..c6d1063e0
--- /dev/null
+++ b/purpur-server/minecraft-patches/features/0017-API-for-any-mob-to-burn-daylight.patch
@@ -0,0 +1,279 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ben Kerllenevich
+Date: Tue, 25 May 2021 16:31:09 -0400
+Subject: [PATCH] API for any mob to burn daylight
+
+Co-authored by: Encode42
+
+diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
+index 468df93a0302f200c2bd5e9bc65feccdd8649bf3..663cd67250c516fa8e16fa55dd91c02131507fd0 100644
+--- a/net/minecraft/world/entity/Entity.java
++++ b/net/minecraft/world/entity/Entity.java
+@@ -544,6 +544,24 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
+ }
+ // Purpur end - Add canSaveToDisk to Entity
+
++ // Purpur start - copied from Mob - API for any mob to burn daylight
++ public boolean isSunBurnTick() {
++ if (!this.level().isClientSide() && this.level().environmentAttributes().getValue(EnvironmentAttributes.MONSTERS_BURN, this.position())) {
++ float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue();
++ BlockPos blockPos = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ());
++ boolean flag = this.isInWater() || this.isInPowderSnow || this.wasInPowderSnow;
++ if (lightLevelDependentMagicValue > 0.5F
++ && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F
++ && !flag
++ && this.level().canSeeSky(blockPos)) {
++ return true;
++ }
++ }
++
++ return false;
++ }
++ // Purpur end - copied from Mob - API for any mob to burn daylight
++
+ public Entity(EntityType> type, Level level) {
+ this.type = type;
+ this.level = level;
+diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
+index f991e7a6988e98ec64b6af3c6c56522b19d929d2..78e68335805270ff1f942fe28e0e833adb41fd85 100644
+--- a/net/minecraft/world/entity/LivingEntity.java
++++ b/net/minecraft/world/entity/LivingEntity.java
+@@ -290,6 +290,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event
+ public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API
+ public int invulnerableDuration = LivingEntity.INVULNERABLE_DURATION; // Paper - configurable invulnerable duration
++ protected boolean shouldBurnInDay = false; public boolean shouldBurnInDay() { return this.shouldBurnInDay; } public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } // Purpur - API for any mob to burn daylight
+ // CraftBukkit end
+
+ protected LivingEntity(EntityType extends LivingEntity> type, Level level) {
+@@ -793,6 +794,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ this.getSleepingPos().ifPresent(blockPos -> output.store("sleeping_pos", BlockPos.CODEC, blockPos));
+ DataResult> dataResult = this.brain.serializeStart(NbtOps.INSTANCE).map(tag -> new Dynamic<>(NbtOps.INSTANCE, tag));
+ dataResult.resultOrPartial(LOGGER::error).ifPresent(dynamic -> output.store("Brain", Codec.PASSTHROUGH, (Dynamic>)dynamic));
++ output.putBoolean("Purpur.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - API for any mob to burn daylight
+ if (this.lastHurtByPlayer != null) {
+ this.lastHurtByPlayer.store(output, "last_hurt_by_player");
+ output.putInt("last_hurt_by_player_memory_time", this.lastHurtByPlayerMemoryTime);
+@@ -917,6 +919,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ } // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong
+ }, this::clearSleepingPos);
+ input.read("Brain", Codec.PASSTHROUGH).ifPresent(dynamic -> this.brain = this.makeBrain((Dynamic>)dynamic));
++ this.shouldBurnInDay = input.getBooleanOr("Purpur.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - API for any mob to burn daylight
+ this.lastHurtByPlayer = EntityReference.read(input, "last_hurt_by_player");
+ this.lastHurtByPlayerMemoryTime = input.getIntOr("last_hurt_by_player_memory_time", 0);
+ this.lastHurtByMob = EntityReference.read(input, "last_hurt_by_mob");
+@@ -3850,6 +3853,37 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
+ if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterOrRain()) {
+ this.hurtServer(serverLevel, this.damageSources().drown(), 1.0F);
+ }
++
++ // Purpur start - copied from Mob - API for any mob to burn daylight
++ if (this.getType().is(EntityTypeTags.BURN_IN_DAYLIGHT) && this.isAlive()) {
++ boolean flag = this.shouldBurnInDay() && this.isSunBurnTick(); // Paper - shouldBurnInDay API // Purpur - use shouldBurnInDay() method to handle Phantoms properly - API for any mob to burn daylight
++ if (flag) {
++ EquipmentSlot equipmentSlot = this.sunProtectionSlot();
++ ItemStack itemBySlot = this.getItemBySlot(equipmentSlot);
++ if (!itemBySlot.isEmpty()) {
++ if (itemBySlot.isDamageableItem()) {
++ Item item = itemBySlot.getItem();
++ itemBySlot.setDamageValue(itemBySlot.getDamageValue() + this.random.nextInt(2));
++ if (itemBySlot.getDamageValue() >= itemBySlot.getMaxDamage()) {
++ this.onEquippedItemBroken(item, equipmentSlot);
++ this.setItemSlot(equipmentSlot, ItemStack.EMPTY);
++ }
++ }
++
++ flag = false;
++ }
++
++ if (flag) {
++ if (getRider() == null || !this.isControllable()) // Purpur - ignore mobs which are uncontrollable or without rider - API for any mob to burn daylight
++ this.igniteForSeconds(8.0F);
++ }
++ }
++ }
++ }
++
++ protected EquipmentSlot sunProtectionSlot() {
++ return net.minecraft.world.entity.EquipmentSlot.HEAD;
++ // Purpur end - copied from Mob - API for any mob to burn daylight
+ }
+
+ protected void applyInput() {
+diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
+index c94a1bd594bcd3b2f7525f1541d2e55897954623..327982be3748e82a36c7a24ede989dacebfb04db 100644
+--- a/net/minecraft/world/entity/Mob.java
++++ b/net/minecraft/world/entity/Mob.java
+@@ -544,9 +544,9 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
+ @Override
+ public void aiStep() {
+ super.aiStep();
+- if (this.getType().is(EntityTypeTags.BURN_IN_DAYLIGHT)) {
++ /*if (this.getType().is(EntityTypeTags.BURN_IN_DAYLIGHT)) { // Purpur start - implemented in LivingEntity - API for any mob to burn daylight
+ this.burnUndead();
+- }
++ }*/ // Purpur end - implemented in LivingEntity - API for any mob to burn daylight
+
+ ProfilerFiller profilerFiller = Profiler.get();
+ profilerFiller.push("looting");
+@@ -601,19 +601,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
+ }
+
+ public boolean isSunBurnTick() {
+- if (!this.level().isClientSide() && this.level().environmentAttributes().getValue(EnvironmentAttributes.MONSTERS_BURN, this.position())) {
+- float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue();
+- BlockPos blockPos = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ());
+- boolean flag = this.isInWaterOrRain() || this.isInPowderSnow || this.wasInPowderSnow;
+- if (lightLevelDependentMagicValue > 0.5F
+- && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F
+- && !flag
+- && this.level().canSeeSky(blockPos)) {
+- return true;
+- }
+- }
+-
+- return false;
++ // Purpur - implemented in Entity - API for any mob to burn daylight
++ return super.isSunBurnTick();
+ }
+
+ protected Vec3i getPickupReach() {
+diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
+index 2fa22088ac507eceb36f3c77f24a733076641d8f..ff944ad57d4e9e4a910cd63282e5e7594626365e 100644
+--- a/net/minecraft/world/entity/monster/Phantom.java
++++ b/net/minecraft/world/entity/monster/Phantom.java
+@@ -52,7 +52,7 @@ public class Phantom extends Mob implements Enemy {
+ Vec3 crystalPosition; // Purpur - Phantoms attracted to crystals and crystals shoot phantoms
+ // Paper start
+ public java.util.@Nullable UUID spawningEntity;
+- public boolean shouldBurnInDay = true;
++ //public boolean shouldBurnInDay = true; // Purpur - API for any mob to burn daylight
+ // Paper end
+ private static final net.minecraft.world.item.crafting.Ingredient TORCH = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.item.Items.TORCH, net.minecraft.world.item.Items.SOUL_TORCH); // Purpur - Phantoms burn in light
+
+@@ -61,6 +61,7 @@ public class Phantom extends Mob implements Enemy {
+ this.xpReward = 5;
+ this.moveControl = new Phantom.PhantomMoveControl(this);
+ this.lookControl = new Phantom.PhantomLookControl(this);
++ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight
+ }
+
+ // Purpur start - Ridables
+@@ -297,7 +298,7 @@ public class Phantom extends Mob implements Enemy {
+ this.setPhantomSize(input.getIntOr("size", 0));
+ // Paper start
+ this.spawningEntity = input.read("Paper.SpawningEntity", net.minecraft.core.UUIDUtil.CODEC).orElse(null);
+- this.shouldBurnInDay = input.getBooleanOr("Paper.ShouldBurnInDay", true);
++ //this.shouldBurnInDay = input.getBooleanOr("Paper.ShouldBurnInDay", true); // Purpur - implemented in LivingEntity - API for any mob to burn daylight
+ // Paper end
+ }
+
+@@ -308,7 +309,7 @@ public class Phantom extends Mob implements Enemy {
+ output.putInt("size", this.getPhantomSize());
+ // Paper start
+ output.storeNullable("Paper.SpawningEntity", net.minecraft.core.UUIDUtil.CODEC, this.spawningEntity);
+- output.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay);
++ //output.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - implemented in LivingEntity - API for any mob to burn daylight
+ // Paper end
+ }
+
+diff --git a/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java b/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java
+index 1ab860be69bcc1ab5cc07418c2d7e733afdc482b..60afd81d3bf671889fbff5d4a3fabb38a8e2d461 100644
+--- a/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java
+@@ -66,11 +66,12 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
+ AbstractSkeleton.this.setAggressive(true);
+ }
+ };
+- private boolean shouldBurnInDay = true; // Paper - shouldBurnInDay API
++ //private boolean shouldBurnInDay = true; // Paper - shouldBurnInDay API // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight
+
+ protected AbstractSkeleton(EntityType extends AbstractSkeleton> type, Level level) {
+ super(type, level);
+ this.reassessWeaponGoal();
++ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight
+ }
+
+ @Override
+@@ -223,14 +224,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
+ protected void readAdditionalSaveData(ValueInput input) {
+ super.readAdditionalSaveData(input);
+ this.reassessWeaponGoal();
+- this.shouldBurnInDay = input.getBooleanOr("Paper.ShouldBurnInDay", true); // Paper - shouldBurnInDay API
++ //this.shouldBurnInDay = input.getBooleanOr("Paper.ShouldBurnInDay", true); // Paper - shouldBurnInDay API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
+ }
+
+ // Paper start - shouldBurnInDay API
+ @Override
+ protected void addAdditionalSaveData(final net.minecraft.world.level.storage.ValueOutput output) {
+ super.addAdditionalSaveData(output);
+- output.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay);
++ //output.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - implemented in LivingEntity - API for any mob to burn daylight
+ }
+ // Paper end - shouldBurnInDay API
+
+diff --git a/net/minecraft/world/entity/monster/zombie/Husk.java b/net/minecraft/world/entity/monster/zombie/Husk.java
+index 928e2c95146bc3fc9b8c41c5b6c3970fc919bb15..31b91dbc3f3e1875fbe6750bb815514686d14f7f 100644
+--- a/net/minecraft/world/entity/monster/zombie/Husk.java
++++ b/net/minecraft/world/entity/monster/zombie/Husk.java
+@@ -27,6 +27,7 @@ import org.jspecify.annotations.Nullable;
+ public class Husk extends Zombie {
+ public Husk(EntityType extends Husk> type, Level level) {
+ super(type, level);
++ this.setShouldBurnInDay(false); // Purpur - API for any mob to burn daylight
+ }
+
+ // Purpur start - Ridables
+@@ -84,7 +85,7 @@ public class Husk extends Zombie {
+
+ @Override
+ public boolean isSunSensitive() {
+- return false;
++ return this.shouldBurnInDay; // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight
+ }
+
+ @Override
+diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
+index dfdf9ee98a25ec1f7a1f41326c98155131494d93..d32a831ba76f65c4719c2672ffaec81a861cc7e6 100644
+--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
++++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
+@@ -92,11 +92,12 @@ public class Zombie extends Monster {
+ private boolean canBreakDoors = false;
+ private int inWaterTime = 0;
+ public int conversionTime;
+- private boolean shouldBurnInDay = true; // Paper - Add more Zombie API
++ //private boolean shouldBurnInDay = true; // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
+
+ public Zombie(EntityType extends Zombie> type, Level level) {
+ super(type, level);
+ this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(level.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(type, level.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty
++ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight
+ }
+
+ public Zombie(Level level) {
+@@ -347,6 +348,7 @@ public class Zombie extends Monster {
+ // CraftBukkit end
+ }
+
++ public boolean shouldBurnInDay() { return this.isSunSensitive(); } // Purpur - for ABI compatibility - API for any mob to burn daylight
+ public boolean isSunSensitive() {
+ return this.shouldBurnInDay; // Paper - Add more Zombie API
+ }
+@@ -486,7 +488,7 @@ public class Zombie extends Monster {
+ output.putBoolean("CanBreakDoors", this.canBreakDoors());
+ output.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1);
+ output.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1);
+- output.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API
++ //output.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
+ }
+
+ @Override
+@@ -501,7 +503,7 @@ public class Zombie extends Monster {
+ } else {
+ this.getEntityData().set(DATA_DROWNED_CONVERSION_ID, false);
+ }
+- this.shouldBurnInDay = input.getBooleanOr("Paper.ShouldBurnInDay", true); // Paper - Add more Zombie API
++ //this.shouldBurnInDay = input.getBooleanOr("Paper.ShouldBurnInDay", true); // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
+ }
+
+ @Override
diff --git a/purpur-server/minecraft-patches/features/0017-Add-EntityTeleportHinderedEvent.patch b/purpur-server/minecraft-patches/features/0017-Add-EntityTeleportHinderedEvent.patch
deleted file mode 100644
index 3947801b1..000000000
--- a/purpur-server/minecraft-patches/features/0017-Add-EntityTeleportHinderedEvent.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Mariell Hoversholm
-Date: Sat, 9 Jan 2021 15:26:04 +0100
-Subject: [PATCH] Add EntityTeleportHinderedEvent
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-diff --git a/net/minecraft/world/level/block/EndGatewayBlock.java b/net/minecraft/world/level/block/EndGatewayBlock.java
-index 84a1bd5e40e635962d795506861447851e443eee..54abeb142e119edd1c1d1c263821b95b1f05c388 100644
---- a/net/minecraft/world/level/block/EndGatewayBlock.java
-+++ b/net/minecraft/world/level/block/EndGatewayBlock.java
-@@ -98,6 +98,13 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal {
- org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(level.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.END_GATEWAY); // Paper - add portal type
- if (!event.callEvent()) return;
- // Paper end - call EntityPortalEnterEvent
-+ // Purpur start - Add EntityTeleportHinderedEvent
-+ if (level.purpurConfig.imposeTeleportRestrictionsOnGateways && (entity.isVehicle() || entity.isPassenger())) {
-+ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY).callEvent()) {
-+ return;
-+ }
-+ }
-+ // Purpur end - Add EntityTeleportHinderedEvent
- entity.setAsInsidePortal(this, pos);
- TheEndGatewayBlockEntity.triggerCooldown(level, pos, state, theEndGatewayBlockEntity);
- }
-diff --git a/net/minecraft/world/level/block/EndPortalBlock.java b/net/minecraft/world/level/block/EndPortalBlock.java
-index 01cddd7001b4a7f99c1b1d147fac904d3064d733..7e60bcadd2d343e00fc554dba0b85c9191f7efb6 100644
---- a/net/minecraft/world/level/block/EndPortalBlock.java
-+++ b/net/minecraft/world/level/block/EndPortalBlock.java
-@@ -58,6 +58,13 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal {
- protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
- if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
- if (entity.canUsePortal(false)) {
-+ // Purpur start - Add EntityTeleportHinderedEvent
-+ if (level.purpurConfig.imposeTeleportRestrictionsOnEndPortals && (entity.isVehicle() || entity.isPassenger())) {
-+ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL).callEvent()) {
-+ return;
-+ }
-+ }
-+ // Purpur end - Add EntityTeleportHinderedEvent
- // CraftBukkit start - Entity in portal
- org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(level.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.ENDER); // Paper - add portal type
- level.getCraftServer().getPluginManager().callEvent(event);
-diff --git a/net/minecraft/world/level/block/NetherPortalBlock.java b/net/minecraft/world/level/block/NetherPortalBlock.java
-index 006444811c00a8820bddaf75950e794271efdd82..eb659209008209c0930770e5f9671a3d7a4abae6 100644
---- a/net/minecraft/world/level/block/NetherPortalBlock.java
-+++ b/net/minecraft/world/level/block/NetherPortalBlock.java
-@@ -117,6 +117,13 @@ public class NetherPortalBlock extends Block implements Portal {
- protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
- if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
- if (entity.canUsePortal(false)) {
-+ // Purpur start - Add EntityTeleportHinderedEvent
-+ if (level.purpurConfig.imposeTeleportRestrictionsOnNetherPortals && (entity.isVehicle() || entity.isPassenger())) {
-+ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.NETHER_PORTAL).callEvent()) {
-+ return;
-+ }
-+ }
-+ // Purpur end - Add EntityTeleportHinderedEvent
- // CraftBukkit start - Entity in portal
- org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(level.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.NETHER); // Paper - add portal type
- level.getCraftServer().getPluginManager().callEvent(event);
diff --git a/purpur-server/minecraft-patches/features/0018-Cows-naturally-aggressive-to-players-chance.patch b/purpur-server/minecraft-patches/features/0018-Cows-naturally-aggressive-to-players-chance.patch
new file mode 100644
index 000000000..afa3b58ca
--- /dev/null
+++ b/purpur-server/minecraft-patches/features/0018-Cows-naturally-aggressive-to-players-chance.patch
@@ -0,0 +1,79 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath
+Date: Mon, 30 Aug 2021 22:49:53 -0500
+Subject: [PATCH] Cows naturally aggressive to players chance
+
+
+diff --git a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
+index ccdd439a89b7e7e10ee960cfe1e5e119d5367799..49292ae53f2b4554064daa4953a8cec00aa1fa98 100644
+--- a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
++++ b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java
+@@ -135,7 +135,7 @@ public class DefaultAttributes {
+ .put(EntityType.LLAMA, Llama.createAttributes().build())
+ .put(EntityType.MAGMA_CUBE, MagmaCube.createAttributes().build())
+ .put(EntityType.MANNEQUIN, LivingEntity.createLivingAttributes().build())
+- .put(EntityType.MOOSHROOM, Cow.createAttributes().build())
++ .put(EntityType.MOOSHROOM, net.minecraft.world.entity.animal.cow.AbstractCow.createAttributes().build()) // Purpur - Cows naturally aggressive to players chance
+ .put(EntityType.MULE, AbstractChestedHorse.createBaseChestedHorseAttributes().build())
+ .put(EntityType.NAUTILUS, Nautilus.createAttributes().build())
+ .put(EntityType.OCELOT, Ocelot.createAttributes().build())
+diff --git a/net/minecraft/world/entity/animal/cow/Cow.java b/net/minecraft/world/entity/animal/cow/Cow.java
+index bb8c75d20e6a1300d68ae75233962bdc26736c77..9fa18b190091bbfcb9a65d8d35f68fc7375f504f 100644
+--- a/net/minecraft/world/entity/animal/cow/Cow.java
++++ b/net/minecraft/world/entity/animal/cow/Cow.java
+@@ -23,6 +23,8 @@ import net.minecraft.world.level.storage.ValueOutput;
+ import org.jspecify.annotations.Nullable;
+
+ public class Cow extends AbstractCow {
++ private boolean isNaturallyAggressiveToPlayers; // Purpur - Cows naturally aggressive to players chance
++
+ private static final EntityDataAccessor> DATA_VARIANT_ID = SynchedEntityData.defineId(Cow.class, EntityDataSerializers.COW_VARIANT);
+
+ public Cow(EntityType extends Cow> type, Level level) {
+@@ -49,8 +51,9 @@ public class Cow extends AbstractCow {
+ // Purpur start - Configurable entity base attributes
+ @Override
+ public void initAttributes() {
+- this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.cowMaxHealth);
+- this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.cowScale);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.cowMaxHealth);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SCALE).setBaseValue(this.level().purpurConfig.cowScale);
++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.cowNaturallyAggressiveToPlayersDamage); // Purpur - Cows naturally aggressive to players chance
+ }
+ // Purpur end - Configurable entity base attributes
+
+@@ -68,6 +71,13 @@ public class Cow extends AbstractCow {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ @Override
++ protected void registerGoals() {
++ super.registerGoals();
++ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - Cows naturally aggressive to players chance
++ this.targetSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.player.Player.class, 10, true, false, (ignored, ignored2) -> isNaturallyAggressiveToPlayers)); // Purpur - Cows naturally aggressive to players chance
++ }
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+@@ -80,6 +90,12 @@ public class Cow extends AbstractCow {
+ VariantUtils.writeVariant(output, this.getVariant());
+ }
+
++ // Purpur start - Cows naturally aggressive to players chance
++ public static net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder createAttributes() {
++ return AbstractCow.createAttributes().add(net.minecraft.world.entity.ai.attributes.Attributes.ATTACK_DAMAGE, 0.0D);
++ }
++ // Purpur end - Cows naturally aggressive to players chance
++
+ @Override
+ protected void readAdditionalSaveData(ValueInput input) {
+ super.readAdditionalSaveData(input);
+@@ -100,6 +116,7 @@ public class Cow extends AbstractCow {
+ public SpawnGroupData finalizeSpawn(
+ ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
+ ) {
++ this.isNaturallyAggressiveToPlayers = level.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= level.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance; // Purpur - Cows naturally aggressive to players chance
+ VariantUtils.selectVariantToSpawn(SpawnContext.create(level, this.blockPosition()), Registries.COW_VARIANT).ifPresent(this::setVariant);
+ return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
+ }
diff --git a/purpur-server/minecraft-patches/features/0019-API-for-any-mob-to-burn-daylight.patch b/purpur-server/minecraft-patches/features/0019-API-for-any-mob-to-burn-daylight.patch
deleted file mode 100644
index 82e4c0a82..000000000
--- a/purpur-server/minecraft-patches/features/0019-API-for-any-mob-to-burn-daylight.patch
+++ /dev/null
@@ -1,344 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Ben Kerllenevich
-Date: Tue, 25 May 2021 16:31:09 -0400
-Subject: [PATCH] API for any mob to burn daylight
-
-Co-authored by: Encode42
-
-diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
-index 62a38ecedbd579b32a8fd9cff5a433bfe635fc62..8473a7d9af9d83e97387ddf4cc50f6ad22730def 100644
---- a/net/minecraft/world/entity/Entity.java
-+++ b/net/minecraft/world/entity/Entity.java
-@@ -530,6 +530,24 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
- }
- // Purpur end - Add canSaveToDisk to Entity
-
-+ // Purpur start - copied from Mob - API for any mob to burn daylight
-+ public boolean isSunBurnTick() {
-+ if (this.level().isDay() && !this.level().isClientSide) {
-+ float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue();
-+ BlockPos blockPos = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ());
-+ boolean flag = this.isInWaterRainOrBubble() || this.isInPowderSnow || this.wasInPowderSnow;
-+ if (lightLevelDependentMagicValue > 0.5F
-+ && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F
-+ && !flag
-+ && this.level().canSeeSky(blockPos)) {
-+ return true;
-+ }
-+ }
-+
-+ return false;
-+ }
-+ // Purpur end - copied from Mob - API for any mob to burn daylight
-+
- public Entity(EntityType> entityType, Level level) {
- this.type = entityType;
- this.level = level;
-diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
-index 2dc588e2d503c16ccd2589ce18abd2ecebbc8e74..db5a2227009bc4d655fc781d5850221f36f2d112 100644
---- a/net/minecraft/world/entity/LivingEntity.java
-+++ b/net/minecraft/world/entity/LivingEntity.java
-@@ -301,6 +301,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
- public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper
- public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event
- public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API
-+ protected boolean shouldBurnInDay = false; public boolean shouldBurnInDay() { return this.shouldBurnInDay; } public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } // Purpur - API for any mob to burn daylight
-
- @Override
- public float getBukkitYaw() {
-@@ -809,6 +810,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
- });
- DataResult dataResult = this.brain.serializeStart(NbtOps.INSTANCE);
- dataResult.resultOrPartial(LOGGER::error).ifPresent(brain -> compound.put("Brain", brain));
-+ compound.putBoolean("Purpur.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - API for any mob to burn daylight
- }
-
- @Override
-@@ -892,6 +894,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
- if (compound.contains("Brain", 10)) {
- this.brain = this.makeBrain(new Dynamic<>(NbtOps.INSTANCE, compound.get("Brain")));
- }
-+
-+ // Purpur start - API for any mob to burn daylight
-+ if (compound.contains("Purpur.ShouldBurnInDay")) {
-+ this.shouldBurnInDay = compound.getBoolean("Purpur.ShouldBurnInDay");
-+ }
-+ // Purpur end - API for any mob to burn daylight
- }
-
- // CraftBukkit start
-@@ -3574,6 +3582,32 @@ public abstract class LivingEntity extends Entity implements Attackable {
- if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) {
- this.hurtServer(serverLevel, this.damageSources().drown(), 1.0F);
- }
-+
-+ // Purpur start - copied from Zombie - API for any mob to burn daylight
-+ if (this.isAlive()) {
-+ boolean flag = this.shouldBurnInDay() && this.isSunBurnTick(); // Paper - shouldBurnInDay API // Purpur - use shouldBurnInDay() method to handle Phantoms properly - API for any mob to burn daylight
-+ if (flag) {
-+ ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD);
-+ if (!itemBySlot.isEmpty()) {
-+ if (itemBySlot.isDamageableItem()) {
-+ Item item = itemBySlot.getItem();
-+ itemBySlot.setDamageValue(itemBySlot.getDamageValue() + this.random.nextInt(2));
-+ if (itemBySlot.getDamageValue() >= itemBySlot.getMaxDamage()) {
-+ this.onEquippedItemBroken(item, EquipmentSlot.HEAD);
-+ this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY);
-+ }
-+ }
-+
-+ flag = false;
-+ }
-+
-+ if (flag) {
-+ if (getRider() == null || !this.isControllable()) // Purpur - ignore mobs which are uncontrollable or without rider - API for any mob to burn daylight
-+ this.igniteForSeconds(8.0F);
-+ }
-+ }
-+ }
-+ // Purpur end - copied from Zombie - API for any mob to burn daylight
- }
-
- public boolean isSensitiveToWater() {
-diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
-index d93584c6793818463e8883ffe399bf16b03263a9..70ee86993d381445855ac7e7290da384d6675987 100644
---- a/net/minecraft/world/entity/Mob.java
-+++ b/net/minecraft/world/entity/Mob.java
-@@ -1655,19 +1655,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
- }
-
- public boolean isSunBurnTick() {
-- if (this.level().isDay() && !this.level().isClientSide) {
-- float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue();
-- BlockPos blockPos = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ());
-- boolean flag = this.isInWaterRainOrBubble() || this.isInPowderSnow || this.wasInPowderSnow;
-- if (lightLevelDependentMagicValue > 0.5F
-- && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F
-- && !flag
-- && this.level().canSeeSky(blockPos)) {
-- return true;
-- }
-- }
--
-- return false;
-+ // Purpur - implemented in Entity - API for any mob to burn daylight
-+ return super.isSunBurnTick();
- }
-
- @Override
-diff --git a/net/minecraft/world/entity/monster/AbstractSkeleton.java b/net/minecraft/world/entity/monster/AbstractSkeleton.java
-index e186aee80b052b7fc4bfe02763010bfb2d55ea35..223739818e9ac6c9fe396b82bce53a3ab029610a 100644
---- a/net/minecraft/world/entity/monster/AbstractSkeleton.java
-+++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java
-@@ -64,11 +64,12 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
- AbstractSkeleton.this.setAggressive(true);
- }
- };
-- private boolean shouldBurnInDay = true; // Paper - shouldBurnInDay API
-+ //private boolean shouldBurnInDay = true; // Paper - shouldBurnInDay API // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight
-
- protected AbstractSkeleton(EntityType extends AbstractSkeleton> entityType, Level level) {
- super(entityType, level);
- this.reassessWeaponGoal();
-+ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight
- }
-
- @Override
-@@ -110,27 +111,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
-
- @Override
- public void aiStep() {
-- boolean isSunBurnTick = this.shouldBurnInDay && this.isSunBurnTick(); // Paper - shouldBurnInDay API
-- if (isSunBurnTick) {
-- ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD);
-- if (!itemBySlot.isEmpty()) {
-- if (itemBySlot.isDamageableItem()) {
-- Item item = itemBySlot.getItem();
-- itemBySlot.setDamageValue(itemBySlot.getDamageValue() + this.random.nextInt(2));
-- if (itemBySlot.getDamageValue() >= itemBySlot.getMaxDamage()) {
-- this.onEquippedItemBroken(item, EquipmentSlot.HEAD);
-- this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY);
-- }
-- }
--
-- isSunBurnTick = false;
-- }
--
-- if (isSunBurnTick) {
-- this.igniteForSeconds(8.0F);
-- }
-- }
--
-+ // Purpur - implemented in LivingEntity - API for any mob to burn daylight
- super.aiStep();
- }
-
-@@ -243,7 +224,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
- super.readAdditionalSaveData(compound);
- this.reassessWeaponGoal();
- // Paper start - shouldBurnInDay API
-- if (compound.contains("Paper.ShouldBurnInDay")) {
-+ if (false && compound.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - API for any mob to burn daylight
- this.shouldBurnInDay = compound.getBoolean("Paper.ShouldBurnInDay");
- }
- // Paper end - shouldBurnInDay API
-@@ -252,7 +233,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
- @Override
- public void addAdditionalSaveData(final net.minecraft.nbt.CompoundTag nbt) {
- super.addAdditionalSaveData(nbt);
-- nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay);
-+ //nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - implemented in LivingEntity - API for any mob to burn daylight
- }
- // Paper end - shouldBurnInDay API
-
-diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java
-index 31eef2869945d9de565d627cac3fc1a5db380a2a..e618e716cb5ff3a3c5d284e985455694cc0edde0 100644
---- a/net/minecraft/world/entity/monster/Husk.java
-+++ b/net/minecraft/world/entity/monster/Husk.java
-@@ -19,6 +19,7 @@ import net.minecraft.world.level.ServerLevelAccessor;
- public class Husk extends Zombie {
- public Husk(EntityType extends Husk> entityType, Level level) {
- super(entityType, level);
-+ this.setShouldBurnInDay(false); // Purpur - API for any mob to burn daylight
- }
-
- // Purpur start - Ridables
-@@ -82,7 +83,7 @@ public class Husk extends Zombie {
-
- @Override
- public boolean isSunSensitive() {
-- return false;
-+ return this.shouldBurnInDay; // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight
- }
-
- @Override
-diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
-index 32b7c34d3c68dcfa936b628b2d038524204129a3..0ee817699fffbb929011465029182cc56befc30c 100644
---- a/net/minecraft/world/entity/monster/Phantom.java
-+++ b/net/minecraft/world/entity/monster/Phantom.java
-@@ -60,6 +60,7 @@ public class Phantom extends FlyingMob implements Enemy {
- this.xpReward = 5;
- this.moveControl = new Phantom.PhantomMoveControl(this);
- this.lookControl = new Phantom.PhantomLookControl(this);
-+ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight
- }
-
- // Purpur start - Ridables
-@@ -146,6 +147,16 @@ public class Phantom extends FlyingMob implements Enemy {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ //private boolean shouldBurnInDay = true; // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight
-+ // Purpur start - API for any mob to burn daylight
-+ public boolean shouldBurnInDay() {
-+ boolean burnFromDaylight = this.shouldBurnInDay && this.level().purpurConfig.phantomBurnInDaylight;
-+ boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight;
-+ return burnFromDaylight || burnFromLightSource;
-+ }
-+ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; }
-+ // Purpur end - API for any mob to burn daylight
-+
- @Override
- public boolean isFlapping() {
- return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0;
-@@ -261,6 +272,7 @@ public class Phantom extends FlyingMob implements Enemy {
-
- @Override
- public void aiStep() {
-+ // Purpur - implemented in LivingEntity; moved down to shouldBurnInDay() - API for any mob to burn daylight
- // Purpur start - Phantoms burn in light
- boolean burnFromDaylight = this.shouldBurnInDay && this.isSunBurnTick() && this.level().purpurConfig.phantomBurnInDaylight;
- boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight;
-@@ -299,7 +311,7 @@ public class Phantom extends FlyingMob implements Enemy {
- if (compound.hasUUID("Paper.SpawningEntity")) {
- this.spawningEntity = compound.getUUID("Paper.SpawningEntity");
- }
-- if (compound.contains("Paper.ShouldBurnInDay")) {
-+ if (false && compound.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - API for any mob to burn daylight
- this.shouldBurnInDay = compound.getBoolean("Paper.ShouldBurnInDay");
- }
- // Paper end
-@@ -316,7 +328,7 @@ public class Phantom extends FlyingMob implements Enemy {
- if (this.spawningEntity != null) {
- compound.putUUID("Paper.SpawningEntity", this.spawningEntity);
- }
-- compound.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay);
-+ //compound.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - implemented in LivingEntity - API for any mob to burn daylight
- // Paper end
- }
-
-diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
-index bb8c37c8348172947efe14d48ed9ae203409affa..b1da45df27f02395d793e7eafe576f5f92aa3a7b 100644
---- a/net/minecraft/world/entity/monster/Zombie.java
-+++ b/net/minecraft/world/entity/monster/Zombie.java
-@@ -89,11 +89,12 @@ public class Zombie extends Monster {
- private boolean canBreakDoors;
- private int inWaterTime;
- public int conversionTime;
-- private boolean shouldBurnInDay = true; // Paper - Add more Zombie API
-+ //private boolean shouldBurnInDay = true; // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
-
- public Zombie(EntityType extends Zombie> entityType, Level level) {
- super(entityType, level);
- this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(level.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(entityType, level.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty
-+ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight
- }
-
- public Zombie(Level level) {
-@@ -290,29 +291,7 @@ public class Zombie extends Monster {
-
- @Override
- public void aiStep() {
-- if (this.isAlive()) {
-- boolean flag = this.isSunSensitive() && this.isSunBurnTick();
-- if (flag) {
-- ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD);
-- if (!itemBySlot.isEmpty()) {
-- if (itemBySlot.isDamageableItem()) {
-- Item item = itemBySlot.getItem();
-- itemBySlot.setDamageValue(itemBySlot.getDamageValue() + this.random.nextInt(2));
-- if (itemBySlot.getDamageValue() >= itemBySlot.getMaxDamage()) {
-- this.onEquippedItemBroken(item, EquipmentSlot.HEAD);
-- this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY);
-- }
-- }
--
-- flag = false;
-- }
--
-- if (flag) {
-- this.igniteForSeconds(8.0F);
-- }
-- }
-- }
--
-+ // Purpur - implemented in LivingEntity - API for any mob to burn daylight
- super.aiStep();
- }
-
-@@ -371,6 +350,7 @@ public class Zombie extends Monster {
- // CraftBukkit end
- }
-
-+ public boolean shouldBurnInDay() { return this.isSunSensitive(); } // Purpur - for ABI compatibility - API for any mob to burn daylight
- public boolean isSunSensitive() {
- return this.shouldBurnInDay; // Paper - Add more Zombie API
- }
-@@ -509,7 +489,7 @@ public class Zombie extends Monster {
- compound.putBoolean("CanBreakDoors", this.canBreakDoors());
- compound.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1);
- compound.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1);
-- compound.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API
-+ //compound.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
- }
-
- @Override
-@@ -522,7 +502,7 @@ public class Zombie extends Monster {
- this.startUnderWaterConversion(compound.getInt("DrownedConversionTime"));
- }
- // Paper start - Add more Zombie API
-- if (compound.contains("Paper.ShouldBurnInDay")) {
-+ if (false && compound.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - API for any mob to burn daylight
- this.shouldBurnInDay = compound.getBoolean("Paper.ShouldBurnInDay");
- }
- // Paper end - Add more Zombie API
diff --git a/purpur-server/minecraft-patches/features/0021-Mobs-always-drop-experience.patch b/purpur-server/minecraft-patches/features/0019-Mobs-always-drop-experience.patch
similarity index 57%
rename from purpur-server/minecraft-patches/features/0021-Mobs-always-drop-experience.patch
rename to purpur-server/minecraft-patches/features/0019-Mobs-always-drop-experience.patch
index 48e8a9675..04eb4894b 100644
--- a/purpur-server/minecraft-patches/features/0021-Mobs-always-drop-experience.patch
+++ b/purpur-server/minecraft-patches/features/0019-Mobs-always-drop-experience.patch
@@ -4,26 +4,8 @@ Date: Tue, 21 Dec 2021 20:40:42 -0600
Subject: [PATCH] Mobs always drop experience
-diff --git a/net/minecraft/world/entity/GlowSquid.java b/net/minecraft/world/entity/GlowSquid.java
-index e717c063c8f9623b8c4b4ea3843d05fd79af3653..b982d4b7bdf39fcaf5f22cc889467d7b953e3a8e 100644
---- a/net/minecraft/world/entity/GlowSquid.java
-+++ b/net/minecraft/world/entity/GlowSquid.java
-@@ -59,6 +59,13 @@ public class GlowSquid extends Squid {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.glowSquidAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected ParticleOptions getInkParticle() {
- return ParticleTypes.GLOW_SQUID_INK;
diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java
-index 4fa526496265a85b637136f0fd0692ef4f570ad6..4ac052a78841939a53dac2afb575cb115581e249 100644
+index e83900f8d6adbe8a48294f250bd6cc6e3fad8160..b642f71d282773afb9fe273cbe65765afa2d5868 100644
--- a/net/minecraft/world/entity/ambient/Bat.java
+++ b/net/minecraft/world/entity/ambient/Bat.java
@@ -116,6 +116,13 @@ public class Bat extends AmbientCreature {
@@ -40,13 +22,31 @@ index 4fa526496265a85b637136f0fd0692ef4f570ad6..4ac052a78841939a53dac2afb575cb11
@Override
public boolean isFlapping() {
return !this.isResting() && this.tickCount % 10.0F == 0.0F;
-diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java
-index 636ff0f4f8415b6ce23d2676781503443c854cfe..57c50ce5724b073b1aedf4df3129285143097303 100644
---- a/net/minecraft/world/entity/animal/Bee.java
-+++ b/net/minecraft/world/entity/animal/Bee.java
-@@ -487,6 +487,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+diff --git a/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
+index 947160c4dfc4e50bb75a1a797cb2f22602b22643..e5ac43bf5631254c31d91abb1c5de408807429dd 100644
+--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java
++++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
+@@ -160,6 +160,13 @@ public class Axolotl extends Animal implements Bucketable {
}
- // Purpur end - Make entity breeding times configurable
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.axolotlAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public float getWalkTargetValue(BlockPos pos, LevelReader level) {
+ return 0.0F;
+diff --git a/net/minecraft/world/entity/animal/bee/Bee.java b/net/minecraft/world/entity/animal/bee/Bee.java
+index e57200d6560a38cbecd681a30b75409412fce170..10dfa28ec46727e60f8a9c90d7e8914aa8b96ea1 100644
+--- a/net/minecraft/world/entity/animal/bee/Bee.java
++++ b/net/minecraft/world/entity/animal/bee/Bee.java
+@@ -499,6 +499,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+ // Purpur start - Mobs always drop experience
+ @Override
@@ -56,31 +56,13 @@ index 636ff0f4f8415b6ce23d2676781503443c854cfe..57c50ce5724b073b1aedf4df31292851
+ // Purpur end - Mobs always drop experience
+
@Override
- public boolean isSensitiveToWater() {
- return this.level().purpurConfig.beeTakeDamageFromWater;
-diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java
-index b41ca04043e65f107edaebc49d398650898e35fb..edd796fd34e43d66a48104201d885756fdd968c3 100644
---- a/net/minecraft/world/entity/animal/Cat.java
-+++ b/net/minecraft/world/entity/animal/Cat.java
-@@ -140,6 +140,13 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true);
-diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java
-index 2364596156c21e82879f5bf4fd873b9d90b1c308..4d0b172a9d54b1524c8052051859c7178774bef7 100644
---- a/net/minecraft/world/entity/animal/Chicken.java
-+++ b/net/minecraft/world/entity/animal/Chicken.java
-@@ -95,6 +95,13 @@ public class Chicken extends Animal {
+ public long getPersistentAngerEndTime() {
+ return this.entityData.get(DATA_ANGER_END_TIME);
+diff --git a/net/minecraft/world/entity/animal/chicken/Chicken.java b/net/minecraft/world/entity/animal/chicken/Chicken.java
+index 6308bb606b34d781e315f56a55e6544b3c156d85..341d6ecefb126be61b5f43a73638847e2bf9f125 100644
+--- a/net/minecraft/world/entity/animal/chicken/Chicken.java
++++ b/net/minecraft/world/entity/animal/chicken/Chicken.java
+@@ -117,6 +117,13 @@ public class Chicken extends Animal {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -94,10 +76,226 @@ index 2364596156c21e82879f5bf4fd873b9d90b1c308..4d0b172a9d54b1524c8052051859c717
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Cod.java b/net/minecraft/world/entity/animal/Cod.java
-index ac7259cfc8428131f90956d7f76f2227049ffae3..b259de78198e0e3df9e5901019283ad246c8e044 100644
---- a/net/minecraft/world/entity/animal/Cod.java
-+++ b/net/minecraft/world/entity/animal/Cod.java
+diff --git a/net/minecraft/world/entity/animal/cow/Cow.java b/net/minecraft/world/entity/animal/cow/Cow.java
+index 9fa18b190091bbfcb9a65d8d35f68fc7375f504f..1463e94d3851614caee216b50e90d1980de75298 100644
+--- a/net/minecraft/world/entity/animal/cow/Cow.java
++++ b/net/minecraft/world/entity/animal/cow/Cow.java
+@@ -71,6 +71,13 @@ public class Cow extends AbstractCow {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.cowAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/animal/cow/MushroomCow.java b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+index a8e6e703a51130066547724dd08bdfe5e11c99e5..3327b93f095b6b6b6d5620bffd03232d4fb47d20 100644
+--- a/net/minecraft/world/entity/animal/cow/MushroomCow.java
++++ b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+@@ -99,6 +99,13 @@ public class MushroomCow extends AbstractCow implements Shearable {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.mooshroomAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public float getWalkTargetValue(BlockPos pos, LevelReader level) {
+ return level.getBlockState(pos.below()).is(Blocks.MYCELIUM) ? 10.0F : level.getPathfindingCostFromLightLevels(pos);
+diff --git a/net/minecraft/world/entity/animal/dolphin/Dolphin.java b/net/minecraft/world/entity/animal/dolphin/Dolphin.java
+index d73789bb8ce0f65be94437484c3ed41e26cd7510..bea132780ef9b8aac23dbd38cebed080082c2a87 100644
+--- a/net/minecraft/world/entity/animal/dolphin/Dolphin.java
++++ b/net/minecraft/world/entity/animal/dolphin/Dolphin.java
+@@ -167,6 +167,13 @@ public class Dolphin extends AgeableWaterCreature {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.dolphinAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public @Nullable SpawnGroupData finalizeSpawn(
+ ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
+diff --git a/net/minecraft/world/entity/animal/equine/Donkey.java b/net/minecraft/world/entity/animal/equine/Donkey.java
+index 6cf6853c244b7589d2a57e7ae77933d4a1503ccd..ca02355276286a88d618467d9191d648a3cf7b12 100644
+--- a/net/minecraft/world/entity/animal/equine/Donkey.java
++++ b/net/minecraft/world/entity/animal/equine/Donkey.java
+@@ -54,6 +54,13 @@ public class Donkey extends AbstractChestedHorse {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.donkeyAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public SoundEvent getAmbientSound() {
+ return SoundEvents.DONKEY_AMBIENT;
+diff --git a/net/minecraft/world/entity/animal/equine/Horse.java b/net/minecraft/world/entity/animal/equine/Horse.java
+index 1c17ab94901ce1c6370670c06bf0801ee6b5b393..bb7ae0bc176fc873b0e1c760b62c5c4e0ee05ae8 100644
+--- a/net/minecraft/world/entity/animal/equine/Horse.java
++++ b/net/minecraft/world/entity/animal/equine/Horse.java
+@@ -88,6 +88,13 @@ public class Horse extends AbstractHorse {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.horseAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void randomizeAttributes(RandomSource random) {
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt));
+diff --git a/net/minecraft/world/entity/animal/equine/Llama.java b/net/minecraft/world/entity/animal/equine/Llama.java
+index eb2fc0e6d497241f1b4f3971155b10d14f5427f8..eef4b602bd03df53823da6f576246c330e46d0d4 100644
+--- a/net/minecraft/world/entity/animal/equine/Llama.java
++++ b/net/minecraft/world/entity/animal/equine/Llama.java
+@@ -166,6 +166,13 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.llamaAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ public boolean isTraderLlama() {
+ return false;
+ }
+diff --git a/net/minecraft/world/entity/animal/equine/Mule.java b/net/minecraft/world/entity/animal/equine/Mule.java
+index 9bafe3e204b3e4624a95b130552c8230c0835a30..8514c0b7657366a1c40217b950c74c95631c328a 100644
+--- a/net/minecraft/world/entity/animal/equine/Mule.java
++++ b/net/minecraft/world/entity/animal/equine/Mule.java
+@@ -53,6 +53,13 @@ public class Mule extends AbstractChestedHorse {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.muleAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public SoundEvent getAmbientSound() {
+ return SoundEvents.MULE_AMBIENT;
+diff --git a/net/minecraft/world/entity/animal/equine/SkeletonHorse.java b/net/minecraft/world/entity/animal/equine/SkeletonHorse.java
+index 3865937e4a56636cde44f7d8f16873ae16512323..2502716b8efe4584fba9d9f9989ba9cba67568bc 100644
+--- a/net/minecraft/world/entity/animal/equine/SkeletonHorse.java
++++ b/net/minecraft/world/entity/animal/equine/SkeletonHorse.java
+@@ -81,6 +81,13 @@ public class SkeletonHorse extends AbstractHorse {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.skeletonHorseAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0).add(Attributes.MOVEMENT_SPEED, 0.2F);
+ }
+diff --git a/net/minecraft/world/entity/animal/equine/TraderLlama.java b/net/minecraft/world/entity/animal/equine/TraderLlama.java
+index 4c07cd57aa3518adb4bc9b1213cc572a5b81f935..0515d1071324d82c14be4b9e97c8a583dd45a721 100644
+--- a/net/minecraft/world/entity/animal/equine/TraderLlama.java
++++ b/net/minecraft/world/entity/animal/equine/TraderLlama.java
+@@ -84,6 +84,13 @@ public class TraderLlama extends Llama {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.traderLlamaAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public boolean isTraderLlama() {
+ return true;
+diff --git a/net/minecraft/world/entity/animal/equine/ZombieHorse.java b/net/minecraft/world/entity/animal/equine/ZombieHorse.java
+index b770d3118452b0b7a362b1f541bb602f4d3cbcec..5b671d468698444569b1d97437d746d49c0db757 100644
+--- a/net/minecraft/world/entity/animal/equine/ZombieHorse.java
++++ b/net/minecraft/world/entity/animal/equine/ZombieHorse.java
+@@ -95,6 +95,13 @@ public class ZombieHorse extends AbstractHorse {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.zombieHorseAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 25.0);
+ }
+diff --git a/net/minecraft/world/entity/animal/feline/Cat.java b/net/minecraft/world/entity/animal/feline/Cat.java
+index 92b67565485b2fade3e80fb4b944edfc12d9e0a2..4422cc2f0ed1b603348f3f5c0d6650f871190ffd 100644
+--- a/net/minecraft/world/entity/animal/feline/Cat.java
++++ b/net/minecraft/world/entity/animal/feline/Cat.java
+@@ -142,6 +142,13 @@ public class Cat extends TamableAnimal {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.catAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ this.temptGoal = new Cat.CatTemptGoal(this, 0.6, stack -> stack.is(ItemTags.CAT_FOOD), true);
+diff --git a/net/minecraft/world/entity/animal/feline/Ocelot.java b/net/minecraft/world/entity/animal/feline/Ocelot.java
+index 13272516003f763d2c69dc599c8ff7696bec718b..8583fefcb37dc043293bf622b5a25adbbcc8128e 100644
+--- a/net/minecraft/world/entity/animal/feline/Ocelot.java
++++ b/net/minecraft/world/entity/animal/feline/Ocelot.java
+@@ -105,6 +105,13 @@ public class Ocelot extends Animal {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.ocelotAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ public boolean isTrusting() {
+ return this.entityData.get(DATA_TRUSTING);
+ }
+diff --git a/net/minecraft/world/entity/animal/fish/Cod.java b/net/minecraft/world/entity/animal/fish/Cod.java
+index 8655aae805f239cbd049065232293854b18c73cf..05de579a16726454034dc4a913161676b5c73552 100644
+--- a/net/minecraft/world/entity/animal/fish/Cod.java
++++ b/net/minecraft/world/entity/animal/fish/Cod.java
@@ -39,6 +39,13 @@ public class Cod extends AbstractSchoolingFish {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -112,191 +310,11 @@ index ac7259cfc8428131f90956d7f76f2227049ffae3..b259de78198e0e3df9e5901019283ad2
@Override
public ItemStack getBucketItemStack() {
return new ItemStack(Items.COD_BUCKET);
-diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java
-index b62c4449047da36d8b4d4b87d03c77906d12dc31..a0297ac3ba520122ed2095d6008c057d749b731e 100644
---- a/net/minecraft/world/entity/animal/Cow.java
-+++ b/net/minecraft/world/entity/animal/Cow.java
-@@ -88,6 +88,13 @@ public class Cow extends Animal {
- }
- // Purpur end - Cows naturally aggressive to players chance
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.cowAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java
-index e104058b3c01bea4cc8a77de2ad4378465903b34..7003b532182737a745491e397a967b72e6b308aa 100644
---- a/net/minecraft/world/entity/animal/Dolphin.java
-+++ b/net/minecraft/world/entity/animal/Dolphin.java
-@@ -163,6 +163,13 @@ public class Dolphin extends AgeableWaterCreature {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.dolphinAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Nullable
- @Override
- public SpawnGroupData finalizeSpawn(
-diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java
-index 22a70c6af965114e272bb56cb217f975a3cd1bd4..aa610af9db105081fcabc1f299e5f2dd1f4d907e 100644
---- a/net/minecraft/world/entity/animal/Fox.java
-+++ b/net/minecraft/world/entity/animal/Fox.java
-@@ -189,6 +189,13 @@ public class Fox extends Animal implements VariantHolder {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.foxAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/animal/IronGolem.java b/net/minecraft/world/entity/animal/IronGolem.java
-index 23108729ce65ef8b7b215b82f29347513cfd4ebf..ccadc9a151e258ff2c74c65c374b1f09d56d10ec 100644
---- a/net/minecraft/world/entity/animal/IronGolem.java
-+++ b/net/minecraft/world/entity/animal/IronGolem.java
-@@ -105,6 +105,13 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.ironGolemAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void registerGoals() {
- if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options
-diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java
-index 5e9795f447e88a42909730d383eaa36acfaf18f5..3bcd119757dfc579df790fcc8919a3636bafa7fe 100644
---- a/net/minecraft/world/entity/animal/MushroomCow.java
-+++ b/net/minecraft/world/entity/animal/MushroomCow.java
-@@ -93,6 +93,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.rabbitAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- public void registerGoals() {
- this.goalSelector.addGoal(1, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/animal/Salmon.java b/net/minecraft/world/entity/animal/Salmon.java
-index 8bd4b2b29438bff65ed00a42bbc9639111af181f..5da2f14770aebb2286c3e8cbd9622a89a33e0e20 100644
---- a/net/minecraft/world/entity/animal/Salmon.java
-+++ b/net/minecraft/world/entity/animal/Salmon.java
-@@ -61,6 +61,13 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder, B
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.axolotlAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- public float getWalkTargetValue(BlockPos pos, LevelReader level) {
- return 0.0F;
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java
-index 0c357ffacfe4dd982a58e6cf2338c7e6b24610f5..6f106f10466440f8e65e04511f67d48f082d703f 100644
+index e5f5bc2c4b4f36e0e911b2c5ef67ef6e0d4cd0b1..64916356de4b9981e04c5befef15b067914f6d75 100644
--- a/net/minecraft/world/entity/animal/goat/Goat.java
+++ b/net/minecraft/world/entity/animal/goat/Goat.java
-@@ -142,6 +142,13 @@ public class Goat extends Animal {
+@@ -146,6 +146,13 @@ public class Goat extends Animal {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -490,137 +400,299 @@ index 0c357ffacfe4dd982a58e6cf2338c7e6b24610f5..6f106f10466440f8e65e04511f67d48f
@Override
protected Brain.Provider brainProvider() {
return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java
-index 1db6ccdc6c83c704aa84a46ee2751a17125bf457..3e0181578a6f2d22d1da3776abf30bf97d124620 100644
---- a/net/minecraft/world/entity/animal/horse/Donkey.java
-+++ b/net/minecraft/world/entity/animal/horse/Donkey.java
-@@ -54,6 +54,13 @@ public class Donkey extends AbstractChestedHorse {
+diff --git a/net/minecraft/world/entity/animal/golem/CopperGolem.java b/net/minecraft/world/entity/animal/golem/CopperGolem.java
+index 2d0ce5d420f88a95eda34a3fe81c815999bde300..4f92ac01a6d362a7ef748b74b75773575970859f 100644
+--- a/net/minecraft/world/entity/animal/golem/CopperGolem.java
++++ b/net/minecraft/world/entity/animal/golem/CopperGolem.java
+@@ -147,6 +147,13 @@ public class CopperGolem extends AbstractGolem implements ContainerUser, Shearab
}
// Purpur end - Toggle for water sensitive mob damage
+ // Purpur start - Mobs always drop experience
+ @Override
+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.donkeyAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected SoundEvent getAmbientSound() {
- return SoundEvents.DONKEY_AMBIENT;
-diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java
-index f257d549570918381925cef98734fc0aa605f8f2..be0d636ca894c5995f28f59c196cd8e56dd228c4 100644
---- a/net/minecraft/world/entity/animal/horse/Horse.java
-+++ b/net/minecraft/world/entity/animal/horse/Horse.java
-@@ -81,6 +81,13 @@ public class Horse extends AbstractHorse implements VariantHolder {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.horseAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void randomizeAttributes(RandomSource random) {
- this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt));
-diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java
-index 872a54186a20fd855fe7981f3ff1c867f4c64d19..c21d558a6a3a61d6c54b8163f8cb4963846b2c26 100644
---- a/net/minecraft/world/entity/animal/horse/Llama.java
-+++ b/net/minecraft/world/entity/animal/horse/Llama.java
-@@ -155,6 +155,13 @@ public class Llama extends AbstractChestedHorse implements VariantHolder brainProvider() {
+ return NautilusAi.brainProvider();
+diff --git a/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java b/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java
+index 94383c5020b6631203ddc4e0a58a222729ffe9a2..7e4d005053e6812f329ab7ac1f252c547d4c9a12 100644
+--- a/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java
++++ b/net/minecraft/world/entity/animal/nautilus/ZombieNautilus.java
+@@ -61,6 +61,13 @@ public class ZombieNautilus extends AbstractNautilus {
+ }
+ // Purpur end - Make entity breeding times configurable
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.zombieNautilusAlwaysDropExp;
+ }
+ // Purpur end - Mobs always drop experience
+
public static AttributeSupplier.Builder createAttributes() {
- return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0).add(Attributes.MOVEMENT_SPEED, 0.2F);
+ return AbstractNautilus.createAttributes().add(Attributes.MOVEMENT_SPEED, 1.1F);
}
+diff --git a/net/minecraft/world/entity/animal/panda/Panda.java b/net/minecraft/world/entity/animal/panda/Panda.java
+index e9aa07dea0515f53a08a7066fa9e23e0ee69d69e..5116e9e16070e23d13b526d21facb7b5ad0988ba 100644
+--- a/net/minecraft/world/entity/animal/panda/Panda.java
++++ b/net/minecraft/world/entity/animal/panda/Panda.java
+@@ -157,6 +157,13 @@ public class Panda extends Animal {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.pandaAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected boolean canDispenserEquipIntoSlot(EquipmentSlot slot) {
+ return slot == EquipmentSlot.MAINHAND && this.canPickUpLoot();
+diff --git a/net/minecraft/world/entity/animal/parrot/Parrot.java b/net/minecraft/world/entity/animal/parrot/Parrot.java
+index e97782bc8232120d4e7d1feeb8ca87fd37a1fcf9..bbe3977939004b7d77e38b14d48c9c26e596d123 100644
+--- a/net/minecraft/world/entity/animal/parrot/Parrot.java
++++ b/net/minecraft/world/entity/animal/parrot/Parrot.java
+@@ -221,6 +221,13 @@ public class Parrot extends ShoulderRidingEntity implements FlyingAnimal {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.parrotAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public @Nullable SpawnGroupData finalizeSpawn(
+ ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
+diff --git a/net/minecraft/world/entity/animal/pig/Pig.java b/net/minecraft/world/entity/animal/pig/Pig.java
+index 020932539727739b54ed2f7899cbf11ad940f4df..45142ce558ef28455f9b74ca81d51b3ecdb7a458 100644
+--- a/net/minecraft/world/entity/animal/pig/Pig.java
++++ b/net/minecraft/world/entity/animal/pig/Pig.java
+@@ -102,6 +102,13 @@ public class Pig extends Animal implements ItemSteerable {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.pigAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/animal/polarbear/PolarBear.java b/net/minecraft/world/entity/animal/polarbear/PolarBear.java
+index 13d26a6981d6907f35f1f2bde93934c7c1fe8120..592711e205ee959cc66de80933ad5a2dcec3092f 100644
+--- a/net/minecraft/world/entity/animal/polarbear/PolarBear.java
++++ b/net/minecraft/world/entity/animal/polarbear/PolarBear.java
+@@ -140,6 +140,13 @@ public class PolarBear extends Animal implements NeutralMob {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.polarBearAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public @Nullable AgeableMob getBreedOffspring(ServerLevel level, AgeableMob partner) {
+ return EntityType.POLAR_BEAR.create(level, EntitySpawnReason.BREEDING);
+diff --git a/net/minecraft/world/entity/animal/rabbit/Rabbit.java b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+index b1c72047f7aa63f62b0ad0274811b587b1d3486b..c39004a546c28c9f8af26e727c67dbff85ba1212 100644
+--- a/net/minecraft/world/entity/animal/rabbit/Rabbit.java
++++ b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+@@ -170,6 +170,13 @@ public class Rabbit extends Animal {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.rabbitAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/animal/sheep/Sheep.java b/net/minecraft/world/entity/animal/sheep/Sheep.java
+index 7eca49c9237c61ab12f60ff16085aa8fd10c99ac..d712673d237f4e4d99a714ddf09c4582387f0e3c 100644
+--- a/net/minecraft/world/entity/animal/sheep/Sheep.java
++++ b/net/minecraft/world/entity/animal/sheep/Sheep.java
+@@ -102,6 +102,13 @@ public class Sheep extends Animal implements Shearable {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.sheepAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ this.eatBlockGoal = new EatBlockGoal(this);
+diff --git a/net/minecraft/world/entity/animal/squid/GlowSquid.java b/net/minecraft/world/entity/animal/squid/GlowSquid.java
+index 2aa2a84a7ada369c45a85119a933eb92297af4dc..dd1bd8b1a348a0cc398b123a77d3cb28dd1273ae 100644
+--- a/net/minecraft/world/entity/animal/squid/GlowSquid.java
++++ b/net/minecraft/world/entity/animal/squid/GlowSquid.java
+@@ -64,6 +64,13 @@ public class GlowSquid extends Squid {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.glowSquidAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected ParticleOptions getInkParticle() {
+ return ParticleTypes.GLOW_SQUID_INK;
+diff --git a/net/minecraft/world/entity/animal/squid/Squid.java b/net/minecraft/world/entity/animal/squid/Squid.java
+index e307ebfb8b2781b6175b520e148e6bd58d2b9dc4..6b5be8e58aa7e3acd14ff3cb1ba25d15f8d37410 100644
+--- a/net/minecraft/world/entity/animal/squid/Squid.java
++++ b/net/minecraft/world/entity/animal/squid/Squid.java
+@@ -108,6 +108,13 @@ public class Squid extends AgeableWaterCreature {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.squidAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this));
+diff --git a/net/minecraft/world/entity/animal/turtle/Turtle.java b/net/minecraft/world/entity/animal/turtle/Turtle.java
+index 7d5987fe641646ecbf8e389d57a0a9a04e9c0959..a3f2076e6f0e51ac51a8af94cae91baf82c247a1 100644
+--- a/net/minecraft/world/entity/animal/turtle/Turtle.java
++++ b/net/minecraft/world/entity/animal/turtle/Turtle.java
+@@ -126,6 +126,13 @@ public class Turtle extends Animal {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.turtleAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ public void setHomePos(BlockPos homePos) {
+ this.homePos = homePos;
+ }
+diff --git a/net/minecraft/world/entity/animal/wolf/Wolf.java b/net/minecraft/world/entity/animal/wolf/Wolf.java
+index 20f945ee06bcdb4736e6d3a8b20a5cbd3d79df0f..7fbe841818d08fd930f7ce405e84e5ed4badb614 100644
+--- a/net/minecraft/world/entity/animal/wolf/Wolf.java
++++ b/net/minecraft/world/entity/animal/wolf/Wolf.java
+@@ -230,6 +230,13 @@ public class Wolf extends TamableAnimal implements NeutralMob {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.wolfAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
diff --git a/net/minecraft/world/entity/boss/wither/WitherBoss.java b/net/minecraft/world/entity/boss/wither/WitherBoss.java
-index 7a3688e6cad1bbb0a47d8f3d0218bd777a0ab033..2d9f64cddbec782de1775ec6da67b16203e3fd90 100644
+index ef6dcc8183d9963d1e683f2cc74fec6443d175a9..fe4362040da72b51c14b3c65f75fe8a72757bab3 100644
--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java
+++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java
-@@ -226,6 +226,13 @@ public class WitherBoss extends Monster implements RangedAttackMob {
+@@ -228,6 +228,13 @@ public class WitherBoss extends Monster implements RangedAttackMob {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -635,10 +707,10 @@ index 7a3688e6cad1bbb0a47d8f3d0218bd777a0ab033..2d9f64cddbec782de1775ec6da67b162
protected PathNavigation createNavigation(Level level) {
FlyingPathNavigation flyingPathNavigation = new FlyingPathNavigation(this, level);
diff --git a/net/minecraft/world/entity/monster/Blaze.java b/net/minecraft/world/entity/monster/Blaze.java
-index 1ea964b3a3b9403ad3a500bf1c4b8d69a529d16a..79f5f0dbf95ed72dd031495c75675d7b6c7dfc34 100644
+index e2afd7677986c70dd924017e8822fd6abd808f48..187da2d55cdb039b62abe708dadd6c05e13ac64f 100644
--- a/net/minecraft/world/entity/monster/Blaze.java
+++ b/net/minecraft/world/entity/monster/Blaze.java
-@@ -83,6 +83,13 @@ public class Blaze extends Monster {
+@@ -84,6 +84,13 @@ public class Blaze extends Monster {
}
// Purpur end - Configurable entity base attributes
@@ -652,29 +724,11 @@ index 1ea964b3a3b9403ad3a500bf1c4b8d69a529d16a..79f5f0dbf95ed72dd031495c75675d7b
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-diff --git a/net/minecraft/world/entity/monster/CaveSpider.java b/net/minecraft/world/entity/monster/CaveSpider.java
-index 420fe0d01d0b173a6a541f77e1aaca3f3bb565e7..7eca4b751d900c6d6ee34993c3e2368127d19e03 100644
---- a/net/minecraft/world/entity/monster/CaveSpider.java
-+++ b/net/minecraft/world/entity/monster/CaveSpider.java
-@@ -58,6 +58,13 @@ public class CaveSpider extends Spider {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.caveSpiderAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- public boolean doHurtTarget(ServerLevel level, Entity source) {
- if (super.doHurtTarget(level, source)) {
diff --git a/net/minecraft/world/entity/monster/Creeper.java b/net/minecraft/world/entity/monster/Creeper.java
-index 6d9995d5f38b2f94a2d3362da7861b3e90e4fb6f..a85b64799faa860367cded67a264b436cd46f049 100644
+index b0ed96c243f9abb3868d92bb513ad1620aa8e269..608d787b73dce1726ccece9e0372acf995f261d4 100644
--- a/net/minecraft/world/entity/monster/Creeper.java
+++ b/net/minecraft/world/entity/monster/Creeper.java
-@@ -274,6 +274,13 @@ public class Creeper extends Monster {
+@@ -273,6 +273,13 @@ public class Creeper extends Monster {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -686,28 +740,10 @@ index 6d9995d5f38b2f94a2d3362da7861b3e90e4fb6f..a85b64799faa860367cded67a264b436
+ // Purpur end - Mobs always drop experience
+
@Override
- protected SoundEvent getHurtSound(DamageSource damageSource) {
+ public SoundEvent getHurtSound(DamageSource damageSource) {
return SoundEvents.CREEPER_HURT;
-diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java
-index 0a1a78e65b6472b713835262b5937bc7ea67b95c..6c73245b8d04f194e72165aa0000ca79a95db59d 100644
---- a/net/minecraft/world/entity/monster/Drowned.java
-+++ b/net/minecraft/world/entity/monster/Drowned.java
-@@ -129,6 +129,13 @@ public class Drowned extends Zombie implements RangedAttackMob {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.drownedAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void addBehaviourGoals() {
- this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0));
diff --git a/net/minecraft/world/entity/monster/ElderGuardian.java b/net/minecraft/world/entity/monster/ElderGuardian.java
-index 2b1d33f4938b978c5b04ede7562bdecb5fbd2245..358021a6eb936ac43e29c7c2c92c71e9cae6ab93 100644
+index 1ea323a17440abbe36c9528e80e169816267005b..abb7496c293175828fde54ae2b4991aa3ff6b30f 100644
--- a/net/minecraft/world/entity/monster/ElderGuardian.java
+++ b/net/minecraft/world/entity/monster/ElderGuardian.java
@@ -58,6 +58,13 @@ public class ElderGuardian extends Guardian {
@@ -725,10 +761,10 @@ index 2b1d33f4938b978c5b04ede7562bdecb5fbd2245..358021a6eb936ac43e29c7c2c92c71e9
return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.3F).add(Attributes.ATTACK_DAMAGE, 8.0).add(Attributes.MAX_HEALTH, 80.0);
}
diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
-index 6fccfb243c26c27b665df57e5e19eb3350c52ddf..78b1619afa2062638fbfe21b9978f634be1aaf62 100644
+index 47c621f01658f3392b58f3f5c1f31bd539f63dd6..c90a955b14ae10037f31c7e9b8a86df3323602cc 100644
--- a/net/minecraft/world/entity/monster/EnderMan.java
+++ b/net/minecraft/world/entity/monster/EnderMan.java
-@@ -115,6 +115,13 @@ public class EnderMan extends Monster implements NeutralMob {
+@@ -114,6 +114,13 @@ public class EnderMan extends Monster implements NeutralMob {
}
// Purpur end - Configurable entity base attributes
@@ -743,10 +779,10 @@ index 6fccfb243c26c27b665df57e5e19eb3350c52ddf..78b1619afa2062638fbfe21b9978f634
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
diff --git a/net/minecraft/world/entity/monster/Endermite.java b/net/minecraft/world/entity/monster/Endermite.java
-index 38e3b3ed2c003fe7bbb476f7bf9a882ea2de792a..441f7d3cfa1e9896a065dae51d871901ac4330e3 100644
+index c79c689cb99ad2a6cab88cf8b583ff0f9e91b115..4a778ad22f92e3fd95665a9b40ae932b427bac16 100644
--- a/net/minecraft/world/entity/monster/Endermite.java
+++ b/net/minecraft/world/entity/monster/Endermite.java
-@@ -77,6 +77,13 @@ public class Endermite extends Monster {
+@@ -79,6 +79,13 @@ public class Endermite extends Monster {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -760,29 +796,11 @@ index 38e3b3ed2c003fe7bbb476f7bf9a882ea2de792a..441f7d3cfa1e9896a065dae51d871901
@Override
protected void registerGoals() {
this.goalSelector.addGoal(1, new FloatGoal(this));
-diff --git a/net/minecraft/world/entity/monster/Evoker.java b/net/minecraft/world/entity/monster/Evoker.java
-index 61ed6606948cc5f8af543eb9ae05f9aeb4e73b89..5c32406d00ec20516649d7a219a5b3c27c8945aa 100644
---- a/net/minecraft/world/entity/monster/Evoker.java
-+++ b/net/minecraft/world/entity/monster/Evoker.java
-@@ -82,6 +82,13 @@ public class Evoker extends SpellcasterIllager {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.evokerAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Ghast.java b/net/minecraft/world/entity/monster/Ghast.java
-index 68debfa8c6d0fc3ff536d2b4d89c131fd6aca935..a9d92e857c5d05da6f2a5b6264590efe235061a7 100644
+index 443eb9f12d6df950c59c9d4db4853087fd23d24e..673d4e06d6dc4c94ddaafcdc86cbdbd686964ddd 100644
--- a/net/minecraft/world/entity/monster/Ghast.java
+++ b/net/minecraft/world/entity/monster/Ghast.java
-@@ -91,6 +91,13 @@ public class Ghast extends FlyingMob implements Enemy {
+@@ -90,6 +90,13 @@ public class Ghast extends Mob implements Enemy {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -797,7 +815,7 @@ index 68debfa8c6d0fc3ff536d2b4d89c131fd6aca935..a9d92e857c5d05da6f2a5b6264590efe
protected void registerGoals() {
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
diff --git a/net/minecraft/world/entity/monster/Giant.java b/net/minecraft/world/entity/monster/Giant.java
-index 009b8a8b1b9aabc0aef1c12a0c0f65f9ccfcd306..3f575abee4c8933d1642400d134b0fc915215a1a 100644
+index f1176f73d4468b2f39e48fe5454c5f5bf481afd9..9a081135025f114d473c50e68a778e034f33ab82 100644
--- a/net/minecraft/world/entity/monster/Giant.java
+++ b/net/minecraft/world/entity/monster/Giant.java
@@ -69,6 +69,13 @@ public class Giant extends Monster {
@@ -812,13 +830,13 @@ index 009b8a8b1b9aabc0aef1c12a0c0f65f9ccfcd306..3f575abee4c8933d1642400d134b0fc9
+ // Purpur end - Mobs always drop experience
+
public static AttributeSupplier.Builder createAttributes() {
- return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0);
- }
+ return Monster.createMonsterAttributes()
+ .add(Attributes.MAX_HEALTH, 100.0)
diff --git a/net/minecraft/world/entity/monster/Guardian.java b/net/minecraft/world/entity/monster/Guardian.java
-index 819679a224ffe33e03d8e6b429c8e31b67c769fa..60278b2491f644b70ef96b2e14e1f07bb341a0f1 100644
+index 9948511659de9222a19f6b9f660e4441ea98a4a9..60490d0611a352ba0546b39fd41259713a7f18b5 100644
--- a/net/minecraft/world/entity/monster/Guardian.java
+++ b/net/minecraft/world/entity/monster/Guardian.java
-@@ -105,6 +105,13 @@ public class Guardian extends Monster {
+@@ -104,6 +104,13 @@ public class Guardian extends Monster {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -832,44 +850,8 @@ index 819679a224ffe33e03d8e6b429c8e31b67c769fa..60278b2491f644b70ef96b2e14e1f07b
@Override
protected void registerGoals() {
MoveTowardsRestrictionGoal moveTowardsRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0);
-diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java
-index e618e716cb5ff3a3c5d284e985455694cc0edde0..a5bfc6f5caba1da8cfcb345524e05e8676672cb0 100644
---- a/net/minecraft/world/entity/monster/Husk.java
-+++ b/net/minecraft/world/entity/monster/Husk.java
-@@ -75,6 +75,13 @@ public class Husk extends Zombie {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.huskAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- public static boolean checkHuskSpawnRules(
- EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
- ) {
-diff --git a/net/minecraft/world/entity/monster/Illusioner.java b/net/minecraft/world/entity/monster/Illusioner.java
-index ad661f2bf8957644605b52a469d6a7cf8e064398..9686658b90e886d6236f553d7406771814d18672 100644
---- a/net/minecraft/world/entity/monster/Illusioner.java
-+++ b/net/minecraft/world/entity/monster/Illusioner.java
-@@ -91,6 +91,13 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.illusionerAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/MagmaCube.java b/net/minecraft/world/entity/monster/MagmaCube.java
-index bf26f5f6017c60d5991d5f6c87da2acbd95ef5bb..312d4a3d312b5c326d6ca13ccfc48171e18f4370 100644
+index 1bf9d04e5e44272b02753290995795f194cbdae1..765a0d0376e344d2f108a5abe97e654bd972c80b 100644
--- a/net/minecraft/world/entity/monster/MagmaCube.java
+++ b/net/minecraft/world/entity/monster/MagmaCube.java
@@ -75,6 +75,13 @@ public class MagmaCube extends Slime {
@@ -887,12 +869,12 @@ index bf26f5f6017c60d5991d5f6c87da2acbd95ef5bb..312d4a3d312b5c326d6ca13ccfc48171
return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F);
}
diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
-index 0ee817699fffbb929011465029182cc56befc30c..39f94cee78e8fc14d892cb64fb5234bf88d964ad 100644
+index ff944ad57d4e9e4a910cd63282e5e7594626365e..1f3389185ccf997165dc2caf9f78ec560cfd68bd 100644
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
-@@ -157,6 +157,13 @@ public class Phantom extends FlyingMob implements Enemy {
- public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; }
- // Purpur end - API for any mob to burn daylight
+@@ -136,6 +136,13 @@ public class Phantom extends Mob implements Enemy {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+ // Purpur start - Mobs always drop experience
+ @Override
@@ -904,29 +886,11 @@ index 0ee817699fffbb929011465029182cc56befc30c..39f94cee78e8fc14d892cb64fb5234bf
@Override
public boolean isFlapping() {
return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0;
-diff --git a/net/minecraft/world/entity/monster/Pillager.java b/net/minecraft/world/entity/monster/Pillager.java
-index 869a1007de13f3f5d757968d0f84cbf43786c870..a57d869cdc6a05124237933437aa2d26ff72cab3 100644
---- a/net/minecraft/world/entity/monster/Pillager.java
-+++ b/net/minecraft/world/entity/monster/Pillager.java
-@@ -95,6 +95,13 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.pillagerAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java
-index 3d9eae0403875a99c25ccb47888dc591f051e744..ce5cd032203839887a29008c2a1420c6bb6f4fee 100644
+index ad2913b02ded9b5087c69ba279cebfd81d9ef75e..5e6fd02985eef337f2ff8e48fbd904a064c0560a 100644
--- a/net/minecraft/world/entity/monster/Ravager.java
+++ b/net/minecraft/world/entity/monster/Ravager.java
-@@ -104,6 +104,13 @@ public class Ravager extends Raider {
+@@ -110,6 +110,13 @@ public class Ravager extends Raider {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -941,10 +905,10 @@ index 3d9eae0403875a99c25ccb47888dc591f051e744..ce5cd032203839887a29008c2a1420c6
protected void registerGoals() {
super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Shulker.java b/net/minecraft/world/entity/monster/Shulker.java
-index c26e4858a14571d58e439cabd5f2593da4ee2634..a006300aea2cbb05400550f1c79e872d095384f8 100644
+index 0a5a6f23cd8e4317db4e7c0ba8883e99f3aff148..2b73382e5bcf47da483ea88e2eae480ebb48e8f9 100644
--- a/net/minecraft/world/entity/monster/Shulker.java
+++ b/net/minecraft/world/entity/monster/Shulker.java
-@@ -136,6 +136,13 @@ public class Shulker extends AbstractGolem implements VariantHolder entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
- ) {
diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java
-index d01bc46d77340b10b23d0c0d50bddc37657028c8..241526239bdbd5d9276f85e7fca46a7051f46a25 100644
+index 758887f3fcec2bf0946cddb184e19a1c9b64eee3..37b0c8f55ed4ac4feac6a35bd4377007a19ea2ce 100644
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
-@@ -126,6 +126,13 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
+@@ -124,6 +124,13 @@ public class Strider extends Animal implements ItemSteerable {
}
// Purpur end - Make entity breeding times configurable
@@ -1067,7 +977,7 @@ index d01bc46d77340b10b23d0c0d50bddc37657028c8..241526239bdbd5d9276f85e7fca46a70
EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
) {
diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java
-index ffdb200d9716104f8df91dbeef590b2264e587b8..0ce9eb1f4108b6afab6df84d5e709be0882e515a 100644
+index 6ead673c44891c6b1c1688f80bf299527d7bc777..acd196d435758a8730569ba4e772bb954c4f85b6 100644
--- a/net/minecraft/world/entity/monster/Vex.java
+++ b/net/minecraft/world/entity/monster/Vex.java
@@ -117,6 +117,13 @@ public class Vex extends Monster implements TraceableEntity {
@@ -1084,29 +994,11 @@ index ffdb200d9716104f8df91dbeef590b2264e587b8..0ce9eb1f4108b6afab6df84d5e709be0
@Override
public boolean isFlapping() {
return this.tickCount % TICKS_PER_FLAP == 0;
-diff --git a/net/minecraft/world/entity/monster/Vindicator.java b/net/minecraft/world/entity/monster/Vindicator.java
-index 5f68d73460adfac2ead57d168156a2784af979ae..b584f71440a81ac09d24e59763a21e857f290e5a 100644
---- a/net/minecraft/world/entity/monster/Vindicator.java
-+++ b/net/minecraft/world/entity/monster/Vindicator.java
-@@ -87,6 +87,13 @@ public class Vindicator extends AbstractIllager {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.vindicatorAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void registerGoals() {
- super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java
-index 96ba35f3530ab405a960c79955699666deb6b845..e4353c64732067198f082cdd266c1f1ee1fe4f4e 100644
+index 86d9952ed0f692e8f229b0c0bcb6cacf53a00c8b..97a427faa37ce9b0c558da40d582b16ac1e96da2 100644
--- a/net/minecraft/world/entity/monster/Witch.java
+++ b/net/minecraft/world/entity/monster/Witch.java
-@@ -88,6 +88,13 @@ public class Witch extends Raider implements RangedAttackMob {
+@@ -89,6 +89,13 @@ public class Witch extends Raider implements RangedAttackMob {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -1120,29 +1012,11 @@ index 96ba35f3530ab405a960c79955699666deb6b845..e4353c64732067198f082cdd266c1f1e
@Override
protected void registerGoals() {
super.registerGoals();
-diff --git a/net/minecraft/world/entity/monster/WitherSkeleton.java b/net/minecraft/world/entity/monster/WitherSkeleton.java
-index a4dc9b7fbde19b08eb389dc42df21aa5df94e703..ff2596f69d00b36c65872ab2e27e5d44a6ffa3e1 100644
---- a/net/minecraft/world/entity/monster/WitherSkeleton.java
-+++ b/net/minecraft/world/entity/monster/WitherSkeleton.java
-@@ -66,6 +66,13 @@ public class WitherSkeleton extends AbstractSkeleton {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.witherSkeletonAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void registerGoals() {
- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true));
diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java
-index 79a4a3f4e10e1f9c1a6100060a95636075fc8236..d2a67f3e1c971f737e58567dae23fa70e9d942ea 100644
+index e2708eb836d60588c1bedb75c520e5007185034a..d6de61ed4415cd00858375406567ea9407030e1e 100644
--- a/net/minecraft/world/entity/monster/Zoglin.java
+++ b/net/minecraft/world/entity/monster/Zoglin.java
-@@ -117,6 +117,13 @@ public class Zoglin extends Monster implements HoglinBase {
+@@ -119,6 +119,13 @@ public class Zoglin extends Monster implements HoglinBase {
}
// Purpur end - Toggle for water sensitive mob damage
@@ -1156,62 +1030,8 @@ index 79a4a3f4e10e1f9c1a6100060a95636075fc8236..d2a67f3e1c971f737e58567dae23fa70
@Override
protected Brain.Provider brainProvider() {
return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
-diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
-index b1da45df27f02395d793e7eafe576f5f92aa3a7b..7af71c777dca26cd94b1807a2a77ea0d30e92976 100644
---- a/net/minecraft/world/entity/monster/Zombie.java
-+++ b/net/minecraft/world/entity/monster/Zombie.java
-@@ -147,6 +147,13 @@ public class Zombie extends Monster {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.zombieAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
-diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java
-index 94b9abc765b78a40a7ecbf4cbd775b778d49c815..1ca0514732916d325c4a76d73120aaf613c3f780 100644
---- a/net/minecraft/world/entity/monster/ZombieVillager.java
-+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
-@@ -131,6 +131,13 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.zombieVillagerAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
-diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-index 09c991d8e344f11bc84dea453042ee35c39e580e..fddbbffafea275dad187b7908386cf4c05c86743 100644
---- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-+++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-@@ -112,6 +112,13 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Mobs always drop experience
-+ @Override
-+ protected boolean isAlwaysExperienceDropper() {
-+ return this.level().purpurConfig.zombifiedPiglinAlwaysDropExp;
-+ }
-+ // Purpur end - Mobs always drop experience
-+
- @Override
- public void setPersistentAngerTarget(@Nullable UUID target) {
- this.persistentAngerTarget = target;
diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
-index 896bd531a5333d6dc8996bbdfc5c878b1a7d2da0..cf0a15ff4a49bcc17dc6dd58e91eadec0c519455 100644
+index 5e3f7005a7167c786038823a8437ad2e90a41d2c..460640f5512be6553f1ec69e20e27c7cc797068b 100644
--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
@@ -136,6 +136,13 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
@@ -1224,15 +1044,87 @@ index 896bd531a5333d6dc8996bbdfc5c878b1a7d2da0..cf0a15ff4a49bcc17dc6dd58e91eadec
+ return this.level().purpurConfig.hoglinAlwaysDropExp;
+ }
+ // Purpur end - Mobs always drop experience
++
+ @VisibleForTesting
+ public void setTimeInOverworld(int timeInOverworld) {
+ this.timeInOverworld = timeInOverworld;
+diff --git a/net/minecraft/world/entity/monster/illager/Evoker.java b/net/minecraft/world/entity/monster/illager/Evoker.java
+index c4f45f6303a46ad54991c9013608a4e5ba8b9fee..1572f7653045902fa05f0499d920eb2b2ff46931 100644
+--- a/net/minecraft/world/entity/monster/illager/Evoker.java
++++ b/net/minecraft/world/entity/monster/illager/Evoker.java
+@@ -81,6 +81,13 @@ public class Evoker extends SpellcasterIllager {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.evokerAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
+
@Override
- public boolean canBeLeashed() {
- return true;
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/illager/Illusioner.java b/net/minecraft/world/entity/monster/illager/Illusioner.java
+index 32278f51f4973d1294e52f0775697e9f5b295ee0..ea9b61b6f8463edf3497d240b010f8da3e04f62f 100644
+--- a/net/minecraft/world/entity/monster/illager/Illusioner.java
++++ b/net/minecraft/world/entity/monster/illager/Illusioner.java
+@@ -93,6 +93,13 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.illusionerAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/illager/Pillager.java b/net/minecraft/world/entity/monster/illager/Pillager.java
+index 6190286ab2f454382d497b4fce47632e6f771215..68fe150d0da04084690670f29a0a4ea035e8c921 100644
+--- a/net/minecraft/world/entity/monster/illager/Pillager.java
++++ b/net/minecraft/world/entity/monster/illager/Pillager.java
+@@ -97,6 +97,13 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.pillagerAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
+diff --git a/net/minecraft/world/entity/monster/illager/Vindicator.java b/net/minecraft/world/entity/monster/illager/Vindicator.java
+index 86b463a16e8630af4918ea43a2546995aa00244f..367c74123ee9d07795527eec6ba2f83a9e953081 100644
+--- a/net/minecraft/world/entity/monster/illager/Vindicator.java
++++ b/net/minecraft/world/entity/monster/illager/Vindicator.java
+@@ -89,6 +89,13 @@ public class Vindicator extends AbstractIllager {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.vindicatorAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ super.registerGoals();
diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java
-index 55ebfa5df06a59203248514d10dced9660ebf215..f0d78cf5fe2c39add9a673471103c352cce72a45 100644
+index d6c834914ddea76280466bf0f7d001a76af34f08..49ed463ae7ef65b2630a5b914689e04fa729a40c 100644
--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
-@@ -183,6 +183,13 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
+@@ -173,6 +173,13 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
}
// Purpur end - Toggle for water sensitive mob damage
@@ -1244,10 +1136,10 @@ index 55ebfa5df06a59203248514d10dced9660ebf215..f0d78cf5fe2c39add9a673471103c352
+ // Purpur end - Mobs always drop experience
+
@Override
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
-index 2237681f298113bda0556699e19e880f4b04a853..4984b9864b63f92bc939b530253e871ca94a3277 100644
+index 4bf2038fea712e65f420ade915a18470b79318fc..7baccc23f868ac9b8720bfd77b2af6b7dd368820 100644
--- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
+++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java
@@ -97,6 +97,13 @@ public class PiglinBrute extends AbstractPiglin {
@@ -1264,11 +1156,191 @@ index 2237681f298113bda0556699e19e880f4b04a853..4984b9864b63f92bc939b530253e871c
public static AttributeSupplier.Builder createAttributes() {
return Monster.createMonsterAttributes()
.add(Attributes.MAX_HEALTH, 50.0)
-diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
-index 97e5bb0cc335b23211e78044919282bfabad26a5..16fbe4e6521cd4f6baa8f5dd590da0fc749f6585 100644
---- a/net/minecraft/world/entity/npc/Villager.java
-+++ b/net/minecraft/world/entity/npc/Villager.java
-@@ -285,6 +285,13 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
+diff --git a/net/minecraft/world/entity/monster/skeleton/Skeleton.java b/net/minecraft/world/entity/monster/skeleton/Skeleton.java
+index 30d79be765118a50e2e2c5bfde6bf6bbc957cf40..03e441e7e9033961dbcf60e574fae48621513c87 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Skeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/Skeleton.java
+@@ -57,6 +57,13 @@ public class Skeleton extends AbstractSkeleton {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.skeletonAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/monster/skeleton/Stray.java b/net/minecraft/world/entity/monster/skeleton/Stray.java
+index ec19c49d195daff5839c991cce63b1ffc15a7e0b..5cea4ff662c7136d2778b84c21f368cb5ac1c81a 100644
+--- a/net/minecraft/world/entity/monster/skeleton/Stray.java
++++ b/net/minecraft/world/entity/monster/skeleton/Stray.java
+@@ -54,6 +54,13 @@ public class Stray extends AbstractSkeleton {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.strayAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ public static boolean checkStraySpawnRules(
+ EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
+diff --git a/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java b/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
+index 3e8cc658b333f1259784e1426896ac8b8c1537fa..40134013e3254c6c6ed370150adb4bda7c0f2d9a 100644
+--- a/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java
+@@ -66,6 +66,13 @@ public class WitherSkeleton extends AbstractSkeleton {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.witherSkeletonAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true));
+diff --git a/net/minecraft/world/entity/monster/spider/CaveSpider.java b/net/minecraft/world/entity/monster/spider/CaveSpider.java
+index fad3e951e443f04f5bf0423cde42c0ae299a4236..fb4caabbbe5bd0befdaba49ee3cfe70c326b50a7 100644
+--- a/net/minecraft/world/entity/monster/spider/CaveSpider.java
++++ b/net/minecraft/world/entity/monster/spider/CaveSpider.java
+@@ -58,6 +58,13 @@ public class CaveSpider extends Spider {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.caveSpiderAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public boolean doHurtTarget(ServerLevel level, Entity target) {
+ if (super.doHurtTarget(level, target)) {
+diff --git a/net/minecraft/world/entity/monster/spider/Spider.java b/net/minecraft/world/entity/monster/spider/Spider.java
+index 81c500de41b11d4aa6c52dc290f132ad2c23f009..7993ea937772cabe848726c942b6df0ae52e74e2 100644
+--- a/net/minecraft/world/entity/monster/spider/Spider.java
++++ b/net/minecraft/world/entity/monster/spider/Spider.java
+@@ -84,6 +84,13 @@ public class Spider extends Monster {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.spiderAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(1, new FloatGoal(this));
+diff --git a/net/minecraft/world/entity/monster/zombie/Drowned.java b/net/minecraft/world/entity/monster/zombie/Drowned.java
+index ec36b854dccae7cef905aeb2fcd4ec177828139c..abafb96df26b3d987ce3ec3e1e96e8fc20cb5b6b 100644
+--- a/net/minecraft/world/entity/monster/zombie/Drowned.java
++++ b/net/minecraft/world/entity/monster/zombie/Drowned.java
+@@ -133,6 +133,13 @@ public class Drowned extends Zombie implements RangedAttackMob {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.drownedAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void addBehaviourGoals() {
+ this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0));
+diff --git a/net/minecraft/world/entity/monster/zombie/Husk.java b/net/minecraft/world/entity/monster/zombie/Husk.java
+index 31b91dbc3f3e1875fbe6750bb815514686d14f7f..ef289dd3fe0be980c200affb0b84a1066fe52232 100644
+--- a/net/minecraft/world/entity/monster/zombie/Husk.java
++++ b/net/minecraft/world/entity/monster/zombie/Husk.java
+@@ -83,6 +83,13 @@ public class Husk extends Zombie {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.huskAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ public boolean isSunSensitive() {
+ return this.shouldBurnInDay; // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight
+diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
+index d32a831ba76f65c4719c2672ffaec81a861cc7e6..f14fc03577a94dc6bd6e536e819a32c2d6144f02 100644
+--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
++++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
+@@ -150,6 +150,13 @@ public class Zombie extends Monster {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.zombieAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+index 3da4f757d879f8b855c5d36688f1f5dd50fc88a0..a9a04a4c9cedf33b68c99b2aec12289e63fa156b 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+@@ -138,6 +138,13 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.zombieVillagerAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+ super.defineSynchedData(builder);
+diff --git a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+index 9a1da88752b0dd708365dd41a074cc0e90f36e1c..528baf4ca71725d4af6876d195b6d75fdab5ca58 100644
+--- a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+@@ -113,6 +113,13 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
+ }
+ // Purpur end - Toggle for water sensitive mob damage
+
++ // Purpur start - Mobs always drop experience
++ @Override
++ protected boolean isAlwaysExperienceDropper() {
++ return this.level().purpurConfig.zombifiedPiglinAlwaysDropExp;
++ }
++ // Purpur end - Mobs always drop experience
++
+ @Override
+ protected void addBehaviourGoals() {
+ this.goalSelector.addGoal(1, new SpearUseGoal<>(this, 1.0, 1.0, 10.0F, 2.0F));
+diff --git a/net/minecraft/world/entity/npc/villager/Villager.java b/net/minecraft/world/entity/npc/villager/Villager.java
+index b6bfe06a2ad8e4219d99de050b30ce1ad15b8b34..996468c21a79d698a8d842189ffd4f2dc86a4302 100644
+--- a/net/minecraft/world/entity/npc/villager/Villager.java
++++ b/net/minecraft/world/entity/npc/villager/Villager.java
+@@ -289,6 +289,13 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
// Purpur end - Toggle for water sensitive mob damage
@@ -1282,11 +1354,11 @@ index 97e5bb0cc335b23211e78044919282bfabad26a5..16fbe4e6521cd4f6baa8f5dd590da0fc
@Override
public Brain getBrain() {
return (Brain)super.getBrain();
-diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java
-index 8046a2d640e7c4d59cb5b9c6dff3bf5f026c7153..c3fbcc7956a64d49466874776f257ba27f55f2a4 100644
---- a/net/minecraft/world/entity/npc/WanderingTrader.java
-+++ b/net/minecraft/world/entity/npc/WanderingTrader.java
-@@ -114,6 +114,13 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
+diff --git a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+index cabebbc25788a8c41912f97dac85af41c9433b68..9502fe0c4f125f5802fde032954c447b14435da2 100644
+--- a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
++++ b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java
+@@ -106,6 +106,13 @@ public class WanderingTrader extends AbstractVillager implements Consumable.Over
}
// Purpur end - Toggle for water sensitive mob damage
diff --git a/purpur-server/minecraft-patches/features/0020-Cows-naturally-aggressive-to-players-chance.patch b/purpur-server/minecraft-patches/features/0020-Cows-naturally-aggressive-to-players-chance.patch
deleted file mode 100644
index 9df4054e7..000000000
--- a/purpur-server/minecraft-patches/features/0020-Cows-naturally-aggressive-to-players-chance.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Blake Galbreath
-Date: Mon, 30 Aug 2021 22:49:53 -0500
-Subject: [PATCH] Cows naturally aggressive to players chance
-
-
-diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java
-index a8c76fcbbaa4afd2d0bd568874995b91d8d67c03..b62c4449047da36d8b4d4b87d03c77906d12dc31 100644
---- a/net/minecraft/world/entity/animal/Cow.java
-+++ b/net/minecraft/world/entity/animal/Cow.java
-@@ -32,6 +32,8 @@ import net.minecraft.world.level.Level;
- import net.minecraft.world.level.block.state.BlockState;
-
- public class Cow extends Animal {
-+ private boolean isNaturallyAggressiveToPlayers; // Purpur - Cows naturally aggressive to players chance
-+
- private static final EntityDimensions BABY_DIMENSIONS = EntityType.COW.getDimensions().scale(0.5F).withEyeHeight(0.665F);
-
- public Cow(EntityType extends Cow> entityType, Level level) {
-@@ -60,6 +62,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 - Cows naturally aggressive to players chance
- }
- // Purpur end - Configurable entity base attributes
-
-@@ -77,17 +80,27 @@ public class Cow extends Animal {
- }
- // Purpur end - Toggle for water sensitive mob damage
-
-+ // Purpur start - Cows naturally aggressive to players chance
-+ @Override
-+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.EntitySpawnReason 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);
-+ }
-+ // Purpur end - Cows naturally aggressive to players chance
-+
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new FloatGoal(this));
- this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables
- this.goalSelector.addGoal(1, new PanicGoal(this, 2.0));
-+ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - Cows naturally aggressive to players chance
- this.goalSelector.addGoal(2, new BreedGoal(this, 1.0));
- this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, itemStack -> 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), false)); // Purpur - Cows eat mushrooms
- this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25));
- this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0));
- 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, (ignored, ignored2) -> isNaturallyAggressiveToPlayers)); // Purpur - Cows naturally aggressive to players chance
- }
-
- @Override
-@@ -96,7 +109,7 @@ public class Cow extends Animal {
- }
-
- public static AttributeSupplier.Builder createAttributes() {
-- return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.MOVEMENT_SPEED, 0.2F);
-+ return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.MOVEMENT_SPEED, 0.2F).add(Attributes.ATTACK_DAMAGE, 0.0D); // Purpur - Cows naturally aggressive to players chance
- }
-
- @Override
diff --git a/purpur-server/minecraft-patches/features/0008-Configurable-void-damage-height-and-damage.patch b/purpur-server/minecraft-patches/features/0020-Setting-to-reintroduce-end-void-rings.patch
similarity index 64%
rename from purpur-server/minecraft-patches/features/0008-Configurable-void-damage-height-and-damage.patch
rename to purpur-server/minecraft-patches/features/0020-Setting-to-reintroduce-end-void-rings.patch
index e666f3848..0c35dd916 100644
--- a/purpur-server/minecraft-patches/features/0008-Configurable-void-damage-height-and-damage.patch
+++ b/purpur-server/minecraft-patches/features/0020-Setting-to-reintroduce-end-void-rings.patch
@@ -1,41 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Blake Galbreath
-Date: Thu, 27 Feb 2020 21:42:19 -0600
-Subject: [PATCH] Configurable void damage height and damage
+From: granny
+Date: Mon, 8 Dec 2025 17:02:40 -0800
+Subject: [PATCH] Setting to reintroduce end void rings
-temporarily migrate to paper's config
-drop patch on the next minecraft release
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
-index 9afbfe9bf493e09ca1963e8956ab7573964479b4..d04c06fafd133f773f311e7c2708fa8b049da67c 100644
+index cfd9596246713030f7c0f28a65abeed6dcc8d81b..952444a26fd13ae0b385b2b7f717d965b4c76d19 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
-@@ -1222,6 +1222,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getSupportedHeldProjectiles();
ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedHeldProjectiles);
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
-index 43657822f0660613078e9afa512000b5255a1537..a5284118fa4c3c2fff52c8220615c9ca848d9af0 100644
+index 053d51070df51e901bdf8f0f33316e4f25ea9a2f..214b915712538f98811b4efde8bf360202a2ef49 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
-@@ -2294,6 +2294,12 @@ public abstract class Player extends LivingEntity {
+@@ -2089,6 +2089,12 @@ public abstract class Player extends Avatar implements ContainerUser {
@Override
public ItemStack getProjectile(ItemStack shootable) {
@@ -54,11 +54,10 @@ index 43657822f0660613078e9afa512000b5255a1537..a5284118fa4c3c2fff52c8220615c9ca
if (!(shootable.getItem() instanceof ProjectileWeaponItem)) {
return ItemStack.EMPTY;
} else {
-@@ -2306,6 +2312,39 @@ public abstract class Player extends LivingEntity {
+@@ -2102,6 +2108,37 @@ public abstract class Player extends Avatar implements ContainerUser {
for (int i = 0; i < this.inventory.getContainerSize(); i++) {
ItemStack item = this.inventory.getItem(i);
-+
+ // Purpur start - config for turning bundles into functional quivers
+ if ((this.level().purpurConfig.bowUseBundleAsQuiver || this.level().purpurConfig.crossbowUseBundleAsQuiver) && !this.abilities.instabuild && item.getItem() instanceof net.minecraft.world.item.BundleItem) {
+ net.minecraft.world.item.component.BundleContents bundleContents = item.get(net.minecraft.core.component.DataComponents.BUNDLE_CONTENTS);
@@ -90,12 +89,11 @@ index 43657822f0660613078e9afa512000b5255a1537..a5284118fa4c3c2fff52c8220615c9ca
+ return itemStack;
+ }
+ // Purpur end - config for turning bundles into functional quivers
-+
if (supportedHeldProjectiles.test(item)) {
return item;
}
diff --git a/net/minecraft/world/item/BowItem.java b/net/minecraft/world/item/BowItem.java
-index b3e003694ce0da357e91ab3ce2b1380f9ab0a32a..186bd391ed3738734ca2d8e82339af0158ae4875 100644
+index 0a14a098f3aa40c8195c3a3bdf61ad6ae0fcc9d2..06cd5f1664d2f02fe36a16e675dfbb7ebf66751c 100644
--- a/net/minecraft/world/item/BowItem.java
+++ b/net/minecraft/world/item/BowItem.java
@@ -27,7 +27,7 @@ public class BowItem extends ProjectileWeaponItem {
@@ -108,10 +106,10 @@ index b3e003694ce0da357e91ab3ce2b1380f9ab0a32a..186bd391ed3738734ca2d8e82339af01
if (level.purpurConfig.infinityWorksWithoutArrows && projectile.isEmpty() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, stack) > 0) {
projectile = new ItemStack(Items.ARROW);
diff --git a/net/minecraft/world/item/BundleItem.java b/net/minecraft/world/item/BundleItem.java
-index 966029b761bcb31113b167831fe7f4f2dea4b17d..eda25cc71b4804d805b1a7f875f823b20efc754b 100644
+index 79f3955cbf3a19b013d86180d8dda576ab4c25cd..8eae89acdfdc15a3a2ebfa72ea5a2c4282fdf770 100644
--- a/net/minecraft/world/item/BundleItem.java
+++ b/net/minecraft/world/item/BundleItem.java
-@@ -131,7 +131,7 @@ public class BundleItem extends Item {
+@@ -132,7 +132,7 @@ public class BundleItem extends Item {
}
private void dropContent(Level level, Player player, ItemStack stack) {
@@ -121,10 +119,10 @@ index 966029b761bcb31113b167831fe7f4f2dea4b17d..eda25cc71b4804d805b1a7f875f823b2
player.awardStat(Stats.ITEM_USED.get(this));
}
diff --git a/net/minecraft/world/item/CrossbowItem.java b/net/minecraft/world/item/CrossbowItem.java
-index 1131e984fd30e40c1b99054b5db9462ffe55b5f1..c9dbe63316cad0437f50fa3f7ffe345ec1906752 100644
+index a29ff7584371d35d9b0fff71681f672b76dea07c..d1d450fa22f5deb766b39f2c34d4cf7cda944644 100644
--- a/net/minecraft/world/item/CrossbowItem.java
+++ b/net/minecraft/world/item/CrossbowItem.java
-@@ -72,7 +72,7 @@ public class CrossbowItem extends ProjectileWeaponItem {
+@@ -68,7 +68,7 @@ public class CrossbowItem extends ProjectileWeaponItem {
if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) {
this.performShooting(level, player, hand, itemInHand, getShootingPower(chargedProjectiles), (float) level.purpurConfig.crossbowProjectileOffset, null); // Purpur - Projectile offset config
return InteractionResult.CONSUME;
@@ -133,9 +131,9 @@ index 1131e984fd30e40c1b99054b5db9462ffe55b5f1..c9dbe63316cad0437f50fa3f7ffe345e
this.startSoundPlayed = false;
this.midLoadSoundPlayed = false;
player.startUsingItem(hand);
-@@ -124,7 +124,7 @@ public class CrossbowItem extends ProjectileWeaponItem {
- return CrossbowItem.tryLoadProjectiles(shooter, crossbowStack, true);
+@@ -95,7 +95,7 @@ public class CrossbowItem extends ProjectileWeaponItem {
}
+
private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbowStack, boolean consume) {
- List list = draw(crossbowStack, shooter.getProjectile(crossbowStack), shooter, consume);
+ List list = draw(crossbowStack, shooter.getProjectile(crossbowStack, true), shooter, consume); // Purpur - config for turning bundles into functional quivers
@@ -143,10 +141,10 @@ index 1131e984fd30e40c1b99054b5db9462ffe55b5f1..c9dbe63316cad0437f50fa3f7ffe345e
if (!list.isEmpty()) {
crossbowStack.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(list));
diff --git a/net/minecraft/world/item/component/BundleContents.java b/net/minecraft/world/item/component/BundleContents.java
-index fca2dd0fb9ff4ff795a01de722fbb31dc02682fa..6fb9becef49bd4161c7829d240dd9e786f2226b5 100644
+index e513f95105b0663bd6155e69ac814bc8dbba5b76..2bf687e86ae6d0117f7c72e535f6841eaeefd2ea 100644
--- a/net/minecraft/world/item/component/BundleContents.java
+++ b/net/minecraft/world/item/component/BundleContents.java
-@@ -163,7 +163,12 @@ public final class BundleContents implements TooltipComponent {
+@@ -164,7 +164,12 @@ public final class BundleContents implements TooltipComponent {
}
private int findStackIndex(ItemStack stack) {
@@ -160,20 +158,19 @@ index fca2dd0fb9ff4ff795a01de722fbb31dc02682fa..6fb9becef49bd4161c7829d240dd9e78
return -1;
} else {
for (int i = 0; i < this.items.size(); i++) {
-@@ -223,11 +228,20 @@ public final class BundleContents implements TooltipComponent {
+@@ -227,11 +232,19 @@ public final class BundleContents implements TooltipComponent {
+ }
- @Nullable
- public ItemStack removeOne() {
-+ // Purpur start - config for turning bundles into functional quivers
+ public @Nullable ItemStack removeOne() {
++ // Purpur start - config for turning bundles into functional quivers
+ return this.removeOne(null);
+ }
-+ @Nullable
-+ public ItemStack removeOne(ItemStack itemStack2) {
-+ // Purpur end - config for turning bundles into functional quivers
++ public @Nullable ItemStack removeOne(ItemStack itemStack2) {
++ // Purpur end - config for turning bundles into functional quivers
if (this.items.isEmpty()) {
return null;
} else {
- int i = this.selectedItem != -1 && this.selectedItem < this.items.size() ? this.selectedItem : 0;
+ int i = this.indexIsOutsideAllowedBounds(this.selectedItem) ? 0 : this.selectedItem;
- ItemStack itemStack = this.items.remove(i).copy();
+ // Purpur start - config for turning bundles into functional quivers
+ int stackIndex = itemStack2 != null ? this.findStackIndex(itemStack2, true) : -1;
diff --git a/purpur-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch b/purpur-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch
index cca45cce0..70f8de868 100644
--- a/purpur-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch
+++ b/purpur-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch
@@ -1,6 +1,6 @@
--- a/io/papermc/paper/entity/activation/ActivationRange.java
+++ b/io/papermc/paper/entity/activation/ActivationRange.java
-@@ -141,6 +_,8 @@
+@@ -147,6 +_,8 @@
continue;
}
@@ -9,11 +9,11 @@
final int worldHeight = world.getHeight();
ActivationRange.maxBB = player.getBoundingBox().inflate(maxRange, worldHeight, maxRange);
ActivationType.MISC.boundingBox = player.getBoundingBox().inflate(miscActivationRange, worldHeight, miscActivationRange);
-@@ -282,6 +_,7 @@
+@@ -288,6 +_,7 @@
* @return
*/
public static boolean checkIfActive(final Entity entity) {
-+ if (entity.level().purpurConfig.squidImmuneToEAR && entity instanceof net.minecraft.world.entity.animal.Squid) return true; // Purpur - Squid EAR immunity
++ if (entity.level().purpurConfig.squidImmuneToEAR && entity instanceof net.minecraft.world.entity.animal.squid.Squid) return true; // Purpur - Squid EAR immunity
// Never safe to skip fireworks or item gravity
if (entity instanceof FireworkRocketEntity || (entity instanceof ItemEntity && (entity.tickCount + entity.getId()) % 4 == 0)) { // Needed for item gravity, see ItemEntity tick
return true;
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/CrashReport.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/CrashReport.java.patch
index 52cafd0d1..736446dfb 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/CrashReport.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/CrashReport.java.patch
@@ -16,8 +16,8 @@
+ return this.getFriendlyReport(type, extraInfo); // Purpur - Rebrand
}
- @Nullable
-@@ -161,7 +_,7 @@
+ public @Nullable Path getSaveFile() {
+@@ -160,7 +_,7 @@
}
public boolean saveToFile(Path path, ReportType type) {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/commands/CommandSourceStack.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/commands/CommandSourceStack.java.patch
index 1a48edcf9..a94b0ea45 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/commands/CommandSourceStack.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/commands/CommandSourceStack.java.patch
@@ -1,12 +1,12 @@
--- a/net/minecraft/commands/CommandSourceStack.java
+++ b/net/minecraft/commands/CommandSourceStack.java
-@@ -455,6 +_,19 @@
+@@ -430,6 +_,19 @@
}
// CraftBukkit end
+ // Purpur start - Gamemode extra permissions
-+ public boolean testPermission(int i, String bukkitPermission) {
-+ if (hasPermission(i, bukkitPermission)) {
++ public boolean testPermission(net.minecraft.server.permissions.Permission permission, String bukkitPermission) {
++ if (hasPermission(permission, bukkitPermission)) {
+ return true;
+ }
+ net.kyori.adventure.text.Component permissionMessage = getLevel().getServer().server.permissionMessage();
@@ -20,7 +20,7 @@
public Vec3 getPosition() {
return this.worldPosition;
}
-@@ -540,6 +_,30 @@
+@@ -512,6 +_,30 @@
}
}
}
@@ -37,11 +37,11 @@
+ sendSuccess(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message), broadcastToOps);
+ }
+
-+ public void sendSuccess(@Nullable net.kyori.adventure.text.Component message) {
++ public void sendSuccess(net.kyori.adventure.text.@Nullable Component message) {
+ sendSuccess(message, false);
+ }
+
-+ public void sendSuccess(@Nullable net.kyori.adventure.text.Component message, boolean broadcastToOps) {
++ public void sendSuccess(net.kyori.adventure.text.@Nullable Component message, boolean broadcastToOps) {
+ if (message == null) {
+ return;
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/commands/Commands.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/commands/Commands.java.patch
index f6226f550..85a32af62 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/commands/Commands.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/commands/Commands.java.patch
@@ -1,17 +1,20 @@
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
-@@ -216,8 +_,8 @@
+@@ -265,11 +_,11 @@
JfrCommand.register(this.dispatcher);
}
-- if (SharedConstants.IS_RUNNING_IN_IDE) {
-- TestCommand.register(this.dispatcher);
-+ if (org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands || SharedConstants.IS_RUNNING_IN_IDE) { // Purpur - register minecraft debug commands
-+ if (!org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands) TestCommand.register(this.dispatcher); // Purpur - register minecraft debug commands
+- if (SharedConstants.DEBUG_CHASE_COMMAND) {
++ if (org.purpurmc.purpur.PurpurConfig.registerMinecraftDisabledCommands || SharedConstants.DEBUG_CHASE_COMMAND) { // Purpur - register disabled minecraft commands
+ ChaseCommand.register(this.dispatcher);
+ }
+
+- if (SharedConstants.DEBUG_DEV_COMMANDS || SharedConstants.IS_RUNNING_IN_IDE) {
++ if (org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands || SharedConstants.DEBUG_DEV_COMMANDS || SharedConstants.IS_RUNNING_IN_IDE) { // Purpur - register minecraft debug commands
RaidCommand.register(this.dispatcher, context);
DebugPathCommand.register(this.dispatcher);
DebugMobSpawningCommand.register(this.dispatcher);
-@@ -245,6 +_,14 @@
+@@ -297,6 +_,14 @@
StopCommand.register(this.dispatcher);
TransferCommand.register(this.dispatcher);
WhitelistCommand.register(this.dispatcher);
@@ -26,19 +29,20 @@
}
if (selection.includeIntegrated) {
-@@ -488,6 +_,7 @@
- private void runSync(ServerPlayer player, java.util.Collection bukkit, RootCommandNode rootCommandNode) {
+@@ -522,6 +_,7 @@
+ private void runSync(ServerPlayer player, java.util.Collection bukkit, RootCommandNode rootCommandNode) {
// Paper end - Perf: Async command map building
new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootCommandNode, true).callEvent(); // Paper - Brigadier API
+ if (org.bukkit.event.player.PlayerCommandSendEvent.getHandlerList().getRegisteredListeners().length > 0) { // Purpur - Skip events if there's no listeners
org.bukkit.event.player.PlayerCommandSendEvent event = new org.bukkit.event.player.PlayerCommandSendEvent(player.getBukkitEntity(), new java.util.LinkedHashSet<>(bukkit));
event.getPlayer().getServer().getPluginManager().callEvent(event);
-@@ -498,6 +_,7 @@
+@@ -532,6 +_,8 @@
}
}
// CraftBukkit end
+ } // Purpur - Skip events if there's no listeners
-
- player.connection.send(new ClientboundCommandsPacket(rootCommandNode));
++
+ player.connection.send(new ClientboundCommandsPacket(rootCommandNode, COMMAND_NODE_INSPECTOR));
}
+
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch
index c89e997d6..9c23cd46d 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/commands/arguments/selector/EntitySelector.java
+++ b/net/minecraft/commands/arguments/selector/EntitySelector.java
-@@ -192,26 +_,27 @@
+@@ -190,26 +_,27 @@
this.checkPermissions(source);
if (this.playerName != null) {
ServerPlayer playerByName = source.getServer().getPlayerList().getPlayerByName(this.playerName);
@@ -32,7 +32,7 @@
players.add(serverPlayer1);
if (players.size() >= resultLimit) {
return players;
-@@ -270,4 +_,10 @@
+@@ -267,4 +_,10 @@
public static Component joinNames(List extends Entity> names) {
return ComponentUtils.formatList(names, Entity::getDisplayName);
}
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch
index 8b669b1d6..0d1842e69 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/core/BlockPos.java
+++ b/net/minecraft/core/BlockPos.java
-@@ -63,6 +_,12 @@
+@@ -61,6 +_,12 @@
public static final int MAX_HORIZONTAL_COORDINATE = 33554431;
// Paper end - Optimize Bit Operations by inlining
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch
index 067298651..533c3c88a 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
-@@ -892,5 +_,22 @@
+@@ -750,5 +_,22 @@
DispenserBlock.registerBehavior(Items.TNT_MINECART, new MinecartDispenseItemBehavior(EntityType.TNT_MINECART));
DispenserBlock.registerBehavior(Items.HOPPER_MINECART, new MinecartDispenseItemBehavior(EntityType.HOPPER_MINECART));
DispenserBlock.registerBehavior(Items.COMMAND_BLOCK_MINECART, new MinecartDispenseItemBehavior(EntityType.COMMAND_BLOCK_MINECART));
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch
index c0e69aa51..9a2c1e083 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
-@@ -31,7 +_,7 @@
+@@ -32,7 +_,7 @@
return false;
} else {
LivingEntity livingEntity = entitiesOfClass.getFirst();
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/GameTestHelper.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/GameTestHelper.java.patch
index 2076037b3..5a40e03dc 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/GameTestHelper.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/GameTestHelper.java.patch
@@ -1,11 +1,11 @@
--- a/net/minecraft/gametest/framework/GameTestHelper.java
+++ b/net/minecraft/gametest/framework/GameTestHelper.java
-@@ -279,6 +_,8 @@
- return gameType.isCreative();
+@@ -322,6 +_,8 @@
+ return gameType;
}
+ public void setAfk(final boolean afk) {} // Purpur - AFK API
+
@Override
- public boolean isLocalPlayer() {
- return true;
+ public boolean isClientAuthoritative() {
+ return false;
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/TestCommand.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/TestCommand.java.patch
new file mode 100644
index 000000000..c9f48d7e7
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/TestCommand.java.patch
@@ -0,0 +1,11 @@
+--- a/net/minecraft/gametest/framework/TestCommand.java
++++ b/net/minecraft/gametest/framework/TestCommand.java
+@@ -443,7 +_,7 @@
+ )
+ )
+ );
+- if (SharedConstants.IS_RUNNING_IN_IDE) {
++ if (org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands || SharedConstants.IS_RUNNING_IN_IDE) { // Purpur - register minecraft debug commands
+ literalArgumentBuilder = literalArgumentBuilder.then(
+ Commands.literal("export")
+ .then(
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch
index ac6b9a64d..2d95e190f 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
-@@ -588,11 +_,20 @@
+@@ -554,11 +_,20 @@
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
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch
index 60c29bda0..4d67b4695 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/network/chat/SignedMessageChain.java
+++ b/net/minecraft/network/chat/SignedMessageChain.java
-@@ -45,7 +_,7 @@
+@@ -44,7 +_,7 @@
SignedMessageLink signedMessageLink = SignedMessageChain.this.nextLink;
if (signedMessageLink == null) {
throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.CHAIN_BROKEN);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/Main.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/Main.java.patch
index 16550b7e6..2b6f384e7 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/Main.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/Main.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/server/Main.java
+++ b/net/minecraft/server/Main.java
-@@ -108,6 +_,12 @@
+@@ -105,6 +_,13 @@
JvmProfiler.INSTANCE.start(Environment.SERVER);
}
@@ -8,6 +8,7 @@
+ 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", true);
+ org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands = purpurConfiguration.getBoolean("settings.register-minecraft-debug-commands"); // Purpur - register minecraft debug commands
++ org.purpurmc.purpur.PurpurConfig.registerMinecraftDisabledCommands = purpurConfiguration.getBoolean("settings.register-minecraft-disabled-commands"); // Purpur - register disabled minecraft commands
+ // Purpur end - Add toggle for enchant level clamping - load config files early
+
io.papermc.paper.plugin.PluginInitializerManager.load(optionSet); // Paper
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch
index a3769afc7..9d58a48aa 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
-@@ -284,6 +_,7 @@
+@@ -290,6 +_,7 @@
public joptsimple.OptionSet options;
public org.bukkit.command.ConsoleCommandSender console;
public static int currentTick; // Paper - improve tick loop
@@ -8,26 +8,24 @@
public java.util.Queue processQueue = new java.util.concurrent.ConcurrentLinkedQueue();
public int autosavePeriod;
// Paper - don't store the vanilla dispatcher
-@@ -294,7 +_,7 @@
- public static final int TICK_TIME = 1000000000 / MinecraftServer.TPS;
- private static final int SAMPLE_INTERVAL = 20; // Paper - improve server tick loop
- @Deprecated(forRemoval = true) // Paper
-- public final double[] recentTps = new double[3];
-+ public final double[] recentTps = new double[4]; // Purpur - Add 5 second tps average in /tps
- // Spigot end
- public volatile boolean hasFullyShutdown; // Paper - Improved watchdog support
- public volatile boolean abnormalExit; // Paper - Improved watchdog support
-@@ -302,7 +_,9 @@
- public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files
+@@ -306,6 +_,8 @@
public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
private final Set pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
-+ public boolean lagging = false; // Purpur - Lagging threshold
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
++ public boolean lagging = false; // Purpur - Lagging threshold
+ protected boolean upnp = false; // Purpur - UPnP Port Forwarding
-
- public static S spin(Function threadFunction) {
- ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
-@@ -1001,6 +_,15 @@
+ // Paper start - improve tick loop
+ public final ca.spottedleaf.moonrise.common.time.TickData tickTimes1s = new ca.spottedleaf.moonrise.common.time.TickData(java.util.concurrent.TimeUnit.SECONDS.toNanos(1L));
+ public final ca.spottedleaf.moonrise.common.time.TickData tickTimes5s = new ca.spottedleaf.moonrise.common.time.TickData(java.util.concurrent.TimeUnit.SECONDS.toNanos(5L));
+@@ -375,6 +_,7 @@
+ public double[] computeTPS() {
+ final long interval = this.tickRateManager().nanosecondsPerTick();
+ return new double[] {
++ getTPS(this.tickTimes5s, interval), // Purpur - Add 5 second tps average in /tps
+ getTPS(this.tickTimes1m, interval),
+ getTPS(this.tickTimes5m, interval),
+ getTPS(this.tickTimes15m, interval)
+@@ -1016,6 +_,15 @@
LOGGER.info("Stopping server");
Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing
@@ -43,24 +41,16 @@
// CraftBukkit start
if (this.server != null) {
this.server.spark.disable(); // Paper - spark
-@@ -1093,6 +_,8 @@
- this.safeShutdown(waitForServer, false);
+@@ -1114,6 +_,8 @@
+ this.safeShutdown(waitForShutdown, false);
}
- public void safeShutdown(boolean waitForServer, boolean isRestarting) {
+ public void safeShutdown(boolean waitForShutdown, boolean isRestarting) {
+ org.purpurmc.purpur.task.BossBarTask.stopAll(); // Purpur - Implement TPSBar
+ org.purpurmc.purpur.task.BeehiveTask.instance().unregister(); // Purpur - Give bee counts in beehives to Purpur clients
this.isRestarting = isRestarting;
this.hasLoggedStop = true; // Paper - Debugging
if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
-@@ -1112,6 +_,7 @@
- private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L;
- private long lastTick = 0;
- private long catchupTime = 0;
-+ public final RollingAverage tps5s = new RollingAverage(5); // Purpur - Add 5 second tps average in /tps
- public final RollingAverage tps1 = new RollingAverage(60);
- public final RollingAverage tps5 = new RollingAverage(60 * 5);
- public final RollingAverage tps15 = new RollingAverage(60 * 15);
-@@ -1197,6 +_,16 @@
+@@ -1291,6 +_,16 @@
}
// Paper end - Add onboarding message for initial server start
@@ -75,45 +65,21 @@
+ // Purpur end - config for startup commands
+
while (this.running) {
- long l;
- if (!this.isPaused() && this.tickRateManager.isSprinting() && this.tickRateManager.checkShouldSprintThisTick()) {
-@@ -1221,14 +_,19 @@
- if (++MinecraftServer.currentTick % MinecraftServer.SAMPLE_INTERVAL == 0) {
- final long diff = currentTime - tickSection;
- final java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP);
-+ tps5s.add(currentTps, diff); // Purpur - Add 5 second tps average in /tps
- tps1.add(currentTps, diff);
- tps5.add(currentTps, diff);
- tps15.add(currentTps, diff);
+ final long tickStart = System.nanoTime(); // Paper - improve tick loop
+ long l; // Paper - improve tick loop - diff on change, expect this to be tick interval
+@@ -1304,8 +_,10 @@
+ final long ticksBehind = Math.max(1L, this.tickSchedule.getPeriodsAhead(l, tickStart));
+ final long catchup = (long)Math.max(
+ 1,
+- 5 //ConfigHolder.getConfig().tickLoop.catchupTicks.getOrDefault(MoonriseConfig.TickLoop.DEFAULT_CATCHUP_TICKS).intValue()
++ org.purpurmc.purpur.PurpurConfig.tpsCatchup ? 5 : 1 //ConfigHolder.getConfig().tickLoop.catchupTicks.getOrDefault(MoonriseConfig.TickLoop.DEFAULT_CATCHUP_TICKS).intValue() // Purpur - Configurable TPS Catchup
+ );
++
++ lagging = getTPS()[0] < org.purpurmc.purpur.PurpurConfig.laggingThreshold; // Purpur - Lagging threshold
- // Backwards compat with bad plugins
-- this.recentTps[0] = tps1.getAverage();
-- this.recentTps[1] = tps5.getAverage();
-- this.recentTps[2] = tps15.getAverage();
-+ // Purpur start - Add 5 second tps average in /tps
-+ this.recentTps[0] = tps5s.getAverage();
-+ this.recentTps[1] = tps1.getAverage();
-+ this.recentTps[2] = tps5.getAverage();
-+ this.recentTps[3] = tps15.getAverage();
-+ // Purpur end - Add 5 second tps average in /tps
-+ lagging = recentTps[0] < org.purpurmc.purpur.PurpurConfig.laggingThreshold; // Purpur - Lagging threshold
- tickSection = currentTime;
- }
- // Paper end - further improve server tick loop
-@@ -1260,6 +_,12 @@
- profilerFiller.popPush("nextTickWait");
- this.mayHaveDelayedTasks = true;
- this.delayedTasksMaxNextTickTimeNanos = Math.max(Util.getNanos() + l, this.nextTickTimeNanos);
-+ // Purpur start - Configurable TPS Catchup
-+ if (!org.purpurmc.purpur.PurpurConfig.tpsCatchup /*|| !gg.pufferfish.pufferfish.PufferfishConfig.tpsCatchup*/) { // Purpur - Configurable TPS Catchup
-+ this.nextTickTimeNanos = currentTime + l;
-+ this.delayedTasksMaxNextTickTimeNanos = nextTickTimeNanos;
-+ }
-+ // Purpur end - Configurable TPS Catchup
- this.startMeasuringTaskExecutionTime();
- this.waitUntilNextTick();
- this.finishMeasuringTaskExecutionTime();
-@@ -1690,7 +_,7 @@
+ // adjust ticksBehind so that it is not greater-than catchup
+ if (ticksBehind > catchup) {
+@@ -1787,7 +_,7 @@
long worldTime = level.getGameTime();
final ClientboundSetTimePacket worldPacket = new ClientboundSetTimePacket(worldTime, dayTime, doDaylight);
for (Player entityhuman : level.players()) {
@@ -122,7 +88,7 @@
continue;
}
ServerPlayer entityplayer = (ServerPlayer) entityhuman;
-@@ -1855,7 +_,7 @@
+@@ -1954,7 +_,7 @@
@DontObfuscate
public String getServerModName() {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/PlayerAdvancements.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/PlayerAdvancements.java.patch
index 423015dc4..a029c0fb0 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/PlayerAdvancements.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/PlayerAdvancements.java.patch
@@ -1,17 +1,17 @@
--- a/net/minecraft/server/PlayerAdvancements.java
+++ b/net/minecraft/server/PlayerAdvancements.java
-@@ -148,6 +_,7 @@
+@@ -146,6 +_,7 @@
AdvancementHolder advancementHolder = advancementManager.get(path);
if (advancementHolder == null) {
- if (!path.getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) return; // CraftBukkit
+ if (!path.getNamespace().equals(Identifier.DEFAULT_NAMESPACE)) return; // CraftBukkit
+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressIgnoredAdvancementWarnings) // Purpur - Logger settings (suppressing pointless logs)
LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", path, this.playerSavePath);
} else {
this.startProgress(advancementHolder, progress);
-@@ -195,6 +_,7 @@
+@@ -193,6 +_,7 @@
advancement.value().display().ifPresent(displayInfo -> {
// Paper start - Add Adventure message to PlayerAdvancementDoneEvent
- if (event.message() != null && this.player.serverLevel().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) {
+ if (event.message() != null && this.player.level().getGameRules().get(GameRules.SHOW_ADVANCEMENT_MESSAGES)) {
+ if (org.purpurmc.purpur.PurpurConfig.advancementOnlyBroadcastToAffectedPlayer) this.player.sendMessage(message); else // Purpur - Configurable broadcast settings
this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false);
// Paper end
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/EnchantCommand.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/EnchantCommand.java.patch
index 74bd1f710..6379c1d94 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/EnchantCommand.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/EnchantCommand.java.patch
@@ -9,7 +9,7 @@
throw ERROR_LEVEL_TOO_HIGH.create(level, enchantment1.getMaxLevel());
} else {
int i = 0;
-@@ -81,7 +_,7 @@
+@@ -80,7 +_,7 @@
ItemStack mainHandItem = livingEntity.getMainHandItem();
if (!mainHandItem.isEmpty()) {
if (enchantment1.canEnchant(mainHandItem)
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch
index b1ef32c8b..f06984320 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch
@@ -1,17 +1,17 @@
--- a/net/minecraft/server/commands/GameModeCommand.java
+++ b/net/minecraft/server/commands/GameModeCommand.java
-@@ -51,6 +_,18 @@
+@@ -53,6 +_,18 @@
}
- private static int setMode(CommandContext source, Collection players, GameType gameType) {
+ private static int setMode(CommandContext context, Collection players, GameType gameType) {
+ // Purpur start - Gamemode extra permissions
+ if (org.purpurmc.purpur.PurpurConfig.commandGamemodeRequiresPermission) {
+ String gamemode = gameType.getName();
-+ CommandSourceStack sender = source.getSource();
-+ if (!sender.testPermission(2, "minecraft.command.gamemode." + gamemode)) {
++ CommandSourceStack sender = context.getSource();
++ if (!sender.testPermission(Permissions.COMMANDS_GAMEMASTER, "minecraft.command.gamemode." + gamemode)) {
+ return 0;
+ }
-+ if (sender.getEntity() instanceof ServerPlayer player && (players.size() > 1 || !players.contains(player)) && !sender.testPermission(2, "minecraft.command.gamemode." + gamemode + ".other")) {
++ if (sender.getEntity() instanceof ServerPlayer player && (players.size() > 1 || !players.contains(player)) && !sender.testPermission(Permissions.COMMANDS_GAMEMASTER, "minecraft.command.gamemode." + gamemode + ".other")) {
+ return 0;
+ }
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GiveCommand.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GiveCommand.java.patch
index 5cedf347f..8037f0654 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GiveCommand.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GiveCommand.java.patch
@@ -1,10 +1,10 @@
--- a/net/minecraft/server/commands/GiveCommand.java
+++ b/net/minecraft/server/commands/GiveCommand.java
-@@ -66,6 +_,7 @@
+@@ -68,6 +_,7 @@
i1 -= min;
ItemStack itemStack1 = item.createItemStack(min, false);
boolean flag = serverPlayer.getInventory().add(itemStack1);
+ if (org.purpurmc.purpur.PurpurConfig.disableGiveCommandDrops) continue; // Purpur - add config option for toggling give command dropping
if (flag && itemStack1.isEmpty()) {
- ItemEntity itemEntity = serverPlayer.drop(itemStack, false, false, false); // CraftBukkit - SPIGOT-2942: Add boolean to call event
+ ItemEntity itemEntity = serverPlayer.drop(itemStack, false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command
if (itemEntity != null) {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch
index af8b6989d..8230e207e 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch
@@ -1,18 +1,18 @@
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
-@@ -106,6 +_,7 @@
- // CraftBukkit start
- if (!org.bukkit.craftbukkit.Main.useConsole) return;
+@@ -195,6 +_,7 @@
+ public void run() {
+ if (!org.bukkit.craftbukkit.Main.useConsole) return; // CraftBukkit
// Paper start - Use TerminalConsoleAppender
+ if (DedicatedServer.this.gui == null || System.console() != null) // Purpur - GUI Improvements - has no GUI or has console (did not double-click)
new com.destroystokyo.paper.console.PaperConsole(DedicatedServer.this).start();
/*
- jline.console.ConsoleReader bufferedreader = DedicatedServer.this.reader;
-@@ -224,6 +_,15 @@
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
+@@ -273,6 +_,15 @@
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
-+ /*// Purpur start - Purpur config files // Purpur - Configurable void damage height and damage
++ // Purpur start - Purpur config files
+ try {
+ org.purpurmc.purpur.PurpurConfig.init((java.io.File) options.valueOf("purpur-settings"));
+ } catch (Exception e) {
@@ -20,12 +20,12 @@
+ return false;
+ }
+ org.purpurmc.purpur.PurpurConfig.registerCommands();
-+ */// Purpur end - Purpur config files // Purpur - Configurable void damage height and damage
++ // Purpur end - Purpur config files
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
- this.setPvpAllowed(properties.pvp);
-@@ -271,6 +_,30 @@
- if (true) throw new IllegalStateException("Failed to bind to port", var10); // Paper - Propagate failed to bind to port error
+ // this.worldData.setGameType(properties.gameMode.get()); // CraftBukkit - moved to world loading
+@@ -315,6 +_,30 @@
+ if (true) throw new IllegalStateException("Failed to bind to port", var11); // Paper - Propagate failed to bind to port error
return false;
}
+ // Purpur start - UPnP Port Forwarding
@@ -54,13 +54,14 @@
+ // Purpur end - UPnP Port Forwarding
// CraftBukkit start
- // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // Spigot - moved up
-@@ -350,6 +_,8 @@
+ this.server.loadPlugins();
+@@ -389,6 +_,9 @@
+ MinecraftServerStatistics.registerJmxMonitoring(this);
LOGGER.info("JMX monitoring enabled");
}
-
++
+ org.purpurmc.purpur.task.BossBarTask.startAll(); // Purpur - Implement TPSBar
+ if (org.purpurmc.purpur.PurpurConfig.beeCountPayload) org.purpurmc.purpur.task.BeehiveTask.instance().register(); // Purpur - Give bee counts in beehives to Purpur clients
+
+ this.notificationManager().serverStarted();
return true;
- }
- }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch
index 14576e237..1a7ed8c07 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch
@@ -1,10 +1,10 @@
--- a/net/minecraft/server/dedicated/DedicatedServerProperties.java
+++ b/net/minecraft/server/dedicated/DedicatedServerProperties.java
-@@ -49,6 +_,7 @@
+@@ -57,6 +_,7 @@
public final boolean onlineMode = this.get("online-mode", true);
public final boolean preventProxyConnections = this.get("prevent-proxy-connections", false);
public final String serverIp = this.get("server-ip", "");
+ public final String serverName = this.get("server-name", "Unknown Server"); // Purpur - Bring back server name
- public final boolean pvp = this.get("pvp", true);
- public final boolean allowFlight = this.get("allow-flight", false);
- public final String motd = this.get("motd", "A Minecraft Server");
+ public final Settings.MutableValue allowFlight = this.getMutable("allow-flight", false);
+ public final Settings.MutableValue motd = this.getMutable("motd", "A Minecraft Server");
+ public final boolean codeOfConduct = this.get("enable-code-of-conduct", false);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/StatsComponent.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/StatsComponent.java.patch
index a082bca56..fb8ae8440 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/StatsComponent.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/StatsComponent.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/server/gui/StatsComponent.java
+++ b/net/minecraft/server/gui/StatsComponent.java
-@@ -43,7 +_,7 @@
+@@ -41,7 +_,7 @@
}
this.msgs[0] = "Memory use: " + l / 1024L / 1024L + " mb (" + Runtime.getRuntime().freeMemory() * 100L / Runtime.getRuntime().maxMemory() + "% free)";
this.msgs[1] = "Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms";
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch
index a4cf79160..3c37f2002 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch
@@ -1,21 +1,22 @@
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
-@@ -207,6 +_,8 @@
+@@ -218,6 +_,8 @@
private final StructureManager structureManager;
private final StructureCheck structureCheck;
private final boolean tickTime;
+ private double preciseTime; // Purpur - Configurable daylight cycle
+ private boolean forceTime; // Purpur - Configurable daylight cycle
private final RandomSequences randomSequences;
+ final LevelDebugSynchronizers debugSynchronizers = new LevelDebugSynchronizers(this);
- // CraftBukkit start
-@@ -595,7 +_,24 @@
+@@ -622,8 +_,25 @@
// CraftBukkit end
this.tickTime = tickTime;
this.server = server;
- this.customSpawners = customSpawners;
++ this.customSpawners = new ArrayList<>(); // Purpur - Allow toggling special MobSpawners per world
+ this.serverLevelData = serverLevelData;
+ // Purpur start - Allow toggling special MobSpawners per world
-+ this.customSpawners = new ArrayList<>();
+ if (purpurConfig.phantomSpawning) {
+ this.customSpawners.add(new net.minecraft.world.level.levelgen.PhantomSpawner());
+ }
@@ -29,13 +30,13 @@
+ this.customSpawners.add(new net.minecraft.world.entity.ai.village.VillageSiege());
+ }
+ if (purpurConfig.villagerTraderSpawning) {
-+ this.customSpawners.add(new net.minecraft.world.entity.npc.WanderingTraderSpawner(serverLevelData));
++ this.customSpawners.add(new net.minecraft.world.entity.npc.wanderingtrader.WanderingTraderSpawner(serverLevelData));
+ }
+ // Purpur end - Allow toggling special MobSpawners per world
- this.serverLevelData = serverLevelData;
ChunkGenerator chunkGenerator = levelStem.generator();
// CraftBukkit start
-@@ -681,6 +_,7 @@
+ this.serverLevelData.setWorld(this);
+@@ -709,6 +_,7 @@
this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler);
// Paper end - rewrite chunk system
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
@@ -43,21 +44,21 @@
}
// Paper start
-@@ -727,7 +_,7 @@
+@@ -760,7 +_,7 @@
}
- int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
-- if (this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) {
-+ if (this.purpurConfig.playersSkipNight && this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) { // Purpur - Config for skipping night
+ int i = this.getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE);
+- if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) {
++ if (this.purpurConfig.playersSkipNight && this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) { // Purpur - Config for skipping night
// Paper start - create time skip event - move up calculations
final long newDayTime = this.levelData.getDayTime() + 24000L;
org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(
-@@ -846,6 +_,13 @@
+@@ -895,6 +_,13 @@
this.serverLevelData.getScheduledEvents().tick(this.server, l);
Profiler.get().pop();
- if (this.serverLevelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) {
+ if (this.getGameRules().get(GameRules.ADVANCE_TIME)) {
+ // Purpur start - Configurable daylight cycle
-+ int incrementTicks = isDay() ? this.purpurConfig.daytimeTicks : this.purpurConfig.nighttimeTicks;
++ int incrementTicks = isBrightOutside() ? this.purpurConfig.daytimeTicks : this.purpurConfig.nighttimeTicks;
+ if (incrementTicks != 12000) {
+ this.preciseTime += 12000 / (double) incrementTicks;
+ this.setDayTime(this.preciseTime);
@@ -66,11 +67,10 @@
this.setDayTime(this.levelData.getDayTime() + 1L);
}
}
-@@ -853,7 +_,21 @@
+@@ -902,6 +_,20 @@
public void setDayTime(long time) {
this.serverLevelData.setDayTime(time);
-- }
+ // Purpur start - Configurable daylight cycle
+ this.preciseTime = time;
+ this.forceTime = false;
@@ -84,33 +84,68 @@
+ // Purpur start - Configurable daylight cycle
+ public boolean isForceTime() {
+ return this.forceTime;
-+ }
+ // Purpur end - Configurable daylight cycle
+ }
- public void tickCustomSpawners(boolean spawnEnemies, boolean spawnFriendlies) {
- for (CustomSpawner customSpawner : this.customSpawners) {
-@@ -934,9 +_,18 @@
+ public long getDayCount() {
+@@ -1010,9 +_,17 @@
&& this.random.nextDouble() < currentDifficultyAt.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01) // Paper - Configurable spawn chances for skeleton horses
- && !this.getBlockState(blockPos.below()).is(Blocks.LIGHTNING_ROD);
+ && !this.getBlockState(blockPos.below()).is(BlockTags.LIGHTNING_RODS);
if (flag) {
+- SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
+ // Purpur start - Special mobs naturally spawn
-+ net.minecraft.world.entity.animal.horse.AbstractHorse entityhorseskeleton;
++ net.minecraft.world.entity.animal.equine.AbstractHorse skeletonHorse;
+ if (purpurConfig.zombieHorseSpawnChance > 0D && random.nextDouble() <= purpurConfig.zombieHorseSpawnChance) {
-+ entityhorseskeleton = EntityType.ZOMBIE_HORSE.create(this, EntitySpawnReason.EVENT);
++ skeletonHorse = EntityType.ZOMBIE_HORSE.create(this, EntitySpawnReason.EVENT);
+ } else {
-+ entityhorseskeleton = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
-+ if (entityhorseskeleton != null) ((SkeletonHorse) entityhorseskeleton).setTrap(true);
++ skeletonHorse = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
++ if (skeletonHorse != null) ((SkeletonHorse) skeletonHorse).setTrap(true);
+ }
+ // Purpur end - Special mobs naturally spawn
- SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
if (skeletonHorse != null) {
- skeletonHorse.setTrap(true);
+ //skeletonHorse.setTrap(true); // Purpur - Special mobs naturally spawn - moved up
skeletonHorse.setAge(0);
skeletonHorse.setPos(blockPos.getX(), blockPos.getY(), blockPos.getZ());
this.addFreshEntity(skeletonHorse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit
-@@ -1009,7 +_,7 @@
- pointOfInterestType -> pointOfInterestType.is(PoiTypes.LIGHTNING_ROD),
+@@ -1047,9 +_,35 @@
+ if (blockState.is(Blocks.SNOW)) {
+ int layersValue = blockState.getValue(SnowLayerBlock.LAYERS);
+ if (layersValue < Math.min(i, 8)) {
++ // Purpur start - Smooth snow accumulation
++ boolean canSnow = true;
++ // Ensure snow doesn't get more than N layers taller than its neighbors
++ // We only need to check blocks that are taller than the minimum step height
++ if (org.purpurmc.purpur.PurpurConfig.smoothSnowAccumulationStep > 0 && layersValue >= org.purpurmc.purpur.PurpurConfig.smoothSnowAccumulationStep) {
++ int layersValueMin = layersValue - org.purpurmc.purpur.PurpurConfig.smoothSnowAccumulationStep;
++ for (Direction direction : Direction.Plane.HORIZONTAL) {
++ BlockPos blockPosNeighbor = heightmapPos.relative(direction);
++ BlockState blockStateNeighbor = this.getBlockState(blockPosNeighbor);
++ if (blockStateNeighbor.is(Blocks.SNOW)) {
++ // Special check for snow layers, if neighbors are too short, don't accumulate
++ int layersValueNeighbor = blockStateNeighbor.getValue(SnowLayerBlock.LAYERS);
++ if (layersValueNeighbor <= layersValueMin) {
++ canSnow = false;
++ break;
++ }
++ } else if (!Block.isFaceFull(blockStateNeighbor.getCollisionShape(this, blockPosNeighbor), direction.getOpposite())) {
++ // Since our layer is tall enough already, if we have a non-full neighbor block, don't accumulate
++ canSnow = false;
++ break;
++ }
++ }
++ }
++ if (canSnow) {
++ // Purpur end - Smooth snow accumulation
+ BlockState blockState1 = blockState.setValue(SnowLayerBlock.LAYERS, layersValue + 1);
+ Block.pushEntitiesUp(blockState, blockState1, this, heightmapPos);
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, heightmapPos, blockState1, 3, null); // CraftBukkit
++ } // Purpur - Smooth snow accumulation
+ }
+ } else {
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, heightmapPos, Blocks.SNOW.defaultBlockState(), 3, null); // CraftBukkit
+@@ -1070,7 +_,7 @@
+ poiType -> poiType.is(PoiTypes.LIGHTNING_ROD),
blockPos -> blockPos.getY() == this.getHeight(Heightmap.Types.WORLD_SURFACE, blockPos.getX(), blockPos.getZ()) - 1,
pos,
- 128,
@@ -118,10 +153,10 @@
PoiManager.Occupancy.ANY
);
return optional.map(blockPos -> blockPos.above(1));
-@@ -1057,8 +_,26 @@
- int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
+@@ -1119,8 +_,26 @@
+ int i = this.getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE);
Component component;
- if (this.sleepStatus.areEnoughSleeping(_int)) {
+ if (this.sleepStatus.areEnoughSleeping(i)) {
+ // Purpur start - Customizable sleeping actionbar messages
+ if (org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.isBlank()) {
+ return;
@@ -139,13 +174,13 @@
+ if (!org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.equalsIgnoreCase("default")) {
+ component = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent,
+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("count", Integer.toString(this.sleepStatus.amountSleeping())),
-+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("total", Integer.toString(this.sleepStatus.sleepersNeeded(_int)))));
++ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("total", Integer.toString(this.sleepStatus.sleepersNeeded(i)))));
+ } else
+ // Purpur end - Customizable sleeping actionbar messages
- component = Component.translatable("sleep.players_sleeping", this.sleepStatus.amountSleeping(), this.sleepStatus.sleepersNeeded(_int));
+ component = Component.translatable("sleep.players_sleeping", this.sleepStatus.amountSleeping(), this.sleepStatus.sleepersNeeded(i));
}
-@@ -1191,6 +_,7 @@
+@@ -1275,6 +_,7 @@
@VisibleForTesting
public void resetWeatherCycle() {
// CraftBukkit start
@@ -153,7 +188,7 @@
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....
-@@ -1198,6 +_,7 @@
+@@ -1282,6 +_,7 @@
this.serverLevelData.setRainTime(0);
}
// CraftBukkit end
@@ -161,7 +196,16 @@
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.
-@@ -2676,7 +_,7 @@
+@@ -1954,7 +_,7 @@
+ Explosion.BlockInteraction blockInteraction = switch (explosionInteraction) {
+ case NONE -> Explosion.BlockInteraction.KEEP;
+ case BLOCK -> this.getDestroyType(GameRules.BLOCK_EXPLOSION_DROP_DECAY);
+- case MOB -> this.getGameRules().get(GameRules.MOB_GRIEFING)
++ case MOB -> ((source instanceof net.minecraft.world.entity.projectile.hurtingprojectile.LargeFireball) ? this.getGameRules().get(GameRules.MOB_GRIEFING, this.purpurConfig.fireballsMobGriefingOverride) : this.getGameRules().get(GameRules.MOB_GRIEFING)) // Purpur - Add mobGriefing override to everything affected
+ ? this.getDestroyType(GameRules.MOB_EXPLOSION_DROP_DECAY)
+ : Explosion.BlockInteraction.KEEP;
+ case TNT -> this.getDestroyType(GameRules.TNT_EXPLOSION_DROP_DECAY);
+@@ -2846,7 +_,7 @@
// 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
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch
index 8adf80143..e61821aca 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch
@@ -1,52 +1,50 @@
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
-@@ -393,6 +_,10 @@
- public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent
- public @Nullable String clientBrandName = null; // Paper - Brand support
- public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event
-+ public boolean purpurClient = false; // Purpur - Purpur client support
+@@ -433,6 +_,9 @@
+ public boolean isRealPlayer; // Paper
+ public com.destroystokyo.paper.event.entity.@Nullable PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent
+ public org.bukkit.event.player.PlayerQuitEvent.@Nullable QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event
+ private boolean tpsBar = false; // Purpur - Implement TPSBar
+ private boolean compassBar = false; // Purpur - Add compass command
+ private boolean ramBar = false; // Purpur - Implement rambar commands
// Paper start - rewrite chunk system
private ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader;
-@@ -561,6 +_,10 @@
- if (tag != null) {
- BlockPos.CODEC.parse(NbtOps.INSTANCE, tag).resultOrPartial(LOGGER::error).ifPresent(pos -> this.raidOmenPosition = pos);
+@@ -506,6 +_,9 @@
+ this.respawnConfig = input.read("respawn", ServerPlayer.RespawnConfig.CODEC).orElse(null);
+ this.spawnExtraParticlesOnFall = input.getBooleanOr("spawn_extra_particles_on_fall", false);
+ this.raidOmenPosition = input.read("raid_omen_position", BlockPos.CODEC).orElse(null);
++ this.tpsBar = input.getBooleanOr("Purpur.TPSBar", false); // Purpur - Implement TPSBar
++ this.compassBar = input.getBooleanOr("Purpur.CompassBar", false); // Purpur - Add compass command
++ this.ramBar = input.getBooleanOr("Purpur.RamBar", false); // Purpur - Implement rambar command
+ // Paper start - Expand PlayerGameModeChangeEvent
+ this.loadGameTypes(input);
+ }
+@@ -547,6 +_,9 @@
+ output.store("ShoulderEntityRight", CompoundTag.CODEC, this.getShoulderEntityRight());
}
-+
-+ if (compound.contains("Purpur.TPSBar")) { this.tpsBar = compound.getBoolean("Purpur.TPSBar"); } // Purpur - Implement TPSBar
-+ if (compound.contains("Purpur.CompassBar")) { this.compassBar = compound.getBoolean("Purpur.CompassBar"); } // Purpur - Add compass command
-+ if (compound.contains("Purpur.RamBar")) { this.ramBar = compound.getBoolean("Purpur.RamBar"); } // Purpur - Implement rambar command
+ this.getBukkitEntity().setExtraData(output); // CraftBukkit
++ output.putBoolean("Purpur.TPSBar", this.tpsBar); // Purpur - Implement TPSBar
++ output.putBoolean("Purpur.CompassBar", this.compassBar); // Purpur - Add compass command
++ output.putBoolean("Purpur.RamBar", this.ramBar); // Purpur - Add rambar command
}
- @Override
-@@ -605,6 +_,9 @@
- }
-
- this.saveEnderPearls(compound);
-+ compound.putBoolean("Purpur.TPSBar", this.tpsBar); // Purpur - Implement TPSBar
-+ compound.putBoolean("Purpur.CompassBar", this.compassBar); // Purpur - Add compass command
-+ compound.putBoolean("Purpur.RamBar", this.ramBar); // Purpur - Add rambar command
- }
-
- private void saveParentVehicle(CompoundTag tag) {
-@@ -1124,6 +_,7 @@
- )
- );
+ private void saveParentVehicle(ValueOutput output) {
+@@ -1183,6 +_,7 @@
+ // Paper - moved up to sendClientboundPlayerCombatKillPacket()
+ sendClientboundPlayerCombatKillPacket(event.getShowDeathMessages(), deathScreenMessage); // Paper - Expand PlayerDeathEvent
Team team = this.getTeam();
+ if (org.purpurmc.purpur.PurpurConfig.deathMessageOnlyBroadcastToAffectedPlayer) this.sendSystemMessage(deathMessage); else // Purpur - Configurable broadcast settings
if (team == null || team.getDeathMessageVisibility() == Team.Visibility.ALWAYS) {
this.server.getPlayerList().broadcastSystemMessage(deathMessage, false);
} else if (team.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OTHER_TEAMS) {
-@@ -1217,6 +_,13 @@
+@@ -1290,6 +_,13 @@
if (this.isInvulnerableTo(level, damageSource)) {
return false;
} else {
+ // Purpur start - Add boat fall damage config
+ if (damageSource.is(net.minecraft.tags.DamageTypeTags.IS_FALL)) {
-+ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.Boat && !level().purpurConfig.boatsDoFallDamage) {
++ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.boat.Boat && !level().purpurConfig.boatsDoFallDamage) {
+ return false;
+ }
+ }
@@ -54,29 +52,29 @@
Entity entity = damageSource.getEntity();
if (!( // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false.
!(entity instanceof Player player && !this.canHarmPlayer(player))
-@@ -1446,6 +_,7 @@
- serverLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
- this.unsetRemoved();
- // CraftBukkit end
-+ this.portalPos = io.papermc.paper.util.MCUtil.toBlockPosition(exit); // Purpur - Fix stuck in portals
+@@ -1544,6 +_,7 @@
+
+ profilerFiller.pop();
+ profilerFiller.push("placing");
++ this.portalPos = org.bukkit.craftbukkit.util.CraftLocation.toBlockPosition(exit); // Purpur - Fix stuck in portals
this.setServerLevel(level);
this.connection.internalTeleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); // CraftBukkit - use internal teleport without event
this.connection.resetPosition();
-@@ -1564,7 +_,7 @@
- new AABB(vec3.x() - 8.0, vec3.y() - 5.0, vec3.z() - 8.0, vec3.x() + 8.0, vec3.y() + 5.0, vec3.z() + 8.0),
- monster -> monster.isPreventingPlayerRest(this.serverLevel(), this)
- );
-- if (!entitiesOfClass.isEmpty()) {
-+ if (!this.level().purpurConfig.playerSleepNearMonsters && !entitiesOfClass.isEmpty()) { // Purpur - Config to ignore nearby mobs when sleeping
- return Either.left(Player.BedSleepingProblem.NOT_SAFE);
+@@ -1652,7 +_,7 @@
+ new AABB(vec3.x() - 8.0, vec3.y() - 5.0, vec3.z() - 8.0, vec3.x() + 8.0, vec3.y() + 5.0, vec3.z() + 8.0),
+ monster -> monster.isPreventingPlayerRest(this.level(), this)
+ );
+- if (!entitiesOfClass.isEmpty()) {
++ if (!this.level().purpurConfig.playerSleepNearMonsters && !entitiesOfClass.isEmpty()) { // Purpur - Config to ignore nearby mobs when sleeping
+ return Either.left(Player.BedSleepingProblem.NOT_SAFE);
+ }
}
- }
-@@ -1601,7 +_,19 @@
- CriteriaTriggers.SLEPT_IN_BED.trigger(this);
- });
- if (!this.serverLevel().canSleepThroughNights()) {
-- this.displayClientMessage(Component.translatable("sleep.not_possible"), true);
-+ // Purpur start - Customizable sleeping actionbar messages
+@@ -1692,8 +_,19 @@
+ CriteriaTriggers.SLEPT_IN_BED.trigger(this);
+ });
+ if (!this.level().canSleepThroughNights()) {
+- this.displayClientMessage(Component.translatable("sleep.not_possible"), true);
++ // Purpur start - Customizable sleeping actionbar messages
+ Component clientMessage;
+ if (org.purpurmc.purpur.PurpurConfig.sleepNotPossible.isBlank()) {
+ clientMessage = null;
@@ -84,15 +82,15 @@
+ clientMessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepNotPossible));
+ } else {
+ clientMessage = Component.translatable("sleep.not_possible");
-+ }
+ }
+ if (clientMessage != null) {
+ this.displayClientMessage(clientMessage, true);
-+ }
-+ // Purpur end - Customizable sleeping actionbar messages
- }
++ }// Purpur end - Customizable sleeping actionbar messages
++ }
- ((ServerLevel)this.level()).updateSleepingPlayerList();
-@@ -1709,6 +_,7 @@
+ this.level().updateSleepingPlayerList();
+ return either;
+@@ -1784,6 +_,7 @@
@Override
public void openTextEdit(SignBlockEntity signEntity, boolean isFrontText) {
@@ -100,7 +98,7 @@
this.connection.send(new ClientboundBlockUpdatePacket(this.level(), signEntity.getBlockPos()));
this.connection.send(new ClientboundOpenSignEditorPacket(signEntity.getBlockPos(), isFrontText));
}
-@@ -2014,6 +_,26 @@
+@@ -2121,6 +_,26 @@
this.lastSentExp = -1; // CraftBukkit - Added to reset
}
@@ -111,7 +109,7 @@
+ }
+ }
+
-+ public void sendActionBarMessage(@Nullable net.kyori.adventure.text.Component message) {
++ public void sendActionBarMessage(net.kyori.adventure.text.@Nullable Component message) {
+ if (message != null) {
+ sendActionBarMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message));
+ }
@@ -125,9 +123,9 @@
+ // Purpur end - Component related conveniences
+
@Override
- public void displayClientMessage(Component chatComponent, boolean actionBar) {
- this.sendSystemMessage(chatComponent, actionBar);
-@@ -2235,6 +_,20 @@
+ public void displayClientMessage(Component message, boolean overlay) {
+ this.sendSystemMessage(message, overlay);
+@@ -2355,6 +_,20 @@
);
}
@@ -138,17 +136,17 @@
+ }
+ }
+
-+ public void sendMessage(@Nullable net.kyori.adventure.text.Component message) {
++ public void sendMessage(net.kyori.adventure.text.@Nullable Component message) {
+ if (message != null) {
+ this.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message));
+ }
+ }
+ // Purpur end - Component related conveniences
+
- public void sendSystemMessage(Component mesage) {
- this.sendSystemMessage(mesage, false);
+ public void sendSystemMessage(Component message) {
+ this.sendSystemMessage(message, false);
}
-@@ -2373,7 +_,67 @@
+@@ -2492,7 +_,67 @@
public void resetLastActionTime() {
this.lastActionTime = Util.getMillis();
@@ -180,7 +178,7 @@
+
+ msg = event.getBroadcastMsg();
+ if (msg != null && !msg.isEmpty()) {
-+ String playerName = this.getGameProfile().getName();
++ String playerName = this.getGameProfile().name();
+ if (org.purpurmc.purpur.PurpurConfig.afkBroadcastUseDisplayName) {
+ net.kyori.adventure.text.Component playerDisplayNameComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(this.getBukkitEntity().getDisplayName());
+ playerName = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText().serialize(playerDisplayNameComponent);
@@ -210,14 +208,14 @@
+ }
+
+ @Override
-+ public boolean canBeCollidedWith() {
-+ return !this.isAfk() && super.canBeCollidedWith();
++ public boolean canBeCollidedWith(Entity entity) {
++ return !this.isAfk() && super.canBeCollidedWith(entity);
+ }
+ // Purpur end - AFK API
public ServerStatsCounter getStats() {
return this.stats;
-@@ -3078,4 +_,56 @@
+@@ -3128,4 +_,65 @@
return (org.bukkit.craftbukkit.entity.CraftPlayer) super.getBukkitEntity();
}
// CraftBukkit end
@@ -237,9 +235,18 @@
+
+ ServerLevel toLevel = ((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle();
+ if (this.level() == toLevel) {
-+ this.connection.teleport(to);
++ this.connection.internalTeleport(to);
+ } else {
-+ this.server.getPlayerList().respawn(this, true, RemovalReason.KILLED, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.DEATH, to);
++ this.teleport(new TeleportTransition(
++ toLevel,
++ org.bukkit.craftbukkit.util.CraftLocation.toVec3(to),
++ Vec3.ZERO,
++ to.getYaw(),
++ to.getPitch(),
++ net.minecraft.world.entity.Relative.ALL,
++ TeleportTransition.DO_NOTHING,
++ org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN
++ ));
+ }
+ }
+ // Purpur end - Add option to teleport to spawn if outside world border
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch
index 2586f46df..b7c623e53 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
-@@ -351,6 +_,7 @@
+@@ -365,6 +_,7 @@
}
return false;
}
@@ -8,7 +8,7 @@
}
// CraftBukkit end
-@@ -464,6 +_,7 @@
+@@ -482,6 +_,7 @@
public InteractionHand interactHand;
public ItemStack interactItemStack;
public InteractionResult useItemOn(ServerPlayer player, Level level, ItemStack stack, InteractionHand hand, BlockHitResult hitResult) {
@@ -16,7 +16,7 @@
BlockPos blockPos = hitResult.getBlockPos();
BlockState blockState = level.getBlockState(blockPos);
boolean cancelledBlock = false;
-@@ -506,7 +_,7 @@
+@@ -524,7 +_,7 @@
boolean flag = !player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty();
boolean flag1 = player.isSecondaryUseActive() && flag;
ItemStack itemStack = stack.copy();
@@ -25,9 +25,9 @@
InteractionResult interactionResult = blockState.useItemOn(player.getItemInHand(hand), level, player, hand, hitResult);
if (interactionResult.consumesAction()) {
CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(player, blockPos, itemStack);
-@@ -552,4 +_,18 @@
- public void setLevel(ServerLevel serverLevel) {
- this.level = serverLevel;
+@@ -570,4 +_,18 @@
+ public void setLevel(ServerLevel level) {
+ this.level = level;
}
+
+ // Purpur start - Shift right click to use exp for mending
@@ -35,8 +35,8 @@
+ 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));
++ this.player.giveExperiencePoints(itemstack.getDamageValue() == 1 ? -2 : -points);
++ this.player.level().addFreshEntity(new net.minecraft.world.entity.ExperienceOrb(this.player.level(), this.player.getX(), this.player.getY(), this.player.getZ(), itemstack.getDamageValue() == 1 ? 1 : points, org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN, this.player, this.player));
+ return true;
+ }
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch
index fe8a95124..a68b41c11 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/server/level/WorldGenRegion.java
+++ b/net/minecraft/server/level/WorldGenRegion.java
-@@ -312,6 +_,7 @@
+@@ -311,6 +_,7 @@
return true;
} else {
// Paper start - Buffer OOB setBlock calls
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch
index 4405b9245..eb1276339 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch
@@ -1,72 +1,82 @@
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
-@@ -41,6 +_,7 @@
- private long keepAliveChallenge;
+@@ -40,10 +_,11 @@
+ public final Connection connection; // Paper
+ private final boolean transferred;
+ //private long keepAliveTime; // Paper - improve keepalives
+- //private boolean keepAlivePending; // Paper - improve keepalives
++ private boolean keepAlivePending; // Paper - improve keepalives // Purpur - Alternative Keepalive Handling
+ //private long keepAliveChallenge; // Paper - improve keepalives
private long closedListenerTime;
private boolean closed = false;
+ private it.unimi.dsi.fastutil.longs.LongList keepAlives = new it.unimi.dsi.fastutil.longs.LongArrayList(); // Purpur - Alternative Keepalive Handling
- private int latency;
+ private volatile int latency; // Paper - improve keepalives - make volatile
+ private final io.papermc.paper.util.KeepAlive keepAlive; // Paper - improve keepalives
private volatile boolean suspendFlushingOnServerThread = false;
- // CraftBukkit start
-@@ -51,6 +_,7 @@
+@@ -54,6 +_,10 @@
public final java.util.Map packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks
private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit
- protected static final net.minecraft.resources.ResourceLocation MINECRAFT_BRAND = net.minecraft.resources.ResourceLocation.withDefaultNamespace("brand"); // Paper - Brand support
-+ protected static final net.minecraft.resources.ResourceLocation PURPUR_CLIENT = net.minecraft.resources.ResourceLocation.fromNamespaceAndPath("purpur", "client"); // Purpur - Purpur client support
-
- public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie, net.minecraft.server.level.ServerPlayer player) { // CraftBukkit
- this.server = server;
-@@ -118,6 +_,16 @@
-
- @Override
- public void handleKeepAlive(ServerboundKeepAlivePacket packet) {
+ protected static final net.minecraft.resources.Identifier MINECRAFT_BRAND = net.minecraft.resources.Identifier.withDefaultNamespace("brand"); // Paper - Brand support
++ // Purpur start - Purpur client support
++ protected static final net.minecraft.resources.Identifier PURPUR_CLIENT = net.minecraft.resources.Identifier.fromNamespaceAndPath("purpur", "client");
++ public boolean purpurClient;
++ // Purpur end - Purpur client support
+ // Paper start - retain certain values
+ public @Nullable String playerBrand;
+ public final java.util.Set pluginMessagerChannels;
+@@ -105,6 +_,18 @@
+ // Paper start - improve keepalives
+ long now = System.nanoTime();
+ io.papermc.paper.util.KeepAlive.PendingKeepAlive pending = this.keepAlive.pendingKeepAlives.peek();
+ // Purpur start - Alternative Keepalive Handling
+ if (org.purpurmc.purpur.PurpurConfig.useAlternateKeepAlive) {
+ if (this.keepAlivePending && !keepAlives.isEmpty() && keepAlives.contains(packet.getId())) {
+ int ping = (int) (Util.getMillis() - packet.getId());
-+ this.latency = (this.latency * 3 + ping) / 4;
++ int updatedLatency = (this.latency * 3 + ping) / 4;
++ this.latency = updatedLatency;
+ this.keepAlivePending = false;
+ keepAlives.clear(); // we got a valid response, lets roll with it and forget the rest
+ }
++ return;
+ } else
+ // Purpur end - Alternative Keepalive Handling
- if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) {
- int i = (int)(Util.getMillis() - this.keepAliveTime);
- this.latency = (this.latency * 3 + i) / 4;
-@@ -159,6 +_,13 @@
- ServerGamePacketListenerImpl.LOGGER.error("Couldn't register custom payload", ex);
- this.disconnect(Component.literal("Invalid payload REGISTER!"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause
+ if (pending != null && pending.challengeId() == packet.getId()) {
+ this.keepAlive.pendingKeepAlives.remove(pending);
+
+@@ -179,6 +_,12 @@
+ return;
}
-+ // Purpur start - Purpur client support
-+ } else if (identifier.equals(PURPUR_CLIENT)) {
-+ try {
-+ player.purpurClient = true;
-+ } catch (Exception ignore) {
+
++ // Purpur start - Purpur client support
++ if (identifier.equals(PURPUR_CLIENT)) {
++ this.purpurClient = true;
+ }
-+ // Purpur end - Purpur client support
- } else if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_UNREGISTER)) {
- try {
- String channels = payload.toString(com.google.common.base.Charsets.UTF_8);
-@@ -238,6 +_,22 @@
- // Paper start - give clients a longer time to respond to pings as per pre 1.12.2 timings
- // This should effectively place the keepalive handling back to "as it was" before 1.12.2
- final long elapsedTime = millis - this.keepAliveTime;
++ // Purpur end - Purpur client support
+
+ if (identifier.equals(MINECRAFT_BRAND)) {
+ this.playerBrand = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.wrappedBuffer(data)).readUtf(256);
+ }
+@@ -264,6 +_,23 @@
+ Profiler.get().push("keepAlive");
+ long millis = Util.getMillis();
+ // Paper start - improve keepalives
+ // Purpur start - Alternative Keepalive Handling
+ if (org.purpurmc.purpur.PurpurConfig.useAlternateKeepAlive) {
-+ if (elapsedTime >= 1000L) { // 1 second
-+ if (this.keepAlivePending && !this.processedDisconnect && keepAlives.size() * 1000L >= KEEPALIVE_LIMIT) {
-+ this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT);
-+ } else if (this.checkIfClosed(millis)) {
-+ this.keepAlivePending = true;
-+ this.keepAliveTime = millis; // hijack this field for 1 second intervals
-+ this.keepAlives.add(millis); // currentTime is ID
-+ this.send(new ClientboundKeepAlivePacket(millis));
++ if (this.checkIfClosed(millis) && !this.processedDisconnect) {
++ long currTime = System.nanoTime();
++ if ((currTime - this.keepAlive.lastKeepAliveTx) >= java.util.concurrent.TimeUnit.SECONDS.toNanos(1L)) { // 1 second
++ this.keepAlive.lastKeepAliveTx = currTime;
++ if (this.keepAlivePending && !this.processedDisconnect && keepAlives.size() * 1000L >= KEEPALIVE_LIMIT) {
++ this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT);
++ } else if (this.checkIfClosed(millis)) {
++ this.keepAlivePending = true;
++ this.keepAlives.add(millis); // currentTime is ID
++ this.send(new ClientboundKeepAlivePacket(millis));
++ }
+ }
+ }
+ } else
+ // Purpur end - Alternative Keepalive Handling
-+
- if (!this.isSingleplayerOwner() && elapsedTime >= 15000L) { // use vanilla's 15000L between keep alive packets
- if (this.keepAlivePending) {
- if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected
+ if (this.checkIfClosed(millis) && !this.processedDisconnect) {
+ long currTime = System.nanoTime();
+
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch
index 8d25c5e92..06fd70e60 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch
@@ -1,8 +1,8 @@
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -326,6 +_,20 @@
- this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat
+@@ -346,6 +_,20 @@
}
+ // Paper end - configuration phase API
+ // Purpur start - AFK API
+ private final com.google.common.cache.LoadingCache kickPermissionCache = com.google.common.cache.CacheBuilder.newBuilder()
@@ -21,20 +21,20 @@
@Override
public void tick() {
if (this.ackBlockChangesUpTo > -1) {
-@@ -384,6 +_,12 @@
- if (this.player.getLastActionTime() > 0L
- && this.server.getPlayerIdleTimeout() > 0
- && Util.getMillis() - this.player.getLastActionTime() > this.server.getPlayerIdleTimeout() * 1000L * 60L && !this.player.wonGame) { // Paper - Prevent AFK kick while watching end credits
-+ // Purpur start - AFK API
-+ this.player.setAfk(true);
-+ if (!this.player.level().purpurConfig.idleTimeoutKick || (!Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK")) && kickPermissionCache.getUnchecked(this.player.getBukkitEntity()))) {
-+ return;
-+ }
-+ // Purpur end - AFK API
- this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854
- this.disconnect(Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause
+@@ -363,6 +_,12 @@
+ && this.server.playerIdleTimeout() > 0
+ && Util.getMillis() - this.player.getLastActionTime() > TimeUnit.MINUTES.toMillis(this.server.playerIdleTimeout())
+ && !this.player.wonGame) {
++ // Purpur start - AFK API
++ this.player.setAfk(true);
++ if (!this.player.level().purpurConfig.idleTimeoutKick || (!Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK")) && kickPermissionCache.getUnchecked(this.player.getBukkitEntity()))) {
++ return;
++ }
++ // Purpur end - AFK API
+ this.disconnect(Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause
+ }
}
-@@ -629,6 +_,8 @@
+@@ -682,6 +_,8 @@
this.lastYaw = to.getYaw();
this.lastPitch = to.getPitch();
@@ -43,15 +43,15 @@
Location oldTo = to.clone();
PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
this.cserver.getPluginManager().callEvent(event);
-@@ -709,6 +_,7 @@
- PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
+@@ -761,6 +_,7 @@
+ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level());
if (packet.getId() == this.awaitingTeleport) {
if (this.awaitingPositionFromClient == null) {
+ ServerGamePacketListenerImpl.LOGGER.warn("Disconnected on accept teleport packet. Was not expecting position data from client at this time"); // Purpur - Add more logger output for invalid movement kicks
this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause
return;
}
-@@ -1176,6 +_,10 @@
+@@ -1301,6 +_,10 @@
final int maxBookPageSize = pageMax.intValue();
final double multiplier = Math.clamp(io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.totalMultiplier, 0.3D, 1D);
long byteAllowed = maxBookPageSize;
@@ -62,7 +62,7 @@
for (final String page : pageList) {
final int byteLength = page.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;
byteTotal += byteLength;
-@@ -1200,7 +_,8 @@
+@@ -1325,7 +_,8 @@
}
if (byteTotal > byteAllowed) {
@@ -72,7 +72,7 @@
this.disconnectAsync(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause // Paper - add proper async disconnect
return;
}
-@@ -1219,31 +_,45 @@
+@@ -1344,31 +_,45 @@
Optional optional = packet.title();
optional.ifPresent(list::add);
list.addAll(packet.pages());
@@ -82,9 +82,9 @@
+ // Purpur end - Allow color codes in books
Consumer> consumer = optional.isPresent()
- ? texts -> this.signBook(texts.get(0), texts.subList(1, texts.size()), slot)
-- : texts -> this.updateBookContents(texts, slot);
+- : list1 -> this.updateBookContents(list1, slot);
+ ? texts -> this.signBook(texts.get(0), texts.subList(1, texts.size()), slot, hasSignPerm) // Purpur - Allow color codes in books
-+ : texts -> this.updateBookContents(texts, slot, hasEditPerm); // Purpur - Allow color codes in books
++ : list1 -> this.updateBookContents(list1, slot, hasEditPerm); // Purpur - Allow color codes in books
this.filterTextPacket(list).thenAcceptAsync(consumer, this.server);
}
}
@@ -120,9 +120,9 @@
- List> list = pages.stream().map(filteredText -> this.filterableFromOutgoing(filteredText).map(Component::literal)).toList();
+ List> list = pages.stream().map((filteredText) -> this.filterableFromOutgoing(filteredText).map(s -> hexColor(s, hasPerm))).toList(); // Purpur - Allow color codes in books
itemStack.set(
- DataComponents.WRITTEN_BOOK_CONTENT,
- new WrittenBookContent(this.filterableFromOutgoing(title), this.player.getName().getString(), 0, list, true)
-@@ -1257,6 +_,16 @@
+ DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(this.filterableFromOutgoing(title), this.player.getPlainTextName(), 0, list, true)
+ );
+@@ -1381,6 +_,16 @@
return this.player.isTextFilteringEnabled() ? Filterable.passThrough(filteredText.filteredOrEmpty()) : Filterable.from(filteredText);
}
@@ -138,11 +138,11 @@
+
@Override
public void handleEntityTagQuery(ServerboundEntityTagQueryPacket packet) {
- PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
-@@ -1292,7 +_,15 @@
+ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level());
+@@ -1420,7 +_,15 @@
@Override
public void handleMovePlayer(ServerboundMovePlayerPacket packet) {
- PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
+ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level());
- if (containsInvalidValues(packet.getX(0.0), packet.getY(0.0), packet.getZ(0.0), packet.getYRot(0.0F), packet.getXRot(0.0F))) {
+ // Purpur start - Add more logger output for invalid movement kicks
+ boolean invalidX = Double.isNaN(packet.getX(0.0));
@@ -155,40 +155,40 @@
+ // Purpur end - Add more logger output for invalid movement kicks
this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause
} else {
- ServerLevel serverLevel = this.player.serverLevel();
-@@ -1467,7 +_,7 @@
- movedWrongly = true;
- if (event.getLogWarning())
- // Paper end
-- LOGGER.warn("{} moved wrongly!", this.player.getName().getString());
-+ LOGGER.warn("{} moved wrongly!, ({})", this.player.getName().getString(), verticalDelta); // Purpur - AFK API
- } // Paper
- }
-
-@@ -1533,6 +_,8 @@
- this.lastYaw = to.getYaw();
- this.lastPitch = to.getPitch();
-
-+ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur - AFK API
-+
- Location oldTo = to.clone();
- PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
- this.cserver.getPluginManager().callEvent(event);
-@@ -1589,6 +_,13 @@
- this.player.tryResetCurrentImpulseContext();
+ ServerLevel serverLevel = this.player.level();
+@@ -1603,7 +_,7 @@
+ movedWrongly = true;
+ if (event.getLogWarning())
+ // Paper end
+- LOGGER.warn("{} moved wrongly!", this.player.getPlainTextName());
++ LOGGER.warn("{} moved wrongly!, ({})", this.player.getPlainTextName(), verticalDelta); // Purpur - AFK API
+ } // Paper
}
-+ // Purpur start - Dont run with scissors!
-+ if (this.player.serverLevel().purpurConfig.dontRunWithScissors && this.player.isSprinting() && !(this.player.serverLevel().purpurConfig.ignoreScissorsInWater && this.player.isInWater()) && !(this.player.serverLevel().purpurConfig.ignoreScissorsInLava && this.player.isInLava()) && (isScissors(this.player.getItemInHand(InteractionHand.MAIN_HAND)) || isScissors(this.player.getItemInHand(InteractionHand.OFF_HAND))) && (int) (Math.random() * 10) == 0) {
-+ this.player.hurtServer(this.player.serverLevel(), this.player.damageSources().scissors(), (float) this.player.serverLevel().purpurConfig.scissorsRunningDamage);
-+ if (!org.purpurmc.purpur.PurpurConfig.dontRunWithScissors.isBlank()) this.player.sendActionBarMessage(org.purpurmc.purpur.PurpurConfig.dontRunWithScissors);
-+ }
-+ // Purpur end - Dont run with scissors!
+@@ -1668,6 +_,8 @@
+ this.lastYaw = to.getYaw();
+ this.lastPitch = to.getPitch();
+
++ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur - AFK API
+
- this.player.checkMovementStatistics(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z);
- this.lastGoodX = this.player.getX();
- this.lastGoodY = this.player.getY();
-@@ -1637,6 +_,17 @@
+ Location oldTo = to.clone();
+ PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
+ this.cserver.getPluginManager().callEvent(event);
+@@ -1723,6 +_,13 @@
+ this.player.tryResetCurrentImpulseContext();
+ }
+
++ // Purpur start - Dont run with scissors!
++ if (this.player.level().purpurConfig.dontRunWithScissors && this.player.isSprinting() && !(this.player.level().purpurConfig.ignoreScissorsInWater && this.player.isInWater()) && !(this.player.level().purpurConfig.ignoreScissorsInLava && this.player.isInLava()) && (isScissors(this.player.getItemInHand(InteractionHand.MAIN_HAND)) || isScissors(this.player.getItemInHand(InteractionHand.OFF_HAND))) && (int) (Math.random() * 10) == 0) {
++ this.player.hurtServer(this.player.level(), this.player.damageSources().scissors(), (float) this.player.level().purpurConfig.scissorsRunningDamage);
++ if (!org.purpurmc.purpur.PurpurConfig.dontRunWithScissors.isBlank()) this.player.sendActionBarMessage(org.purpurmc.purpur.PurpurConfig.dontRunWithScissors);
++ }
++ // Purpur end - Dont run with scissors!
++
+ this.player.checkMovementStatistics(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z);
+ this.lastGoodX = this.player.getX();
+ this.lastGoodY = this.player.getY();
+@@ -1740,6 +_,17 @@
}
}
@@ -196,29 +196,38 @@
+ public boolean isScissors(ItemStack stack) {
+ if (!stack.is(Items.SHEARS)) return false;
+
-+ ResourceLocation itemModelReference = stack.get(net.minecraft.core.component.DataComponents.ITEM_MODEL);
-+ if (itemModelReference != null && itemModelReference.equals(this.player.serverLevel().purpurConfig.dontRunWithScissorsItemModelReference)) return true;
++ Identifier itemModelReference = stack.get(net.minecraft.core.component.DataComponents.ITEM_MODEL);
++ if (itemModelReference != null && itemModelReference.equals(this.player.level().purpurConfig.dontRunWithScissorsItemModelReference)) return true;
+
+ return stack.getOrDefault(DataComponents.CUSTOM_MODEL_DATA, net.minecraft.world.item.component.CustomModelData.EMPTY).equals(net.minecraft.world.item.component.CustomModelData.EMPTY);
+ }
+ // Purpur end - Dont run with scissors!
+
- // Paper start - optimise out extra getCubes
- private boolean hasNewCollision(final ServerLevel level, final Entity entity, final AABB oldBox, final AABB newBox) {
- final List collisionsBB = new java.util.ArrayList<>();
-@@ -2001,6 +_,7 @@
+ private boolean shouldCheckPlayerMovement(boolean isElytraMovement) {
+ if (this.isSingleplayerOwner()) {
+ return false;
+@@ -2154,6 +_,7 @@
boolean cancelled;
if (hitResult == null || hitResult.getType() != HitResult.Type.BLOCK) {
-+ if (this.player.gameMode.shiftClickMended(itemInHand)) return; // Purpur - Shift right click to use exp for mending
++ if (this.player.gameMode.shiftClickMended(itemInHand)) return; // Purpur - Shift right click to use exp for mending
org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemInHand, hand);
cancelled = event.useItemInHand() == Event.Result.DENY;
} else {
-@@ -2741,6 +_,7 @@
+@@ -2800,6 +_,7 @@
AABB boundingBox = target.getBoundingBox();
- if (this.player.canInteractWithEntity(boundingBox, io.papermc.paper.configuration.GlobalConfiguration.get().misc.clientInteractionLeniencyDistance.or(3.0))) { // Paper - configurable lenience value for interact range
+ if (packet.isWithinRange(this.player, boundingBox, io.papermc.paper.configuration.GlobalConfiguration.get().misc.clientInteractionLeniencyDistance.or(3.0))) { // Paper - configurable lenience value for interact range
+ if (target instanceof net.minecraft.world.entity.Mob mob) mob.ticksSinceLastInteraction = 0; // Purpur - Entity lifespan
packet.dispatch(
new ServerboundInteractPacket.Handler() {
private void performInteraction(InteractionHand hand, ServerGamePacketListenerImpl.EntityInteraction entityInteraction, PlayerInteractEntityEvent event) { // CraftBukkit
+@@ -3545,7 +_,7 @@
+ @Override
+ public void handleChangeGameMode(ServerboundChangeGameModePacket packet) {
+ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level());
+- if (!GameModeCommand.PERMISSION_CHECK.check(this.player.permissions())) {
++ if (!GameModeCommand.PERMISSION_CHECK.check(this.player.permissions()) && !player.getBukkitEntity().hasPermission("purpur.debug.f3n")) { // Purpur - Add permission for F3+N debug
+ LOGGER.warn(
+ "Player {} tried to change game mode to {} without required permissions",
+ this.player.getGameProfile().name(),
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch
index 5b3bc1b3f..ec161a6f4 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
-@@ -307,7 +_,7 @@
+@@ -278,7 +_,7 @@
ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!");
ServerLoginPacketListenerImpl.this.startClientVerification(ServerLoginPacketListenerImpl.this.createOfflineProfile(string1)); // Spigot
} else {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch
index 1818a74df..4b9176bcd 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch
@@ -1,31 +1,22 @@
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
-@@ -396,6 +_,7 @@
+@@ -311,6 +_,7 @@
scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
}
// Paper end - Configurable player collision
+ org.purpurmc.purpur.task.BossBarTask.addToAll(player); // Purpur - Implement TPSBar
- PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), loggableAddress, player.getId(), serverLevel.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
- // Paper start - Send empty chunk, so players aren't stuck in the world loading screen with our chunk system not sending chunks when dead
- if (player.isDeadOrDying()) {
-@@ -501,6 +_,7 @@
+ // CraftBukkit start - moved down
+ LOGGER.info(
+ "{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", // CraftBukkit - add world name
+@@ -431,6 +_,7 @@
}
- public net.kyori.adventure.text.Component remove(ServerPlayer player, net.kyori.adventure.text.Component leaveMessage) {
+ public net.kyori.adventure.text.@Nullable Component remove(ServerPlayer player, net.kyori.adventure.text.Component leaveMessage) {
// Paper end - Fix kick event leave message not being sent
+ org.purpurmc.purpur.task.BossBarTask.removeFromAll(player.getBukkitEntity()); // Purpur - Implement TPSBar
- ServerLevel serverLevel = player.serverLevel();
+ ServerLevel serverLevel = player.level();
player.awardStat(Stats.LEAVE_GAME);
// CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it
-@@ -665,7 +_,7 @@
- // return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameProfile)
- // ? Component.translatable("multiplayer.disconnect.server_full")
- // : null;
-- if (this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameProfile)) {
-+ if (this.players.size() >= this.maxPlayers && !(player.hasPermission("purpur.joinfullserver") || this.canBypassPlayerLimit(gameProfile))) { // Purpur - Allow player join full server by permission
- event.disallow(org.bukkit.event.player.PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure
- }
- }
-@@ -919,6 +_,20 @@
+@@ -770,6 +_,20 @@
}
}
@@ -36,7 +27,7 @@
+ }
+ }
+
-+ public void broadcastMessage(@Nullable net.kyori.adventure.text.Component message, boolean overlay) {
++ public void broadcastMessage(net.kyori.adventure.text.@Nullable Component message, boolean overlay) {
+ if (message != null) {
+ this.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), overlay);
+ }
@@ -46,11 +37,20 @@
public void broadcastAll(Packet> packet, ResourceKey dimension) {
for (ServerPlayer serverPlayer : this.players) {
if (serverPlayer.level().dimension() == dimension) {
-@@ -1002,6 +_,7 @@
- } else {
- b = (byte)(24 + permLevel);
- }
-+ if (b < 28 && player.getBukkitEntity().hasPermission("purpur.debug.f3n")) b = 28; // Purpur - Add permission for F3+N debug
-
+@@ -863,6 +_,7 @@
+ case ADMINS -> EntityEvent.PERMISSION_LEVEL_ADMINS;
+ case OWNERS -> EntityEvent.PERMISSION_LEVEL_OWNERS;
+ };
++ if (b < EntityEvent.PERMISSION_LEVEL_OWNERS && player.getBukkitEntity().hasPermission("purpur.debug.f3n")) b = EntityEvent.PERMISSION_LEVEL_OWNERS; // Purpur - Add permission for F3+N debug
player.connection.send(new ClientboundEntityEventPacket(player, b));
}
+
+@@ -874,7 +_,7 @@
+
+ // Paper start - whitelist verify event / login event
+ public LoginResult canBypassFullServerLogin(final NameAndId nameAndId, final LoginResult currentResult) {
+- final boolean shouldKick = this.players.size() >= this.getMaxPlayers() && !this.canBypassPlayerLimit(nameAndId);
++ final boolean shouldKick = this.players.size() >= this.getMaxPlayers() && !(/*player.hasPermission("purpur.joinfullserver") || */this.canBypassPlayerLimit(nameAndId)); // Purpur - Allow player join full server by permission TODO: this hasn't worked for a while, so comment it out until we can reliably check perms of the player joining
+ final io.papermc.paper.event.player.PlayerServerFullCheckEvent fullCheckEvent = new io.papermc.paper.event.player.PlayerServerFullCheckEvent(
+ new com.destroystokyo.paper.profile.CraftPlayerProfile(nameAndId),
+ io.papermc.paper.adventure.PaperAdventure.asAdventure(currentResult.message),
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch
index 384d2c33b..a9e87d51d 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch
@@ -1,10 +1,10 @@
--- a/net/minecraft/stats/ServerRecipeBook.java
+++ b/net/minecraft/stats/ServerRecipeBook.java
-@@ -138,6 +_,7 @@
- try {
- ResourceKey> resourceKey = ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(string));
- if (!isRecognized.test(resourceKey)) {
-+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressUnrecognizedRecipeErrors) // Purpur - Logger settings (suppressing pointless logs)
- LOGGER.error("Tried to load unrecognized recipe: {} removed now.", resourceKey);
- } else {
- output.accept(resourceKey);
+@@ -106,6 +_,7 @@
+ private void loadRecipes(List>> recipes, Consumer>> output, Predicate>> isRecognized) {
+ for (ResourceKey> resourceKey : recipes) {
+ if (!isRecognized.test(resourceKey)) {
++ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressUnrecognizedRecipeErrors) // Purpur - Logger settings (suppressing pointless logs)
+ LOGGER.error("Tried to load unrecognized recipe: {} removed now.", resourceKey);
+ } else {
+ output.accept(resourceKey);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatRules.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatRules.java.patch
index a70c7a253..45e676e4b 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatRules.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatRules.java.patch
@@ -2,19 +2,19 @@
+++ b/net/minecraft/world/damagesource/CombatRules.java
@@ -15,7 +_,7 @@
- public static float getDamageAfterAbsorb(LivingEntity entity, float damage, DamageSource damageSource, float armorValue, float armorToughness) {
+ public static float getDamageAfterAbsorb(LivingEntity entity, float damageAmount, DamageSource damageSource, float armorValue, float armorToughness) {
float f = 2.0F + armorToughness / 4.0F;
-- float f1 = Mth.clamp(armorValue - damage / f, armorValue * 0.2F, 20.0F);
-+ float f1 = Mth.clamp(armorValue - damage / f, armorValue * 0.2F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur - Add attribute clamping and armor limit config
+- float f1 = Mth.clamp(armorValue - damageAmount / f, armorValue * 0.2F, 20.0F);
++ float f1 = Mth.clamp(armorValue - damageAmount / f, armorValue * 0.2F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur - Add attribute clamping and armor limit config
float f2 = f1 / 25.0F;
ItemStack weaponItem = damageSource.getWeaponItem();
float f3;
@@ -30,7 +_,7 @@
}
- public static float getDamageAfterMagicAbsorb(float damage, float enchantModifiers) {
+ public static float getDamageAfterMagicAbsorb(float damageAmount, float enchantModifiers) {
- float f = Mth.clamp(enchantModifiers, 0.0F, 20.0F);
+ float f = Mth.clamp(enchantModifiers, 0.0F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur - Add attribute clamping and armor limit config
- return damage * (1.0F - f / 25.0F);
+ return damageAmount * (1.0F - f / 25.0F);
}
}
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch
index 0994f6fcd..c39efefcb 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/damagesource/CombatTracker.java
+++ b/net/minecraft/world/damagesource/CombatTracker.java
-@@ -54,7 +_,7 @@
+@@ -64,7 +_,7 @@
private Component getMessageForAssistedFall(Entity entity, Component entityDisplayName, String hasWeaponTranslationKey, String noWeaponTranslationKey) {
ItemStack itemStack = entity instanceof LivingEntity livingEntity ? livingEntity.getMainHandItem() : ItemStack.EMPTY;
@@ -9,7 +9,7 @@
? Component.translatable(hasWeaponTranslationKey, this.mob.getDisplayName(), entityDisplayName, itemStack.getDisplayName())
: Component.translatable(noWeaponTranslationKey, this.mob.getDisplayName(), entityDisplayName);
}
-@@ -98,6 +_,15 @@
+@@ -107,6 +_,15 @@
Component component = ComponentUtils.wrapInSquareBrackets(Component.translatable(string + ".link")).withStyle(INTENTIONAL_GAME_DESIGN_STYLE);
return Component.translatable(string + ".message", this.mob.getDisplayName(), component);
} else {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSource.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSource.java.patch
index 4fe0b6a16..f244d3350 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSource.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSource.java.patch
@@ -1,20 +1,21 @@
--- a/net/minecraft/world/damagesource/DamageSource.java
+++ b/net/minecraft/world/damagesource/DamageSource.java
-@@ -28,6 +_,8 @@
- private boolean sweep = false;
- private boolean melting = false;
- private boolean poison = false;
+@@ -24,6 +_,8 @@
+ private org.bukkit.block.@Nullable Block eventBlockDamager; // Relevant block set. damageSourcePosition is only used for bad respawn point explosion or custom damage
+ private org.bukkit.block.@Nullable BlockState fromBlockSnapshot; // Captured block snapshot when the eventBlockDamager is not relevant (e.g. for bad respawn point explosions the block is already removed)
+ private boolean critical; // Supports arrows and sweeping damage
+ private boolean scissors = false; // Purpur - Dont run with scissors!
+ private boolean stonecutter = false; // Purpur - Stonecutter damage
- @Nullable
- private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API
-@@ -58,6 +_,27 @@
- return this.poison;
+ public DamageSource knownCause(final org.bukkit.event.entity.EntityDamageEvent.DamageCause cause) {
+ final DamageSource damageSource = this.copy();
+@@ -35,6 +_,30 @@
+ return this.knownCause;
}
+ // Purpur start - Dont run with scissors!
+ public DamageSource scissors() {
++ this.knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.SUICIDE);
+ this.scissors = true;
+ return this;
+ }
@@ -23,8 +24,10 @@
+ return this.scissors;
+ }
+ // Purpur end - Dont run with scissors!
++
+ // Purpur start - - Stonecutter damage
+ public DamageSource stonecutter() {
++ this.knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.CONTACT);
+ this.stonecutter = true;
+ return this;
+ }
@@ -34,19 +37,19 @@
+ }
+ // Purpur end - Stonecutter damage
+
- // Paper start - fix DamageSource API
@Nullable
- public Entity getCustomEventDamager() {
-@@ -118,6 +_,8 @@
- damageSource.sweep = this.isSweep();
- damageSource.poison = this.isPoison();
- damageSource.melting = this.isMelting();
+ public Entity eventEntityDamager() {
+ return this.eventEntityDamager;
+@@ -94,6 +_,8 @@
+ damageSource.eventBlockDamager = this.eventBlockDamager;
+ damageSource.fromBlockSnapshot = this.fromBlockSnapshot;
+ damageSource.critical = this.critical;
+ damageSource.scissors = this.isScissors(); // Purpur - Dont run with scissors!
+ damageSource.stonecutter = this.isStonecutter(); // Purpur - Stonecutter damage
return damageSource;
}
// CraftBukkit end
-@@ -184,11 +_,20 @@
+@@ -157,11 +_,20 @@
} else {
Component component = this.causingEntity == null ? this.directEntity.getDisplayName() : this.causingEntity.getDisplayName();
ItemStack itemStack = this.causingEntity instanceof LivingEntity livingEntity1 ? livingEntity1.getMainHandItem() : ItemStack.EMPTY;
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSources.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSources.java.patch
index 9e3c63dab..29006dbaf 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSources.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSources.java.patch
@@ -1,26 +1,29 @@
--- a/net/minecraft/world/damagesource/DamageSources.java
+++ b/net/minecraft/world/damagesource/DamageSources.java
-@@ -45,11 +_,15 @@
- // CraftBukkit start
- private final DamageSource melting;
- private final DamageSource poison;
+@@ -42,6 +_,8 @@
+ private final DamageSource stalagmite;
+ private final DamageSource outsideBorder;
+ private final DamageSource genericKill;
+ private final DamageSource scissors; // Purpur - Dont run with scissors!
+ private final DamageSource stonecutter; // Purpur - Stonecutter damage
public DamageSources(RegistryAccess registry) {
this.damageTypes = registry.lookupOrThrow(Registries.DAMAGE_TYPE);
- this.melting = this.source(DamageTypes.ON_FIRE).melting();
- this.poison = this.source(DamageTypes.MAGIC).poison();
+@@ -70,6 +_,8 @@
+ this.stalagmite = this.source(DamageTypes.STALAGMITE);
+ this.outsideBorder = this.source(DamageTypes.OUTSIDE_BORDER);
+ this.genericKill = this.source(DamageTypes.GENERIC_KILL);
+ this.scissors = this.source(DamageTypes.MAGIC).scissors(); // Purpur - Dont run with scissors!
+ this.stonecutter = this.source(DamageTypes.MAGIC).stonecutter(); // Purpur - Stonecutter damage
- // CraftBukkit end
- this.inFire = this.source(DamageTypes.IN_FIRE);
- this.campfire = this.source(DamageTypes.CAMPFIRE);
-@@ -100,6 +_,17 @@
}
- // CraftBukkit end
-+ // Purpur start - Dont run with scissors!
+ private DamageSource source(ResourceKey damageTypeKey) {
+@@ -83,6 +_,18 @@
+ private DamageSource source(ResourceKey damageTypeKey, @Nullable Entity causingEntity, @Nullable Entity directEntity) {
+ return new DamageSource(this.damageTypes.getOrThrow(damageTypeKey), causingEntity, directEntity);
+ }
++
++ // Purpur start - Dont run with scissor
+ public DamageSource scissors() {
+ return this.scissors;
+ }
@@ -31,6 +34,6 @@
+ return this.stonecutter;
+ }
+ // Purpur end - Stonecutter damage
+
public DamageSource inFire() {
return this.inFire;
- }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch
index 48b0053a0..0e8d7e3f7 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch
@@ -5,9 +5,9 @@
@Override
public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) {
- if (entity.getHealth() > 1.0F) {
-- entity.hurtServer(level, entity.damageSources().poison(), 1.0F); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON
+- entity.hurtServer(level, entity.damageSources().magic().knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.POISON), 1.0F); // CraftBukkit
+ if (entity.getHealth() > entity.level().purpurConfig.entityMinimalHealthPoison) { // Purpur
-+ entity.hurtServer(level, entity.damageSources().poison(), entity.level().purpurConfig.entityPoisonDegenerationAmount); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON // Purpur - Config MobEffect by world
++ entity.hurtServer(level, entity.damageSources().magic().knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.POISON), entity.level().purpurConfig.entityPoisonDegenerationAmount); // CraftBukkit // Purpur - Config MobEffect by world
}
return true;
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch
index 31b781a7f..77a30ef9a 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch
@@ -1,28 +1,26 @@
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
-@@ -136,7 +_,7 @@
+@@ -153,6 +_,7 @@
import org.slf4j.Logger;
- public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker
--
+ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Nameable, ItemOwner, SlotProvider, EntityAccess, ScoreHolder, DataComponentGetter, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker
+ public static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur - Configurable entity base attributes
// CraftBukkit start
private static final int CURRENT_LEVEL = 2;
- public boolean preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; keep initial motion on first setPositionRotation
-@@ -253,9 +_,10 @@
+ static boolean isLevelAtLeast(ValueInput input, int level) {
+@@ -282,8 +_,9 @@
public double xOld;
public double yOld;
public double zOld;
+ public float maxUpStep; // Purpur - Add option to set armorstand step height
public boolean noPhysics;
- private boolean wasOnFire;
- public final RandomSource random = SHARED_RANDOM; // Paper - Share random for entities to make them more random
+ public final RandomSource random; // Paper - Share random for entities to make them more random // Add toggle for RNG manipulation
public int tickCount;
- private int remainingFireTicks = -this.getFireImmuneTicks();
+ private int remainingFireTicks;
public boolean wasTouchingWater;
-@@ -289,8 +_,8 @@
- public PortalProcessor portalProcess;
+@@ -316,8 +_,8 @@
+ public @Nullable PortalProcessor portalProcess;
public int portalCooldown;
private boolean invulnerable;
- protected UUID uuid = Mth.createInsecureUUID(this.random);
@@ -32,7 +30,7 @@
private boolean hasGlowingTag;
private final Set tags = new io.papermc.paper.util.SizeLimitedSet<>(new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(), MAX_ENTITY_TAG_COUNT); // Paper - fully limit tag size - replace set impl
private final double[] pistonDeltas = new double[]{0.0, 0.0, 0.0};
-@@ -342,6 +_,7 @@
+@@ -373,6 +_,7 @@
public long activatedTick = Integer.MIN_VALUE;
public boolean isTemporarilyActive;
public long activatedImmunityTick = Integer.MIN_VALUE;
@@ -40,7 +38,7 @@
public void inactiveTick() {
}
-@@ -522,10 +_,21 @@
+@@ -535,10 +_,21 @@
}
// Paper end - optimise entity tracker
@@ -50,10 +48,10 @@
+ }
+ // Purpur end - Add canSaveToDisk to Entity
+
- public Entity(EntityType> entityType, Level level) {
- this.type = entityType;
+ public Entity(EntityType> type, Level level) {
+ this.type = type;
this.level = level;
- this.dimensions = entityType.getDimensions();
+ this.dimensions = type.getDimensions();
+ // Purpur start - Add toggle for RNG manipulation
+ this.random = level == null || level.purpurConfig.entitySharedRandom ? SHARED_RANDOM : RandomSource.create();
+ this.uuid = Mth.createInsecureUUID(this.random);
@@ -62,15 +60,15 @@
this.position = Vec3.ZERO;
this.blockPosition = BlockPos.ZERO;
this.chunkPosition = ChunkPos.ZERO;
-@@ -904,6 +_,7 @@
+@@ -931,6 +_,7 @@
&& this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> this.getY() >= v)
&& (!(this instanceof Player player) || !player.getAbilities().invulnerable))) {
// Paper end - Configurable nether ceiling damage
-+ if (this.level.purpurConfig.teleportOnNetherCeilingDamage && this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER && this instanceof ServerPlayer player) player.teleport(io.papermc.paper.util.MCUtil.toLocation(this.level, this.level.getSharedSpawnPos())); else // Purpur - Add option to teleport to spawn on nether ceiling damage
++ if (this.level.purpurConfig.teleportOnNetherCeilingDamage && this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER && this instanceof ServerPlayer player) player.teleport(org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.level.levelData.getRespawnData().pos(), this.level)); else // Purpur - Add option to teleport to spawn on nether ceiling damage
this.onBelowWorld();
}
}
-@@ -1826,7 +_,7 @@
+@@ -1960,7 +_,7 @@
}
public boolean fireImmune() {
@@ -78,53 +76,38 @@
+ return this.immuneToFire != null ? immuneToFire : this.getType().fireImmune(); // Purpur - add fire immune API
}
- public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource source) {
-@@ -1895,7 +_,7 @@
- return this.isInWater() || flag;
- }
-
-- public void updateInWaterStateAndDoWaterCurrentPushing() {
-+ public void updateInWaterStateAndDoWaterCurrentPushing() { // Purpur - Movement options for armor stands - package-private -> public - TODO: use AT file
- if (this.getVehicle() instanceof AbstractBoat abstractBoat && !abstractBoat.isUnderWater()) {
- this.wasTouchingWater = false;
- } else if (this.updateFluidHeightAndDoFluidPushing(FluidTags.WATER, 0.014)) {
-@@ -2521,6 +_,13 @@
- compound.putBoolean("Paper.FreezeLock", true);
+ public boolean causeFallDamage(double fallDistance, float damageMultiplier, DamageSource damageSource) {
+@@ -2658,6 +_,11 @@
+ output.putBoolean("Paper.FreezeLock", true);
}
// Paper end
-+
+ // Purpur start - Fire immune API
+ if (immuneToFire != null) {
-+ compound.putBoolean("Purpur.FireImmune", immuneToFire);
++ output.putBoolean("Purpur.FireImmune", immuneToFire);
+ }
+ // Purpur end - Fire immune API
-+
- return compound;
- } catch (Throwable var9) {
- CrashReport crashReport = CrashReport.forThrowable(var9, "Saving entity NBT");
-@@ -2670,6 +_,13 @@
- freezeLocked = compound.getBoolean("Paper.FreezeLock");
+ } catch (Throwable var7) {
+ CrashReport crashReport = CrashReport.forThrowable(var7, "Saving entity NBT");
+ CrashReportCategory crashReportCategory = crashReport.addCategory("Entity being saved");
+@@ -2778,6 +_,9 @@
}
+ freezeLocked = input.getBooleanOr("Paper.FreezeLock", false);
// Paper end
+
-+ // Purpur start - Fire immune API
-+ if (compound.contains("Purpur.FireImmune")) {
-+ immuneToFire = compound.getBoolean("Purpur.FireImmune");
-+ }
-+ // Purpur end - Fire immune API
++ immuneToFire = input.read("Purpur.FireImmune", com.mojang.serialization.Codec.BOOL).orElse(null); // Purpur - Fire immune API
+
- } catch (Throwable var17) {
- CrashReport crashReport = CrashReport.forThrowable(var17, "Loading entity NBT");
+ } catch (Throwable var7) {
+ CrashReport crashReport = CrashReport.forThrowable(var7, "Loading entity NBT");
CrashReportCategory crashReportCategory = crashReport.addCategory("Entity being loaded");
-@@ -2916,6 +_,7 @@
- if (this.isAlive() && this instanceof Leashable leashable) {
- if (leashable.getLeashHolder() == player) {
- if (!this.level().isClientSide()) {
-+ if (hand == InteractionHand.OFF_HAND && (level().purpurConfig.villagerCanBeLeashed || level().purpurConfig.wanderingTraderCanBeLeashed) && this instanceof net.minecraft.world.entity.npc.AbstractVillager) return InteractionResult.CONSUME; // Purpur - Allow leashing villagers
- // CraftBukkit start - fire PlayerUnleashEntityEvent
- // Paper start - Expand EntityUnleashEvent
- org.bukkit.event.player.PlayerUnleashEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand, !player.hasInfiniteMaterials());
-@@ -3241,15 +_,18 @@
+@@ -3041,6 +_,7 @@
+ if (this.isAlive() && this instanceof Leashable leashable2) {
+ if (leashable2.getLeashHolder() == player) {
+ if (!this.level().isClientSide()) {
++ if (hand == InteractionHand.OFF_HAND && (level().purpurConfig.villagerCanBeLeashed || level().purpurConfig.wanderingTraderCanBeLeashed) && this instanceof net.minecraft.world.entity.npc.villager.AbstractVillager) return InteractionResult.CONSUME; // Purpur - Allow leashing villagers
+ // Paper start - EntityUnleashEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerUnleashEntityEvent(
+ leashable2, player, hand, !player.hasInfiniteMaterials(), true
+@@ -3471,15 +_,18 @@
return Vec3.directionFromRotation(this.getRotationVector());
}
@@ -144,7 +127,7 @@
}
}
}
-@@ -3454,7 +_,7 @@
+@@ -3685,7 +_,7 @@
}
public int getMaxAirSupply() {
@@ -153,8 +136,8 @@
}
public int getAirSupply() {
-@@ -3949,7 +_,7 @@
- // CraftBukkit end
+@@ -4220,7 +_,7 @@
+ }
public boolean canUsePortal(boolean allowPassengers) {
- return (allowPassengers || !this.isPassenger()) && this.isAlive();
@@ -162,7 +145,7 @@
}
public boolean canTeleport(Level fromLevel, Level toLevel) {
-@@ -4481,6 +_,12 @@
+@@ -4739,6 +_,12 @@
return Mth.lerp(partialTick, this.yRotO, this.yRot);
}
@@ -175,7 +158,7 @@
// Paper start - optimise collisions
public boolean updateFluidHeightAndDoFluidPushing(final TagKey fluid, final double flowScale) {
if (this.touchingUnloadedChunk()) {
-@@ -4879,7 +_,7 @@
+@@ -5159,7 +_,7 @@
}
public float maxUpStep() {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntityType.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntityType.java.patch
index 6b937ec99..f33120729 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntityType.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntityType.java.patch
@@ -1,23 +1,23 @@
--- a/net/minecraft/world/entity/EntityType.java
+++ b/net/minecraft/world/entity/EntityType.java
-@@ -1083,6 +_,16 @@
+@@ -1240,6 +_,16 @@
return register(vanillaEntityId(key), builder);
}
+ // Purpur start - PlayerSetSpawnerTypeWithEggEvent
+ public static EntityType> getFromBukkitType(org.bukkit.entity.EntityType bukkitType) {
-+ return getFromKey(ResourceLocation.parse(bukkitType.getKey().toString()));
++ return getFromKey(Identifier.parse(bukkitType.getKey().toString()));
+ }
+
-+ public static EntityType> getFromKey(ResourceLocation location) {
++ public static EntityType> getFromKey(Identifier location) {
+ return BuiltInRegistries.ENTITY_TYPE.getValue(location);
+ }
+ // Purpur end - PlayerSetSpawnerTypeWithEggEvent
+
- public static ResourceLocation getKey(EntityType> entityType) {
+ public static Identifier getKey(EntityType> entityType) {
return BuiltInRegistries.ENTITY_TYPE.getKey(entityType);
}
-@@ -1312,6 +_,16 @@
+@@ -1467,6 +_,16 @@
return this.category;
}
@@ -34,19 +34,11 @@
public String getDescriptionId() {
return this.descriptionId;
}
-@@ -1370,7 +_,14 @@
- entity.load(tag);
- },
- // Paper end - Don't fire sync event during generation
-- () -> LOGGER.warn("Skipping Entity with id {}", tag.getString("id"))
-+ // Purpur start - log skipped entity's position
-+ () -> {LOGGER.warn("Skipping Entity with id {}", tag.getString("id"));
-+ try {
-+ ListTag pos = tag.getList("Pos", 6);
-+ EntityType.LOGGER.warn("Location: {} {},{},{}", level.getWorld().getName(), pos.getDouble(0), pos.getDouble(1), pos.getDouble(2));
-+ } catch (Throwable ignore) {}
-+ }
-+ // Purpur end - log skipped entity's position
- );
- }
-
+@@ -1528,6 +_,7 @@
+ // Paper start - Add logging for debugging entity tags with invalid ids
+ () -> {
+ LOGGER.warn("Skipping Entity with id {}", input.getStringOr("id", "[invalid]"));
++ LOGGER.warn("Location: {} {}", level.getWorld().getName(), input.read("Pos", net.minecraft.world.phys.Vec3.CODEC).orElse(net.minecraft.world.phys.Vec3.ZERO)); // Purpur - log skipped entity's position
+ if ((DEBUG_ENTITIES_WITH_INVALID_IDS || level.getCraftServer().getServer().isDebugging()) && input instanceof TagValueInput tagInput) {
+ LOGGER.warn("Skipped entity tag: {}", tagInput.input);
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch
index a14e7f6a5..76b98442d 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch
@@ -1,15 +1,15 @@
--- a/net/minecraft/world/entity/ExperienceOrb.java
+++ b/net/minecraft/world/entity/ExperienceOrb.java
-@@ -323,7 +_,7 @@
+@@ -355,7 +_,7 @@
public void playerTouch(Player entity) {
if (entity instanceof ServerPlayer serverPlayer) {
if (entity.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent
-- entity.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(entity, 2, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2;
-+ entity.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(entity, this.level().purpurConfig.playerExpPickupDelay, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; // Purpur - Configurable player pickup exp delay
+- entity.takeXpDelay = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(entity, 2, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entity.takeXpDelay = 2;
++ entity.takeXpDelay = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(entity, this.level().purpurConfig.playerExpPickupDelay, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entity.takeXpDelay = 2; // Purpur - Configurable player pickup exp delay
entity.take(this, 1);
- int i = this.repairPlayerItems(serverPlayer, this.value);
+ int i = this.repairPlayerItems(serverPlayer, this.getValue());
if (i > 0) {
-@@ -339,7 +_,7 @@
+@@ -371,7 +_,7 @@
}
private int repairPlayerItems(ServerPlayer player, int value) {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch
index bf89dba4b..a99629671 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch
@@ -1,37 +1,37 @@
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
-@@ -459,6 +_,12 @@
- if (d < 0.0) {
- double damagePerBlock = this.level().getWorldBorder().getDamagePerBlock();
- if (damagePerBlock > 0.0) {
-+ // Purpur start - Add option to teleport to spawn if outside world border
-+ if (this.level().purpurConfig.teleportIfOutsideBorder && this instanceof ServerPlayer serverPlayer) {
-+ serverPlayer.teleport(io.papermc.paper.util.MCUtil.toLocation(this.level(), this.level().getSharedSpawnPos()));
-+ return;
-+ }
-+ // Purpur end - Add option to teleport to spawn if outside world border
- this.hurtServer(serverLevel1, this.damageSources().outOfBorder(), Math.max(1, Mth.floor(-d * damagePerBlock)));
- }
+@@ -447,6 +_,12 @@
+ if (d < 0.0) {
+ double damagePerBlock = serverLevel1.getWorldBorder().getDamagePerBlock();
+ if (damagePerBlock > 0.0) {
++ // Purpur start - Add option to teleport to spawn if outside world border
++ if (this.level().purpurConfig.teleportIfOutsideBorder && this instanceof ServerPlayer serverPlayer) {
++ serverPlayer.teleport(org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.level().levelData.getRespawnData().pos(), this.level()));
++ return;
++ }
++ // Purpur end - Add option to teleport to spawn if outside world border
+ this.hurtServer(serverLevel1, this.damageSources().outOfBorder(), Math.max(1, Mth.floor(-d * damagePerBlock)));
}
-@@ -472,7 +_,7 @@
- && (!flag || !((Player)this).getAbilities().invulnerable);
- if (flag1) {
- this.setAirSupply(this.decreaseAirSupply(this.getAirSupply()));
-- if (this.getAirSupply() == -20) {
-+ if (this.getAirSupply() == -this.level().purpurConfig.drowningDamageInterval) { // Purpur - Drowning Settings
+ }
+@@ -462,7 +_,7 @@
+ if (this.shouldTakeDrowningDamage()) {
this.setAirSupply(0);
- Vec3 deltaMovement = this.getDeltaMovement();
-
-@@ -492,7 +_,7 @@
- );
- }
-
-- this.hurt(this.damageSources().drown(), 2.0F);
-+ this.hurt(this.damageSources().drown(), (float) this.level().purpurConfig.damageFromDrowning); // Purpur - Drowning Settings
+ serverLevel1.broadcastEntityEvent(this, EntityEvent.DROWN_PARTICLES);
+- this.hurtServer(serverLevel1, this.damageSources().drown(), 2.0F);
++ this.hurtServer(serverLevel1, this.damageSources().drown(), (float) this.level().purpurConfig.damageFromDrowning); // Purpur - Drowning Settings
}
- } else if (this.getAirSupply() < this.getMaxAirSupply()) {
+ } else if (this.getAirSupply() < this.getMaxAirSupply() && MobEffectUtil.shouldEffectsRefillAirsupply(this)) {
this.setAirSupply(this.increaseAirSupply(this.getAirSupply()));
-@@ -1009,14 +_,32 @@
+@@ -522,7 +_,7 @@
+ }
+
+ protected boolean shouldTakeDrowningDamage() {
+- return this.getAirSupply() <= -20;
++ return this.getAirSupply() <= -this.level().purpurConfig.drowningDamageInterval; // Purpur - Drowning Settings
+ }
+
+ @Override
+@@ -1050,14 +_,32 @@
if (lookingEntity != null) {
ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD);
EntityType> type = lookingEntity.getType();
@@ -72,7 +72,7 @@
return d;
}
-@@ -1063,6 +_,7 @@
+@@ -1104,6 +_,7 @@
Iterator iterator = this.activeEffects.values().iterator();
while (iterator.hasNext()) {
MobEffectInstance effect = iterator.next();
@@ -80,7 +80,7 @@
EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, cause, EntityPotionEffectEvent.Action.CLEARED);
if (event.isCancelled()) {
continue;
-@@ -1372,6 +_,24 @@
+@@ -1424,6 +_,24 @@
this.stopSleeping();
}
@@ -105,27 +105,38 @@
this.noActionTime = 0;
if (amount < 0.0F) {
amount = 0.0F;
-@@ -1536,11 +_,11 @@
- protected Player resolvePlayerResponsibleForDamage(DamageSource damageSource) {
+@@ -1685,10 +_,10 @@
+ protected @Nullable Player resolvePlayerResponsibleForDamage(DamageSource damageSource) {
Entity entity = damageSource.getEntity();
if (entity instanceof Player player) {
-- this.lastHurtByPlayerTime = 100;
-+ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur - Config for mob last hurt by player time
- this.lastHurtByPlayer = player;
- return player;
+- this.setLastHurtByPlayer(player, 100);
++ this.setLastHurtByPlayer(player, this.level().purpurConfig.mobLastHurtByPlayerTime); // Purpur - Config for mob last hurt by player time
} else if (entity instanceof Wolf wolf && wolf.isTame()) {
-- this.lastHurtByPlayerTime = 100;
-+ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur - Config for mob last hurt by player time
- if (wolf.getOwner() instanceof Player player1) {
- this.lastHurtByPlayer = player1;
+ if (wolf.getOwnerReference() != null) {
+- this.setLastHurtByPlayer(wolf.getOwnerReference().getUUID(), 100);
++ this.setLastHurtByPlayer(wolf.getOwnerReference().getUUID(), this.level().purpurConfig.mobLastHurtByPlayerTime); // Purpur - Config for mob last hurt by player time
} else {
-@@ -1594,6 +_,18 @@
+ this.lastHurtByPlayer = null;
+ this.lastHurtByPlayerMemoryTime = 0;
+@@ -1739,6 +_,30 @@
}
}
+ // Purpur start - Totems work in inventory
+ if (level().purpurConfig.totemOfUndyingWorksInInventory && this instanceof ServerPlayer player && (itemStack == null || itemStack.getItem() != Items.TOTEM_OF_UNDYING) && player.getBukkitEntity().hasPermission("purpur.inventory_totem")) {
-+ for (ItemStack item : player.getInventory().items) {
++ for (ItemStack item : player.getInventory().getNonEquipmentItems()) {
++ if (item.getItem() == Items.TOTEM_OF_UNDYING) {
++ itemInHand = item;
++ itemStack = item.copy();
++ break;
++ }
++ }
++ }
++ // Purpur end - Totems work in inventory
++
++ // Purpur start - Totems work in inventory
++ if (level().purpurConfig.totemOfUndyingWorksInInventory && this instanceof ServerPlayer player && (itemStack == null || itemStack.getItem() != Items.TOTEM_OF_UNDYING) && player.getBukkitEntity().hasPermission("purpur.inventory_totem")) {
++ for (ItemStack item : player.getInventory().getNonEquipmentItems()) {
+ if (item.getItem() == Items.TOTEM_OF_UNDYING) {
+ itemInHand = item;
+ itemStack = item.copy();
@@ -138,15 +149,15 @@
final org.bukkit.inventory.EquipmentSlot handSlot = (hand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand) : null;
final EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), handSlot);
event.setCancelled(itemStack == null);
-@@ -1790,6 +_,7 @@
- boolean flag = this.lastHurtByPlayerTime > 0;
+@@ -1920,6 +_,7 @@
+ boolean flag = this.lastHurtByPlayerMemoryTime > 0;
this.dropEquipment(level); // CraftBukkit - from below
- if (this.shouldDropLoot() && level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
+ if (this.shouldDropLoot(level)) {
+ if (!(damageSource.is(net.minecraft.world.damagesource.DamageTypes.CRAMMING) && level().purpurConfig.disableDropsOnCrammingDeath)) { // Purpur - Disable loot drops on death by cramming
this.dropFromLootTable(level, damageSource, flag);
// Paper start
final boolean prev = this.clearEquipmentSlots;
-@@ -1798,6 +_,7 @@
+@@ -1928,6 +_,7 @@
// Paper end
this.dropCustomDeathLoot(level, damageSource, flag);
this.clearEquipmentSlots = prev; // Paper
@@ -154,7 +165,7 @@
}
// CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment
-@@ -2989,6 +_,7 @@
+@@ -3202,6 +_,7 @@
float f = (float)(d * 10.0 - 3.0);
if (f > 0.0F) {
this.playSound(this.getFallDamageSound((int)f), 1.0F, 1.0F);
@@ -162,7 +173,7 @@
this.hurt(this.damageSources().flyIntoWall(), f);
}
}
-@@ -4398,6 +_,12 @@
+@@ -4666,6 +_,12 @@
? slot == EquipmentSlot.MAINHAND && this.canUseSlot(EquipmentSlot.MAINHAND)
: slot == equippable.slot() && this.canUseSlot(equippable.slot()) && equippable.canBeEquippedBy(this.getType());
}
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Mob.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Mob.java.patch
index 918032262..35009fa56 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Mob.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Mob.java.patch
@@ -1,14 +1,14 @@
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
-@@ -145,6 +_,7 @@
- private BlockPos restrictCenter = BlockPos.ZERO;
- private float restrictRadius = -1.0F;
+@@ -150,6 +_,7 @@
+ private int homeRadius = -1;
public boolean aware = true; // CraftBukkit
+ public net.kyori.adventure.util.TriState despawnInPeacefulOverride = net.kyori.adventure.util.TriState.NOT_SET; // Paper - allow changing despawnInPeaceful
+ public int ticksSinceLastInteraction; // Purpur - Entity lifespan
- protected Mob(EntityType extends Mob> entityType, Level level) {
- super(entityType, level);
-@@ -294,6 +_,7 @@
+ protected Mob(EntityType extends Mob> type, Level level) {
+ super(type, level);
+@@ -292,6 +_,7 @@
target = null;
}
}
@@ -16,7 +16,7 @@
this.target = target;
return true;
// CraftBukkit end
-@@ -337,7 +_,27 @@
+@@ -335,7 +_,27 @@
}
profilerFiller.pop();
@@ -44,28 +44,24 @@
+ // Purpur end - Entity lifespan
@Override
- protected void playHurtSound(DamageSource source) {
-@@ -486,6 +_,7 @@
- compound.putBoolean("NoAI", this.isNoAi());
+ protected void playHurtSound(DamageSource damageSource) {
+@@ -439,6 +_,7 @@
+ output.putString("Paper.DespawnInPeacefulOverride", this.despawnInPeacefulOverride.name());
}
- compound.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit
-+ compound.putInt("Purpur.ticksSinceLastInteraction", this.ticksSinceLastInteraction); // Purpur - Entity lifespan
+ // Paper end - allow changing despawnInPeaceful
++ output.putInt("Purpur.ticksSinceLastInteraction", this.ticksSinceLastInteraction); // Purpur - Entity lifespan
}
@Override
-@@ -568,6 +_,11 @@
- this.aware = compound.getBoolean("Bukkit.Aware");
- }
- // CraftBukkit end
-+ // Purpur start - Entity lifespan
-+ if (compound.contains("Purpur.ticksSinceLastInteraction")) {
-+ this.ticksSinceLastInteraction = compound.getInt("Purpur.ticksSinceLastInteraction");
-+ }
-+ // Purpur end - Entity lifespan
+@@ -466,6 +_,7 @@
+ this.lootTableSeed = input.getLongOr("DeathLootTableSeed", 0L);
+ this.setNoAi(input.getBooleanOr("NoAI", false));
+ this.aware = input.getBooleanOr("Bukkit.Aware", true); // CraftBukkit
++ this.ticksSinceLastInteraction = input.getIntOr("Purpur.ticksSinceLastInteraction", 0); // Purpur- Entity lifespan
+ // Paper start - allow changing despawnInPeaceful
+ this.despawnInPeacefulOverride = readDespawnInPeacefulOverride(input);
}
-
- @Override
-@@ -1280,7 +_,7 @@
+@@ -1246,7 +_,7 @@
);
}
@@ -74,10 +70,10 @@
return spawnGroupData;
}
-@@ -1619,6 +_,7 @@
- this.playAttackSound();
+@@ -1597,6 +_,7 @@
}
+ this.lungeForwardMaybe();
+ if (target instanceof net.minecraft.server.level.ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur - Entity lifespan
return flag;
}
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch
index c457ae742..f499d70f9 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
+++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
-@@ -86,7 +_,7 @@
+@@ -85,7 +_,7 @@
};
// Paper start - optimise POI access
final java.util.List, BlockPos>> poiposes = new java.util.ArrayList<>();
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java.patch
index 2bbc2776e..694422e8b 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java
+++ b/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java
-@@ -46,6 +_,7 @@
+@@ -45,6 +_,7 @@
@Override
public boolean canStillUse(ServerLevel level, Villager entity, long gameTime) {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch
new file mode 100644
index 000000000..3ff26e6d1
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch
@@ -0,0 +1,42 @@
+--- a/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java
++++ b/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java
+@@ -285,7 +_,7 @@
+ LevelChunk chunkNow = level.getChunkSource().getChunkNow(chunkPos.x, chunkPos.z);
+ if (chunkNow != null) {
+ for (BlockEntity blockEntity : chunkNow.getBlockEntities().values()) {
+- if (blockEntity instanceof ChestBlockEntity chestBlockEntity) {
++ if (blockEntity instanceof net.minecraft.world.level.block.entity.BaseContainerBlockEntity chestBlockEntity) { // Purpur - copper golem can place items in barrels or shulkers option
+ double d1 = chestBlockEntity.getBlockPos().distToCenterSqr(mob.position());
+ if (d1 < d) {
+ TransportItemsBetweenContainers.TransportItemTarget transportItemTarget1 = this.isTargetValidToPick(
+@@ -369,7 +_,11 @@
+ }
+
+ private boolean isTargetBlocked(Level level, TransportItemsBetweenContainers.TransportItemTarget target) {
+- return ChestBlock.isChestBlockedAt(level, target.pos);
++ // Purpur start - copper golem can place items in barrels or shulkers option
++ boolean isBarrelBlocked = !level.purpurConfig.copperGolemCanOpenBarrel && target.state.is(net.minecraft.world.level.block.Blocks.BARREL);
++ boolean isShulkerBlocked = !level.purpurConfig.copperGolemCanOpenShulker && target.blockEntity instanceof net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity shulkerBoxBlockEntity && !net.minecraft.world.level.block.ShulkerBoxBlock.canOpen(target.state, level, target.pos, shulkerBoxBlockEntity);
++ return target.state.is(net.minecraft.world.level.block.Blocks.BARREL) ? isBarrelBlocked : isShulkerBlocked || net.minecraft.world.level.block.ChestBlock.isChestBlockedAt(level, target.pos);
++ // Purpur end - copper golem can place items in barrels or shulkers option
+ }
+
+ private boolean targetHasNotChanged(Level level, TransportItemsBetweenContainers.TransportItemTarget target) {
+@@ -446,7 +_,7 @@
+ }
+
+ private boolean isWantedBlock(PathfinderMob mob, BlockState state) {
+- return isPickingUpItems(mob) ? this.sourceBlockType.test(state) : this.destinationBlockType.test(state);
++ return isPickingUpItems(mob) ? this.sourceBlockType.test(state) : (mob.level().purpurConfig.copperGolemCanOpenBarrel && state.is(net.minecraft.world.level.block.Blocks.BARREL)) || (mob.level().purpurConfig.copperGolemCanOpenShulker && state.is(net.minecraft.tags.BlockTags.SHULKER_BOXES)) || this.destinationBlockType.test(state); // Purpur - copper golem can place items in barrels or shulkers option
+ }
+
+ private static double getInteractionRange(PathfinderMob mob) {
+@@ -525,7 +_,7 @@
+ int i = 0;
+
+ for (ItemStack itemStack : container) {
+- if (!itemStack.isEmpty()) {
++ if (!itemStack.isEmpty() && (!(container instanceof net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity) || !itemStack.is(net.minecraft.tags.ItemTags.SHULKER_BOXES))) { // Purpur - copper golem can place items in barrels or shulkers option
+ int min = Math.min(itemStack.getCount(), 16);
+ return container.removeItem(i, min);
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch
index f321637d7..dbec726c4 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch
@@ -1,11 +1,11 @@
--- a/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java
+++ b/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java
-@@ -58,7 +_,7 @@
+@@ -59,7 +_,7 @@
if (firstPassenger instanceof Player player) {
int temper = this.horse.getTemper();
int maxTemper = this.horse.getMaxTemper();
- if (maxTemper > 0 && this.horse.getRandom().nextInt(maxTemper) < temper && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this.horse, ((org.bukkit.craftbukkit.entity.CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { // CraftBukkit - fire EntityTameEvent
-+ if (this.horse.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials() || maxTemper > 0 && this.horse.getRandom().nextInt(maxTemper) < temper && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this.horse, ((org.bukkit.craftbukkit.entity.CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { // CraftBukkit - fire EntityTameEvent // Purpur - Config to always tame in Creative
++ if (((this.horse.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials()) || (maxTemper > 0 && this.horse.getRandom().nextInt(maxTemper) < temper)) && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this.horse, ((org.bukkit.craftbukkit.entity.CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { // CraftBukkit - fire EntityTameEvent // Purpur - Config to always tame in Creative
this.horse.tameWithName(player);
return;
}
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch
index b072c14f4..6600c8fdd 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/ai/goal/SwellGoal.java
+++ b/net/minecraft/world/entity/ai/goal/SwellGoal.java
-@@ -55,6 +_,14 @@
+@@ -54,6 +_,14 @@
this.creeper.setSwellDir(-1);
} else {
this.creeper.setSwellDir(1);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/targeting/TargetingConditions.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/targeting/TargetingConditions.java.patch
index df5fd519b..f090e4c9a 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/targeting/TargetingConditions.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/targeting/TargetingConditions.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
+++ b/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
-@@ -64,6 +_,10 @@
+@@ -63,6 +_,10 @@
return false;
} else if (this.selector != null && !this.selector.test(target, level)) {
return false;
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch
deleted file mode 100644
index fc1ce3bb3..000000000
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch
+++ /dev/null
@@ -1,23 +0,0 @@
---- a/net/minecraft/world/entity/ambient/Bat.java
-+++ b/net/minecraft/world/entity/ambient/Bat.java
-@@ -231,7 +_,7 @@
- } else {
- int maxLocalRawBrightness = level.getMaxLocalRawBrightness(pos);
- int i = 4;
-- if (isHalloween()) {
-+ if (Bat.isHalloweenSeason(level.getMinecraftWorld())) { // Purpur - Halloween options and optimizations
- i = 7;
- } else if (randomSource.nextBoolean()) {
- return false;
-@@ -243,6 +_,11 @@
- }
- }
-
-+ // 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 - Halloween options and optimizations
- private static boolean isHalloween() {
- LocalDate localDate = LocalDate.now();
- int i = localDate.get(ChronoField.DAY_OF_MONTH);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch
index 56a99c436..c6916a32a 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch
@@ -1,24 +1,24 @@
--- a/net/minecraft/world/entity/animal/Animal.java
+++ b/net/minecraft/world/entity/animal/Animal.java
-@@ -142,7 +_,7 @@
+@@ -146,7 +_,7 @@
ItemStack itemInHand = player.getItemInHand(hand);
if (this.isFood(itemInHand)) {
int age = this.getAge();
-- if (!this.level().isClientSide && age == 0 && this.canFallInLove()) {
-+ if (!this.level().isClientSide && age == 0 && this.canFallInLove() && (this.level().purpurConfig.animalBreedingCooldownSeconds <= 0 || !this.level().hasBreedingCooldown(player.getUUID(), this.getClass()))) { // Purpur - Add adjustable breeding cooldown to config
+- if (player instanceof ServerPlayer serverPlayer && age == 0 && this.canFallInLove()) {
++ if (player instanceof ServerPlayer serverPlayer && age == 0 && this.canFallInLove() && (this.level().purpurConfig.animalBreedingCooldownSeconds <= 0 || !this.level().hasBreedingCooldown(player.getUUID(), this.getClass()))) { // Purpur - Add adjustable breeding cooldown to config
final ItemStack breedCopy = itemInHand.copy(); // Paper - Fix EntityBreedEvent copying
this.usePlayerItem(player, hand, itemInHand);
- this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying
-@@ -239,10 +_,20 @@
- public void spawnChildFromBreeding(ServerLevel level, Animal mate) {
- AgeableMob breedOffspring = this.getBreedOffspring(level, mate);
+ this.setInLove(serverPlayer, breedCopy); // Paper - Fix EntityBreedEvent copying
+@@ -227,10 +_,20 @@
+ public void spawnChildFromBreeding(ServerLevel level, Animal partner) {
+ AgeableMob breedOffspring = this.getBreedOffspring(level, partner);
if (breedOffspring != null) {
- breedOffspring.setBaby(true);
-- breedOffspring.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F);
+- breedOffspring.snapTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F);
+ //breedOffspring.setBaby(true); // Purpur - Add adjustable breeding cooldown to config - moved down
-+ //breedOffspring.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); // Purpur - Add adjustable breeding cooldown to config - moved down
- // CraftBukkit start - call EntityBreedEvent
- ServerPlayer breeder = Optional.ofNullable(this.getLoveCause()).or(() -> Optional.ofNullable(mate.getLoveCause())).orElse(null);
++ //breedOffspring.snapTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); // Purpur - Add adjustable breeding cooldown to config - moved down
+ // CraftBukkit start - Call EntityBreedEvent
+ ServerPlayer breeder = Optional.ofNullable(this.getLoveCause()).or(() -> Optional.ofNullable(partner.getLoveCause())).orElse(null);
+ // Purpur start - Add adjustable breeding cooldown to config
+ if (breeder != null && level.purpurConfig.animalBreedingCooldownSeconds > 0) {
+ if (level.hasBreedingCooldown(breeder.getUUID(), this.getClass())) {
@@ -27,8 +27,8 @@
+ level.addBreedingCooldown(breeder.getUUID(), this.getClass());
+ }
+ breedOffspring.setBaby(true);
-+ breedOffspring.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F);
++ breedOffspring.snapTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F);
+ // Purpur end - Add adjustable breeding cooldown to config
int experience = this.getRandom().nextInt(7) + 1;
- org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(breedOffspring, this, mate, breeder, this.breedItem, experience);
+ org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(breedOffspring, this, partner, breeder, this.breedItem, experience);
if (entityBreedEvent.isCancelled()) {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Bee.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Bee.java.patch
deleted file mode 100644
index b25618ac3..000000000
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Bee.java.patch
+++ /dev/null
@@ -1,43 +0,0 @@
---- a/net/minecraft/world/entity/animal/Bee.java
-+++ b/net/minecraft/world/entity/animal/Bee.java
-@@ -365,7 +_,7 @@
- }
-
- public static boolean isNightOrRaining(Level level) {
-- return level.dimensionType().hasSkyLight() && (level.isNight() || level.isRaining());
-+ return level.dimensionType().hasSkyLight() && (level.isNight() && !level.purpurConfig.beeCanWorkAtNight || level.isRaining() && !level.purpurConfig.beeCanWorkInRain); // Purpur - Bee can work when raining or at night
- }
-
- public void setStayOutOfHiveCountdown(int stayOutOfHiveCountdown) {
-@@ -398,6 +_,7 @@
- this.hurtServer(level, this.damageSources().drown(), 1.0F);
- }
-
-+ if (hasStung && !this.level().purpurConfig.beeDiesAfterSting) setHasStung(false); else // Purpur - Stop bees from dying after stinging
- if (hasStung) {
- this.timeSinceSting++;
- if (this.timeSinceSting % 5 == 0 && this.random.nextInt(Mth.clamp(1200 - this.timeSinceSting, 1, 1200)) == 0) {
-@@ -1136,6 +_,7 @@
- Bee.this.savedFlowerPos = optional.get();
- Bee.this.navigation
- .moveTo(Bee.this.savedFlowerPos.getX() + 0.5, Bee.this.savedFlowerPos.getY() + 0.5, Bee.this.savedFlowerPos.getZ() + 0.5, 1.2F);
-+ new org.purpurmc.purpur.event.entity.BeeFoundFlowerEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos)).callEvent(); // Purpur - Bee API
- return true;
- } else {
- Bee.this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(Bee.this.random, 20, 60);
-@@ -1182,6 +_,7 @@
- this.pollinating = false;
- Bee.this.navigation.stop();
- Bee.this.remainingCooldownBeforeLocatingNewFlower = 200;
-+ new org.purpurmc.purpur.event.entity.BeeStopPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), Bee.this.savedFlowerPos == null ? null : io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos), Bee.this.hasNectar()).callEvent(); // Purpur - Bee API
- }
-
- @Override
-@@ -1228,6 +_,7 @@
- this.setWantedPos();
- }
-
-+ if (this.successfulPollinatingTicks == 0) new org.purpurmc.purpur.event.entity.BeeStartedPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos)).callEvent(); // Purpur - Bee API
- this.successfulPollinatingTicks++;
- if (Bee.this.random.nextFloat() < 0.05F && this.successfulPollinatingTicks > this.lastSoundPlayedTick + 60) {
- this.lastSoundPlayedTick = this.successfulPollinatingTicks;
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cat.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cat.java.patch
deleted file mode 100644
index e2dcf1d10..000000000
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cat.java.patch
+++ /dev/null
@@ -1,26 +0,0 @@
---- a/net/minecraft/world/entity/animal/Cat.java
-+++ b/net/minecraft/world/entity/animal/Cat.java
-@@ -332,6 +_,14 @@
- return this.isTame() && otherAnimal instanceof Cat cat && cat.isTame() && super.canMate(otherAnimal);
- }
-
-+ // Purpur start - Configurable default collar color
-+ @Override
-+ public void tame(Player player) {
-+ setCollarColor(level().purpurConfig.catDefaultCollarColor);
-+ super.tame(player);
-+ }
-+ // Purpur end - Configurable default collar color
-+
- @Nullable
- @Override
- public SpawnGroupData finalizeSpawn(
-@@ -438,7 +_,7 @@
- }
-
- private void tryToTame(Player player) {
-- if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit
-+ if (this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials() || this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit // Purpur - Config to always tame in Creative
- this.tame(player);
- this.setOrderedToSit(true);
- this.level().broadcastEntityEvent(this, (byte)7);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/IronGolem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/IronGolem.java.patch
deleted file mode 100644
index 176e8f9bc..000000000
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/IronGolem.java.patch
+++ /dev/null
@@ -1,53 +0,0 @@
---- a/net/minecraft/world/entity/animal/IronGolem.java
-+++ b/net/minecraft/world/entity/animal/IronGolem.java
-@@ -56,13 +_,26 @@
- private int remainingPersistentAngerTime;
- @Nullable
- private UUID persistentAngerTarget;
-+ @Nullable private UUID summoner; // Purpur - Summoner API
-
- public IronGolem(EntityType extends IronGolem> entityType, Level level) {
- super(entityType, level);
- }
-
-+ // Purpur start - Summoner API
-+ @Nullable
-+ public UUID getSummoner() {
-+ return summoner;
-+ }
-+
-+ public void setSummoner(@Nullable UUID summoner) {
-+ this.summoner = summoner;
-+ }
-+ // Purpur end - Summoner API
-+
- @Override
- protected void registerGoals() {
-+ if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options
- this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0, true));
- this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9, 32.0F));
- this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6, false));
-@@ -140,6 +_,7 @@
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
- compound.putBoolean("PlayerCreated", this.isPlayerCreated());
-+ if (getSummoner() != null) compound.putUUID("Purpur.Summoner", getSummoner()); // Purpur - Summoner API
- this.addPersistentAngerSaveData(compound);
- }
-
-@@ -147,6 +_,7 @@
- public void readAdditionalSaveData(CompoundTag compound) {
- super.readAdditionalSaveData(compound);
- this.setPlayerCreated(compound.getBoolean("PlayerCreated"));
-+ if (compound.contains("Purpur.Summoner")) setSummoner(compound.getUUID("Purpur.Summoner")); // Purpur - Summoner API
- this.readPersistentAngerSaveData(this.level(), compound);
- }
-
-@@ -266,6 +_,7 @@
- float f = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F;
- this.playSound(SoundEvents.IRON_GOLEM_REPAIR, 1.0F, f);
- itemInHand.consume(1, player);
-+ if (this.level().purpurConfig.ironGolemHealCalm && isAngry() && getHealth() == getMaxHealth()) stopBeingAngry(); // Purpur - Iron golem calm anger options
- return InteractionResult.SUCCESS;
- }
- }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch
new file mode 100644
index 000000000..536d9a92f
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch
@@ -0,0 +1,73 @@
+--- a/net/minecraft/world/entity/animal/bee/Bee.java
++++ b/net/minecraft/world/entity/animal/bee/Bee.java
+@@ -171,7 +_,7 @@
+ // Paper end - Fix MC-167279
+ this.lookControl = new Bee.BeeLookControl(this);
+ this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
+- this.setPathfindingMalus(PathType.WATER, -1.0F);
++ if (this.level().purpurConfig.beeCanInstantlyStartDrowning) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - bee can instantly start drowning in water option
+ this.setPathfindingMalus(PathType.WATER_BORDER, 16.0F);
+ this.setPathfindingMalus(PathType.COCOA, -1.0F);
+ this.setPathfindingMalus(PathType.FENCE, -1.0F);
+@@ -360,13 +_,19 @@
+ if (this.stayOutOfHiveCountdown <= 0 && !this.beePollinateGoal.isPollinating() && !this.hasStung() && this.getTarget() == null) {
+ boolean flag = this.hasNectar()
+ || this.isTiredOfLookingForNectar()
+- || this.level().environmentAttributes().getValue(EnvironmentAttributes.BEES_STAY_IN_HIVE, this.position());
++ || this.level().environmentAttributes().getValue(EnvironmentAttributes.BEES_STAY_IN_HIVE, this.position()) || isNightOrRaining(this.level()); // Purpur - Bee can work when raining or at night
+ return flag && !this.isHiveNearFire();
+ } else {
+ return false;
+ }
+ }
+
++ // Purpur start - Bee can work when raining or at night
++ public static boolean isNightOrRaining(Level level) {
++ return level.dimensionType().hasSkyLight() && (level.isDarkOutside() && !level.purpurConfig.beeCanWorkAtNight || level.isRaining() && !level.purpurConfig.beeCanWorkInRain); // Purpur - Bee can work when raining or at night
++ }
++ // Purpur end - Bee can work when raining or at night
++
+ public void setStayOutOfHiveCountdown(int stayOutOfHiveCountdown) {
+ this.stayOutOfHiveCountdown = stayOutOfHiveCountdown;
+ }
+@@ -387,7 +_,7 @@
+ @Override
+ protected void customServerAiStep(ServerLevel level) {
+ boolean hasStung = this.hasStung();
+- if (this.isInWater()) {
++ if (this.level().purpurConfig.beeCanInstantlyStartDrowning && this.isInWater()) { // Purpur - bee can instantly start drowning in water option
+ this.underWaterTicks++;
+ } else {
+ this.underWaterTicks = 0;
+@@ -397,6 +_,7 @@
+ this.hurtServer(level, this.damageSources().drown(), 1.0F);
+ }
+
++ if (hasStung && !this.level().purpurConfig.beeDiesAfterSting) setHasStung(false); else // Purpur - Stop bees from dying after stinging
+ if (hasStung) {
+ this.timeSinceSting++;
+ if (this.timeSinceSting % 5 == 0 && this.random.nextInt(Mth.clamp(1200 - this.timeSinceSting, 1, 1200)) == 0) {
+@@ -1130,6 +_,7 @@
+ Bee.this.savedFlowerPos = optional.get();
+ Bee.this.navigation
+ .moveTo(Bee.this.savedFlowerPos.getX() + 0.5, Bee.this.savedFlowerPos.getY() + 0.5, Bee.this.savedFlowerPos.getZ() + 0.5, 1.2F);
++ new org.purpurmc.purpur.event.entity.BeeFoundFlowerEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(Bee.this.savedFlowerPos, Bee.this.level())).callEvent(); // Purpur - Bee API
+ return true;
+ } else {
+ Bee.this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(Bee.this.random, 20, 60);
+@@ -1176,6 +_,7 @@
+ this.pollinating = false;
+ Bee.this.navigation.stop();
+ Bee.this.remainingCooldownBeforeLocatingNewFlower = 200;
++ new org.purpurmc.purpur.event.entity.BeeStopPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), Bee.this.savedFlowerPos == null ? null : org.bukkit.craftbukkit.util.CraftLocation.toBukkit(Bee.this.savedFlowerPos, Bee.this.level()), Bee.this.hasNectar()).callEvent(); // Purpur - Bee API
+ }
+
+ @Override
+@@ -1222,6 +_,7 @@
+ this.setWantedPos();
+ }
+
++ if (this.successfulPollinatingTicks == 0) new org.purpurmc.purpur.event.entity.BeeStartedPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(Bee.this.savedFlowerPos, Bee.this.level())).callEvent(); // Purpur - Bee API
+ this.successfulPollinatingTicks++;
+ if (Bee.this.random.nextFloat() < 0.05F && this.successfulPollinatingTicks > this.lastSoundPlayedTick + 60) {
+ this.lastSoundPlayedTick = this.successfulPollinatingTicks;
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cow.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/cow/AbstractCow.java.patch
similarity index 90%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cow.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/cow/AbstractCow.java.patch
index 61b3e9983..6ab713663 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cow.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/cow/AbstractCow.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/animal/Cow.java
-+++ b/net/minecraft/world/entity/animal/Cow.java
-@@ -43,7 +_,7 @@
+--- a/net/minecraft/world/entity/animal/cow/AbstractCow.java
++++ b/net/minecraft/world/entity/animal/cow/AbstractCow.java
+@@ -40,7 +_,7 @@
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(1, new PanicGoal(this, 2.0));
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0));
@@ -9,7 +9,7 @@
this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25));
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0));
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
-@@ -99,6 +_,10 @@
+@@ -96,6 +_,10 @@
ItemStack itemStack = ItemUtils.createFilledResult(itemInHand, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit
player.setItemInHand(hand, itemStack);
return InteractionResult.SUCCESS;
@@ -20,7 +20,7 @@
} else {
return super.mobInteract(player, hand);
}
-@@ -114,4 +_,67 @@
+@@ -105,4 +_,67 @@
public EntityDimensions getDefaultDimensions(Pose pose) {
return this.isBaby() ? BABY_DIMENSIONS : super.getDefaultDimensions(pose);
}
@@ -50,7 +50,7 @@
+ }
+ return InteractionResult.CONSUME; // require 5 mushrooms to transform (prevents mushroom duping)
+ }
-+ MushroomCow mooshroom = EntityType.MOOSHROOM.create(level(), EntitySpawnReason.CONVERSION);
++ MushroomCow mooshroom = EntityType.MOOSHROOM.create(level(), net.minecraft.world.entity.EntitySpawnReason.CONVERSION);
+ if (mooshroom == null) {
+ return InteractionResult.PASS;
+ }
@@ -59,7 +59,7 @@
+ } else {
+ mooshroom.setVariant(MushroomCow.Variant.RED);
+ }
-+ mooshroom.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
++ mooshroom.snapTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+ mooshroom.setHealth(this.getHealth());
+ mooshroom.setAge(getAge());
+ mooshroom.copyPosition(this);
@@ -79,7 +79,7 @@
+ stack.shrink(1);
+ }
+ for (int i = 0; i < 15; ++i) {
-+ ((ServerLevel) level()).sendParticlesSource(((ServerLevel) level()).players(), null, net.minecraft.core.particles.ParticleTypes.HAPPY_VILLAGER,
++ ((net.minecraft.server.level.ServerLevel) level()).sendParticlesSource(((net.minecraft.server.level.ServerLevel) level()).players(), null, net.minecraft.core.particles.ParticleTypes.HAPPY_VILLAGER,
+ false, true,
+ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1,
+ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/MushroomCow.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/cow/MushroomCow.java.patch
similarity index 61%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/MushroomCow.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/cow/MushroomCow.java.patch
index 1d6651865..c042bfe98 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/MushroomCow.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/cow/MushroomCow.java.patch
@@ -1,15 +1,15 @@
---- a/net/minecraft/world/entity/animal/MushroomCow.java
-+++ b/net/minecraft/world/entity/animal/MushroomCow.java
-@@ -192,6 +_,13 @@
- level.playSound(null, this, SoundEvents.MOOSHROOM_SHEAR, soundSource, 1.0F, 1.0F);
- this.convertTo(EntityType.COW, ConversionParams.single(this, false, false), mob -> {
+--- a/net/minecraft/world/entity/animal/cow/MushroomCow.java
++++ b/net/minecraft/world/entity/animal/cow/MushroomCow.java
+@@ -199,6 +_,13 @@
+ level.playSound(null, this, SoundEvents.MOOSHROOM_SHEAR, source, 1.0F, 1.0F);
+ this.convertTo(EntityType.COW, ConversionParams.single(this, false, false), cow -> {
level.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(0.5), this.getZ(), 1, 0.0, 0.0, 0.0, 0.0);
+ // Purpur start - Fix cow rotation when shearing mooshroom
-+ mob.copyPosition(this);
-+ mob.yBodyRot = this.yBodyRot;
-+ mob.setYHeadRot(this.getYHeadRot());
-+ mob.yRotO = this.yRotO;
-+ mob.xRotO = this.xRotO;
++ cow.copyPosition(this);
++ cow.yBodyRot = this.yBodyRot;
++ cow.setYHeadRot(this.getYHeadRot());
++ cow.yRotO = this.yRotO;
++ cow.xRotO = this.xRotO;
+ // Purpur end - Fix cow rotation when shearing mooshroom
// Paper start - custom shear drops; moved drop generation to separate method
drops.forEach(drop -> {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Dolphin.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch
similarity index 84%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Dolphin.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch
index 7a3ebe2c4..4cfc72671 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Dolphin.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch
@@ -1,14 +1,14 @@
---- a/net/minecraft/world/entity/animal/Dolphin.java
-+++ b/net/minecraft/world/entity/animal/Dolphin.java
-@@ -71,6 +_,7 @@
- private static final int TOTAL_MOISTNESS_LEVEL = 2400;
- public static final Predicate ALLOWED_ITEMS = itemEntity -> !itemEntity.hasPickUpDelay() && itemEntity.isAlive() && itemEntity.isInWater();
+--- a/net/minecraft/world/entity/animal/dolphin/Dolphin.java
++++ b/net/minecraft/world/entity/animal/dolphin/Dolphin.java
+@@ -75,6 +_,7 @@
public static final float BABY_SCALE = 0.65F;
+ private static final boolean DEFAULT_GOT_FISH = false;
+ @Nullable public BlockPos treasurePos;
+ private boolean isNaturallyAggressiveToPlayers; // Purpur - Dolphins naturally aggressive to players chance
- public Dolphin(EntityType extends Dolphin> entityType, Level level) {
- super(entityType, level);
-@@ -87,6 +_,7 @@
+ public Dolphin(EntityType extends Dolphin> type, Level level) {
+ super(type, level);
+@@ -90,6 +_,7 @@
this.setAirSupply(this.getMaxAirSupply());
this.setXRot(0.0F);
SpawnGroupData spawnGroupData1 = Objects.requireNonNullElseGet(spawnGroupData, () -> new AgeableMob.AgeableMobGroupData(0.1F));
@@ -16,7 +16,7 @@
return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData1);
}
-@@ -169,17 +_,19 @@
+@@ -155,17 +_,19 @@
protected void registerGoals() {
this.goalSelector.addGoal(0, new BreathAirGoal(this));
this.goalSelector.addGoal(0, new TryFindWaterGoal(this));
@@ -37,7 +37,7 @@
}
public static AttributeSupplier.Builder createAttributes() {
-@@ -412,6 +_,7 @@
+@@ -392,6 +_,7 @@
@Override
public boolean canUse() {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/equine/Llama.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/equine/Llama.java.patch
new file mode 100644
index 000000000..f5a863392
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/equine/Llama.java.patch
@@ -0,0 +1,42 @@
+--- a/net/minecraft/world/entity/animal/equine/Llama.java
++++ b/net/minecraft/world/entity/animal/equine/Llama.java
+@@ -76,6 +_,7 @@
+ boolean didSpit;
+ private @Nullable Llama caravanHead;
+ public @Nullable Llama caravanTail; // Paper - public
++ public boolean shouldJoinCaravan = true; // Purpur - Llama API
+
+ public Llama(EntityType extends Llama> type, Level level) {
+ super(type, level);
+@@ -105,6 +_,7 @@
+ super.addAdditionalSaveData(output);
+ output.store("Variant", Llama.Variant.LEGACY_CODEC, this.getVariant());
+ output.putInt("Strength", this.getStrength());
++ output.putBoolean("Purpur.ShouldJoinCaravan", shouldJoinCaravan); // Purpur - Llama API
+ }
+
+ @Override
+@@ -112,6 +_,7 @@
+ this.setStrength(input.getIntOr("Strength", 0));
+ super.readAdditionalSaveData(input);
+ this.setVariant(input.read("Variant", Llama.Variant.LEGACY_CODEC).orElse(Llama.Variant.DEFAULT));
++ this.shouldJoinCaravan = input.getBooleanOr("Purpur.ShouldJoinCaravan", true); // Purpur - Llama API
+ }
+
+ @Override
+@@ -388,6 +_,7 @@
+
+ public void leaveCaravan() {
+ if (this.caravanHead != null) {
++ new org.purpurmc.purpur.event.entity.LlamaLeaveCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity()).callEvent(); // Purpur - Llama API
+ this.caravanHead.caravanTail = null;
+ }
+
+@@ -395,6 +_,7 @@
+ }
+
+ public void joinCaravan(Llama caravanHead) {
++ if (!this.level().purpurConfig.llamaJoinCaravans || !shouldJoinCaravan || !new org.purpurmc.purpur.event.entity.LlamaJoinCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity(), (org.bukkit.entity.Llama) caravanHead.getBukkitEntity()).callEvent()) return; // Purpur - Llama API // Purpur - Config to disable Llama caravans
+ this.caravanHead = caravanHead;
+ this.caravanHead.caravanTail = this;
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch
new file mode 100644
index 000000000..ff93d1657
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch
@@ -0,0 +1,26 @@
+--- a/net/minecraft/world/entity/animal/feline/Cat.java
++++ b/net/minecraft/world/entity/animal/feline/Cat.java
+@@ -354,6 +_,14 @@
+ return this.isTame() && otherAnimal instanceof Cat cat && cat.isTame() && super.canMate(otherAnimal);
+ }
+
++ // Purpur start - Configurable default collar color
++ @Override
++ public void tame(Player player) {
++ setCollarColor(level().purpurConfig.catDefaultCollarColor);
++ super.tame(player);
++ }
++ // Purpur end - Configurable default collar color
++
+ @Override
+ public @Nullable SpawnGroupData finalizeSpawn(
+ ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
+@@ -451,7 +_,7 @@
+ }
+
+ private void tryToTame(Player player) {
+- if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit
++ if (((this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials()) || this.random.nextInt(3) == 0) && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit // Purpur - Config to always tame in Creative
+ this.tame(player);
+ this.setOrderedToSit(true);
+ this.level().broadcastEntityEvent(this, EntityEvent.TAMING_SUCCEEDED);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Ocelot.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/feline/Ocelot.java.patch
similarity index 77%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Ocelot.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/feline/Ocelot.java.patch
index 419638b78..21c0a7907 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Ocelot.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/feline/Ocelot.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/animal/Ocelot.java
-+++ b/net/minecraft/world/entity/animal/Ocelot.java
-@@ -232,7 +_,7 @@
+--- a/net/minecraft/world/entity/animal/feline/Ocelot.java
++++ b/net/minecraft/world/entity/animal/feline/Ocelot.java
+@@ -234,7 +_,7 @@
public boolean checkSpawnObstruction(LevelReader level) {
if (level.isUnobstructed(this) && !level.containsAnyLiquid(this.getBoundingBox())) {
BlockPos blockPos = this.blockPosition();
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/WaterAnimal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/fish/WaterAnimal.java.patch
similarity index 84%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/WaterAnimal.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/fish/WaterAnimal.java.patch
index b42850fc8..a572fa81f 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/WaterAnimal.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/fish/WaterAnimal.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/animal/WaterAnimal.java
-+++ b/net/minecraft/world/entity/animal/WaterAnimal.java
-@@ -74,8 +_,7 @@
+--- a/net/minecraft/world/entity/animal/fish/WaterAnimal.java
++++ b/net/minecraft/world/entity/animal/fish/WaterAnimal.java
+@@ -76,8 +_,7 @@
seaLevel = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(seaLevel);
i = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(i);
// Paper end - Make water animal spawn height configurable
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Fox.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch
similarity index 91%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Fox.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch
index c0f401ee5..f6fdc8513 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Fox.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/animal/Fox.java
-+++ b/net/minecraft/world/entity/animal/Fox.java
-@@ -335,6 +_,11 @@
+--- a/net/minecraft/world/entity/animal/fox/Fox.java
++++ b/net/minecraft/world/entity/animal/fox/Fox.java
+@@ -357,6 +_,11 @@
}
private void setTargetGoals() {
@@ -12,15 +12,15 @@
if (this.getVariant() == Fox.Variant.RED) {
this.targetSelector.addGoal(4, this.landTargetGoal);
this.targetSelector.addGoal(4, this.turtleEggTargetGoal);
-@@ -364,6 +_,7 @@
- @Override
+@@ -384,6 +_,7 @@
+
public void setVariant(Fox.Variant variant) {
this.entityData.set(DATA_TYPE_ID, variant.getId());
+ this.setTargetGoals(); // Purpur - Tulips change fox type - fix API bug not updating pathfinders on type change
}
- List getTrustedUUIDs() {
-@@ -684,6 +_,29 @@
+ @Override
+@@ -709,6 +_,29 @@
return slot == EquipmentSlot.MAINHAND;
}
// Paper end
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch
index 11559576e..d854787d7 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/animal/goat/Goat.java
+++ b/net/minecraft/world/entity/animal/goat/Goat.java
-@@ -392,6 +_,7 @@
+@@ -389,6 +_,7 @@
// Paper start - Goat ram API
public void ram(net.minecraft.world.entity.LivingEntity entity) {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch
new file mode 100644
index 000000000..6ce83f8b0
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch
@@ -0,0 +1,44 @@
+--- a/net/minecraft/world/entity/animal/golem/CopperGolem.java
++++ b/net/minecraft/world/entity/animal/golem/CopperGolem.java
+@@ -83,6 +_,7 @@
+ private final AnimationState interactionDropItemAnimationState = new AnimationState();
+ private final AnimationState interactionDropNoItemAnimationState = new AnimationState();
+ public static final EquipmentSlot EQUIPMENT_SLOT_ANTENNA = EquipmentSlot.SADDLE;
++ @Nullable private UUID summoner; // Purpur - Summoner API
+
+ public CopperGolem(EntityType extends AbstractGolem> type, Level level) {
+ super(type, level);
+@@ -96,6 +_,17 @@
+ this.getBrain().setMemory(MemoryModuleType.TRANSPORT_ITEMS_COOLDOWN_TICKS, this.getRandom().nextInt(60, 100));
+ }
+
++ // Purpur start - Summoner API
++ @Nullable
++ public UUID getSummoner() {
++ return summoner;
++ }
++
++ public void setSummoner(@Nullable UUID summoner) {
++ this.summoner = summoner;
++ }
++ // Purpur end - Summoner API
++
+ public static AttributeSupplier.Builder createAttributes() {
+ return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F).add(Attributes.STEP_HEIGHT, 1.0).add(Attributes.MAX_HEALTH, 12.0);
+ }
+@@ -171,6 +_,7 @@
+ super.addAdditionalSaveData(output);
+ output.putLong("next_weather_age", this.nextWeatheringTick);
+ output.store("weather_state", WeatheringCopper.WeatherState.CODEC, this.getWeatherState());
++ output.storeNullable("Purpur.Summoner", net.minecraft.core.UUIDUtil.CODEC, getSummoner()); // Purpur - Summoner API
+ }
+
+ @Override
+@@ -178,6 +_,7 @@
+ super.readAdditionalSaveData(input);
+ this.nextWeatheringTick = input.getLongOr("next_weather_age", -1L);
+ this.setWeatherState(input.read("weather_state", WeatheringCopper.WeatherState.CODEC).orElse(WeatheringCopper.WeatherState.UNAFFECTED));
++ this.setSummoner(input.read("Purpur.Summoner", net.minecraft.core.UUIDUtil.CODEC).orElse(null)); // Purpur - Summoner API
+ }
+
+ @Override
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/CopperGolemAi.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/CopperGolemAi.java.patch
new file mode 100644
index 000000000..81805e39c
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/CopperGolemAi.java.patch
@@ -0,0 +1,23 @@
+--- a/net/minecraft/world/entity/animal/golem/CopperGolemAi.java
++++ b/net/minecraft/world/entity/animal/golem/CopperGolemAi.java
+@@ -43,7 +_,7 @@
+ private static final int TICK_TO_START_ON_REACHED_INTERACTION = 1;
+ private static final int TICK_TO_PLAY_ON_REACHED_SOUND = 9;
+ private static final Predicate TRANSPORT_ITEM_SOURCE_BLOCK = state -> state.is(BlockTags.COPPER_CHESTS);
+- private static final Predicate TRANSPORT_ITEM_DESTINATION_BLOCK = state -> state.is(Blocks.CHEST) || state.is(Blocks.TRAPPED_CHEST);
++ private static final Predicate TRANSPORT_ITEM_DESTINATION_BLOCK = state -> state.is(Blocks.CHEST) || state.is(Blocks.TRAPPED_CHEST); // Purpur - copper golem can place items in barrels or shulkers option - diff on change
+ private static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(
+ SensorType.NEAREST_LIVING_ENTITIES, SensorType.HURT_BY
+ );
+@@ -158,6 +_,11 @@
+ }
+
+ if (integer == 60) {
++ // Purpur start - copper golem can place items in barrels or shulkers option
++ if (container instanceof net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity shulkerBoxBlockEntity && shulkerBoxBlockEntity.openCount > 0) {
++ container.stopOpen(copperGolem);
++ }
++ // Purpur end - copper golem can place items in barrels or shulkers option
+ if (container.getEntitiesWithContainerOpen().contains(pathfinderMob)) {
+ container.stopOpen(copperGolem);
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch
new file mode 100644
index 000000000..9d2f00982
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch
@@ -0,0 +1,52 @@
+--- a/net/minecraft/world/entity/animal/golem/IronGolem.java
++++ b/net/minecraft/world/entity/animal/golem/IronGolem.java
+@@ -58,13 +_,25 @@
+ private static final UniformInt PERSISTENT_ANGER_TIME = TimeUtil.rangeOfSeconds(20, 39);
+ private long persistentAngerEndTime;
+ private @Nullable EntityReference persistentAngerTarget;
++ private java.util.@Nullable UUID summoner; // Purpur - Summoner API
+
+ public IronGolem(EntityType extends IronGolem> type, Level level) {
+ super(type, level);
+ }
+
++ // Purpur start - Summoner API
++ public java.util.@Nullable UUID getSummoner() {
++ return summoner;
++ }
++
++ public void setSummoner(java.util.@Nullable UUID summoner) {
++ this.summoner = summoner;
++ }
++ // Purpur end - Summoner API
++
+ @Override
+ protected void registerGoals() {
++ if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options
+ this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0, true));
+ this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9, 32.0F));
+ this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6, false));
+@@ -142,6 +_,7 @@
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
+ output.putBoolean("PlayerCreated", this.isPlayerCreated());
++ output.storeNullable("Purpur.Summoner", net.minecraft.core.UUIDUtil.CODEC, getSummoner()); // Purpur - Summoner API
+ this.addPersistentAngerSaveData(output);
+ }
+
+@@ -149,6 +_,7 @@
+ protected void readAdditionalSaveData(ValueInput input) {
+ super.readAdditionalSaveData(input);
+ this.setPlayerCreated(input.getBooleanOr("PlayerCreated", false));
++ this.setSummoner(input.read("Purpur.Summoner", net.minecraft.core.UUIDUtil.CODEC).orElse(null)); // Purpur - Summoner API
+ this.readPersistentAngerSaveData(this.level(), input);
+ }
+
+@@ -267,6 +_,7 @@
+ float f = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F;
+ this.playSound(SoundEvents.IRON_GOLEM_REPAIR, 1.0F, f);
+ itemInHand.consume(1, player);
++ if (this.level().purpurConfig.ironGolemHealCalm && isAngry() && getHealth() == getMaxHealth()) stopBeingAngry(); // Purpur - Iron golem calm anger options
+ return InteractionResult.SUCCESS;
+ }
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/SnowGolem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/SnowGolem.java.patch
similarity index 64%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/SnowGolem.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/SnowGolem.java.patch
index b6401d764..8e017028e 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/SnowGolem.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/golem/SnowGolem.java.patch
@@ -1,22 +1,21 @@
---- a/net/minecraft/world/entity/animal/SnowGolem.java
-+++ b/net/minecraft/world/entity/animal/SnowGolem.java
-@@ -44,15 +_,27 @@
- public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackMob {
+--- a/net/minecraft/world/entity/animal/golem/SnowGolem.java
++++ b/net/minecraft/world/entity/animal/golem/SnowGolem.java
+@@ -46,15 +_,26 @@
private static final EntityDataAccessor DATA_PUMPKIN_ID = SynchedEntityData.defineId(SnowGolem.class, EntityDataSerializers.BYTE);
private static final byte PUMPKIN_FLAG = 16;
-+ @Nullable private java.util.UUID summoner; // Purpur - Summoner API
+ private static final boolean DEFAULT_PUMPKIN = true;
++ private java.util.@Nullable UUID summoner; // Purpur - Summoner API
- public SnowGolem(EntityType extends SnowGolem> entityType, Level level) {
- super(entityType, level);
+ public SnowGolem(EntityType extends SnowGolem> type, Level level) {
+ super(type, level);
}
+ // Purpur start - Summoner API
-+ @Nullable
-+ public java.util.UUID getSummoner() {
++ public java.util.@Nullable UUID getSummoner() {
+ return summoner;
+ }
+
-+ public void setSummoner(@Nullable java.util.UUID summoner) {
++ public void setSummoner(java.util.@Nullable UUID summoner) {
+ this.summoner = summoner;
+ }
+ // Purpur end - Summoner API
@@ -30,19 +29,18 @@
this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F));
this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entity, level) -> entity instanceof Enemy));
-@@ -72,6 +_,7 @@
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
- compound.putBoolean("Pumpkin", this.hasPumpkin());
-+ if (getSummoner() != null) compound.putUUID("Purpur.Summoner", getSummoner()); // Purpur - Summoner API
+@@ -74,12 +_,14 @@
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
+ output.putBoolean("Pumpkin", this.hasPumpkin());
++ output.storeNullable("Purpur.Summoner", net.minecraft.core.UUIDUtil.CODEC, getSummoner()); // Purpur - Summoner API
}
@Override
-@@ -80,6 +_,7 @@
- if (compound.contains("Pumpkin")) {
- this.setPumpkin(compound.getBoolean("Pumpkin"));
- }
-+ if (compound.contains("Purpur.Summoner")) setSummoner(compound.getUUID("Purpur.Summoner")); // Purpur - Summoner API
+ protected void readAdditionalSaveData(ValueInput input) {
+ super.readAdditionalSaveData(input);
+ this.setPumpkin(input.getBooleanOr("Pumpkin", true));
++ this.setSummoner(input.read("Purpur.Summoner", net.minecraft.core.UUIDUtil.CODEC).orElse(null)); // Purpur - Summoner API
}
@Override
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/horse/Llama.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/horse/Llama.java.patch
deleted file mode 100644
index c0e613a83..000000000
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/horse/Llama.java.patch
+++ /dev/null
@@ -1,42 +0,0 @@
---- a/net/minecraft/world/entity/animal/horse/Llama.java
-+++ b/net/minecraft/world/entity/animal/horse/Llama.java
-@@ -72,6 +_,7 @@
- private Llama caravanHead;
- @Nullable
- public Llama caravanTail; // Paper
-+ public boolean shouldJoinCaravan = true; // Purpur - Llama API
-
- public Llama(EntityType extends Llama> entityType, Level level) {
- super(entityType, level);
-@@ -106,6 +_,7 @@
- super.addAdditionalSaveData(compound);
- compound.putInt("Variant", this.getVariant().id);
- compound.putInt("Strength", this.getStrength());
-+ compound.putBoolean("Purpur.ShouldJoinCaravan", shouldJoinCaravan); // Purpur - Llama API
- }
-
- @Override
-@@ -113,6 +_,7 @@
- this.setStrength(compound.getInt("Strength"));
- super.readAdditionalSaveData(compound);
- this.setVariant(Llama.Variant.byId(compound.getInt("Variant")));
-+ if (compound.contains("Purpur.ShouldJoinCaravan")) this.shouldJoinCaravan = compound.getBoolean("Purpur.ShouldJoinCaravan"); // Purpur - Llama API
- }
-
- @Override
-@@ -386,6 +_,7 @@
-
- public void leaveCaravan() {
- if (this.caravanHead != null) {
-+ new org.purpurmc.purpur.event.entity.LlamaLeaveCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity()).callEvent(); // Purpur - Llama API
- this.caravanHead.caravanTail = null;
- }
-
-@@ -393,6 +_,7 @@
- }
-
- public void joinCaravan(Llama caravanHead) {
-+ if (!this.level().purpurConfig.llamaJoinCaravans || !shouldJoinCaravan || !new org.purpurmc.purpur.event.entity.LlamaJoinCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity(), (org.bukkit.entity.Llama) caravanHead.getBukkitEntity()).callEvent()) return; // Purpur - Llama API // Purpur - Config to disable Llama caravans
- this.caravanHead = caravanHead;
- this.caravanHead.caravanTail = this;
- }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Parrot.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch
similarity index 70%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Parrot.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch
index 04548f96b..66096c247 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Parrot.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/animal/Parrot.java
-+++ b/net/minecraft/world/entity/animal/Parrot.java
-@@ -152,6 +_,7 @@
+--- a/net/minecraft/world/entity/animal/parrot/Parrot.java
++++ b/net/minecraft/world/entity/animal/parrot/Parrot.java
+@@ -164,6 +_,7 @@
protected void registerGoals() {
this.goalSelector.addGoal(0, new TamableAnimal.TamableAnimalPanicGoal(1.25));
this.goalSelector.addGoal(0, new FloatGoal(this));
@@ -8,16 +8,16 @@
this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0F));
this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this));
this.goalSelector.addGoal(2, new FollowOwnerGoal(this, 1.0, 5.0F, 1.0F));
-@@ -257,7 +_,7 @@
+@@ -269,7 +_,7 @@
}
- if (!this.level().isClientSide) {
+ if (!this.level().isClientSide()) {
- if (this.random.nextInt(10) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit
-+ if (this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials() || (this.random.nextInt(10) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled())) { // CraftBukkit // Purpur - Config to always tame in Creative
++ if (((this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials()) || this.random.nextInt(10) == 0) && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit // Purpur - Config to always tame in Creative
this.tame(player);
- this.level().broadcastEntityEvent(this, (byte)7);
+ this.level().broadcastEntityEvent(this, EntityEvent.TAMING_SUCCEEDED);
} else {
-@@ -265,6 +_,7 @@
+@@ -277,6 +_,7 @@
}
}
@@ -25,7 +25,7 @@
return InteractionResult.SUCCESS;
} else if (!itemInHand.is(ItemTags.PARROT_POISONOUS_FOOD)) {
if (!this.isFlying() && this.isTame() && this.isOwnedBy(player)) {
-@@ -289,7 +_,7 @@
+@@ -301,7 +_,7 @@
@Override
public boolean isFood(ItemStack stack) {
@@ -34,7 +34,7 @@
}
public static boolean checkParrotSpawnRules(
-@@ -304,13 +_,13 @@
+@@ -316,12 +_,12 @@
@Override
public boolean canMate(Animal otherAnimal) {
@@ -42,11 +42,10 @@
+ return super.canMate(otherAnimal); // Purpur - Breedable parrots
}
- @Nullable
@Override
- public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
+ public @Nullable AgeableMob getBreedOffspring(ServerLevel level, AgeableMob partner) {
- return null;
+ return level.purpurConfig.parrotBreedable ? EntityType.PARROT.create(level, EntitySpawnReason.BREEDING) : null; // Purpur - Breedable parrots
}
- @Nullable
+ @Override
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Pig.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch
similarity index 77%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Pig.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch
index 7ae89deb5..3b45f4fdc 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Pig.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch
@@ -1,12 +1,12 @@
---- a/net/minecraft/world/entity/animal/Pig.java
-+++ b/net/minecraft/world/entity/animal/Pig.java
-@@ -132,6 +_,19 @@
+--- a/net/minecraft/world/entity/animal/pig/Pig.java
++++ b/net/minecraft/world/entity/animal/pig/Pig.java
+@@ -138,6 +_,19 @@
@Override
public InteractionResult mobInteract(Player player, InteractionHand hand) {
boolean isFood = this.isFood(player.getItemInHand(hand));
+ // Purpur start - Pigs give saddle back
+ if (level().purpurConfig.pigGiveSaddleBack && player.isSecondaryUseActive() && !isFood && isSaddled() && !isVehicle()) {
-+ this.steering.setSaddle(false);
++ this.setItemSlot(EquipmentSlot.SADDLE, ItemStack.EMPTY);
+ if (!player.getAbilities().instabuild) {
+ ItemStack saddle = new ItemStack(Items.SADDLE);
+ if (!player.getInventory().add(saddle)) {
@@ -18,5 +18,5 @@
+ // Purpur end - Pigs give saddle back
+
if (!isFood && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) {
- if (!this.level().isClientSide) {
+ if (!this.level().isClientSide()) {
player.startRiding(this);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/PolarBear.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/polarbear/PolarBear.java.patch
similarity index 84%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/PolarBear.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/polarbear/PolarBear.java.patch
index 775a03fbe..06b4c45f4 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/PolarBear.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/polarbear/PolarBear.java.patch
@@ -1,7 +1,7 @@
---- a/net/minecraft/world/entity/animal/PolarBear.java
-+++ b/net/minecraft/world/entity/animal/PolarBear.java
-@@ -64,6 +_,29 @@
- super(entityType, level);
+--- a/net/minecraft/world/entity/animal/polarbear/PolarBear.java
++++ b/net/minecraft/world/entity/animal/polarbear/PolarBear.java
+@@ -66,6 +_,29 @@
+ super(type, level);
}
+ // Purpur start - Breedable Polar Bears
@@ -27,10 +27,10 @@
+ }
+ // Purpur end - Breedable Polar Bears
+
- @Nullable
@Override
- public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
-@@ -72,7 +_,7 @@
+ public @Nullable AgeableMob getBreedOffspring(ServerLevel level, AgeableMob partner) {
+ return EntityType.POLAR_BEAR.create(level, EntitySpawnReason.BREEDING);
+@@ -73,7 +_,7 @@
@Override
public boolean isFood(ItemStack stack) {
@@ -39,7 +39,7 @@
}
@Override
-@@ -81,6 +_,12 @@
+@@ -82,6 +_,12 @@
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal());
this.goalSelector.addGoal(1, new PanicGoal(this, 2.0, mob -> mob.isBaby() ? DamageTypeTags.PANIC_CAUSES : DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES));
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Rabbit.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/rabbit/Rabbit.java.patch
similarity index 89%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Rabbit.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/rabbit/Rabbit.java.patch
index ed0b1c6aa..d378a0a96 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Rabbit.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/rabbit/Rabbit.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/animal/Rabbit.java
-+++ b/net/minecraft/world/entity/animal/Rabbit.java
-@@ -376,10 +_,23 @@
+--- a/net/minecraft/world/entity/animal/rabbit/Rabbit.java
++++ b/net/minecraft/world/entity/animal/rabbit/Rabbit.java
+@@ -404,10 +_,23 @@
}
this.setVariant(randomRabbitVariant);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/GlowSquid.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/squid/GlowSquid.java.patch
similarity index 65%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/GlowSquid.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/squid/GlowSquid.java.patch
index 61c07231e..00859fa4c 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/GlowSquid.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/squid/GlowSquid.java.patch
@@ -1,7 +1,7 @@
---- a/net/minecraft/world/entity/GlowSquid.java
-+++ b/net/minecraft/world/entity/GlowSquid.java
-@@ -25,6 +_,13 @@
- super(entityType, level);
+--- a/net/minecraft/world/entity/animal/squid/GlowSquid.java
++++ b/net/minecraft/world/entity/animal/squid/GlowSquid.java
+@@ -30,6 +_,13 @@
+ super(type, level);
}
+ // Purpur start - Flying squids! Oh my!
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Squid.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/squid/Squid.java.patch
similarity index 83%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Squid.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/squid/Squid.java.patch
index af92a24dd..9ca8b5607 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Squid.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/squid/Squid.java.patch
@@ -1,10 +1,10 @@
---- a/net/minecraft/world/entity/animal/Squid.java
-+++ b/net/minecraft/world/entity/animal/Squid.java
-@@ -46,10 +_,29 @@
+--- a/net/minecraft/world/entity/animal/squid/Squid.java
++++ b/net/minecraft/world/entity/animal/squid/Squid.java
+@@ -48,10 +_,29 @@
- public Squid(EntityType extends Squid> entityType, Level level) {
- super(entityType, level);
-- //this.random.setSeed(this.getId()); // Paper - Share random for entities to make them more random
+ public Squid(EntityType extends Squid> type, Level level) {
+ super(type, level);
+- // this.random.setSeed(this.getId()); // Paper - Share random for entities to make them more random
+ if (!level.purpurConfig.entitySharedRandom) this.random.setSeed(this.getId()); // Paper - Share random for entities to make them more random // Purpur - Add toggle for RNG manipulation
this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F;
}
@@ -31,15 +31,15 @@
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this));
-@@ -127,6 +_,7 @@
+@@ -128,6 +_,7 @@
}
- if (this.isInWaterOrBubble()) {
+ if (this.isInWater()) {
+ if (canFly()) setNoGravity(!wasTouchingWater); // Purpur - Flying squids! Oh my!
if (this.tentacleMovement < (float) Math.PI) {
float f = this.tentacleMovement / (float) Math.PI;
this.tentacleAngle = Mth.sin(f * f * (float) Math.PI) * (float) Math.PI * 0.25F;
-@@ -310,7 +_,7 @@
+@@ -308,7 +_,7 @@
int noActionTime = this.squid.getNoActionTime();
if (noActionTime > 100) {
this.squid.movementVector = Vec3.ZERO;
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Wolf.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch
similarity index 76%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Wolf.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch
index 4c48e990c..e7ed8a723 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Wolf.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/animal/Wolf.java
-+++ b/net/minecraft/world/entity/animal/Wolf.java
-@@ -94,6 +_,37 @@
+--- a/net/minecraft/world/entity/animal/wolf/Wolf.java
++++ b/net/minecraft/world/entity/animal/wolf/Wolf.java
+@@ -100,6 +_,37 @@
EntityType> type = entity.getType();
return type == EntityType.SHEEP || type == EntityType.RABBIT || type == EntityType.FOX;
};
@@ -38,7 +38,7 @@
private static final float START_HEALTH = 8.0F;
private static final float TAME_HEALTH = 40.0F;
private static final float ARMOR_REPAIR_UNIT = 0.125F;
-@@ -115,12 +_,47 @@
+@@ -121,12 +_,47 @@
this.setPathfindingMalus(PathType.DANGER_POWDER_SNOW, -1.0F);
}
@@ -56,14 +56,14 @@
+ this.targetSelector.removeGoal(PATHFINDER_VANILLA);
+ this.targetSelector.removeGoal(PATHFINDER_RABID);
+ if (this.isRabid) {
-+ setOwnerUUID(null);
++ this.setOwnerReference(null);
+ setTame(false, true);
+ this.targetSelector.addGoal(5, PATHFINDER_RABID);
-+ if (modifyEffects) this.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.CONFUSION, 1200));
++ if (modifyEffects) this.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.NAUSEA, 1200));
+ } else {
+ this.targetSelector.addGoal(5, PATHFINDER_VANILLA);
+ this.stopBeingAngry();
-+ if (modifyEffects) this.removeEffect(net.minecraft.world.effect.MobEffects.CONFUSION);
++ if (modifyEffects) this.removeEffect(net.minecraft.world.effect.MobEffects.NAUSEA);
+ }
+ }
+ // Purpur end - Configurable chance for wolves to spawn rabid
@@ -86,38 +86,38 @@
this.goalSelector.addGoal(4, new LeapAtTargetGoal(this, 0.4F));
this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0, true));
this.goalSelector.addGoal(6, new FollowOwnerGoal(this, 1.0, 10.0F, 2.0F));
-@@ -133,7 +_,7 @@
+@@ -139,7 +_,7 @@
this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this));
this.targetSelector.addGoal(3, new HurtByTargetGoal(this).setAlertOthers());
this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt));
- this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR));
-+ // this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR)); // Purpur - Configurable chance for wolves to spawn rabid - moved to updatePathfinders()
++ //this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR)); // Purpur - Configurable chance for wolves to spawn rabid - moved to updatePathfinders()
this.targetSelector.addGoal(6, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR));
this.targetSelector.addGoal(7, new NearestAttackableTargetGoal<>(this, AbstractSkeleton.class, false));
this.targetSelector.addGoal(8, new ResetUniversalAngerTargetGoal<>(this, true));
-@@ -182,6 +_,7 @@
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
- compound.putByte("CollarColor", (byte)this.getCollarColor().getId());
-+ compound.putBoolean("Purpur.IsRabid", this.isRabid); // Purpur - Configurable chance for wolves to spawn rabid
- this.getVariant().unwrapKey().ifPresent(resourceKey -> compound.putString("variant", resourceKey.location().toString()));
- this.addPersistentAngerSaveData(compound);
- }
-@@ -196,6 +_,10 @@
- if (compound.contains("CollarColor", 99)) {
- this.setCollarColor(DyeColor.byId(compound.getInt("CollarColor")));
- }
+@@ -229,6 +_,7 @@
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
+ output.store("CollarColor", DyeColor.LEGACY_ID_CODEC, this.getCollarColor());
++ output.putBoolean("Purpur.IsRabid", this.isRabid); // Purpur - Configurable chance for wolves to spawn rabid
+ VariantUtils.writeVariant(output, this.getVariant());
+ this.addPersistentAngerSaveData(output);
+ this.getSoundVariant()
+@@ -243,6 +_,10 @@
+ super.readAdditionalSaveData(input);
+ VariantUtils.readVariant(input, Registries.WOLF_VARIANT).ifPresent(this::setVariant);
+ this.setCollarColor(input.read("CollarColor", DyeColor.LEGACY_ID_CODEC).orElse(DEFAULT_COLLAR_COLOR));
+ // Purpur start - Configurable chance for wolves to spawn rabid
-+ this.isRabid = compound.getBoolean("Purpur.IsRabid");
++ this.isRabid = input.getBooleanOr("Purpur.IsRabid", false);
+ this.updatePathfinders(false);
+ // Purpur end - Configurable chance for wolves to spawn rabid
-
- this.readPersistentAngerSaveData(this.level(), compound);
- }
-@@ -215,6 +_,10 @@
+ this.readPersistentAngerSaveData(this.level(), input);
+ input.read("sound_variant", ResourceKey.codec(Registries.WOLF_SOUND_VARIANT))
+ .flatMap(resourceKey -> this.registryAccess().lookupOrThrow(Registries.WOLF_SOUND_VARIANT).get((ResourceKey)resourceKey))
+@@ -266,6 +_,10 @@
}
- this.setVariant(holder);
+ this.setSoundVariant(WolfSoundVariants.pickRandomSoundVariant(this.registryAccess(), level.getRandom()));
+ // Purpur start - Configurable chance for wolves to spawn rabid
+ this.isRabid = level.getLevel().purpurConfig.wolfNaturalRabid > 0.0D && random.nextDouble() <= level.getLevel().purpurConfig.wolfNaturalRabid;
+ this.updatePathfinders(false);
@@ -125,19 +125,19 @@
return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
}
-@@ -263,6 +_,11 @@
+@@ -316,6 +_,11 @@
public void tick() {
super.tick();
if (this.isAlive()) {
+ // Purpur start - Configurable chance for wolves to spawn rabid
+ if (this.age % 300 == 0 && this.isRabid()) {
-+ this.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.CONFUSION, 400));
++ this.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.NAUSEA, 400));
+ }
+ // Purpur end - Configurable chance for wolves to spawn rabid
this.interestedAngleO = this.interestedAngle;
if (this.isInterested()) {
this.interestedAngle = this.interestedAngle + (1.0F - this.interestedAngle) * 0.4F;
-@@ -481,13 +_,27 @@
+@@ -517,13 +_,27 @@
itemInHand.consume(1, player);
this.tryToTame(player);
return InteractionResult.SUCCESS_SERVER;
@@ -161,8 +161,8 @@
}
private void tryToTame(Player player) {
-- if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call and isCancelled check.
-+ if (this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials() || this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call and isCancelled check. // Purpur - Config to always tame in Creative
+- if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call
++ if (((this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials()) || this.random.nextInt(3) == 0) && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call // Purpur - Config to always tame in Creative
this.tame(player);
this.navigation.stop();
this.setTarget(null);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch
index 5deaa74ba..b58f13a85 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
+++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
-@@ -38,6 +_,24 @@
+@@ -39,6 +_,24 @@
this.setPos(x, y, z);
}
@@ -25,7 +25,7 @@
@Override
protected Entity.MovementEmission getMovementEmission() {
return Entity.MovementEmission.NONE;
-@@ -74,6 +_,8 @@
+@@ -75,6 +_,8 @@
}
}
// Paper end - Fix invulnerable end crystals
@@ -34,7 +34,7 @@
}
@Override
-@@ -119,15 +_,17 @@
+@@ -115,15 +_,17 @@
}
// CraftBukkit end
if (!damageSource.is(DamageTypeTags.IS_EXPLOSION)) {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch
index e07733ccf..ca3634fcb 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
-@@ -974,6 +_,7 @@
+@@ -957,6 +_,7 @@
@Override
protected boolean canRide(Entity entity) {
@@ -8,8 +8,8 @@
return false;
}
-@@ -1009,7 +_,7 @@
- boolean flag = worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT);
+@@ -992,7 +_,7 @@
+ boolean flag = level.getGameRules().get(GameRules.MOB_DROPS);
int i = 500;
- if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch
index 30e1ffb25..e59a055c2 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch
@@ -1,24 +1,23 @@
--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java
+++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java
-@@ -77,6 +_,7 @@
+@@ -80,6 +_,7 @@
private static final TargetingConditions.Selector LIVING_ENTITY_SELECTOR = (entity, level) -> !entity.getType().is(EntityTypeTags.WITHER_FRIENDS)
&& entity.attackable();
private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0).selector(LIVING_ENTITY_SELECTOR);
-+ @Nullable private java.util.UUID summoner; // Purpur - Summoner API
++ private java.util.@Nullable UUID summoner; // Purpur - Summoner API
- public WitherBoss(EntityType extends WitherBoss> entityType, Level level) {
- super(entityType, level);
-@@ -85,6 +_,17 @@
+ public WitherBoss(EntityType extends WitherBoss> type, Level level) {
+ super(type, level);
+@@ -88,6 +_,16 @@
this.xpReward = 50;
}
+ // Purpur start - Summoner API
-+ @Nullable
-+ public java.util.UUID getSummoner() {
++ public java.util.@Nullable UUID getSummoner() {
+ return summoner;
+ }
+
-+ public void setSummoner(@Nullable java.util.UUID summoner) {
++ public void setSummoner(java.util.@Nullable UUID summoner) {
+ this.summoner = summoner;
+ }
+ // Purpur end - Summoner API
@@ -26,23 +25,23 @@
@Override
protected PathNavigation createNavigation(Level level) {
FlyingPathNavigation flyingPathNavigation = new FlyingPathNavigation(this, level);
-@@ -117,6 +_,7 @@
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
- compound.putInt("Invul", this.getInvulnerableTicks());
-+ if (getSummoner() != null) compound.putUUID("Purpur.Summoner", getSummoner()); // Purpur - Summoner API
+@@ -120,6 +_,7 @@
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
+ output.putInt("Invul", this.getInvulnerableTicks());
++ output.storeNullable("Purpur.Summoner", net.minecraft.core.UUIDUtil.CODEC, getSummoner()); // Purpur - Summoner API
}
@Override
-@@ -126,6 +_,7 @@
+@@ -129,6 +_,7 @@
if (this.hasCustomName()) {
this.bossEvent.setName(this.getDisplayName());
}
-+ if (compound.contains("Purpur.Summoner")) setSummoner(compound.getUUID("Purpur.Summoner")); // Purpur - Summoner API
++ this.setSummoner(input.read("Purpur.Summoner", net.minecraft.core.UUIDUtil.CODEC).orElse(null)); // Purpur - Summoner API
}
@Override
-@@ -269,7 +_,7 @@
+@@ -272,7 +_,7 @@
level.explode(this, this.getX(), this.getEyeY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB);
}
// CraftBukkit end
@@ -51,7 +50,7 @@
// CraftBukkit start - Use relative location for far away sounds
// level.globalLevelEvent(1023, this.blockPosition(), 0);
int viewDistance = level.getCraftServer().getViewDistance() * 16;
-@@ -376,8 +_,10 @@
+@@ -379,8 +_,10 @@
}
}
@@ -64,7 +63,7 @@
}
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
-@@ -574,6 +_,7 @@
+@@ -577,6 +_,7 @@
@Override
protected boolean canRide(Entity entity) {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch
index 1ac4c29b0..035025719 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch
@@ -1,28 +1,28 @@
--- a/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/net/minecraft/world/entity/decoration/ArmorStand.java
-@@ -93,10 +_,13 @@
- private boolean noTickPoseDirty = false;
+@@ -92,10 +_,13 @@
+ public boolean canTickSetByAPI = false;
private boolean noTickEquipmentDirty = false;
// Paper end - Allow ArmorStands not to tick
+ public boolean canMovementTick = true; // Purpur - Movement options for armor stands
- public ArmorStand(EntityType extends ArmorStand> entityType, Level level) {
- super(entityType, level);
+ public ArmorStand(EntityType extends ArmorStand> type, Level level) {
+ super(type, level);
if (level != null) this.canTick = level.paperConfig().entities.armorStands.tick; // Paper - Allow ArmorStands not to tick
+ if (level != null) this.canMovementTick = level.purpurConfig.armorstandMovement; // Purpur - Movement options for armor stands
+ this.setShowArms(level != null && level.purpurConfig.armorstandPlaceWithArms); // Purpur - Config to show Armor Stand arms on spawn
}
public ArmorStand(Level level, double x, double y, double z) {
-@@ -620,6 +_,7 @@
-
+@@ -522,6 +_,7 @@
+ // Paper start - Allow ArmorStands not to tick
@Override
public void tick() {
+ maxUpStep = level().purpurConfig.armorstandStepHeight; // Purpur - Add option to set armorstand step height
- // Paper start - Allow ArmorStands not to tick
if (!this.canTick) {
- if (this.noTickPoseDirty) {
-@@ -949,4 +_,18 @@
+ if (this.noTickEquipmentDirty) {
+ this.noTickEquipmentDirty = false;
+@@ -810,4 +_,18 @@
}
}
// Paper end
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch
index 024469799..9a7d5bb73 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
-@@ -52,6 +_,12 @@
+@@ -54,6 +_,12 @@
public boolean canMobPickup = true; // Paper - Item#canEntityPickup
private int despawnRate = -1; // Paper - Alternative item-despawn-rate
public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API
@@ -11,9 +11,9 @@
+ public boolean immuneToLightning = false;
+ // Purpur end - Item entity immunities
- public ItemEntity(EntityType extends ItemEntity> entityType, Level level) {
- super(entityType, level);
-@@ -337,7 +_,16 @@
+ public ItemEntity(EntityType extends ItemEntity> type, Level level) {
+ super(type, level);
+@@ -330,7 +_,16 @@
@Override
public final boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) {
@@ -29,9 +29,9 @@
+ } else if (this.isInvulnerableToBase(damageSource)) {
+ // Purpur end - Item entity immunities
return false;
- } else if (!level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && damageSource.getEntity() instanceof Mob) {
+ } else if (!level.getGameRules().get(GameRules.MOB_GRIEFING) && damageSource.getEntity() instanceof Mob) {
return false;
-@@ -539,6 +_,12 @@
+@@ -508,6 +_,12 @@
public void setItem(ItemStack stack) {
this.getEntityData().set(DATA_ITEM, stack);
this.despawnRate = this.level().paperConfig().entities.spawning.altItemDespawnRate.enabled ? this.level().paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(stack.getItem(), this.level().spigotConfig.itemDespawnRate) : this.level().spigotConfig.itemDespawnRate; // Paper - Alternative item-despawn-rate
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch
index eb0ed35f3..a3308c373 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
-@@ -251,4 +_,32 @@
+@@ -235,4 +_,32 @@
return !this.level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid();
}
// Paper end - Option to prevent TNT from moving in water
@@ -20,7 +20,7 @@
+ new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.TNT));
+ tntItem.setPickUpDelay(10);
+
-+ inHand.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand));
++ inHand.hurtAndBreak(1, player, hand.asEquipmentSlot());
+ serverWorld.addFreshEntity(tntItem, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CUSTOM);
+
+ this.playSound(net.minecraft.sounds.SoundEvents.SHEEP_SHEAR);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch
deleted file mode 100644
index 37349cc6c..000000000
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch
+++ /dev/null
@@ -1,23 +0,0 @@
---- a/net/minecraft/world/entity/monster/AbstractSkeleton.java
-+++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java
-@@ -158,10 +_,7 @@
- this.reassessWeaponGoal();
- this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || random.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 i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
-- if (i1 == 10 && i == 31 && random.nextFloat() < 0.25F) {
-+ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(level.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur - Halloween options and optimizations
- this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
- this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
- }
-@@ -217,7 +_,7 @@
- if (event.getProjectile() == arrow.getBukkitEntity()) {
- // CraftBukkit end
- Projectile.spawnProjectileUsingShoot(
-- arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4
-+ arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, serverLevel.purpurConfig.skeletonBowAccuracyMap.getOrDefault(serverLevel.getDifficulty().getId(), (float) (14 - serverLevel.getDifficulty().getId() * 4)) // Purpur - skeleton bow accuracy option
- );
- } // CraftBukkit
- }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch
index c3719371c..d27c4e8c7 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch
@@ -1,19 +1,20 @@
--- a/net/minecraft/world/entity/monster/Creeper.java
+++ b/net/minecraft/world/entity/monster/Creeper.java
-@@ -50,6 +_,7 @@
+@@ -56,6 +_,7 @@
public int explosionRadius = 3;
- private int droppedSkulls;
- public Entity entityIgniter; // CraftBukkit
+ public boolean droppedSkulls;
+ public @Nullable Entity entityIgniter; // CraftBukkit
+ private boolean exploding = false; // Purpur - Config to make Creepers explode on death
- public Creeper(EntityType extends Creeper> entityType, Level level) {
- super(entityType, level);
-@@ -161,6 +_,26 @@
- }
+ public Creeper(EntityType extends Creeper> type, Level level) {
+ super(type, level);
+@@ -159,6 +_,27 @@
+ return false; // CraftBukkit
}
+ // Purpur start - Special mobs naturally spawn
-+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.EntitySpawnReason spawnReason, @Nullable net.minecraft.world.entity.SpawnGroupData entityData) {
++ @Override
++ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.EntitySpawnReason spawnReason, net.minecraft.world.entity.@Nullable SpawnGroupData entityData) {
+ double chance = world.getLevel().purpurConfig.creeperChargedChance;
+ if (chance > 0D && random.nextDouble() <= chance) {
+ setPowered(true);
@@ -33,7 +34,7 @@
+ // Purpur end - Config to make Creepers explode on death
+
@Override
- protected SoundEvent getHurtSound(DamageSource damageSource) {
+ public SoundEvent getHurtSound(DamageSource damageSource) {
return SoundEvents.CREEPER_HURT;
@@ -243,14 +_,16 @@
}
@@ -50,7 +51,7 @@
// CraftBukkit end
this.dead = true;
- serverLevel.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this)
-+ serverLevel.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) && level().purpurConfig.creeperAllowGriefing ? Level.ExplosionInteraction.MOB : Level.ExplosionInteraction.NONE); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) // Purpur - Add enderman and creeper griefing controls
++ serverLevel.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.MOB_GRIEFING) && level().purpurConfig.creeperAllowGriefing ? Level.ExplosionInteraction.MOB : Level.ExplosionInteraction.NONE); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) // Purpur - Add enderman and creeper griefing controls
this.spawnLingeringCloud();
this.triggerOnDeathMobEffects(serverLevel, Entity.RemovalReason.KILLED);
this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch
index bac97afe7..7479b47dc 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/monster/EnderMan.java
+++ b/net/minecraft/world/entity/monster/EnderMan.java
-@@ -102,7 +_,7 @@
+@@ -101,7 +_,7 @@
this.goalSelector.addGoal(11, new EnderMan.EndermanTakeBlockGoal(this));
this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt));
this.targetSelector.addGoal(2, new HurtByTargetGoal(this));
@@ -9,32 +9,32 @@
this.targetSelector.addGoal(4, new ResetUniversalAngerTargetGoal<>(this, false));
}
-@@ -230,7 +_,7 @@
+@@ -220,7 +_,7 @@
boolean isBeingStaredBy(Player player) {
// Paper start - EndermanAttackPlayerEvent
-- final boolean shouldAttack = isBeingStaredBy0(player);
-+ final boolean shouldAttack = !this.level().purpurConfig.endermanDisableStareAggro && isBeingStaredBy0(player); // Purpur - Config to ignore Dragon Head wearers and stare aggro
+- final boolean shouldAttack = this.isBeingStaredBy0(player);
++ final boolean shouldAttack = !this.level().purpurConfig.endermanDisableStareAggro && this.isBeingStaredBy0(player); // Purpur - Config to ignore Dragon Head wearers and stare aggro
final com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) player.getBukkitEntity());
event.setCancelled(!shouldAttack);
return event.callEvent();
-@@ -385,6 +_,7 @@
+@@ -375,6 +_,7 @@
public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) {
if (this.isInvulnerableTo(level, damageSource)) {
return false;
+ } else if (org.purpurmc.purpur.PurpurConfig.endermanShortHeight && damageSource.is(net.minecraft.world.damagesource.DamageTypes.IN_WALL)) { return false; // Purpur - no suffocation damage if short height - Short enderman height
} else {
- boolean flag = damageSource.getDirectEntity() instanceof ThrownPotion;
- if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && !flag) {
-@@ -397,6 +_,7 @@
+ AbstractThrownPotion abstractThrownPotion1 = damageSource.getDirectEntity() instanceof AbstractThrownPotion abstractThrownPotion
+ ? abstractThrownPotion
+@@ -391,6 +_,7 @@
} else {
- boolean flag1 = flag && this.hurtWithCleanWater(level, damageSource, (ThrownPotion)damageSource.getDirectEntity(), amount);
+ boolean flag = abstractThrownPotion1 != null && this.hurtWithCleanWater(level, damageSource, abstractThrownPotion1, amount);
-+ if (!flag1 && level.purpurConfig.endermanIgnoreProjectiles) return super.hurtServer(level, damageSource, amount); // Purpur - Config to disable Enderman teleport on projectile hit
++ if (!flag && level.purpurConfig.endermanIgnoreProjectiles) return super.hurtServer(level, damageSource, amount); // Purpur - Config to disable Enderman teleport on projectile hit
if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent
for (int i = 0; i < 64; i++) {
if (this.teleport()) {
-@@ -440,7 +_,7 @@
+@@ -434,7 +_,7 @@
@Override
public boolean requiresCustomPersistence() {
@@ -43,19 +43,19 @@
}
static class EndermanFreezeWhenLookedAt extends Goal {
-@@ -484,6 +_,7 @@
+@@ -477,6 +_,7 @@
@Override
public boolean canUse() {
+ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls
return this.enderman.getCarriedBlock() != null
- && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)
+ && getServerLevel(this.enderman).getGameRules().get(GameRules.MOB_GRIEFING)
&& this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0;
-@@ -633,6 +_,7 @@
+@@ -625,6 +_,7 @@
@Override
public boolean canUse() {
+ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls
return this.enderman.getCarriedBlock() == null
- && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)
+ && getServerLevel(this.enderman).getGameRules().get(GameRules.MOB_GRIEFING)
&& this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0;
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch
index 9965430e8..a399138fa 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch
@@ -1,13 +1,13 @@
--- a/net/minecraft/world/entity/monster/Endermite.java
+++ b/net/minecraft/world/entity/monster/Endermite.java
-@@ -28,12 +_,23 @@
- public class Endermite extends Monster {
+@@ -30,12 +_,23 @@
private static final int MAX_LIFE = 2400;
- public int life;
+ private static final int DEFAULT_LIFE = 0;
+ public int life = 0;
+ private boolean isPlayerSpawned; // Purpur - Add back player spawned endermite API
- public Endermite(EntityType extends Endermite> entityType, Level level) {
- super(entityType, level);
+ public Endermite(EntityType extends Endermite> type, Level level) {
+ super(type, level);
this.xpReward = 3;
}
@@ -24,18 +24,18 @@
@Override
protected void registerGoals() {
this.goalSelector.addGoal(1, new FloatGoal(this));
-@@ -79,12 +_,14 @@
- public void readAdditionalSaveData(CompoundTag compound) {
- super.readAdditionalSaveData(compound);
- this.life = compound.getInt("Lifetime");
-+ this.isPlayerSpawned = compound.getBoolean("PlayerSpawned"); // Purpur - Add back player spawned endermite API
+@@ -81,12 +_,14 @@
+ protected void readAdditionalSaveData(ValueInput input) {
+ super.readAdditionalSaveData(input);
+ this.life = input.getIntOr("Lifetime", 0);
++ this.isPlayerSpawned = input.getBooleanOr("PlayerSpawned", false); // Purpur - Add back player spawned endermite API
}
@Override
- public void addAdditionalSaveData(CompoundTag compound) {
- super.addAdditionalSaveData(compound);
- compound.putInt("Lifetime", this.life);
-+ compound.putBoolean("PlayerSpawned", this.isPlayerSpawned); // Purpur - Add back player spawned endermite API
+ protected void addAdditionalSaveData(ValueOutput output) {
+ super.addAdditionalSaveData(output);
+ output.putInt("Lifetime", this.life);
++ output.putBoolean("PlayerSpawned", this.isPlayerSpawned); // Purpur - Add back player spawned endermite API
}
@Override
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch
new file mode 100644
index 000000000..c05e83d84
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch
@@ -0,0 +1,14 @@
+--- a/net/minecraft/world/entity/monster/Ghast.java
++++ b/net/minecraft/world/entity/monster/Ghast.java
+@@ -156,6 +_,11 @@
+ public static boolean checkGhastSpawnRules(
+ EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
++ // Purpur start - Config to disable hostile mob spawn on ice
++ if (net.minecraft.world.entity.monster.Monster.canSpawnInBlueAndPackedIce(level, pos)) {
++ return false;
++ }
++ // Purpur end - Config to disable hostile mob spawn on ice
+ return level.getDifficulty() != Difficulty.PEACEFUL && random.nextInt(20) == 0 && checkMobSpawnRules(entityType, level, spawnReason, pos, random);
+ }
+
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch
new file mode 100644
index 000000000..c85899c80
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch
@@ -0,0 +1,14 @@
+--- a/net/minecraft/world/entity/monster/Guardian.java
++++ b/net/minecraft/world/entity/monster/Guardian.java
+@@ -312,6 +_,11 @@
+ public static boolean checkGuardianSpawnRules(
+ EntityType extends Guardian> entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
++ // Purpur start - Config to disable hostile mob spawn on ice
++ if (canSpawnInBlueAndPackedIce(level, pos)) {
++ return false;
++ }
++ // Purpur end - Config to disable hostile mob spawn on ice
+ return (random.nextInt(20) == 0 || !level.canSeeSkyFromBelowWater(pos))
+ && level.getDifficulty() != Difficulty.PEACEFUL
+ && (EntitySpawnReason.isSpawner(spawnReason) || level.getFluidState(pos).is(FluidTags.WATER))
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/MagmaCube.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/MagmaCube.java.patch
new file mode 100644
index 000000000..358fa1924
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/MagmaCube.java.patch
@@ -0,0 +1,14 @@
+--- a/net/minecraft/world/entity/monster/MagmaCube.java
++++ b/net/minecraft/world/entity/monster/MagmaCube.java
+@@ -31,6 +_,11 @@
+ public static boolean checkMagmaCubeSpawnRules(
+ EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
++ // Purpur start - Config to disable hostile mob spawn on ice
++ if (net.minecraft.world.entity.monster.Monster.canSpawnInBlueAndPackedIce(level, pos)) {
++ return false;
++ }
++ // Purpur end - Config to disable hostile mob spawn on ice
+ return level.getDifficulty() != Difficulty.PEACEFUL;
+ }
+
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Monster.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Monster.java.patch
index c833d4fc6..6db59e5bc 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Monster.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Monster.java.patch
@@ -1,17 +1,39 @@
--- a/net/minecraft/world/entity/monster/Monster.java
+++ b/net/minecraft/world/entity/monster/Monster.java
-@@ -88,6 +_,14 @@
+@@ -84,6 +_,11 @@
}
public static boolean isDarkEnoughToSpawn(ServerLevelAccessor level, BlockPos pos, RandomSource random) {
+ // Purpur start - Config to disable hostile mob spawn on ice
-+ if (!level.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce || !level.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce) {
-+ net.minecraft.world.level.block.state.BlockState spawnBlock = level.getBlockState(pos.below());
-+ if ((!level.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.PACKED_ICE)) || (!level.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.BLUE_ICE))) {
-+ return false;
-+ }
++ if (canSpawnInBlueAndPackedIce(level, pos)) {
++ return false;
+ }
+ // Purpur end - Config to disable hostile mob spawn on ice
if (level.getBrightness(LightLayer.SKY, pos) > random.nextInt(32)) {
return false;
} else {
+@@ -109,6 +_,11 @@
+ public static boolean checkAnyLightMonsterSpawnRules(
+ EntityType extends Monster> entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
++ // Purpur start - Config to disable hostile mob spawn on ice
++ if (canSpawnInBlueAndPackedIce(level, pos)) {
++ return false;
++ }
++ // Purpur end - Config to disable hostile mob spawn on ice
+ return level.getDifficulty() != Difficulty.PEACEFUL && checkMobSpawnRules(entityType, level, spawnReason, pos, random);
+ }
+
+@@ -146,4 +_,12 @@
+ return ItemStack.EMPTY;
+ }
+ }
++
++ // Purpur start - Config to disable hostile mob spawn on ice
++ public static boolean canSpawnInBlueAndPackedIce(LevelAccessor level, BlockPos pos) {
++ net.minecraft.world.level.block.state.BlockState spawnBlock = level.getBlockState(pos.below());
++
++ return (!level.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.PACKED_ICE)) || (!level.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.BLUE_ICE));
++ }
++ // Purpur end - Config to disable hostile mob spawn on ice
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch
index acec89121..9f60b3712 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
-@@ -158,7 +_,11 @@
+@@ -166,7 +_,11 @@
ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData
) {
this.anchorPoint = this.blockPosition().above(5);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch
index 6e2afb392..7173a96a0 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch
@@ -1,14 +1,14 @@
--- a/net/minecraft/world/entity/monster/Ravager.java
+++ b/net/minecraft/world/entity/monster/Ravager.java
-@@ -70,6 +_,7 @@
+@@ -76,6 +_,7 @@
protected void registerGoals() {
super.registerGoals();
this.goalSelector.addGoal(0, new FloatGoal(this));
-+ if (level().purpurConfig.ravagerAvoidRabbits) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, net.minecraft.world.entity.animal.Rabbit.class, 6.0F, 1.0D, 1.2D)); // Purpur - option to make ravagers afraid of rabbits
++ if (level().purpurConfig.ravagerAvoidRabbits) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, net.minecraft.world.entity.animal.rabbit.Rabbit.class, 6.0F, 1.0D, 1.2D)); // Purpur - option to make ravagers afraid of rabbits
this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, true));
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.4));
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
-@@ -150,7 +_,7 @@
+@@ -154,7 +_,7 @@
)) {
BlockState blockState = serverLevel.getBlockState(blockPos);
Block block = blockState.getBlock();
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch
index eee30bbe5..21c6840c6 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch
@@ -1,14 +1,6 @@
--- a/net/minecraft/world/entity/monster/Shulker.java
+++ b/net/minecraft/world/entity/monster/Shulker.java
-@@ -50,6 +_,7 @@
- import net.minecraft.world.level.ServerLevelAccessor;
- import net.minecraft.world.level.block.Blocks;
- import net.minecraft.world.level.block.state.BlockState;
-+import net.minecraft.world.level.entity.EntityTypeTest;
- import net.minecraft.world.level.gameevent.GameEvent;
- import net.minecraft.world.phys.AABB;
- import net.minecraft.world.phys.Vec3;
-@@ -88,6 +_,21 @@
+@@ -93,6 +_,21 @@
this.lookControl = new Shulker.ShulkerLookControl(this);
}
@@ -30,7 +22,7 @@
@Override
protected void registerGoals() {
this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0F, 0.02F, true));
-@@ -459,11 +_,21 @@
+@@ -454,11 +_,21 @@
private void hitByShulkerBullet() {
Vec3 vec3 = this.position();
AABB boundingBox = this.getBoundingBox();
@@ -42,7 +34,7 @@
+ if ((!this.level().purpurConfig.shulkerSpawnFromBulletRequireOpenLid || !this.isClosed()) && this.teleportSomewhere()) {
+ float chance = this.level().purpurConfig.shulkerSpawnFromBulletBaseChance;
+ if (!this.level().purpurConfig.shulkerSpawnFromBulletNearbyEquation.isBlank()) {
-+ int nearby = this.level().getEntities((EntityTypeTest) EntityType.SHULKER, boundingBox.inflate(this.level().purpurConfig.shulkerSpawnFromBulletNearbyRange), Entity::isAlive).size();
++ int nearby = this.level().getEntities((net.minecraft.world.level.entity.EntityTypeTest) EntityType.SHULKER, boundingBox.inflate(this.level().purpurConfig.shulkerSpawnFromBulletNearbyRange), Entity::isAlive).size();
+ try {
+ chance -= ((Number) scriptEngine.eval("let nearby = " + nearby + "; " + this.level().purpurConfig.shulkerSpawnFromBulletNearbyEquation)).floatValue();
+ } catch (javax.script.ScriptException e) {
@@ -55,13 +47,13 @@
+ // Purpur end - Shulker spawn from bullet options
if (shulker != null) {
shulker.setVariant(this.getVariant());
- shulker.moveTo(vec3);
-@@ -573,7 +_,7 @@
+ shulker.snapTo(vec3);
+@@ -565,7 +_,7 @@
+ }
- @Override
public Optional getVariant() {
- return Optional.ofNullable(this.getColor());
+ return Optional.ofNullable(this.level().purpurConfig.shulkerSpawnFromBulletRandomColor ? DyeColor.random(this.level().random) : this.getColor()); // Purpur - Shulker spawn from bullet options
}
- @Nullable
+ public @Nullable DyeColor getColor() {
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Slime.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Slime.java.patch
new file mode 100644
index 000000000..7963b593d
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Slime.java.patch
@@ -0,0 +1,14 @@
+--- a/net/minecraft/world/entity/monster/Slime.java
++++ b/net/minecraft/world/entity/monster/Slime.java
+@@ -302,6 +_,11 @@
+ public static boolean checkSlimeSpawnRules(
+ EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
++ // Purpur start - Config to disable hostile mob spawn on ice
++ if (net.minecraft.world.entity.monster.Monster.canSpawnInBlueAndPackedIce(level, pos)) {
++ return false;
++ }
++ // Purpur end - Config to disable hostile mob spawn on ice
+ if (level.getDifficulty() != Difficulty.PEACEFUL) {
+ if (EntitySpawnReason.isSpawner(spawnReason)) {
+ return checkMobSpawnRules(entityType, level, spawnReason, pos, random);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Strider.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Strider.java.patch
index efb04f5ac..86f2a97ff 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Strider.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Strider.java.patch
@@ -1,12 +1,12 @@
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
-@@ -414,6 +_,19 @@
+@@ -390,6 +_,18 @@
@Override
public InteractionResult mobInteract(Player player, InteractionHand hand) {
boolean isFood = this.isFood(player.getItemInHand(hand));
+ // Purpur start
+ if (level().purpurConfig.striderGiveSaddleBack && player.isSecondaryUseActive() && !isFood && isSaddled() && !isVehicle()) {
-+ this.steering.setSaddle(false);
++ this.setItemSlot(EquipmentSlot.SADDLE, ItemStack.EMPTY);
+ if (!player.getAbilities().instabuild) {
+ ItemStack saddle = new ItemStack(Items.SADDLE);
+ if (!player.getInventory().add(saddle)) {
@@ -16,7 +16,6 @@
+ return InteractionResult.SUCCESS;
+ }
+ // Purpur end
-+
if (!isFood && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) {
- if (!this.level().isClientSide) {
+ if (!this.level().isClientSide()) {
player.startRiding(this);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch
deleted file mode 100644
index e1a87265f..000000000
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch
+++ /dev/null
@@ -1,20 +0,0 @@
---- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-+++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
-@@ -112,7 +_,7 @@
- this.maybeAlertOthers();
- }
-
-- if (this.isAngry()) {
-+ if (this.isAngry() && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur - Toggle for Zombified Piglin death always counting as player kill when angry
- this.lastHurtByPlayerTime = this.tickCount;
- }
-
-@@ -163,7 +_,7 @@
- this.ticksUntilNextAlert = ALERT_INTERVAL.sample(this.random);
- }
-
-- if (livingEntity instanceof Player) {
-+ if (livingEntity instanceof Player && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur - Toggle for Zombified Piglin death always counting as player kill when angry
- this.setLastHurtByPlayer((Player)livingEntity);
- }
-
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/hoglin/Hoglin.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/hoglin/Hoglin.java.patch
new file mode 100644
index 000000000..0034248ca
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/hoglin/Hoglin.java.patch
@@ -0,0 +1,14 @@
+--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java
++++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+@@ -202,6 +_,11 @@
+ public static boolean checkHoglinSpawnRules(
+ EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
++ // Purpur start - Config to disable hostile mob spawn on ice
++ if (net.minecraft.world.entity.monster.Monster.canSpawnInBlueAndPackedIce(level, pos)) {
++ return false;
++ }
++ // Purpur end - Config to disable hostile mob spawn on ice
+ return !level.getBlockState(pos.below()).is(Blocks.NETHER_WART_BLOCK);
+ }
+
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Vindicator.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/illager/Vindicator.java.patch
similarity index 79%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Vindicator.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/illager/Vindicator.java.patch
index fe07bf809..a79df0bf1 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Vindicator.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/illager/Vindicator.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/monster/Vindicator.java
-+++ b/net/minecraft/world/entity/monster/Vindicator.java
-@@ -132,6 +_,11 @@
+--- a/net/minecraft/world/entity/monster/illager/Vindicator.java
++++ b/net/minecraft/world/entity/monster/illager/Vindicator.java
+@@ -131,6 +_,11 @@
RandomSource random = level.getRandom();
this.populateDefaultEquipmentSlots(random, difficulty);
this.populateDefaultEquipmentEnchantments(level, random, difficulty);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch
new file mode 100644
index 000000000..b8e4bf183
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch
@@ -0,0 +1,14 @@
+--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
++++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
+@@ -208,6 +_,11 @@
+ public static boolean checkPiglinSpawnRules(
+ EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
++ // Purpur start - Config to disable hostile mob spawn on ice
++ if (canSpawnInBlueAndPackedIce(level, pos)) {
++ return false;
++ }
++ // Purpur end - Config to disable hostile mob spawn on ice
+ return !level.getBlockState(pos.below()).is(Blocks.NETHER_WART_BLOCK);
+ }
+
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch
index c7ccb700d..931363770 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch
@@ -1,19 +1,14 @@
--- a/net/minecraft/world/entity/monster/piglin/PiglinAi.java
+++ b/net/minecraft/world/entity/monster/piglin/PiglinAi.java
-@@ -4,6 +_,7 @@
- import com.google.common.collect.ImmutableSet;
- import com.mojang.datafixers.util.Pair;
- import java.util.Collections;
-+import java.util.Iterator;
- import java.util.List;
- import java.util.Optional;
- import net.minecraft.server.level.ServerLevel;
-@@ -666,13 +_,20 @@
+@@ -667,13 +_,23 @@
public static boolean isWearingSafeArmor(LivingEntity entity) {
- for (ItemStack itemStack : entity.getArmorAndBodyArmorSlots()) {
-- if (itemStack.is(ItemTags.PIGLIN_SAFE_ARMOR)) {
-+ if (itemStack.is(ItemTags.PIGLIN_SAFE_ARMOR) || (entity.level().purpurConfig.piglinIgnoresArmorWithGoldTrim && isWearingGoldTrim(itemStack.getItem()))) { // Purpur - piglins ignore gold-trimmed armor
+ for (EquipmentSlot equipmentSlot : EquipmentSlotGroup.ARMOR) {
+- if (entity.getItemBySlot(equipmentSlot).is(ItemTags.PIGLIN_SAFE_ARMOR)) {
++ // Purpur start - piglins ignore gold-trimmed armor
++ net.minecraft.world.item.ItemStack itemStack = entity.getItemBySlot(equipmentSlot);
++ if (itemStack.is(ItemTags.PIGLIN_SAFE_ARMOR) || (entity.level().purpurConfig.piglinIgnoresArmorWithGoldTrim && isWearingGoldTrim(itemStack))) {
++ // Purpur end - piglins ignore gold-trimmed armor
return true;
}
}
@@ -22,8 +17,8 @@
}
+
+ // Purpur start - piglins ignore gold-trimmed armor
-+ private static boolean isWearingGoldTrim(Item itemstack) {
-+ net.minecraft.world.item.equipment.trim.ArmorTrim armorTrim = itemstack.components().get(net.minecraft.core.component.DataComponents.TRIM);
++ private static boolean isWearingGoldTrim(net.minecraft.world.item.ItemStack itemstack) {
++ net.minecraft.world.item.equipment.trim.ArmorTrim armorTrim = itemstack.getComponents().get(net.minecraft.core.component.DataComponents.TRIM);
+ return armorTrim != null && armorTrim.material().is(net.minecraft.world.item.equipment.trim.TrimMaterials.GOLD);
+ }
+ // Purpur end - piglins ignore gold-trimmed armor
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch
new file mode 100644
index 000000000..e5dcc11bf
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch
@@ -0,0 +1,20 @@
+--- a/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java
+@@ -137,7 +_,7 @@
+ this.populateDefaultEquipmentEnchantments(level, random, difficulty);
+ this.reassessWeaponGoal();
+ this.setCanPickUpLoot(level.getLevel().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || random.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot
+- if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && SpecialDates.isHalloween() && random.nextFloat() < 0.25F) {
++ if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && (level.getLevel().purpurConfig.forceHalloweenSeason || SpecialDates.isHalloween()) && random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur - Halloween options and optimizations
+ this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
+ this.setDropChance(EquipmentSlot.HEAD, 0.0F);
+ }
+@@ -184,7 +_,7 @@
+ double squareRoot = Math.sqrt(d * d + d2 * d2);
+ if (this.level() instanceof ServerLevel serverLevel) {
+ Projectile.Delayed delayedEntity = Projectile.spawnProjectileUsingShootDelayed( // Paper - delayed
+- arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4
++ arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, serverLevel.purpurConfig.skeletonBowAccuracyMap.getOrDefault(serverLevel.getDifficulty().getId(), (float) (14 - serverLevel.getDifficulty().getId() * 4)) // Purpur - skeleton bow accuracy option
+ );
+
+ // Paper start - call EntityShootBowEvent
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Skeleton.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/skeleton/Skeleton.java.patch
similarity index 84%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Skeleton.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/skeleton/Skeleton.java.patch
index bba419b18..5982e0484 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Skeleton.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/skeleton/Skeleton.java.patch
@@ -1,8 +1,8 @@
---- a/net/minecraft/world/entity/monster/Skeleton.java
-+++ b/net/minecraft/world/entity/monster/Skeleton.java
-@@ -135,4 +_,64 @@
- this.spawnAtLocation(level, Items.SKELETON_SKULL);
- }
+--- a/net/minecraft/world/entity/monster/skeleton/Skeleton.java
++++ b/net/minecraft/world/entity/monster/skeleton/Skeleton.java
+@@ -130,4 +_,64 @@
+ SoundEvent getStepSound() {
+ return SoundEvents.SKELETON_STEP;
}
+
+ // Purpur start - Skeletons eat wither roses
@@ -32,7 +32,7 @@
+ return net.minecraft.world.InteractionResult.PASS;
+ }
+
-+ skeleton.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
++ skeleton.snapTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+ skeleton.setHealth(this.getHealth());
+ skeleton.setAggressive(this.isAggressive());
+ skeleton.copyPosition(this);
@@ -56,7 +56,7 @@
+ }
+
+ for (int i = 0; i < 15; ++i) {
-+ ((ServerLevel) level()).sendParticlesSource(((ServerLevel) level()).players(), null, net.minecraft.core.particles.ParticleTypes.HAPPY_VILLAGER,
++ ((net.minecraft.server.level.ServerLevel) level()).sendParticlesSource(((net.minecraft.server.level.ServerLevel) level()).players(), null, net.minecraft.core.particles.ParticleTypes.HAPPY_VILLAGER,
+ false, true,
+ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1,
+ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0);
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/warden/WardenAi.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/warden/WardenAi.java.patch
new file mode 100644
index 000000000..6c45d2405
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/warden/WardenAi.java.patch
@@ -0,0 +1,21 @@
+--- a/net/minecraft/world/entity/monster/warden/WardenAi.java
++++ b/net/minecraft/world/entity/monster/warden/WardenAi.java
+@@ -175,15 +_,16 @@
+ brain.addActivityAndRemoveMemoryWhenStopped(
+ Activity.FIGHT,
+ 10,
+- ImmutableList.of(
++ ImmutableList.copyOf(java.util.stream.Stream.>of( // Purpur - configurable warden sonic boom
+ DIG_COOLDOWN_SETTER,
+ StopAttackingIfTargetInvalid.create(
+ (level, entity) -> !warden.getAngerLevel().isAngry() || !warden.canTargetEntity(entity), WardenAi::onTargetInvalid, false
+ ),
+ SetEntityLookTarget.create(entity -> isTarget(warden, entity), (float)warden.getAttributeValue(Attributes.FOLLOW_RANGE)),
+ SetWalkTargetFromAttackTargetIfTargetOutOfReach.create(1.2F),
+- new SonicBoom(),
++ warden.level().purpurConfig.wardenCanUseSonicBoom ? new SonicBoom() : null, // Purpur - configurable warden sonic boom
+ MeleeAttack.create(18)
++ ).filter(java.util.Objects::nonNull).toList() // Purpur - configurable warden sonic boom
+ ),
+ MemoryModuleType.ATTACK_TARGET
+ );
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Drowned.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/Drowned.java.patch
similarity index 94%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Drowned.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/Drowned.java.patch
index 3d8569ee4..2f3581f1e 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Drowned.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/Drowned.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/monster/Drowned.java
-+++ b/net/minecraft/world/entity/monster/Drowned.java
-@@ -82,10 +_,23 @@
+--- a/net/minecraft/world/entity/monster/zombie/Drowned.java
++++ b/net/minecraft/world/entity/monster/zombie/Drowned.java
+@@ -86,10 +_,23 @@
this.goalSelector.addGoal(2, new Drowned.DrownedAttackGoal(this, 1.0, false));
this.goalSelector.addGoal(5, new Drowned.DrownedGoToBeachGoal(this, 1.0));
this.goalSelector.addGoal(6, new Drowned.DrownedSwimUpGoal(this, 1.0, this.level().getSeaLevel()));
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Zombie.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch
similarity index 63%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Zombie.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch
index ba29551ef..375b49003 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Zombie.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch
@@ -1,6 +1,6 @@
---- a/net/minecraft/world/entity/monster/Zombie.java
-+++ b/net/minecraft/world/entity/monster/Zombie.java
-@@ -114,7 +_,19 @@
+--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
++++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
+@@ -118,7 +_,19 @@
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0));
this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class));
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
@@ -21,15 +21,12 @@
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR));
}
-@@ -550,10 +_,7 @@
+@@ -524,7 +_,7 @@
+ }
}
- if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
-- LocalDate localDate = LocalDate.now();
-- int i = localDate.get(ChronoField.DAY_OF_MONTH);
-- int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
-- if (i1 == 10 && i == 31 && random.nextFloat() < 0.25F) {
-+ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(level.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur - Halloween options and optimizations
- this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
- this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
- }
+- if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && SpecialDates.isHalloween() && random.nextFloat() < 0.25F) {
++ if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && (level.getLevel().purpurConfig.forceHalloweenSeason || SpecialDates.isHalloween()) && random.nextFloat() < level.getLevel().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur - Halloween options and optimizations
+ this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
+ this.setDropChance(EquipmentSlot.HEAD, 0.0F);
+ }
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/ZombieVillager.java.patch
similarity index 81%
rename from purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch
rename to purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/ZombieVillager.java.patch
index e5517a82e..fd9bd006c 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/ZombieVillager.java.patch
@@ -1,13 +1,13 @@
---- a/net/minecraft/world/entity/monster/ZombieVillager.java
-+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
-@@ -156,10 +_,10 @@
+--- a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java
+@@ -159,10 +_,10 @@
public InteractionResult mobInteract(Player player, InteractionHand hand) {
ItemStack itemInHand = player.getItemInHand(hand);
if (itemInHand.is(Items.GOLDEN_APPLE)) {
- if (this.hasEffect(MobEffects.WEAKNESS)) {
+ if (this.hasEffect(MobEffects.WEAKNESS) && level().purpurConfig.zombieVillagerCureEnabled) { // Purpur - Add option to disable zombie villagers cure
itemInHand.consume(1, player);
- if (!this.level().isClientSide) {
+ if (!this.level().isClientSide()) {
- this.startConverting(player.getUUID(), this.random.nextInt(2401) + 3600);
+ this.startConverting(player.getUUID(), this.random.nextInt(level().purpurConfig.zombieVillagerCuringTimeMax - level().purpurConfig.zombieVillagerCuringTimeMin + 1) + level().purpurConfig.zombieVillagerCuringTimeMin); // Purpur - Customizable Zombie Villager curing times
}
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java.patch
new file mode 100644
index 000000000..0dae756c2
--- /dev/null
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java.patch
@@ -0,0 +1,40 @@
+--- a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
++++ b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java
+@@ -109,6 +_,12 @@
+ this.maybeAlertOthers();
+ }
+
++ // Purpur start - Toggle for Zombified Piglin death always counting as player kill when angry
++ if (this.isAngry() && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) {
++ this.lastHurtByPlayerMemoryTime = this.tickCount;
++ }
++ // Purpur end - Toggle for Zombified Piglin death always counting as player kill when angry
++
+ super.customServerAiStep(level);
+ }
+
+@@ -156,6 +_,12 @@
+ this.ticksUntilNextAlert = ALERT_INTERVAL.sample(this.random);
+ }
+
++ // Purpur start - Toggle for Zombified Piglin death always counting as player kill when angry
++ if (target instanceof Player player && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) {
++ this.setLastHurtByPlayer(player, this.tickCount);
++ }
++ // Purpur end - Toggle for Zombified Piglin death always counting as player kill when angry
++
+ return super.setTarget(target, reason); // CraftBukkit
+ }
+
+@@ -176,6 +_,11 @@
+ public static boolean checkZombifiedPiglinSpawnRules(
+ EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
+ ) {
++ // Purpur start - Config to disable hostile mob spawn on ice
++ if (canSpawnInBlueAndPackedIce(level, pos)) {
++ return false;
++ }
++ // Purpur end - Config to disable hostile mob spawn on ice
+ return level.getDifficulty() != Difficulty.PEACEFUL && !level.getBlockState(pos.below()).is(Blocks.NETHER_WART_BLOCK);
+ }
+
diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch
index d5c870866..6d573d3e2 100644
--- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch
+++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch
@@ -1,39 +1,41 @@
--- a/net/minecraft/world/entity/npc/CatSpawner.java
+++ b/net/minecraft/world/entity/npc/CatSpawner.java
-@@ -27,7 +_,7 @@
- if (this.nextTick > 0) {
- return 0;
- } else {
-- this.nextTick = 1200;
-+ this.nextTick = level.purpurConfig.catSpawnDelay; // Purpur - Cat spawning options
- Player randomPlayer = level.getRandomPlayer();
- if (randomPlayer == null) {
- return 0;
-@@ -61,8 +_,12 @@
-
- private int spawnInVillage(ServerLevel serverLevel, BlockPos pos) {
- int i = 48;
-- if (serverLevel.getPoiManager().getCountInRange(holder -> holder.is(PoiTypes.HOME), pos, 48, PoiManager.Occupancy.IS_OCCUPIED) > 4L) {
-- List entitiesOfClass = serverLevel.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(48.0, 8.0, 48.0));
-+ // Purpur start - Cat spawning options
-+ int range = serverLevel.purpurConfig.catSpawnVillageScanRange;
-+ if (range <= 0) return 0;
-+ if (serverLevel.getPoiManager().getCountInRange(holder -> holder.is(PoiTypes.HOME), pos, range, PoiManager.Occupancy.IS_OCCUPIED) > 4L) {
-+ List entitiesOfClass = serverLevel.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(range, 8.0, range));
-+ // Purpur end - Cat spawning options
- if (entitiesOfClass.size() < 5) {
- return this.spawnCat(pos, serverLevel);
- }
-@@ -73,7 +_,11 @@
-
- private int spawnInHut(ServerLevel serverLevel, BlockPos pos) {
- int i = 16;
-- List entitiesOfClass = serverLevel.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(16.0, 8.0, 16.0));
-+ // Purpur start - Cat spawning options
-+ int range = serverLevel.purpurConfig.catSpawnSwampHutScanRange;
-+ if (range <= 0) return 0;
-+ List entitiesOfClass = serverLevel.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(range, 8.0, range));
-+ // Purpur end - Cat spawning options
- return entitiesOfClass.size() < 1 ? this.spawnCat(pos, serverLevel) : 0;
+@@ -23,7 +_,7 @@
+ public void tick(ServerLevel level, boolean spawnEnemies) {
+ this.nextTick--;
+ if (this.nextTick <= 0) {
+- this.nextTick = 1200;
++ this.nextTick = level.purpurConfig.catSpawnDelay; // Purpur - Cat spawning options
+ Player randomPlayer = level.getRandomPlayer();
+ if (randomPlayer != null) {
+ RandomSource randomSource = level.random;
+@@ -45,9 +_,12 @@
}
+ private void spawnInVillage(ServerLevel level, BlockPos pos) {
+- int i = 48;
+- if (level.getPoiManager().getCountInRange(holder -> holder.is(PoiTypes.HOME), pos, 48, PoiManager.Occupancy.IS_OCCUPIED) > 4L) {
+- List entitiesOfClass = level.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(48.0, 8.0, 48.0));
++ // Purpur start - Cat spawning options
++ int range = level.purpurConfig.catSpawnVillageScanRange;
++ if (range <= 0) return;
++ if (level.getPoiManager().getCountInRange(holder -> holder.is(PoiTypes.HOME), pos, range, PoiManager.Occupancy.IS_OCCUPIED) > 4L) {
++ List