diff --git a/gradle.properties b/gradle.properties index 6809d75..ece6843 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,5 +17,5 @@ purpurBranch = ver/1.20.6 pufferfishBranch = ver/1.20 usePufferfish = false -paperCommit = 25e44bc63b467c19fe63ad6edfd8981d127f7f44 -purpurCommit = 6b1ee98f813ee19f8046b3c528feeee61840a35b +paperCommit = 4ea67abd46ecbfb501ed2e0f13d494635972bfa0 +purpurCommit = b02dc7ac072ffbffa0e47c78b20cc51e752c68a6 diff --git a/patches/api/0001-Pufferfish-API-Changes.patch b/patches/api/0001-Pufferfish-API-Changes.patch deleted file mode 100644 index b12f8e0..0000000 --- a/patches/api/0001-Pufferfish-API-Changes.patch +++ /dev/null @@ -1,527 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Kevin Raneri -Date: Tue, 9 Nov 2021 14:01:56 -0500 -Subject: [PATCH] Pufferfish API Changes - -Pufferfish -Copyright (C) 2024 Pufferfish Studios LLC - -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/build.gradle.kts b/build.gradle.kts -index 04853c43b99951bf0d4c96ef73724625bdaf018f..9164120d299d062c62529a7ef74eac0ded367993 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -51,6 +51,7 @@ dependencies { - apiAndDocs("net.kyori:adventure-text-logger-slf4j") - api("org.apache.logging.log4j:log4j-api:$log4jVersion") - api("org.slf4j:slf4j-api:$slf4jVersion") -+ api("io.sentry:sentry:5.4.0") // Pufferfish - - implementation("org.ow2.asm:asm:9.7") - implementation("org.ow2.asm:asm-commons:9.7") -@@ -109,6 +110,13 @@ val generateApiVersioningFile by tasks.registering { - } - } - -+// Pufferfish Start -+tasks.withType { -+ val compilerArgs = options.compilerArgs -+ compilerArgs.add("--add-modules=jdk.incubator.vector") -+} -+// Pufferfish End -+ - tasks.jar { - from(generateApiVersioningFile.map { it.outputs.files.singleFile }) { - into("META-INF/maven/${project.group}/${project.name}") -diff --git a/src/main/java/gg/pufferfish/pufferfish/sentry/SentryContext.java b/src/main/java/gg/pufferfish/pufferfish/sentry/SentryContext.java -new file mode 100644 -index 0000000000000000000000000000000000000000..10310fdd53de28efb8a8250f6d3b0c8eb08fb68a ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/sentry/SentryContext.java -@@ -0,0 +1,161 @@ -+package gg.pufferfish.pufferfish.sentry; -+ -+import com.google.gson.Gson; -+import java.lang.reflect.Field; -+import java.lang.reflect.Modifier; -+import java.util.Map; -+import java.util.TreeMap; -+import org.apache.logging.log4j.ThreadContext; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Event; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.plugin.Plugin; -+import org.bukkit.plugin.RegisteredListener; -+import org.jetbrains.annotations.Nullable; -+ -+public class SentryContext { -+ -+ private static final Gson GSON = new Gson(); -+ -+ public static void setPluginContext(@Nullable Plugin plugin) { -+ if (plugin != null) { -+ ThreadContext.put("pufferfishsentry_pluginname", plugin.getName()); -+ ThreadContext.put("pufferfishsentry_pluginversion", plugin.getDescription().getVersion()); -+ } -+ } -+ -+ public static void removePluginContext() { -+ ThreadContext.remove("pufferfishsentry_pluginname"); -+ ThreadContext.remove("pufferfishsentry_pluginversion"); -+ } -+ -+ public static void setSenderContext(@Nullable CommandSender sender) { -+ if (sender != null) { -+ ThreadContext.put("pufferfishsentry_playername", sender.getName()); -+ if (sender instanceof Player player) { -+ ThreadContext.put("pufferfishsentry_playerid", player.getUniqueId().toString()); -+ } -+ } -+ } -+ -+ public static void removeSenderContext() { -+ ThreadContext.remove("pufferfishsentry_playername"); -+ ThreadContext.remove("pufferfishsentry_playerid"); -+ } -+ -+ public static void setEventContext(Event event, RegisteredListener registration) { -+ setPluginContext(registration.getPlugin()); -+ -+ try { -+ // Find the player that was involved with this event -+ Player player = null; -+ if (event instanceof PlayerEvent) { -+ player = ((PlayerEvent) event).getPlayer(); -+ } else { -+ Class eventClass = event.getClass(); -+ -+ Field playerField = null; -+ -+ for (Field field : eventClass.getDeclaredFields()) { -+ if (field.getType().equals(Player.class)) { -+ playerField = field; -+ break; -+ } -+ } -+ -+ if (playerField != null) { -+ playerField.setAccessible(true); -+ player = (Player) playerField.get(event); -+ } -+ } -+ -+ if (player != null) { -+ setSenderContext(player); -+ } -+ } catch (Exception e) {} // We can't really safely log exceptions. -+ -+ ThreadContext.put("pufferfishsentry_eventdata", GSON.toJson(serializeFields(event))); -+ } -+ -+ public static void removeEventContext() { -+ removePluginContext(); -+ removeSenderContext(); -+ ThreadContext.remove("pufferfishsentry_eventdata"); -+ } -+ -+ private static Map serializeFields(Object object) { -+ Map fields = new TreeMap<>(); -+ fields.put("_class", object.getClass().getName()); -+ for (Field declaredField : object.getClass().getDeclaredFields()) { -+ try { -+ if (Modifier.isStatic(declaredField.getModifiers())) { -+ continue; -+ } -+ -+ String fieldName = declaredField.getName(); -+ if (fieldName.equals("handlers")) { -+ continue; -+ } -+ declaredField.setAccessible(true); -+ Object value = declaredField.get(object); -+ if (value != null) { -+ fields.put(fieldName, value.toString()); -+ } else { -+ fields.put(fieldName, ""); -+ } -+ } catch (Exception e) {} // We can't really safely log exceptions. -+ } -+ return fields; -+ } -+ -+ public static class State { -+ -+ private Plugin plugin; -+ private Command command; -+ private String commandLine; -+ private Event event; -+ private RegisteredListener registeredListener; -+ -+ public Plugin getPlugin() { -+ return plugin; -+ } -+ -+ public void setPlugin(Plugin plugin) { -+ this.plugin = plugin; -+ } -+ -+ public Command getCommand() { -+ return command; -+ } -+ -+ public void setCommand(Command command) { -+ this.command = command; -+ } -+ -+ public String getCommandLine() { -+ return commandLine; -+ } -+ -+ public void setCommandLine(String commandLine) { -+ this.commandLine = commandLine; -+ } -+ -+ public Event getEvent() { -+ return event; -+ } -+ -+ public void setEvent(Event event) { -+ this.event = event; -+ } -+ -+ public RegisteredListener getRegisteredListener() { -+ return registeredListener; -+ } -+ -+ public void setRegisteredListener(RegisteredListener registeredListener) { -+ this.registeredListener = registeredListener; -+ } -+ } -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ab5fea0b03224bf249352ce340e94704ff713345 ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java -@@ -0,0 +1,40 @@ -+package gg.pufferfish.pufferfish.simd; -+ -+import java.util.logging.Level; -+import java.util.logging.Logger; -+import jdk.incubator.vector.FloatVector; -+import jdk.incubator.vector.IntVector; -+import jdk.incubator.vector.VectorSpecies; -+ -+/** -+ * Basically, java is annoying and we have to push this out to its own class. -+ */ -+@Deprecated -+public class SIMDChecker { -+ -+ @Deprecated -+ public static boolean canEnable(Logger logger) { -+ try { -+ if (SIMDDetection.getJavaVersion() != 17 && SIMDDetection.getJavaVersion() != 18 && SIMDDetection.getJavaVersion() != 19) { -+ return false; -+ } else { -+ SIMDDetection.testRun = true; -+ -+ VectorSpecies ISPEC = IntVector.SPECIES_PREFERRED; -+ VectorSpecies FSPEC = FloatVector.SPECIES_PREFERRED; -+ -+ logger.log(Level.INFO, "Max SIMD vector size on this system is " + ISPEC.vectorBitSize() + " bits (int)"); -+ logger.log(Level.INFO, "Max SIMD vector size on this system is " + FSPEC.vectorBitSize() + " bits (float)"); -+ -+ if (ISPEC.elementSize() < 2 || FSPEC.elementSize() < 2) { -+ logger.log(Level.WARNING, "SIMD is not properly supported on this system!"); -+ return false; -+ } -+ -+ return true; -+ } -+ } catch (NoClassDefFoundError | Exception ignored) {} // Basically, we don't do anything. This lets us detect if it's not functional and disable it. -+ return false; -+ } -+ -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a84889d3e9cfc4d7ab5f867820a6484c6070711b ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java -@@ -0,0 +1,35 @@ -+package gg.pufferfish.pufferfish.simd; -+ -+import java.util.logging.Logger; -+ -+@Deprecated -+public class SIMDDetection { -+ -+ public static boolean isEnabled = false; -+ public static boolean versionLimited = false; -+ public static boolean testRun = false; -+ -+ @Deprecated -+ public static boolean canEnable(Logger logger) { -+ try { -+ return SIMDChecker.canEnable(logger); -+ } catch (NoClassDefFoundError | Exception ignored) { -+ return false; -+ } -+ } -+ -+ @Deprecated -+ public static int getJavaVersion() { -+ // https://stackoverflow.com/a/2591122 -+ String version = System.getProperty("java.version"); -+ if(version.startsWith("1.")) { -+ version = version.substring(2, 3); -+ } else { -+ int dot = version.indexOf("."); -+ if(dot != -1) { version = version.substring(0, dot); } -+ } -+ version = version.split("-")[0]; // Azul is stupid -+ return Integer.parseInt(version); -+ } -+ -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java b/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ae2464920c9412ac90b819a540ee58be0741465f ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java -@@ -0,0 +1,83 @@ -+package gg.pufferfish.pufferfish.simd; -+ -+import java.awt.Color; -+import jdk.incubator.vector.FloatVector; -+import jdk.incubator.vector.IntVector; -+import jdk.incubator.vector.VectorMask; -+import jdk.incubator.vector.VectorSpecies; -+import org.bukkit.map.MapPalette; -+ -+@Deprecated -+public class VectorMapPalette { -+ -+ private static final VectorSpecies I_SPEC = IntVector.SPECIES_PREFERRED; -+ private static final VectorSpecies F_SPEC = FloatVector.SPECIES_PREFERRED; -+ -+ @Deprecated -+ public static void matchColorVectorized(int[] in, byte[] out) { -+ int speciesLength = I_SPEC.length(); -+ int i; -+ for (i = 0; i < in.length - speciesLength; i += speciesLength) { -+ float[] redsArr = new float[speciesLength]; -+ float[] bluesArr = new float[speciesLength]; -+ float[] greensArr = new float[speciesLength]; -+ int[] alphasArr = new int[speciesLength]; -+ -+ for (int j = 0; j < speciesLength; j++) { -+ alphasArr[j] = (in[i + j] >> 24) & 0xFF; -+ redsArr[j] = (in[i + j] >> 16) & 0xFF; -+ greensArr[j] = (in[i + j] >> 8) & 0xFF; -+ bluesArr[j] = (in[i + j] >> 0) & 0xFF; -+ } -+ -+ IntVector alphas = IntVector.fromArray(I_SPEC, alphasArr, 0); -+ FloatVector reds = FloatVector.fromArray(F_SPEC, redsArr, 0); -+ FloatVector greens = FloatVector.fromArray(F_SPEC, greensArr, 0); -+ FloatVector blues = FloatVector.fromArray(F_SPEC, bluesArr, 0); -+ IntVector resultIndex = IntVector.zero(I_SPEC); -+ VectorMask modificationMask = VectorMask.fromLong(I_SPEC, 0xffffffff); -+ -+ modificationMask = modificationMask.and(alphas.lt(128).not()); -+ FloatVector bestDistances = FloatVector.broadcast(F_SPEC, Float.MAX_VALUE); -+ -+ for (int c = 4; c < MapPalette.colors.length; c++) { -+ // We're using 32-bit floats here because it's 2x faster and nobody will know the difference. -+ // For correctness, the original algorithm uses 64-bit floats instead. Completely unnecessary. -+ FloatVector compReds = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getRed()); -+ FloatVector compGreens = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getGreen()); -+ FloatVector compBlues = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getBlue()); -+ -+ FloatVector rMean = reds.add(compReds).div(2.0f); -+ FloatVector rDiff = reds.sub(compReds); -+ FloatVector gDiff = greens.sub(compGreens); -+ FloatVector bDiff = blues.sub(compBlues); -+ -+ FloatVector weightR = rMean.div(256.0f).add(2); -+ FloatVector weightG = FloatVector.broadcast(F_SPEC, 4.0f); -+ FloatVector weightB = FloatVector.broadcast(F_SPEC, 255.0f).sub(rMean).div(256.0f).add(2.0f); -+ -+ FloatVector distance = weightR.mul(rDiff).mul(rDiff).add(weightG.mul(gDiff).mul(gDiff)).add(weightB.mul(bDiff).mul(bDiff)); -+ -+ // Now we compare to the best distance we've found. -+ // This mask contains a "1" if better, and a "0" otherwise. -+ VectorMask bestDistanceMask = distance.lt(bestDistances); -+ bestDistances = bestDistances.blend(distance, bestDistanceMask); // Update the best distances -+ -+ // Update the result array -+ // We also AND with the modification mask because we don't want to interfere if the alpha value isn't large enough. -+ resultIndex = resultIndex.blend(c, bestDistanceMask.cast(I_SPEC).and(modificationMask)); // Update the results -+ } -+ -+ for (int j = 0; j < speciesLength; j++) { -+ int index = resultIndex.lane(j); -+ out[i + j] = (byte) (index < 128 ? index : -129 + (index - 127)); -+ } -+ } -+ -+ // For the final ones, fall back to the regular method -+ for (; i < in.length; i++) { -+ out[i] = MapPalette.matchColor(new Color(in[i], true)); -+ } -+ } -+ -+} -diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java -index c80faa079eca1564847070f0338fc98024639829..e632d51d3487eb4807243b6705999ad124466bf5 100644 ---- a/src/main/java/org/bukkit/map/MapPalette.java -+++ b/src/main/java/org/bukkit/map/MapPalette.java -@@ -1,6 +1,7 @@ - package org.bukkit.map; - - import com.google.common.base.Preconditions; -+import gg.pufferfish.pufferfish.simd.SIMDDetection; // Pufferfish - import java.awt.Color; - import java.awt.Graphics2D; - import java.awt.Image; -@@ -40,7 +41,7 @@ public final class MapPalette { - } - - @NotNull -- static final Color[] colors = { -+ public static final Color[] colors = { // Pufferfish - public access - c(0, 0, 0, 0), c(0, 0, 0, 0), c(0, 0, 0, 0), c(0, 0, 0, 0), - c(89, 125, 39), c(109, 153, 48), c(127, 178, 56), c(67, 94, 29), - c(174, 164, 115), c(213, 201, 140), c(247, 233, 163), c(130, 123, 86), -@@ -211,9 +212,15 @@ public final class MapPalette { - temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth()); - - byte[] result = new byte[temp.getWidth() * temp.getHeight()]; -+ // Pufferfish start -+ if (!SIMDDetection.isEnabled) { - for (int i = 0; i < pixels.length; i++) { - result[i] = matchColor(new Color(pixels[i], true)); - } -+ } else { -+ gg.pufferfish.pufferfish.simd.VectorMapPalette.matchColorVectorized(pixels, result); -+ } -+ // Pufferfish end - return result; - } - -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index fc2dae69165776d08274e34a69962cc70445f411..899d67fa782fac639fe7fb096e05c551d75bd647 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -584,7 +584,9 @@ public final class SimplePluginManager implements PluginManager { - - // Paper start - private void handlePluginException(String msg, Throwable ex, Plugin plugin) { -+ gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish - server.getLogger().log(Level.SEVERE, msg, ex); -+ gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish - callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerPluginEnableDisableException(msg, ex, plugin))); - } - // Paper end -@@ -654,9 +656,11 @@ public final class SimplePluginManager implements PluginManager { - )); - } - } catch (Throwable ex) { -+ gg.pufferfish.pufferfish.sentry.SentryContext.setEventContext(event, registration); // Pufferfish - // Paper start - error reporting - String msg = "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName(); - server.getLogger().log(Level.SEVERE, msg, ex); -+ gg.pufferfish.pufferfish.sentry.SentryContext.removeEventContext(); // Pufferfish - if (!(event instanceof com.destroystokyo.paper.event.server.ServerExceptionEvent)) { // We don't want to cause an endless event loop - callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event))); - } -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index eaefbb00e9993d54906cc8cf35cf753c0d6c7707..301e82369603f3dd6e6c1bd380da4bacacd7ef6c 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -336,7 +336,13 @@ public final class JavaPluginLoader implements PluginLoader { - try { - jPlugin.setEnabled(true); - } catch (Throwable ex) { -+ gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish - server.getLogger().log(Level.SEVERE, "Error occurred while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); -+ gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish -+ // Paper start - Disable plugins that fail to load -+ this.server.getPluginManager().disablePlugin(jPlugin); -+ return; -+ // Paper end - } - - // Perhaps abort here, rather than continue going, but as it stands, -@@ -361,7 +367,9 @@ public final class JavaPluginLoader implements PluginLoader { - try { - jPlugin.setEnabled(false); - } catch (Throwable ex) { -+ gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish - server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); -+ gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish - } - - if (cloader instanceof PluginClassLoader) { -diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -index 7e4f7cb2afbc145e532285c793573ad107bc3033..12449e18180d604e9cbbc744da74a8b222a18e1f 100644 ---- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -@@ -50,6 +50,8 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm - private io.papermc.paper.plugin.provider.classloader.PluginClassLoaderGroup classLoaderGroup; // Paper - public io.papermc.paper.plugin.provider.entrypoint.DependencyContext dependencyContext; // Paper - -+ private boolean closed = false; // Pufferfish -+ - static { - ClassLoader.registerAsParallelCapable(); - } -@@ -197,6 +199,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm - throw new ClassNotFoundException(name); - } - -+ public boolean _airplane_hasClass(@NotNull String name) { return this.classes.containsKey(name); } // Pufferfish - @Override - protected Class findClass(String name) throws ClassNotFoundException { - if (name.startsWith("org.bukkit.") || name.startsWith("net.minecraft.")) { -@@ -204,7 +207,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm - } - Class result = classes.get(name); - -- if (result == null) { -+ if (result == null && !this.closed) { // Pufferfish - String path = name.replace('.', '/').concat(".class"); - JarEntry entry = jar.getJarEntry(path); - -@@ -251,6 +254,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm - this.setClass(name, result); // Paper - } - -+ if (result == null) throw new ClassNotFoundException(name); // Pufferfish - return result; - } - -@@ -265,6 +269,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm - // Paper end - super.close(); - } finally { -+ this.closed = true; // Pufferfish - jar.close(); - } - } diff --git a/patches/api/0002-Purpur-API-Changes.patch b/patches/api/0001-Purpur-API-Patches.patch similarity index 86% rename from patches/api/0002-Purpur-API-Changes.patch rename to patches/api/0001-Purpur-API-Patches.patch index db4566c..0e1aed9 100644 --- a/patches/api/0002-Purpur-API-Changes.patch +++ b/patches/api/0001-Purpur-API-Patches.patch @@ -1,34 +1,14 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Fri, 26 Apr 2024 18:07:21 +0900 -Subject: [PATCH] Purpur API Changes +From: AlphaKR93 +Date: Tue, 30 Apr 2024 23:08:38 +0900 +Subject: [PATCH] Purpur API Patches -PurpurMC -Copyright (C) 2024 PurpurMC - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/build.gradle.kts b/build.gradle.kts -index 9164120d299d062c62529a7ef74eac0ded367993..09e541dcbbb43699b4402036b8a3cc86a0ac9aad 100644 +index 65e67b8726f1e19a6bcb1fe2f448e4ab68df11d1..892e78b1d2d29dc54def03fcb6d85a93ad56d84c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts -@@ -129,6 +129,8 @@ tasks.jar { +@@ -121,6 +121,8 @@ tasks.jar { } tasks.withType { @@ -185,24 +165,11 @@ index a736d7bcdc5861a01b66ba36158db1c716339346..22fc165fd9c95f0f3ae1be7a0857e48c class DummyVersionFetcher implements VersionFetcher { @Override -diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java -index ab5fea0b03224bf249352ce340e94704ff713345..3441cdad70da1bd523c5933b1a914688718c2657 100644 ---- a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java -+++ b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java -@@ -15,7 +15,7 @@ public class SIMDChecker { - @Deprecated - public static boolean canEnable(Logger logger) { - try { -- if (SIMDDetection.getJavaVersion() != 17 && SIMDDetection.getJavaVersion() != 18 && SIMDDetection.getJavaVersion() != 19) { -+ if (SIMDDetection.getJavaVersion() < 17 || SIMDDetection.getJavaVersion() > 21) { - return false; - } else { - SIMDDetection.testRun = true; diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 9a428153f34291bdc026a71f7e60e285b7794b0c..53ce0fb2dac9c22680ab934f535b5a2037139445 100644 +index 687bd8f54c9bfb5f5ab1f7ad9d232daf2433cc76..60de2456d00e85ac5ec5c4549198429aea87bc6d 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2884,4 +2884,127 @@ public final class Bukkit { +@@ -2907,4 +2907,127 @@ public final class Bukkit { public static Server.Spigot spigot() { return server.spigot(); } @@ -421,10 +388,10 @@ index 918a045165cdcde264bc24082b7afebb407271de..687d11619379aead7f665d4a5f8f8bcc + // Purpur end } diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index ec117c47401ea1a04beb0e5ee9d4d394db7c5c4e..5b058d709751a5b720e209931774e09fcc9c960c 100644 +index 82d009c0bbe4b3026a535e02d6e0ed20c7bd525d..0366400fe6dea7af40badaa3335b49ff5992a516 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java -@@ -11559,4 +11559,40 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -11653,4 +11653,40 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla public boolean isEnabledByFeature(@NotNull World world) { return Bukkit.getDataPackManager().isEnabledByFeature(this, world); } @@ -577,10 +544,10 @@ index 30298a629b39bd43ce14b414fc697b2dfcbea89c..ce00af9121de7a910aaea4e0685a06d4 + // Purpur end - OfflinePlayer API } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 4ff1b38eb65f97344257204cf018f176f247ed36..c15b0b05870a469ea5d314c9fac6a57a045f463c 100644 +index 27084402cf0e46dcd171074629b7c4156e48aa44..a15d0ed710ff261f203d7e355e7d532f2e68abc9 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -2235,6 +2235,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2254,6 +2254,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi } // Paper end @@ -599,7 +566,7 @@ index 4ff1b38eb65f97344257204cf018f176f247ed36..c15b0b05870a469ea5d314c9fac6a57a /** * Sends the component to the player * -@@ -2518,4 +2530,105 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2537,4 +2549,105 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi */ boolean isOwnedByCurrentRegion(@NotNull Entity entity); // Paper end - Folia region threading API @@ -706,10 +673,10 @@ index 4ff1b38eb65f97344257204cf018f176f247ed36..c15b0b05870a469ea5d314c9fac6a57a + // Purpur end } diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index e6f66d70d024cf4f0536a5bf8e51bf7b306335df..07e75978b4fc0e446e8aa46a40be5e371dc1c11b 100644 +index 97f97ea5c6aa513c439f86a9c82821e0f7d9cd1e..83a5b68c785a88594e6e3824ed282844086f7f1a 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java -@@ -4233,6 +4233,86 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient +@@ -4249,6 +4249,86 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient @Nullable public DragonBattle getEnderDragonBattle(); @@ -959,10 +926,10 @@ index 138d2530de2410f4a9424dabd3e5ce0cd1c1dcd2..10a8d64ad2da0be2c14f34c3e7d1957c // Paper start /** diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 23def071492ccd715693d534cc506936e18f0f46..706096924ffd3b578866693e2937de4182fad554 100644 +index 62e3793903905b94eb1a120345015149abb33713..07b8c0dd049ff783fd2e408be634642479bf8b1e 100644 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -1144,4 +1144,55 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent +@@ -1155,4 +1155,55 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent */ @NotNull String getScoreboardEntryName(); // Paper end - entity scoreboard name @@ -1111,30 +1078,16 @@ index bcc6ba95bd21c7972865838c636a03f50b6c1f1a..c3fcd8dd7dbb1e1a18e17c014c1e6411 + // Purpur end } diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index 65112eae8b92344796850b1e4c89e75443eab2fe..5369d802d37863a1efc0c031520147ceedcadc78 100644 +index b777e530122549455dcce6fac8d4a151c1c0af42..61a046584acf48693489ff551a0dd4c4b16af9ff 100644 --- a/src/main/java/org/bukkit/entity/LivingEntity.java +++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -1445,4 +1445,41 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource +@@ -1447,4 +1447,27 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource */ void setBodyYaw(float bodyYaw); // Paper end - body yaw API + + // Purpur start + /** -+ * Gets the distance (in blocks) this entity can safely fall without taking damage -+ * -+ * @return Safe fall distance -+ */ -+ float getSafeFallDistance(); -+ -+ /** -+ * Set the distance (in blocks) this entity can safely fall without taking damage -+ * -+ * @param safeFallDistance Safe fall distance -+ */ -+ void setSafeFallDistance(float safeFallDistance); -+ -+ /** + * Play item break animation for the item in specified equipment slot + * + * @param slot Equipment slot to play break animation for @@ -1182,10 +1135,10 @@ index bc84b892cae5fe7019a3ad481e9da79956efa1fe..48eb5b00c460cccde29d327cef1d63fc + // Purpur end } diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index d048ae07cc33fd77d128cc1ebf88b0804969fa3c..8bbbdad40bc6a1932d8f79ec95c0a92037b3dac5 100644 +index 8a1e39474af88188f2e1765731b57d349f0ee645..b76adf4370555b02b891a49f8019b4e152c002c2 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java -@@ -3752,4 +3752,123 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM +@@ -3796,4 +3796,123 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM @Override Spigot spigot(); // Spigot end @@ -1379,13 +1332,13 @@ index 14543c2238b45c526dd9aebea2aa5c22f5df54dc..5312daf33405704c74e2c9e109754285 + // Purpur end } diff --git a/src/main/java/org/bukkit/entity/Wolf.java b/src/main/java/org/bukkit/entity/Wolf.java -index 84db38388bf7a58e66d6cd29620b4fe64b0a897e..82ebd99549ce9f9e6427a50cef424e9007735708 100644 +index 4b84c04675775e2a606630b00de8afe51665cebc..ccbaf40a3131f477b4be2264401ad893725c1162 100644 --- a/src/main/java/org/bukkit/entity/Wolf.java +++ b/src/main/java/org/bukkit/entity/Wolf.java -@@ -69,4 +69,20 @@ public interface Wolf extends Tameable, Sittable, io.papermc.paper.entity.Collar - * @param interested Whether the wolf is interested - */ - public void setInterested(boolean interested); +@@ -112,4 +112,20 @@ public interface Wolf extends Tameable, Sittable, io.papermc.paper.entity.Collar + return variant; + } + } + + // Purpur start + /** @@ -1435,10 +1388,10 @@ index c9f395064656dd0126410eb3c6e197baa450c063..13156a12e5df50cdc1e465dc0bd9d941 * When a player gets bad omen after killing a patrol captain. */ diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java -index daa1306a7324d946d66ad5a674bbc84371d8d4d6..f3b2d7b6fda051211add2b3215f120fb6911aeed 100644 +index 59b375569a75cb1e1f7c610f96078e102ec0d3ed..a3f74891abbdc51dbbddaeb511f2754e0603c904 100644 --- a/src/main/java/org/bukkit/event/inventory/InventoryType.java +++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java -@@ -165,7 +165,7 @@ public enum InventoryType { +@@ -166,7 +166,7 @@ public enum InventoryType { SMITHING_NEW(4, "Upgrade Gear"), ; @@ -1464,32 +1417,13 @@ index c60be4fd24c7fdf65251dd6169e5e1ac3b588d95..569deccd2f1cf21da9b5906433ac493c + boolean canDoUnsafeEnchants(); + + void setDoUnsafeEnchants(boolean canDoUnsafeEnchants); -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java -index f680545b6b59bf8d2ad154b0472dda4cba42a162..58a62ba0635f9158bf18043da89aba7521e0e2e1 100644 ---- a/src/main/java/org/bukkit/inventory/ItemFactory.java -+++ b/src/main/java/org/bukkit/inventory/ItemFactory.java -@@ -353,4 +353,14 @@ public interface ItemFactory { - */ - @NotNull ItemStack enchantWithLevels(@NotNull ItemStack itemStack, @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, boolean allowTreasure, @NotNull java.util.Random random); - // Paper end - enchantWithLevels API -+ -+ // Purpur start -+ /** -+ * Returns the lines of text shown when hovering over an item -+ * @param itemStack The ItemStack -+ * @param advanced Whether advanced tooltips are shown -+ * @return the list of Components -+ */ -+ @NotNull java.util.List getHoverLines(@NotNull ItemStack itemStack, boolean advanced); + // Purpur end } diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 7414b4fa690d393a8e9557cc1fd1ce12fa426940..591759aef6c7c3333cbdab596c6619af9185c3c2 100644 +index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db534286d267b05 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -17,6 +17,18 @@ import org.bukkit.inventory.meta.ItemMeta; +@@ -17,6 +17,17 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.material.MaterialData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -1503,12 +1437,11 @@ index 7414b4fa690d393a8e9557cc1fd1ce12fa426940..591759aef6c7c3333cbdab596c6619af +import org.bukkit.inventory.meta.Repairable; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataHolder; -+import com.destroystokyo.paper.Namespaced; +// Purpur end /** * Represents a stack of items. -@@ -1061,4 +1073,635 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat +@@ -1073,4 +1084,565 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat return Bukkit.getUnsafe().computeTooltipLines(this, tooltipContext, player); } // Paper end - expose itemstack tooltip lines @@ -1993,67 +1926,6 @@ index 7414b4fa690d393a8e9557cc1fd1ce12fa426940..591759aef6c7c3333cbdab596c6619af + } + + /** -+ * Gets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @return Set of {@link com.destroystokyo.paper.Namespaced} -+ */ -+ @NotNull -+ public java.util.Set getDestroyableKeys() { -+ return getItemMeta().getDestroyableKeys(); -+ } -+ -+ /** -+ * Sets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @param canDestroy Collection of {@link com.destroystokyo.paper.Namespaced} -+ */ -+ public void setDestroyableKeys(@NotNull Collection canDestroy) { -+ ItemMeta itemMeta = getItemMeta(); -+ itemMeta.setDestroyableKeys(canDestroy); -+ setItemMeta(itemMeta); -+ } -+ -+ /** -+ * Gets the collection of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @return Set of {@link com.destroystokyo.paper.Namespaced} -+ */ -+ @NotNull -+ public java.util.Set getPlaceableKeys() { -+ return getItemMeta().getPlaceableKeys(); -+ } -+ -+ /** -+ * Sets the set of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @param canPlaceOn Collection of {@link com.destroystokyo.paper.Namespaced} -+ */ -+ @NotNull -+ public void setPlaceableKeys(@NotNull Collection canPlaceOn) { -+ ItemMeta itemMeta = getItemMeta(); -+ itemMeta.setPlaceableKeys(canPlaceOn); -+ setItemMeta(itemMeta); -+ } -+ -+ /** -+ * Checks for the existence of any keys that the item can be placed on -+ * -+ * @return true if this item has placeable keys -+ */ -+ public boolean hasPlaceableKeys() { -+ return hasItemMeta() && getItemMeta().hasPlaceableKeys(); -+ } -+ -+ /** -+ * Checks for the existence of any keys that the item can destroy -+ * -+ * @return true if this item has destroyable keys -+ */ -+ public boolean hasDestroyableKeys() { -+ return hasItemMeta() && getItemMeta().hasDestroyableKeys(); -+ } -+ -+ /** + * Repairs this item by 1 durability + */ + public void repair() { @@ -2098,7 +1970,7 @@ index 7414b4fa690d393a8e9557cc1fd1ce12fa426940..591759aef6c7c3333cbdab596c6619af + public boolean damage(int amount, boolean ignoreUnbreaking) { + Damageable damageable = (Damageable) getItemMeta(); + if (amount > 0) { -+ int unbreaking = getEnchantLevel(Enchantment.DURABILITY); ++ int unbreaking = getEnchantLevel(Enchantment.UNBREAKING); + int reduce = 0; + for (int i = 0; unbreaking > 0 && i < amount; ++i) { + if (reduceDamage(java.util.concurrent.ThreadLocalRandom.current(), unbreaking)) { @@ -2133,15 +2005,6 @@ index 7414b4fa690d393a8e9557cc1fd1ce12fa426940..591759aef6c7c3333cbdab596c6619af + } + return random.nextInt(unbreaking + 1) > 0; + } -+ -+ /** -+ * Returns the lines of text shown when hovering over the item -+ * @param advanced Whether advanced tooltips are shown -+ * @return the list of Components -+ */ -+ public @NotNull List getHoverLines(boolean advanced) { -+ return Bukkit.getItemFactory().getHoverLines(this, advanced); -+ } + // Purpur end } diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java @@ -2230,7 +2093,7 @@ index cd3296fea01648592d2af89b3d80135acb6d0958..45797a6fbae1d8edc4211cb30def24ad permissions.put(lname, new PermissionAttachmentInfo(parent, lname, attachment, value)); diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index 301e82369603f3dd6e6c1bd380da4bacacd7ef6c..0c6ca7588fb3d6b6497ddf032fe75e5c6c9719e5 100644 +index eaefbb00e9993d54906cc8cf35cf753c0d6c7707..f1e58639213be0c43cd2ff090b625e7d0a67e8be 100644 --- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java @@ -55,6 +55,7 @@ public final class JavaPluginLoader implements PluginLoader { @@ -2242,10 +2105,10 @@ index 301e82369603f3dd6e6c1bd380da4bacacd7ef6c..0c6ca7588fb3d6b6497ddf032fe75e5c /** * This class was not meant to be constructed explicitly diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -index 653135352c104a6ddeb74a1b6d4916c6952d6271..46b0d02aa759b3735e6ac811523d459cf263aa8b 100644 +index 8e1b6be2462aaa692efa1f72986921a6dc357196..b6e18b12fd4d61ce92203582906d24b4d14e6cc5 100644 --- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -@@ -66,6 +66,7 @@ public class LibraryLoader +@@ -68,6 +68,7 @@ public class LibraryLoader @Override public void transferStarted(@NotNull TransferEvent event) throws TransferCancelledException { @@ -2253,7 +2116,7 @@ index 653135352c104a6ddeb74a1b6d4916c6952d6271..46b0d02aa759b3735e6ac811523d459c logger.log( Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName() ); } } ); -@@ -81,6 +82,7 @@ public class LibraryLoader +@@ -88,6 +89,7 @@ public class LibraryLoader { return null; } @@ -2261,7 +2124,7 @@ index 653135352c104a6ddeb74a1b6d4916c6952d6271..46b0d02aa759b3735e6ac811523d459c 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 -@@ -119,6 +121,7 @@ public class LibraryLoader +@@ -135,6 +137,7 @@ public class LibraryLoader } jarFiles.add( url ); @@ -2269,204 +2132,6 @@ index 653135352c104a6ddeb74a1b6d4916c6952d6271..46b0d02aa759b3735e6ac811523d459c 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/src/main/java/org/bukkit/potion/PotionEffect.java b/src/main/java/org/bukkit/potion/PotionEffect.java -index c8ab330ef171795d08fa201cf8320703c7f1c66b..93e2ea220dc03c122f82af65d5e9fda5b582290c 100644 ---- a/src/main/java/org/bukkit/potion/PotionEffect.java -+++ b/src/main/java/org/bukkit/potion/PotionEffect.java -@@ -33,6 +33,7 @@ public class PotionEffect implements ConfigurationSerializable { - private static final String AMBIENT = "ambient"; - private static final String PARTICLES = "has-particles"; - private static final String ICON = "has-icon"; -+ private static final String KEY = "namespacedKey"; // Purpur - private final int amplifier; - private final int duration; - private final PotionEffectType type; -@@ -40,6 +41,7 @@ public class PotionEffect implements ConfigurationSerializable { - private final boolean particles; - private final boolean icon; - private final PotionEffect hiddenEffect; // Paper -+ @Nullable private final NamespacedKey key; // Purpur - - /** - * Creates a potion effect. -@@ -50,11 +52,12 @@ public class PotionEffect implements ConfigurationSerializable { - * @param ambient the ambient status, see {@link PotionEffect#isAmbient()} - * @param particles the particle status, see {@link PotionEffect#hasParticles()} - * @param icon the icon status, see {@link PotionEffect#hasIcon()} -+ * @param key the namespacedKey, see {@link PotionEffect#getKey()} - * @param hiddenEffect the hidden PotionEffect - * @hidden Internal-- hidden effects are only shown internally - */ - @org.jetbrains.annotations.ApiStatus.Internal // Paper -- public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon, @Nullable PotionEffect hiddenEffect) { // Paper -+ public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon, @Nullable PotionEffect hiddenEffect, @Nullable NamespacedKey key) { // Paper // Purpur - Preconditions.checkArgument(type != null, "effect type cannot be null"); - this.type = type; - this.duration = duration; -@@ -62,6 +65,7 @@ public class PotionEffect implements ConfigurationSerializable { - this.ambient = ambient; - this.particles = particles; - this.icon = icon; -+ this.key = key; // Purpur - // Paper start - this.hiddenEffect = hiddenEffect; - } -@@ -77,10 +81,27 @@ public class PotionEffect implements ConfigurationSerializable { - * @param icon the icon status, see {@link PotionEffect#hasIcon()} - */ - public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon) { -- this(type, duration, amplifier, ambient, particles, icon, null); -+ this(type, duration, amplifier, ambient, particles, icon, null, null); // Purpur - // Paper end - } - -+ // Purpur start -+ /** -+ * Creates a potion effect. -+ * @param type effect type -+ * @param duration measured in ticks, see {@link -+ * PotionEffect#getDuration()} -+ * @param amplifier the amplifier, see {@link PotionEffect#getAmplifier()} -+ * @param ambient the ambient status, see {@link PotionEffect#isAmbient()} -+ * @param particles the particle status, see {@link PotionEffect#hasParticles()} -+ * @param icon the icon status, see {@link PotionEffect#hasIcon()} -+ * @param key the namespacedKey, see {@link PotionEffect#getKey()} -+ */ -+ public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon, @Nullable NamespacedKey key) { -+ this(type, duration, amplifier, ambient, particles, icon, null, key); -+ } -+ // Purpur end -+ - /** - * Creates a potion effect with no defined color. - * -@@ -126,33 +147,33 @@ public class PotionEffect implements ConfigurationSerializable { - * @param map the map to deserialize from - */ - public PotionEffect(@NotNull Map map) { -- this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true)), (PotionEffect) map.get(HIDDEN_EFFECT)); // Paper -+ this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true)), (PotionEffect) map.get(HIDDEN_EFFECT), getKey(map)); // Paper // Purpur - getKey - } - - // Paper start - @NotNull - public PotionEffect withType(@NotNull PotionEffectType type) { -- return new PotionEffect(type, duration, amplifier, ambient, particles, icon); -+ return new PotionEffect(type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key - } - @NotNull - public PotionEffect withDuration(int duration) { -- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key - } - @NotNull - public PotionEffect withAmplifier(int amplifier) { -- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key - } - @NotNull - public PotionEffect withAmbient(boolean ambient) { -- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key - } - @NotNull - public PotionEffect withParticles(boolean particles) { -- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key - } - @NotNull - public PotionEffect withIcon(boolean icon) { -- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key - } - - /** -@@ -169,6 +190,13 @@ public class PotionEffect implements ConfigurationSerializable { - } - // Paper end - -+ // Purpur start -+ @NotNull -+ public PotionEffect withKey(@Nullable NamespacedKey key) { -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); -+ } -+ // Purpur end -+ - @NotNull - private static PotionEffectType getEffectType(@NotNull Map map) { - PotionEffectType effect; -@@ -201,6 +229,17 @@ public class PotionEffect implements ConfigurationSerializable { - return def; - } - -+ // Purpur start -+ @Nullable -+ private static NamespacedKey getKey(@NotNull Map map) { -+ Object key = map.get(KEY); -+ if (key instanceof String stringKey) { -+ return NamespacedKey.fromString(stringKey); -+ } -+ return null; -+ } -+ // Purpur end -+ - @Override - @NotNull - public Map serialize() { -@@ -215,6 +254,11 @@ public class PotionEffect implements ConfigurationSerializable { - if (this.hiddenEffect != null) { - builder.put(HIDDEN_EFFECT, this.hiddenEffect); - } -+ // Purpur start -+ if (key != null) { -+ builder.put(KEY, key.toString()); -+ } -+ // Purpur end - return builder.build(); - // Paper end - } -@@ -243,7 +287,7 @@ public class PotionEffect implements ConfigurationSerializable { - return false; - } - PotionEffect that = (PotionEffect) obj; -- return this.type.equals(that.type) && this.ambient == that.ambient && this.amplifier == that.amplifier && this.duration == that.duration && this.particles == that.particles && this.icon == that.icon && java.util.Objects.equals(this.hiddenEffect, that.hiddenEffect); // Paper -+ return this.type.equals(that.type) && this.ambient == that.ambient && this.amplifier == that.amplifier && this.duration == that.duration && this.particles == that.particles && this.icon == that.icon && java.util.Objects.equals(this.hiddenEffect, that.hiddenEffect) && this.key == that.key; // Paper // Purpur - add key - } - - /** -@@ -339,6 +383,24 @@ public class PotionEffect implements ConfigurationSerializable { - return icon; - } - -+ -+ // Purpur start -+ /** -+ * @return if the key isn't the default namespacedKey -+ */ -+ public boolean hasKey() { -+ return key != null; -+ } -+ -+ /** -+ * @return the key attached to the potion -+ */ -+ @Nullable -+ public NamespacedKey getKey() { -+ return key; -+ } -+ // Purpur end -+ - @Override - public int hashCode() { - int hash = 1; -@@ -354,6 +416,6 @@ public class PotionEffect implements ConfigurationSerializable { - - @Override - public String toString() { -- return "PotionEffect{" + "amplifier=" + amplifier + ", duration=" + duration + ", type=" + type + ", ambient=" + ambient + ", particles=" + particles + ", icon=" + icon + ", hiddenEffect=" + hiddenEffect + '}'; // Paper -+ return "PotionEffect{" + "amplifier=" + amplifier + ", duration=" + duration + ", type=" + type + ", ambient=" + ambient + ", particles=" + particles + ", icon=" + icon + ", hiddenEffect=" + hiddenEffect + ", key=" + key + '}'; // Paper // Purpur - add key - } - } diff --git a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java index 7763d6101ac61900db1e2310966b99584539fd0e..d5a42707d365ffd72532bbb1a59a1ca7145f9918 100644 --- a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java @@ -2993,10 +2658,10 @@ index 0000000000000000000000000000000000000000..519809eab5d926dc7b0a7bad5d446d0d +} diff --git a/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java b/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..32602b398ede24a35ed8a996faa2b23455615a7b +index 0000000000000000000000000000000000000000..8ea97ddceedb7c719e8a50a0dd8f3f0919ca1647 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java -@@ -0,0 +1,54 @@ +@@ -0,0 +1,53 @@ +package org.purpurmc.purpur.event; + +import org.bukkit.block.Block; @@ -3005,7 +2670,6 @@ index 0000000000000000000000000000000000000000..32602b398ede24a35ed8a996faa2b234 +import org.bukkit.event.HandlerList; +import org.bukkit.event.block.BlockExplodeEvent; +import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; +import java.util.Collections; + +/** @@ -3016,8 +2680,8 @@ index 0000000000000000000000000000000000000000..32602b398ede24a35ed8a996faa2b234 + private boolean cancelled; + private final float yield; + -+ public PreBlockExplodeEvent(@NotNull final Block what, final float yield, @Nullable BlockState explodedBlockState) { -+ super(what, Collections.emptyList(), yield, explodedBlockState); ++ public PreBlockExplodeEvent(@NotNull final Block what, final float yield, @NotNull BlockState explodedBlockState) { ++ super(what, explodedBlockState, Collections.emptyList(), yield); + this.yield = yield; + this.cancelled = false; + } @@ -3918,60 +3582,6 @@ index 0000000000000000000000000000000000000000..eebb5d124456b8209d1b8e8cc4cb772d + return handlers; + } +} -diff --git a/src/main/java/org/purpurmc/purpur/event/packet/NetworkItemSerializeEvent.java b/src/main/java/org/purpurmc/purpur/event/packet/NetworkItemSerializeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c0da73d2ea83a6055e34894ba1c7506fc8667712 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/packet/NetworkItemSerializeEvent.java -@@ -0,0 +1,48 @@ -+package org.purpurmc.purpur.event.packet; -+ -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when an item is about to be written to a packet. -+ */ -+public class NetworkItemSerializeEvent extends Event { -+ private ItemStack itemStack; -+ -+ public NetworkItemSerializeEvent(@NotNull ItemStack itemStack) { -+ super(!org.bukkit.Bukkit.isPrimaryThread()); -+ this.itemStack = itemStack; -+ } -+ -+ /** -+ * @return The item that is about to be serialized. Not mutable -+ */ -+ @NotNull -+ public ItemStack getItemStack() { -+ return itemStack; -+ } -+ -+ /** -+ * Sets the item that will be serialized. -+ * -+ * @param itemStack The item -+ */ -+ public void setItemStack(@Nullable ItemStack itemStack) { -+ this.itemStack = itemStack; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java b/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..c88394336bc9ab0f66a2af24d393f4a176a234d5 @@ -4123,18 +3733,3 @@ index 12946bd55fcf7c40d39081779a7fa30049ee6165..9c2d605c50cbf9aefa56ec209df9f6ce + public void stopTiming() { /*handler.stopTiming();*/ } // Purpur } -diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java -index 88f1ca89fa640a686231b8eec87e70419b2d73ef..d6b91c49a267c89d7df2ddee7ccfe64675d117be 100644 ---- a/src/test/java/org/bukkit/AnnotationTest.java -+++ b/src/test/java/org/bukkit/AnnotationTest.java -@@ -47,6 +47,10 @@ public class AnnotationTest { - "org/bukkit/plugin/java/PluginClassLoader", - // Generic functional interface - "org/bukkit/util/Consumer", -+ // Purpur start -+ "gg/pufferfish/pufferfish/sentry/SentryContext", -+ "gg/pufferfish/pufferfish/sentry/SentryContext$State", -+ // Purpur end - // Paper start - "io/papermc/paper/util/TransformingRandomAccessList", - "io/papermc/paper/util/TransformingRandomAccessList$TransformedListIterator", diff --git a/patches/server/0001-Pufferfish-Server-Changes.patch b/patches/server/0001-Pufferfish-Server-Changes.patch deleted file mode 100644 index 48f3aa4..0000000 --- a/patches/server/0001-Pufferfish-Server-Changes.patch +++ /dev/null @@ -1,3393 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Kevin Raneri -Date: Fri, 26 Apr 2024 18:07:20 +0900 -Subject: [PATCH] Pufferfish Server Changes - -Pufferfish -Copyright (C) 2024 Pufferfish Studios LLC - -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/build.gradle.kts b/build.gradle.kts -index bcfe59b6efb628ee1e7f9d60667360d4d885fb6a..4517548e2c892c2e94f91e7449660f9e36b8f14e 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -13,8 +13,12 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) { - val alsoShade: Configuration by configurations.creating - - dependencies { -- implementation(project(":paper-api")) -- implementation(project(":paper-mojangapi")) -+ implementation(project(":pufferfish-api")) // Pufferfish // Paper -+ // Pufferfish start -+ implementation("io.papermc.paper:paper-mojangapi:1.19.2-R0.1-SNAPSHOT") { -+ exclude("io.papermc.paper", "paper-api") -+ } -+ // Pufferfish end - // Paper start - implementation("org.jline:jline-terminal-jansi:3.21.0") - implementation("net.minecrell:terminalconsoleappender:1.3.0") -@@ -50,6 +54,13 @@ dependencies { - runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") - runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") - -+ // Pufferfish start -+ implementation("org.yaml:snakeyaml:1.32") -+ implementation ("com.github.carleslc.Simple-YAML:Simple-Yaml:1.8.4") { -+ exclude(group="org.yaml", module="snakeyaml") -+ } -+ // Pufferfish end -+ - testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") - testImplementation("org.hamcrest:hamcrest:2.2") -@@ -59,6 +70,14 @@ dependencies { - } - - val craftbukkitPackageVersion = "1_20_R3" // Paper -+ -+// Pufferfish Start -+tasks.withType { -+ val compilerArgs = options.compilerArgs -+ compilerArgs.add("--add-modules=jdk.incubator.vector") -+} -+// Pufferfish End -+ - tasks.jar { - archiveClassifier.set("dev") - -@@ -71,7 +90,7 @@ tasks.jar { - attributes( - "Main-Class" to "org.bukkit.craftbukkit.Main", - "Implementation-Title" to "CraftBukkit", -- "Implementation-Version" to "git-Paper-$implementationVersion", -+ "Implementation-Version" to "git-Pufferfish-$implementationVersion", // Pufferfish - "Implementation-Vendor" to date, // Paper - "Specification-Title" to "Bukkit", - "Specification-Version" to project.version, -diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java -index 7620c72a4c243cbeea245203ce03a97cbfa7d922..b35a9f4c5f8960864c402ede8a51fb5ab9c4fcc0 100644 ---- a/src/main/java/co/aikar/timings/TimingsExport.java -+++ b/src/main/java/co/aikar/timings/TimingsExport.java -@@ -240,7 +240,8 @@ public class TimingsExport extends Thread { - parent.put("config", createObject( - pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), - pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), -- pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)) -+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Pufferfish -+ pair("pufferfish", mapAsJSON(gg.pufferfish.pufferfish.PufferfishConfig.getConfigCopy(), null)) // Pufferfish - )); - - new TimingsExport(listeners, parent, history).start(); -diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java -index 4b002e8b75d117b726b0de274a76d3596fce015b..692c962193cf9fcc6801fc93f3220bdc673d527b 100644 ---- a/src/main/java/com/destroystokyo/paper/Metrics.java -+++ b/src/main/java/com/destroystokyo/paper/Metrics.java -@@ -593,7 +593,7 @@ public class Metrics { - boolean logFailedRequests = config.getBoolean("logFailedRequests", false); - // Only start Metrics, if it's enabled in the config - if (config.getBoolean("enabled", true)) { -- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger()); -+ Metrics metrics = new Metrics("Pufferfish", serverUUID, logFailedRequests, Bukkit.getLogger()); // Pufferfish - - metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { - String minecraftVersion = Bukkit.getVersion(); -@@ -607,11 +607,11 @@ public class Metrics { - final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion(); - if (implVersion != null) { - final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1); -- paperVersion = "git-Paper-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); -+ paperVersion = "git-Pufferfish-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); // Pufferfish - } else { - paperVersion = "unknown"; - } -- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> paperVersion)); -+ metrics.addCustomChart(new Metrics.SimplePie("pufferfish_version", () -> paperVersion)); // Pufferfish - - metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { - Map> map = new HashMap<>(); -diff --git a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java -index 41b9405d6759d865e0d14dd4f95163e9690e967d..091b1ae822e1c0517e59572e7a9bda11e998c0ee 100644 ---- a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java -+++ b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java -@@ -26,7 +26,7 @@ public abstract class AreaMap { - - // we use linked for better iteration. - // map of: coordinate to set of objects in coordinate -- protected final Long2ObjectOpenHashMap> areaMap = new Long2ObjectOpenHashMap<>(1024, 0.7f); -+ protected Long2ObjectOpenHashMap> areaMap = new Long2ObjectOpenHashMap<>(1024, 0.7f); // Pufferfish - not actually final - protected final PooledLinkedHashSets pooledHashSets; - - protected final ChangeCallback addCallback; -@@ -160,7 +160,8 @@ public abstract class AreaMap { - protected abstract PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getEmptySetFor(final E object); - - // expensive op, only for debug -- protected void validate(final E object, final int viewDistance) { -+ protected void validate0(final E object, final int viewDistance) { // Pufferfish - rename this thing just in case it gets used I'd rather a compile time error. -+ if (true) throw new UnsupportedOperationException(); // Pufferfish - not going to put in the effort to fix this if it doesn't ever get used. - int entiesGot = 0; - int expectedEntries = (2 * viewDistance + 1); - expectedEntries *= expectedEntries; -diff --git a/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java -index 46954db7ecd35ac4018fdf476df7c8020d7ce6c8..1ad890a244bdf6df48a8db68cb43450e08c788a6 100644 ---- a/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java -+++ b/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java -@@ -5,7 +5,7 @@ import net.minecraft.server.level.ServerPlayer; - /** - * @author Spottedleaf - */ --public final class PlayerAreaMap extends AreaMap { -+public class PlayerAreaMap extends AreaMap { // Pufferfish - not actually final - - public PlayerAreaMap() { - super(); -diff --git a/src/main/java/gg/airplane/structs/FluidDirectionCache.java b/src/main/java/gg/airplane/structs/FluidDirectionCache.java -new file mode 100644 -index 0000000000000000000000000000000000000000..aa8467b9dda1f7707e41f50ac7b3e9d7343723ec ---- /dev/null -+++ b/src/main/java/gg/airplane/structs/FluidDirectionCache.java -@@ -0,0 +1,136 @@ -+package gg.airplane.structs; -+ -+import it.unimi.dsi.fastutil.HashCommon; -+ -+/** -+ * This is a replacement for the cache used in FluidTypeFlowing. -+ * The requirements for the previous cache were: -+ * - Store 200 entries -+ * - Look for the flag in the cache -+ * - If it exists, move to front of cache -+ * - If it doesn't exist, remove last entry in cache and insert in front -+ * -+ * This class accomplishes something similar, however has a few different -+ * requirements put into place to make this more optimize: -+ * -+ * - maxDistance is the most amount of entries to be checked, instead -+ * of having to check the entire list. -+ * - In combination with that, entries are all tracked by age and how -+ * frequently they're used. This enables us to remove old entries, -+ * without constantly shifting any around. -+ * -+ * Usage of the previous map would have to reset the head every single usage, -+ * shifting the entire map. Here, nothing happens except an increment when -+ * the cache is hit, and when it needs to replace an old element only a single -+ * element is modified. -+ */ -+public class FluidDirectionCache { -+ -+ private static class FluidDirectionEntry { -+ private final T data; -+ private final boolean flag; -+ private int uses = 0; -+ private int age = 0; -+ -+ private FluidDirectionEntry(T data, boolean flag) { -+ this.data = data; -+ this.flag = flag; -+ } -+ -+ public int getValue() { -+ return this.uses - (this.age >> 1); // age isn't as important as uses -+ } -+ -+ public void incrementUses() { -+ this.uses = this.uses + 1 & Integer.MAX_VALUE; -+ } -+ -+ public void incrementAge() { -+ this.age = this.age + 1 & Integer.MAX_VALUE; -+ } -+ } -+ -+ private final FluidDirectionEntry[] entries; -+ private final int mask; -+ private final int maxDistance; // the most amount of entries to check for a value -+ -+ public FluidDirectionCache(int size) { -+ int arraySize = HashCommon.nextPowerOfTwo(size); -+ this.entries = new FluidDirectionEntry[arraySize]; -+ this.mask = arraySize - 1; -+ this.maxDistance = Math.min(arraySize, 4); -+ } -+ -+ public Boolean getValue(T data) { -+ FluidDirectionEntry curr; -+ int pos; -+ -+ if ((curr = this.entries[pos = HashCommon.mix(data.hashCode()) & this.mask]) == null) { -+ return null; -+ } else if (data.equals(curr.data)) { -+ curr.incrementUses(); -+ return curr.flag; -+ } -+ -+ int checked = 1; // start at 1 because we already checked the first spot above -+ -+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) { -+ if (data.equals(curr.data)) { -+ curr.incrementUses(); -+ return curr.flag; -+ } else if (++checked >= this.maxDistance) { -+ break; -+ } -+ } -+ -+ return null; -+ } -+ -+ public void putValue(T data, boolean flag) { -+ FluidDirectionEntry curr; -+ int pos; -+ -+ if ((curr = this.entries[pos = HashCommon.mix(data.hashCode()) & this.mask]) == null) { -+ this.entries[pos] = new FluidDirectionEntry<>(data, flag); // add -+ return; -+ } else if (data.equals(curr.data)) { -+ curr.incrementUses(); -+ return; -+ } -+ -+ int checked = 1; // start at 1 because we already checked the first spot above -+ -+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) { -+ if (data.equals(curr.data)) { -+ curr.incrementUses(); -+ return; -+ } else if (++checked >= this.maxDistance) { -+ this.forceAdd(data, flag); -+ return; -+ } -+ } -+ -+ this.entries[pos] = new FluidDirectionEntry<>(data, flag); // add -+ } -+ -+ private void forceAdd(T data, boolean flag) { -+ int expectedPos = HashCommon.mix(data.hashCode()) & this.mask; -+ -+ int toRemovePos = expectedPos; -+ FluidDirectionEntry entryToRemove = this.entries[toRemovePos]; -+ -+ for (int i = expectedPos + 1; i < expectedPos + this.maxDistance; i++) { -+ int pos = i & this.mask; -+ FluidDirectionEntry entry = this.entries[pos]; -+ if (entry.getValue() < entryToRemove.getValue()) { -+ toRemovePos = pos; -+ entryToRemove = entry; -+ } -+ -+ entry.incrementAge(); // use this as a mechanism to age the other entries -+ } -+ -+ // remove the least used/oldest entry -+ this.entries[toRemovePos] = new FluidDirectionEntry(data, flag); -+ } -+} -diff --git a/src/main/java/gg/airplane/structs/ItemListWithBitset.java b/src/main/java/gg/airplane/structs/ItemListWithBitset.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1b7a4ee47f4445d7f2ac91d3a73ae113edbdddb2 ---- /dev/null -+++ b/src/main/java/gg/airplane/structs/ItemListWithBitset.java -@@ -0,0 +1,114 @@ -+package gg.airplane.structs; -+ -+import net.minecraft.core.NonNullList; -+import net.minecraft.world.item.ItemStack; -+import org.apache.commons.lang.Validate; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.AbstractList; -+import java.util.Arrays; -+import java.util.List; -+ -+public class ItemListWithBitset extends AbstractList { -+ public static ItemListWithBitset fromList(List list) { -+ if (list instanceof ItemListWithBitset ours) { -+ return ours; -+ } -+ return new ItemListWithBitset(list); -+ } -+ -+ private static ItemStack[] createArray(int size) { -+ ItemStack[] array = new ItemStack[size]; -+ Arrays.fill(array, ItemStack.EMPTY); -+ return array; -+ } -+ -+ private final ItemStack[] items; -+ -+ private long bitSet = 0; -+ private final long allBits; -+ -+ private static class OurNonNullList extends NonNullList { -+ protected OurNonNullList(List delegate) { -+ super(delegate, ItemStack.EMPTY); -+ } -+ } -+ -+ public final NonNullList nonNullList = new OurNonNullList(this); -+ -+ private ItemListWithBitset(List list) { -+ this(list.size()); -+ -+ for (int i = 0; i < list.size(); i++) { -+ this.set(i, list.get(i)); -+ } -+ } -+ -+ public ItemListWithBitset(int size) { -+ Validate.isTrue(size < Long.BYTES * 8, "size is too large"); -+ -+ this.items = createArray(size); -+ this.allBits = ((1L << size) - 1); -+ } -+ -+ public boolean isCompletelyEmpty() { -+ return this.bitSet == 0; -+ } -+ -+ public boolean hasFullStacks() { -+ return (this.bitSet & this.allBits) == allBits; -+ } -+ -+ @Override -+ public ItemStack set(int index, @NotNull ItemStack itemStack) { -+ ItemStack existing = this.items[index]; -+ -+ this.items[index] = itemStack; -+ -+ if (itemStack == ItemStack.EMPTY) { -+ this.bitSet &= ~(1L << index); -+ } else { -+ this.bitSet |= 1L << index; -+ } -+ -+ return existing; -+ } -+ -+ @NotNull -+ @Override -+ public ItemStack get(int var0) { -+ return this.items[var0]; -+ } -+ -+ @Override -+ public int size() { -+ return this.items.length; -+ } -+ -+ @Override -+ public void clear() { -+ Arrays.fill(this.items, ItemStack.EMPTY); -+ } -+ -+ // these are unsupported for block inventories which have a static size -+ @Override -+ public void add(int var0, ItemStack var1) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public ItemStack remove(int var0) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public String toString() { -+ return "ItemListWithBitset{" + -+ "items=" + Arrays.toString(items) + -+ ", bitSet=" + Long.toString(bitSet, 2) + -+ ", allBits=" + Long.toString(allBits, 2) + -+ ", size=" + this.items.length + -+ '}'; -+ } -+} -diff --git a/src/main/java/gg/airplane/structs/Long2FloatAgingCache.java b/src/main/java/gg/airplane/structs/Long2FloatAgingCache.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a7f297ebb569f7c1f205e967ca485be70013a714 ---- /dev/null -+++ b/src/main/java/gg/airplane/structs/Long2FloatAgingCache.java -@@ -0,0 +1,119 @@ -+package gg.airplane.structs; -+ -+import it.unimi.dsi.fastutil.HashCommon; -+ -+/** -+ * A replacement for the cache used in Biome. -+ */ -+public class Long2FloatAgingCache { -+ -+ private static class AgingEntry { -+ private long data; -+ private float value; -+ private int uses = 0; -+ private int age = 0; -+ -+ private AgingEntry(long data, float value) { -+ this.data = data; -+ this.value = value; -+ } -+ -+ public void replace(long data, float flag) { -+ this.data = data; -+ this.value = flag; -+ } -+ -+ public int getValue() { -+ return this.uses - (this.age >> 1); // age isn't as important as uses -+ } -+ -+ public void incrementUses() { -+ this.uses = this.uses + 1 & Integer.MAX_VALUE; -+ } -+ -+ public void incrementAge() { -+ this.age = this.age + 1 & Integer.MAX_VALUE; -+ } -+ } -+ -+ private final AgingEntry[] entries; -+ private final int mask; -+ private final int maxDistance; // the most amount of entries to check for a value -+ -+ public Long2FloatAgingCache(int size) { -+ int arraySize = HashCommon.nextPowerOfTwo(size); -+ this.entries = new AgingEntry[arraySize]; -+ this.mask = arraySize - 1; -+ this.maxDistance = Math.min(arraySize, 4); -+ } -+ -+ public float getValue(long data) { -+ AgingEntry curr; -+ int pos; -+ -+ if ((curr = this.entries[pos = HashCommon.mix(HashCommon.long2int(data)) & this.mask]) == null) { -+ return Float.NaN; -+ } else if (data == curr.data) { -+ curr.incrementUses(); -+ return curr.value; -+ } -+ -+ int checked = 1; // start at 1 because we already checked the first spot above -+ -+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) { -+ if (data == curr.data) { -+ curr.incrementUses(); -+ return curr.value; -+ } else if (++checked >= this.maxDistance) { -+ break; -+ } -+ } -+ -+ return Float.NaN; -+ } -+ -+ public void putValue(long data, float value) { -+ AgingEntry curr; -+ int pos; -+ -+ if ((curr = this.entries[pos = HashCommon.mix(HashCommon.long2int(data)) & this.mask]) == null) { -+ this.entries[pos] = new AgingEntry(data, value); // add -+ return; -+ } else if (data == curr.data) { -+ curr.incrementUses(); -+ return; -+ } -+ -+ int checked = 1; // start at 1 because we already checked the first spot above -+ -+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) { -+ if (data == curr.data) { -+ curr.incrementUses(); -+ return; -+ } else if (++checked >= this.maxDistance) { -+ this.forceAdd(data, value); -+ return; -+ } -+ } -+ -+ this.entries[pos] = new AgingEntry(data, value); // add -+ } -+ -+ private void forceAdd(long data, float value) { -+ int expectedPos = HashCommon.mix(HashCommon.long2int(data)) & this.mask; -+ AgingEntry entryToRemove = this.entries[expectedPos]; -+ -+ for (int i = expectedPos + 1; i < expectedPos + this.maxDistance; i++) { -+ int pos = i & this.mask; -+ AgingEntry entry = this.entries[pos]; -+ if (entry.getValue() < entryToRemove.getValue()) { -+ entryToRemove = entry; -+ } -+ -+ entry.incrementAge(); // use this as a mechanism to age the other entries -+ } -+ -+ // remove the least used/oldest entry -+ entryToRemove.replace(data, value); -+ } -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishCommand.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..020368da69b9a492155f6de6297f74732f4ab6ea ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishCommand.java -@@ -0,0 +1,68 @@ -+package gg.pufferfish.pufferfish; -+ -+import java.io.IOException; -+import java.util.Collections; -+import java.util.List; -+import java.util.stream.Collectors; -+import java.util.stream.Stream; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.md_5.bungee.api.ChatColor; -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.Bukkit; -+import org.bukkit.Location; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+ -+public class PufferfishCommand extends Command { -+ -+ public PufferfishCommand() { -+ super("pufferfish"); -+ this.description = "Pufferfish related commands"; -+ this.usageMessage = "/pufferfish [reload | version]"; -+ this.setPermission("bukkit.command.pufferfish"); -+ } -+ -+ public static void init() { -+ MinecraftServer.getServer().server.getCommandMap().register("pufferfish", "Pufferfish", new PufferfishCommand()); -+ } -+ -+ @Override -+ public List tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException { -+ if (args.length == 1) { -+ return Stream.of("reload", "version") -+ .filter(arg -> arg.startsWith(args[0].toLowerCase())) -+ .collect(Collectors.toList()); -+ } -+ return Collections.emptyList(); -+ } -+ -+ @Override -+ public boolean execute(CommandSender sender, String commandLabel, String[] args) { -+ if (!testPermission(sender)) return true; -+ String prefix = ChatColor.of("#12fff6") + "" + ChatColor.BOLD + "Pufferfish » " + ChatColor.of("#e8f9f9"); -+ -+ if (args.length != 1) { -+ sender.sendMessage(prefix + "Usage: " + usageMessage); -+ args = new String[]{"version"}; -+ } -+ -+ if (args[0].equalsIgnoreCase("reload")) { -+ MinecraftServer console = MinecraftServer.getServer(); -+ try { -+ PufferfishConfig.load(); -+ } catch (IOException e) { -+ sender.sendMessage(Component.text("Failed to reload.", NamedTextColor.RED)); -+ e.printStackTrace(); -+ return true; -+ } -+ console.server.reloadCount++; -+ -+ Command.broadcastCommandMessage(sender, prefix + "Pufferfish configuration has been reloaded."); -+ } else if (args[0].equalsIgnoreCase("version")) { -+ Command.broadcastCommandMessage(sender, prefix + "This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")"); -+ } -+ -+ return true; -+ } -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6464682e2f93659e73aca491031c8051ab000033 ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -@@ -0,0 +1,302 @@ -+package gg.pufferfish.pufferfish; -+ -+import gg.pufferfish.pufferfish.simd.SIMDDetection; -+import java.io.File; -+import java.io.IOException; -+import java.util.Collections; -+import net.minecraft.core.registries.BuiltInRegistries; -+import java.util.Locale; -+import java.util.Map; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.tags.TagKey; -+import org.apache.logging.log4j.Level; -+import org.bukkit.configuration.ConfigurationSection; -+import net.minecraft.world.entity.EntityType; -+import java.lang.reflect.Method; -+import java.lang.reflect.Modifier; -+import java.util.List; -+import net.minecraft.server.MinecraftServer; -+import org.apache.logging.log4j.Level; -+import org.bukkit.configuration.ConfigurationSection; -+import org.bukkit.configuration.MemoryConfiguration; -+import org.jetbrains.annotations.Nullable; -+import org.simpleyaml.configuration.comments.CommentType; -+import org.simpleyaml.configuration.file.YamlFile; -+import org.simpleyaml.exceptions.InvalidConfigurationException; -+ -+public class PufferfishConfig { -+ -+ private static final YamlFile config = new YamlFile(); -+ private static int updates = 0; -+ -+ private static ConfigurationSection convertToBukkit(org.simpleyaml.configuration.ConfigurationSection section) { -+ ConfigurationSection newSection = new MemoryConfiguration(); -+ for (String key : section.getKeys(false)) { -+ if (section.isConfigurationSection(key)) { -+ newSection.set(key, convertToBukkit(section.getConfigurationSection(key))); -+ } else { -+ newSection.set(key, section.get(key)); -+ } -+ } -+ return newSection; -+ } -+ -+ public static ConfigurationSection getConfigCopy() { -+ return convertToBukkit(config); -+ } -+ -+ public static int getUpdates() { -+ return updates; -+ } -+ -+ public static void load() throws IOException { -+ File configFile = new File("pufferfish.yml"); -+ -+ if (configFile.exists()) { -+ try { -+ config.load(configFile); -+ } catch (InvalidConfigurationException e) { -+ throw new IOException(e); -+ } -+ } -+ -+ getString("info.version", "1.0"); -+ setComment("info", -+ "Pufferfish Configuration", -+ "Check out Pufferfish Host for maximum performance server hosting: https://pufferfish.host", -+ "Join our Discord for support: https://discord.gg/reZw4vQV9H", -+ "Download new builds at https://ci.pufferfish.host/job/Pufferfish"); -+ -+ for (Method method : PufferfishConfig.class.getDeclaredMethods()) { -+ if (Modifier.isStatic(method.getModifiers()) && Modifier.isPrivate(method.getModifiers()) && method.getParameterCount() == 0 && -+ method.getReturnType() == Void.TYPE && !method.getName().startsWith("lambda")) { -+ method.setAccessible(true); -+ try { -+ method.invoke(null); -+ } catch (Throwable t) { -+ MinecraftServer.LOGGER.warn("Failed to load configuration option from " + method.getName(), t); -+ } -+ } -+ } -+ -+ updates++; -+ -+ config.save(configFile); -+ -+ // Attempt to detect vectorization -+ try { -+ SIMDDetection.isEnabled = SIMDDetection.canEnable(PufferfishLogger.LOGGER); -+ SIMDDetection.versionLimited = SIMDDetection.getJavaVersion() != 17 && SIMDDetection.getJavaVersion() != 18 && SIMDDetection.getJavaVersion() != 19; -+ } catch (NoClassDefFoundError | Exception ignored) { -+ ignored.printStackTrace(); -+ } -+ -+ if (SIMDDetection.isEnabled) { -+ PufferfishLogger.LOGGER.info("SIMD operations detected as functional. Will replace some operations with faster versions."); -+ } else if (SIMDDetection.versionLimited) { -+ PufferfishLogger.LOGGER.warning("Will not enable SIMD! These optimizations are only safely supported on Java 17, Java 18, and Java 19."); -+ } else { -+ PufferfishLogger.LOGGER.warning("SIMD operations are available for your server, but are not configured!"); -+ PufferfishLogger.LOGGER.warning("To enable additional optimizations, add \"--add-modules=jdk.incubator.vector\" to your startup flags, BEFORE the \"-jar\"."); -+ PufferfishLogger.LOGGER.warning("If you have already added this flag, then SIMD operations are not supported on your JVM or CPU."); -+ PufferfishLogger.LOGGER.warning("Debug: Java: " + System.getProperty("java.version") + ", test run: " + SIMDDetection.testRun); -+ } -+ } -+ -+ private static void setComment(String key, String... comment) { -+ if (config.contains(key)) { -+ config.setComment(key, String.join("\n", comment), CommentType.BLOCK); -+ } -+ } -+ -+ private static void ensureDefault(String key, Object defaultValue, String... comment) { -+ if (!config.contains(key)) { -+ config.set(key, defaultValue); -+ config.setComment(key, String.join("\n", comment), CommentType.BLOCK); -+ } -+ } -+ -+ private static boolean getBoolean(String key, boolean defaultValue, String... comment) { -+ return getBoolean(key, null, defaultValue, comment); -+ } -+ -+ private static boolean getBoolean(String key, @Nullable String oldKey, boolean defaultValue, String... comment) { -+ ensureDefault(key, defaultValue, comment); -+ return config.getBoolean(key, defaultValue); -+ } -+ -+ private static int getInt(String key, int defaultValue, String... comment) { -+ return getInt(key, null, defaultValue, comment); -+ } -+ -+ private static int getInt(String key, @Nullable String oldKey, int defaultValue, String... comment) { -+ ensureDefault(key, defaultValue, comment); -+ return config.getInt(key, defaultValue); -+ } -+ -+ private static double getDouble(String key, double defaultValue, String... comment) { -+ return getDouble(key, null, defaultValue, comment); -+ } -+ -+ private static double getDouble(String key, @Nullable String oldKey, double defaultValue, String... comment) { -+ ensureDefault(key, defaultValue, comment); -+ return config.getDouble(key, defaultValue); -+ } -+ -+ private static String getString(String key, String defaultValue, String... comment) { -+ return getOldString(key, null, defaultValue, comment); -+ } -+ -+ private static String getOldString(String key, @Nullable String oldKey, String defaultValue, String... comment) { -+ ensureDefault(key, defaultValue, comment); -+ return config.getString(key, defaultValue); -+ } -+ -+ private static List getStringList(String key, List defaultValue, String... comment) { -+ return getStringList(key, null, defaultValue, comment); -+ } -+ -+ private static List getStringList(String key, @Nullable String oldKey, List defaultValue, String... comment) { -+ ensureDefault(key, defaultValue, comment); -+ return config.getStringList(key); -+ } -+ -+ public static String sentryDsn; -+ private static void sentry() { -+ String sentryEnvironment = System.getenv("SENTRY_DSN"); -+ String sentryConfig = getString("sentry-dsn", "", "Sentry DSN for improved error logging, leave blank to disable", "Obtain from https://sentry.io/"); -+ -+ sentryDsn = sentryEnvironment == null ? sentryConfig : sentryEnvironment; -+ if (sentryDsn != null && !sentryDsn.isBlank()) { -+ gg.pufferfish.pufferfish.sentry.SentryManager.init(); -+ } -+ } -+ -+ public static boolean enableBooks; -+ private static void books() { -+ enableBooks = getBoolean("enable-books", true, -+ "Whether or not books should be writeable.", -+ "Servers that anticipate being a target for duping may want to consider", -+ "disabling this option.", -+ "This can be overridden per-player with the permission pufferfish.usebooks"); -+ } -+ -+ public static boolean tpsCatchup; -+ private static void tpsCatchup() { -+ tpsCatchup = getBoolean("tps-catchup", true, -+ "If this setting is true, the server will run faster after a lag spike in", -+ "an attempt to maintain 20 TPS. This option (defaults to true per", -+ "spigot/paper) can cause mobs to move fast after a lag spike."); -+ } -+ -+ public static boolean enableSuffocationOptimization; -+ private static void suffocationOptimization() { -+ enableSuffocationOptimization = getBoolean("enable-suffocation-optimization", true, -+ "Optimizes the suffocation check by selectively skipping", -+ "the check in a way that still appears vanilla. This should", -+ "be left enabled on most servers, but is provided as a", -+ "configuration option if the vanilla deviation is undesirable."); -+ } -+ -+ public static boolean enableAsyncMobSpawning; -+ public static boolean asyncMobSpawningInitialized; -+ private static void asyncMobSpawning() { -+ boolean temp = getBoolean("enable-async-mob-spawning", true, -+ "Whether or not asynchronous mob spawning should be enabled.", -+ "On servers with many entities, this can improve performance by up to 15%. You must have", -+ "paper's per-player-mob-spawns setting set to true for this to work.", -+ "One quick note - this does not actually spawn mobs async (that would be very unsafe).", -+ "This just offloads some expensive calculations that are required for mob spawning."); -+ -+ // This prevents us from changing the value during a reload. -+ if (!asyncMobSpawningInitialized) { -+ asyncMobSpawningInitialized = true; -+ enableAsyncMobSpawning = temp; -+ } -+ } -+ -+ public static int maxProjectileLoadsPerTick; -+ public static int maxProjectileLoadsPerProjectile; -+ private static void projectileLoading() { -+ maxProjectileLoadsPerTick = getInt("projectile.max-loads-per-tick", 10, "Controls how many chunks are allowed", "to be sync loaded by projectiles in a tick."); -+ maxProjectileLoadsPerProjectile = getInt("projectile.max-loads-per-projectile", 10, "Controls how many chunks a projectile", "can load in its lifetime before it gets", "automatically removed."); -+ -+ setComment("projectile", "Optimizes projectile settings"); -+ } -+ -+ -+ public static boolean dearEnabled; -+ public static int startDistance; -+ public static int startDistanceSquared; -+ public static int maximumActivationPrio; -+ public static int activationDistanceMod; -+ -+ private static void dynamicActivationOfBrains() throws IOException { -+ dearEnabled = getBoolean("dab.enabled", "activation-range.enabled", true); -+ startDistance = getInt("dab.start-distance", "activation-range.start-distance", 12, -+ "This value determines how far away an entity has to be", -+ "from the player to start being effected by DEAR."); -+ startDistanceSquared = startDistance * startDistance; -+ maximumActivationPrio = getInt("dab.max-tick-freq", "activation-range.max-tick-freq", 20, -+ "This value defines how often in ticks, the furthest entity", -+ "will get their pathfinders and behaviors ticked. 20 = 1s"); -+ activationDistanceMod = getInt("dab.activation-dist-mod", "activation-range.activation-dist-mod", 8, -+ "This value defines how much distance modifies an entity's", -+ "tick frequency. freq = (distanceToPlayer^2) / (2^value)", -+ "If you want further away entities to tick less often, use 7.", -+ "If you want further away entities to tick more often, try 9."); -+ -+ for (EntityType entityType : BuiltInRegistries.ENTITY_TYPE) { -+ entityType.dabEnabled = true; // reset all, before setting the ones to true -+ } -+ getStringList("dab.blacklisted-entities", "activation-range.blacklisted-entities", Collections.emptyList(), "A list of entities to ignore for activation") -+ .forEach(name -> EntityType.byString(name).ifPresentOrElse(entityType -> { -+ entityType.dabEnabled = false; -+ }, () -> MinecraftServer.LOGGER.warn("Unknown entity \"" + name + "\""))); -+ -+ setComment("dab", "Optimizes entity brains when", "they're far away from the player"); -+ } -+ -+ public static Map projectileTimeouts; -+ private static void projectileTimeouts() { -+ // Set some defaults -+ getInt("entity_timeouts.SNOWBALL", -1); -+ getInt("entity_timeouts.LLAMA_SPIT", -1); -+ setComment("entity_timeouts", -+ "These values define a entity's maximum lifespan. If an", -+ "entity is in this list and it has survived for longer than", -+ "that number of ticks, then it will be removed. Setting a value to", -+ "-1 disables this feature."); -+ -+ for (EntityType entityType : BuiltInRegistries.ENTITY_TYPE) { -+ String type = EntityType.getKey(entityType).getPath().toUpperCase(Locale.ROOT); -+ entityType.ttl = config.getInt("entity_timeouts." + type, -1); -+ } -+ } -+ -+ public static boolean throttleInactiveGoalSelectorTick; -+ private static void inactiveGoalSelectorThrottle() { -+ throttleInactiveGoalSelectorTick = getBoolean("inactive-goal-selector-throttle", "inactive-goal-selector-disable", true, -+ "Throttles the AI goal selector in entity inactive ticks.", -+ "This can improve performance by a few percent, but has minor gameplay implications."); -+ } -+ -+ public static boolean allowEndCrystalRespawn; -+ private static void allowEndCrystalRespawn() { -+ allowEndCrystalRespawn = getBoolean("allow-end-crystal-respawn", true, -+ "Allows end crystals to respawn the ender dragon.", -+ "On servers that expect end crystal fights in the end dimension, disabling this", -+ "will prevent the server from performing an expensive search to attempt respawning", -+ "the ender dragon whenever a player places an end crystal."); -+ } -+ -+ -+ public static boolean disableMethodProfiler; -+ public static boolean disableOutOfOrderChat; -+ private static void miscSettings() { -+ disableMethodProfiler = getBoolean("misc.disable-method-profiler", true); -+ disableOutOfOrderChat = getBoolean("misc.disable-out-of-order-chat", false); -+ setComment("misc", "Settings for things that don't belong elsewhere"); -+ } -+ -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishLogger.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishLogger.java -new file mode 100644 -index 0000000000000000000000000000000000000000..53f2df00c6809618a9ee3d2ea72e85e8052fbcf1 ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishLogger.java -@@ -0,0 +1,16 @@ -+package gg.pufferfish.pufferfish; -+ -+import java.util.logging.Level; -+import java.util.logging.Logger; -+import org.bukkit.Bukkit; -+ -+public class PufferfishLogger extends Logger { -+ public static final PufferfishLogger LOGGER = new PufferfishLogger(); -+ -+ private PufferfishLogger() { -+ super("Pufferfish", null); -+ -+ setParent(Bukkit.getLogger()); -+ setLevel(Level.ALL); -+ } -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishVersionFetcher.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishVersionFetcher.java -new file mode 100644 -index 0000000000000000000000000000000000000000..893d8c0946ef71a0561221dd76bffff0dc940d56 ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishVersionFetcher.java -@@ -0,0 +1,136 @@ -+package gg.pufferfish.pufferfish; -+ -+import static net.kyori.adventure.text.Component.text; -+import static net.kyori.adventure.text.format.NamedTextColor.GREEN; -+import static net.kyori.adventure.text.format.NamedTextColor.RED; -+ -+import com.destroystokyo.paper.VersionHistoryManager; -+import com.destroystokyo.paper.util.VersionFetcher; -+import com.google.gson.Gson; -+import com.google.gson.JsonObject; -+import java.io.IOException; -+import java.net.URI; -+import java.net.http.HttpClient; -+import java.net.http.HttpRequest; -+import java.net.http.HttpResponse; -+import java.nio.charset.StandardCharsets; -+import java.util.concurrent.TimeUnit; -+import java.util.logging.Level; -+import java.util.logging.Logger; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.JoinConfiguration; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.format.TextDecoration; -+import org.bukkit.craftbukkit.CraftServer; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class PufferfishVersionFetcher implements VersionFetcher { -+ -+ private static final Logger LOGGER = Logger.getLogger("PufferfishVersionFetcher"); -+ private static final HttpClient client = HttpClient.newHttpClient(); -+ -+ private static final URI JENKINS_URI = URI.create("https://ci.pufferfish.host/job/Pufferfish-1.20/lastSuccessfulBuild/buildNumber"); -+ private static final String GITHUB_FORMAT = "https://api.github.com/repos/pufferfish-gg/Pufferfish/compare/ver/1.20...%s"; -+ -+ private static final HttpResponse.BodyHandler JSON_OBJECT_BODY_HANDLER = responseInfo -> HttpResponse.BodySubscribers -+ .mapping( -+ HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8), -+ string -> new Gson().fromJson(string, JsonObject.class) -+ ); -+ -+ @Override -+ public long getCacheTime() { -+ return TimeUnit.MINUTES.toMillis(30); -+ } -+ -+ @Override -+ public @NotNull Component getVersionMessage(final @NotNull String serverVersion) { -+ final String[] parts = CraftServer.class.getPackage().getImplementationVersion().split("-"); -+ @NotNull Component component; -+ -+ if (parts.length != 3) { -+ component = text("Unknown server version.", RED); -+ } else { -+ final String versionString = parts[2]; -+ -+ try { -+ component = this.fetchJenkinsVersion(Integer.parseInt(versionString)); -+ } catch (NumberFormatException e) { -+ component = this.fetchGithubVersion(versionString.substring(1, versionString.length() - 1)); -+ } -+ } -+ -+ final @Nullable Component history = this.getHistory(); -+ return history != null ? Component -+ .join(JoinConfiguration.noSeparators(), component, Component.newline(), this.getHistory()) : component; -+ } -+ -+ private @NotNull Component fetchJenkinsVersion(final int versionNumber) { -+ final HttpRequest request = HttpRequest.newBuilder(JENKINS_URI).build(); -+ try { -+ final HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); -+ if (response.statusCode() != 200) { -+ return text("Received invalid status code (" + response.statusCode() + ") from server.", RED); -+ } -+ -+ int latestVersionNumber; -+ try { -+ latestVersionNumber = Integer.parseInt(response.body()); -+ } catch (NumberFormatException e) { -+ LOGGER.log(Level.WARNING, "Received invalid response from Jenkins \"" + response.body() + "\"."); -+ return text("Received invalid response from server.", RED); -+ } -+ -+ final int versionDiff = latestVersionNumber - versionNumber; -+ return this.getResponseMessage(versionDiff); -+ } catch (IOException | InterruptedException e) { -+ LOGGER.log(Level.WARNING, "Failed to look up version from Jenkins", e); -+ return text("Failed to retrieve version from server.", RED); -+ } -+ } -+ -+ // Based off code contributed by Techcable in Paper/GH-65 -+ private @NotNull Component fetchGithubVersion(final @NotNull String hash) { -+ final URI uri = URI.create(String.format(GITHUB_FORMAT, hash)); -+ final HttpRequest request = HttpRequest.newBuilder(uri).build(); -+ try { -+ final HttpResponse response = client.send(request, JSON_OBJECT_BODY_HANDLER); -+ if (response.statusCode() != 200) { -+ return text("Received invalid status code (" + response.statusCode() + ") from server.", RED); -+ } -+ -+ final JsonObject obj = response.body(); -+ final int versionDiff = obj.get("behind_by").getAsInt(); -+ -+ return this.getResponseMessage(versionDiff); -+ } catch (IOException | InterruptedException e) { -+ LOGGER.log(Level.WARNING, "Failed to look up version from GitHub", e); -+ return text("Failed to retrieve version from server.", RED); -+ } -+ } -+ -+ private @NotNull Component getResponseMessage(final int versionDiff) { -+ return switch (Math.max(-1, Math.min(1, versionDiff))) { -+ case -1 -> text("You are running an unsupported version of Pufferfish.", RED); -+ case 0 -> text("You are on the latest version!", GREEN); -+ default -> text("You are running " + versionDiff + " version" + (versionDiff == 1 ? "" : "s") + " beyond. " + -+ "Please update your server when possible to maintain stability, security, and receive the latest optimizations.", -+ RED); -+ }; -+ } -+ -+ private @Nullable Component getHistory() { -+ final VersionHistoryManager.VersionData data = VersionHistoryManager.INSTANCE.getVersionData(); -+ if (data == null) { -+ return null; -+ } -+ -+ final String oldVersion = data.getOldVersion(); -+ if (oldVersion == null) { -+ return null; -+ } -+ -+ return Component.text("Previous version: " + oldVersion, NamedTextColor.GRAY, TextDecoration.ITALIC); -+ } -+} -\ No newline at end of file -diff --git a/src/main/java/gg/pufferfish/pufferfish/sentry/PufferfishSentryAppender.java b/src/main/java/gg/pufferfish/pufferfish/sentry/PufferfishSentryAppender.java -new file mode 100644 -index 0000000000000000000000000000000000000000..731ef11c7a025ae95ed8a757b530d834733d0621 ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/sentry/PufferfishSentryAppender.java -@@ -0,0 +1,135 @@ -+package gg.pufferfish.pufferfish.sentry; -+ -+import com.google.common.reflect.TypeToken; -+import com.google.gson.Gson; -+import io.sentry.Breadcrumb; -+import io.sentry.Sentry; -+import io.sentry.SentryEvent; -+import io.sentry.SentryLevel; -+import io.sentry.protocol.Message; -+import io.sentry.protocol.User; -+import java.util.Map; -+import org.apache.logging.log4j.Level; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Marker; -+import org.apache.logging.log4j.core.LogEvent; -+import org.apache.logging.log4j.core.Logger; -+import org.apache.logging.log4j.core.appender.AbstractAppender; -+import org.apache.logging.log4j.core.filter.AbstractFilter; -+ -+public class PufferfishSentryAppender extends AbstractAppender { -+ -+ private static final org.apache.logging.log4j.Logger logger = LogManager.getLogger(PufferfishSentryAppender.class); -+ private static final Gson GSON = new Gson(); -+ -+ public PufferfishSentryAppender() { -+ super("PufferfishSentryAdapter", new SentryFilter(), null); -+ } -+ -+ @Override -+ public void append(LogEvent logEvent) { -+ if (logEvent.getThrown() != null && logEvent.getLevel().isMoreSpecificThan(Level.WARN)) { -+ try { -+ logException(logEvent); -+ } catch (Exception e) { -+ logger.warn("Failed to log event with sentry", e); -+ } -+ } else { -+ try { -+ logBreadcrumb(logEvent); -+ } catch (Exception e) { -+ logger.warn("Failed to log event with sentry", e); -+ } -+ } -+ } -+ -+ private void logException(LogEvent e) { -+ SentryEvent event = new SentryEvent(e.getThrown()); -+ -+ Message sentryMessage = new Message(); -+ sentryMessage.setMessage(e.getMessage().getFormattedMessage()); -+ -+ event.setThrowable(e.getThrown()); -+ event.setLevel(getLevel(e.getLevel())); -+ event.setLogger(e.getLoggerName()); -+ event.setTransaction(e.getLoggerName()); -+ event.setExtra("thread_name", e.getThreadName()); -+ -+ boolean hasContext = e.getContextData() != null; -+ -+ if (hasContext && e.getContextData().containsKey("pufferfishsentry_playerid")) { -+ User user = new User(); -+ user.setId(e.getContextData().getValue("pufferfishsentry_playerid")); -+ user.setUsername(e.getContextData().getValue("pufferfishsentry_playername")); -+ event.setUser(user); -+ } -+ -+ if (hasContext && e.getContextData().containsKey("pufferfishsentry_pluginname")) { -+ event.setExtra("plugin.name", e.getContextData().getValue("pufferfishsentry_pluginname")); -+ event.setExtra("plugin.version", e.getContextData().getValue("pufferfishsentry_pluginversion")); -+ event.setTransaction(e.getContextData().getValue("pufferfishsentry_pluginname")); -+ } -+ -+ if (hasContext && e.getContextData().containsKey("pufferfishsentry_eventdata")) { -+ Map eventFields = GSON.fromJson((String) e.getContextData().getValue("pufferfishsentry_eventdata"), new TypeToken>() {}.getType()); -+ if (eventFields != null) { -+ event.setExtra("event", eventFields); -+ } -+ } -+ -+ Sentry.captureEvent(event); -+ } -+ -+ private void logBreadcrumb(LogEvent e) { -+ Breadcrumb breadcrumb = new Breadcrumb(); -+ -+ breadcrumb.setLevel(getLevel(e.getLevel())); -+ breadcrumb.setCategory(e.getLoggerName()); -+ breadcrumb.setType(e.getLoggerName()); -+ breadcrumb.setMessage(e.getMessage().getFormattedMessage()); -+ -+ Sentry.addBreadcrumb(breadcrumb); -+ } -+ -+ private SentryLevel getLevel(Level level) { -+ switch (level.getStandardLevel()) { -+ case TRACE: -+ case DEBUG: -+ return SentryLevel.DEBUG; -+ case WARN: -+ return SentryLevel.WARNING; -+ case ERROR: -+ return SentryLevel.ERROR; -+ case FATAL: -+ return SentryLevel.FATAL; -+ case INFO: -+ default: -+ return SentryLevel.INFO; -+ } -+ } -+ -+ private static class SentryFilter extends AbstractFilter { -+ -+ @Override -+ public Result filter(Logger logger, org.apache.logging.log4j.Level level, Marker marker, String msg, -+ Object... params) { -+ return this.filter(logger.getName()); -+ } -+ -+ @Override -+ public Result filter(Logger logger, org.apache.logging.log4j.Level level, Marker marker, Object msg, Throwable t) { -+ return this.filter(logger.getName()); -+ } -+ -+ @Override -+ public Result filter(LogEvent event) { -+ return this.filter(event == null ? null : event.getLoggerName()); -+ } -+ -+ private Result filter(String loggerName) { -+ return loggerName != null && loggerName.startsWith("gg.castaway.pufferfish.sentry") ? Result.DENY -+ : Result.NEUTRAL; -+ } -+ -+ } -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/sentry/SentryManager.java b/src/main/java/gg/pufferfish/pufferfish/sentry/SentryManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1b29210ad0bbb4ada150f23357f0c80d331c996d ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/sentry/SentryManager.java -@@ -0,0 +1,40 @@ -+package gg.pufferfish.pufferfish.sentry; -+ -+import gg.pufferfish.pufferfish.PufferfishConfig; -+import io.sentry.Sentry; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+ -+public class SentryManager { -+ -+ private static final Logger logger = LogManager.getLogger(SentryManager.class); -+ -+ private SentryManager() { -+ -+ } -+ -+ private static boolean initialized = false; -+ -+ public static synchronized void init() { -+ if (initialized) { -+ return; -+ } -+ try { -+ initialized = true; -+ -+ Sentry.init(options -> { -+ options.setDsn(PufferfishConfig.sentryDsn); -+ options.setMaxBreadcrumbs(100); -+ }); -+ -+ PufferfishSentryAppender appender = new PufferfishSentryAppender(); -+ appender.start(); -+ ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).addAppender(appender); -+ logger.info("Sentry logging started!"); -+ } catch (Exception e) { -+ logger.warn("Failed to initialize sentry!", e); -+ initialized = false; -+ } -+ } -+ -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java b/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8e5323d5d9af25c8a85c4b34a6be76cfc54384cf ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java -@@ -0,0 +1,73 @@ -+package gg.pufferfish.pufferfish.util; -+ -+import com.google.common.collect.Queues; -+import gg.pufferfish.pufferfish.PufferfishLogger; -+import java.util.Queue; -+import java.util.concurrent.locks.Condition; -+import java.util.concurrent.locks.Lock; -+import java.util.concurrent.locks.ReentrantLock; -+import java.util.logging.Level; -+ -+public class AsyncExecutor implements Runnable { -+ -+ private final Queue jobs = Queues.newArrayDeque(); -+ private final Lock mutex = new ReentrantLock(); -+ private final Condition cond = mutex.newCondition(); -+ private final Thread thread; -+ private volatile boolean killswitch = false; -+ -+ public AsyncExecutor(String threadName) { -+ this.thread = new Thread(this, threadName); -+ } -+ -+ public void start() { -+ thread.start(); -+ } -+ -+ public void kill() { -+ killswitch = true; -+ cond.signalAll(); -+ } -+ -+ public void submit(Runnable runnable) { -+ mutex.lock(); -+ try { -+ jobs.offer(runnable); -+ cond.signalAll(); -+ } finally { -+ mutex.unlock(); -+ } -+ } -+ -+ @Override -+ public void run() { -+ while (!killswitch) { -+ try { -+ Runnable runnable = takeRunnable(); -+ if (runnable != null) { -+ runnable.run(); -+ } -+ } catch (InterruptedException e) { -+ Thread.currentThread().interrupt(); -+ } catch (Exception e) { -+ PufferfishLogger.LOGGER.log(Level.SEVERE, e, () -> "Failed to execute async job for thread " + thread.getName()); -+ } -+ } -+ } -+ -+ private Runnable takeRunnable() throws InterruptedException { -+ mutex.lock(); -+ try { -+ while (jobs.isEmpty() && !killswitch) { -+ cond.await(); -+ } -+ -+ if (jobs.isEmpty()) return null; // We've set killswitch -+ -+ return jobs.remove(); -+ } finally { -+ mutex.unlock(); -+ } -+ } -+ -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/util/AsyncPlayerAreaMap.java b/src/main/java/gg/pufferfish/pufferfish/util/AsyncPlayerAreaMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fdcb62d12164024a5f354d60cc863821a18d1b2a ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/util/AsyncPlayerAreaMap.java -@@ -0,0 +1,31 @@ -+package gg.pufferfish.pufferfish.util; -+ -+import com.destroystokyo.paper.util.misc.PlayerAreaMap; -+import com.destroystokyo.paper.util.misc.PooledLinkedHashSets; -+import java.util.concurrent.ConcurrentHashMap; -+import net.minecraft.server.level.ServerPlayer; -+ -+public final class AsyncPlayerAreaMap extends PlayerAreaMap { -+ -+ public AsyncPlayerAreaMap() { -+ super(); -+ this.areaMap = new Long2ObjectOpenHashMapWrapper<>(new ConcurrentHashMap<>(1024, 0.7f)); -+ } -+ -+ public AsyncPlayerAreaMap(final PooledLinkedHashSets pooledHashSets) { -+ super(pooledHashSets); -+ this.areaMap = new Long2ObjectOpenHashMapWrapper<>(new ConcurrentHashMap<>(1024, 0.7f)); -+ } -+ -+ public AsyncPlayerAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, -+ final ChangeCallback removeCallback) { -+ this(pooledHashSets, addCallback, removeCallback, null); -+ } -+ -+ public AsyncPlayerAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, -+ final ChangeCallback removeCallback, final ChangeSourceCallback changeSourceCallback) { -+ super(pooledHashSets, addCallback, removeCallback, changeSourceCallback); -+ this.areaMap = new Long2ObjectOpenHashMapWrapper<>(new ConcurrentHashMap<>(1024, 0.7f)); -+ } -+ -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/util/IterableWrapper.java b/src/main/java/gg/pufferfish/pufferfish/util/IterableWrapper.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c1929840254a3e6d721816f4a20415bea1742580 ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/util/IterableWrapper.java -@@ -0,0 +1,20 @@ -+package gg.pufferfish.pufferfish.util; -+ -+import java.util.Iterator; -+import org.jetbrains.annotations.NotNull; -+ -+public class IterableWrapper implements Iterable { -+ -+ private final Iterator iterator; -+ -+ public IterableWrapper(Iterator iterator) { -+ this.iterator = iterator; -+ } -+ -+ @NotNull -+ @Override -+ public Iterator iterator() { -+ return iterator; -+ } -+ -+} -diff --git a/src/main/java/gg/pufferfish/pufferfish/util/Long2ObjectOpenHashMapWrapper.java b/src/main/java/gg/pufferfish/pufferfish/util/Long2ObjectOpenHashMapWrapper.java -new file mode 100644 -index 0000000000000000000000000000000000000000..facd55463d44cb7e3d2ca6892982f5497b8dded1 ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/util/Long2ObjectOpenHashMapWrapper.java -@@ -0,0 +1,40 @@ -+package gg.pufferfish.pufferfish.util; -+ -+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -+import java.util.Map; -+import org.jetbrains.annotations.Nullable; -+ -+public class Long2ObjectOpenHashMapWrapper extends Long2ObjectOpenHashMap { -+ -+ private final Map backingMap; -+ -+ public Long2ObjectOpenHashMapWrapper(Map map) { -+ backingMap = map; -+ } -+ -+ @Override -+ public V put(Long key, V value) { -+ return backingMap.put(key, value); -+ } -+ -+ @Override -+ public V get(Object key) { -+ return backingMap.get(key); -+ } -+ -+ @Override -+ public V remove(Object key) { -+ return backingMap.remove(key); -+ } -+ -+ @Nullable -+ @Override -+ public V putIfAbsent(Long key, V value) { -+ return backingMap.putIfAbsent(key, value); -+ } -+ -+ @Override -+ public int size() { -+ return backingMap.size(); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index e028353e0261310afc42ca0454b723d9f1ffc131..2222625a515d9ae6c3e9c92fc4d4a5bf974af5f8 100644 ---- a/src/main/java/io/papermc/paper/util/MCUtil.java -+++ b/src/main/java/io/papermc/paper/util/MCUtil.java -@@ -215,7 +215,7 @@ public final class MCUtil { - } - - public static long getCoordinateKey(final Entity entity) { -- return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); -+ return ((long)(entity.blockPosition.getZ() >> 4) << 32) | ((entity.blockPosition.getX() >> 4) & 0xFFFFFFFFL); // Pufferfish - eliminate double->long cast in hotpath - } - - public static long getCoordinateKey(final ChunkPos pair) { -diff --git a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java -index 0af9ed92824ccf30814eceb6a2c2e5c12661c991..67eeb39aede6908d2756e49821ca350ebe916902 100644 ---- a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java -+++ b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java -@@ -37,7 +37,7 @@ public class SignedMessageChain { - throw new SignedMessageChain.DecodeException(Component.translatable("chat.disabled.chain_broken"), false); // Paper - diff on change (if disconnects, need a new kick event cause) - } else if (playerPublicKey.data().hasExpired()) { - throw new SignedMessageChain.DecodeException(Component.translatable("chat.disabled.expiredProfileKey"), false, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes -- } else if (body.timeStamp().isBefore(this.lastTimeStamp)) { -+ } else if (!gg.pufferfish.pufferfish.PufferfishConfig.disableOutOfOrderChat && body.timeStamp().isBefore(this.lastTimeStamp)) { // Pufferfish - throw new SignedMessageChain.DecodeException(Component.translatable("multiplayer.disconnect.out_of_order_chat"), true, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes - } else { - this.lastTimeStamp = body.timeStamp(); -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 2dc07e5ef249636e85ad9c78e3729e9e066a8fe8..b9e0a32f5829ca15f949effcafcbe2a975f6f690 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -312,6 +312,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { - AtomicReference atomicreference = new AtomicReference(); -@@ -1229,6 +1230,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop // Paper - } - - public SystemReport fillSystemReport(SystemReport details) { -@@ -2452,6 +2459,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop needsChangeBroadcasting = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets); -+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap = new gg.pufferfish.pufferfish.util.AsyncPlayerAreaMap(this.pooledLinkedPlayerHashSets); // Pufferfish - // Paper end - optimise chunk tick iteration - - public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) { -@@ -1448,8 +1448,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - return ChunkMap.this.level.getServer().getScaledTrackingDistance(initialDistance); - } - -+ private static int getHighestRange(Entity parent, int highest) { -+ List passengers = parent.getPassengers(); -+ -+ for (int i = 0, size = passengers.size(); i < size; i++) { -+ Entity entity = passengers.get(i); -+ int range = entity.getType().clientTrackingRange() * 16; -+ range = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, range); // Paper -+ -+ if (range > highest) { // Paper - we need the lowest range thanks to the fact that our tracker doesn't account for passenger logic // Tuinity - not anymore! -+ highest = range; -+ } -+ -+ highest = getHighestRange(entity, highest); -+ } -+ -+ return highest; -+ } -+ - private int getEffectiveRange() { - int i = this.range; -+ // Pufferfish start - remove iterators and streams -+ /* - Iterator iterator = this.entity.getIndirectPassengers().iterator(); - - while (iterator.hasNext()) { -@@ -1461,6 +1481,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - i = j; - } - } -+ */ -+ i = getHighestRange(this.entity, i); -+ // Pufferfish end - - return this.scaledRange(i); - } -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 366c0c9b45a819f7f94ebe3e49b8ab7f9edf9ce7..1cf8c819c0d7776c3b33d6594ca81abe3c2a719d 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -77,6 +77,9 @@ public class ServerChunkCache extends ChunkSource { - private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4]; - // Paper end - -+ public boolean firstRunSpawnCounts = true; // Pufferfish -+ public final java.util.concurrent.atomic.AtomicBoolean _pufferfish_spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false); // Pufferfish - optimize countmobs -+ - public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory) { - this.level = world; - this.mainThreadProcessor = new ServerChunkCache.MainThreadExecutor(world); -@@ -513,6 +516,7 @@ public class ServerChunkCache extends ChunkSource { - - // Paper - optimise chunk tick iteration - -+ this.level.resetIceAndSnowTick(); // Pufferfish - reset ice & snow tick random - if (this.level.getServer().tickRateManager().runsNormally()) { - gameprofilerfiller.popPush("naturalSpawnCount"); - this.level.timings.countNaturalMobs.startTiming(); // Paper - timings -@@ -521,6 +525,7 @@ public class ServerChunkCache extends ChunkSource { - int naturalSpawnChunkCount = k; - NaturalSpawner.SpawnState spawnercreature_d; // moved down - if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled -+ if (!gg.pufferfish.pufferfish.PufferfishConfig.enableAsyncMobSpawning) { // Pufferfish - moved down when async processing - // re-set mob counts - for (ServerPlayer player : this.level.players) { - // Paper start - per player mob spawning backoff -@@ -535,14 +540,18 @@ public class ServerChunkCache extends ChunkSource { - } - // Paper end - per player mob spawning backoff - } -- spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); -+ lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); // Pufferfish - async mob spawning -+ } // Pufferfish - (endif) moved down when async processing - } else { -- spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); -+ // Pufferfish start - async mob spawning -+ lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); -+ _pufferfish_spawnCountsReady.set(true); -+ // Pufferfish end - } - // Paper end - Optional per player mob spawns - this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings - -- this.lastSpawnState = spawnercreature_d; -+ // this.lastSpawnState = spawnercreature_d; // Pufferfish - this is managed asynchronously - gameprofilerfiller.popPush("spawnAndTick"); - boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit - -@@ -632,8 +641,8 @@ public class ServerChunkCache extends ChunkSource { - if (tick && chunk1.chunkStatus.isOrAfter(net.minecraft.server.level.FullChunkStatus.ENTITY_TICKING)) { - // Paper end - optimise chunk tick iteration - chunk1.incrementInhabitedTime(j); -- if (spawn && flag && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair)) { // Spigot // Paper - optimise chunk tick iteration -- NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1); -+ if (spawn && flag && (!gg.pufferfish.pufferfish.PufferfishConfig.enableAsyncMobSpawning || _pufferfish_spawnCountsReady.get()) && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair)) { // Spigot // Paper - optimise chunk tick iteration // Pufferfish -+ NaturalSpawner.spawnForChunk(this.level, chunk1, lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag1); // Pufferfish - } - - if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - optimise chunk tick iteration -@@ -680,6 +689,40 @@ public class ServerChunkCache extends ChunkSource { - gameprofilerfiller.pop(); - gameprofilerfiller.pop(); - } -+ -+ // Pufferfish start - optimize mob spawning -+ if (gg.pufferfish.pufferfish.PufferfishConfig.enableAsyncMobSpawning) { -+ for (ServerPlayer player : this.level.players) { -+ // Paper start - per player mob spawning backoff -+ for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) { -+ player.mobCounts[ii] = 0; -+ -+ int newBackoff = player.mobBackoffCounts[ii] - 1; // TODO make configurable bleed // TODO use nonlinear algorithm? -+ if (newBackoff < 0) { -+ newBackoff = 0; -+ } -+ player.mobBackoffCounts[ii] = newBackoff; -+ } -+ // Paper end - per player mob spawning backoff -+ } -+ if (firstRunSpawnCounts) { -+ firstRunSpawnCounts = false; -+ _pufferfish_spawnCountsReady.set(true); -+ } -+ if (_pufferfish_spawnCountsReady.getAndSet(false)) { -+ net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> { -+ int mapped = distanceManager.getNaturalSpawnChunkCount(); -+ io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator objectiterator = -+ level.entityTickList.entities.iterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); -+ gg.pufferfish.pufferfish.util.IterableWrapper wrappedIterator = -+ new gg.pufferfish.pufferfish.util.IterableWrapper<>(objectiterator); -+ lastSpawnState = NaturalSpawner.createState(mapped, wrappedIterator, this::getFullChunk, null, true); -+ objectiterator.finishedIterating(); -+ _pufferfish_spawnCountsReady.set(true); -+ }); -+ } -+ } -+ // Pufferfish end - } - - private void getFullChunk(long pos, Consumer chunkConsumer) { -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 529ab44baaf573b97cf7e89560c548642733188f..db55ad9aaabfa1ea998754f3ac352d1698936696 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -183,7 +183,8 @@ public class ServerEntity { - long i1 = this.positionCodec.encodeZ(vec3d); - boolean flag6 = k < -32768L || k > 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L; - -- if (!flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()&& !(io.papermc.paper.configuration.GlobalConfiguration.get().collisions.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Paper - send full pos for hard colliding entities to prevent collision problems due to desync -+ if (!flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround() && !(io.papermc.paper.configuration.GlobalConfiguration.get().collisions.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Paper - send full pos for hard colliding entities to prevent collision problems due to desync -+ if (flag2 || flag3 || this.entity instanceof AbstractArrow) { // Pufferfish - if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) { - if (flag2) { - packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), this.entity.onGround()); -@@ -197,6 +198,7 @@ public class ServerEntity { - flag4 = true; - flag5 = true; - } -+ } // Pufferfish - } else { - this.wasOnGround = this.entity.onGround(); - this.teleportDelay = 0; -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 502bdc726b7890b00ee36871d905dea44e8719e3..fbffe3dab1b7812b50df5d6bddf4fbdb2e583339 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -894,6 +894,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - org.spigotmc.ActivationRange.activateEntities(this); // Spigot - this.timings.entityTick.startTiming(); // Spigot - this.entityTickList.forEach((entity) -> { -+ entity.activatedPriorityReset = false; // Pufferfish - DAB - if (!entity.isRemoved()) { - if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed - entity.discard(); -@@ -913,7 +914,20 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - - gameprofilerfiller.push("tick"); -- this.guardEntityTick(this::tickNonPassenger, entity); -+ // Pufferfish start - copied from this.guardEntityTick -+ try { -+ this.tickNonPassenger(entity); // Pufferfish - changed -+ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick -+ } catch (Throwable throwable) { -+ if (throwable instanceof ThreadDeath) throw throwable; // Paper -+ // Paper start - Prevent tile entity and entity crashes -+ final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); -+ MinecraftServer.LOGGER.error(msg, throwable); -+ getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); -+ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); -+ // Paper end -+ } -+ // Pufferfish end - gameprofilerfiller.pop(); - } - } -@@ -978,9 +992,11 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - // Paper start - optimise random block ticking - private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); -- private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong()); -+ // private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); // Pufferfish - moved to super - // Paper end - -+ private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Pufferfish -+ - public void tickChunk(LevelChunk chunk, int randomTickSpeed) { - ChunkPos chunkcoordintpair = chunk.getPos(); - boolean flag = this.isRaining(); -@@ -991,7 +1007,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - gameprofilerfiller.push("thunder"); - final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change - -- if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder -+ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && /*this.random.nextInt(this.spigotConfig.thunderChance) == 0 &&*/ chunk.shouldDoLightning(this.random)) { // Spigot // Paper - Option to disable thunder // Pufferfish - replace random with shouldDoLightning - blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper - - if (this.isRainingAt(blockposition)) { -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index fe2ef36ab5dc4b933abf24dbfd0e811c53239cf0..e725c1c0496383007ffb94c46fc18340666b5e29 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1135,6 +1135,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - @Override - public void handleEditBook(ServerboundEditBookPacket packet) { -+ if (!gg.pufferfish.pufferfish.PufferfishConfig.enableBooks && !this.player.getBukkitEntity().hasPermission("pufferfish.usebooks")) return; // Pufferfish - // Paper start - Book size limits - if (!this.cserver.isPrimaryThread()) { - List pageList = packet.getPages(); -diff --git a/src/main/java/net/minecraft/world/CompoundContainer.java b/src/main/java/net/minecraft/world/CompoundContainer.java -index 241fec02e6869c638d3a160819b32173a081467b..6a8f9e8f5bf108674c47018def28906e2d0a729c 100644 ---- a/src/main/java/net/minecraft/world/CompoundContainer.java -+++ b/src/main/java/net/minecraft/world/CompoundContainer.java -@@ -1,5 +1,6 @@ - package net.minecraft.world; - -+import net.minecraft.core.Direction; // Pufferfish - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.ItemStack; - -@@ -64,6 +65,23 @@ public class CompoundContainer implements Container { - this.container2 = second; - } - -+ // Pufferfish start -+ @Override -+ public boolean hasEmptySlot(Direction enumdirection) { -+ return this.container1.hasEmptySlot(null) || this.container2.hasEmptySlot(null); -+ } -+ -+ @Override -+ public boolean isCompletelyFull(Direction enumdirection) { -+ return this.container1.isCompletelyFull(null) && this.container2.isCompletelyFull(null); -+ } -+ -+ @Override -+ public boolean isCompletelyEmpty(Direction enumdirection) { -+ return this.container1.isCompletelyEmpty(null) && this.container2.isCompletelyEmpty(null); -+ } -+ // Pufferfish end -+ - @Override - public int getContainerSize() { - return this.container1.getContainerSize() + this.container2.getContainerSize(); -diff --git a/src/main/java/net/minecraft/world/Container.java b/src/main/java/net/minecraft/world/Container.java -index d6cbe98e67fdbf8db46338a88ab1356dd63b50a3..20dd3a63b2f955b05a75eb240e33ae4cf6aef28f 100644 ---- a/src/main/java/net/minecraft/world/Container.java -+++ b/src/main/java/net/minecraft/world/Container.java -@@ -3,6 +3,8 @@ package net.minecraft.world; - import java.util.Set; - import java.util.function.Predicate; - import net.minecraft.core.BlockPos; -+ -+import net.minecraft.core.Direction; // Pufferfish - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.Item; - import net.minecraft.world.item.ItemStack; -@@ -14,6 +16,63 @@ import org.bukkit.craftbukkit.entity.CraftHumanEntity; - // CraftBukkit end - - public interface Container extends Clearable { -+ // Pufferfish start - allow the inventory to override and optimize these frequent calls -+ default boolean hasEmptySlot(@org.jetbrains.annotations.Nullable Direction enumdirection) { // there is a slot with 0 items in it -+ if (this instanceof WorldlyContainer worldlyContainer) { -+ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) { -+ if (this.getItem(i).isEmpty()) { -+ return true; -+ } -+ } -+ } else { -+ int size = this.getContainerSize(); -+ for (int i = 0; i < size; i++) { -+ if (this.getItem(i).isEmpty()) { -+ return true; -+ } -+ } -+ } -+ return false; -+ } -+ -+ default boolean isCompletelyFull(@org.jetbrains.annotations.Nullable Direction enumdirection) { // every stack is maxed -+ if (this instanceof WorldlyContainer worldlyContainer) { -+ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) { -+ ItemStack itemStack = this.getItem(i); -+ if (itemStack.getCount() < itemStack.getMaxStackSize()) { -+ return false; -+ } -+ } -+ } else { -+ int size = this.getContainerSize(); -+ for (int i = 0; i < size; i++) { -+ ItemStack itemStack = this.getItem(i); -+ if (itemStack.getCount() < itemStack.getMaxStackSize()) { -+ return false; -+ } -+ } -+ } -+ return true; -+ } -+ -+ default boolean isCompletelyEmpty(@org.jetbrains.annotations.Nullable Direction enumdirection) { -+ if (this instanceof WorldlyContainer worldlyContainer) { -+ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) { -+ if (!this.getItem(i).isEmpty()) { -+ return false; -+ } -+ } -+ } else { -+ int size = this.getContainerSize(); -+ for (int i = 0; i < size; i++) { -+ if (!this.getItem(i).isEmpty()) { -+ return false; -+ } -+ } -+ } -+ return true; -+ } -+ // Pufferfish end - - int LARGE_MAX_STACK_SIZE = 64; - int DEFAULT_DISTANCE_LIMIT = 8; -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 637478fd8a284e6833cf8f5fa17ccf9d73d1dd3f..1aa45e64e49ea011c2ba5e943b4e72c4f3a47176 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -309,7 +309,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - public double yo; - public double zo; - private Vec3 position; -- private BlockPos blockPosition; -+ public BlockPos blockPosition; // Pufferfish - private->public - private ChunkPos chunkPosition; - private Vec3 deltaMovement; - private float yRot; -@@ -424,6 +424,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - private UUID originWorld; - public boolean freezeLocked = false; // Paper - Freeze Tick Lock API - public boolean fixedPose = false; // Paper - Expand Pose API -+ public boolean activatedPriorityReset = false; // Pufferfish - DAB -+ public int activatedPriority = gg.pufferfish.pufferfish.PufferfishConfig.maximumActivationPrio; // Pufferfish - DAB (golf score) -+ public final BlockPos.MutableBlockPos cachedBlockPos = new BlockPos.MutableBlockPos(); // Pufferfish - reduce entity allocations - - public void setOrigin(@javax.annotation.Nonnull Location location) { - this.origin = location.toVector(); -@@ -820,6 +823,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - } - - public void tick() { -+ // Pufferfish start - entity TTL -+ if (type != EntityType.PLAYER && type.ttl >= 0 && this.tickCount >= type.ttl) { -+ discard(); -+ return; -+ } -+ // Pufferfish end - entity TTL - this.baseTick(); - } - -@@ -4421,16 +4430,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - } - - public boolean updateFluidHeightAndDoFluidPushing(TagKey tag, double speed) { -- if (this.touchingUnloadedChunk()) { -+ if (false && this.touchingUnloadedChunk()) { // Pufferfish - cost of a lookup here is the same cost as below, so skip - return false; - } else { - AABB axisalignedbb = this.getBoundingBox().deflate(0.001D); -- int i = Mth.floor(axisalignedbb.minX); -- int j = Mth.ceil(axisalignedbb.maxX); -- int k = Mth.floor(axisalignedbb.minY); -- int l = Mth.ceil(axisalignedbb.maxY); -- int i1 = Mth.floor(axisalignedbb.minZ); -- int j1 = Mth.ceil(axisalignedbb.maxZ); -+ // Pufferfish start - rename -+ int minBlockX = Mth.floor(axisalignedbb.minX); -+ int maxBlockX = Mth.ceil(axisalignedbb.maxX); -+ int minBlockY = Mth.floor(axisalignedbb.minY); -+ int maxBlockY = Mth.ceil(axisalignedbb.maxY); -+ int minBlockZ = Mth.floor(axisalignedbb.minZ); -+ int maxBlockZ = Mth.ceil(axisalignedbb.maxZ); -+ // Pufferfish end - double d1 = 0.0D; - boolean flag = this.isPushedByFluid(); - boolean flag1 = false; -@@ -4438,14 +4449,61 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - int k1 = 0; - BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); - -- for (int l1 = i; l1 < j; ++l1) { -- for (int i2 = k; i2 < l; ++i2) { -- for (int j2 = i1; j2 < j1; ++j2) { -- blockposition_mutableblockposition.set(l1, i2, j2); -- FluidState fluid = this.level().getFluidState(blockposition_mutableblockposition); -+ // Pufferfish start - based off CollisionUtil.getCollisionsForBlocksOrWorldBorder -+ final int minSection = io.papermc.paper.util.WorldUtil.getMinSection(this.level()); -+ final int maxSection = io.papermc.paper.util.WorldUtil.getMaxSection(this.level()); -+ final int minBlock = minSection << 4; -+ final int maxBlock = (maxSection << 4) | 15; -+ -+ // special cases: -+ if (minBlockY > maxBlock || maxBlockY < minBlock) { -+ // no point in checking -+ return false; -+ } -+ -+ int minYIterate = Math.max(minBlock, minBlockY); -+ int maxYIterate = Math.min(maxBlock, maxBlockY); -+ -+ int minChunkX = minBlockX >> 4; -+ int maxChunkX = maxBlockX >> 4; -+ -+ int minChunkZ = minBlockZ >> 4; -+ int maxChunkZ = maxBlockZ >> 4; -+ -+ for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { -+ int minZ = currChunkZ == minChunkZ ? minBlockZ & 15 : 0; // coordinate in chunk -+ int maxZ = currChunkZ == maxChunkZ ? maxBlockZ & 15 : 16; // coordinate in chunk -+ -+ for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) { -+ int minX = currChunkX == minChunkX ? minBlockX & 15 : 0; // coordinate in chunk -+ int maxX = currChunkX == maxChunkX ? maxBlockX & 15 : 16; // coordinate in chunk -+ -+ net.minecraft.world.level.chunk.ChunkAccess chunk = this.level().getChunkIfLoadedImmediately(currChunkX, currChunkZ); -+ if (chunk == null) { -+ return false; // if we're touching an unloaded chunk then it's false -+ } -+ -+ net.minecraft.world.level.chunk.LevelChunkSection[] sections = chunk.getSections(); -+ -+ for (int currY = minYIterate; currY < maxYIterate; ++currY) { -+ net.minecraft.world.level.chunk.LevelChunkSection section = sections[(currY >> 4) - minSection]; -+ -+ if (section == null || section.hasOnlyAir() || section.fluidStateCount == 0) { // if no fluids, nothing in this section -+ // empty -+ // skip to next section -+ currY = (currY & ~(15)) + 15; // increment by 15: iterator loop increments by the extra one -+ continue; -+ } -+ -+ net.minecraft.world.level.chunk.PalettedContainer blocks = section.states; -+ -+ for (int currZ = minZ; currZ < maxZ; ++currZ) { -+ for (int currX = minX; currX < maxX; ++currX) { -+ FluidState fluid = blocks.get(currX & 15, currY & 15, currZ & 15).getFluidState(); - - if (fluid.is(tag)) { -- double d2 = (double) ((float) i2 + fluid.getHeight(this.level(), blockposition_mutableblockposition)); -+ blockposition_mutableblockposition.set((currChunkX << 4) + currX, currY, (currChunkZ << 4) + currZ); -+ double d2 = (double) ((float) currY + fluid.getHeight(this.level(), blockposition_mutableblockposition)); - - if (d2 >= axisalignedbb.minY) { - flag1 = true; -@@ -4467,9 +4525,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - // CraftBukkit end - } - } -+ } -+ } - } - } - } -+ // Pufferfish end - - if (vec3d.length() > 0.0D) { - if (k1 > 0) { -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index 09e8445a3f8c6b3ebc852a75a9a25b41a51ba659..dc11683ee4d8a6b7a1c42bcae36dc6e8105cd994 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -305,6 +305,8 @@ public class EntityType implements FeatureElement, EntityTypeT - private final boolean canSpawnFarFromPlayer; - private final int clientTrackingRange; - private final int updateInterval; -+ public boolean dabEnabled = false; // Pufferfish -+ public int ttl = -1; // Pufferfish - @Nullable - private String descriptionId; - @Nullable -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index e9bb7feb591032904516d1b9374f486d8a7d066c..366121188c5abb550ed0a5f99d25c001628685bb 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -143,7 +143,6 @@ import org.bukkit.event.entity.EntityTeleportEvent; - import org.bukkit.event.player.PlayerItemConsumeEvent; - // CraftBukkit end - --import co.aikar.timings.MinecraftTimings; // Paper - - public abstract class LivingEntity extends Entity implements Attackable { - -@@ -414,7 +413,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - boolean flag = this instanceof net.minecraft.world.entity.player.Player; - - if (!this.level().isClientSide) { -- if (this.isInWall()) { -+ if (shouldCheckForSuffocation() && this.isInWall()) { // Pufferfish - optimize suffocation - this.hurt(this.damageSources().inWall(), 1.0F); - } else if (flag && !this.level().getWorldBorder().isWithinBounds(this.getBoundingBox())) { - double d0 = this.level().getWorldBorder().getDistanceToBorder(this) + this.level().getWorldBorder().getDamageSafeZone(); -@@ -1418,6 +1417,19 @@ public abstract class LivingEntity extends Entity implements Attackable { - return this.getHealth() <= 0.0F; - } - -+ // Pufferfish start - optimize suffocation -+ public boolean couldPossiblyBeHurt(float amount) { -+ if ((float) this.invulnerableTime > (float) this.invulnerableDuration / 2.0F && amount <= this.lastHurt) { -+ return false; -+ } -+ return true; -+ } -+ -+ public boolean shouldCheckForSuffocation() { -+ return !gg.pufferfish.pufferfish.PufferfishConfig.enableSuffocationOptimization || (tickCount % 10 == 0 && couldPossiblyBeHurt(1.0F)); -+ } -+ // Pufferfish end -+ - @Override - public boolean hurt(DamageSource source, float amount) { - if (this.isInvulnerableTo(source)) { -@@ -2024,6 +2036,20 @@ public abstract class LivingEntity extends Entity implements Attackable { - return this.lastClimbablePos; - } - -+ -+ // Pufferfish start -+ private boolean cachedOnClimable = false; -+ private BlockPos lastClimbingPosition = null; -+ -+ public boolean onClimableCached() { -+ if (!this.blockPosition().equals(this.lastClimbingPosition)) { -+ this.cachedOnClimable = this.onClimbable(); -+ this.lastClimbingPosition = this.blockPosition(); -+ } -+ return this.cachedOnClimable; -+ } -+ // Pufferfish end -+ - public boolean onClimbable() { - if (this.isSpectator()) { - return false; -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index d2c92df28475f0a32a0134324eb0a5609a9afb99..a6b48b4eab6e0e98205fd9cafc3cde5ad39651af 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -222,14 +222,16 @@ public abstract class Mob extends LivingEntity implements Targeting { - return this.lookControl; - } - -+ int _pufferfish_inactiveTickDisableCounter = 0; // Pufferfish - throttle inactive goal selector ticking - // Paper start - @Override - public void inactiveTick() { - super.inactiveTick(); -- if (this.goalSelector.inactiveTick()) { -+ boolean isThrottled = gg.pufferfish.pufferfish.PufferfishConfig.throttleInactiveGoalSelectorTick && _pufferfish_inactiveTickDisableCounter++ % 20 != 0; // Pufferfish - throttle inactive goal selector ticking -+ if (this.goalSelector.inactiveTick(this.activatedPriority, true) && !isThrottled) { // Pufferfish - pass activated priroity // Pufferfish - throttle inactive goal selector ticking - this.goalSelector.tick(); - } -- if (this.targetSelector.inactiveTick()) { -+ if (this.targetSelector.inactiveTick(this.activatedPriority, true)) { // Pufferfish - pass activated priority - this.targetSelector.tick(); - } - } -@@ -913,16 +915,20 @@ public abstract class Mob extends LivingEntity implements Targeting { - - if (i % 2 != 0 && this.tickCount > 1) { - this.level().getProfiler().push("targetSelector"); -+ if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.targetSelector.tickRunningGoals(false); - this.level().getProfiler().pop(); - this.level().getProfiler().push("goalSelector"); -+ if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.goalSelector.tickRunningGoals(false); - this.level().getProfiler().pop(); - } else { - this.level().getProfiler().push("targetSelector"); -+ if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.targetSelector.tick(); - this.level().getProfiler().pop(); - this.level().getProfiler().push("goalSelector"); -+ if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking - this.goalSelector.tick(); - this.level().getProfiler().pop(); - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -index b99a080ab27e24d8131fda931ca70d6d271bb01c..8d6954d05d2bf6d6c1c4953db3127b011a858cec 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -@@ -23,9 +23,11 @@ public class AttributeMap { - private final Map attributes = Maps.newHashMap(); - private final Set dirtyAttributes = Sets.newHashSet(); - private final AttributeSupplier supplier; -+ private final java.util.function.Function createInstance; // Pufferfish - - public AttributeMap(AttributeSupplier defaultAttributes) { - this.supplier = defaultAttributes; -+ this.createInstance = attributex -> this.supplier.createInstance(this::onAttributeModified, attributex); // Pufferfish - } - - private void onAttributeModified(AttributeInstance instance) { -@@ -42,9 +44,10 @@ public class AttributeMap { - return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().isClientSyncable()).collect(Collectors.toList()); - } - -+ - @Nullable - public AttributeInstance getInstance(Attribute attribute) { -- return this.attributes.computeIfAbsent(attribute, attributex -> this.supplier.createInstance(this::onAttributeModified, attributex)); -+ return this.attributes.computeIfAbsent(attribute, this.createInstance); // Pufferfish - cache lambda, as for some reason java allocates it anyways - } - - @Nullable -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java -index 758f62416ca9c02351348ac0d41deeb4624abc0e..69130969c9a434ec2361e573c9a1ec9f462dfda2 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java -@@ -36,7 +36,11 @@ public class VillagerPanicTrigger extends Behavior { - - @Override - protected void tick(ServerLevel world, Villager entity, long time) { -- if (time % 100L == 0L) { -+ // Pufferfish start -+ if (entity.nextGolemPanic < 0) entity.nextGolemPanic = time + 100; -+ if (--entity.nextGolemPanic < time) { -+ entity.nextGolemPanic = -1; -+ // Pufferfish end - entity.spawnGolemIfNeeded(world, time, 3); - } - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -index 38af5c7280366fd6ec077f3d914ea5f3ee77451a..d78e1f6191738d426968efc24e734f04b0fc7edb 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -@@ -52,9 +52,12 @@ public class GoalSelector { - } - - // Paper start -- public boolean inactiveTick() { -+ public boolean inactiveTick(int tickRate, boolean inactive) { // Pufferfish start -+ if (inactive && !gg.pufferfish.pufferfish.PufferfishConfig.dearEnabled) tickRate = 4; // reset to Paper's -+ tickRate = Math.min(tickRate, this.newGoalRate); - this.curRate++; -- return this.curRate % this.newGoalRate == 0; -+ return this.curRate % tickRate == 0; -+ // Pufferfish end - } - public boolean hasTasks() { - for (WrappedGoal task : this.availableGoals) { -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -index aee0147649d458b87d92496eda0c1723ebe570d2..89e9ea999d2fbd81a1d74382ef3fcd675fc8b94e 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -@@ -121,6 +121,7 @@ public abstract class MoveToBlockGoal extends Goal { - for (int m = 0; m <= l; m = m > 0 ? -m : 1 - m) { - for (int n = m < l && m > -l ? l : 0; n <= l; n = n > 0 ? -n : 1 - n) { - mutableBlockPos.setWithOffset(blockPos, m, k - 1, n); -+ if (!this.mob.level().hasChunkAt(mutableBlockPos)) continue; // Pufferfish - if this block isn't loaded, continue - if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level(), mutableBlockPos)) { - this.blockPos = mutableBlockPos; - this.mob.movingTarget = mutableBlockPos == BlockPos.ZERO ? null : mutableBlockPos.immutable(); // Paper -diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -index d2f0c3b26d4beedb49d86e0242d843590d469d02..28cff997a1b263784e245f692adbff2a888a2d53 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -@@ -76,9 +76,18 @@ public class TargetingConditions { - } - - if (this.range > 0.0) { -- double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0; -- double e = Math.max((this.useFollowRange ? this.getFollowRange(baseEntity) : this.range) * d, 2.0); // Paper - Fix MC-145656 -+ // Pufferfish start - check range before getting visibility -+ // d = invisibility percent, e = follow range adjusted for invisibility, f = distance - double f = baseEntity.distanceToSqr(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ()); -+ double followRangeRaw = this.useFollowRange ? this.getFollowRange(baseEntity) : this.range; -+ -+ if (f > followRangeRaw * followRangeRaw) { // the actual follow range will always be this value or smaller, so if the distance is larger then it never will return true after getting invis -+ return false; -+ } -+ -+ double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0; -+ double e = Math.max((followRangeRaw) * d, 2.0); // Paper - Fix MC-145656 -+ // Pufferfish end - if (f > e * e) { - return false; - } -diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index 44fa2d4f90389f5526746bd94a2450c03340bd0b..4fba7c2f6ec363846a772ef2a63e9b3fc1037de5 100644 ---- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java -+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -@@ -241,13 +241,22 @@ public class Bat extends AmbientCreature { - } - } - -+ // Pufferfish start - only check for spooky season once an hour -+ private static boolean isSpookySeason = false; -+ private static final int ONE_HOUR = 20 * 60 * 60; -+ private static int lastSpookyCheck = -ONE_HOUR; - private static boolean isHalloween() { -+ if (net.minecraft.server.MinecraftServer.currentTick - lastSpookyCheck > ONE_HOUR) { - LocalDate localdate = LocalDate.now(); - int i = localdate.get(ChronoField.DAY_OF_MONTH); - int j = localdate.get(ChronoField.MONTH_OF_YEAR); - -- return j == 10 && i >= 20 || j == 11 && i <= 3; -+ isSpookySeason = j == 10 && i >= 20 || j == 11 && i <= 3; -+ lastSpookyCheck = net.minecraft.server.MinecraftServer.currentTick; -+ } -+ return isSpookySeason; - } -+ // Pufferfish end - - @Override - protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { -diff --git a/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java b/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java -index 5ad5f22e5aa26445e5eb229958e7bf356bdd460e..d241ca4d0295f9fce39c11197bd435cfac7f6e54 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java -+++ b/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java -@@ -221,9 +221,11 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS - return 0.4F; - } - -+ private int behaviorTick = 0; // Pufferfish - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("allayBrain"); -+ if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("allayActivityUpdate"); -diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -index b21e180641d17438997a80e5bcb0ec7998d24a2e..33c160994f70f71446d665e7487913437c9f9db4 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -+++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -@@ -275,9 +275,11 @@ public class Axolotl extends Animal implements LerpingModel, VariantHolder { - } - } - -+ private int behaviorTick = 0; // Pufferfish - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("frogBrain"); -+ if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("frogActivityUpdate"); -diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -index 958816ce2166248b542c96c10c398a52d769b4db..415afe3473d9f8a50b1edab8cfda6158e59836e6 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -@@ -80,9 +80,11 @@ public class Tadpole extends AbstractFish { - return SoundEvents.TADPOLE_FLOP; - } - -+ private int behaviorTick = 0; // Pufferfish - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("tadpoleBrain"); -+ if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("tadpoleActivityUpdate"); -diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 5d247ac38fe8a61603b3d934f3000bcda773142b..2e4177cfb02616ef6fa689f6d378976e39484cfb 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -191,9 +191,11 @@ public class Goat extends Animal { - return (Brain) super.getBrain(); // CraftBukkit - decompile error - } - -+ private int behaviorTick = 0; // Pufferfish - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("goatBrain"); -+ if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("goatActivityUpdate"); -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 12440ee2dccc0a697fb403765f2e1b987ccc0283..de2471cfa96a23944f229f33ffdff88b6b7756e4 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -151,6 +151,13 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - this.bossEvent.setName(this.getDisplayName()); - } - -+ // Pufferfish start - optimize suffocation -+ @Override -+ public boolean shouldCheckForSuffocation() { -+ return true; -+ } -+ // Pufferfish end -+ - @Override - protected SoundEvent getAmbientSound() { - return SoundEvents.WITHER_AMBIENT; -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index f33c03e81b7ff643741f56eea055e6af260de618..6563e625ebae47fc68e5010d36bd4b4d327c07b7 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -333,11 +333,17 @@ public class EnderMan extends Monster implements NeutralMob { - private boolean teleport(double x, double y, double z) { - BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(x, y, z); - -- while (blockposition_mutableblockposition.getY() > this.level().getMinBuildHeight() && !this.level().getBlockState(blockposition_mutableblockposition).blocksMotion()) { -+ // Pufferfish start - single chunk lookup -+ net.minecraft.world.level.chunk.LevelChunk chunk = this.level().getChunkIfLoaded(blockposition_mutableblockposition); -+ if (chunk == null) { -+ return false; -+ } -+ // Pufferfish end -+ while (blockposition_mutableblockposition.getY() > this.level().getMinBuildHeight() && !chunk.getBlockState(blockposition_mutableblockposition).blocksMotion()) { // Pufferfish - blockposition_mutableblockposition.move(Direction.DOWN); - } - -- BlockState iblockdata = this.level().getBlockState(blockposition_mutableblockposition); -+ BlockState iblockdata = chunk.getBlockState(blockposition_mutableblockposition); // Pufferfish - boolean flag = iblockdata.blocksMotion(); - boolean flag1 = iblockdata.getFluidState().is(FluidTags.WATER); - -diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index 050ffa4a23feba29fdf4c6a175cdff4e5009027d..1299f93d4f983e6715e447add65df91ef9e9090a 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -155,9 +155,11 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - return (Brain)super.getBrain(); - } - -+ private int behaviorTick; // Pufferfish - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("hoglinBrain"); -+ if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); - HoglinAi.updateActivity(this); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index a9813da7f2b248f98f22e0ad2e7842915025ec12..83d83e3f84bb6bd58761671c6cd4c8683545ff4c 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -300,9 +300,11 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - return !this.cannotHunt; - } - -+ private int behaviorTick; // Pufferfish - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("piglinBrain"); -+ if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - PiglinAi.updateActivity(this); -diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index 937f81a859953498abe73bea560c86e6560e1c33..0a151c679b0dc943598180942d6d4b3886211688 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -+++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -@@ -273,11 +273,13 @@ public class Warden extends Monster implements VibrationSystem { - - } - -+ private int behaviorTick = 0; // Pufferfish - @Override - protected void customServerAiStep() { - ServerLevel worldserver = (ServerLevel) this.level(); - - worldserver.getProfiler().push("wardenBrain"); -+ if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick(worldserver, this); - this.level().getProfiler().pop(); - super.customServerAiStep(); -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 24044795d8e0f1fb15a4f2f5401f44897092f2a3..96ca567af2d8fb2ba39f995be80b935344550124 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -143,6 +143,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - return holder.is(PoiTypes.MEETING); - }); - -+ public long nextGolemPanic = -1; // Pufferfish -+ - public Villager(EntityType entityType, Level world) { - this(entityType, world, VillagerType.PLAINS); - } -@@ -246,6 +248,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - } - // Spigot End - -+ private int behaviorTick = 0; // Pufferfish - @Override - @Deprecated // Paper - protected void customServerAiStep() { -@@ -255,7 +258,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - protected void customServerAiStep(final boolean inactive) { - // Paper end - this.level().getProfiler().push("villagerBrain"); -- if (!inactive) this.getBrain().tick((ServerLevel) this.level(), this); // Paper -+ // Pufferfish start -+ if (!inactive && this.behaviorTick++ % this.activatedPriority == 0) { -+ this.getBrain().tick((ServerLevel) this.level(), this); // Paper -+ } -+ // Pufferfish end - this.level().getProfiler().pop(); - if (this.assignProfessionWhenSpawned) { - this.assignProfessionWhenSpawned = false; -diff --git a/src/main/java/net/minecraft/world/entity/player/Inventory.java b/src/main/java/net/minecraft/world/entity/player/Inventory.java -index 96c898086f35fd83f9b1ce7e3fe53d31b2fa4c31..c6a925cbd35eb33b27b90bfa8344ac7515d28b76 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Inventory.java -+++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java -@@ -687,6 +687,8 @@ public class Inventory implements Container, Nameable { - } - - public boolean contains(ItemStack stack) { -+ // Pufferfish start - don't allocate iterators -+ /* - Iterator iterator = this.compartments.iterator(); - - while (iterator.hasNext()) { -@@ -701,6 +703,18 @@ public class Inventory implements Container, Nameable { - } - } - } -+ */ -+ for (int i = 0; i < this.compartments.size(); i++) { -+ List list = this.compartments.get(i); -+ for (int j = 0; j < list.size(); j++) { -+ ItemStack itemstack1 = list.get(j); -+ -+ if (!itemstack1.isEmpty() && ItemStack.isSameItemSameTags(itemstack1, stack)) { -+ return true; -+ } -+ } -+ } -+ // Pufferfish end - - return false; - } -diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index 156809090f1f83ad68e7e2477a3cfddac5757a8e..837f68825f601971f374be47952b23108bf66ba6 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -45,6 +45,36 @@ public abstract class Projectile extends Entity implements TraceableEntity { - super(type, world); - } - -+ // Pufferfish start -+ private static int loadedThisTick = 0; -+ private static int loadedTick; -+ -+ private int loadedLifetime = 0; -+ @Override -+ public void setPos(double x, double y, double z) { -+ int currentTick = net.minecraft.server.MinecraftServer.currentTick; -+ if (loadedTick != currentTick) { -+ loadedTick = currentTick; -+ loadedThisTick = 0; -+ } -+ int previousX = Mth.floor(this.getX()) >> 4, previousZ = Mth.floor(this.getZ()) >> 4; -+ int newX = Mth.floor(x) >> 4, newZ = Mth.floor(z) >> 4; -+ if (previousX != newX || previousZ != newZ) { -+ boolean isLoaded = ((net.minecraft.server.level.ServerChunkCache) this.level().getChunkSource()).getChunkAtIfLoadedMainThread(newX, newZ) != null; -+ if (!isLoaded) { -+ if (Projectile.loadedThisTick > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerTick) { -+ if (++this.loadedLifetime > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerProjectile) { -+ this.discard(); -+ } -+ return; -+ } -+ Projectile.loadedThisTick++; -+ } -+ } -+ super.setPos(x, y, z); -+ } -+ // Pufferfish end -+ - public void setOwner(@Nullable Entity entity) { - if (entity != null) { - this.ownerUUID = entity.getUUID(); -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java -index 756d0434472921992c9d84597d7c9c824e93614c..38c573d440946ca7ee6016ef92e9c1605031e611 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java -@@ -28,7 +28,10 @@ import org.bukkit.inventory.InventoryHolder; - - public abstract class AbstractMinecartContainer extends AbstractMinecart implements ContainerEntity { - -+ // Pufferfish start - private NonNullList itemStacks; -+ private gg.airplane.structs.ItemListWithBitset itemStacksOptimized; -+ // Pufferfish end - @Nullable - public ResourceLocation lootTable; - public long lootTableSeed; -@@ -90,12 +93,18 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme - - protected AbstractMinecartContainer(EntityType type, Level world) { - super(type, world); -- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513 -+ // Pufferfish start -+ this.itemStacksOptimized = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // CraftBukkit - SPIGOT-3513 -+ this.itemStacks = this.itemStacksOptimized.nonNullList; -+ // Pufferfish end - } - - protected AbstractMinecartContainer(EntityType type, double x, double y, double z, Level world) { - super(type, world, x, y, z); -- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513 -+ // Pufferfish start -+ this.itemStacksOptimized = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // CraftBukkit - SPIGOT-3513 -+ this.itemStacks = this.itemStacksOptimized.nonNullList; -+ // Pufferfish end - } - - @Override -@@ -164,6 +173,10 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme - protected void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); - this.lootableData.loadNbt(nbt); // Paper -+ // Pufferfish start -+ this.itemStacksOptimized = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); -+ this.itemStacks = this.itemStacksOptimized.nonNullList; -+ // Pufferfish end - this.readChestVehicleSaveData(nbt); - } - -diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -index e1696f6b77df4c8fceaece64701d4db78b0a4c42..faa3f62d22266a3c32d6c95c3ffebd4aa3880739 100644 ---- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java -+++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -@@ -55,7 +55,7 @@ public class EndCrystalItem extends Item { - world.gameEvent((Entity) context.getPlayer(), GameEvent.ENTITY_PLACE, blockposition1); - EndDragonFight enderdragonbattle = ((ServerLevel) world).getDragonFight(); - -- if (enderdragonbattle != null) { -+ if (enderdragonbattle != null && gg.pufferfish.pufferfish.PufferfishConfig.allowEndCrystalRespawn) { // Pufferfish - enderdragonbattle.tryRespawn(aboveBlockPosition); // Paper - Perf: Do crystal-portal proximity check before entity lookup - } - } -diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java -index 27b0a79f7a7c47047216aae42944bac2a2151181..a097cfc528f709c80575f35483b6878314ea2717 100644 ---- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java -+++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java -@@ -26,8 +26,13 @@ public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBoo - final CraftingBookCategory category; - final ItemStack result; - final NonNullList ingredients; -+ private final boolean isBukkit; // Pufferfish - -+ // Pufferfish start - public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, NonNullList ingredients) { -+ this(group, category, result, ingredients, false); -+ } -+ public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, NonNullList ingredients, boolean isBukkit) { this.isBukkit = isBukkit; // Pufferfish end - this.group = group; - this.category = category; - this.result = result; -@@ -77,6 +82,28 @@ public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBoo - } - - public boolean matches(CraftingContainer inventory, Level world) { -+ // Pufferfish start -+ if (!this.isBukkit) { -+ java.util.List ingredients = com.google.common.collect.Lists.newArrayList(this.ingredients.toArray(new Ingredient[0])); -+ -+ inventory: for (int index = 0; index < inventory.getContainerSize(); index++) { -+ ItemStack itemStack = inventory.getItem(index); -+ -+ if (!itemStack.isEmpty()) { -+ for (int i = 0; i < ingredients.size(); i++) { -+ if (ingredients.get(i).test(itemStack)) { -+ ingredients.remove(i); -+ continue inventory; -+ } -+ } -+ return false; -+ } -+ } -+ -+ return ingredients.isEmpty(); -+ } -+ // Pufferfish end -+ - StackedContents autorecipestackmanager = new StackedContents(); - autorecipestackmanager.initialize(this); // Paper - better exact choice recipes - int i = 0; -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index ca89d1593bf1b46c79a882db528cbca1359dc9d4..a82de7111915b19cdc3f065910465a5e7e843aff 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -215,6 +215,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - // Paper end - - public abstract ResourceKey getTypeKey(); -+ -+ protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); public net.minecraft.util.RandomSource getThreadUnsafeRandom() { return this.randomTickRandom; } // Pufferfish - move thread unsafe random initialization // Pufferfish - getter - - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config; Async-Anti-Xray: Pass executor - this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot -@@ -1317,13 +1319,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - try { - tickConsumer.accept(entity); - MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick -- } catch (Throwable throwable) { -+ } catch (Throwable throwable) { // Pufferfish - diff on change ServerLevel.tick - if (throwable instanceof ThreadDeath) throw throwable; // Paper - // Paper start - Prevent block entity and entity crashes - final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); - MinecraftServer.LOGGER.error(msg, throwable); - getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); // Paper - ServerExceptionEvent -- entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); -+ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Pufferfish - diff on change ServerLevel.tick - // Paper end - Prevent block entity and entity crashes - } - } -@@ -1797,6 +1799,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - - public ProfilerFiller getProfiler() { -+ if (gg.pufferfish.pufferfish.PufferfishConfig.disableMethodProfiler) return net.minecraft.util.profiling.InactiveProfiler.INSTANCE; // Pufferfish - return (ProfilerFiller) this.profiler.get(); - } - -diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index da7489986848316fed029b71d1bc4e1248c9c9a8..661acdf4b1f33d150b0caf179e925d3162d7be35 100644 ---- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java -+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -425,12 +425,12 @@ public final class NaturalSpawner { - } - } - -- private static BlockPos getRandomPosWithin(Level world, LevelChunk chunk) { -+ private static BlockPos getRandomPosWithin(ServerLevel world, LevelChunk chunk) { // Pufferfish - accept serverlevel - ChunkPos chunkcoordintpair = chunk.getPos(); -- int i = chunkcoordintpair.getMinBlockX() + world.random.nextInt(16); -- int j = chunkcoordintpair.getMinBlockZ() + world.random.nextInt(16); -+ int i = chunkcoordintpair.getMinBlockX() + world.getThreadUnsafeRandom().nextInt(16); // Pufferfish - use thread unsafe random -+ int j = chunkcoordintpair.getMinBlockZ() + world.getThreadUnsafeRandom().nextInt(16); // Pufferfish - int k = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i, j) + 1; -- int l = Mth.randomBetweenInclusive(world.random, world.getMinBuildHeight(), k); -+ int l = Mth.randomBetweenInclusive(world.getThreadUnsafeRandom(), world.getMinBuildHeight(), k); // Pufferfish - - return new BlockPos(i, l, j); - } -diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java -index 64076a452a315090d299a7a58a43fd3b5c1b4e0a..0c317b0147a73a8075e0883f0c132f4db0bdfea7 100644 ---- a/src/main/java/net/minecraft/world/level/biome/Biome.java -+++ b/src/main/java/net/minecraft/world/level/biome/Biome.java -@@ -63,13 +63,18 @@ public final class Biome { - private final BiomeGenerationSettings generationSettings; - private final MobSpawnSettings mobSettings; - private final BiomeSpecialEffects specialEffects; -- private final ThreadLocal temperatureCache = ThreadLocal.withInitial(() -> Util.make(() -> { -+ // Pufferfish start - use our cache -+ private final ThreadLocal temperatureCache = ThreadLocal.withInitial(() -> Util.make(() -> { -+ /* - Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = new Long2FloatLinkedOpenHashMap(1024, 0.25F) { - protected void rehash(int i) { - } - }; - long2FloatLinkedOpenHashMap.defaultReturnValue(Float.NaN); - return long2FloatLinkedOpenHashMap; -+ */ -+ return new gg.airplane.structs.Long2FloatAgingCache(TEMPERATURE_CACHE_SIZE); -+ // Pufferfish end - })); - - Biome(Biome.ClimateSettings weather, BiomeSpecialEffects effects, BiomeGenerationSettings generationSettings, MobSpawnSettings spawnSettings) { -@@ -112,17 +117,15 @@ public final class Biome { - @Deprecated - public float getTemperature(BlockPos blockPos) { - long l = blockPos.asLong(); -- Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = this.temperatureCache.get(); -- float f = long2FloatLinkedOpenHashMap.get(l); -+ // Pufferfish start -+ gg.airplane.structs.Long2FloatAgingCache cache = this.temperatureCache.get(); -+ float f = cache.getValue(l); - if (!Float.isNaN(f)) { - return f; - } else { - float g = this.getHeightAdjustedTemperature(blockPos); -- if (long2FloatLinkedOpenHashMap.size() == 1024) { -- long2FloatLinkedOpenHashMap.removeFirstFloat(); -- } -- -- long2FloatLinkedOpenHashMap.put(l, g); -+ cache.putValue(l, g); -+ // Pufferfish end - return g; - } - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -index 9b1243d96e0694c62fc9e82e9be540bce0d2b3ad..3514022d898a24052c917ebf55dcef3e757d6836 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -@@ -31,7 +31,10 @@ import org.bukkit.entity.HumanEntity; - public class ChestBlockEntity extends RandomizableContainerBlockEntity implements LidBlockEntity { - - private static final int EVENT_SET_OPEN_COUNT = 1; -+ // Pufferfish start - private NonNullList items; -+ private gg.airplane.structs.ItemListWithBitset optimizedItems; -+ // Pufferfish end - public final ContainerOpenersCounter openersCounter; - private final ChestLidController chestLidController; - -@@ -65,9 +68,13 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement - } - // CraftBukkit end - -+ private final boolean isNative = getClass().equals(ChestBlockEntity.class); // Pufferfish - protected ChestBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); -- this.items = NonNullList.withSize(27, ItemStack.EMPTY); -+ // Pufferfish start -+ this.optimizedItems = new gg.airplane.structs.ItemListWithBitset(27); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - this.openersCounter = new ContainerOpenersCounter() { - @Override - protected void onOpen(Level world, BlockPos pos, BlockState state) { -@@ -98,6 +105,23 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement - this.chestLidController = new ChestLidController(); - } - -+ // Pufferfish start -+ @Override -+ public boolean hasEmptySlot(Direction enumdirection) { -+ return isNative ? !this.optimizedItems.hasFullStacks() : super.hasEmptySlot(enumdirection); -+ } -+ -+ @Override -+ public boolean isCompletelyFull(Direction enumdirection) { -+ return isNative ? this.optimizedItems.hasFullStacks() && super.isCompletelyFull(enumdirection) : super.isCompletelyFull(enumdirection); -+ } -+ -+ @Override -+ public boolean isCompletelyEmpty(Direction enumdirection) { -+ return isNative && this.optimizedItems.isCompletelyEmpty() || super.isCompletelyEmpty(enumdirection); -+ } -+ // Pufferfish end -+ - public ChestBlockEntity(BlockPos pos, BlockState state) { - this(BlockEntityType.CHEST, pos, state); - } -@@ -115,7 +139,10 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement - @Override - public void load(CompoundTag nbt) { - super.load(nbt); -- this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); -+ // Pufferfish start -+ this.optimizedItems = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - if (!this.tryLoadLootTable(nbt)) { - ContainerHelper.loadAllItems(nbt, this.items); - } -@@ -187,7 +214,10 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement - - @Override - protected void setItems(NonNullList list) { -- this.items = list; -+ // Pufferfish start -+ this.optimizedItems = gg.airplane.structs.ItemListWithBitset.fromList(list); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index cdb739df2a285032d25d84f4464f202a7a3fa578..6b9cd8543a5bfc2b936ba18f66ffd60f2f792e43 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -@@ -48,7 +48,10 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - public static final int MOVE_ITEM_SPEED = 8; - public static final int HOPPER_CONTAINER_SIZE = 5; -+ // Pufferfish start - private NonNullList items; -+ private gg.airplane.structs.ItemListWithBitset optimizedItems; // Pufferfish -+ // Pufferfish end - public int cooldownTime; - private long tickedGameTime; - -@@ -84,14 +87,37 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - public HopperBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.HOPPER, pos, state); -- this.items = NonNullList.withSize(5, ItemStack.EMPTY); -+ // Pufferfish start -+ this.optimizedItems = new gg.airplane.structs.ItemListWithBitset(5); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - this.cooldownTime = -1; - } - -+ // Pufferfish start -+ @Override -+ public boolean hasEmptySlot(Direction enumdirection) { -+ return !this.optimizedItems.hasFullStacks(); -+ } -+ -+ @Override -+ public boolean isCompletelyFull(Direction enumdirection) { -+ return this.optimizedItems.hasFullStacks() && super.isCompletelyFull(enumdirection); -+ } -+ -+ @Override -+ public boolean isCompletelyEmpty(Direction enumdirection) { -+ return this.optimizedItems.isCompletelyEmpty() || super.isCompletelyEmpty(enumdirection); -+ } -+ // Pufferfish end -+ - @Override - public void load(CompoundTag nbt) { - super.load(nbt); -- this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); -+ // Pufferfish start -+ this.optimizedItems = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - if (!this.tryLoadLootTable(nbt)) { - ContainerHelper.loadAllItems(nbt, this.items); - } -@@ -492,6 +518,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - } - - private static boolean isFullContainer(Container inventory, Direction direction) { -+ if (true) return inventory.isCompletelyFull(direction); // Pufferfish - use bitsets - // Paper start - Perf: Optimize Hoppers - if (inventory instanceof WorldlyContainer worldlyContainer) { - for (final int slot : worldlyContainer.getSlotsForFace(direction)) { -@@ -514,7 +541,10 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - } - - private static boolean isEmptyContainer(Container inv, Direction facing) { -- return allMatch(inv, facing, IS_EMPTY_TEST); // Paper - Perf: Optimize Hoppers -+ // Pufferfish start - use bitsets -+ //return allMatch(inv, facing, IS_EMPTY_TEST); // Paper - Perf: Optimize Hoppers -+ return inv.isCompletelyEmpty(facing); -+ // Pufferfish end - } - - public static boolean suckInItems(Level world, Hopper hopper) { -@@ -714,7 +744,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - if (HopperBlockEntity.canPlaceItemInContainer(to, stack, slot, side)) { - boolean flag = false; -- boolean flag1 = to.isEmpty(); -+ boolean flag1 = to.isCompletelyEmpty(side); // Pufferfish - - if (itemstack1.isEmpty()) { - // Spigot start - SPIGOT-6693, InventorySubcontainer#setItem -@@ -909,7 +939,10 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - @Override - protected void setItems(NonNullList list) { -- this.items = list; -+ // Pufferfish start -+ this.optimizedItems = gg.airplane.structs.ItemListWithBitset.fromList(list); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - } - - public static void entityInside(Level world, BlockPos pos, BlockState state, Entity entity, HopperBlockEntity blockEntity) { -diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java -index dfd1246b735fe64c5beae83567a013861eb00822..fa64bf5ad13c278438039b663ea3134e72108411 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java -@@ -94,12 +94,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc - public boolean isEmpty() { - this.unpackLootTable(null); - // Paper start - Perf: Optimize Hoppers -- for (final ItemStack itemStack : this.getItems()) { -- if (!itemStack.isEmpty()) { -- return false; -- } -- } -- return true; -+ return this.isCompletelyEmpty(null); // Pufferfish - use super - // Paper end - Perf: Optimize Hoppers - } - -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 465458e8a7dbaf9afb32709a71c7b2620d1e1fd2..270a892373ecbb3982990d6201d79c8a66de4f60 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -86,6 +86,18 @@ public class LevelChunk extends ChunkAccess { - private final LevelChunkTicks fluidTicks; - public volatile FullChunkStatus chunkStatus = FullChunkStatus.INACCESSIBLE; // Paper - rewrite chunk system - -+ // Pufferfish start - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively -+ private int lightningTick; -+ // shouldDoLightning compiles down to 29 bytes, which with the default of 35 byte inlining should guarantee an inline -+ public final boolean shouldDoLightning(net.minecraft.util.RandomSource random) { -+ if (this.lightningTick-- <= 0) { -+ this.lightningTick = random.nextInt(this.level.spigotConfig.thunderChance) << 1; -+ return true; -+ } -+ return false; -+ } -+ // Pufferfish end -+ - public LevelChunk(Level world, ChunkPos pos) { - this(world, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, (LevelChunkSection[]) null, (LevelChunk.PostLoadProcessor) null, (BlendingData) null); - } -@@ -109,6 +121,8 @@ public class LevelChunk extends ChunkAccess { - this.postLoad = entityLoader; - this.blockTicks = blockTickScheduler; - this.fluidTicks = fluidTickScheduler; -+ -+ this.lightningTick = this.level.getThreadUnsafeRandom().nextInt(100000) << 1; // Pufferfish - initialize lightning tick - } - - // CraftBukkit start -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -index 796bbef3544e06b8e7aac7e8ac5f740a2613f4bd..2422ca3ffc6ab7178cacf933b8013f85e7de4bd9 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -25,6 +25,7 @@ public class LevelChunkSection { - public final PalettedContainer states; - // CraftBukkit start - read/write - private PalettedContainer> biomes; -+ public short fluidStateCount; // Pufferfish - public final com.destroystokyo.paper.util.maplist.IBlockDataList tickingList = new com.destroystokyo.paper.util.maplist.IBlockDataList(); // Paper - // Paper start - optimise collisions - private int specialCollidingBlocks; -@@ -102,6 +103,7 @@ public class LevelChunkSection { - - if (!fluid.isEmpty()) { - --this.tickingFluidCount; -+ --this.fluidStateCount; // Pufferfish - } - - if (!state.isAir()) { -@@ -116,6 +118,7 @@ public class LevelChunkSection { - - if (!fluid1.isEmpty()) { - ++this.tickingFluidCount; -+ ++this.fluidStateCount; // Pufferfish - } - - this.updateBlockCallback(x, y, z, iblockdata1, state); // Paper - optimise collisions -@@ -162,6 +165,7 @@ public class LevelChunkSection { - if (fluid.isRandomlyTicking()) { - this.tickingFluidCount = (short) (this.tickingFluidCount + 1); - } -+ this.fluidStateCount++; // Pufferfish - } - - // Paper start - optimise collisions -diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java -index 83a39f900551e39d5af6f17a339a386ddee4feef..0c8c534fc69172387f188af5282accfed7597ac7 100644 ---- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java -+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java -@@ -9,7 +9,7 @@ import javax.annotation.Nullable; - import net.minecraft.world.entity.Entity; - - public class EntityTickList { -- private final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? -+ public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? // Pufferfish - private->public - - private void ensureActiveIsNotIterated() { - // Paper - replace with better logic, do not delay removals -diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -index 6d8ff6c06af5545634f255ed17dc1e489ece2548..6411aa4ff6bd4cabb25c426fa8f4a7eedb969c03 100644 ---- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -@@ -45,6 +45,8 @@ public abstract class FlowingFluid extends Fluid { - public static final BooleanProperty FALLING = BlockStateProperties.FALLING; - public static final IntegerProperty LEVEL = BlockStateProperties.LEVEL_FLOWING; - private static final int CACHE_SIZE = 200; -+ // Pufferfish start - use our own cache -+ /* - private static final ThreadLocal> OCCLUSION_CACHE = ThreadLocal.withInitial(() -> { - Object2ByteLinkedOpenHashMap object2bytelinkedopenhashmap = new Object2ByteLinkedOpenHashMap(200) { - protected void rehash(int i) {} -@@ -53,6 +55,14 @@ public abstract class FlowingFluid extends Fluid { - object2bytelinkedopenhashmap.defaultReturnValue((byte) 127); - return object2bytelinkedopenhashmap; - }); -+ */ -+ -+ private static final ThreadLocal> localFluidDirectionCache = ThreadLocal.withInitial(() -> { -+ // Pufferfish todo - mess with this number for performance -+ // with 2048 it seems very infrequent on a small world that it has to remove old entries -+ return new gg.airplane.structs.FluidDirectionCache<>(2048); -+ }); -+ // Pufferfish end - private final Map shapes = Maps.newIdentityHashMap(); - - public FlowingFluid() {} -@@ -251,6 +261,8 @@ public abstract class FlowingFluid extends Fluid { - return false; - } - // Paper end - optimise collisions -+ // Pufferfish start - modify to use our cache -+ /* - Object2ByteLinkedOpenHashMap object2bytelinkedopenhashmap; - - if (!state.getBlock().hasDynamicShape() && !fromState.getBlock().hasDynamicShape()) { -@@ -258,9 +270,16 @@ public abstract class FlowingFluid extends Fluid { - } else { - object2bytelinkedopenhashmap = null; - } -+ */ -+ gg.airplane.structs.FluidDirectionCache cache = null; -+ -+ if (!state.getBlock().hasDynamicShape() && !fromState.getBlock().hasDynamicShape()) { -+ cache = localFluidDirectionCache.get(); -+ } - - Block.BlockStatePairKey block_a; - -+ /* - if (object2bytelinkedopenhashmap != null) { - block_a = new Block.BlockStatePairKey(state, fromState, face); - byte b0 = object2bytelinkedopenhashmap.getAndMoveToFirst(block_a); -@@ -271,11 +290,22 @@ public abstract class FlowingFluid extends Fluid { - } else { - block_a = null; - } -+ */ -+ if (cache != null) { -+ block_a = new Block.BlockStatePairKey(state, fromState, face); -+ Boolean flag = cache.getValue(block_a); -+ if (flag != null) { -+ return flag; -+ } -+ } else { -+ block_a = null; -+ } - - VoxelShape voxelshape = state.getCollisionShape(world, pos); - VoxelShape voxelshape1 = fromState.getCollisionShape(world, fromPos); - boolean flag = !Shapes.mergedFaceOccludes(voxelshape, voxelshape1, face); - -+ /* - if (object2bytelinkedopenhashmap != null) { - if (object2bytelinkedopenhashmap.size() == 200) { - object2bytelinkedopenhashmap.removeLastByte(); -@@ -283,6 +313,11 @@ public abstract class FlowingFluid extends Fluid { - - object2bytelinkedopenhashmap.putAndMoveToFirst(block_a, (byte) (flag ? 1 : 0)); - } -+ */ -+ if (cache != null) { -+ cache.putValue(block_a, flag); -+ } -+ // Pufferfish end - - return flag; - } -diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootParams.java b/src/main/java/net/minecraft/world/level/storage/loot/LootParams.java -index 37a0002bbe6539648db5219bb373e0404ae48dc0..ca0571d232e102c4b177a1ea44b96f5f0f440211 100644 ---- a/src/main/java/net/minecraft/world/level/storage/loot/LootParams.java -+++ b/src/main/java/net/minecraft/world/level/storage/loot/LootParams.java -@@ -21,8 +21,10 @@ public class LootParams { - - public LootParams(ServerLevel world, Map, Object> parameters, Map dynamicDrops, float luck) { - this.level = world; -- this.params = parameters; -- this.dynamicDrops = dynamicDrops; -+ // Pufferfish start - use unmodifiable maps instead of immutable ones to skip the copy -+ this.params = java.util.Collections.unmodifiableMap(parameters); -+ this.dynamicDrops = java.util.Collections.unmodifiableMap(dynamicDrops); -+ // Pufferfish end - this.luck = luck; - } - -diff --git a/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java b/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java -index 88a4a72bb390947dc17e5da09a99b2d1b3ac4621..284c76ddb9724b44bb2e93f590685c728e843e6d 100644 ---- a/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java -+++ b/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java -@@ -17,50 +17,69 @@ public class EntityCollisionContext implements CollisionContext { - return defaultValue; - } - }; -- private final boolean descending; -- private final double entityBottom; -- private final ItemStack heldItem; -- private final Predicate canStandOnFluid; -+ // Pufferfish start - remove these and pray no plugin uses them -+ // private final boolean descending; -+ // private final double entityBottom; -+ // private final ItemStack heldItem; -+ // private final Predicate canStandOnFluid; -+ // Pufferfish end - @Nullable - private final Entity entity; - - protected EntityCollisionContext(boolean descending, double minY, ItemStack heldItem, Predicate walkOnFluidPredicate, @Nullable Entity entity) { -- this.descending = descending; -- this.entityBottom = minY; -- this.heldItem = heldItem; -- this.canStandOnFluid = walkOnFluidPredicate; -+ // Pufferfish start - remove these -+ // this.descending = descending; -+ // this.entityBottom = minY; -+ // this.heldItem = heldItem; -+ // this.canStandOnFluid = walkOnFluidPredicate; -+ // Pufferfish end - this.entity = entity; - } - - @Deprecated - protected EntityCollisionContext(Entity entity) { -- this( -- entity.isDescending(), -- entity.getY(), -- entity instanceof LivingEntity ? ((LivingEntity)entity).getMainHandItem() : ItemStack.EMPTY, -- entity instanceof LivingEntity ? ((LivingEntity)entity)::canStandOnFluid : fluidState -> false, -- entity -- ); -+ // Pufferfish start - remove this -+ // this( -+ // entity.isDescending(), -+ // entity.getY(), -+ // entity instanceof LivingEntity ? ((LivingEntity)entity).getMainHandItem() : ItemStack.EMPTY, -+ // entity instanceof LivingEntity ? ((LivingEntity)entity)::canStandOnFluid : fluidState -> false, -+ // entity -+ // ); -+ // Pufferfish end -+ this.entity = entity; - } - - @Override - public boolean isHoldingItem(Item item) { -- return this.heldItem.is(item); -+ // Pufferfish start -+ Entity entity = this.entity; -+ if (entity instanceof LivingEntity livingEntity) { -+ return livingEntity.getMainHandItem().is(item); -+ } -+ return ItemStack.EMPTY.is(item); -+ // Pufferfish end - } - - @Override - public boolean canStandOnFluid(FluidState stateAbove, FluidState state) { -- return this.canStandOnFluid.test(state) && !stateAbove.getType().isSame(state.getType()); -+ // Pufferfish start -+ Entity entity = this.entity; -+ if (entity instanceof LivingEntity livingEntity) { -+ return livingEntity.canStandOnFluid(state) && !stateAbove.getType().isSame(state.getType()); -+ } -+ return false; -+ // Pufferfish end - } - - @Override - public boolean isDescending() { -- return this.descending; -+ return this.entity != null && this.entity.isDescending(); // Pufferfish - } - - @Override - public boolean isAbove(VoxelShape shape, BlockPos pos, boolean defaultValue) { -- return this.entityBottom > (double)pos.getY() + shape.max(Direction.Axis.Y) - 1.0E-5F; -+ return (this.entity == null ? -Double.MAX_VALUE : entity.getY()) > (double)pos.getY() + shape.max(Direction.Axis.Y) - 1.0E-5F; // Pufferfish - } - - @Nullable -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index c490a29bcf7410bc54959ee71375605964379ed5..18bfe2fb7efad66f5fae07a30593d640c597bf77 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -266,7 +266,7 @@ import javax.annotation.Nullable; // Paper - import javax.annotation.Nonnull; // Paper - - public final class CraftServer implements Server { -- private final String serverName = "Paper"; // Paper -+ private final String serverName = "Pufferfish"; // Paper // Pufferfish - private final String serverVersion; - private final String bukkitVersion = Versioning.getBukkitVersion(); - private final Logger logger = Logger.getLogger("Minecraft"); -@@ -1137,6 +1137,11 @@ public final class CraftServer implements Server { - plugin.getPluginMeta().getDisplayName(), - "This plugin is not properly shutting down its async tasks when it is being shut down. This task may throw errors during the final shutdown logs and might not complete before process dies." - )); -+ getLogger().log(Level.SEVERE, String.format("%s Stacktrace", worker.getThread().getName())); -+ StackTraceElement[] stackTrace = worker.getThread().getStackTrace(); -+ for (StackTraceElement element : stackTrace) { -+ getLogger().log(Level.SEVERE, " " + element.toString()); -+ } - } - } - // Paper end - Wait for Async Tasks during shutdown -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java -index 96d772eb02f79f8c478f5e6f065e387aa7665b18..c5ce412f321b8b4f31cc042893659e213b081f29 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java -@@ -45,6 +45,6 @@ public class CraftShapelessRecipe extends ShapelessRecipe implements CraftRecipe - data.set(i, this.toNMS(ingred.get(i), true)); - } - -- MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data))); -+ MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data, true))); // Pufferfish - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 3c7a771c48cc2732cc038ca11bb93ec5f8c2d667..94681c5d807019be5caf0b5d5156c0d670f45f8f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -502,7 +502,7 @@ public final class CraftMagicNumbers implements UnsafeValues { - - @Override - public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { -- return new com.destroystokyo.paper.PaperVersionFetcher(); -+ return new gg.pufferfish.pufferfish.PufferfishVersionFetcher(); // Pufferfish - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -index 774556a62eb240da42e84db4502e2ed43495be17..80553face9c70c2a3d897681e7761df85b22d464 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -@@ -11,7 +11,7 @@ public final class Versioning { - public static String getBukkitVersion() { - String result = "Unknown-Version"; - -- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties"); -+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/gg.pufferfish.pufferfish/pufferfish-api/pom.properties"); // Pufferfish - Properties properties = new Properties(); - - if (stream != null) { -diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 3283ed99c35ffed6805567705e0518d9f84feedc..d7c7e12c0b8f77e59d94de130972f762ed227726 100644 ---- a/src/main/java/org/spigotmc/ActivationRange.java -+++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -38,6 +38,10 @@ import co.aikar.timings.MinecraftTimings; - import net.minecraft.world.entity.schedule.Activity; - import net.minecraft.world.level.Level; - import net.minecraft.world.phys.AABB; -+// Pufferfish start -+import net.minecraft.world.phys.Vec3; -+import java.util.List; -+// Pufferfish end - - public class ActivationRange - { -@@ -223,6 +227,25 @@ public class ActivationRange - } - // Paper end - Configurable marker ticking - ActivationRange.activateEntity(entity); -+ -+ // Pufferfish start -+ if (gg.pufferfish.pufferfish.PufferfishConfig.dearEnabled && entity.getType().dabEnabled) { -+ if (!entity.activatedPriorityReset) { -+ entity.activatedPriorityReset = true; -+ entity.activatedPriority = gg.pufferfish.pufferfish.PufferfishConfig.maximumActivationPrio; -+ } -+ Vec3 playerVec = player.position(); -+ Vec3 entityVec = entity.position(); -+ double diffX = playerVec.x - entityVec.x, diffY = playerVec.y - entityVec.y, diffZ = playerVec.z - entityVec.z; -+ int squaredDistance = (int) (diffX * diffX + diffY * diffY + diffZ * diffZ); -+ entity.activatedPriority = squaredDistance > gg.pufferfish.pufferfish.PufferfishConfig.startDistanceSquared ? -+ Math.max(1, Math.min(squaredDistance >> gg.pufferfish.pufferfish.PufferfishConfig.activationDistanceMod, entity.activatedPriority)) : -+ 1; -+ } else { -+ entity.activatedPriority = 1; -+ } -+ // Pufferfish end -+ - } - // Paper end - } -@@ -239,12 +262,12 @@ public class ActivationRange - if ( MinecraftServer.currentTick > entity.activatedTick ) - { - if ( entity.defaultActivationState ) -- { -+ { // Pufferfish - diff on change - entity.activatedTick = MinecraftServer.currentTick; - return; - } - if ( entity.activationType.boundingBox.intersects( entity.getBoundingBox() ) ) -- { -+ { // Pufferfish - diff on change - entity.activatedTick = MinecraftServer.currentTick; - } - } -@@ -298,7 +321,7 @@ public class ActivationRange - if ( entity instanceof LivingEntity ) - { - LivingEntity living = (LivingEntity) entity; -- if ( living.onClimbable() || living.jumping || living.hurtTime > 0 || living.activeEffects.size() > 0 || living.isFreezing()) // Paper -+ if ( living.onClimableCached() || living.jumping || living.hurtTime > 0 || living.activeEffects.size() > 0 || living.isFreezing() ) // Paper // Pufferfish - use cached - { - return 1; // Paper - } diff --git a/patches/server/0002-Purpur-Server-Changes.patch b/patches/server/0001-Purpur-Server-Patches.patch similarity index 86% rename from patches/server/0002-Purpur-Server-Changes.patch rename to patches/server/0001-Purpur-Server-Patches.patch index 2b85133..af38473 100644 --- a/patches/server/0002-Purpur-Server-Changes.patch +++ b/patches/server/0001-Purpur-Server-Patches.patch @@ -1,71 +1,49 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Fri, 26 Apr 2024 18:07:21 +0900 -Subject: [PATCH] Purpur Server Changes +From: AlphaKR93 +Date: Tue, 30 Apr 2024 23:09:48 +0900 +Subject: [PATCH] Purpur Server Patches -PurpurMC -Copyright (C) 2024 PurpurMC - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/build.gradle.kts b/build.gradle.kts -index 4517548e2c892c2e94f91e7449660f9e36b8f14e..1cad0728d005df9475a978b272adef9703f2ba46 100644 +index 5d448d8a7cf6626a11791f30ad52baf41a099272..81996f00384674b29368e8bea944bdd14d631da3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts -@@ -13,12 +13,12 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) { +@@ -12,8 +12,12 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) { val alsoShade: Configuration by configurations.creating dependencies { -- implementation(project(":pufferfish-api")) // Pufferfish // Paper -- // Pufferfish start -- implementation("io.papermc.paper:paper-mojangapi:1.19.2-R0.1-SNAPSHOT") { +- implementation(project(":paper-api")) +- implementation(project(":paper-mojangapi")) + // Purpur start + implementation(project(":purpur-api")) + implementation("io.papermc.paper:paper-mojangapi:${project.version}") { - exclude("io.papermc.paper", "paper-api") - } -- // Pufferfish end ++ exclude("io.papermc.paper", "paper-api") ++ } + // Purpur end // Paper start implementation("org.jline:jline-terminal-jansi:3.21.0") implementation("net.minecrell:terminalconsoleappender:1.3.0") -@@ -61,6 +61,10 @@ dependencies { - } - // Pufferfish end +@@ -47,6 +51,10 @@ dependencies { + runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") + runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") + 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 + testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") testImplementation("org.hamcrest:hamcrest:2.2") -@@ -90,7 +94,7 @@ tasks.jar { +@@ -79,7 +87,7 @@ tasks.jar { attributes( "Main-Class" to "org.bukkit.craftbukkit.Main", "Implementation-Title" to "CraftBukkit", -- "Implementation-Version" to "git-Pufferfish-$implementationVersion", // Pufferfish +- "Implementation-Version" to "git-Paper-$implementationVersion", + "Implementation-Version" to "git-Purpur-$implementationVersion", // Pufferfish // Purpur "Implementation-Vendor" to date, // Paper "Specification-Title" to "Bukkit", "Specification-Version" to project.version, -@@ -169,7 +173,7 @@ fun TaskContainer.registerRunTask( +@@ -138,7 +146,7 @@ fun TaskContainer.registerRunTask( name: String, block: JavaExec.() -> Unit ): TaskProvider = register(name) { @@ -166,14 +144,14 @@ index 0000000000000000000000000000000000000000..15a226e3854d731f7724025ea3459c8a + } +} diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java -index 692c962193cf9fcc6801fc93f3220bdc673d527b..8cde30544e14f8fc2dac32966ae3c21f8cf3a551 100644 +index 4b002e8b75d117b726b0de274a76d3596fce015b..8cde30544e14f8fc2dac32966ae3c21f8cf3a551 100644 --- a/src/main/java/com/destroystokyo/paper/Metrics.java +++ b/src/main/java/com/destroystokyo/paper/Metrics.java @@ -593,7 +593,7 @@ public class Metrics { boolean logFailedRequests = config.getBoolean("logFailedRequests", false); // Only start Metrics, if it's enabled in the config if (config.getBoolean("enabled", true)) { -- Metrics metrics = new Metrics("Pufferfish", serverUUID, logFailedRequests, Bukkit.getLogger()); // Pufferfish +- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger()); + Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Pufferfish // Purpur metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { @@ -187,11 +165,11 @@ index 692c962193cf9fcc6801fc93f3220bdc673d527b..8cde30544e14f8fc2dac32966ae3c21f - final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion(); - if (implVersion != null) { - final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1); -- paperVersion = "git-Pufferfish-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); // Pufferfish +- paperVersion = "git-Paper-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); - } else { - paperVersion = "unknown"; - } -- metrics.addCustomChart(new Metrics.SimplePie("pufferfish_version", () -> paperVersion)); // Pufferfish +- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> paperVersion)); + metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ? "bungee" : "offline"))); // Purpur + metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() != null) ? org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() : "unknown")); // Purpur @@ -305,7 +283,7 @@ index c5d5648f4ca603ef2b1df723b58f9caf4dd3c722..3cb56595822799926a8141e60a42f5d1 .completer(new ConsoleCommandCompleter(this.server)) .option(LineReader.Option.COMPLETE_IN_WORD, true); diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -index 59699c59fdfc611177fdb3136f84ab539b17d9c9..4819c043e193603581598c91d44d407a08ecd5fb 100644 +index c72d6bccf7d72d08d388c65936a89c92261c7860..ee746753515c9cea8dd246f4f56e6781956726c1 100644 --- a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java @@ -137,6 +137,10 @@ public class MobGoalHelper { @@ -332,63 +310,6 @@ index 039a86034928a5eb7aaa2d7ca76a7bddcca346bd..308f67d0616e2d6bb135258f1fda53cc setListData(vector); } -diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -index 6464682e2f93659e73aca491031c8051ab000033..8afc58f35deb49084a20b803e91ce4692ce6e4d6 100644 ---- a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -+++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -@@ -28,6 +28,7 @@ public class PufferfishConfig { - - private static final YamlFile config = new YamlFile(); - private static int updates = 0; -+ public static File pufferfishFile; // Purpur - - private static ConfigurationSection convertToBukkit(org.simpleyaml.configuration.ConfigurationSection section) { - ConfigurationSection newSection = new MemoryConfiguration(); -@@ -50,7 +51,7 @@ public class PufferfishConfig { - } - - public static void load() throws IOException { -- File configFile = new File("pufferfish.yml"); -+ File configFile = pufferfishFile; // Purpur - - if (configFile.exists()) { - try { -@@ -86,7 +87,7 @@ public class PufferfishConfig { - // Attempt to detect vectorization - try { - SIMDDetection.isEnabled = SIMDDetection.canEnable(PufferfishLogger.LOGGER); -- SIMDDetection.versionLimited = SIMDDetection.getJavaVersion() != 17 && SIMDDetection.getJavaVersion() != 18 && SIMDDetection.getJavaVersion() != 19; -+ SIMDDetection.versionLimited = SIMDDetection.getJavaVersion() < 17 || SIMDDetection.getJavaVersion() > 21; - } catch (NoClassDefFoundError | Exception ignored) { - ignored.printStackTrace(); - } -@@ -94,7 +95,7 @@ public class PufferfishConfig { - if (SIMDDetection.isEnabled) { - PufferfishLogger.LOGGER.info("SIMD operations detected as functional. Will replace some operations with faster versions."); - } else if (SIMDDetection.versionLimited) { -- PufferfishLogger.LOGGER.warning("Will not enable SIMD! These optimizations are only safely supported on Java 17, Java 18, and Java 19."); -+ PufferfishLogger.LOGGER.warning("Will not enable SIMD! These optimizations are only safely supported on Java 17 through Java 21."); - } else { - PufferfishLogger.LOGGER.warning("SIMD operations are available for your server, but are not configured!"); - PufferfishLogger.LOGGER.warning("To enable additional optimizations, add \"--add-modules=jdk.incubator.vector\" to your startup flags, BEFORE the \"-jar\"."); -@@ -232,7 +233,7 @@ public class PufferfishConfig { - public static int activationDistanceMod; - - private static void dynamicActivationOfBrains() throws IOException { -- dearEnabled = getBoolean("dab.enabled", "activation-range.enabled", true); -+ dearEnabled = getBoolean("dab.enabled", "activation-range.enabled", false); // Purpur - startDistance = getInt("dab.start-distance", "activation-range.start-distance", 12, - "This value determines how far away an entity has to be", - "from the player to start being effected by DEAR."); -@@ -276,7 +277,7 @@ public class PufferfishConfig { - - public static boolean throttleInactiveGoalSelectorTick; - private static void inactiveGoalSelectorThrottle() { -- throttleInactiveGoalSelectorTick = getBoolean("inactive-goal-selector-throttle", "inactive-goal-selector-disable", true, -+ throttleInactiveGoalSelectorTick = getBoolean("inactive-goal-selector-throttle", "inactive-goal-selector-disable", false, // Purpur - "Throttles the AI goal selector in entity inactive ticks.", - "This can improve performance by a few percent, but has minor gameplay implications."); - } diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..e1ffd62f4ebceecb9bc5471df3da406cffea0483 100644 --- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java @@ -406,7 +327,7 @@ index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..e1ffd62f4ebceecb9bc5471df3da406c private static final ThreadLocal> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>(); diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -index b66a7d4aab887309579154815a0d4abf9de506b0..e6f56bc5b129699bab60db9c97c7f73b6ede2351 100644 +index 56b07a3306e5735816c8d89601b519cb0db6379a..604de7aed6db44c9c84d541765e57da48883cf00 100644 --- a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java @@ -1779,7 +1779,7 @@ public final class NewChunkHolder { @@ -567,10 +488,10 @@ index a8e813ca89b033f061e695288b3383bdcf128531..1ab65af9359d19530bba7f985a604d2a } if (SysoutCatcher.NAG_INTERVAL > 0 || SysoutCatcher.NAG_TIMEOUT > 0) { diff --git a/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java b/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java -index 708e5bb9bbf0476fcc2c4b92c6830b094703b43e..6141f716b15ad47ac2ac4c9ce92a3897b3ad8807 100644 +index 6f14cb9a73faa1d0ae2939d08809d9f6c2a99e1d..4e98745670032038f7b4f8e1adabc1e00e7f15bf 100644 --- a/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java +++ b/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java -@@ -104,6 +104,7 @@ public class PluginInitializerManager { +@@ -112,6 +112,7 @@ public class PluginInitializerManager { @SuppressWarnings("unchecked") java.util.List files = ((java.util.List) optionSet.valuesOf("add-plugin")).stream().map(File::toPath).toList(); io.papermc.paper.plugin.util.EntrypointUtil.registerProvidersFromSource(io.papermc.paper.plugin.provider.source.PluginFlagProviderSource.INSTANCE, files); @@ -700,7 +621,7 @@ index 0000000000000000000000000000000000000000..cb78dac8e072b5cb3c6e52e17c9ecdf7 + } +} diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java -index 99c5038672b09d0874125e3df280174c1e8151e6..f91ea723a1c85f6cf8c4f6dd7f182b948c2f2e81 100644 +index 4f3cc14d48690bb183d09bb7a5ba1e23e8a0c08a..c366d84518979e842a6f10f969a5951539ecac93 100644 --- a/src/main/java/net/minecraft/CrashReport.java +++ b/src/main/java/net/minecraft/CrashReport.java @@ -125,6 +125,10 @@ public class CrashReport { @@ -715,7 +636,7 @@ index 99c5038672b09d0874125e3df280174c1e8151e6..f91ea723a1c85f6cf8c4f6dd7f182b94 stringbuilder.append(CrashReport.getErrorComment()); stringbuilder.append("\n\n"); diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index f341813e9713e39bfe142ca34b751de3d8efd25b..546ff84046856ecfe0f2a07d3ba3f886f8df4dca 100644 +index e6c7f62ed379a78645933670299e4fcda8540ed1..7475aaac2673729091eabc741c8ebb561aeec8f1 100644 --- a/src/main/java/net/minecraft/commands/CommandSourceStack.java +++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java @@ -230,6 +230,19 @@ public class CommandSourceStack implements ExecutionCommandSource parseresults, String s, String label) { // CraftBukkit CommandSourceStack commandlistenerwrapper = (CommandSourceStack) parseresults.getContext().getSource(); @@ -820,7 +741,7 @@ index b7f338e982d0dcab99137ab6dc200b82ac6b7cba..b203394ed62807e7d5df433830993f1d ContextChain contextchain = this.finishParsing(parseresults, s, commandlistenerwrapper, label); // CraftBukkit // Paper - Add UnknownCommandEvent try { -@@ -357,7 +365,7 @@ public class Commands { +@@ -358,7 +366,7 @@ public class Commands { Commands.LOGGER.error("'/{}' threw an exception", s, exception); } } finally { @@ -829,7 +750,7 @@ index b7f338e982d0dcab99137ab6dc200b82ac6b7cba..b203394ed62807e7d5df433830993f1d } } -@@ -506,6 +514,7 @@ public class Commands { +@@ -501,6 +509,7 @@ public class Commands { private void runSync(ServerPlayer player, Collection bukkit, RootCommandNode rootcommandnode) { // Paper end - Perf: Async command map building new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper - Brigadier API @@ -837,7 +758,7 @@ index b7f338e982d0dcab99137ab6dc200b82ac6b7cba..b203394ed62807e7d5df433830993f1d PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit)); event.getPlayer().getServer().getPluginManager().callEvent(event); -@@ -516,6 +525,7 @@ public class Commands { +@@ -511,6 +520,7 @@ public class Commands { } } // CraftBukkit end @@ -965,10 +886,10 @@ index e9775b4506909bee65a74964f0d5391a0513de1d..684f7f202305c09b1037c5d38a52a5ea } } diff --git a/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java b/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java -index b8fa8d5bb62a51281a8ec676066fb02ddeacbebf..682d6d8bd679106a6f07df31adb8dbc568c10d62 100644 +index 7b118a92a6eb779f800ae8f5d8f6e3c861fc4f6a..057a038e8dcacd7496a0b2373de2c20255a5c297 100644 --- a/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java +++ b/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java -@@ -116,10 +116,10 @@ public class ArgumentTypeInfos { +@@ -119,10 +119,10 @@ public class ArgumentTypeInfos { register(registry, "dimension", DimensionArgument.class, SingletonArgumentInfo.contextFree(DimensionArgument::dimension)); register(registry, "gamemode", GameModeArgument.class, SingletonArgumentInfo.contextFree(GameModeArgument::gameMode)); register(registry, "time", TimeArgument.class, new TimeArgument.Info()); @@ -984,10 +905,10 @@ index b8fa8d5bb62a51281a8ec676066fb02ddeacbebf..682d6d8bd679106a6f07df31adb8dbc5 register(registry, "template_rotation", TemplateRotationArgument.class, SingletonArgumentInfo.contextFree(TemplateRotationArgument::templateRotation)); register(registry, "heightmap", HeightmapTypeArgument.class, SingletonArgumentInfo.contextFree(HeightmapTypeArgument::heightmap)); diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java -index 70f9e737b3b9f80395afc3542aafe4a0c774c722..70fa9893c7af6387df9e5c33be21653e73222b36 100644 +index 665e88b2dedf9d5bb50914d5f3d377f2d19f40b0..f70a80b496bd1498778e82fc221c3b1b39308b75 100644 --- a/src/main/java/net/minecraft/core/BlockPos.java +++ b/src/main/java/net/minecraft/core/BlockPos.java -@@ -47,6 +47,12 @@ public class BlockPos extends Vec3i { +@@ -61,6 +61,12 @@ public class BlockPos extends Vec3i { private static final int X_OFFSET = 38; // Paper end - Optimize Bit Operations by inlining @@ -1001,10 +922,10 @@ index 70f9e737b3b9f80395afc3542aafe4a0c774c722..70fa9893c7af6387df9e5c33be21653e super(x, y, z); } diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index e2e1273d787536d2fe1bdbbf8af36eb5ac220599..a3fe92e1db6755a9111ab58e84d61f429d72010f 100644 +index 5dab1e10303177e5a4d97a91ee46ede66f30ae35..68236139e3571791b891dbbef6e3ee20031e16d9 100644 --- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -1203,6 +1203,23 @@ public interface DispenseItemBehavior { +@@ -1048,5 +1048,22 @@ public interface DispenseItemBehavior { } } }); @@ -1012,7 +933,7 @@ index e2e1273d787536d2fe1bdbbf8af36eb5ac220599..a3fe92e1db6755a9111ab58e84d61f42 + DispenserBlock.registerBehavior(Items.ANVIL, (new OptionalDispenseItemBehavior() { + @Override + public ItemStack execute(BlockSource dispenser, ItemStack stack) { -+ Level level = dispenser.level(); ++ net.minecraft.world.level.Level level = dispenser.level(); + if (!level.purpurConfig.dispenserPlaceAnvils) return super.execute(dispenser, stack); + Direction facing = dispenser.blockEntity().getBlockState().getValue(DispenserBlock.FACING); + BlockPos pos = dispenser.pos().relative(facing); @@ -1026,26 +947,25 @@ index e2e1273d787536d2fe1bdbbf8af36eb5ac220599..a3fe92e1db6755a9111ab58e84d61f42 + })); + // Purpur end } - - static Vec3 getEntityPokingOutOfBlockPos(BlockSource pointer, EntityType entityType, Direction direction) { + } diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -index 8d65cdb013706a932c2c73231108b2810b99e1c7..5b1938fc849db743e65cd7eed0f83ba059b9525e 100644 +index a024c697a65bbab27408da1d6a75e531d9719b47..e4fab82b369f2c2ea0d8c8acd814d06140d551fc 100644 --- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java +++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -@@ -104,7 +104,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { +@@ -105,7 +105,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { if (ishearable.readyForShearing()) { // CraftBukkit start // Paper start - Add drops to shear events - org.bukkit.event.block.BlockShearEntityEvent event = CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem, ishearable.generateDefaultDrops()); -+ org.bukkit.event.block.BlockShearEntityEvent event = CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem, ishearable.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.MOB_LOOTING, CraftItemStack.asNMSCopy(craftItem)))); // Purpur ++ org.bukkit.event.block.BlockShearEntityEvent event = CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem, ishearable.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.LOOTING, CraftItemStack.asNMSCopy(craftItem)))); // Purpur if (event.isCancelled()) { // Paper end - Add drops to shear events continue; diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index a536ebcf29d8ef0ed32863bd8d5e70f7a0636e8d..9e31954212b1d6162dca2fbc91d373e908560335 100644 +index 58d28b6c1cc7da7d786f78308db971f7502ad844..9f274048be29ed54dd91983447beadf076cf7438 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java -@@ -570,11 +570,20 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -607,11 +607,20 @@ public class Connection extends SimpleChannelInboundHandler> { 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 @@ -1066,42 +986,11 @@ index a536ebcf29d8ef0ed32863bd8d5e70f7a0636e8d..9e31954212b1d6162dca2fbc91d373e9 Connection.joinAttemptsThisTick = 0; } // Paper end - Buffer joins to world -diff --git a/src/main/java/net/minecraft/network/FriendlyByteBuf.java b/src/main/java/net/minecraft/network/FriendlyByteBuf.java -index b863249ff7e13cf4939c8961601f0564c62fd661..bdcfd80f937c34956911373905d66424bbff8e1d 100644 ---- a/src/main/java/net/minecraft/network/FriendlyByteBuf.java -+++ b/src/main/java/net/minecraft/network/FriendlyByteBuf.java -@@ -95,6 +95,8 @@ public class FriendlyByteBuf extends ByteBuf { - private static final int MAX_PUBLIC_KEY_LENGTH = 512; - private static final Gson GSON = new Gson(); - -+ public static boolean hasItemSerializeEvent = false; // Purpur -+ - public FriendlyByteBuf(ByteBuf parent) { - this.source = parent; - } -@@ -640,6 +642,17 @@ public class FriendlyByteBuf extends ByteBuf { - this.writeBoolean(false); - } else { - this.writeBoolean(true); -+ // Purpur start -+ if (hasItemSerializeEvent) { -+ var event = new org.purpurmc.purpur.event.packet.NetworkItemSerializeEvent(stack.asBukkitCopy()); -+ event.callEvent(); -+ ItemStack newStack = ItemStack.fromBukkitCopy(event.getItemStack()); -+ if (org.purpurmc.purpur.PurpurConfig.fixNetworkSerializedItemsInCreative && !ItemStack.matches(stack, newStack)) { -+ stack.save(newStack.getOrCreateTagElement("Purpur.OriginalItem")); -+ } -+ stack = newStack; -+ } -+ // Purpur end - Item item = stack.getItem(); - - this.writeId(BuiltInRegistries.ITEM, item); diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -index 83302c252f54481f239522e5c6861ccfe233070a..620edb63cacd15e38f7fc859efd4095bfb5e5f72 100644 +index 57e76b53e5e314c3e6b8856010f7a84188121582..8c134a642ccaf3530022f2e675a858d726e1dda4 100644 --- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java +++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -@@ -50,7 +50,7 @@ public class PacketUtils { +@@ -51,7 +51,7 @@ public class PacketUtils { if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players if (listener.shouldHandleMessage(packet)) { co.aikar.timings.Timing timing = co.aikar.timings.MinecraftTimings.getPacketTiming(packet); // Paper - timings @@ -1109,14 +998,14 @@ index 83302c252f54481f239522e5c6861ccfe233070a..620edb63cacd15e38f7fc859efd4095b + try { // Paper - timings // Purpur packet.handle(listener); } catch (Exception exception) { - label25: + if (exception instanceof ReportedException) { diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTimePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTimePacket.java -index 9ec6145fe04ec64bbee8ec6a837719caebdbc6f5..358d610ad020cada1bb83e393deeeaaec05a2791 100644 +index 76ef195a5074006b009acd9cc1744667c6aecbb9..659577549e132754281df76a7a1bfd884443c56a 100644 --- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTimePacket.java +++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTimePacket.java -@@ -5,7 +5,7 @@ import net.minecraft.network.protocol.Packet; - - public class ClientboundSetTimePacket implements Packet { +@@ -10,7 +10,7 @@ public class ClientboundSetTimePacket implements Packet processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); public int autosavePeriod; public Commands vanillaCommandDispatcher; -@@ -303,11 +304,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && this.tickCount % autosavePeriod == 0; try { this.isSaving = true; -@@ -1556,20 +1582,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { entityplayer.connection.suspendFlushing(); }); @@ -1413,7 +1300,7 @@ index b9e0a32f5829ca15f949effcafcbe2a975f6f690..60b5e0643d933393b5473681ac9261db // Paper start - Folia scheduler API ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) Bukkit.getGlobalRegionScheduler()).tick(); getAllLevels().forEach(level -> { -@@ -1667,22 +1693,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Purpur Iterator iterator = this.getAllLevels().iterator(); // Paper - Throw exception on world create while being ticked; move down - while (iterator.hasNext()) { - ServerLevel worldserver = (ServerLevel) iterator.next(); -@@ -1712,29 +1739,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - Add EntityMoveEvent net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers worldserver.updateLagCompensationTick(); // Paper - lag compensation @@ -1472,7 +1356,9 @@ index b9e0a32f5829ca15f949effcafcbe2a975f6f690..60b5e0643d933393b5473681ac9261db - this.profiler.push(() -> { + /*this.profiler.push(() -> { // Purpur - return worldserver + " " + worldserver.dimension().location(); + String s = String.valueOf(worldserver); + + return s + " " + String.valueOf(worldserver.dimension().location()); - }); + });*/ // Purpur /* Drop global time updates @@ -1502,7 +1388,7 @@ index b9e0a32f5829ca15f949effcafcbe2a975f6f690..60b5e0643d933393b5473681ac9261db } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world"); -@@ -1742,33 +1770,33 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop // Paper +- return "Paper"; // Paper + return org.purpurmc.purpur.PurpurConfig.serverModName; // Purpur - Purpur > // Pufferfish > // Paper } public SystemReport fillSystemReport(SystemReport details) { -@@ -2459,7 +2487,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { this.executeBlocking(() -> { this.saveDebugReport(path.resolve("server")); -@@ -2711,40 +2739,40 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { + /*gameprofilerfiller.push(() -> { // Purpur - return "function " + function.id(); + return "function " + String.valueOf(function.id()); - }); + });*/ // Purpur try { - InstantiatedFunction instantiatedfunction = function.instantiate((CompoundTag) null, this.getDispatcher(), source); + InstantiatedFunction instantiatedfunction = function.instantiate((CompoundTag) null, this.getDispatcher()); @@ -86,7 +86,7 @@ public class ServerFunctionManager { } catch (Exception exception) { ServerFunctionManager.LOGGER.warn("Failed to execute function {}", function.id(), exception); @@ -1741,7 +1626,7 @@ index df0c15f6b5b2224d53e4f8fad42b9a1e5f33dc25..92aa26881818fec92d0663e2ccf50716 } diff --git a/src/main/java/net/minecraft/server/commands/EnchantCommand.java b/src/main/java/net/minecraft/server/commands/EnchantCommand.java -index 15bfe2e58d16864af29b04c17181ebf45fa21eba..8b0c61bcdb8e00dda6fb8f43e6d74711361eba9c 100644 +index 84f1ba6275f04624f46ccd772924b5e075e7b205..bfb455fb74f0a9645212f90acb54f68d1c7d9772 100644 --- a/src/main/java/net/minecraft/server/commands/EnchantCommand.java +++ b/src/main/java/net/minecraft/server/commands/EnchantCommand.java @@ -70,7 +70,7 @@ public class EnchantCommand { @@ -1757,8 +1642,8 @@ index 15bfe2e58d16864af29b04c17181ebf45fa21eba..8b0c61bcdb8e00dda6fb8f43e6d74711 ItemStack itemStack = livingEntity.getMainHandItem(); if (!itemStack.isEmpty()) { if (enchantment2.canEnchant(itemStack) -- && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantments(itemStack).keySet(), enchantment2)) { -+ && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantments(itemStack).keySet(), enchantment2) || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchantCommand && !itemStack.hasEnchantment(enchantment2))) { // Purpur +- && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(itemStack).keySet(), enchantment2)) { ++ && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(itemStack).keySet(), enchantment2) || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchantCommand && !itemStack.hasEnchantment(enchantment2))) { // Purpur itemStack.enchant(enchantment2, level); i++; } else if (targets.size() == 1) { @@ -1786,22 +1671,22 @@ index d1da3600dc07107309b20ebe6e7c0c4da0e8de76..244b4719c689f153fa36381a60acc280 for (ServerPlayer serverPlayer : targets) { diff --git a/src/main/java/net/minecraft/server/commands/GiveCommand.java b/src/main/java/net/minecraft/server/commands/GiveCommand.java -index 1b459a8ee8a6bc039e742d65796bc76660a1c765..599172b994d75484f7c7e0ce6d3d3d771c1c44d0 100644 +index 47355158e5e762540a10dc67b23092a0fc53bce3..9f1c8a62bda242781a0966fa2fc01534261423c7 100644 --- a/src/main/java/net/minecraft/server/commands/GiveCommand.java +++ b/src/main/java/net/minecraft/server/commands/GiveCommand.java -@@ -59,6 +59,7 @@ public class GiveCommand { +@@ -92,6 +92,7 @@ public class GiveCommand { boolean flag = entityplayer.getInventory().add(itemstack1); ItemEntity entityitem; + if (org.purpurmc.purpur.PurpurConfig.disableGiveCommandDrops) continue; // Purpur - add config option for toggling give command dropping if (flag && itemstack1.isEmpty()) { - itemstack1.setCount(1); - entityitem = entityplayer.drop(itemstack1, false, false, false); // CraftBukkit - SPIGOT-2942: Add boolean to call event + entityitem = entityplayer.drop(itemstack, false, false, false); // CraftBukkit - SPIGOT-2942: Add boolean to call event + if (entityitem != null) { diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 435b129c433704c24828d8fb57e14333c9423207..5ca6af93362d205438f8321ee2461ae7f8160df1 100644 +index eb4fc900164d1fb3a78653ae8bc42ea30323f5b7..775c5de4f5094260096cef6723dd50dfe2cb0c81 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -99,6 +99,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -110,6 +110,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface return; } // Paper start - Use TerminalConsoleAppender @@ -1809,7 +1694,7 @@ index 435b129c433704c24828d8fb57e14333c9423207..5ca6af93362d205438f8321ee2461ae7 new com.destroystokyo.paper.console.PaperConsole(DedicatedServer.this).start(); /* jline.console.ConsoleReader bufferedreader = DedicatedServer.this.reader; -@@ -219,8 +220,18 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -232,6 +233,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface thread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics @@ -1824,11 +1709,8 @@ index 435b129c433704c24828d8fb57e14333c9423207..5ca6af93362d205438f8321ee2461ae7 + // Purpur end com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // Paper - init PaperBrigadierProvider -+ gg.pufferfish.pufferfish.PufferfishConfig.pufferfishFile = (java.io.File) options.valueOf("pufferfish-settings"); // Purpur - gg.pufferfish.pufferfish.PufferfishConfig.load(); // Pufferfish - gg.pufferfish.pufferfish.PufferfishCommand.init(); // Pufferfish -@@ -270,6 +281,30 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -281,6 +291,30 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface if (true) throw new IllegalStateException("Failed to bind to port", ioexception); // Paper - Propagate failed to bind to port error return false; } @@ -1859,16 +1741,16 @@ index 435b129c433704c24828d8fb57e14333c9423207..5ca6af93362d205438f8321ee2461ae7 // CraftBukkit start // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // Spigot - moved up -@@ -342,6 +377,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -354,6 +388,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + DedicatedServer.LOGGER.info("JMX monitoring enabled"); } - if (gg.pufferfish.pufferfish.PufferfishConfig.enableAsyncMobSpawning) mobSpawnExecutor.start(); // Pufferfish + org.purpurmc.purpur.task.BossBarTask.startAll(); // Purpur + if (org.purpurmc.purpur.PurpurConfig.beeCountPayload) org.purpurmc.purpur.task.BeehiveTask.instance().register(); // Purpur return true; } } -@@ -488,7 +525,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -506,7 +542,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface } public void handleConsoleInputs() { @@ -1877,7 +1759,7 @@ index 435b129c433704c24828d8fb57e14333c9423207..5ca6af93362d205438f8321ee2461ae7 // Paper start - Perf: use proper queue ConsoleInput servercommand; while ((servercommand = this.serverCommandQueue.poll()) != null) { -@@ -505,7 +542,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -523,7 +559,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface // CraftBukkit end } @@ -1887,10 +1769,10 @@ index 435b129c433704c24828d8fb57e14333c9423207..5ca6af93362d205438f8321ee2461ae7 @Override diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java -index bab2471616404821671264ccefd729cab8d0bf58..ae75edfaa9e4c72f11fbb7ffc66294be47c206cc 100644 +index 9d10cdacb3aed2c00dc60aeb6f2cbeb48905e21f..842f382de43df5d5c321422372ec30ccdd7859d7 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java -@@ -57,6 +57,7 @@ public class DedicatedServerProperties extends Settings list = Lists.newArrayList(); List list1 = this.level.players(); ObjectIterator objectiterator = this.entityMap.values().iterator(); @@ -2119,7 +2001,7 @@ index 1081e9df44bb24b2c51ebd9364c21c7b2a3a205a..bb412ca874b85d777c0e3565fcefcee1 ChunkMap.TrackedEntity playerchunkmap_entitytracker; -@@ -1198,17 +1198,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1214,17 +1214,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider playerchunkmap_entitytracker.serverEntity.sendChanges(); } } @@ -2141,10 +2023,10 @@ index 1081e9df44bb24b2c51ebd9364c21c7b2a3a205a..bb412ca874b85d777c0e3565fcefcee1 } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f36005536e 100644 +index b99f50604bafecbc68835974c9ed0caa91911a40..476a04d87a61b021816d2970e86042bde32d95a2 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -264,16 +264,16 @@ public class ServerChunkCache extends ChunkSource { +@@ -259,14 +259,14 @@ public class ServerChunkCache extends ChunkSource { return ifLoaded; } // Paper end - Perf: Optimise getChunkAt calls for loaded chunks @@ -2155,16 +2037,14 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 + //gameprofilerfiller.incrementCounter("getChunk"); // Purpur long k = ChunkPos.asLong(x, z); - ChunkAccess ichunkaccess; - // Paper - rewrite chunk system - there are no correct callbacks to remove items from cache in the new chunk system - gameprofilerfiller.incrementCounter("getChunkCacheMiss"); + //gameprofilerfiller.incrementCounter("getChunkCacheMiss"); // Purpur - CompletableFuture> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create, true); // Paper + CompletableFuture> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create); ServerChunkCache.MainThreadExecutor chunkproviderserver_b = this.mainThreadProcessor; -@@ -281,10 +281,10 @@ public class ServerChunkCache extends ChunkSource { +@@ -274,10 +274,10 @@ public class ServerChunkCache extends ChunkSource { if (!completablefuture.isDone()) { // Paper io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.pushChunkWait(this.level, x1, z1); // Paper - rewrite chunk system com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads @@ -2175,9 +2055,9 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 - this.level.timings.syncChunkLoad.stopTiming(); // Paper + //this.level.timings.syncChunkLoad.stopTiming(); // Paper // Purpur } // Paper - ichunkaccess = (ChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { - return ichunkaccess1; -@@ -433,17 +433,17 @@ public class ServerChunkCache extends ChunkSource { + ChunkResult chunkresult = (ChunkResult) completablefuture.join(); + ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error +@@ -425,17 +425,17 @@ public class ServerChunkCache extends ChunkSource { public void save(boolean flush) { this.runDistanceManagerUpdates(); @@ -2199,7 +2079,7 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 } // Paper end - Incremental chunk and player saving -@@ -467,37 +467,37 @@ public class ServerChunkCache extends ChunkSource { +@@ -459,40 +459,39 @@ public class ServerChunkCache extends ChunkSource { // CraftBukkit start - modelled on below public void purgeUnload() { if (true) return; // Paper - tickets will be removed later, this behavior isn't really well accounted for by the chunk system @@ -2222,7 +2102,10 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 - this.level.timings.doChunkMap.startTiming(); // Spigot + //this.level.getProfiler().push("purge"); // Purpur + //this.level.timings.doChunkMap.startTiming(); // Spigot // Purpur - this.distanceManager.purgeStaleTickets(); + if (this.level.tickRateManager().runsNormally() || !tickChunks) { + this.distanceManager.purgeStaleTickets(); + } +- this.runDistanceManagerUpdates(); - this.level.timings.doChunkMap.stopTiming(); // Spigot - this.level.getProfiler().popPush("chunks"); @@ -2250,7 +2133,7 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 this.clearCache(); } -@@ -507,19 +507,19 @@ public class ServerChunkCache extends ChunkSource { +@@ -502,18 +501,18 @@ public class ServerChunkCache extends ChunkSource { this.lastInhabitedUpdate = i; if (!this.level.isDebug()) { @@ -2267,8 +2150,7 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 // Paper - optimise chunk tick iteration - this.level.resetIceAndSnowTick(); // Pufferfish - reset ice & snow tick random - if (this.level.getServer().tickRateManager().runsNormally()) { + if (this.level.tickRateManager().runsNormally()) { - gameprofilerfiller.popPush("naturalSpawnCount"); - this.level.timings.countNaturalMobs.startTiming(); // Paper - timings + //gameprofilerfiller.popPush("naturalSpawnCount"); // Purpur @@ -2276,20 +2158,20 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 int k = this.distanceManager.getNaturalSpawnChunkCount(); // Paper start - Optional per player mob spawns int naturalSpawnChunkCount = k; -@@ -549,10 +549,10 @@ public class ServerChunkCache extends ChunkSource { - // Pufferfish end +@@ -538,10 +537,10 @@ public class ServerChunkCache extends ChunkSource { + spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); } // Paper end - Optional per player mob spawns - this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings + // this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings // Purpur - // this.lastSpawnState = spawnercreature_d; // Pufferfish - this is managed asynchronously + this.lastSpawnState = spawnercreature_d; - gameprofilerfiller.popPush("spawnAndTick"); + //gameprofilerfiller.popPush("spawnAndTick"); // Purpur boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit // Paper start - optimise chunk tick iteration -@@ -658,19 +658,19 @@ public class ServerChunkCache extends ChunkSource { +@@ -647,19 +646,19 @@ public class ServerChunkCache extends ChunkSource { } } // Paper end - optimise chunk tick iteration @@ -2315,7 +2197,7 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 // Paper start - optimise chunk tick iteration if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) { it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet copy = this.chunkMap.needsChangeBroadcasting.clone(); -@@ -684,10 +684,10 @@ public class ServerChunkCache extends ChunkSource { +@@ -673,10 +672,10 @@ public class ServerChunkCache extends ChunkSource { } } // Paper end - optimise chunk tick iteration @@ -2327,9 +2209,9 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 + //gameprofilerfiller.pop(); // Purpur + //gameprofilerfiller.pop(); // Purpur } - - // Pufferfish start - optimize mob spawning -@@ -893,7 +893,7 @@ public class ServerChunkCache extends ChunkSource { + } + +@@ -848,7 +847,7 @@ public class ServerChunkCache extends ChunkSource { @Override protected void doRunTask(Runnable task) { @@ -2339,10 +2221,10 @@ index 1cf8c819c0d7776c3b33d6594ca81abe3c2a719d..7b3ba500f465b999ce11964b0e4e30f3 } diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index db55ad9aaabfa1ea998754f3ac352d1698936696..04b98e23eed926d8473cc2464e04a5b9f18f1140 100644 +index 4f103f731623a8570238a6867fda1c5f83fca4e4..39e7dcf3c92c9203c190782be401c00c010b8aeb 100644 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java +++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -73,7 +73,7 @@ public class ServerEntity { +@@ -77,7 +77,7 @@ public class ServerEntity { @Nullable private List> trackedDataValues; // CraftBukkit start @@ -2352,10 +2234,10 @@ index db55ad9aaabfa1ea998754f3ac352d1698936696..04b98e23eed926d8473cc2464e04a5b9 public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer> consumer, Set trackedPlayers) { this.trackedPlayers = trackedPlayers; diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7954f1b26 100644 +index 0981d440d0dbfe4df668d1f3f1b5706a93bc4434..f72af2feb74626abbdfbfd090c15357457810240 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -215,6 +215,8 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -220,6 +220,8 @@ public class ServerLevel extends Level implements WorldGenLevel { private final StructureManager structureManager; private final StructureCheck structureCheck; private final boolean tickTime; @@ -2364,7 +2246,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 private final RandomSequences randomSequences; public long lastMidTickExecuteFailure; // Paper - execute chunk tasks mid tick -@@ -224,6 +226,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -229,6 +231,7 @@ public class ServerLevel extends Level implements WorldGenLevel { 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) @@ -2372,7 +2254,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 public LevelChunk getChunkIfLoaded(int x, int z) { return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately -@@ -707,7 +710,24 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -713,7 +716,24 @@ public class ServerLevel extends Level implements WorldGenLevel { this.dragonParts = new Int2ObjectOpenHashMap(); this.tickTime = flag1; this.server = minecraftserver; @@ -2398,7 +2280,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 this.serverLevelData = iworlddataserver; ChunkGenerator chunkgenerator = worlddimension.generator(); // CraftBukkit start -@@ -769,6 +789,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -775,6 +795,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.chunkTaskScheduler = new io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler(this, io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.workerThreads); // Paper - rewrite chunk system this.entityLookup = new io.papermc.paper.chunk.system.entity.EntityLookup(this, new EntityCallbacks()); // Paper - rewrite chunk system @@ -2406,7 +2288,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 } // Paper start -@@ -803,23 +824,23 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -809,23 +830,23 @@ public class ServerLevel extends Level implements WorldGenLevel { } public void tick(BooleanSupplier shouldKeepTicking) { @@ -2434,7 +2316,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 // CraftBukkit start j = this.levelData.getDayTime() + 24000L; TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (j - j % 24000L) - this.getDayTime()); -@@ -844,38 +865,38 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -850,38 +871,38 @@ public class ServerLevel extends Level implements WorldGenLevel { this.tickTime(); } @@ -2489,7 +2371,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 boolean flag1 = !paperConfig().unsupportedSettings.disableWorldTickingWhenEmpty || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players // Paper - restore this if (flag1) { -@@ -883,25 +904,25 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -889,24 +910,24 @@ public class ServerLevel extends Level implements WorldGenLevel { } if (flag1 || this.emptyTime++ < 300) { @@ -2509,7 +2391,6 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 - this.timings.entityTick.startTiming(); // Spigot + //this.timings.entityTick.startTiming(); // Spigot // Purpur this.entityTickList.forEach((entity) -> { - entity.activatedPriorityReset = false; // Pufferfish - DAB if (!entity.isRemoved()) { if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed entity.discard(); @@ -2522,19 +2403,13 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 if (true || this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { // Paper - now always true if in the ticking list Entity entity1 = entity.getVehicle(); -@@ -913,7 +934,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -918,22 +939,21 @@ public class ServerLevel extends Level implements WorldGenLevel { entity.stopRiding(); } - gameprofilerfiller.push("tick"); + //gameprofilerfiller.push("tick"); // Purpur - // Pufferfish start - copied from this.guardEntityTick - try { - this.tickNonPassenger(entity); // Pufferfish - changed -@@ -928,20 +949,19 @@ public class ServerLevel extends Level implements WorldGenLevel { - // Paper end - } - // Pufferfish end + this.guardEntityTick(this::tickNonPassenger, entity); - gameprofilerfiller.pop(); + //gameprofilerfiller.pop(); // Purpur } @@ -2557,7 +2432,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 } @Override -@@ -959,6 +979,13 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -951,6 +971,13 @@ public class ServerLevel extends Level implements WorldGenLevel { this.serverLevelData.setGameTime(i); this.serverLevelData.getScheduledEvents().tick(this.server, i); if (this.levelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { @@ -2571,7 +2446,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 this.setDayTime(this.levelData.getDayTime() + 1L); } -@@ -967,7 +994,21 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -959,7 +986,21 @@ public class ServerLevel extends Level implements WorldGenLevel { public void setDayTime(long timeOfDay) { this.serverLevelData.setDayTime(timeOfDay); @@ -2593,16 +2468,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 public void tickCustomSpawners(boolean spawnMonsters, boolean spawnAnimals) { Iterator iterator = this.customSpawners.iterator(); -@@ -992,7 +1033,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - // Paper start - optimise random block ticking - private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); -- // private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); // Pufferfish - moved to super -+ private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong()); public net.minecraft.util.RandomSource getThreadUnsafeRandom() { return this.randomTickRandom; } // Pufferfish - moved to super // Purpur - dont break ABI - // Paper end - - private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Pufferfish -@@ -1002,9 +1043,9 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -992,9 +1033,9 @@ public class ServerLevel extends Level implements WorldGenLevel { boolean flag = this.isRaining(); int j = chunkcoordintpair.getMinBlockX(); int k = chunkcoordintpair.getMinBlockZ(); @@ -2613,8 +2479,8 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 + //gameprofilerfiller.push("thunder"); // Purpur final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change - if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && /*this.random.nextInt(this.spigotConfig.thunderChance) == 0 &&*/ chunk.shouldDoLightning(this.random)) { // Spigot // Paper - Option to disable thunder // Pufferfish - replace random with shouldDoLightning -@@ -1015,10 +1056,18 @@ public class ServerLevel extends Level implements WorldGenLevel { + if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder +@@ -1005,10 +1046,18 @@ public class ServerLevel extends Level implements WorldGenLevel { boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper - Configurable spawn chances for skeleton horses if (flag1) { @@ -2635,7 +2501,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 entityhorseskeleton.setAge(0); entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()); this.addFreshEntity(entityhorseskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit -@@ -1035,7 +1084,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1025,7 +1074,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } } @@ -2644,7 +2510,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 if (!this.paperConfig().environment.disableIceAndSnow) { // Paper - Option to disable ice and snow for (int l = 0; l < randomTickSpeed; ++l) { -@@ -1048,8 +1097,8 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1038,8 +1087,8 @@ public class ServerLevel extends Level implements WorldGenLevel { } } // Paper - Option to disable ice and snow @@ -2655,7 +2521,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 if (randomTickSpeed > 0) { // Paper start - optimize random block ticking LevelChunkSection[] sections = chunk.getSections(); -@@ -1083,8 +1132,8 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1073,8 +1122,8 @@ public class ServerLevel extends Level implements WorldGenLevel { } // Paper end - optimise random block ticking @@ -2666,7 +2532,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 } @VisibleForTesting -@@ -1142,7 +1191,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1132,7 +1181,7 @@ public class ServerLevel extends Level implements WorldGenLevel { return holder.is(PoiTypes.LIGHTNING_ROD); }, (blockposition1) -> { return blockposition1.getY() == this.getHeight(Heightmap.Types.WORLD_SURFACE, blockposition1.getX(), blockposition1.getZ()) - 1; @@ -2675,7 +2541,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 return optional.map((blockposition1) -> { return blockposition1.above(1); -@@ -1191,11 +1240,27 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1181,11 +1230,27 @@ public class ServerLevel extends Level implements WorldGenLevel { if (this.canSleepThroughNights()) { if (!this.getServer().isSingleplayer() || this.getServer().isPublished()) { int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); @@ -2704,7 +2570,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 ichatmutablecomponent = Component.translatable("sleep.players_sleeping", this.sleepStatus.amountSleeping(), this.sleepStatus.sleepersNeeded(i)); } -@@ -1335,6 +1400,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1325,6 +1390,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @VisibleForTesting public void resetWeatherCycle() { // CraftBukkit start @@ -2712,7 +2578,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 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.... -@@ -1342,6 +1408,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1332,6 +1398,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.serverLevelData.setRainTime(0); } // CraftBukkit end @@ -2720,7 +2586,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 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. -@@ -1409,24 +1476,24 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1399,24 +1466,24 @@ public class ServerLevel extends Level implements WorldGenLevel { // Spigot end // Paper start- timings final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity); @@ -2753,7 +2619,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 Iterator iterator = entity.getPassengers().iterator(); while (iterator.hasNext()) { -@@ -1449,17 +1516,17 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1439,17 +1506,17 @@ public class ServerLevel extends Level implements WorldGenLevel { if (passenger instanceof Player || this.entityTickList.contains(passenger)) { // Paper - EAR 2 final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(passenger); @@ -2777,7 +2643,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 // Paper start - EAR 2 if (isActive) { passenger.rideTick(); -@@ -1471,7 +1538,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1461,7 +1528,7 @@ public class ServerLevel extends Level implements WorldGenLevel { vehicle.positionRider(passenger); } // Paper end - EAR 2 @@ -2786,7 +2652,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 Iterator iterator = passenger.getPassengers().iterator(); while (iterator.hasNext()) { -@@ -1480,7 +1547,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1470,7 +1537,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.tickPassenger(passenger, entity2); } @@ -2795,7 +2661,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 } } else { passenger.stopRiding(); -@@ -1500,14 +1567,14 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1490,14 +1557,14 @@ public class ServerLevel extends Level implements WorldGenLevel { org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); } @@ -2813,7 +2679,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 // Copied from save() // CraftBukkit start - moved from MinecraftServer.saveChunks -@@ -1519,7 +1586,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1509,7 +1576,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData()); } // CraftBukkit end @@ -2822,7 +2688,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 } // Paper end - Incremental chunk and player saving -@@ -1533,7 +1600,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1523,7 +1590,7 @@ public class ServerLevel extends Level implements WorldGenLevel { if (!savingDisabled) { org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld())); // CraftBukkit @@ -2831,7 +2697,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 if (progressListener != null) { progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); } -@@ -1543,11 +1610,11 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1533,11 +1600,11 @@ public class ServerLevel extends Level implements WorldGenLevel { progressListener.progressStage(Component.translatable("menu.savingChunks")); } @@ -2846,7 +2712,7 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 // Paper - rewrite chunk system - entity saving moved into ChunkHolder } else if (close) { chunkproviderserver.close(false); } // Paper - rewrite chunk system -@@ -2852,7 +2919,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2787,7 +2854,7 @@ public class ServerLevel extends Level implements WorldGenLevel { // 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 @@ -2856,10 +2722,10 @@ index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..00ac2902be93327c7dd1bf78ee5922d7 } // Paper end - Fix merchant inventory not closing on entity removal diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb10207e428091 100644 +index 8437316888c6056060a2780652147590b6fe7443..42a623254bd2886d09eb0cfeb01dd12d0dda19cf 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -281,6 +281,10 @@ public class ServerPlayer extends Player { +@@ -298,6 +298,10 @@ public class ServerPlayer extends Player { 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 @@ -2870,19 +2736,19 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 // Paper start - replace player chunk loader private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); -@@ -568,6 +572,9 @@ public class ServerPlayer extends Player { - } +@@ -608,6 +612,9 @@ public class ServerPlayer extends Player { + }); } -+ if (nbt.contains("Purpur.RamBar")) { this.ramBar = nbt.getBoolean("Purpur.RamBar"); } // Purpur + if (nbt.contains("Purpur.TPSBar")) { this.tpsBar = nbt.getBoolean("Purpur.TPSBar"); } // Purpur + if (nbt.contains("Purpur.CompassBar")) { this.compassBar = nbt.getBoolean("Purpur.CompassBar"); } // Purpur ++ if (nbt.contains("Purpur.RamBar")) { this.ramBar = nbt.getBoolean("Purpur.RamBar"); } // Purpur } @Override -@@ -634,6 +641,9 @@ public class ServerPlayer extends Player { +@@ -684,6 +691,9 @@ public class ServerPlayer extends Player { + }); } - this.getBukkitEntity().setExtraData(nbt); // CraftBukkit + nbt.putBoolean("Purpur.RamBar", this.ramBar); // Purpur + nbt.putBoolean("Purpur.TPSBar", this.tpsBar); // Purpur @@ -2890,9 +2756,9 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 } // CraftBukkit start - World fallback code, either respawn location or global spawn -@@ -762,6 +772,15 @@ public class ServerPlayer extends Player { - this.trackStartFallingPosition(); +@@ -813,6 +823,15 @@ public class ServerPlayer extends Player { this.trackEnteredOrExitedLavaOnVehicle(); + this.updatePlayerAttributes(); this.advancements.flushDirty(this); + + // Purpur start @@ -2905,8 +2771,8 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 + // Purpur end } - public void doTick() { -@@ -999,6 +1018,7 @@ public class ServerPlayer extends Player { + private void updatePlayerAttributes() { +@@ -1076,6 +1095,7 @@ public class ServerPlayer extends Player { })); PlayerTeam scoreboardteam = this.getTeam(); @@ -2914,7 +2780,7 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 if (scoreboardteam != null && scoreboardteam.getDeathMessageVisibility() != Team.Visibility.ALWAYS) { if (scoreboardteam.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OTHER_TEAMS) { this.server.getPlayerList().broadcastSystemToTeam(this, ichatbasecomponent); -@@ -1102,6 +1122,16 @@ public class ServerPlayer extends Player { +@@ -1179,6 +1199,16 @@ public class ServerPlayer extends Player { if (this.isInvulnerableTo(source)) { return false; } else { @@ -2931,7 +2797,7 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 boolean flag = this.server.isDedicatedServer() && this.isPvpAllowed() && source.is(DamageTypeTags.IS_FALL); if (!flag && this.spawnInvulnerableTime > 0 && !source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { -@@ -1213,7 +1243,7 @@ public class ServerPlayer extends Player { +@@ -1290,7 +1320,7 @@ public class ServerPlayer extends Player { PortalInfo shapedetectorshape = this.findDimensionEntryPoint(worldserver); if (shapedetectorshape != null) { @@ -2940,7 +2806,7 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 worldserver = shapedetectorshape.world; // CraftBukkit if (worldserver == null) { } else // CraftBukkit - empty to fall through to null to event if (resourcekey == LevelStem.OVERWORLD && worldserver.getTypeKey() == LevelStem.NETHER) { // CraftBukkit -@@ -1236,8 +1266,8 @@ public class ServerPlayer extends Player { +@@ -1313,8 +1343,8 @@ public class ServerPlayer extends Player { worldserver = ((CraftWorld) exit.getWorld()).getHandle(); // CraftBukkit end @@ -2951,7 +2817,7 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 if (true) { // CraftBukkit this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds -@@ -1248,13 +1278,14 @@ public class ServerPlayer extends Player { +@@ -1325,13 +1355,14 @@ public class ServerPlayer extends Player { playerlist.sendPlayerPermissionLevel(this); worldserver1.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); this.unsetRemoved(); @@ -2967,7 +2833,7 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 this.triggerDimensionChangeTriggers(worldserver1); this.connection.send(new ClientboundPlayerAbilitiesPacket(this.getAbilities())); playerlist.sendLevelInfo(this, worldserver); -@@ -1404,7 +1435,7 @@ public class ServerPlayer extends Player { +@@ -1481,7 +1512,7 @@ public class ServerPlayer extends Player { return entitymonster.isPreventingPlayerRest(this); }); @@ -2976,7 +2842,7 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 return Either.left(Player.BedSleepingProblem.NOT_SAFE); } } -@@ -1444,7 +1475,19 @@ public class ServerPlayer extends Player { +@@ -1521,7 +1552,19 @@ public class ServerPlayer extends Player { }); if (!this.serverLevel().canSleepThroughNights()) { @@ -2997,15 +2863,7 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 } ((ServerLevel) this.level()).updateSleepingPlayerList(); -@@ -1549,6 +1592,7 @@ public class ServerPlayer extends Player { - - @Override - public void openTextEdit(SignBlockEntity sign, boolean front) { -+ if (level().purpurConfig.signAllowColors) this.connection.send(sign.getTranslatedUpdatePacket(textFilteringEnabled, front)); // Purpur - this.connection.send(new ClientboundBlockUpdatePacket(this.level(), sign.getBlockPos())); - this.connection.send(new ClientboundOpenSignEditorPacket(sign.getBlockPos(), front)); - } -@@ -1883,6 +1927,26 @@ public class ServerPlayer extends Player { +@@ -1977,6 +2020,26 @@ public class ServerPlayer extends Player { this.lastSentExp = -1; // CraftBukkit - Added to reset } @@ -3032,7 +2890,7 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 @Override public void displayClientMessage(Component message, boolean overlay) { this.sendSystemMessage(message, overlay); -@@ -2204,8 +2268,68 @@ public class ServerPlayer extends Player { +@@ -2296,8 +2359,68 @@ public class ServerPlayer extends Player { public void resetLastActionTime() { this.lastActionTime = Util.getMillis(); @@ -3101,7 +2959,7 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 public ServerStatsCounter getStats() { return this.stats; } -@@ -2757,4 +2881,50 @@ public class ServerPlayer extends Player { +@@ -2865,4 +2988,50 @@ public class ServerPlayer extends Player { return (CraftPlayer) super.getBukkitEntity(); } // CraftBukkit end @@ -3153,10 +3011,10 @@ index b3781efbd3edcf102fe1bda5d6149915dc1127c6..305b90d10a499e9731f5178433fb1020 + // Purpur end } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index a7b217ddbcbf92513bd38101fdfca2075505e267..f8edb6b0d119582cf404b9931adc09484465fc9d 100644 +index 5cedce1f432f6b809b25269242a16477682c824f..6d194797d8fe2cd6e5652d596f4bc66ffc3b6375 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -397,6 +397,7 @@ public class ServerPlayerGameMode { +@@ -400,6 +400,7 @@ public class ServerPlayerGameMode { } else {capturedBlockEntity = true;} // Paper - Send block entities after destroy prediction return false; } @@ -3164,24 +3022,24 @@ index a7b217ddbcbf92513bd38101fdfca2075505e267..f8edb6b0d119582cf404b9931adc0948 } // CraftBukkit end -@@ -516,6 +517,7 @@ public class ServerPlayerGameMode { +@@ -512,6 +513,7 @@ public class ServerPlayerGameMode { public InteractionHand interactHand; public ItemStack interactItemStack; public InteractionResult useItemOn(ServerPlayer player, Level world, ItemStack stack, InteractionHand hand, BlockHitResult hitResult) { + if (shiftClickMended(stack)) return InteractionResult.SUCCESS; // Purpur BlockPos blockposition = hitResult.getBlockPos(); BlockState iblockdata = world.getBlockState(blockposition); - InteractionResult enuminteractionresult = InteractionResult.PASS; -@@ -577,7 +579,7 @@ public class ServerPlayerGameMode { - boolean flag1 = player.isSecondaryUseActive() && flag; + boolean cancelledBlock = false; +@@ -573,7 +575,7 @@ public class ServerPlayerGameMode { ItemStack itemstack1 = stack.copy(); + InteractionResult enuminteractionresult; - if (!flag1) { + if (!flag1 || (player.level().purpurConfig.composterBulkProcess && iblockdata.is(Blocks.COMPOSTER))) { // Purpur - enuminteractionresult = iblockdata.use(world, player, hand, hitResult); + ItemInteractionResult iteminteractionresult = iblockdata.useItemOn(player.getItemInHand(hand), world, player, hand, hitResult); - if (enuminteractionresult.consumesAction()) { -@@ -618,4 +620,18 @@ public class ServerPlayerGameMode { + if (iteminteractionresult.consumesAction()) { +@@ -621,4 +623,18 @@ public class ServerPlayerGameMode { public void setLevel(ServerLevel world) { this.level = world; } @@ -3201,25 +3059,25 @@ index a7b217ddbcbf92513bd38101fdfca2075505e267..f8edb6b0d119582cf404b9931adc0948 + // Purpur end } diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -index 9c3f8f79c2b3389a118dce9a1558edda52446833..01097e09c020fbe08d4fb467c02abc356657f768 100644 +index 1351423a12c19a01f602a202832372a399e6a867..1e2025674eafcf56460c741083c91e2e42d61b19 100644 --- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java +++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -@@ -318,6 +318,7 @@ public class WorldGenRegion implements WorldGenLevel { +@@ -326,6 +326,7 @@ public class WorldGenRegion implements WorldGenLevel { return true; } else { // Paper start - Buffer OOB setBlock calls + if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressSetBlockFarChunk) // Purpur if (!hasSetFarWarned) { - Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + i + ", " + j + "], pos: " + pos + ", status: " + this.generatingStatus + (this.currentlyGenerating == null ? "" : ", currently generating: " + (String) this.currentlyGenerating.get())); - hasSetFarWarned = true; + Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + i + ", " + j + "], pos: " + String.valueOf(pos) + ", status: " + String.valueOf(this.generatingStatus) + (this.currentlyGenerating == null ? "" : ", currently generating: " + (String) this.currentlyGenerating.get())); + hasSetFarWarned = true; diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 0306771b8f90dcdd77f151c19c6c2d75c41f8feb..02e65b0bd212d46855baee48fab35dc95a88b43f 100644 +index 8ac5d8ccf731100a1be690cb2ed1be82cadba8ed..8368c5ff929df9d32cdb95cc2da0e9f7f3b85d2a 100644 --- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -51,11 +51,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - private long keepAliveTime = Util.getMillis(); // Paper - private boolean keepAlivePending; +@@ -73,11 +73,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack private long keepAliveChallenge; + private long closedListenerTime; + private boolean closed = false; + private it.unimi.dsi.fastutil.longs.LongList keepAlives = new it.unimi.dsi.fastutil.longs.LongArrayList(); // Purpur private int latency; private volatile boolean suspendFlushingOnServerThread = false; @@ -3230,7 +3088,7 @@ index 0306771b8f90dcdd77f151c19c6c2d75c41f8feb..02e65b0bd212d46855baee48fab35dc9 public ServerCommonPacketListenerImpl(MinecraftServer minecraftserver, Connection networkmanager, CommonListenerCookie commonlistenercookie, ServerPlayer player) { // CraftBukkit this.server = minecraftserver; -@@ -91,6 +93,16 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -123,6 +125,16 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @Override public void handleKeepAlive(ServerboundKeepAlivePacket packet) { @@ -3247,7 +3105,7 @@ index 0306771b8f90dcdd77f151c19c6c2d75c41f8feb..02e65b0bd212d46855baee48fab35dc9 //PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // CraftBukkit // Paper - handle ServerboundKeepAlivePacket async if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) { int i = (int) (Util.getMillis() - this.keepAliveTime); -@@ -138,6 +150,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -170,6 +182,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t register custom payload", ex); this.disconnect("Invalid payload REGISTER!", org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause } @@ -3261,7 +3119,7 @@ index 0306771b8f90dcdd77f151c19c6c2d75c41f8feb..02e65b0bd212d46855baee48fab35dc9 } else if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_UNREGISTER)) { try { String channels = payload.toString(com.google.common.base.Charsets.UTF_8); -@@ -203,12 +222,27 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -246,12 +265,27 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack } protected void keepConnectionAlive() { @@ -3287,10 +3145,10 @@ index 0306771b8f90dcdd77f151c19c6c2d75c41f8feb..02e65b0bd212d46855baee48fab35dc9 + } else + // Purpur end + - if (this.keepAlivePending) { - if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected - ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); // more info -@@ -224,7 +258,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + if (!this.isSingleplayerOwner() && elapsedTime >= KEEPALIVE_LIMIT) { // Paper - check keepalive limit, don't fire if already disconnected + if (this.keepAlivePending && !this.processedDisconnect) { // Paper + this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause +@@ -264,7 +298,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack } // Paper end - give clients a longer time to respond to pings as per pre 1.12.2 timings @@ -3298,12 +3156,12 @@ index 0306771b8f90dcdd77f151c19c6c2d75c41f8feb..02e65b0bd212d46855baee48fab35dc9 + //this.server.getProfiler().pop(); // Purpur } - public void suspendFlushing() { + private boolean checkIfClosed(long time) { diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a109a54101c 100644 +index 8e67853a7a93fa736c147e8b2df537746dc8e94f..6d9242bc79526ebe4fdfe1f5d0ded429da2a9f95 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -324,6 +324,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -332,6 +332,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl private boolean justTeleported = false; // CraftBukkit end @@ -3324,7 +3182,7 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 @Override public void tick() { if (this.ackBlockChangesUpTo > -1) { -@@ -391,6 +405,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -399,6 +413,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl } if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L && !this.player.wonGame) { // Paper - Prevent AFK kick while watching end credits @@ -3337,7 +3195,7 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 this.disconnect(Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause } -@@ -638,6 +658,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -658,6 +678,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.lastYaw = to.getYaw(); this.lastPitch = to.getPitch(); @@ -3346,7 +3204,7 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 Location oldTo = to.clone(); PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); this.cserver.getPluginManager().callEvent(event); -@@ -711,6 +733,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -731,6 +753,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl if (packet.getId() == this.awaitingTeleport) { if (this.awaitingPositionFromClient == null) { this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause @@ -3354,12 +3212,12 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 return; } -@@ -1143,10 +1166,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1161,10 +1184,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl int maxBookPageSize = io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.pageMax; double multiplier = Math.max(0.3D, Math.min(1D, io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.totalMultiplier)); long byteAllowed = maxBookPageSize; + // Purpur start -+ int slot = packet.getSlot(); ++ int slot = packet.slot(); + ItemStack itemstack = Inventory.isHotbarSlot(slot) || slot == Inventory.SLOT_OFFHAND ? this.player.getInventory().getItem(slot) : ItemStack.EMPTY; + // Purpur end for (String testString : pageList) { @@ -3370,7 +3228,7 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 server.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause return; } -@@ -1170,6 +1198,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1188,6 +1216,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl if (byteTotal > byteAllowed) { ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send too large of a book. Book Size: " + byteTotal + " - Allowed: "+ byteAllowed + " - Pages: " + pageList.size()); @@ -3378,74 +3236,7 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 server.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause return; } -@@ -1223,13 +1252,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - itemstack1.setTag(nbttagcompound.copy()); - } - -+ // Purpur start -+ boolean hasPerm = getCraftPlayer().hasPermission("purpur.book.color.edit") || getCraftPlayer().hasPermission("purpur.book.color.sign"); - itemstack1.addTagElement("author", StringTag.valueOf(this.player.getName().getString())); - if (this.player.isTextFilteringEnabled()) { -- itemstack1.addTagElement("title", StringTag.valueOf(title.filteredOrEmpty())); -+ itemstack1.addTagElement("title", StringTag.valueOf(color(title.filteredOrEmpty(), hasPerm))); - } else { -- itemstack1.addTagElement("filtered_title", StringTag.valueOf(title.filteredOrEmpty())); -- itemstack1.addTagElement("title", StringTag.valueOf(title.raw())); -+ itemstack1.addTagElement("filtered_title", StringTag.valueOf(color(title.filteredOrEmpty(), hasPerm))); -+ itemstack1.addTagElement("title", StringTag.valueOf(color(title.raw(), hasPerm))); - } -+ // Purpur end - - this.updateBookPages(pages, (s) -> { - return Component.Serializer.toJson(Component.literal(s)); -@@ -1241,10 +1273,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - private void updateBookPages(List list, UnaryOperator unaryoperator, ItemStack itemstack, int slot, ItemStack handItem) { // CraftBukkit - ListTag nbttaglist = new ListTag(); - -+ // Purpur start -+ boolean hasPerm = getCraftPlayer().hasPermission("purpur.book.color.edit"); - if (this.player.isTextFilteringEnabled()) { -- Stream stream = list.stream().map((filteredtext) -> { // CraftBukkit - decompile error -- return StringTag.valueOf((String) unaryoperator.apply(filteredtext.filteredOrEmpty())); -+ Stream stream = list.stream().map(s -> color(s.filteredOrEmpty(), hasPerm, false)).map((s) -> { // CraftBukkit - decompile error -+ return StringTag.valueOf((String) unaryoperator.apply(s)); - }); -+ // Purpur end - - Objects.requireNonNull(nbttaglist); - stream.forEach(nbttaglist::add); -@@ -1254,11 +1289,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - for (int j = list.size(); i < j; ++i) { - FilteredText filteredtext = (FilteredText) list.get(i); -- String s = filteredtext.raw(); -+ String s = color(filteredtext.raw(), hasPerm, false); // Purpur - - nbttaglist.add(StringTag.valueOf((String) unaryoperator.apply(s))); - if (filteredtext.isFiltered()) { -- nbttagcompound.putString(String.valueOf(i), (String) unaryoperator.apply(filteredtext.filteredOrEmpty())); -+ nbttagcompound.putString(String.valueOf(i), (String) unaryoperator.apply((String) color(filteredtext.filteredOrEmpty(), hasPerm, false))); // Purpur - } - } - -@@ -1271,6 +1306,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.player.getInventory().setItem(slot, CraftEventFactory.handleEditBookEvent(this.player, slot, handItem, itemstack)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent) - } - -+ // Purpur start -+ private String color(String str, boolean hasPerm) { -+ return color(str, hasPerm, true); -+ } -+ -+ private String color(String str, boolean hasPerm, boolean parseHex) { -+ return hasPerm ? org.bukkit.ChatColor.color(str, parseHex) : str; -+ } -+ // Purpur end -+ - @Override - public void handleEntityTagQuery(ServerboundEntityTagQuery packet) { - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); -@@ -1320,8 +1365,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1306,8 +1335,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @Override public void handleMovePlayer(ServerboundMovePlayerPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -3463,16 +3254,16 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 } else { ServerLevel worldserver = this.player.serverLevel(); -@@ -1505,7 +1558,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - if (!event.isAllowed()) { +@@ -1494,7 +1531,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl movedWrongly = true; if (event.getLogWarning()) + // Paper end - ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString()); + ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!, ({})", this.player.getName().getString(), d11); // Purpur - } + } // Paper } -@@ -1572,6 +1625,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1562,6 +1599,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.lastYaw = to.getYaw(); this.lastPitch = to.getPitch(); @@ -3481,8 +3272,8 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 Location oldTo = to.clone(); PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); this.cserver.getPluginManager().callEvent(event); -@@ -1607,6 +1662,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.player.resetFallDistance(); +@@ -1603,6 +1642,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.player.resetCurrentImpulseContext(); } + // Purpur Start @@ -3495,21 +3286,23 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 this.player.checkMovementStatistics(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5); this.lastGoodX = this.player.getX(); this.lastGoodY = this.player.getY(); -@@ -1646,6 +1708,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1642,6 +1688,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl return false; } // Paper end - optimise out extra getCubes + + // Purpur start + public boolean isScissor(ItemStack stack) { -+ return stack.is(Items.SHEARS) && (stack.getTag() == null || stack.getTag().getInt("CustomModelData") == 0); ++ if (!stack.is(Items.SHEARS)) return false; ++ net.minecraft.world.item.component.CustomModelData customModelData = stack.get(net.minecraft.core.component.DataComponents.CUSTOM_MODEL_DATA); ++ return customModelData == null || customModelData.value() == 0; + } + // Purpur end + private boolean isPlayerCollidingWithAnythingNew(LevelReader world, AABB box, double newX, double newY, double newZ) { AABB axisalignedbb1 = this.player.getBoundingBox().move(newX - this.player.getX(), newY - this.player.getY(), newZ - this.player.getZ()); Iterable iterable = world.getCollisions(this.player, axisalignedbb1.deflate(9.999999747378752E-6D)); -@@ -1656,7 +1725,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1652,7 +1707,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl do { if (!iterator.hasNext()) { @@ -3518,7 +3311,7 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 } voxelshape1 = (VoxelShape) iterator.next(); -@@ -1991,6 +2060,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1990,6 +2045,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl boolean cancelled; if (movingobjectposition == null || movingobjectposition.getType() != HitResult.Type.BLOCK) { @@ -3526,7 +3319,7 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemstack, enumhand); cancelled = event.useItemInHand() == Event.Result.DENY; } else { -@@ -2395,7 +2465,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2464,7 +2520,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl public void handleCommand(String s) { // Paper - private -> public org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + s); // Paper - Add async catcher @@ -3535,7 +3328,7 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); -@@ -2405,7 +2475,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2474,7 +2530,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.cserver.getPluginManager().callEvent(event); if (event.isCancelled()) { @@ -3544,7 +3337,7 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 return; } -@@ -2418,7 +2488,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2487,7 +2543,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl java.util.logging.Logger.getLogger(ServerGamePacketListenerImpl.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); return; } finally { @@ -3553,15 +3346,15 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 } } // CraftBukkit end -@@ -2709,6 +2779,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2774,6 +2830,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl AABB axisalignedbb = entity.getBoundingBox(); - if (axisalignedbb.distanceToSqr(this.player.getEyePosition()) < ServerGamePacketListenerImpl.MAX_INTERACTION_DISTANCE) { + if (this.player.canInteractWithEntity(axisalignedbb, 1.0D)) { + if (entity instanceof Mob mob) mob.ticksSinceLastInteraction = 0; // Purpur packet.dispatch(new ServerboundInteractPacket.Handler() { private void performInteraction(InteractionHand enumhand, ServerGamePacketListenerImpl.EntityInteraction playerconnection_a, PlayerInteractEntityEvent event) { // CraftBukkit ItemStack itemstack = ServerGamePacketListenerImpl.this.player.getItemInHand(enumhand); -@@ -2722,6 +2793,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2787,6 +2844,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event); @@ -3569,25 +3362,12 @@ index e725c1c0496383007ffb94c46fc18340666b5e29..f7ac60e1aa188ec25a4c5d326cdd4a10 + // Entity in bucket - SPIGOT-4048 and SPIGOT-6859a if ((entity instanceof Bucketable && entity 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.getEntityData().resendPossiblyDesyncedEntity(player); // Paper - The entire mob gets deleted, so resend it. -@@ -3309,6 +3382,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - } - } -+ // Purpur start -+ if (org.purpurmc.purpur.PurpurConfig.fixNetworkSerializedItemsInCreative) { -+ var tag = itemstack.getTagElement("Purpur.OriginalItem"); -+ if (tag != null) itemstack = ItemStack.of(tag); -+ } -+ // Purpur end - - boolean flag1 = packet.getSlotNum() >= 1 && packet.getSlotNum() <= 45; - boolean flag2 = itemstack.isEmpty() || itemstack.getDamageValue() >= 0 && itemstack.getCount() <= 64 && !itemstack.isEmpty(); + entity.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it. diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index c5fa9f4d28f9a7f64a50a902ee5e631bfc00119c..8b62f992ec61d0a66a3856b4928ee2d705548291 100644 +index b656741eb68adeb04bf995f1045902cb6bd5f2e7..3b4fadb37eafb2f7b0ce4d6b276d2fdaa8287521 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -270,7 +270,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, +@@ -315,7 +315,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!"); ServerLoginPacketListenerImpl.this.startClientVerification(ServerLoginPacketListenerImpl.this.createOfflineProfile(s1)); // Spigot } else { @@ -3597,7 +3377,7 @@ index c5fa9f4d28f9a7f64a50a902ee5e631bfc00119c..8b62f992ec61d0a66a3856b4928ee2d7 } } catch (AuthenticationUnavailableException authenticationunavailableexception) { diff --git a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java -index e5006e7672ba79ed4bcf2c4173c5a9ed4c68395b..6338c52e0082d36d3b80038fdb44abf2772adb30 100644 +index 6f1c9fa89e718cbc01a8d72de34154f49c5f46db..2455f8e9679914660ec4fcd081138dabfe9c225b 100644 --- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java @@ -153,6 +153,7 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene @@ -3629,10 +3409,10 @@ index f14113eef226e906c0d21641e74a27471254909d..0c25f3ed0a8a538edc7cadd3476100c9 } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..ac1e0c66f167218306504db6037cc1d6509072a0 100644 +index a2142930b4d4b05987c90496fb9d733d99040aa0..b863f6fe65c796a1d3102cc3eddb5d6c5becd3ac 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -487,6 +487,7 @@ public abstract class PlayerList { +@@ -486,6 +486,7 @@ public abstract class PlayerList { scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam); } // Paper end - Configurable player collision @@ -3640,7 +3420,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..ac1e0c66f167218306504db6037cc1d6 PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ()); } -@@ -599,6 +600,7 @@ public abstract class PlayerList { +@@ -597,6 +598,7 @@ public abstract class PlayerList { } public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer, net.kyori.adventure.text.Component leaveMessage) { // Paper end - Fix kick event leave message not being sent @@ -3648,7 +3428,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..ac1e0c66f167218306504db6037cc1d6 ServerLevel worldserver = entityplayer.serverLevel(); entityplayer.awardStat(Stats.LEAVE_GAME); -@@ -753,7 +755,7 @@ public abstract class PlayerList { +@@ -752,7 +754,7 @@ public abstract class PlayerList { event.disallow(PlayerLoginEvent.Result.KICK_BANNED, io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure } else { // return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile) ? IChatBaseComponent.translatable("multiplayer.disconnect.server_full") : null; @@ -3657,7 +3437,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..ac1e0c66f167218306504db6037cc1d6 event.disallow(PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure } } -@@ -1064,6 +1066,20 @@ public abstract class PlayerList { +@@ -1063,6 +1065,20 @@ public abstract class PlayerList { } // CraftBukkit end @@ -3678,7 +3458,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..ac1e0c66f167218306504db6037cc1d6 public void broadcastAll(Packet packet, ResourceKey dimension) { Iterator iterator = this.players.iterator(); -@@ -1167,6 +1183,7 @@ public abstract class PlayerList { +@@ -1166,6 +1182,7 @@ public abstract class PlayerList { } else { b0 = (byte) (24 + permissionLevel); } @@ -3686,7 +3466,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..ac1e0c66f167218306504db6037cc1d6 player.connection.send(new ClientboundEntityEventPacket(player, b0)); } -@@ -1175,6 +1192,27 @@ public abstract class PlayerList { +@@ -1174,6 +1191,27 @@ public abstract class PlayerList { player.getBukkitEntity().recalculatePermissions(); // CraftBukkit this.server.getCommands().sendCommands(player); } // Paper - Add sendOpLevel API @@ -3714,7 +3494,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..ac1e0c66f167218306504db6037cc1d6 } public boolean isWhiteListed(GameProfile profile) { -@@ -1236,7 +1274,7 @@ public abstract class PlayerList { +@@ -1235,7 +1273,7 @@ public abstract class PlayerList { public void saveAll(int interval) { io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main @@ -3723,7 +3503,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..ac1e0c66f167218306504db6037cc1d6 int numSaved = 0; long now = MinecraftServer.currentTick; for (int i = 0; i < this.players.size(); ++i) { -@@ -1247,7 +1285,7 @@ public abstract class PlayerList { +@@ -1246,7 +1284,7 @@ public abstract class PlayerList { } // Paper end - Incremental chunk and player saving } @@ -3766,6 +3546,18 @@ index 4103ddf16164e3992fef0765d368282572537e29..a0cb49233b1dbf53ce9d1bcc52b89678 ServerRecipeBook.LOGGER.error("Tried to load unrecognized recipe: {} removed now.", minecraftkey); } else { handler.accept((RecipeHolder) optional.get()); +diff --git a/src/main/java/net/minecraft/util/StringUtil.java b/src/main/java/net/minecraft/util/StringUtil.java +index 0bd191acb9596d3aa21c337230d26f09d26f6888..20211f40aeeade9217ece087688974bdf55afc56 100644 +--- a/src/main/java/net/minecraft/util/StringUtil.java ++++ b/src/main/java/net/minecraft/util/StringUtil.java +@@ -69,6 +69,7 @@ public class StringUtil { + + // Paper start - Username validation + public static boolean isReasonablePlayerName(final String name) { ++ if (true) return org.purpurmc.purpur.PurpurConfig.usernameValidCharactersPattern.matcher(name).matches(); // Purpur + if (name.isEmpty() || name.length() > 16) { + return false; + } diff --git a/src/main/java/net/minecraft/util/profiling/ActiveProfiler.java b/src/main/java/net/minecraft/util/profiling/ActiveProfiler.java index bce2dac613d29083dd5fbb68739304cc5a6d4d27..600a7036b503f60cc9c95f189f73c2dbf020e2e1 100644 --- a/src/main/java/net/minecraft/util/profiling/ActiveProfiler.java @@ -3951,16 +3743,19 @@ index a715ecf4a8ac91d3e5e5c6269d89e54b2c1cd279..223c3665126c576eddb1a8f7c9f5bc60 }; } diff --git a/src/main/java/net/minecraft/world/damagesource/CombatRules.java b/src/main/java/net/minecraft/world/damagesource/CombatRules.java -index ccbfcef3e83b1bef364447657bfd08a92d615cf6..aa2331c6df4e79d4bb0add071a0b11d2a3a08b88 100644 +index ddc880ac0c8378bc1132be5deba746c1484c941c..7a8e4b9a9f2e1e5a9c38ad330c75df1f880d3e8b 100644 --- a/src/main/java/net/minecraft/world/damagesource/CombatRules.java +++ b/src/main/java/net/minecraft/world/damagesource/CombatRules.java -@@ -11,12 +11,12 @@ public class CombatRules { +@@ -12,7 +12,7 @@ public class CombatRules { - public static float getDamageAfterAbsorb(float damage, float armor, float armorToughness) { - float f = 2.0F + armorToughness / 4.0F; + public static float getDamageAfterAbsorb(float damage, DamageSource source, float armor, float armorToughnesss) { + float f = 2.0F + armorToughnesss / 4.0F; - float g = Mth.clamp(armor - damage / f, armor * 0.2F, 20.0F); + float g = Mth.clamp(armor - damage / f, armor * 0.2F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur - return damage * (1.0F - g / 25.0F); + float h = g / 25.0F; + float i = EnchantmentHelper.calculateArmorBreach(source.getEntity(), h); + float j = 1.0F - i; +@@ -20,7 +20,7 @@ public class CombatRules { } public static float getDamageAfterMagicAbsorb(float damageDealt, float protection) { @@ -3970,19 +3765,19 @@ index ccbfcef3e83b1bef364447657bfd08a92d615cf6..aa2331c6df4e79d4bb0add071a0b11d2 } } diff --git a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -index 7056c8ca7a87748f14142c6af274aae492f29f1c..bf06bb78d060bb54d9aaade3605d42ce837d598b 100644 +index 99a7e9eb75231c15bd8bb24fbb4e296bc9fdedff..4fb025a63628eb60509d90b680922a0220104bcb 100644 --- a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java +++ b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -@@ -53,7 +53,7 @@ public class CombatTracker { +@@ -54,7 +54,7 @@ public class CombatTracker { private Component getMessageForAssistedFall(Entity attacker, Component attackerDisplayName, String itemDeathTranslationKey, String deathTranslationKey) { ItemStack itemStack = attacker instanceof LivingEntity livingEntity ? livingEntity.getMainHandItem() : ItemStack.EMPTY; -- return !itemStack.isEmpty() && itemStack.hasCustomHoverName() -+ return !itemStack.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemStack.hasCustomHoverName()) // Purpur +- return !itemStack.isEmpty() && itemStack.has(DataComponents.CUSTOM_NAME) ++ return !itemStack.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemStack.has(DataComponents.CUSTOM_NAME)) // Purpur ? Component.translatable(itemDeathTranslationKey, this.mob.getDisplayName(), attackerDisplayName, itemStack.getDisplayName()) : Component.translatable(deathTranslationKey, this.mob.getDisplayName(), attackerDisplayName); } -@@ -97,6 +97,13 @@ public class CombatTracker { +@@ -98,6 +98,13 @@ public class CombatTracker { Component component = ComponentUtils.wrapInSquareBrackets(Component.translatable(string + ".link")).withStyle(INTENTIONAL_GAME_DESIGN_STYLE); return Component.translatable(string + ".message", this.mob.getDisplayName(), component); } else { @@ -3997,10 +3792,10 @@ index 7056c8ca7a87748f14142c6af274aae492f29f1c..bf06bb78d060bb54d9aaade3605d42ce } } diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -index b26e4d58ea1898a5e4b31c3d6ab33f38835ab2c6..a1724d2d545aa808ea380f910c0190658fc7881b 100644 +index 359a2f0492a9b938a4f015c546e100e0092ae1d4..25e614be19b2b29b36af136b823f27f85e1650fa 100644 --- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java +++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -@@ -27,6 +27,8 @@ public class DamageSource { +@@ -29,6 +29,8 @@ public class DamageSource { private boolean withSweep = false; private boolean melting = false; private boolean poison = false; @@ -4009,7 +3804,7 @@ index b26e4d58ea1898a5e4b31c3d6ab33f38835ab2c6..a1724d2d545aa808ea380f910c019065 @Nullable private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API -@@ -57,6 +59,26 @@ public class DamageSource { +@@ -59,6 +61,26 @@ public class DamageSource { return this.poison; } @@ -4036,7 +3831,7 @@ index b26e4d58ea1898a5e4b31c3d6ab33f38835ab2c6..a1724d2d545aa808ea380f910c019065 // Paper start - fix DamageSource API public @Nullable Entity getCustomEventDamager() { return (this.customEventDamager != null) ? this.customEventDamager : this.directEntity; -@@ -100,6 +122,8 @@ public class DamageSource { +@@ -101,6 +123,8 @@ public class DamageSource { damageSource.withSweep = this.isSweep(); damageSource.poison = this.isPoison(); damageSource.melting = this.isMelting(); @@ -4045,12 +3840,12 @@ index b26e4d58ea1898a5e4b31c3d6ab33f38835ab2c6..a1724d2d545aa808ea380f910c019065 return damageSource; } // CraftBukkit end -@@ -172,10 +196,19 @@ public class DamageSource { +@@ -173,10 +197,19 @@ public class DamageSource { ItemStack itemstack1 = itemstack; -- return !itemstack1.isEmpty() && itemstack1.hasCustomHoverName() ? Component.translatable(s + ".item", killed.getDisplayName(), ichatbasecomponent, itemstack1.getDisplayName()) : Component.translatable(s, killed.getDisplayName(), ichatbasecomponent); -+ return !itemstack1.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemstack1.hasCustomHoverName()) ? Component.translatable(s + ".item", killed.getDisplayName(), ichatbasecomponent, itemstack1.getDisplayName()) : Component.translatable(s, killed.getDisplayName(), ichatbasecomponent); +- return !itemstack1.isEmpty() && itemstack1.has(DataComponents.CUSTOM_NAME) ? Component.translatable(s + ".item", killed.getDisplayName(), ichatbasecomponent, itemstack1.getDisplayName()) : Component.translatable(s, killed.getDisplayName(), ichatbasecomponent); ++ return !itemstack1.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemstack1.has(DataComponents.CUSTOM_NAME)) ? Component.translatable(s + ".item", killed.getDisplayName(), ichatbasecomponent, itemstack1.getDisplayName()) : Component.translatable(s, killed.getDisplayName(), ichatbasecomponent); } } @@ -4067,7 +3862,7 @@ index b26e4d58ea1898a5e4b31c3d6ab33f38835ab2c6..a1724d2d545aa808ea380f910c019065 return this.type().msgId(); } diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSources.java b/src/main/java/net/minecraft/world/damagesource/DamageSources.java -index a47473c9875c70c52b9a61e0156e55961f34c694..2c1fdc031bcfc8f39692312e9ce9c5a3cf987349 100644 +index 349d1683458ec5d641c9823aa7a68dec8820a664..f0568c3d731afaf610ac2f45db53148d38338cdf 100644 --- a/src/main/java/net/minecraft/world/damagesource/DamageSources.java +++ b/src/main/java/net/minecraft/world/damagesource/DamageSources.java @@ -44,11 +44,15 @@ public class DamageSources { @@ -4103,191 +3898,51 @@ index a47473c9875c70c52b9a61e0156e55961f34c694..2c1fdc031bcfc8f39692312e9ce9c5a3 return this.inFire; } diff --git a/src/main/java/net/minecraft/world/effect/HungerMobEffect.java b/src/main/java/net/minecraft/world/effect/HungerMobEffect.java -index 3aad6bd0a1fb7bb3f9b7dab2c10c875864900750..31bd845130e363dd11c225dfd1e9dd896aea8aac 100644 +index a476b56ed98d0a1afc6a396ce29424df78f24ada..5119ff3414fbd9a1ae0a8db0fd15bd3c57c8e148 100644 --- a/src/main/java/net/minecraft/world/effect/HungerMobEffect.java +++ b/src/main/java/net/minecraft/world/effect/HungerMobEffect.java -@@ -15,7 +15,7 @@ class HungerMobEffect extends MobEffect { - if (entity instanceof Player) { - Player entityhuman = (Player) entity; - +@@ -12,7 +12,7 @@ class HungerMobEffect extends MobEffect { + @Override + public boolean applyEffectTick(LivingEntity entity, int amplifier) { + if (entity instanceof Player entityhuman) { - entityhuman.causeFoodExhaustion(0.005F * (float) (amplifier + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent + entityhuman.causeFoodExhaustion(entity.level().purpurConfig.humanHungerExhaustionAmount * (float) (amplifier + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent // Purpur } - } -diff --git a/src/main/java/net/minecraft/world/effect/MobEffectInstance.java b/src/main/java/net/minecraft/world/effect/MobEffectInstance.java -index 5c9a0c91ae53b575d325a294c702668d30252fcf..0758ddbd37a519d03ae134731368f4a69c2f8aab 100644 ---- a/src/main/java/net/minecraft/world/effect/MobEffectInstance.java -+++ b/src/main/java/net/minecraft/world/effect/MobEffectInstance.java -@@ -36,6 +36,7 @@ public class MobEffectInstance implements Comparable { - private boolean showIcon; - @Nullable - public MobEffectInstance hiddenEffect; -+ private org.bukkit.NamespacedKey key; // Purpur - add key - private final Optional factorData; - - public MobEffectInstance(MobEffect type) { -@@ -54,8 +55,14 @@ public class MobEffectInstance implements Comparable { - this(type, duration, amplifier, ambient, visible, visible); - } - -+ // Purpur start -+ public MobEffectInstance(MobEffect type, int duration, int amplifier, boolean ambient, boolean showParticles, boolean showIcon, @Nullable org.bukkit.NamespacedKey key) { -+ this(type, duration, amplifier, ambient, showParticles, showIcon, null, key, type.createFactorData()); -+ } -+ // Purpur end -+ - public MobEffectInstance(MobEffect type, int duration, int amplifier, boolean ambient, boolean showParticles, boolean showIcon) { -- this(type, duration, amplifier, ambient, showParticles, showIcon, null, type.createFactorData()); -+ this(type, duration, amplifier, ambient, showParticles, showIcon, null, null, type.createFactorData()); // Purpur - } - - public MobEffectInstance( -@@ -66,6 +73,7 @@ public class MobEffectInstance implements Comparable { - boolean showParticles, - boolean showIcon, - @Nullable MobEffectInstance hiddenEffect, -+ @Nullable org.bukkit.NamespacedKey key, // Purpur - Optional factorCalculationData - ) { - this.effect = type; -@@ -74,6 +82,7 @@ public class MobEffectInstance implements Comparable { - this.ambient = ambient; - this.visible = showParticles; - this.showIcon = showIcon; -+ this.key = key; // Purpur - add key - this.hiddenEffect = hiddenEffect; - this.factorData = factorCalculationData; - } -@@ -94,6 +103,7 @@ public class MobEffectInstance implements Comparable { - this.ambient = that.ambient; - this.visible = that.visible; - this.showIcon = that.showIcon; -+ this.key = that.key; // Purpur - add key - } - - public boolean update(MobEffectInstance that) { -@@ -138,6 +148,13 @@ public class MobEffectInstance implements Comparable { - bl = true; - } - -+ // Purpur start -+ if (that.key != this.key) { -+ this.key = that.key; -+ bl = true; -+ } -+ // Purpur end -+ - return bl; - } - -@@ -181,6 +198,17 @@ public class MobEffectInstance implements Comparable { - return this.showIcon; - } - -+ // Purpur start -+ public boolean hasKey() { -+ return this.key != null; -+ } -+ -+ @Nullable -+ public org.bukkit.NamespacedKey getKey() { -+ return this.key; -+ } -+ // Purpur end -+ - public boolean tick(LivingEntity entity, Runnable overwriteCallback) { - if (this.hasRemainingDuration()) { - int i = this.isInfiniteDuration() ? entity.tickCount : this.duration; -@@ -237,6 +265,12 @@ public class MobEffectInstance implements Comparable { - string = string + ", Show Icon: false"; - } - -+ // Purpur start -+ if (this.hasKey()) { -+ string = string + ", Key: " + this.key; -+ } -+ // Purpur end -+ - return string; - } - -@@ -251,6 +285,7 @@ public class MobEffectInstance implements Comparable { - && this.duration == mobEffectInstance.duration - && this.amplifier == mobEffectInstance.amplifier - && this.ambient == mobEffectInstance.ambient -+ && this.key == mobEffectInstance.key // Purpur - add key - && this.effect.equals(mobEffectInstance.effect); - } - -@@ -275,6 +310,11 @@ public class MobEffectInstance implements Comparable { - nbt.putBoolean("ambient", this.isAmbient()); - nbt.putBoolean("show_particles", this.isVisible()); - nbt.putBoolean("show_icon", this.showIcon()); -+ // Purpur start -+ if (this.key != null) { -+ nbt.putString("key", this.key.toString()); -+ } -+ // Purpur end - if (this.hiddenEffect != null) { - CompoundTag compoundTag = new CompoundTag(); - this.hiddenEffect.save(compoundTag); -@@ -311,6 +351,13 @@ public class MobEffectInstance implements Comparable { - bl3 = nbt.getBoolean("show_icon"); - } - -+ // Purpur start -+ org.bukkit.NamespacedKey key = null; -+ if (nbt.contains("key")) { -+ key = org.bukkit.NamespacedKey.fromString(nbt.getString("key")); -+ } -+ // Purpur end -+ - MobEffectInstance mobEffectInstance = null; - if (nbt.contains("hidden_effect", 10)) { - mobEffectInstance = loadSpecifiedEffect(type, nbt.getCompound("hidden_effect")); -@@ -325,7 +372,7 @@ public class MobEffectInstance implements Comparable { - optional = Optional.empty(); - } - -- return new MobEffectInstance(type, j, Math.max(i, 0), bl, bl2, bl3, mobEffectInstance, optional); -+ return new MobEffectInstance(type, j, Math.max(i, 0), bl, bl2, bl3, mobEffectInstance, key, optional); // Purpur - add key - } - - @Override + return true; diff --git a/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java b/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java -index 196204a8661c7750408997e052ec706f44161fc6..393cd9fac5b2fd39e4248d0abd4930e6b2ff73a4 100644 +index 3e7a703632251e0a5234259e3702b58b332e5ef0..f2cc43fbccb5d2ba012b350268065c2cfe014faf 100644 --- a/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java +++ b/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java -@@ -11,8 +11,8 @@ class PoisonMobEffect extends MobEffect { +@@ -10,8 +10,8 @@ class PoisonMobEffect extends MobEffect { + @Override - public void applyEffectTick(LivingEntity entity, int amplifier) { - super.applyEffectTick(entity, amplifier); + public boolean applyEffectTick(LivingEntity entity, int amplifier) { - if (entity.getHealth() > 1.0F) { - entity.hurt(entity.damageSources().poison(), 1.0F); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON + if (entity.getHealth() > entity.level().purpurConfig.entityMinimalHealthPoison) { // Purpur + entity.hurt(entity.damageSources().poison(), entity.level().purpurConfig.entityPoisonDegenerationAmount); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON // Purpur } - } + return true; diff --git a/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java b/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java -index 551b20f86347aeca4824b7a424ad7de7c0ff072e..06bb4ad98aa9ca38b8d423681b1ad4b821f5e47d 100644 +index 4dba3e813e054951cbfbe0b323c1f5d973469cc0..426f61d55b9692cf085368df4e4df6f6997aa420 100644 --- a/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java +++ b/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java -@@ -12,7 +12,7 @@ class RegenerationMobEffect extends MobEffect { - public void applyEffectTick(LivingEntity entity, int amplifier) { - super.applyEffectTick(entity, amplifier); +@@ -11,7 +11,7 @@ class RegenerationMobEffect extends MobEffect { + @Override + public boolean applyEffectTick(LivingEntity entity, int amplifier) { if (entity.getHealth() < entity.getMaxHealth()) { - entity.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit + entity.heal(entity.level().purpurConfig.entityHealthRegenAmount, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit // Purpur } - } + return true; diff --git a/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java b/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java -index b994ae09621934df2cdd6a83a7d8ecb44649fb16..c2b812c992db1ac9cd391da902c8d819a6ec2e6d 100644 +index 7b415dca88f50dc472fe4be96e5ef0996f117913..2bb872f29350d15db46b32c686aef78fc1b6fa29 100644 --- a/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java +++ b/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java -@@ -23,7 +23,7 @@ class SaturationMobEffect extends InstantenousMobEffect { +@@ -20,7 +20,7 @@ class SaturationMobEffect extends InstantenousMobEffect { int oldFoodLevel = entityhuman.getFoodData().foodLevel; org.bukkit.event.entity.FoodLevelChangeEvent event = CraftEventFactory.callFoodLevelChangeEvent(entityhuman, amplifier + 1 + oldFoodLevel); if (!event.isCancelled()) { @@ -4297,41 +3952,40 @@ index b994ae09621934df2cdd6a83a7d8ecb44649fb16..c2b812c992db1ac9cd391da902c8d819 ((CraftPlayer) entityhuman.getBukkitEntity()).sendHealthUpdate(); diff --git a/src/main/java/net/minecraft/world/effect/WitherMobEffect.java b/src/main/java/net/minecraft/world/effect/WitherMobEffect.java -index cc45fd864185a7842c465e26304b36f7c744bb93..434390a6b88eac7bd41ad6b05d223c78571885fb 100644 +index f43bf280999ff3860cc702def50cc62b131eb1bd..66d9e99a351f5fc6cf58be3bee4397d92c932d64 100644 --- a/src/main/java/net/minecraft/world/effect/WitherMobEffect.java +++ b/src/main/java/net/minecraft/world/effect/WitherMobEffect.java -@@ -10,7 +10,7 @@ class WitherMobEffect extends MobEffect { +@@ -9,7 +9,7 @@ class WitherMobEffect extends MobEffect { + @Override - public void applyEffectTick(LivingEntity entity, int amplifier) { - super.applyEffectTick(entity, amplifier); + public boolean applyEffectTick(LivingEntity entity, int amplifier) { - entity.hurt(entity.damageSources().wither(), 1.0F); + entity.hurt(entity.damageSources().wither(), entity.level().purpurConfig.entityWitherDegenerationAmount); // Purpur + return true; } - @Override diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6ae598f1f 100644 +index 2bc85351e6e52f90da5fdb29d8d042a06132d742..3aae4fa4176c0bf170f4532ae187e3122c142a6a 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -160,7 +160,7 @@ import org.bukkit.plugin.PluginManager; +@@ -163,7 +163,7 @@ import org.bukkit.plugin.PluginManager; // CraftBukkit end - public abstract class Entity implements Nameable, EntityAccess, CommandSource, ScoreHolder { + public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder { - + public static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur // 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 -@@ -337,7 +337,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -340,6 +340,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public double xOld; public double yOld; public double zOld; -- private float maxUpStep; -+ public float maxUpStep; // Purpur - private -> public ++ public float maxUpStep; // Purpur public boolean noPhysics; public final RandomSource random; public int tickCount; -@@ -379,7 +379,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -381,7 +382,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess private final Set tags; private final double[] pistonDeltas; private long pistonDeltasGameTime; @@ -4340,15 +3994,15 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 private float eyeHeight; public boolean isInPowderSnow; public boolean wasInPowderSnow; -@@ -427,6 +427,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - public boolean activatedPriorityReset = false; // Pufferfish - DAB - public int activatedPriority = gg.pufferfish.pufferfish.PufferfishConfig.maximumActivationPrio; // Pufferfish - DAB (golf score) - public final BlockPos.MutableBlockPos cachedBlockPos = new BlockPos.MutableBlockPos(); // Pufferfish - reduce entity allocations +@@ -426,6 +427,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + private UUID originWorld; + public boolean freezeLocked = false; // Paper - Freeze Tick Lock API + public boolean fixedPose = false; // Paper - Expand Pose API + public @Nullable Boolean immuneToFire = null; // Purpur - Fire immune API public void setOrigin(@javax.annotation.Nonnull Location location) { this.origin = location.toVector(); -@@ -558,6 +559,25 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -557,6 +559,25 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return false; } @@ -4374,7 +4028,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 public final boolean hardCollides() { return this.hardCollides; } -@@ -578,7 +598,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -577,7 +598,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.bb = Entity.INITIAL_AABB; this.stuckSpeedMultiplier = Vec3.ZERO; this.nextStep = 1.0F; @@ -4383,25 +4037,16 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 this.remainingFireTicks = -this.getFireImmuneTicks(); this.fluidHeight = new Object2DoubleArrayMap(2); this.fluidOnEyes = new HashSet(); -@@ -825,7 +845,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - public void tick() { - // Pufferfish start - entity TTL - if (type != EntityType.PLAYER && type.ttl >= 0 && this.tickCount >= type.ttl) { -- discard(); -+ discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Purpur - return; - } - // Pufferfish end - entity TTL -@@ -842,7 +862,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -877,7 +898,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess // CraftBukkit end public void baseTick() { - this.level().getProfiler().push("entityBaseTick"); + //this.level().getProfiler().push("entityBaseTick"); // Purpur if (firstTick && this instanceof net.minecraft.world.entity.NeutralMob neutralMob) neutralMob.tickInitialPersistentAnger(level); // Paper - Prevent entity loading causing async lookups - this.feetBlockState = null; + this.inBlockState = null; if (this.isPassenger() && this.getVehicle().isRemoved()) { -@@ -903,7 +923,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -938,7 +959,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } this.firstTick = false; @@ -4410,7 +4055,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 } public void setSharedFlagOnFire(boolean onFire) { -@@ -912,10 +932,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -947,10 +968,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public void checkBelowWorld() { // Paper start - Configurable nether ceiling damage @@ -4423,7 +4068,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 this.onBelowWorld(); } -@@ -1122,7 +1143,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -1155,7 +1177,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } @@ -4432,7 +4077,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7D) { movement = movement.multiply(this.stuckSpeedMultiplier); this.stuckSpeedMultiplier = Vec3.ZERO; -@@ -1131,7 +1152,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -1164,7 +1186,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess // Paper start - ignore movement changes while inactive. if (isTemporarilyActive && !(this instanceof ItemEntity) && movement == getDeltaMovement() && movementType == MoverType.SELF) { setDeltaMovement(Vec3.ZERO); @@ -4441,7 +4086,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 return; } // Paper end -@@ -1152,8 +1173,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -1185,8 +1207,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.setPos(this.getX() + vec3d1.x, this.getY() + vec3d1.y, this.getZ() + vec3d1.z); } @@ -4452,7 +4097,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 boolean flag = !Mth.equal(movement.x, vec3d1.x); boolean flag1 = !Mth.equal(movement.z, vec3d1.z); -@@ -1172,7 +1193,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -1205,7 +1227,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.checkFallDamage(vec3d1.y, this.onGround(), iblockdata, blockposition); if (this.isRemoved()) { @@ -4461,7 +4106,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 } else { if (this.horizontalCollision) { Vec3 vec3d2 = this.getDeltaMovement(); -@@ -1310,7 +1331,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -1343,7 +1365,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.setRemainingFireTicks(-this.getFireImmuneTicks()); } @@ -4470,7 +4115,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 } } // Paper start - detailed watchdog information -@@ -1808,7 +1829,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -1858,7 +1880,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public boolean fireImmune() { @@ -4479,7 +4124,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 } public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) { -@@ -1881,7 +1902,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -1931,7 +1953,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return this.isInWater() || flag; } @@ -4487,8 +4132,8 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 + public void updateInWaterStateAndDoWaterCurrentPushing() { // Purpur - package-private -> public Entity entity = this.getVehicle(); - if (entity instanceof Boat) { -@@ -2505,6 +2526,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S + if (entity instanceof Boat entityboat) { +@@ -2555,6 +2577,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess nbttagcompound.putBoolean("Paper.FreezeLock", true); } // Paper end @@ -4500,7 +4145,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 return nbttagcompound; } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT"); -@@ -2652,6 +2678,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -2702,6 +2729,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess freezeLocked = nbt.getBoolean("Paper.FreezeLock"); } // Paper end @@ -4512,7 +4157,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT"); -@@ -3027,6 +3058,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3080,6 +3112,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.passengers = ImmutableList.copyOf(list); } @@ -4526,7 +4171,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 this.gameEvent(GameEvent.ENTITY_MOUNT, passenger); } } -@@ -3066,6 +3104,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3119,6 +3158,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return false; } // CraftBukkit end @@ -4541,7 +4186,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 if (this.passengers.size() == 1 && this.passengers.get(0) == entity) { this.passengers = ImmutableList.of(); } else { -@@ -3145,12 +3191,15 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3197,12 +3244,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return Vec3.directionFromRotation(this.getRotationVector()); } @@ -4558,7 +4203,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 } this.isInsidePortal = true; -@@ -3168,7 +3217,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3220,7 +3270,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess ServerLevel worldserver1 = minecraftserver.getLevel(resourcekey); if (true && !this.isPassenger() && this.portalTime++ >= i) { // CraftBukkit @@ -4567,7 +4212,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 this.portalTime = i; // Paper start - Add EntityPortalReadyEvent io.papermc.paper.event.entity.EntityPortalReadyEvent event = new io.papermc.paper.event.entity.EntityPortalReadyEvent(this.getBukkitEntity(), worldserver1 == null ? null : worldserver1.getWorld(), org.bukkit.PortalType.NETHER); -@@ -3186,7 +3235,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3238,7 +3288,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } // Paper - Add EntityPortalReadyEvent // CraftBukkit end @@ -4576,7 +4221,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 } this.isInsidePortal = false; -@@ -3391,7 +3440,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3429,7 +3479,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public int getMaxAirSupply() { @@ -4585,7 +4230,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 } public int getAirSupply() { -@@ -3660,14 +3709,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3698,14 +3748,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } // Paper end - Fix item duplication and teleport issues if (this.level() instanceof ServerLevel && !this.isRemoved()) { @@ -4602,7 +4247,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 PortalInfo shapedetectorshape = (location == null) ? this.findDimensionEntryPoint(worldserver) : new PortalInfo(new Vec3(location.x(), location.y(), location.z()), Vec3.ZERO, this.yRot, this.xRot, worldserver, null); // CraftBukkit if (shapedetectorshape == null) { -@@ -3706,7 +3755,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3744,7 +3794,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.unRide(); // CraftBukkit end @@ -4611,7 +4256,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 // Paper start - Fix item duplication and teleport issues if (this instanceof Mob) { ((Mob) this).dropLeash(true, true); // Paper drop lead -@@ -3733,10 +3782,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3771,10 +3821,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } this.removeAfterChangingDimensions(); @@ -4624,7 +4269,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 return entity; } } else { -@@ -3854,7 +3903,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -3894,7 +3944,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public boolean canChangeDimensions() { @@ -4633,7 +4278,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 } public float getBlockExplosionResistance(Explosion explosion, BlockGetter world, BlockPos pos, BlockState blockState, FluidState fluidState, float max) { -@@ -4152,6 +4201,20 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4190,6 +4240,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return SlotAccess.NULL; } @@ -4654,7 +4299,7 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 @Override public void sendSystemMessage(Component message) {} -@@ -4429,6 +4492,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4477,6 +4541,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.yRotO = this.getYRot(); } @@ -4665,9 +4310,18 @@ index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..f2c6b52fe7fbb05afa0074684cd195f6 + // Purpur end + public boolean updateFluidHeightAndDoFluidPushing(TagKey tag, double speed) { - if (false && this.touchingUnloadedChunk()) { // Pufferfish - cost of a lookup here is the same cost as below, so skip + if (this.touchingUnloadedChunk()) { return false; -@@ -4997,4 +5066,44 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4823,7 +4893,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public float maxUpStep() { +- return 0.0F; ++ return maxUpStep; + } + + public void onExplosionHit(@Nullable Entity entity) {} +@@ -4995,4 +5065,44 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return ((net.minecraft.server.level.ServerChunkCache) level.getChunkSource()).isPositionTicking(this); } // Paper end - Expose entity id counter @@ -4725,19 +4379,20 @@ index d8cc5614502db7025349e085381b6b32ad32296a..f1b9e83206cc67e6ef29ebe088351b0a private EntitySelector() {} // Paper start - Affects Spawning API diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index dc11683ee4d8a6b7a1c42bcae36dc6e8105cd994..a9e2a758669550530eb29475ba99fe42e520f6ae 100644 +index a46bf73c608641bf1f00fd55242de71a0f2ee06e..8120f39a9689dae1233b243b74825e9ff110eac3 100644 --- a/src/main/java/net/minecraft/world/entity/EntityType.java +++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -313,13 +313,24 @@ public class EntityType implements FeatureElement, EntityTypeT +@@ -322,7 +322,8 @@ public class EntityType implements FeatureElement, EntityTypeT private Component description; @Nullable - private ResourceLocation lootTable; + private ResourceKey lootTable; - private final EntityDimensions dimensions; + private EntityDimensions dimensions; // Purpur - remove final + public void setDimensions(EntityDimensions dimensions) { this.dimensions = dimensions; } // Purpur + private final float spawnDimensionsScale; private final FeatureFlagSet requiredFeatures; - private static EntityType register(String id, EntityType.Builder type) { // CraftBukkit - decompile error +@@ -330,6 +331,16 @@ public class EntityType implements FeatureElement, EntityTypeT return (EntityType) Registry.register(BuiltInRegistries.ENTITY_TYPE, id, (EntityType) type.build(id)); // CraftBukkit - decompile error } @@ -4754,7 +4409,7 @@ index dc11683ee4d8a6b7a1c42bcae36dc6e8105cd994..a9e2a758669550530eb29475ba99fe42 public static ResourceLocation getKey(EntityType type) { return BuiltInRegistries.ENTITY_TYPE.getKey(type); } -@@ -531,6 +542,16 @@ public class EntityType implements FeatureElement, EntityTypeT +@@ -537,6 +548,16 @@ public class EntityType implements FeatureElement, EntityTypeT return this.category; } @@ -4771,7 +4426,7 @@ index dc11683ee4d8a6b7a1c42bcae36dc6e8105cd994..a9e2a758669550530eb29475ba99fe42 public String getDescriptionId() { if (this.descriptionId == null) { this.descriptionId = Util.makeDescriptionId("entity", BuiltInRegistries.ENTITY_TYPE.getKey(this)); -@@ -598,6 +619,12 @@ public class EntityType implements FeatureElement, EntityTypeT +@@ -604,6 +625,12 @@ public class EntityType implements FeatureElement, EntityTypeT entity.load(nbt); }, () -> { EntityType.LOGGER.warn("Skipping Entity with id {}", nbt.getString("id")); @@ -4785,10 +4440,10 @@ index dc11683ee4d8a6b7a1c42bcae36dc6e8105cd994..a9e2a758669550530eb29475ba99fe42 } diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -index 36422fb394a158f36c84ba0ee03cc704956c91b2..9a3210e34decb4096533c58f36687e31330198c4 100644 +index a207a31d80a302dbdfe80f8727222542d3a78da2..f5debc8ddc496cd3e2d8b253511ee5cc9a723b38 100644 --- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java +++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -@@ -314,7 +314,7 @@ public class ExperienceOrb extends Entity { +@@ -320,7 +320,7 @@ public class ExperienceOrb extends Entity { public void playerTouch(Player player) { if (!this.level().isClientSide) { if (player.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent @@ -4797,7 +4452,7 @@ index 36422fb394a158f36c84ba0ee03cc704956c91b2..9a3210e34decb4096533c58f36687e31 player.take(this, 1); int i = this.repairPlayerItems(player, this.value); -@@ -332,7 +332,7 @@ public class ExperienceOrb extends Entity { +@@ -338,7 +338,7 @@ public class ExperienceOrb extends Entity { } private int repairPlayerItems(Player player, int amount) { @@ -4806,7 +4461,7 @@ index 36422fb394a158f36c84ba0ee03cc704956c91b2..9a3210e34decb4096533c58f36687e31 if (entry != null) { ItemStack itemstack = (ItemStack) entry.getValue(); -@@ -360,13 +360,15 @@ public class ExperienceOrb extends Entity { +@@ -366,13 +366,15 @@ public class ExperienceOrb extends Entity { } } @@ -4825,7 +4480,7 @@ index 36422fb394a158f36c84ba0ee03cc704956c91b2..9a3210e34decb4096533c58f36687e31 public int getValue() { return this.value; diff --git a/src/main/java/net/minecraft/world/entity/GlowSquid.java b/src/main/java/net/minecraft/world/entity/GlowSquid.java -index 5de938f4a7f16fd3caff783564cbb7e6b2924f9a..09181e9a0d4ceac30d20f4ff488a85b0ab5b1d04 100644 +index 09fdea983772612ef3fff6b2da3cf469a34e4ec0..3e2ea26c23e88c395856b65001f2895db6a52bd4 100644 --- a/src/main/java/net/minecraft/world/entity/GlowSquid.java +++ b/src/main/java/net/minecraft/world/entity/GlowSquid.java @@ -23,6 +23,39 @@ public class GlowSquid extends Squid { @@ -4869,10 +4524,10 @@ index 5de938f4a7f16fd3caff783564cbb7e6b2924f9a..09181e9a0d4ceac30d20f4ff488a85b0 protected ParticleOptions getInkParticle() { return ParticleTypes.GLOW_SQUID_INK; diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3c0a8202e 100644 +index 6e043457a29a890bcefd27fc5bb07c1a7e4e30f7..fa698cfefccdddf5e5e9938a2959004c70f743a7 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -218,9 +218,9 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -229,9 +229,9 @@ public abstract class LivingEntity extends Entity implements Attackable { protected int deathScore; public float lastHurt; public boolean jumping; @@ -4885,15 +4540,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 protected int lerpSteps; protected double lerpX; protected double lerpY; -@@ -253,6 +253,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - protected boolean skipDropExperience; - // CraftBukkit start - public int expToDrop; -+ public float safeFallDistance = 3.0F; // Purpur - public boolean forceDrops; - public ArrayList drops = new ArrayList<>(); // Paper - Restore vanilla drops behavior - public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes; -@@ -262,6 +263,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -274,6 +274,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 @@ -4901,17 +4548,17 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 @Override public float getBukkitYaw() { -@@ -286,7 +288,8 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.effectsDirty = true; +@@ -300,7 +301,8 @@ public abstract class LivingEntity extends Entity implements Attackable { this.useItem = ItemStack.EMPTY; this.lastClimbablePos = Optional.empty(); + this.appliedScale = 1.0F; - this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type)); + this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type), this); // Purpur + this.initAttributes(); // Purpur this.craftAttributes = new CraftAttributeMap(this.attributes); // CraftBukkit // CraftBukkit - setHealth(getMaxHealth()) inlined and simplified to skip the instanceof check for EntityPlayer, as getBukkitEntity() is not initialized in constructor this.entityData.set(LivingEntity.DATA_HEALTH_ID, (float) this.getAttribute(Attributes.MAX_HEALTH).getValue()); -@@ -302,6 +305,8 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -315,6 +317,8 @@ public abstract class LivingEntity extends Entity implements Attackable { this.brain = this.makeBrain(new Dynamic(dynamicopsnbt, (Tag) dynamicopsnbt.createMap((Map) ImmutableMap.of(dynamicopsnbt.createString("memories"), (Tag) dynamicopsnbt.emptyMap())))); } @@ -4920,33 +4567,15 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 public Brain getBrain() { return this.brain; } -@@ -337,6 +342,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -350,6 +354,7 @@ public abstract class LivingEntity extends Entity implements Attackable { public static AttributeSupplier.Builder createLivingAttributes() { - return AttributeSupplier.builder().add(Attributes.MAX_HEALTH).add(Attributes.KNOCKBACK_RESISTANCE).add(Attributes.MOVEMENT_SPEED).add(Attributes.ARMOR).add(Attributes.ARMOR_TOUGHNESS).add(Attributes.MAX_ABSORPTION); + return AttributeSupplier.builder().add(Attributes.MAX_HEALTH).add(Attributes.KNOCKBACK_RESISTANCE).add(Attributes.MOVEMENT_SPEED).add(Attributes.ARMOR).add(Attributes.ARMOR_TOUGHNESS).add(Attributes.MAX_ABSORPTION).add(Attributes.STEP_HEIGHT).add(Attributes.SCALE).add(Attributes.GRAVITY).add(Attributes.SAFE_FALL_DISTANCE).add(Attributes.FALL_DAMAGE_MULTIPLIER).add(Attributes.JUMP_STRENGTH); } + public boolean shouldSendAttribute(Attribute attribute) { return true; } // Purpur @Override protected void checkFallDamage(double heightDifference, boolean onGround, BlockState state, BlockPos landedPosition) { -@@ -349,7 +355,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.tryAddSoulSpeed(); - } - -- if (!this.level().isClientSide && this.fallDistance > 3.0F && onGround && !state.isAir()) { -+ if (!this.level().isClientSide && this.fallDistance > this.safeFallDistance && onGround && !state.isAir()) { // Purpur - double d1 = this.getX(); - double d2 = this.getY(); - double d3 = this.getZ(); -@@ -364,7 +370,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - d3 = (double) landedPosition.getZ() + 0.5D + d5 / d6 * 0.5D; - } - -- float f = (float) Mth.ceil(this.fallDistance - 3.0F); -+ float f = (float) Mth.ceil(this.fallDistance - this.safeFallDistance); // Purpur - double d7 = Math.min((double) (0.2F + f / 15.0F), 2.5D); - int i = (int) (150.0D * d7); - -@@ -404,7 +410,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -418,7 +423,7 @@ public abstract class LivingEntity extends Entity implements Attackable { } super.baseTick(); @@ -4955,7 +4584,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 if (this.fireImmune() || this.level().isClientSide) { this.clearFire(); } -@@ -422,6 +428,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -436,6 +441,7 @@ public abstract class LivingEntity extends Entity implements Attackable { double d1 = this.level().getWorldBorder().getDamagePerBlock(); if (d1 > 0.0D) { @@ -4963,7 +4592,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 this.hurt(this.damageSources().outOfBorder(), (float) Math.max(1, Mth.floor(-d0 * d1))); } } -@@ -433,7 +440,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -447,7 +453,7 @@ public abstract class LivingEntity extends Entity implements Attackable { if (flag1) { this.setAirSupply(this.decreaseAirSupply(this.getAirSupply())); @@ -4972,7 +4601,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 this.setAirSupply(0); Vec3 vec3d = this.getDeltaMovement(); -@@ -445,7 +452,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -459,7 +465,7 @@ public abstract class LivingEntity extends Entity implements Attackable { this.level().addParticle(ParticleTypes.BUBBLE, this.getX() + d2, this.getY() + d3, this.getZ() + d4, vec3d.x, vec3d.y, vec3d.z); } @@ -4981,7 +4610,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 } } -@@ -506,7 +513,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -520,7 +526,7 @@ public abstract class LivingEntity extends Entity implements Attackable { this.yHeadRotO = this.yHeadRot; this.yRotO = this.getYRot(); this.xRotO = this.getXRot(); @@ -4990,7 +4619,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 } public boolean canSpawnSoulSpeedParticle() { -@@ -805,6 +812,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -837,6 +843,7 @@ public abstract class LivingEntity extends Entity implements Attackable { dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> { nbt.put("Brain", nbtbase); }); @@ -4998,7 +4627,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 } @Override -@@ -891,6 +899,11 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -924,6 +931,11 @@ public abstract class LivingEntity extends Entity implements Attackable { this.brain = this.makeBrain(new Dynamic(NbtOps.INSTANCE, nbt.get("Brain"))); } @@ -5010,7 +4639,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 } // CraftBukkit start -@@ -1036,9 +1049,31 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1059,9 +1071,31 @@ public abstract class LivingEntity extends Entity implements Attackable { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); EntityType entitytypes = entity.getType(); @@ -5044,15 +4673,15 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 } return d0; -@@ -1098,6 +1133,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1120,6 +1154,7 @@ public abstract class LivingEntity extends Entity implements Attackable { for (flag = false; iterator.hasNext(); flag = true) { // CraftBukkit start MobEffectInstance effect = (MobEffectInstance) iterator.next(); -+ if (cause == EntityPotionEffectEvent.Cause.MILK && !this.level().purpurConfig.milkClearsBeneficialEffects && effect.getEffect().isBeneficial()) continue; // Purpur ++ if (cause == EntityPotionEffectEvent.Cause.MILK && !this.level().purpurConfig.milkClearsBeneficialEffects && effect.getEffect().value().isBeneficial()) continue; // Purpur EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, cause, EntityPotionEffectEvent.Action.CLEARED); if (event.isCancelled()) { continue; -@@ -1520,13 +1556,13 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1527,13 +1562,13 @@ public abstract class LivingEntity extends Entity implements Attackable { if (entity1 instanceof net.minecraft.world.entity.player.Player) { net.minecraft.world.entity.player.Player entityhuman = (net.minecraft.world.entity.player.Player) entity1; @@ -5068,7 +4697,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 LivingEntity entityliving2 = entitywolf.getOwner(); if (entityliving2 instanceof net.minecraft.world.entity.player.Player) { -@@ -1634,6 +1670,18 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1648,6 +1683,18 @@ public abstract class LivingEntity extends Entity implements Attackable { } } @@ -5087,7 +4716,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 org.bukkit.inventory.EquipmentSlot handSlot = (hand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand) : null; EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), handSlot); event.setCancelled(itemstack == null); -@@ -1800,7 +1848,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1814,7 +1861,7 @@ public abstract class LivingEntity extends Entity implements Attackable { boolean flag = false; if (this.dead && adversary instanceof WitherBoss) { // Paper @@ -5096,7 +4725,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 BlockPos blockposition = this.blockPosition(); BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); -@@ -1846,6 +1894,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1860,6 +1907,7 @@ public abstract class LivingEntity extends Entity implements Attackable { this.dropEquipment(); // CraftBukkit - from below if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { @@ -5104,7 +4733,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 this.dropFromLootTable(source, flag); // Paper start final boolean prev = this.clearEquipmentSlots; -@@ -1854,6 +1903,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1868,6 +1916,7 @@ public abstract class LivingEntity extends Entity implements Attackable { // Paper end this.dropCustomDeathLoot(source, i, flag); this.clearEquipmentSlots = prev; // Paper @@ -5112,37 +4741,29 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 } // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops, () -> { -@@ -2113,7 +2163,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - MobEffectInstance mobeffect = this.getEffect(MobEffects.JUMP); - float f2 = mobeffect == null ? 0.0F : (float) (mobeffect.getAmplifier() + 1); - -- return Mth.ceil((fallDistance - 3.0F - f2) * damageMultiplier); -+ return Mth.ceil((fallDistance - this.safeFallDistance - f2) * damageMultiplier); // Purpur - } - } - -@@ -2336,6 +2386,20 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -2363,6 +2412,21 @@ public abstract class LivingEntity extends Entity implements Attackable { } } -+ // Purpur start -+ if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player player && damagesource.getEntity().level().purpurConfig.creativeOnePunch) { -+ if (player.isCreative()) { -+ double attackDamage = 0; -+ for (AttributeModifier modifier : player.getMainHandItem().getAttributeModifiers(EquipmentSlot.MAINHAND).get(Attributes.ATTACK_DAMAGE)) { -+ attackDamage += modifier.getAmount(); -+ } -+ if (attackDamage == 0) { -+ this.setHealth(0); -+ } -+ } -+ } -+ // Purpur end ++ // Purpur start ++ if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player player && damagesource.getEntity().level().purpurConfig.creativeOnePunch) { ++ if (player.isCreative()) { ++ double attackDamage; ++ net.minecraft.world.item.component.ItemAttributeModifiers itemattributemodifiers = player.getMainHandItem().getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, net.minecraft.world.item.component.ItemAttributeModifiers.EMPTY); ++ ++ attackDamage = itemattributemodifiers.compute(this.getAttributeBaseValue(Attributes.ATTACK_DAMAGE), EquipmentSlot.MAINHAND); ++ ++ if (attackDamage == 0) { ++ this.setHealth(0); ++ } ++ } ++ } ++ // Purpur end + if (f > 0 || !human) { if (human) { // PAIL: Be sure to drag all this code from the EntityHuman subclass each update. -@@ -2556,7 +2620,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -2586,7 +2650,7 @@ public abstract class LivingEntity extends Entity implements Attackable { @Override protected void onBelowWorld() { @@ -5151,16 +4772,16 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 } protected void updateSwingTime() { -@@ -2750,7 +2814,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -2781,7 +2845,7 @@ public abstract class LivingEntity extends Entity implements Attackable { } protected long lastJumpTime = 0L; // Paper - Prevent excessive velocity through repeated crits - protected void jumpFromGround() { + public void jumpFromGround() { // Purpur - protected -> public - Vec3 vec3d = this.getDeltaMovement(); - // Paper start - Prevent excessive velocity through repeated crits - long time = System.nanoTime(); -@@ -2902,6 +2966,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + float f = this.getJumpPower(); + + if (f > 1.0E-5F) { +@@ -2941,6 +3005,7 @@ public abstract class LivingEntity extends Entity implements Attackable { if (f3 > 0.0F) { this.playSound(this.getFallDamageSound((int) f3), 1.0F, 1.0F); @@ -5168,7 +4789,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 this.hurt(this.damageSources().flyIntoWall(), f3); } } -@@ -3123,10 +3188,10 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3163,10 +3228,10 @@ public abstract class LivingEntity extends Entity implements Attackable { } this.run += (f3 - this.run) * 0.3F; @@ -5182,7 +4803,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 // Paper start - stop large pitch and yaw changes from crashing the server this.yRotO += Math.round((this.getYRot() - this.yRotO) / 360.0F) * 360.0F; -@@ -3138,7 +3203,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3178,7 +3243,7 @@ public abstract class LivingEntity extends Entity implements Attackable { this.yHeadRotO += Math.round((this.yHeadRot - this.yHeadRotO) / 360.0F) * 360.0F; // Paper end @@ -5191,7 +4812,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 this.animStep += f2; if (this.isFallFlying()) { ++this.fallFlyTicks; -@@ -3433,19 +3498,19 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3401,19 +3466,19 @@ public abstract class LivingEntity extends Entity implements Attackable { } this.setDeltaMovement(d0, d1, d2); @@ -5216,7 +4837,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 if (this.jumping && this.isAffectedByFluids()) { double d3; -@@ -3472,8 +3537,8 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3440,8 +3505,8 @@ public abstract class LivingEntity extends Entity implements Attackable { this.noJumpDelay = 0; } @@ -5227,7 +4848,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 this.xxa *= 0.98F; this.zza *= 0.98F; this.updateFallFlying(); -@@ -3500,8 +3565,8 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3466,8 +3531,8 @@ public abstract class LivingEntity extends Entity implements Attackable { this.travel(vec3d1); } @@ -5238,7 +4859,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 if (!this.level().isClientSide && !this.isDeadOrDying() && !this.freezeLocked) { // Paper - Freeze Tick Lock API int i = this.getTicksFrozen(); -@@ -3518,18 +3583,20 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3484,18 +3549,20 @@ public abstract class LivingEntity extends Entity implements Attackable { this.hurt(this.damageSources().freeze(), 1.0F); } @@ -5264,7 +4885,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 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()); -@@ -3539,12 +3606,48 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3505,12 +3572,48 @@ 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()); } } @@ -5305,7 +4926,7 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 + flag = false; + } + if (flag) { -+ this.setSecondsOnFire(8); ++ this.igniteForSeconds(8); + } + } + } @@ -5313,11 +4934,11 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 } public boolean isSensitiveToWater() { -@@ -3565,7 +3668,16 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3531,7 +3634,16 @@ public abstract class LivingEntity extends Entity implements Attackable { int j = i / 10; if (j % 2 == 0) { -- itemstack.hurtAndBreak(1, this, (entityliving) -> { +- itemstack.hurtAndBreak(1, this, EquipmentSlot.CHEST); + // Purpur start + int damage = level().purpurConfig.elytraDamagePerSecond; + if (level().purpurConfig.elytraDamageMultiplyBySpeed > 0) { @@ -5326,24 +4947,24 @@ index 366121188c5abb550ed0a5f99d25c001628685bb..d6705dce3bc8c1964184fe425386b3f3 + damage *= (int) speed; + } + } -+ itemstack.hurtAndBreak(damage, this, (entityliving) -> { ++ itemstack.hurtAndBreak(damage, this, EquipmentSlot.CHEST); + // Purpur end - entityliving.broadcastBreakEvent(EquipmentSlot.CHEST); - }); } + + this.gameEvent(GameEvent.ELYTRA_GLIDE); diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152b29b370e 100644 +index e89f9c3e887601d8461eb967ae0bf582b672f631..56da8a4600688efd1987d82d4fcad1757e33f4f2 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -66,6 +66,7 @@ import net.minecraft.world.item.ProjectileWeaponItem; - import net.minecraft.world.item.SpawnEggItem; +@@ -75,6 +75,7 @@ import net.minecraft.world.item.SpawnEggItem; import net.minecraft.world.item.SwordItem; + import net.minecraft.world.item.component.ItemAttributeModifiers; import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.Level; -@@ -136,6 +137,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -151,6 +152,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti private BlockPos restrictCenter; private float restrictRadius; @@ -5351,7 +4972,7 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 public boolean aware = true; // CraftBukkit protected Mob(EntityType type, Level world) { -@@ -149,8 +151,8 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -165,8 +167,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti this.restrictRadius = -1.0F; this.goalSelector = new GoalSelector(world.getProfilerSupplier()); this.targetSelector = new GoalSelector(world.getProfilerSupplier()); @@ -5362,7 +4983,7 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 this.jumpControl = new JumpControl(this); this.bodyRotationControl = this.createBodyControl(); this.navigation = this.createNavigation(world); -@@ -325,6 +327,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -338,6 +340,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti entityliving = null; } } @@ -5370,7 +4991,7 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 this.target = entityliving; return true; // CraftBukkit end -@@ -365,15 +368,35 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -373,15 +376,35 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti @Override public void baseTick() { super.baseTick(); @@ -5406,9 +5027,9 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 + // Purpur end + @Override - protected void playHurtSound(DamageSource source) { + protected void playHurtSound(DamageSource damageSource) { this.resetAmbientSoundTime(); -@@ -563,6 +586,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -584,6 +607,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti } nbt.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit @@ -5416,7 +5037,7 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 } @Override -@@ -633,6 +657,11 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -668,6 +692,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti this.aware = nbt.getBoolean("Bukkit.Aware"); } // CraftBukkit end @@ -5428,7 +5049,7 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 } @Override -@@ -676,8 +705,8 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -718,8 +747,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti @Override public void aiStep() { super.aiStep(); @@ -5439,7 +5060,7 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 Vec3i baseblockposition = this.getPickupReach(); List list = this.level().getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate((double) baseblockposition.getX(), (double) baseblockposition.getY(), (double) baseblockposition.getZ())); Iterator iterator = list.iterator(); -@@ -696,7 +725,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -738,7 +767,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti } } @@ -5448,74 +5069,73 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 } protected Vec3i getPickupReach() { -@@ -908,46 +937,46 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -963,44 +992,44 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti return; } // Paper end - Allow nerfed mobs to jump and float -- this.level().getProfiler().push("sensing"); -+ //this.level().getProfiler().push("sensing"); // Purpur +- ProfilerFiller gameprofilerfiller = this.level().getProfiler(); ++ //ProfilerFiller gameprofilerfiller = this.level().getProfiler(); // Purpur + +- gameprofilerfiller.push("sensing"); ++ //gameprofilerfiller.push("sensing"); // Purpur this.sensing.tick(); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - int i = this.level().getServer().getTickCount() + this.getId(); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + int i = this.tickCount + this.getId(); if (i % 2 != 0 && this.tickCount > 1) { -- this.level().getProfiler().push("targetSelector"); -+ //this.level().getProfiler().push("targetSelector"); // Purpur - if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking +- gameprofilerfiller.push("targetSelector"); ++ //gameprofilerfiller.push("targetSelector"); // Purpur this.targetSelector.tickRunningGoals(false); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("goalSelector"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("goalSelector"); // Purpur - if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("goalSelector"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("goalSelector"); // Purpur this.goalSelector.tickRunningGoals(false); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } else { -- this.level().getProfiler().push("targetSelector"); -+ //this.level().getProfiler().push("targetSelector"); // Purpur - if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking +- gameprofilerfiller.push("targetSelector"); ++ //gameprofilerfiller.push("targetSelector"); // Purpur this.targetSelector.tick(); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("goalSelector"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("goalSelector"); // Purpur - if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("goalSelector"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("goalSelector"); // Purpur this.goalSelector.tick(); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } -- this.level().getProfiler().push("navigation"); -+ //this.level().getProfiler().push("navigation"); // Purpur +- gameprofilerfiller.push("navigation"); ++ //gameprofilerfiller.push("navigation"); // Purpur this.navigation.tick(); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("mob tick"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("mob tick"); // Purpur +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("mob tick"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("mob tick"); // Purpur this.customServerAiStep(); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("controls"); -- this.level().getProfiler().push("move"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("controls"); // Purpur -+ //this.level().getProfiler().push("move"); // Purpur +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("controls"); +- gameprofilerfiller.push("move"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("controls"); // Purpur ++ //gameprofilerfiller.push("move"); // Purpur this.moveControl.tick(); -- this.level().getProfiler().popPush("look"); -+ //this.level().getProfiler().popPush("look"); // Purpur +- gameprofilerfiller.popPush("look"); ++ //gameprofilerfiller.popPush("look"); // Purpur this.lookControl.tick(); -- this.level().getProfiler().popPush("jump"); -+ //this.level().getProfiler().popPush("jump"); // Purpur +- gameprofilerfiller.popPush("jump"); ++ //gameprofilerfiller.popPush("jump"); // Purpur this.jumpControl.tick(); -- this.level().getProfiler().pop(); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.pop(); // Purpur this.sendDebugPackets(); } -@@ -1183,6 +1212,12 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -1309,6 +1338,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti } @@ -5528,24 +5148,24 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 @Nullable public static Item getEquipmentForSlot(EquipmentSlot equipmentSlot, int equipmentLevel) { switch (equipmentSlot) { -@@ -1277,7 +1312,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -1403,7 +1438,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti RandomSource randomsource = world.getRandom(); - this.getAttribute(Attributes.FOLLOW_RANGE).addPermanentModifier(new AttributeModifier("Random spawn bonus", randomsource.triangle(0.0D, 0.11485000000000001D), AttributeModifier.Operation.MULTIPLY_BASE)); -- if (randomsource.nextFloat() < 0.05F) { -+ if (randomsource.nextFloat() < world.getLevel().purpurConfig.entityLeftHandedChance) { // Purpur - this.setLeftHanded(true); - } else { - this.setLeftHanded(false); -@@ -1325,6 +1360,7 @@ public abstract class Mob extends LivingEntity implements Targeting { + this.getAttribute(Attributes.FOLLOW_RANGE).addPermanentModifier(new AttributeModifier("Random spawn bonus", randomsource.triangle(0.0D, 0.11485000000000001D), AttributeModifier.Operation.ADD_MULTIPLIED_BASE)); +- this.setLeftHanded(randomsource.nextFloat() < 0.05F); ++ this.setLeftHanded(randomsource.nextFloat() < world.getLevel().purpurConfig.entityLeftHandedChance); // Purpur + return entityData; + } + +@@ -1450,6 +1485,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti if (!this.isAlive()) { return InteractionResult.PASS; } else if (this.getLeashHolder() == player) { + if (hand == InteractionHand.OFF_HAND && (level().purpurConfig.villagerCanBeLeashed || level().purpurConfig.wanderingTraderCanBeLeashed) && this instanceof net.minecraft.world.entity.npc.AbstractVillager) return InteractionResult.CONSUME; // Purpur // CraftBukkit start - fire PlayerUnleashEntityEvent // Paper start - Expand EntityUnleashEvent - org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand, !player.getAbilities().instabuild); -@@ -1399,7 +1435,7 @@ public abstract class Mob extends LivingEntity implements Targeting { + org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand, !player.hasInfiniteMaterials()); +@@ -1525,7 +1561,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti protected void onOffspringSpawnedFromEgg(Player player, Mob child) {} protected InteractionResult mobInteract(Player player, InteractionHand hand) { @@ -5554,7 +5174,7 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 } public boolean isWithinRestriction() { -@@ -1710,6 +1746,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -1840,21 +1876,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti this.setLastHurtMob(target); } @@ -5562,9 +5182,6 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 return flag; } -@@ -1730,17 +1767,7 @@ public abstract class Mob extends LivingEntity implements Targeting { - } - public boolean isSunBurnTick() { - if (this.level().isDay() && !this.level().isClientSide) { - float f = this.getLightLevelDependentMagicValue(); @@ -5581,7 +5198,7 @@ index a6b48b4eab6e0e98205fd9cafc3cde5ad39651af..dd275ece5887f5215cb785564af27152 } @Override -@@ -1788,4 +1815,56 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -1902,4 +1929,56 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti return itemmonsteregg == null ? null : new ItemStack(itemmonsteregg); } @@ -5652,13 +5269,13 @@ index 2ee48ac3b665db2b02bcb1a30ec972d43a3725b0..59e8f5431ce5026209e1428b5fa5b548 } // Paper end - custom shear drops diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -index 8d6954d05d2bf6d6c1c4953db3127b011a858cec..49c45a0987b8393a9c92ab756c721f17c232ddb1 100644 +index 9ef8f014af332da129bfcd3370da983ec035ecc6..c51b429822d56761f69c49ecd4addfab7b90bad8 100644 --- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java +++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -@@ -24,14 +24,21 @@ public class AttributeMap { - private final Set dirtyAttributes = Sets.newHashSet(); +@@ -22,13 +22,20 @@ public class AttributeMap { + private final Map, AttributeInstance> attributes = new Object2ObjectOpenHashMap<>(); + private final Set dirtyAttributes = new ObjectOpenHashSet<>(); private final AttributeSupplier supplier; - private final java.util.function.Function createInstance; // Pufferfish + private final net.minecraft.world.entity.LivingEntity entity; // Purpur public AttributeMap(AttributeSupplier defaultAttributes) { @@ -5669,29 +5286,28 @@ index 8d6954d05d2bf6d6c1c4953db3127b011a858cec..49c45a0987b8393a9c92ab756c721f17 + this.entity = entity; + // Purpur end this.supplier = defaultAttributes; - this.createInstance = attributex -> this.supplier.createInstance(this::onAttributeModified, attributex); // Pufferfish } private void onAttributeModified(AttributeInstance instance) { -- if (instance.getAttribute().isClientSyncable()) { -+ if (instance.getAttribute().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute()))) { // Purpur +- if (instance.getAttribute().value().isClientSyncable()) { ++ if (instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur this.dirtyAttributes.add(instance); } } -@@ -41,7 +48,7 @@ public class AttributeMap { +@@ -38,7 +45,7 @@ public class AttributeMap { } public Collection getSyncableAttributes() { -- return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().isClientSyncable()).collect(Collectors.toList()); -+ return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().isClientSyncable() && (entity == null || entity.shouldSendAttribute(attribute.getAttribute()))).collect(Collectors.toList()); // Purpur +- return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().value().isClientSyncable()).collect(Collectors.toList()); ++ return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(attribute.getAttribute().value()))).collect(Collectors.toList()); // Purpur } - + @Nullable diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java -index c92583b6d1527db32f4a644f30c8f8468e9e2fc2..b8f65dc8f0db4bbe5f9c223e4ba129738fbfd795 100644 +index 10a1434313b11dae8210484583c6bf3b627416f7..35af18f371b3beaf81fcdca79fefe85e0a862b50 100644 --- a/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java +++ b/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java -@@ -123,7 +123,7 @@ public class DefaultAttributes { +@@ -129,7 +129,7 @@ public class DefaultAttributes { .put(EntityType.OCELOT, Ocelot.createAttributes().build()) .put(EntityType.PANDA, Panda.createAttributes().build()) .put(EntityType.PARROT, Parrot.createAttributes().build()) @@ -5726,7 +5342,7 @@ index e1b6fe9ecda25f86431baf414f1bfd3a26a8b2bd..6499e3fe49e453db11e51eaf717ca8b3 // Paper end - optimise POI access Path path = findPathToPois(entity, set); diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java -index 03092417cd8ab5c6d266f3af9f20f47b34cfaba3..8f7d9f8a5138bcd572691d66c814aaa7c308b317 100644 +index 9379dd4056018b52c93ed4888dcdc94579bd9691..612a14806ec63b0dcf31814396282f4b7f4a527c 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java @@ -59,9 +59,9 @@ public abstract class Behavior implements BehaviorContro @@ -5758,10 +5374,10 @@ index 03092417cd8ab5c6d266f3af9f20f47b34cfaba3..8f7d9f8a5138bcd572691d66c814aaa7 protected void tick(ServerLevel world, E entity, long time) { diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -index d3a2a6dee2d83b3df0ddc521c080f7d72b709461..a1acc479c9d6a838e3180da3ac8a3a02d22db5c1 100644 +index 2ade08d1466660ee1787fa97908002ef56389712..8d4e206aa05b95b7bfec5d23496085cf55a3e1de 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -@@ -40,17 +40,19 @@ public class HarvestFarmland extends Behavior { +@@ -41,17 +41,19 @@ public class HarvestFarmland extends Behavior { private long nextOkStartTime; private int timeWorkedSoFar; private final List validFarmlandAroundVillager = Lists.newArrayList(); @@ -5783,7 +5399,7 @@ index d3a2a6dee2d83b3df0ddc521c080f7d72b709461..a1acc479c9d6a838e3180da3ac8a3a02 BlockPos.MutableBlockPos blockposition_mutableblockposition = entity.blockPosition().mutable(); this.validFarmlandAroundVillager.clear(); -@@ -81,6 +83,7 @@ public class HarvestFarmland extends Behavior { +@@ -82,6 +84,7 @@ public class HarvestFarmland extends Behavior { Block block = iblockdata.getBlock(); Block block1 = world.getBlockState(pos.below()).getBlock(); @@ -5791,7 +5407,7 @@ index d3a2a6dee2d83b3df0ddc521c080f7d72b709461..a1acc479c9d6a838e3180da3ac8a3a02 return block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata) || iblockdata.isAir() && block1 instanceof FarmBlock; } -@@ -106,20 +109,20 @@ public class HarvestFarmland extends Behavior { +@@ -107,20 +110,20 @@ public class HarvestFarmland extends Behavior { Block block = iblockdata.getBlock(); Block block1 = world.getBlockState(this.aboveFarmlandPos.below()).getBlock(); @@ -5815,7 +5431,7 @@ index d3a2a6dee2d83b3df0ddc521c080f7d72b709461..a1acc479c9d6a838e3180da3ac8a3a02 Item item = itemstack.getItem(); if (item instanceof BlockItem) { -@@ -135,7 +138,7 @@ public class HarvestFarmland extends Behavior { +@@ -136,7 +139,7 @@ public class HarvestFarmland extends Behavior { } if (flag) { @@ -5825,7 +5441,7 @@ index d3a2a6dee2d83b3df0ddc521c080f7d72b709461..a1acc479c9d6a838e3180da3ac8a3a02 if (itemstack.isEmpty()) { inventorysubcontainer.setItem(j, ItemStack.EMPTY); diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java b/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java -index 42ae4d293a420f0b8eb476df6389b2e7a693895f..97c20c5b89e6d7e4ed844eff39ee55dfa8988d37 100644 +index 736f46d552d558bf0edd9a86601b5fbb6940815b..cf039181dfe0ddb3ccda44064a5d8a2f6c5c432c 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java @@ -57,7 +57,7 @@ public class InteractWithDoor { @@ -5868,15 +5484,15 @@ index 18dad0825616c4167a0a7555689ee64910a87e09..6945992491027d43eca4f1ca697ad45c && this.lookTime > 0 && entity.getBrain().getMemory(MemoryModuleType.INTERACTION_TARGET).isPresent(); diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java b/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java -index e215491ebaebfc51445adc01452ce768fff3e2dc..ff32c022fa213142ca4b3ff8e74b6eba8ef52169 100644 +index 8508ac7de8cda3127b73e11ff4aee62502e65ead..b1544e028d5a9b84b944e1fb5a12bb163067fb54 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java -@@ -61,6 +61,12 @@ public class TradeWithVillager extends Behavior { +@@ -59,6 +59,12 @@ public class TradeWithVillager extends Behavior { throwHalfStack(entity, ImmutableSet.of(Items.WHEAT), villager); } + // Purpur start -+ if (world.purpurConfig.villagerClericsFarmWarts && world.purpurConfig.villagerClericFarmersThrowWarts && entity.getVillagerData().getProfession() == VillagerProfession.CLERIC && entity.getInventory().countItem(Items.NETHER_WART) > Items.NETHER_WART.getMaxStackSize() / 2) { ++ if (world.purpurConfig.villagerClericsFarmWarts && world.purpurConfig.villagerClericFarmersThrowWarts && entity.getVillagerData().getProfession() == VillagerProfession.CLERIC && entity.getInventory().countItem(Items.NETHER_WART) > Items.NETHER_WART.getDefaultMaxStackSize() / 2) { + throwHalfStack(entity, ImmutableSet.of(Items.NETHER_WART), villager); + } + // Purpur end @@ -5885,10 +5501,10 @@ index e215491ebaebfc51445adc01452ce768fff3e2dc..ff32c022fa213142ca4b3ff8e74b6eba throwHalfStack(entity, this.trades, villager); } diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java -index d2917f9b215919890f28b513601863ccaced17c7..58338e240079f2de1669e8c2ce839451511feafd 100644 +index f000a6c1e61198e6dd06ae5f084d12fdf309f50a..3091d985ba9c55d404332576320718840538722e 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java -@@ -49,8 +49,13 @@ public class VillagerGoalPackages { +@@ -52,8 +52,13 @@ public class VillagerGoalPackages { } public static ImmutableList>> getWorkPackage(VillagerProfession profession, float speed) { @@ -5904,10 +5520,10 @@ index d2917f9b215919890f28b513601863ccaced17c7..58338e240079f2de1669e8c2ce839451 } else { workAtPoi = new WorkAtPoi(); diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java -index 0cc411dd39d981187c9e9a3c5eb8043b19a09b98..f7032f4ea55f5aca293c2640686238b7af0f9c80 100644 +index 0a608418f87b71d5d71706712e1f82da0d7e4d34..03e7ca83e4c28dfaa5b52bcb100bd542db105970 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java -@@ -127,8 +127,10 @@ public class VillagerMakeLove extends Behavior { +@@ -125,8 +125,10 @@ public class VillagerMakeLove extends Behavior { return Optional.empty(); } // Move age setting down @@ -5921,7 +5537,7 @@ index 0cc411dd39d981187c9e9a3c5eb8043b19a09b98..f7032f4ea55f5aca293c2640686238b7 // CraftBukkit end world.broadcastEntityEvent(entityvillager2, (byte) 12); diff --git a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java -index ca02566b20dd52a59bc7b150529a1d68bc560ab0..10265fd19c90cea34372a786bb272dbcdd91b993 100644 +index c8fd5696de7c3623cdb4f498190a5c2708cf843e..e403d9dfeeaa3dcf53be790d761e7e922419efb0 100644 --- a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java +++ b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java @@ -29,6 +29,20 @@ public class MoveControl implements Control { @@ -6003,10 +5619,10 @@ index 4e2c23ccdf4e4a4d65b291dbe20952bae1838bff..0da884a833f6c707fea512e826658c3b this.level.setBlock(blockposition1, Blocks.DIRT.defaultBlockState(), 2); } diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -index d78e1f6191738d426968efc24e734f04b0fc7edb..a2cca3d528625d49411a94e2b6ec578fec9b10da 100644 +index 74d4f653d5c7f1923c59019effd78337402f7025..b4e4670536f6dcea109c029d75d9710cb386f1d0 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -@@ -104,8 +104,8 @@ public class GoalSelector { +@@ -87,8 +87,8 @@ public class GoalSelector { } public void tick() { @@ -6017,10 +5633,10 @@ index d78e1f6191738d426968efc24e734f04b0fc7edb..a2cca3d528625d49411a94e2b6ec578f for (WrappedGoal wrappedGoal : this.availableGoals) { if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams -@@ -122,8 +122,8 @@ public class GoalSelector { - } +@@ -97,8 +97,8 @@ public class GoalSelector { } + this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning()); - profilerFiller.pop(); - profilerFiller.push("goalUpdate"); + //profilerFiller.pop(); // Purpur @@ -6028,7 +5644,7 @@ index d78e1f6191738d426968efc24e734f04b0fc7edb..a2cca3d528625d49411a94e2b6ec578f for (WrappedGoal wrappedGoal2 : this.availableGoals) { // Paper start -@@ -143,13 +143,13 @@ public class GoalSelector { +@@ -118,13 +118,13 @@ public class GoalSelector { } } @@ -6045,7 +5661,7 @@ index d78e1f6191738d426968efc24e734f04b0fc7edb..a2cca3d528625d49411a94e2b6ec578f for (WrappedGoal wrappedGoal : this.availableGoals) { if (wrappedGoal.isRunning() && (tickAll || wrappedGoal.requiresUpdateEveryTick())) { -@@ -157,7 +157,7 @@ public class GoalSelector { +@@ -132,7 +132,7 @@ public class GoalSelector { } } @@ -6091,7 +5707,7 @@ index 515c1f671cb2c3a7cc23053aedf404bbbe77af3e..42a1e5b9c08a9245dd0ce6d4025e3bb5 if (this.mob.isUsingItem()) { if (!bl && this.seeTime < -60) { diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -index 5580a396a56c6e0f364a5368985ee99b9e2be0a8..3facfd6eee17cb0b59425494c966e19833660dd2 100644 +index 6634228ef002cbef67980272a26be4a75c954116..a61abba840a55fb4fbc9716a5e05eb2778068785 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java @@ -40,7 +40,7 @@ public class RemoveBlockGoal extends MoveToBlockGoal { @@ -6104,7 +5720,7 @@ index 5580a396a56c6e0f364a5368985ee99b9e2be0a8..3facfd6eee17cb0b59425494c966e198 } else if (this.nextStartTick > 0) { --this.nextStartTick; diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java -index b0944fa1f3849dd24cd010fa0a6638f5fd7179d1..a3074ec9b430c9d0a0ef33fe353db643849fab7d 100644 +index b0944fa1f3849dd24cd010fa0a6638f5fd7179d1..d409ae987088df3d47192128401d7491aaabc87c 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java @@ -67,7 +67,7 @@ public class RunAroundLikeCrazyGoal extends Goal { @@ -6112,7 +5728,7 @@ index b0944fa1f3849dd24cd010fa0a6638f5fd7179d1..a3074ec9b430c9d0a0ef33fe353db643 int j = this.horse.getMaxTemper(); - if (j > 0 && this.horse.getRandom().nextInt(j) < i && !CraftEventFactory.callEntityTameEvent(this.horse, ((CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { // CraftBukkit - fire EntityTameEvent -+ if ((this.horse.level().purpurConfig.alwaysTameInCreative && ((Player) entity).getAbilities().instabuild) || (j > 0 && this.horse.getRandom().nextInt(j) < i && !CraftEventFactory.callEntityTameEvent(this.horse, ((CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled())) { // CraftBukkit - fire EntityTameEvent // Purpur ++ if ((this.horse.level().purpurConfig.alwaysTameInCreative && entityhuman.hasInfiniteMaterials()) || (j > 0 && this.horse.getRandom().nextInt(j) < i && !CraftEventFactory.callEntityTameEvent(this.horse, ((CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled())) { // CraftBukkit - fire EntityTameEvent // Purpur this.horse.tameWithName(entityhuman); return; } @@ -6136,10 +5752,10 @@ index 137ec75ee803789deb7b1ca93dd9369c9af362b9..ca95d25af3e9a0536868b0c7fd8e7d2f } } diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java -index 0d9b194781d152e842c9a4b8d6f23d307b2e4452..00cf59524477ec79d4354cc403fc3e75a63b81a0 100644 +index 13f8c2cb42334ba3b573ca44ace1d3df76e41ff7..baca552e52c728867fcb0527b6c3eb394b2b9c7f 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java -@@ -62,7 +62,7 @@ public class TemptGoal extends Goal { +@@ -64,7 +64,7 @@ public class TemptGoal extends Goal { } private boolean shouldFollow(LivingEntity entity) { @@ -6149,7 +5765,7 @@ index 0d9b194781d152e842c9a4b8d6f23d307b2e4452..00cf59524477ec79d4354cc403fc3e75 @Override diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index e3a7eaf31ab19cc9f23a0c87649b74bb42976cb4..e12cf130678bda7c1f5873cb03172a698e18fc85 100644 +index 2e9991e6b3c05584002744a2ee2579b1dba218b2..544920a31b649985333f82beafa94a3392f5853e 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java @@ -172,12 +172,12 @@ public abstract class PathNavigation { @@ -6224,7 +5840,7 @@ index 51772f03a3469b11e7166ec6f3a1b9c64a606221..02f2f46ccc48bb4d9bd08555818b0489 this.seen.add(i); } else { diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java -index 9e90cb2f51d1bacacb287e912d14ab9152523205..e553f52de2e0b30511ac1b73cb436374017cd7d7 100644 +index 85b4b24361e785acf75571ff98f924c00ae80748..09a7b418ddf564c0be13297f7c216db2e7ae1578 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java @@ -53,10 +53,10 @@ public abstract class Sensor { @@ -6241,7 +5857,7 @@ index 9e90cb2f51d1bacacb287e912d14ab9152523205..e553f52de2e0b30511ac1b73cb436374 } diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -index 28cff997a1b263784e245f692adbff2a888a2d53..13b8141bdb2a1663431be645eb091f9e7638f3d0 100644 +index d2f0c3b26d4beedb49d86e0242d843590d469d02..7463eefb7d09ea55fe8780210e7e967c2fe7896d 100644 --- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java +++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java @@ -64,6 +64,10 @@ public class TargetingConditions { @@ -6256,18 +5872,10 @@ index 28cff997a1b263784e245f692adbff2a888a2d53..13b8141bdb2a1663431be645eb091f9e if (baseEntity == null) { if (this.isCombat && (!targetEntity.canBeSeenAsEnemy() || targetEntity.level().getDifficulty() == Difficulty.PEACEFUL)) { diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index 4fba7c2f6ec363846a772ef2a63e9b3fc1037de5..735445456bbfab8a64df488fed30f0be28d50159 100644 +index dc27ddf5131e7398a5390a5187261d4c7fb6ccaa..274db35be501d1dd0c5407d350a37b04bf4fbb7e 100644 --- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java +++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -@@ -19,6 +19,7 @@ import net.minecraft.world.entity.EntityDimensions; - import net.minecraft.world.entity.EntityType; - import net.minecraft.world.entity.Mob; - import net.minecraft.world.entity.MobSpawnType; -+import net.minecraft.world.entity.MoverType; - import net.minecraft.world.entity.Pose; - import net.minecraft.world.entity.ai.attributes.AttributeSupplier; - import net.minecraft.world.entity.ai.attributes.Attributes; -@@ -46,12 +47,59 @@ public class Bat extends AmbientCreature { +@@ -44,12 +44,59 @@ public class Bat extends AmbientCreature { public Bat(EntityType type, Level world) { super(type, world); @@ -6318,7 +5926,7 @@ index 4fba7c2f6ec363846a772ef2a63e9b3fc1037de5..735445456bbfab8a64df488fed30f0be + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; + setSpeed(speed); + Vec3 mot = getDeltaMovement(); -+ move(MoverType.SELF, mot.multiply(speed, 0.25, speed)); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.25, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } @@ -6327,7 +5935,7 @@ index 4fba7c2f6ec363846a772ef2a63e9b3fc1037de5..735445456bbfab8a64df488fed30f0be @Override public boolean isFlapping() { return !this.isResting() && (float) this.tickCount % 10.0F == 0.0F; -@@ -101,7 +149,7 @@ public class Bat extends AmbientCreature { +@@ -99,7 +146,7 @@ public class Bat extends AmbientCreature { protected void pushEntities() {} public static AttributeSupplier.Builder createAttributes() { @@ -6336,7 +5944,7 @@ index 4fba7c2f6ec363846a772ef2a63e9b3fc1037de5..735445456bbfab8a64df488fed30f0be } public boolean isResting() { -@@ -134,6 +182,14 @@ public class Bat extends AmbientCreature { +@@ -132,6 +179,14 @@ public class Bat extends AmbientCreature { @Override protected void customServerAiStep() { @@ -6351,7 +5959,7 @@ index 4fba7c2f6ec363846a772ef2a63e9b3fc1037de5..735445456bbfab8a64df488fed30f0be super.customServerAiStep(); BlockPos blockposition = this.blockPosition(); BlockPos blockposition1 = blockposition.above(); -@@ -212,6 +268,28 @@ public class Bat extends AmbientCreature { +@@ -210,6 +265,28 @@ public class Bat extends AmbientCreature { } } @@ -6380,7 +5988,7 @@ index 4fba7c2f6ec363846a772ef2a63e9b3fc1037de5..735445456bbfab8a64df488fed30f0be @Override public void readAdditionalSaveData(CompoundTag nbt) { super.readAdditionalSaveData(nbt); -@@ -231,7 +309,7 @@ public class Bat extends AmbientCreature { +@@ -229,7 +306,7 @@ public class Bat extends AmbientCreature { int i = world.getMaxLocalRawBrightness(pos); byte b0 = 4; @@ -6389,19 +5997,19 @@ index 4fba7c2f6ec363846a772ef2a63e9b3fc1037de5..735445456bbfab8a64df488fed30f0be b0 = 7; } else if (random.nextBoolean()) { return false; -@@ -245,6 +323,7 @@ public class Bat extends AmbientCreature { - private static boolean isSpookySeason = false; - private static final int ONE_HOUR = 20 * 60 * 60; - private static int lastSpookyCheck = -ONE_HOUR; +@@ -239,6 +316,7 @@ public class Bat extends AmbientCreature { + } + } + + public static boolean isHalloweenSeason(Level level) { return level.purpurConfig.forceHalloweenSeason || isHalloween(); } // Purpur private static boolean isHalloween() { - if (net.minecraft.server.MinecraftServer.currentTick - lastSpookyCheck > ONE_HOUR) { LocalDate localdate = LocalDate.now(); + int i = localdate.get(ChronoField.DAY_OF_MONTH); diff --git a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java -index 401cffccd3c6adedcbd3986cd13733772953b31b..b8f973505b184cf198b6782a6f423c921c3881a7 100644 +index 3231eaa6af2ddfe4095ff2d650f580ebd4d43aea..e8cb124d232f7316cc8c35dd8bd12f79bbcda7d6 100644 --- a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java +++ b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java -@@ -94,6 +94,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { +@@ -87,6 +87,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { @Override protected void registerGoals() { super.registerGoals(); @@ -6409,7 +6017,7 @@ index 401cffccd3c6adedcbd3986cd13733772953b31b..b8f973505b184cf198b6782a6f423c92 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)); -@@ -107,7 +108,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { +@@ -100,7 +101,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { @Override public void travel(Vec3 movementInput) { if (this.isEffectiveAi() && this.isInWater()) { @@ -6418,7 +6026,7 @@ index 401cffccd3c6adedcbd3986cd13733772953b31b..b8f973505b184cf198b6782a6f423c92 this.move(MoverType.SELF, this.getDeltaMovement()); this.setDeltaMovement(this.getDeltaMovement().scale(0.9)); if (this.getTarget() == null) { -@@ -168,7 +169,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { +@@ -161,7 +162,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { protected void playStepSound(BlockPos pos, BlockState state) { } @@ -6427,7 +6035,7 @@ index 401cffccd3c6adedcbd3986cd13733772953b31b..b8f973505b184cf198b6782a6f423c92 private final AbstractFish fish; FishMoveControl(AbstractFish owner) { -@@ -176,14 +177,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { +@@ -169,14 +170,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { this.fish = owner; } @@ -6453,7 +6061,7 @@ index 401cffccd3c6adedcbd3986cd13733772953b31b..b8f973505b184cf198b6782a6f423c92 double d = this.wantedX - this.fish.getX(); double e = this.wantedY - this.fish.getY(); diff --git a/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java -index 081d1e38b7b1f286e138b0981aaa760e58761215..a64ab2058d4e3439bf6ee418f3192b83c346eb85 100644 +index 5193cf1d3c922d750a11e492b7636215e23ad0d6..7f90a0d8f65c96844df06b7c4fa3da28a6f51dd1 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Animal.java +++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java @@ -42,6 +42,7 @@ public abstract class Animal extends AgeableMob { @@ -6464,7 +6072,7 @@ index 081d1e38b7b1f286e138b0981aaa760e58761215..a64ab2058d4e3439bf6ee418f3192b83 protected Animal(EntityType type, Level world) { super(type, world); -@@ -151,7 +152,7 @@ public abstract class Animal extends AgeableMob { +@@ -146,7 +147,7 @@ public abstract class Animal extends AgeableMob { if (this.isFood(itemstack)) { int i = this.getAge(); @@ -6473,7 +6081,7 @@ index 081d1e38b7b1f286e138b0981aaa760e58761215..a64ab2058d4e3439bf6ee418f3192b83 final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying this.usePlayerItem(player, hand, itemstack); this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying -@@ -242,12 +243,20 @@ public abstract class Animal extends AgeableMob { +@@ -234,12 +235,20 @@ public abstract class Animal extends AgeableMob { AgeableMob entityageable = this.getBreedOffspring(world, other); if (entityageable != null) { @@ -6497,7 +6105,7 @@ index 081d1e38b7b1f286e138b0981aaa760e58761215..a64ab2058d4e3439bf6ee418f3192b83 int experience = this.getRandom().nextInt(7) + 1; EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(entityageable, this, other, breeder, this.breedItem, experience); if (entityBreedEvent.isCancelled()) { -@@ -275,8 +284,10 @@ public abstract class Animal extends AgeableMob { +@@ -267,8 +276,10 @@ public abstract class Animal extends AgeableMob { entityplayer.awardStat(Stats.ANIMALS_BRED); CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer, this, entityanimal, entityageable); } // Paper @@ -6511,18 +6119,10 @@ index 081d1e38b7b1f286e138b0981aaa760e58761215..a64ab2058d4e3439bf6ee418f3192b83 entityanimal.resetLove(); worldserver.broadcastEntityEvent(this, (byte) 18); diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd6473ba96 100644 +index 0dfb8109fd8c022b079da00f6a0e3fc85b57bf7a..539170813921de2dfcd7ef84dd7512d73cd27e68 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Bee.java +++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -43,6 +43,7 @@ import net.minecraft.world.entity.EntityType; - import net.minecraft.world.entity.LivingEntity; - import net.minecraft.world.entity.Mob; - import net.minecraft.world.entity.MobType; -+import net.minecraft.world.entity.MoverType; - import net.minecraft.world.entity.NeutralMob; - import net.minecraft.world.entity.PathfinderMob; - import net.minecraft.world.entity.Pose; -@@ -147,6 +148,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -143,6 +143,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { public Bee(EntityType type, Level world) { super(type, world); this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60); @@ -6530,7 +6130,7 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd // Paper start - Fix MC-167279 class BeeFlyingMoveControl extends FlyingMoveControl { public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) { -@@ -155,22 +157,69 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -151,22 +152,69 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @Override public void tick() { @@ -6556,12 +6156,12 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd this.moveControl = new BeeFlyingMoveControl(this, 20, true); // Paper end - Fix MC-167279 this.lookControl = new Bee.BeeLookControl(this); - this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F); -- this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); -+ if (isSensitiveToWater()) this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); // Purpur - this.setPathfindingMalus(BlockPathTypes.WATER_BORDER, 16.0F); - this.setPathfindingMalus(BlockPathTypes.COCOA, -1.0F); - this.setPathfindingMalus(BlockPathTypes.FENCE, -1.0F); + this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F); +- this.setPathfindingMalus(PathType.WATER, -1.0F); ++ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur + this.setPathfindingMalus(PathType.WATER_BORDER, 16.0F); + this.setPathfindingMalus(PathType.COCOA, -1.0F); + this.setPathfindingMalus(PathType.FENCE, -1.0F); } + // Purpur start @@ -6592,16 +6192,16 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; + setSpeed(speed); + Vec3 mot = getDeltaMovement(); -+ move(MoverType.SELF, mot.multiply(speed, speed, speed)); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } + // Purpur end + @Override - protected void defineSynchedData() { - super.defineSynchedData(); -@@ -185,6 +234,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +@@ -181,6 +229,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @Override protected void registerGoals() { @@ -6609,7 +6209,7 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd this.goalSelector.addGoal(0, new Bee.BeeAttackGoal(this, 1.399999976158142D, true)); this.goalSelector.addGoal(1, new Bee.BeeEnterHiveGoal()); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); -@@ -200,6 +250,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -198,6 +247,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)); @@ -6617,7 +6217,7 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd this.targetSelector.addGoal(1, (new Bee.BeeHurtByOtherGoal(this)).setAlertOthers(new Class[0])); this.targetSelector.addGoal(2, new Bee.BeeBecomeAngryTargetGoal(this)); this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true)); -@@ -355,7 +406,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -345,7 +395,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { boolean wantsToEnterHive() { if (this.stayOutOfHiveCountdown <= 0 && !this.beePollinateGoal.isPollinating() && !this.hasStung() && this.getTarget() == null) { @@ -6626,7 +6226,7 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd return flag && !this.isHiveNearFire(); } else { -@@ -395,6 +446,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -385,6 +435,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { this.hurt(this.damageSources().drown(), 1.0F); } @@ -6634,7 +6234,7 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd if (flag) { ++this.timeSinceSting; if (this.timeSinceSting % 5 == 0 && this.random.nextInt(Mth.clamp(1200 - this.timeSinceSting, 1, 1200)) == 0) { -@@ -427,6 +479,26 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -417,6 +468,26 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { } } @@ -6661,7 +6261,7 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd @Override public int getRemainingPersistentAngerTime() { return (Integer) this.entityData.get(Bee.DATA_REMAINING_ANGER_TIME); -@@ -742,6 +814,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -726,6 +797,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { if (optional.isPresent()) { Bee.this.savedFlowerPos = (BlockPos) optional.get(); Bee.this.navigation.moveTo((double) Bee.this.savedFlowerPos.getX() + 0.5D, (double) Bee.this.savedFlowerPos.getY() + 0.5D, (double) Bee.this.savedFlowerPos.getZ() + 0.5D, 1.2000000476837158D); @@ -6669,7 +6269,7 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd return true; } else { Bee.this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(Bee.this.random, 20, 60); -@@ -798,6 +871,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -782,6 +854,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { this.pollinating = false; Bee.this.navigation.stop(); Bee.this.remainingCooldownBeforeLocatingNewFlower = 200; @@ -6677,7 +6277,7 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd } @Override -@@ -844,6 +918,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -828,6 +901,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { this.setWantedPos(); } @@ -6685,14 +6285,14 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd ++this.successfulPollinatingTicks; if (Bee.this.random.nextFloat() < 0.05F && this.successfulPollinatingTicks > this.lastSoundPlayedTick + 60) { this.lastSoundPlayedTick = this.successfulPollinatingTicks; -@@ -888,16 +963,16 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +@@ -872,16 +946,16 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { } } - private class BeeLookControl extends LookControl { + private class BeeLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - BeeLookControl(Mob entity) { + BeeLookControl(final Mob entity) { super(entity); } @@ -6706,11 +6306,11 @@ index f9521a6e115f0c975a7885b024c99eae300b63bf..997ab942be9f742804041b07d607e7dd } diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index f760ce7d9df79ef58f8963de3e901cba3e12fcaa..6af5e1dfcfd739e0bc857f648c189151d5a795c8 100644 +index 07559b9629d4ecb40b511256f400a781e39820e0..3e1345f1c534320e07820d573f5c8dba49746425 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Cat.java +++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -98,6 +98,51 @@ public class Cat extends TamableAnimal implements VariantHolder { - super(type, world); +@@ -104,6 +104,53 @@ public class Cat extends TamableAnimal implements VariantHolder { - protected void registerGoals() { - this.temptGoal = new Cat.CatTemptGoal(this, 0.6D, Cat.TEMPT_INGREDIENT, true); +@@ -114,6 +161,7 @@ public class Cat extends TamableAnimal implements VariantHolder { +@@ -126,6 +174,7 @@ public class Cat extends TamableAnimal implements VariantHolder(this, Rabbit.class, false, (Predicate) null)); this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR)); } -@@ -309,6 +356,14 @@ public class Cat extends TamableAnimal implements VariantHolder { +@@ -318,6 +367,14 @@ public class Cat extends TamableAnimal implements VariantHolder { +@@ -377,6 +434,7 @@ public class Cat extends TamableAnimal implements VariantHolder { - } - } else if (this.isFood(itemstack)) { - this.usePlayerItem(player, hand, itemstack); -- if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit -+ if ((this.level().purpurConfig.alwaysTameInCreative && player.getAbilities().instabuild) || (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled())) { // CraftBukkit // Purpur - this.tame(player); - this.setOrderedToSit(true); - this.level().broadcastEntityEvent(this, (byte) 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 + this.tame(player); + this.setOrderedToSit(true); + this.level().broadcastEntityEvent(this, (byte) 7); diff --git a/src/main/java/net/minecraft/world/entity/animal/Chicken.java b/src/main/java/net/minecraft/world/entity/animal/Chicken.java -index 5e7e6526e2750d508a870dfbdbb46e520d201796..0388ff9ce0ffe1029d977a65a528a0d9f228a3ee 100644 +index 0a4d4cb4ad7cda7c50c46151c03586865d56c797..d8fe8f86ccc9b26b2208b090bb6572b483d14bae 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Chicken.java +++ b/src/main/java/net/minecraft/world/entity/animal/Chicken.java -@@ -55,16 +55,65 @@ public class Chicken extends Animal { - this.setPathfindingMalus(BlockPathTypes.WATER, 0.0F); +@@ -54,10 +54,51 @@ public class Chicken extends Animal { + this.setPathfindingMalus(PathType.WATER, 0.0F); } + // Purpur start @@ -6864,8 +6466,9 @@ index 5e7e6526e2750d508a870dfbdbb46e520d201796..0388ff9ce0ffe1029d977a65a528a0d9 + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur + // this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); // Purpur - moved down this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, Chicken.FOOD_ITEMS, false)); - this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.1D)); + this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, (itemstack) -> { + return itemstack.is(ItemTags.CHICKEN_FOOD); +@@ -66,6 +107,14 @@ public class Chicken extends Animal { this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); @@ -6880,7 +6483,7 @@ index 5e7e6526e2750d508a870dfbdbb46e520d201796..0388ff9ce0ffe1029d977a65a528a0d9 } @Override -@@ -73,7 +122,7 @@ public class Chicken extends Animal { +@@ -74,7 +123,7 @@ public class Chicken extends Animal { } public static AttributeSupplier.Builder createAttributes() { @@ -6928,7 +6531,7 @@ index 824e5e4fe7619ae46061c3c978c9a044db8c84ab..f0b6118a9995bb41836685bbf94d2e7f public ItemStack getBucketItemStack() { return new ItemStack(Items.COD_BUCKET); diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java -index 3cdd9f379c7e2d46ea47c9ef55b121c93ec0bb4a..be4ccc42d6f598cbaaf39aafbd49b594ac7b06fe 100644 +index 5a7b1be351834a6b8889b1380cede1be025cb302..1691a98caabf27ea092a9b422649ac84bc0a7235 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Cow.java +++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java @@ -2,6 +2,7 @@ package net.minecraft.world.entity.animal; @@ -6939,21 +6542,23 @@ index 3cdd9f379c7e2d46ea47c9ef55b121c93ec0bb4a..be4ccc42d6f598cbaaf39aafbd49b594 import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; -@@ -30,6 +31,7 @@ import net.minecraft.world.item.ItemUtils; +@@ -29,6 +30,7 @@ import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.ItemUtils; import net.minecraft.world.item.Items; - import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; - import org.joml.Vector3f; - -@@ -40,25 +42,74 @@ import org.bukkit.event.player.PlayerBucketFillEvent; + // CraftBukkit start + import org.bukkit.craftbukkit.event.CraftEventFactory; +@@ -37,6 +39,7 @@ import org.bukkit.event.player.PlayerBucketFillEvent; // CraftBukkit end public class Cow extends Animal { + private boolean isNaturallyAggressiveToPlayers; // Purpur - public Cow(EntityType type, Level world) { + private static final EntityDimensions BABY_DIMENSIONS = EntityType.COW.getDimensions().scale(0.5F).withEyeHeight(0.665F); + +@@ -44,18 +47,65 @@ public class Cow extends Animal { super(type, world); } @@ -6991,9 +6596,9 @@ index 3cdd9f379c7e2d46ea47c9ef55b121c93ec0bb4a..be4ccc42d6f598cbaaf39aafbd49b594 + } + + @Override -+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData entityData, net.minecraft.nbt.CompoundTag entityNbt) { ++ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData entityData) { + this.isNaturallyAggressiveToPlayers = world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance; -+ return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); ++ return super.finalizeSpawn(world, difficulty, spawnReason, entityData); + } + + @Override @@ -7008,8 +6613,10 @@ index 3cdd9f379c7e2d46ea47c9ef55b121c93ec0bb4a..be4ccc42d6f598cbaaf39aafbd49b594 this.goalSelector.addGoal(1, new PanicGoal(this, 2.0D)); + this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); -+ if (level().purpurConfig.cowFeedMushrooms > 0) this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, Ingredient.of(Items.WHEAT, Blocks.RED_MUSHROOM.asItem(), Blocks.BROWN_MUSHROOM.asItem()), false)); else // Purpur - this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, Ingredient.of(Items.WHEAT), false)); + this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, (itemstack) -> { +- return itemstack.is(ItemTags.COW_FOOD); ++ return level().purpurConfig.cowFeedMushrooms > 0 && (itemstack.is(Blocks.RED_MUSHROOM.asItem()) || itemstack.is(Blocks.BROWN_MUSHROOM.asItem())) || itemstack.is(ItemTags.COW_FOOD); // Purpur + }, false)); this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25D)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); @@ -7017,13 +6624,17 @@ index 3cdd9f379c7e2d46ea47c9ef55b121c93ec0bb4a..be4ccc42d6f598cbaaf39aafbd49b594 + this.targetSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, target -> isNaturallyAggressiveToPlayers)); // Purpur } + @Override +@@ -64,7 +114,7 @@ public class Cow extends Animal { + } + public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.MOVEMENT_SPEED, 0.20000000298023224D); + return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.MOVEMENT_SPEED, 0.20000000298023224D).add(Attributes.ATTACK_DAMAGE, 0.0D); // Purpur } @Override -@@ -88,6 +139,7 @@ public class Cow extends Animal { +@@ -94,6 +144,7 @@ public class Cow extends Animal { @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { @@ -7031,7 +6642,7 @@ index 3cdd9f379c7e2d46ea47c9ef55b121c93ec0bb4a..be4ccc42d6f598cbaaf39aafbd49b594 ItemStack itemstack = player.getItemInHand(hand); if (itemstack.is(Items.BUCKET) && !this.isBaby()) { -@@ -95,7 +147,7 @@ public class Cow extends Animal { +@@ -101,7 +152,7 @@ public class Cow extends Animal { PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, hand); if (event.isCancelled()) { @@ -7040,7 +6651,7 @@ index 3cdd9f379c7e2d46ea47c9ef55b121c93ec0bb4a..be4ccc42d6f598cbaaf39aafbd49b594 } // CraftBukkit end -@@ -104,6 +156,10 @@ public class Cow extends Animal { +@@ -110,6 +161,10 @@ public class Cow extends Animal { player.setItemInHand(hand, itemstack1); return InteractionResult.sidedSuccess(this.level().isClientSide); @@ -7051,9 +6662,9 @@ index 3cdd9f379c7e2d46ea47c9ef55b121c93ec0bb4a..be4ccc42d6f598cbaaf39aafbd49b594 } else { return super.mobInteract(player, hand); } -@@ -124,4 +180,69 @@ public class Cow extends Animal { - protected Vector3f getPassengerAttachmentPoint(Entity passenger, EntityDimensions dimensions, float scaleFactor) { - return new Vector3f(0.0F, dimensions.height - 0.03125F * scaleFactor, 0.0F); +@@ -125,4 +180,69 @@ public class Cow extends Animal { + public EntityDimensions getDefaultDimensions(Pose pose) { + return this.isBaby() ? Cow.BABY_DIMENSIONS : super.getDefaultDimensions(pose); } + + // Purpur start - feed mushroom to change to mooshroom @@ -7122,10 +6733,10 @@ index 3cdd9f379c7e2d46ea47c9ef55b121c93ec0bb4a..be4ccc42d6f598cbaaf39aafbd49b594 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -index 45646c69ea73936a8916756fde37dd3f39db0d04..61bb29de8f1eaa833db95fcc38ab6e18c1a2243c 100644 +index 1b1cb0e4d54e52ebe794199e386c54c5d84b3719..c1a9a87ef0fefc499c0e1edbe1031f47cc432b31 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java +++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -@@ -83,19 +83,104 @@ public class Dolphin extends WaterAnimal { +@@ -81,19 +81,104 @@ public class Dolphin extends WaterAnimal { public static final Predicate ALLOWED_ITEMS = (entityitem) -> { return !entityitem.hasPickUpDelay() && entityitem.isAlive() && entityitem.isInWater(); }; @@ -7224,14 +6835,14 @@ index 45646c69ea73936a8916756fde37dd3f39db0d04..61bb29de8f1eaa833db95fcc38ab6e18 + @Nullable @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { this.setAirSupply(this.getMaxAirSupply()); this.setXRot(0.0F); + this.isNaturallyAggressiveToPlayers = world.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance; // Purpur - return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } -@@ -160,17 +245,21 @@ public class Dolphin extends WaterAnimal { +@@ -158,17 +243,21 @@ public class Dolphin extends WaterAnimal { protected void registerGoals() { this.goalSelector.addGoal(0, new BreathAirGoal(this)); this.goalSelector.addGoal(0, new TryFindWaterGoal(this)); @@ -7254,7 +6865,7 @@ index 45646c69ea73936a8916756fde37dd3f39db0d04..61bb29de8f1eaa833db95fcc38ab6e18 } public static AttributeSupplier.Builder createAttributes() { -@@ -221,7 +310,7 @@ public class Dolphin extends WaterAnimal { +@@ -214,7 +303,7 @@ public class Dolphin extends WaterAnimal { @Override protected boolean canRide(Entity entity) { @@ -7263,7 +6874,7 @@ index 45646c69ea73936a8916756fde37dd3f39db0d04..61bb29de8f1eaa833db95fcc38ab6e18 } @Override -@@ -256,6 +345,11 @@ public class Dolphin extends WaterAnimal { +@@ -249,6 +338,11 @@ public class Dolphin extends WaterAnimal { @Override public void tick() { super.tick(); @@ -7275,7 +6886,7 @@ index 45646c69ea73936a8916756fde37dd3f39db0d04..61bb29de8f1eaa833db95fcc38ab6e18 if (this.isNoAi()) { this.setAirSupply(this.getMaxAirSupply()); } else { -@@ -401,6 +495,7 @@ public class Dolphin extends WaterAnimal { +@@ -391,6 +485,7 @@ public class Dolphin extends WaterAnimal { @Override public boolean canUse() { @@ -7284,10 +6895,10 @@ index 45646c69ea73936a8916756fde37dd3f39db0d04..61bb29de8f1eaa833db95fcc38ab6e18 } diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java -index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71777c7874 100644 +index e705449496b1a06270ecbc13f4dce5357479845b..124839f22ed0499ca395a648e858469d81d31f93 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Fox.java +++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java -@@ -36,6 +36,7 @@ import net.minecraft.util.RandomSource; +@@ -37,6 +37,7 @@ import net.minecraft.util.RandomSource; import net.minecraft.util.StringRepresentable; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.InteractionHand; @@ -7295,7 +6906,7 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.AgeableMob; import net.minecraft.world.entity.Entity; -@@ -148,6 +149,64 @@ public class Fox extends Animal implements VariantHolder { +@@ -145,6 +146,64 @@ public class Fox extends Animal implements VariantHolder { this.setCanPickUpLoot(true); } @@ -7358,9 +6969,9 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 + } + @Override - protected void defineSynchedData() { - super.defineSynchedData(); -@@ -167,6 +226,7 @@ public class Fox extends Animal implements VariantHolder { + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +@@ -164,6 +223,7 @@ public class Fox extends Animal implements VariantHolder { return entityliving instanceof AbstractSchoolingFish; }); this.goalSelector.addGoal(0, new Fox.FoxFloatGoal()); @@ -7368,7 +6979,7 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 this.goalSelector.addGoal(0, new ClimbOnTopOfPowderSnowGoal(this, this.level())); this.goalSelector.addGoal(1, new Fox.FaceplantGoal()); this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2D)); -@@ -193,6 +253,7 @@ public class Fox extends Animal implements VariantHolder { +@@ -190,6 +250,7 @@ public class Fox extends Animal implements VariantHolder { 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()); @@ -7376,7 +6987,7 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 this.targetSelector.addGoal(3, new Fox.DefendTrustedTargetGoal(LivingEntity.class, false, false, (entityliving) -> { return Fox.TRUSTED_TARGET_SELECTOR.test(entityliving) && !this.trusts(entityliving.getUUID()); })); -@@ -349,6 +410,11 @@ public class Fox extends Animal implements VariantHolder { +@@ -344,6 +405,11 @@ public class Fox extends Animal implements VariantHolder { } private void setTargetGoals() { @@ -7388,7 +6999,7 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 if (this.getVariant() == Fox.Type.RED) { this.targetSelector.addGoal(4, this.landTargetGoal); this.targetSelector.addGoal(4, this.turtleEggTargetGoal); -@@ -382,6 +448,7 @@ public class Fox extends Animal implements VariantHolder { +@@ -377,6 +443,7 @@ public class Fox extends Animal implements VariantHolder { public void setVariant(Fox.Type variant) { this.entityData.set(Fox.DATA_TYPE_ID, variant.getId()); @@ -7396,7 +7007,7 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 } List getTrustedUUIDs() { -@@ -728,6 +795,29 @@ public class Fox extends Animal implements VariantHolder { +@@ -717,6 +784,29 @@ public class Fox extends Animal implements VariantHolder { } // Paper end @@ -7426,7 +7037,7 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 @Override // Paper start - Cancellable death event protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(DamageSource source) { -@@ -785,16 +875,16 @@ public class Fox extends Animal implements VariantHolder { +@@ -769,16 +859,16 @@ public class Fox extends Animal implements VariantHolder { return new Vec3(0.0D, (double) (0.55F * this.getEyeHeight()), (double) (this.getBbWidth() * 0.4F)); } @@ -7446,7 +7057,7 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 } } -@@ -805,16 +895,16 @@ public class Fox extends Animal implements VariantHolder { +@@ -789,16 +879,16 @@ public class Fox extends Animal implements VariantHolder { } } @@ -7466,7 +7077,7 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 } } -@@ -932,8 +1022,10 @@ public class Fox extends Animal implements VariantHolder { +@@ -916,8 +1006,10 @@ public class Fox extends Animal implements VariantHolder { CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer2, this.animal, this.partner, entityfox); } @@ -7479,7 +7090,7 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 this.animal.resetLove(); this.partner.resetLove(); worldserver.addFreshEntityWithPassengers(entityfox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason -@@ -1319,7 +1411,7 @@ public class Fox extends Animal implements VariantHolder { +@@ -1303,7 +1395,7 @@ public class Fox extends Animal implements VariantHolder { } protected void onReachedTarget() { @@ -7489,10 +7100,10 @@ index f7a7810fdc2f74b79fa14470493485e4b74539ab..445c1993a18da93e89792b7953e5eb71 if (iblockdata.is(Blocks.SWEET_BERRY_BUSH)) { diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -index 6cfe0d6c46caa122db107c607d27a2bdcd82f7a8..442eb602f5c82550a87e218e2013171b718abd62 100644 +index 932fae98c551052cadba4c6fc6e575fc30a25d58..12bc57d36d76f49596df0004fda31a6a678be60c 100644 --- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java +++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -@@ -60,14 +60,59 @@ public class IronGolem extends AbstractGolem implements NeutralMob { +@@ -56,13 +56,58 @@ public class IronGolem extends AbstractGolem implements NeutralMob { private int remainingPersistentAngerTime; @Nullable private UUID persistentAngerTarget; @@ -7500,7 +7111,6 @@ index 6cfe0d6c46caa122db107c607d27a2bdcd82f7a8..442eb602f5c82550a87e218e2013171b public IronGolem(EntityType type, Level world) { super(type, world); - this.setMaxUpStep(1.0F); } + // Purpur start @@ -7552,7 +7162,7 @@ index 6cfe0d6c46caa122db107c607d27a2bdcd82f7a8..442eb602f5c82550a87e218e2013171b this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0D, true)); this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9D, 32.0F)); this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6D, false)); -@@ -75,6 +120,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { +@@ -70,6 +115,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)); @@ -7560,7 +7170,7 @@ index 6cfe0d6c46caa122db107c607d27a2bdcd82f7a8..442eb602f5c82550a87e218e2013171b this.targetSelector.addGoal(1, new DefendVillageTargetGoal(this)); this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); -@@ -139,6 +185,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { +@@ -134,6 +180,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); nbt.putBoolean("PlayerCreated", this.isPlayerCreated()); @@ -7568,7 +7178,7 @@ index 6cfe0d6c46caa122db107c607d27a2bdcd82f7a8..442eb602f5c82550a87e218e2013171b this.addPersistentAngerSaveData(nbt); } -@@ -146,6 +193,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { +@@ -141,6 +188,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { public void readAdditionalSaveData(CompoundTag nbt) { super.readAdditionalSaveData(nbt); this.setPlayerCreated(nbt.getBoolean("PlayerCreated")); @@ -7576,7 +7186,7 @@ index 6cfe0d6c46caa122db107c607d27a2bdcd82f7a8..442eb602f5c82550a87e218e2013171b this.readPersistentAngerSaveData(this.level(), nbt); } -@@ -270,13 +318,13 @@ public class IronGolem extends AbstractGolem implements NeutralMob { +@@ -265,18 +313,19 @@ public class IronGolem extends AbstractGolem implements NeutralMob { ItemStack itemstack = player.getItemInHand(hand); if (!itemstack.is(Items.IRON_INGOT)) { @@ -7592,16 +7202,14 @@ index 6cfe0d6c46caa122db107c607d27a2bdcd82f7a8..442eb602f5c82550a87e218e2013171b } else { float f1 = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F; -@@ -285,6 +333,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - itemstack.shrink(1); - } - + this.playSound(SoundEvents.IRON_GOLEM_REPAIR, 1.0F, f1); + itemstack.consume(1, player); + if (this.level().purpurConfig.ironGolemHealCalm && isAngry() && getHealth() == getMaxHealth()) stopBeingAngry(); // Purpur return InteractionResult.sidedSuccess(this.level().isClientSide); } } diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index 161c128d27f50f145f88142191f1a5c93649ea65..21632120b52e4d594153ebe057a14afa74c3f4eb 100644 +index 0c21959f57ae88fcd0a4d6dc911c1ce347c96528..a7c95199234231db14faa4a07953bcde57d9861d 100644 --- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java +++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java @@ -64,6 +64,43 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder drops = this.generateDefaultDrops(); -+ List drops = this.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getMobLooting(player)); // Purpur +- java.util.List drops = this.generateDefaultDrops(); ++ java.util.List drops = this.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getMobLooting(player)); // Purpur org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); if (event != null) { if (event.isCancelled()) { @@ -7662,16 +7270,16 @@ index 161c128d27f50f145f88142191f1a5c93649ea65..21632120b52e4d594153ebe057a14afa } drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); } -@@ -152,7 +189,7 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder> optional = this.getEffectsFromItemStack(itemstack); +@@ -150,7 +187,7 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder optional = this.getEffectsFromItemStack(itemstack); if (optional.isEmpty()) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } - if (!player.getAbilities().instabuild) { -@@ -176,13 +213,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder generateDefaultDrops() { -+ public List generateDefaultDrops(int looting) { // Purpur - List dropEntities = new java.util.ArrayList<>(5); +- public java.util.List generateDefaultDrops() { ++ public java.util.List generateDefaultDrops(int looting) { // Purpur + java.util.List dropEntities = new java.util.ArrayList<>(5); - for (int i = 0; i < 5; ++i) { + for (int i = 0; i < 5 + (org.purpurmc.purpur.PurpurConfig.allowShearsLooting ? looting : 0); ++i) { // Purpur dropEntities.add(new ItemStack(this.getVariant().getBlockState().getBlock())); } return dropEntities; -@@ -200,7 +237,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder(this, Chicken.class, false)); this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR)); } -@@ -256,7 +295,7 @@ public class Ocelot extends Animal { +@@ -254,7 +293,7 @@ public class Ocelot extends Animal { if (world.isUnobstructed(this) && !world.containsAnyLiquid(this.getBoundingBox())) { BlockPos blockposition = this.blockPosition(); @@ -7775,10 +7383,10 @@ index 4300fab61765dd224fab084d118aae7294fc9de6..3c5f25300d1c7800144a459cc8bf5983 } diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java -index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993ca49a01d 100644 +index db60b91c2b26ca8cdb66e05deab7742ffe212767..7bd81d073ce4a8d5981f256415d3e99e13da79ba 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Panda.java +++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java -@@ -115,6 +115,53 @@ public class Panda extends Animal { +@@ -120,6 +120,53 @@ public class Panda extends Animal { } @@ -7832,7 +7440,7 @@ index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993 @Override public boolean canTakeItem(ItemStack stack) { EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(stack); -@@ -276,6 +323,7 @@ public class Panda extends Animal { +@@ -281,6 +328,7 @@ public class Panda extends Animal { @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); @@ -7840,7 +7448,7 @@ index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993 this.goalSelector.addGoal(2, new Panda.PandaPanicGoal(this, 2.0D)); this.goalSelector.addGoal(2, new Panda.PandaBreedGoal(this, 1.0D)); this.goalSelector.addGoal(3, new Panda.PandaAttackGoal(this, 1.2000000476837158D, true)); -@@ -291,6 +339,7 @@ public class Panda extends Animal { +@@ -298,6 +346,7 @@ public class Panda extends Animal { this.goalSelector.addGoal(12, new Panda.PandaRollGoal(this)); this.goalSelector.addGoal(13, new FollowParentGoal(this, 1.25D)); this.goalSelector.addGoal(14, new WaterAvoidingRandomStrollGoal(this, 1.0D)); @@ -7848,7 +7456,7 @@ index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993 this.targetSelector.addGoal(1, (new Panda.PandaHurtByTargetGoal(this, new Class[0])).setAlertOthers(new Class[0])); } -@@ -614,7 +663,10 @@ public class Panda extends Animal { +@@ -632,7 +681,10 @@ public class Panda extends Animal { public void setAttributes() { if (this.isWeak()) { @@ -7860,7 +7468,7 @@ index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993 } if (this.isLazy()) { -@@ -637,7 +689,7 @@ public class Panda extends Animal { +@@ -655,7 +707,7 @@ public class Panda extends Animal { ItemStack itemstack = player.getItemInHand(hand); if (this.isScared()) { @@ -7869,7 +7477,7 @@ index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993 } else if (this.isOnBack()) { this.setOnBack(false); return InteractionResult.sidedSuccess(this.level().isClientSide); -@@ -655,7 +707,7 @@ public class Panda extends Animal { +@@ -673,7 +725,7 @@ public class Panda extends Animal { this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying } else { if (this.level().isClientSide || this.isSitting() || this.isInWater()) { @@ -7878,7 +7486,7 @@ index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993 } this.tryToSit(); -@@ -674,7 +726,7 @@ public class Panda extends Animal { +@@ -692,7 +744,7 @@ public class Panda extends Animal { return InteractionResult.SUCCESS; } else { @@ -7887,8 +7495,8 @@ index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993 } } -@@ -719,7 +771,7 @@ public class Panda extends Animal { - return new Vector3f(0.0F, dimensions.height - (this.isBaby() ? 0.4375F : 0.0F) * scaleFactor, 0.0F); +@@ -737,7 +789,7 @@ public class Panda extends Animal { + return this.isBaby() ? Panda.BABY_DIMENSIONS : super.getDefaultDimensions(pose); } - private static class PandaMoveControl extends MoveControl { @@ -7896,7 +7504,7 @@ index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993 private final Panda panda; -@@ -729,9 +781,9 @@ public class Panda extends Animal { +@@ -747,9 +799,9 @@ public class Panda extends Animal { } @Override @@ -7909,10 +7517,10 @@ index d683c49fdf2d1e5b0f2620641f9c241e82f96825..adfa18c941b5070692ed855d1d609993 } } diff --git a/src/main/java/net/minecraft/world/entity/animal/Parrot.java b/src/main/java/net/minecraft/world/entity/animal/Parrot.java -index f3f48225c2a1e4bd3d0091d1b4b7e4e150850ed2..670cf5a74554b0b420706db2fbce3a8e5dca147b 100644 +index 5ca96541abbb754f4d9fbe01f37ebaf19c532bbb..b8c69414b734eecb7412fab8ae6996712307da70 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Parrot.java +++ b/src/main/java/net/minecraft/world/entity/animal/Parrot.java -@@ -131,12 +131,88 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder type, Level world) { super(type, world); @@ -7940,9 +7548,9 @@ index f3f48225c2a1e4bd3d0091d1b4b7e4e150850ed2..670cf5a74554b0b420706db2fbce3a8e + } + this.moveControl = new ParrotMoveControl(this, 10, false); + // Purpur end - this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F); - this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, -1.0F); - this.setPathfindingMalus(BlockPathTypes.COCOA, -1.0F); + this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F); + this.setPathfindingMalus(PathType.DAMAGE_FIRE, -1.0F); + this.setPathfindingMalus(PathType.COCOA, -1.0F); } + // Purpur start @@ -8001,8 +7609,8 @@ index f3f48225c2a1e4bd3d0091d1b4b7e4e150850ed2..670cf5a74554b0b420706db2fbce3a8e + @Nullable @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { -@@ -155,8 +231,11 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { -@@ -308,13 +388,13 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder { @@ -155,6 +193,17 @@ public class Pig extends Animal implements ItemSteerable, Saddleable { public InteractionResult mobInteract(Player player, InteractionHand hand) { boolean flag = this.isFood(player.getItemInHand(hand)); @@ -8128,7 +7736,7 @@ index 24770540c51fe4831040d6b46b27636d25ebac40..10d6361077a74c5685eca72d12f99e33 if (!this.level().isClientSide) { player.startRiding(this); diff --git a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java -index c9e10d4ce00b711b30de5d346a5ac26e7b441390..2fecdd574b407eeb1d0cd4f1b34ff7931e620540 100644 +index c87a57e8ceac32a6c8a603aa24f8cb053610e47c..9b6e07b0de7328b18c5e526b89cfd48fdbc79753 100644 --- a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java +++ b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java @@ -59,11 +59,81 @@ public class PolarBear extends Animal implements NeutralMob { @@ -8264,10 +7872,10 @@ index c9e10d4ce00b711b30de5d346a5ac26e7b441390..2fecdd574b407eeb1d0cd4f1b34ff793 public float getStandingAnimationScale(float tickDelta) { diff --git a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java -index a197337f2e09f53cf382022569c8836745d78769..54f5206b686c3cf4d2e5b470c07047a518f5dd00 100644 +index 3f0fad476fe573c3ba946a9436d1b3f7c5260ee2..c758f759ccae81b7651bfcba254f54335f2c7cc8 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java +++ b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java -@@ -45,6 +45,33 @@ public class Pufferfish extends AbstractFish { +@@ -51,6 +51,33 @@ public class Pufferfish extends AbstractFish { this.refreshDimensions(); } @@ -8299,13 +7907,13 @@ index a197337f2e09f53cf382022569c8836745d78769..54f5206b686c3cf4d2e5b470c07047a5 + } + @Override - protected void defineSynchedData() { - super.defineSynchedData(); + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb55dcb825 100644 +index b58300e114e2e27ac68d7a9489bc52b127c9bc17..02702390c0b336762ce8c0d38d804e6f24ebbfd4 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java +++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -@@ -87,6 +87,7 @@ public class Rabbit extends Animal implements VariantHolder { +@@ -86,6 +86,7 @@ public class Rabbit extends Animal implements VariantHolder { private boolean wasOnGround; private int jumpDelayTicks; public int moreCarrotTicks; @@ -8313,7 +7921,7 @@ index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb public Rabbit(EntityType type, Level world) { super(type, world); -@@ -94,9 +95,75 @@ public class Rabbit extends Animal implements VariantHolder { +@@ -93,9 +94,75 @@ public class Rabbit extends Animal implements VariantHolder { this.moveControl = new Rabbit.RabbitMoveControl(this); } @@ -8389,7 +7997,7 @@ index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level())); this.goalSelector.addGoal(1, new Rabbit.RabbitPanicGoal(this, 2.2D)); this.goalSelector.addGoal(2, new BreedGoal(this, 0.8D)); -@@ -111,6 +178,14 @@ public class Rabbit extends Animal implements VariantHolder { +@@ -112,6 +179,14 @@ public class Rabbit extends Animal implements VariantHolder { @Override protected float getJumpPower() { @@ -8404,7 +8012,7 @@ index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb float f = 0.3F; if (this.horizontalCollision || this.moveControl.hasWanted() && this.moveControl.getWantedY() > this.getY() + 0.5D) { -@@ -135,7 +210,7 @@ public class Rabbit extends Animal implements VariantHolder { +@@ -136,7 +211,7 @@ public class Rabbit extends Animal implements VariantHolder { } @Override @@ -8413,7 +8021,7 @@ index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb super.jumpFromGround(); double d0 = this.moveControl.getSpeedModifier(); -@@ -185,6 +260,13 @@ public class Rabbit extends Animal implements VariantHolder { +@@ -186,6 +261,13 @@ public class Rabbit extends Animal implements VariantHolder { @Override public void customServerAiStep() { @@ -8427,7 +8035,7 @@ index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb if (this.jumpDelayTicks > 0) { --this.jumpDelayTicks; } -@@ -402,10 +484,23 @@ public class Rabbit extends Animal implements VariantHolder { +@@ -399,10 +481,23 @@ public class Rabbit extends Animal implements VariantHolder { } this.setVariant(entityrabbit_variant); @@ -8438,7 +8046,7 @@ index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb + } + // Purpur end + - return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData, entityNbt); + return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData); } private static Rabbit.Variant getRandomRabbitVariant(LevelAccessor world, BlockPos pos) { @@ -8451,7 +8059,7 @@ index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb Holder holder = world.getBiome(pos); int i = world.getRandom().nextInt(100); -@@ -469,7 +564,7 @@ public class Rabbit extends Animal implements VariantHolder { +@@ -466,7 +561,7 @@ public class Rabbit extends Animal implements VariantHolder { } } @@ -8460,7 +8068,7 @@ index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb private final Rabbit rabbit; private double nextJumpSpeed; -@@ -480,14 +575,14 @@ public class Rabbit extends Animal implements VariantHolder { +@@ -477,14 +572,14 @@ public class Rabbit extends Animal implements VariantHolder { } @Override @@ -8477,7 +8085,7 @@ index cf4859814a60468f683e3afe285b4934d35e9704..eae2488f2a46e543b496b7a2919aabbb } @Override -@@ -549,7 +644,7 @@ public class Rabbit extends Animal implements VariantHolder { +@@ -546,7 +641,7 @@ public class Rabbit extends Animal implements VariantHolder { @Override public boolean canUse() { if (this.nextStartTick <= 0) { @@ -8525,10 +8133,10 @@ index 0af79daa357f53a8871e293b57e16c099e5d3f64..382e47f26ee94506cb76463a677351b9 public int getMaxSchoolSize() { return 5; diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -index 1d80678f7e8f658e43616f0baf723f096a99122a..658f7943d275267d3fc556572831cc095259d12e 100644 +index 3ce86f952a18cae7fda1903916903b31a63a40b4..6b1244d3957e7f62c96ffd34692b8916337839fd 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java +++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -@@ -119,10 +119,48 @@ public class Sheep extends Animal implements Shearable { +@@ -117,10 +117,48 @@ public class Sheep extends Animal implements Shearable { super(type, world); } @@ -8576,8 +8184,8 @@ index 1d80678f7e8f658e43616f0baf723f096a99122a..658f7943d275267d3fc556572831cc09 + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D)); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new TemptGoal(this, 1.1D, Ingredient.of(Items.WHEAT), false)); -@@ -254,7 +292,7 @@ public class Sheep extends Animal implements Shearable { + this.goalSelector.addGoal(3, new TemptGoal(this, 1.1D, (itemstack) -> { +@@ -259,7 +297,7 @@ public class Sheep extends Animal implements Shearable { if (!this.level().isClientSide && this.readyForShearing()) { // CraftBukkit start // Paper start - custom shear drops @@ -8586,7 +8194,7 @@ index 1d80678f7e8f658e43616f0baf723f096a99122a..658f7943d275267d3fc556572831cc09 org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); if (event != null) { if (event.isCancelled()) { -@@ -281,12 +319,13 @@ public class Sheep extends Animal implements Shearable { +@@ -284,12 +322,13 @@ public class Sheep extends Animal implements Shearable { @Override public void shear(SoundSource shearedSoundCategory) { // Paper start - custom shear drops @@ -8603,13 +8211,13 @@ index 1d80678f7e8f658e43616f0baf723f096a99122a..658f7943d275267d3fc556572831cc09 for (int j = 0; j < count; ++j) { dropEntities.add(new ItemStack(Sheep.ITEM_BY_DYE.get(this.getColor()))); diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index 9eab1170cb123d3b60a02314702516704f959ab7..b75d07f3af4addbb306ecb6baacf1607ef65fc25 100644 +index 5c2ed3c39c8eb850f3be1e2ea5b5a7ea266e16d1..3b74931ae4e3a869d8db38c119e57b44af887859 100644 --- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java +++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -49,17 +49,56 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -47,17 +47,56 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + private static final EntityDataAccessor DATA_PUMPKIN_ID = SynchedEntityData.defineId(SnowGolem.class, EntityDataSerializers.BYTE); private static final byte PUMPKIN_FLAG = 16; - private static final float EYE_HEIGHT = 1.7F; + @Nullable private java.util.UUID summoner; // Purpur public SnowGolem(EntityType type, Level world) { @@ -8664,7 +8272,7 @@ index 9eab1170cb123d3b60a02314702516704f959ab7..b75d07f3af4addbb306ecb6baacf1607 this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entityliving) -> { return entityliving instanceof Enemy; })); -@@ -79,6 +118,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -77,6 +116,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); nbt.putBoolean("Pumpkin", this.hasPumpkin()); @@ -8672,7 +8280,7 @@ index 9eab1170cb123d3b60a02314702516704f959ab7..b75d07f3af4addbb306ecb6baacf1607 } @Override -@@ -87,12 +127,13 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -85,12 +125,13 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM if (nbt.contains("Pumpkin")) { this.setPumpkin(nbt.getBoolean("Pumpkin")); } @@ -8687,7 +8295,7 @@ index 9eab1170cb123d3b60a02314702516704f959ab7..b75d07f3af4addbb306ecb6baacf1607 } @Override -@@ -103,10 +144,11 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -101,10 +142,11 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM this.hurt(this.damageSources().melting(), 1.0F); // CraftBukkit - DamageSources.ON_FIRE -> CraftEventFactory.MELTING } @@ -8700,7 +8308,7 @@ index 9eab1170cb123d3b60a02314702516704f959ab7..b75d07f3af4addbb306ecb6baacf1607 BlockState iblockdata = Blocks.SNOW.defaultBlockState(); for (int i = 0; i < 4; ++i) { -@@ -154,11 +196,11 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -147,11 +189,11 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM if (itemstack.is(Items.SHEARS) && this.readyForShearing()) { // CraftBukkit start // Paper start - custom shear drops @@ -8714,7 +8322,7 @@ index 9eab1170cb123d3b60a02314702516704f959ab7..b75d07f3af4addbb306ecb6baacf1607 } drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); } -@@ -173,19 +215,36 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -164,19 +206,36 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM } return InteractionResult.sidedSuccess(this.level().isClientSide); @@ -8755,10 +8363,10 @@ index 9eab1170cb123d3b60a02314702516704f959ab7..b75d07f3af4addbb306ecb6baacf1607 } diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java -index 36506dc4b99f9de19a23a99c1bccdcb4e7102e72..38d1eb5680281b2812f2396677ffb959a6e089ce 100644 +index 43b4ea96c5c4a6234e5b83d41db9b85c1fe27b8f..cb950ba3ee3bdfe0ff7acdb94c7ee233d73ab22e 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Squid.java +++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java -@@ -44,13 +44,66 @@ public class Squid extends WaterAnimal { +@@ -42,13 +42,66 @@ public class Squid extends WaterAnimal { public Squid(EntityType type, Level world) { super(type, world); @@ -8826,7 +8434,7 @@ index 36506dc4b99f9de19a23a99c1bccdcb4e7102e72..38d1eb5680281b2812f2396677ffb959 this.goalSelector.addGoal(1, new Squid.SquidFleeGoal()); } -@@ -119,6 +172,7 @@ public class Squid extends WaterAnimal { +@@ -117,6 +170,7 @@ public class Squid extends WaterAnimal { } if (this.isInWaterOrBubble()) { @@ -8834,7 +8442,7 @@ index 36506dc4b99f9de19a23a99c1bccdcb4e7102e72..38d1eb5680281b2812f2396677ffb959 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; -@@ -292,10 +346,41 @@ public class Squid extends WaterAnimal { +@@ -290,10 +344,41 @@ public class Squid extends WaterAnimal { @Override public void tick() { @@ -8878,10 +8486,10 @@ index 36506dc4b99f9de19a23a99c1bccdcb4e7102e72..38d1eb5680281b2812f2396677ffb959 float g = Mth.cos(f) * 0.2F; float h = -0.1F + this.squid.getRandom().nextFloat() * 0.2F; diff --git a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -index 6e9e86b6d547d7437c990b65718b95ad0d60f020..98205d89aa0cca82863257abfad46ab834385a20 100644 +index 3d03ffe2e12eca82dfa2f414471d12bb362d4552..2d04addd17d2c358fff598012b323cd7d8bf007e 100644 --- a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java +++ b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -@@ -65,6 +65,33 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder +@@ -67,6 +67,33 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder super(type, world); } @@ -8916,11 +8524,11 @@ index 6e9e86b6d547d7437c990b65718b95ad0d60f020..98205d89aa0cca82863257abfad46ab8 return "entity.minecraft.tropical_fish.predefined." + variant; } diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index 2eb099957a3d0bae3339ff4edbab103fb348abed..2153dac7c7c83ef3192d2b8370b8924ee67383a8 100644 +index 30b87b5cb18c25cdd04eab64cfbe5acd6c1b6d84..01dc59695f295657b1cd7bb015558bfc2ce73b47 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java +++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -86,6 +86,43 @@ public class Turtle extends Animal { - this.setMaxUpStep(1.0F); +@@ -87,6 +87,43 @@ public class Turtle extends Animal { + this.moveControl = new Turtle.TurtleMoveControl(this); } + // Purpur start @@ -8963,7 +8571,7 @@ index 2eb099957a3d0bae3339ff4edbab103fb348abed..2153dac7c7c83ef3192d2b8370b8924e public void setHomePos(BlockPos pos) { this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos... } -@@ -188,6 +225,7 @@ public class Turtle extends Animal { +@@ -189,6 +226,7 @@ public class Turtle extends Animal { @Override protected void registerGoals() { @@ -8971,8 +8579,8 @@ index 2eb099957a3d0bae3339ff4edbab103fb348abed..2153dac7c7c83ef3192d2b8370b8924e this.goalSelector.addGoal(0, new Turtle.TurtlePanicGoal(this, 1.2D)); this.goalSelector.addGoal(1, new Turtle.TurtleBreedGoal(this, 1.0D)); this.goalSelector.addGoal(1, new Turtle.TurtleLayEggGoal(this, 1.0D)); -@@ -344,13 +382,15 @@ public class Turtle extends Animal { - return new Vector3f(0.0F, dimensions.height + (this.isBaby() ? 0.0F : 0.15625F) * scaleFactor, -0.25F * scaleFactor); +@@ -342,13 +380,15 @@ public class Turtle extends Animal { + return this.isBaby() ? Turtle.BABY_DIMENSIONS : super.getDefaultDimensions(pose); } - private static class TurtleMoveControl extends MoveControl { @@ -8988,7 +8596,7 @@ index 2eb099957a3d0bae3339ff4edbab103fb348abed..2153dac7c7c83ef3192d2b8370b8924e } private void updateSpeed() { -@@ -370,7 +410,7 @@ public class Turtle extends Animal { +@@ -368,7 +408,7 @@ public class Turtle extends Animal { } @Override @@ -8997,7 +8605,7 @@ index 2eb099957a3d0bae3339ff4edbab103fb348abed..2153dac7c7c83ef3192d2b8370b8924e this.updateSpeed(); if (this.operation == MoveControl.Operation.MOVE_TO && !this.turtle.getNavigation().isDone()) { double d0 = this.wantedX - this.turtle.getX(); -@@ -386,7 +426,7 @@ public class Turtle extends Animal { +@@ -384,7 +424,7 @@ public class Turtle extends Animal { this.turtle.setYRot(this.rotlerp(this.turtle.getYRot(), f, 90.0F)); this.turtle.yBodyRot = this.turtle.getYRot(); @@ -9007,10 +8615,10 @@ index 2eb099957a3d0bae3339ff4edbab103fb348abed..2153dac7c7c83ef3192d2b8370b8924e this.turtle.setSpeed(Mth.lerp(0.125F, this.turtle.getSpeed(), f1)); this.turtle.setDeltaMovement(this.turtle.getDeltaMovement().add(0.0D, (double) this.turtle.getSpeed() * d1 * 0.1D, 0.0D)); diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java -index 75884a9e69a28404752c1a2cf854335bb78cac01..1fd69e6ab765236b1a09e2791188d1eb7f12ecbb 100644 +index 6f22705072fecbe91196e4966fca2eeec060f120..ed2ae44f7cef5aed17d10cc8a7df0a2276f9f16b 100644 --- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java +++ b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java -@@ -78,6 +78,6 @@ public abstract class WaterAnimal extends PathfinderMob { +@@ -72,6 +72,6 @@ public abstract class WaterAnimal extends PathfinderMob { i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i); j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j); // Paper end - Make water animal spawn height configurable @@ -9019,63 +8627,27 @@ index 75884a9e69a28404752c1a2cf854335bb78cac01..1fd69e6ab765236b1a09e2791188d1eb } } diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -index 2d20b2c1f58beb1ad8c9012d8124e476899e6be6..a90055fe8819a32180754b6060a0f88e81d1a3b6 100644 +index b5ee82e5abfecc59e2362628f288b76881855f36..b12544d1280f39b6c365317a0f4965c8d65b6497 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java +++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -@@ -10,6 +10,7 @@ import net.minecraft.network.syncher.EntityDataAccessor; - import net.minecraft.network.syncher.EntityDataSerializers; - import net.minecraft.network.syncher.SynchedEntityData; - import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; - import net.minecraft.sounds.SoundEvent; - import net.minecraft.sounds.SoundEvents; - import net.minecraft.tags.BlockTags; -@@ -17,9 +18,12 @@ import net.minecraft.util.Mth; - import net.minecraft.util.RandomSource; - import net.minecraft.util.TimeUtil; - import net.minecraft.util.valueproviders.UniformInt; -+import net.minecraft.world.DifficultyInstance; +@@ -30,6 +30,8 @@ import net.minecraft.world.DifficultyInstance; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.AgeableMob; + import net.minecraft.world.entity.Crackiness; import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntityDimensions; -@@ -29,6 +33,7 @@ import net.minecraft.world.entity.Mob; - import net.minecraft.world.entity.MobSpawnType; - import net.minecraft.world.entity.NeutralMob; - import net.minecraft.world.entity.Pose; -+import net.minecraft.world.entity.SpawnGroupData; - import net.minecraft.world.entity.TamableAnimal; - import net.minecraft.world.entity.ai.attributes.AttributeSupplier; - import net.minecraft.world.entity.ai.attributes.Attributes; -@@ -37,6 +42,7 @@ import net.minecraft.world.entity.ai.goal.BegGoal; - import net.minecraft.world.entity.ai.goal.BreedGoal; - import net.minecraft.world.entity.ai.goal.FloatGoal; - import net.minecraft.world.entity.ai.goal.FollowOwnerGoal; -+import net.minecraft.world.entity.ai.goal.Goal; - import net.minecraft.world.entity.ai.goal.LeapAtTargetGoal; - import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; - import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; -@@ -64,6 +70,7 @@ import net.minecraft.world.item.ItemStack; - import net.minecraft.world.item.Items; - import net.minecraft.world.level.Level; - import net.minecraft.world.level.LevelAccessor; -+import net.minecraft.world.level.ServerLevelAccessor; - import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.level.gameevent.GameEvent; - import net.minecraft.world.level.pathfinder.BlockPathTypes; -@@ -86,6 +93,37 @@ public class Wolf extends TamableAnimal implements NeutralMob { +@@ -104,6 +106,37 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder RABID_PREDICATE = entity -> entity instanceof ServerPlayer || entity instanceof Mob; -+ private final Goal PATHFINDER_VANILLA = new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR); -+ private final Goal PATHFINDER_RABID = new NonTameRandomTargetGoal<>(this, LivingEntity.class, false, RABID_PREDICATE); ++ private static final Predicate RABID_PREDICATE = entity -> entity instanceof net.minecraft.server.level.ServerPlayer || entity instanceof Mob; ++ private final net.minecraft.world.entity.ai.goal.Goal PATHFINDER_VANILLA = new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR); ++ private final net.minecraft.world.entity.ai.goal.Goal PATHFINDER_RABID = new NonTameRandomTargetGoal<>(this, LivingEntity.class, false, RABID_PREDICATE); + private static final class AvoidRabidWolfGoal extends AvoidEntityGoal { + private final Wolf wolf; + @@ -9103,10 +8675,10 @@ index 2d20b2c1f58beb1ad8c9012d8124e476899e6be6..a90055fe8819a32180754b6060a0f88e + } + // Purpur end private static final float START_HEALTH = 8.0F; - private static final float TAME_HEALTH = 20.0F; - private float interestedAngle; -@@ -105,12 +143,93 @@ public class Wolf extends TamableAnimal implements NeutralMob { - this.setPathfindingMalus(BlockPathTypes.DANGER_POWDER_SNOW, -1.0F); + private static final float TAME_HEALTH = 40.0F; + private static final float ARMOR_REPAIR_UNIT = 0.125F; +@@ -124,12 +157,86 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.wolfNaturalRabid; -+ this.updatePathfinders(false); -+ return super.finalizeSpawn(world, difficulty, type, data, nbt); -+ } -+ -+ @Override + public void tame(Player player) { + setCollarColor(level().purpurConfig.wolfDefaultCollarColor); + super.tame(player); @@ -9192,14 +8757,14 @@ index 2d20b2c1f58beb1ad8c9012d8124e476899e6be6..a90055fe8819a32180754b6060a0f88e protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new Wolf.WolfPanicGoal(1.5D)); + this.goalSelector.addGoal(1, new Wolf.WolfPanicGoal(this, 1.5D)); this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); this.goalSelector.addGoal(3, new Wolf.WolfAvoidEntityGoal<>(this, Llama.class, 24.0F, 1.5D, 1.5D)); + this.goalSelector.addGoal(3, new AvoidRabidWolfGoal(this, 24.0F, 1.5D, 1.5D)); // Purpur this.goalSelector.addGoal(4, new LeapAtTargetGoal(this, 0.4F)); this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0D, true)); this.goalSelector.addGoal(6, new FollowOwnerGoal(this, 1.0D, 10.0F, 2.0F, false)); -@@ -119,11 +238,12 @@ public class Wolf extends TamableAnimal implements NeutralMob { +@@ -138,11 +245,12 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder(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)); -@@ -150,6 +270,7 @@ public class Wolf extends TamableAnimal implements NeutralMob { +@@ -185,6 +293,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.wolfNaturalRabid; ++ this.updatePathfinders(false); ++ // Purpur end ++ + return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData); + } + +@@ -261,6 +380,11 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder brainProvider() { return Brain.provider(Allay.MEMORY_TYPES, Allay.SENSOR_TYPES); -@@ -224,13 +259,13 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS - private int behaviorTick = 0; // Pufferfish +@@ -217,12 +252,13 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS + @Override protected void customServerAiStep() { - this.level().getProfiler().push("allayBrain"); -- if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish + //this.level().getProfiler().push("allayBrain"); // Purpur -+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("allayActivityUpdate"); @@ -9350,47 +8927,45 @@ index d241ca4d0295f9fce39c11197bd435cfac7f6e54..c783ce59ea766e6c46a3313628b961f2 super.customServerAiStep(); } -@@ -371,9 +406,31 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS +diff --git a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java +index b38281f963377cc82b360e8457da7cad033b8c36..f8790ab5b7c1279719271ee57c00f4f2d6ce9714 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java ++++ b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java +@@ -130,12 +130,12 @@ public class Armadillo extends Animal { @Override - public boolean wantsToPickUp(ItemStack stack) { -- ItemStack itemstack1 = this.getItemInHand(InteractionHand.MAIN_HAND); -- -- return !itemstack1.isEmpty() && this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && this.inventory.canAddItem(stack) && this.allayConsidersItemEqual(itemstack1, stack); -+ // Purpur start -+ if (!this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ return false; -+ } -+ ItemStack itemStack = this.getItemInHand(InteractionHand.MAIN_HAND); -+ if (itemStack.isEmpty()) { -+ return false; -+ } -+ if (!allayConsidersItemEqual(itemStack, stack)) { -+ return false; -+ } -+ if (!this.inventory.canAddItem(stack)) { -+ return false; -+ } -+ for (String tag : this.level().purpurConfig.allayRespectNBT) { -+ if (stack.hasTag() && itemStack.hasTag()) { -+ Tag tag1 = stack.getTag().get(tag); -+ Tag tag2 = itemStack.getTag().get(tag); -+ if (!Objects.equals(tag1, tag2)) { -+ return false; -+ } -+ } -+ } -+ return true; -+ // Purpur end + protected void customServerAiStep() { +- this.level().getProfiler().push("armadilloBrain"); ++ //this.level().getProfiler().push("armadilloBrain"); // Purpur + ((Brain) this.brain).tick((ServerLevel) this.level(), this); // CraftBukkit - decompile error +- this.level().getProfiler().pop(); +- this.level().getProfiler().push("armadilloActivityUpdate"); ++ //this.level().getProfiler().pop(); // Purpur ++ //this.level().getProfiler().push("armadilloActivityUpdate"); // Purpur + ArmadilloAi.updateActivity(this); +- this.level().getProfiler().pop(); ++ //this.level().getProfiler().pop(); // Purpur + if (this.isAlive() && !this.isBaby() && --this.scuteTime <= 0) { + this.playSound(SoundEvents.ARMADILLO_SCUTE_DROP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); + this.forceDrops = true; // CraftBukkit +@@ -469,4 +469,11 @@ public class Armadillo extends Animal { + return this.animationDuration; + } } - - private boolean allayConsidersItemEqual(ItemStack stack, ItemStack stack2) { ++ ++ // Purpur start ++ @Override ++ public int getPurpurBreedTime() { ++ return 6000; ++ } ++ // Purpur end + } diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -index 33c160994f70f71446d665e7487913437c9f9db4..e3f72230e94b15a401e45cf8c10a1890d3278431 100644 +index a8cc6ddbf45370fe632e5c5fb7ceef3d299e62a4..d330f79e860662bc93a1703215e66e6564d181b9 100644 --- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java +++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -@@ -98,6 +98,43 @@ public class Axolotl extends Animal implements LerpingModel, VariantHolder getModelRotationValues() { return this.modelRotationValues; -@@ -278,13 +315,13 @@ public class Axolotl extends Animal implements LerpingModel, VariantHolder optional = this.getBrain().getMemory(MemoryModuleType.PLAY_DEAD_TICKS); -@@ -511,14 +548,22 @@ public class Axolotl extends Animal implements LerpingModel, VariantHolder { +@@ -103,6 +103,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(); @@ -9565,10 +9139,10 @@ index 1767fd2df8cb37e9c36fa3008b5131ff4bdad12c..37f1d3c656997906cef57d9dbefc226d public Frog(EntityType type, Level world) { super(type, world); - this.lookControl = new Frog.FrogLookControl(this); - this.setPathfindingMalus(BlockPathTypes.WATER, 4.0F); - this.setPathfindingMalus(BlockPathTypes.TRAPDOOR, -1.0F); -- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); +@@ -110,6 +112,58 @@ 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 + this.purpurLandController = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.2F); + this.purpurWaterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F); @@ -9589,9 +9163,8 @@ index 1767fd2df8cb37e9c36fa3008b5131ff4bdad12c..37f1d3c656997906cef57d9dbefc226d + } + }; + // Purpur end - this.setMaxUpStep(1.0F); - } - ++ } ++ + // Purpur start + @Override + public boolean isRidable() { @@ -9622,19 +9195,16 @@ index 1767fd2df8cb37e9c36fa3008b5131ff4bdad12c..37f1d3c656997906cef57d9dbefc226d + + public int getPurpurBreedTime() { + return this.level().purpurConfig.frogBreedingTicks; -+ } -+ + } + @Override - protected Brain.Provider brainProvider() { - return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); -@@ -186,13 +239,13 @@ public class Frog extends Animal implements VariantHolder { - private int behaviorTick = 0; // Pufferfish +@@ -183,12 +237,13 @@ public class Frog extends Animal implements VariantHolder> { + @Override protected void customServerAiStep() { - this.level().getProfiler().push("frogBrain"); -- if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish + //this.level().getProfiler().push("frogBrain"); // Purpur -+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("frogActivityUpdate"); @@ -9646,20 +9216,20 @@ index 1767fd2df8cb37e9c36fa3008b5131ff4bdad12c..37f1d3c656997906cef57d9dbefc226d super.customServerAiStep(); } -@@ -376,7 +429,7 @@ public class Frog extends Animal implements VariantHolder { +@@ -371,7 +426,7 @@ public class Frog extends Animal implements VariantHolder> { return world.getBlockState(pos.below()).is(BlockTags.FROGS_SPAWNABLE_ON) && isBrightEnoughToSpawn(world, pos); } - class FrogLookControl extends LookControl { + class FrogLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - FrogLookControl(Mob entity) { + FrogLookControl(final Mob entity) { super(entity); } diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -index 415afe3473d9f8a50b1edab8cfda6158e59836e6..2a9c2a69a0589e4e7b7c79d3716376b360a2eba1 100644 +index 290d41136f5ec7671bc4990dfe50da0a770c124d..09c4cf772df4644413e40055fedcdf42ee8064fd 100644 --- a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java +++ b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -@@ -48,13 +48,50 @@ public class Tadpole extends AbstractFish { +@@ -51,13 +51,50 @@ public class Tadpole extends AbstractFish { protected static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.HURT_BY, SensorType.FROG_TEMPTATIONS); protected static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.LOOK_TARGET, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.NEAREST_VISIBLE_ADULT, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.BREED_TARGET, MemoryModuleType.IS_PANICKING); public boolean ageLocked; // Paper @@ -9711,17 +9281,16 @@ index 415afe3473d9f8a50b1edab8cfda6158e59836e6..2a9c2a69a0589e4e7b7c79d3716376b3 @Override protected PathNavigation createNavigation(Level world) { return new WaterBoundPathNavigation(this, world); -@@ -83,13 +120,12 @@ public class Tadpole extends AbstractFish { - private int behaviorTick = 0; // Pufferfish +@@ -85,12 +122,13 @@ public class Tadpole extends AbstractFish { + @Override protected void customServerAiStep() { - this.level().getProfiler().push("tadpoleBrain"); -- if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish -- this.getBrain().tick((ServerLevel) this.level(), this); ++ //this.level().getProfiler().push("tadpoleBrain"); // Purpur ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish + this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("tadpoleActivityUpdate"); -+ //this.level().getProfiler().push("tadpoleBrain"); // Purpur -+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider + //this.level().getProfiler().pop(); // Purpur + //this.level().getProfiler().push("tadpoleActivityUpdate"); // Purpur TadpoleAi.updateActivity(this); @@ -9731,10 +9300,10 @@ index 415afe3473d9f8a50b1edab8cfda6158e59836e6..2a9c2a69a0589e4e7b7c79d3716376b3 } diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 2e4177cfb02616ef6fa689f6d378976e39484cfb..9d356b08279fd611fb9a7d25be6ede59998a9799 100644 +index 02e49c7ae5e120302b6479cf3e3934b9217eebf0..6a3c68839d3b993c82fabd4e17f53e38ce9c38f7 100644 --- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -92,6 +92,38 @@ public class Goat extends Animal { +@@ -91,6 +91,38 @@ public class Goat extends Animal { return InstrumentItem.create(Items.GOAT_HORN, (Holder) holderset.getRandomElement(randomsource).get()); } @@ -9773,14 +9342,13 @@ index 2e4177cfb02616ef6fa689f6d378976e39484cfb..9d356b08279fd611fb9a7d25be6ede59 @Override protected Brain.Provider brainProvider() { return Brain.provider(Goat.MEMORY_TYPES, Goat.SENSOR_TYPES); -@@ -194,13 +226,13 @@ public class Goat extends Animal { - private int behaviorTick = 0; // Pufferfish +@@ -192,12 +224,13 @@ public class Goat extends Animal { + @Override protected void customServerAiStep() { - this.level().getProfiler().push("goatBrain"); -- if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish + //this.level().getProfiler().push("goatBrain"); // Purpur -+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("goatActivityUpdate"); @@ -9792,7 +9360,7 @@ index 2e4177cfb02616ef6fa689f6d378976e39484cfb..9d356b08279fd611fb9a7d25be6ede59 super.customServerAiStep(); } -@@ -397,6 +429,7 @@ public class Goat extends Animal { +@@ -394,6 +427,7 @@ public class Goat extends Animal { // Paper start - Goat ram API public void ram(net.minecraft.world.entity.LivingEntity entity) { @@ -9801,16 +9369,15 @@ index 2e4177cfb02616ef6fa689f6d378976e39484cfb..9d356b08279fd611fb9a7d25be6ede59 brain.setMemory(MemoryModuleType.RAM_TARGET, entity.position()); brain.eraseMemory(MemoryModuleType.RAM_COOLDOWN_TICKS); diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -index 815eb15086976b8f9e03bf8182d9ed50aec14720..3170f9044f18b8c609433ddbd3ef9ac330644a0f 100644 +index 9357cf0179d19fbdfe76413e909a99b924c85780..59829fb7342696d29aa709d392f89bf263257fd3 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -@@ -149,12 +149,60 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, +@@ -217,11 +217,59 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, protected AbstractHorse(EntityType type, Level world) { super(type, world); + 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.setMaxUpStep(1.0F); this.createInventory(); } @@ -9865,7 +9432,7 @@ index 815eb15086976b8f9e03bf8182d9ed50aec14720..3170f9044f18b8c609433ddbd3ef9ac3 this.goalSelector.addGoal(1, new PanicGoal(this, 1.2D)); this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D)); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D, AbstractHorse.class)); -@@ -165,6 +213,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, +@@ -232,6 +280,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, if (this.canPerformRearing()) { this.goalSelector.addGoal(9, new RandomStandGoal(this)); } @@ -9873,26 +9440,17 @@ index 815eb15086976b8f9e03bf8182d9ed50aec14720..3170f9044f18b8c609433ddbd3ef9ac3 this.addBehaviourGoals(); } -@@ -337,7 +386,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - - @Override - protected int calculateFallDamage(float fallDistance, float damageMultiplier) { -- return Mth.ceil((fallDistance * 0.5F - 3.0F) * damageMultiplier); -+ return Mth.ceil((fallDistance * 0.5F - this.safeFallDistance) * damageMultiplier); - } - - protected int getInventorySize() { -@@ -1231,7 +1280,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, +@@ -1249,7 +1298,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, entityData = new AgeableMob.AgeableMobGroupData(0.2F); } - this.randomizeAttributes(world.getRandom()); + // this.randomizeAttributes(world.getRandom()); // Purpur - replaced by initAttributes() - return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData, entityNbt); + return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData); } diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -index 8c14f9f2ad383f87c498126f135b460a241da410..42efd14b59a2b7da3409895bdff49e83b6cb2fa5 100644 +index ff02169ba14f5264cea8beaf1779e2890c5d74b8..94021abe521aea4a70f5eaa78fb05f9f71b7c38c 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java @@ -15,6 +15,43 @@ public class Donkey extends AbstractChestedHorse { @@ -9940,10 +9498,10 @@ index 8c14f9f2ad383f87c498126f135b460a241da410..42efd14b59a2b7da3409895bdff49e83 protected SoundEvent getAmbientSound() { return SoundEvents.DONKEY_AMBIENT; diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -index 2181d74ad955197eb4f1925a64914a6197fa9023..eab6efcae632a393924d7245a71c40b57c6e316d 100644 +index 6e299770fca78699f7e1988db4cdef37b99d74c1..fdf9ec418b0fc567e286ac79dbdbeddac568ad67 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -@@ -40,6 +40,43 @@ public class Horse extends AbstractHorse implements VariantHolder { +@@ -44,6 +44,43 @@ public class Horse extends AbstractHorse implements VariantHolder { super(type, world); } @@ -9988,7 +9546,7 @@ index 2181d74ad955197eb4f1925a64914a6197fa9023..eab6efcae632a393924d7245a71c40b5 protected void randomizeAttributes(RandomSource random) { this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double)generateMaxHealth(random::nextInt)); diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 6623674136b0f865d5b3d7a10d3bf05793b82f87..22abcf70f51a6752ab6d3f421366adb196e50dfc 100644 +index 1dd4290287725898ace29e46b439b55df8fdd1af..7d2a5c806fd0f1228c45b8a8b56d7ba13b899a2d 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java @@ -75,9 +75,84 @@ public class Llama extends AbstractChestedHorse implements VariantHolder entitytypes, Level world) { super(EntityType.ENDER_DRAGON, world); -@@ -130,6 +131,37 @@ public class EnderDragon extends Mob implements Enemy { +@@ -128,6 +129,37 @@ public class EnderDragon extends Mob implements Enemy { this.noCulling = true; this.phaseManager = new EnderDragonPhaseManager(this); this.explosionSource = new Explosion(world, this, null, null, Double.NaN, Double.NaN, Double.NaN, Float.NaN, true, Explosion.BlockInteraction.DESTROY, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, SoundEvents.GENERIC_EXPLODE); // CraftBukkit @@ -10600,7 +10155,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 } public void setDragonFight(EndDragonFight fight) { -@@ -144,6 +176,27 @@ public class EnderDragon extends Mob implements Enemy { +@@ -142,6 +174,27 @@ public class EnderDragon extends Mob implements Enemy { return this.fightOrigin; } @@ -10628,7 +10183,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0D); } -@@ -205,6 +258,37 @@ public class EnderDragon extends Mob implements Enemy { +@@ -203,6 +256,37 @@ public class EnderDragon extends Mob implements Enemy { @Override public void aiStep() { @@ -10666,7 +10221,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 this.processFlappingMovement(); if (this.level().isClientSide) { this.setHealth(this.getHealth()); -@@ -231,6 +315,8 @@ public class EnderDragon extends Mob implements Enemy { +@@ -229,6 +313,8 @@ public class EnderDragon extends Mob implements Enemy { float f; if (this.isDeadOrDying()) { @@ -10675,7 +10230,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 float f1 = (this.random.nextFloat() - 0.5F) * 8.0F; f = (this.random.nextFloat() - 0.5F) * 4.0F; -@@ -243,9 +329,9 @@ public class EnderDragon extends Mob implements Enemy { +@@ -241,9 +327,9 @@ public class EnderDragon extends Mob implements Enemy { f = 0.2F / ((float) vec3d.horizontalDistance() * 10.0F + 1.0F); f *= (float) Math.pow(2.0D, vec3d.y); @@ -10687,7 +10242,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 this.flapTime += f * 0.5F; } else { this.flapTime += f; -@@ -279,7 +365,7 @@ public class EnderDragon extends Mob implements Enemy { +@@ -277,7 +363,7 @@ public class EnderDragon extends Mob implements Enemy { } this.phaseManager.getCurrentPhase().doClientTick(); @@ -10696,7 +10251,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 DragonPhaseInstance idragoncontroller = this.phaseManager.getCurrentPhase(); idragoncontroller.doServerTick(); -@@ -348,7 +434,7 @@ public class EnderDragon extends Mob implements Enemy { +@@ -346,7 +432,7 @@ public class EnderDragon extends Mob implements Enemy { this.tickPart(this.body, (double) (f11 * 0.5F), 0.0D, (double) (-f12 * 0.5F)); this.tickPart(this.wing1, (double) (f12 * 4.5F), 2.0D, (double) (f11 * 4.5F)); this.tickPart(this.wing2, (double) (f12 * -4.5F), 2.0D, (double) (f11 * -4.5F)); @@ -10705,7 +10260,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 this.knockBack(this.level().getEntities((Entity) this, this.wing1.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); this.knockBack(this.level().getEntities((Entity) this, this.wing2.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); this.hurt(this.level().getEntities((Entity) this, this.head.getBoundingBox().inflate(1.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); -@@ -392,7 +478,7 @@ public class EnderDragon extends Mob implements Enemy { +@@ -390,7 +476,7 @@ public class EnderDragon extends Mob implements Enemy { } if (!this.level().isClientSide) { @@ -10714,7 +10269,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 if (this.dragonFight != null) { this.dragonFight.updateDragon(this); } -@@ -524,7 +610,7 @@ public class EnderDragon extends Mob implements Enemy { +@@ -522,7 +608,7 @@ public class EnderDragon extends Mob implements Enemy { BlockState iblockdata = this.level().getBlockState(blockposition); if (!iblockdata.isAir() && !iblockdata.is(BlockTags.DRAGON_TRANSPARENT)) { @@ -10723,7 +10278,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 // CraftBukkit start - Add blocks to list rather than destroying them // flag1 = this.level().removeBlock(blockposition, false) || flag1; flag1 = true; -@@ -668,7 +754,7 @@ public class EnderDragon extends Mob implements Enemy { +@@ -666,7 +752,7 @@ public class EnderDragon extends Mob implements Enemy { boolean flag = this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT); short short0 = 500; @@ -10732,7 +10287,7 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 short0 = 12000; } -@@ -1104,6 +1190,7 @@ public class EnderDragon extends Mob implements Enemy { +@@ -1102,6 +1188,7 @@ public class EnderDragon extends Mob implements Enemy { @Override protected boolean canRide(Entity entity) { @@ -10741,11 +10296,11 @@ index 1df13af62af7d0bbd92c84d424a07da66bb8583f..ff4b188084d43af9e8ed60e6a7799601 } diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce205f7844e 100644 +index 7ddca52f7fe3f289b4b867e134326b1ead1a2aee..4a98027a12c2535d1df3a9f6390eb85146398403 100644 --- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -85,20 +85,59 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - return entityliving.getMobType() != MobType.UNDEAD && entityliving.attackable(); +@@ -88,20 +88,59 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob + return !entityliving.getType().is(EntityTypeTags.WITHER_FRIENDS) && entityliving.attackable(); }; private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0D).selector(WitherBoss.LIVING_ENTITY_SELECTOR); + @Nullable private java.util.UUID summoner; // Purpur @@ -10805,7 +10360,7 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 @Override protected PathNavigation createNavigation(Level world) { FlyingPathNavigation navigationflying = new FlyingPathNavigation(this, world); -@@ -109,13 +148,113 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -112,13 +151,113 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob return navigationflying; } @@ -10919,7 +10474,7 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0])); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 0, false, false, WitherBoss.LIVING_ENTITY_SELECTOR)); } -@@ -133,6 +272,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -136,6 +275,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); nbt.putInt("Invul", this.getInvulnerableTicks()); @@ -10927,7 +10482,7 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 } @Override -@@ -142,6 +282,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -145,6 +285,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob if (this.hasCustomName()) { this.bossEvent.setName(this.getDisplayName()); } @@ -10935,7 +10490,7 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 } -@@ -264,6 +405,16 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -263,6 +404,16 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob @Override protected void customServerAiStep() { @@ -10952,7 +10507,7 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 int i; if (this.getInvulnerableTicks() > 0) { -@@ -280,7 +431,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -279,7 +430,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob } // CraftBukkit end @@ -10961,7 +10516,7 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 // CraftBukkit start - Use relative location for far away sounds // this.level().globalLevelEvent(1023, new BlockPosition(this), 0); int viewDistance = ((ServerLevel) this.level()).getCraftServer().getViewDistance() * 16; -@@ -305,7 +456,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -304,7 +455,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob this.setInvulnerableTicks(i); if (this.tickCount % 10 == 0) { @@ -10970,16 +10525,16 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 } } else { -@@ -365,7 +516,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -364,7 +515,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob if (this.destroyBlocksTick > 0) { --this.destroyBlocksTick; - if (this.destroyBlocksTick == 0 && this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { + if (this.destroyBlocksTick == 0 && (this.level().purpurConfig.witherBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // Purpur - i = Mth.floor(this.getY()); - j = Mth.floor(this.getX()); - int i1 = Mth.floor(this.getZ()); -@@ -398,8 +549,10 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob + boolean flag = false; + + j = Mth.floor(this.getBbWidth() / 2.0F + 1.0F); +@@ -391,8 +542,10 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob } } @@ -10992,7 +10547,7 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 } this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); -@@ -585,11 +738,11 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -580,11 +733,11 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob } public int getAlternativeTarget(int headIndex) { @@ -11006,7 +10561,7 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 } @Override -@@ -604,6 +757,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -594,6 +747,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob @Override protected boolean canRide(Entity entity) { @@ -11015,10 +10570,10 @@ index de2471cfa96a23944f229f33ffdff88b6b7756e4..1d896c6c49705acd87416dc11a1d8ce2 } diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -index eadcebd7845ee716e33c0ac0544502da1a6c5941..fef18455da5ae020f9875663984b26e54a1c4bf7 100644 +index c2bd2e303f956d390319f6bbbe9a6492ebec5154..6697cd8a632becd72ee132007a61d1221e817abf 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java +++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -100,10 +100,12 @@ public class ArmorStand extends LivingEntity { +@@ -103,10 +103,12 @@ public class ArmorStand extends LivingEntity { private boolean noTickPoseDirty = false; private boolean noTickEquipmentDirty = false; // Paper end - Allow ArmorStands not to tick @@ -11031,24 +10586,23 @@ index eadcebd7845ee716e33c0ac0544502da1a6c5941..fef18455da5ae020f9875663984b26e5 this.handItems = NonNullList.withSize(2, ItemStack.EMPTY); this.armorItems = NonNullList.withSize(4, ItemStack.EMPTY); this.headPose = ArmorStand.DEFAULT_HEAD_POSE; -@@ -113,6 +115,7 @@ public class ArmorStand extends LivingEntity { +@@ -115,6 +117,7 @@ public class ArmorStand extends LivingEntity { + this.rightArmPose = ArmorStand.DEFAULT_RIGHT_ARM_POSE; this.leftLegPose = ArmorStand.DEFAULT_LEFT_LEG_POSE; this.rightLegPose = ArmorStand.DEFAULT_RIGHT_LEG_POSE; - this.setMaxUpStep(0.0F); + this.setShowArms(world != null && world.purpurConfig.armorstandPlaceWithArms); // Purpur } public ArmorStand(Level world, double x, double y, double z) { -@@ -607,7 +610,7 @@ public class ArmorStand extends LivingEntity { +@@ -613,6 +616,7 @@ public class ArmorStand extends LivingEntity { private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(DamageSource damageSource) { // Paper ItemStack itemstack = new ItemStack(Items.ARMOR_STAND); -- if (this.hasCustomName()) { -+ if (this.level().purpurConfig.persistentDroppableEntityDisplayNames && this.hasCustomName()) { // Purpur - itemstack.setHoverName(this.getCustomName()); - } - -@@ -678,6 +681,7 @@ public class ArmorStand extends LivingEntity { ++ if (this.level().purpurConfig.persistentDroppableEntityDisplayNames) + itemstack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); + 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(damageSource); // Paper +@@ -676,6 +680,7 @@ public class ArmorStand extends LivingEntity { @Override public void tick() { @@ -11056,7 +10610,7 @@ index eadcebd7845ee716e33c0ac0544502da1a6c5941..fef18455da5ae020f9875663984b26e5 // Paper start - Allow ArmorStands not to tick if (!this.canTick) { if (this.noTickPoseDirty) { -@@ -1005,4 +1009,18 @@ public class ArmorStand extends LivingEntity { +@@ -1003,4 +1008,18 @@ public class ArmorStand extends LivingEntity { } } // Paper end @@ -11076,18 +10630,18 @@ index eadcebd7845ee716e33c0ac0544502da1a6c5941..fef18455da5ae020f9875663984b26e5 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -index c34701f95580e4cf45fe086115563127432a28c5..2363d9eaad655389c7b7d67d545ef8025f550431 100644 +index da0d1c9a1c4ae081bff9ca4230c9a1503885c354..9af8fcf6abb9b768829592bc1b091ebe4599ed2e 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java +++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -@@ -268,7 +268,13 @@ public class ItemFrame extends HangingEntity { +@@ -262,7 +262,13 @@ public class ItemFrame extends HangingEntity { } if (alwaysDrop) { - this.spawnAtLocation(this.getFrameItemStack()); + // Purpur start + final ItemStack itemFrame = this.getFrameItemStack(); -+ if (this.level().purpurConfig.persistentDroppableEntityDisplayNames && this.hasCustomName()) { -+ itemFrame.setHoverName(this.getCustomName()); ++ if (!this.level().purpurConfig.persistentDroppableEntityDisplayNames) { ++ itemFrame.set(DataComponents.CUSTOM_NAME, null); + } + this.spawnAtLocation(itemFrame); + // Purpur end @@ -11095,27 +10649,18 @@ index c34701f95580e4cf45fe086115563127432a28c5..2363d9eaad655389c7b7d67d545ef802 if (!itemstack.isEmpty()) { diff --git a/src/main/java/net/minecraft/world/entity/decoration/Painting.java b/src/main/java/net/minecraft/world/entity/decoration/Painting.java -index fee2269b241cbfb10bbbb76b404aa5ef3997dfe0..af07901daaf6a0e5cd7e4b1e07fb491566807932 100644 +index 40e7112669abb58a0ab6df1846afec3979e95e55..183464f202d4c2774840edfde1dfcab44d05d0d3 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/Painting.java +++ b/src/main/java/net/minecraft/world/entity/decoration/Painting.java -@@ -120,7 +120,7 @@ public class Painting extends HangingEntity implements VariantHolder holder = loadVariant(nbt).orElseGet(Painting::getDefaultVariant); -+ Holder holder = loadVariant(nbt).orElseGet(() -> (Holder.Reference) getDefaultVariant()); // Purpur - decompile error TODO: still needed? - this.setVariant(holder); - this.direction = Direction.from2DDataValue(nbt.getByte("facing")); - super.readAdditionalSaveData(nbt); -@@ -155,7 +155,13 @@ public class Painting extends HangingEntity implements VariantHolder type, Level world) { super(type, world); -@@ -365,7 +371,16 @@ public class ItemEntity extends Entity implements TraceableEntity { +@@ -371,7 +377,16 @@ public class ItemEntity extends Entity implements TraceableEntity { @Override public boolean hurt(DamageSource source, float amount) { @@ -11157,7 +10702,7 @@ index 29ce703a79f7893ac990ad80e0f1c1cf63546e6c..a6c2ecce3f6947ec15935fcf8c5c51bb return false; } else if (!this.getItem().isEmpty() && this.getItem().is(Items.NETHER_STAR) && source.is(DamageTypeTags.IS_EXPLOSION)) { return false; -@@ -568,6 +583,12 @@ public class ItemEntity extends Entity implements TraceableEntity { +@@ -579,6 +594,12 @@ public class ItemEntity extends Entity implements TraceableEntity { public void setItem(ItemStack stack) { this.getEntityData().set(ItemEntity.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 @@ -11171,10 +10716,10 @@ index 29ce703a79f7893ac990ad80e0f1c1cf63546e6c..a6c2ecce3f6947ec15935fcf8c5c51bb @Override diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index e712bd07ea2946167782473a536e0c72fab4bccd..6d934405cd18d63943171448743cafd5c52026e2 100644 +index f1f352ec0e51f5db59254841a06c176c5a876fc9..dff0e7b08b973a1b29f916e63d3e4778d6c56cdc 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -200,4 +200,29 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -193,4 +193,29 @@ public class PrimedTnt extends Entity implements TraceableEntity { return !level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid(); } // Paper end - Option to prevent TNT from moving in water @@ -11191,7 +10736,7 @@ index e712bd07ea2946167782473a536e0c72fab4bccd..6d934405cd18d63943171448743cafd5 + new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.TNT)); + tntItem.setPickUpDelay(10); + -+ inHand.hurtAndBreak(1, player, entity -> entity.broadcastBreakEvent(hand)); ++ inHand.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand)); + level().addFreshEntity(tntItem, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CUSTOM); + + this.playSound(net.minecraft.sounds.SoundEvents.SHEEP_SHEAR); @@ -11205,10 +10750,10 @@ index e712bd07ea2946167782473a536e0c72fab4bccd..6d934405cd18d63943171448743cafd5 + // Purpur end - Shears can defuse TNT } diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -index 586e3e92ccc275446df6dbbff9bf010a37a9aa8f..a00646bc8a9caefe56e48b7682e8fb0c464b81fa 100644 +index 0c5fe46d2da113beff3e220843593d616e37d4ca..e80307198b051cbcd9f72b36e459276848dcb4c9 100644 --- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java +++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -66,16 +66,19 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo +@@ -65,16 +65,19 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo protected AbstractSkeleton(EntityType type, Level world) { super(type, world); this.reassessWeaponGoal(); @@ -11228,8 +10773,8 @@ index 586e3e92ccc275446df6dbbff9bf010a37a9aa8f..a00646bc8a9caefe56e48b7682e8fb0c this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0])); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); -@@ -99,35 +102,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - } +@@ -93,35 +96,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + abstract SoundEvent getStepSound(); // Paper start - shouldBurnInDay API - private boolean shouldBurnInDay = true; @@ -11258,7 +10803,7 @@ index 586e3e92ccc275446df6dbbff9bf010a37a9aa8f..a00646bc8a9caefe56e48b7682e8fb0c - } - - if (flag) { -- this.setSecondsOnFire(8); +- this.igniteForSeconds(8); - } - } - @@ -11266,7 +10811,7 @@ index 586e3e92ccc275446df6dbbff9bf010a37a9aa8f..a00646bc8a9caefe56e48b7682e8fb0c super.aiStep(); } -@@ -161,11 +143,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo +@@ -153,11 +135,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo this.reassessWeaponGoal(); this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { @@ -11279,15 +10824,7 @@ index 586e3e92ccc275446df6dbbff9bf010a37a9aa8f..a00646bc8a9caefe56e48b7682e8fb0c this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; } -@@ -192,7 +170,6 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - } else { - this.goalSelector.addGoal(4, this.meleeGoal); - } -- - } - } - -@@ -205,7 +182,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo +@@ -205,7 +183,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo double d2 = target.getZ() - this.getZ(); double d3 = Math.sqrt(d0 * d0 + d2 * d2); @@ -11296,7 +10833,7 @@ index 586e3e92ccc275446df6dbbff9bf010a37a9aa8f..a00646bc8a9caefe56e48b7682e8fb0c // CraftBukkit start org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), entityarrow.getPickupItem(), entityarrow, net.minecraft.world.InteractionHand.MAIN_HAND, 0.8F, true); // Paper if (event.isCancelled()) { -@@ -236,7 +213,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo +@@ -236,7 +214,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo this.reassessWeaponGoal(); // Paper start - shouldBurnInDay API if (nbt.contains("Paper.ShouldBurnInDay")) { @@ -11305,7 +10842,7 @@ index 586e3e92ccc275446df6dbbff9bf010a37a9aa8f..a00646bc8a9caefe56e48b7682e8fb0c } // Paper end - shouldBurnInDay API } -@@ -245,7 +222,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo +@@ -245,7 +223,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo @Override public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); @@ -11315,19 +10852,19 @@ index 586e3e92ccc275446df6dbbff9bf010a37a9aa8f..a00646bc8a9caefe56e48b7682e8fb0c // Paper end - shouldBurnInDay API diff --git a/src/main/java/net/minecraft/world/entity/monster/Blaze.java b/src/main/java/net/minecraft/world/entity/monster/Blaze.java -index 58c2b8b8bfd5a40259aa6252243884d14c183ef2..c31d2ab0ed3693cd8334b5bbde1f565fff7c9162 100644 +index aee2fa184bc5723dfd3d54f460a173982d874c8b..27db17e19dd95e99f7bd67747eba3c3072b48ed5 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Blaze.java +++ b/src/main/java/net/minecraft/world/entity/monster/Blaze.java @@ -32,26 +32,73 @@ public class Blaze extends Monster { public Blaze(EntityType type, Level world) { super(type, world); -- this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); +- this.setPathfindingMalus(PathType.WATER, -1.0F); + this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur -+ if (isSensitiveToWater()) this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); // Purpur - this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F); - this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 0.0F); - this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, 0.0F); ++ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur + this.setPathfindingMalus(PathType.LAVA, 8.0F); + this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); + this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); this.xpReward = 10; } @@ -11414,11 +10951,24 @@ index 58c2b8b8bfd5a40259aa6252243884d14c183ef2..c31d2ab0ed3693cd8334b5bbde1f565f this.nextHeightOffsetChangeTick--; if (this.nextHeightOffsetChangeTick <= 0) { this.nextHeightOffsetChangeTick = 100; +diff --git a/src/main/java/net/minecraft/world/entity/monster/Bogged.java b/src/main/java/net/minecraft/world/entity/monster/Bogged.java +index 754eb747179d9318bc5a3883e5622cc400c4e06c..4e929539cb093d58f3311d5f6a62bd1aeb71cfb0 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Bogged.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Bogged.java +@@ -155,7 +155,7 @@ public class Bogged extends AbstractSkeleton implements Shearable { + + // Paper start - shear drops API + @Override +- public java.util.List generateDefaultDrops() { ++ public java.util.List generateDefaultDrops(int looting) { // Purpur + final java.util.List drops = new java.util.ArrayList<>(); + this.generateShearedMushrooms(drops::add); + return drops; diff --git a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java -index 70d25bb45ad603095a1f5812cc396dfc5f16a1e1..c9bd400473166999479f5eef1edad529d3aafe01 100644 +index 87e4b300ac248f6c13d9b4a8f24fd78b24b565b4..43b5a0e7993ae9daef1c1ea67722347f9851d3a9 100644 --- a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java +++ b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java -@@ -29,6 +29,38 @@ public class CaveSpider extends Spider { +@@ -26,6 +26,38 @@ public class CaveSpider extends Spider { return Spider.createAttributes().add(Attributes.MAX_HEALTH, 12.0D); } @@ -11458,13 +11008,13 @@ index 70d25bb45ad603095a1f5812cc396dfc5f16a1e1..c9bd400473166999479f5eef1edad529 public boolean doHurtTarget(Entity target) { if (super.doHurtTarget(target)) { diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index 9657796d08f4a102d9d5ff7685f2a152d1a87fda..54315fb84e3289f0ad8305c2c2cec980a5b2c627 100644 +index cbcb2bfa8f91099e5c374f590f48885390bdf7a7..1829bedfa8084c4932a0e67c36f48f19993e22b6 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java +++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -60,21 +60,99 @@ public class Creeper extends Monster implements PowerableMob { - public int maxSwell = 30; +@@ -61,21 +61,99 @@ public class Creeper extends Monster implements PowerableMob { public int explosionRadius = 3; private int droppedSkulls; + private Player entityIgniter; // CraftBukkit + // Purpur start + private int spacebarCharge = 0; + private int prevSpacebarCharge = 0; @@ -11561,7 +11111,7 @@ index 9657796d08f4a102d9d5ff7685f2a152d1a87fda..54315fb84e3289f0ad8305c2c2cec980 this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); } -@@ -174,6 +252,37 @@ public class Creeper extends Monster implements PowerableMob { +@@ -175,6 +253,37 @@ public class Creeper extends Monster implements PowerableMob { } } @@ -11570,12 +11120,12 @@ index 9657796d08f4a102d9d5ff7685f2a152d1a87fda..54315fb84e3289f0ad8305c2c2cec980 + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.creeperMaxHealth); + } + -+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, @Nullable net.minecraft.world.entity.SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { ++ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, @Nullable net.minecraft.world.entity.SpawnGroupData entityData) { + double chance = world.getLevel().purpurConfig.creeperChargedChance; + if (chance > 0D && random.nextDouble() <= chance) { + setPowered(true); + } -+ return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); ++ return super.finalizeSpawn(world, difficulty, spawnReason, entityData); + } + + @Override @@ -11599,7 +11149,7 @@ index 9657796d08f4a102d9d5ff7685f2a152d1a87fda..54315fb84e3289f0ad8305c2c2cec980 @Override protected SoundEvent getHurtSound(DamageSource source) { return SoundEvents.CREEPER_HURT; -@@ -265,15 +374,17 @@ public class Creeper extends Monster implements PowerableMob { +@@ -263,15 +372,17 @@ public class Creeper extends Monster implements PowerableMob { } public void explodeCreeper() { @@ -11614,12 +11164,12 @@ index 9657796d08f4a102d9d5ff7685f2a152d1a87fda..54315fb84e3289f0ad8305c2c2cec980 if (!event.isCancelled()) { // CraftBukkit end this.dead = true; -- this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit -+ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), this.level().getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) && level().purpurConfig.creeperAllowGriefing ? Level.ExplosionInteraction.MOB : Level.ExplosionInteraction.NONE); // CraftBukkit // Purpur +- this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API ++ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), this.level().getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) && level().purpurConfig.creeperAllowGriefing ? Level.ExplosionInteraction.MOB : Level.ExplosionInteraction.NONE); // CraftBukkit // Paper - fix DamageSource API // Purpur this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause this.spawnLingeringCloud(); // CraftBukkit start -@@ -283,7 +394,7 @@ public class Creeper extends Monster implements PowerableMob { +@@ -281,7 +392,7 @@ public class Creeper extends Monster implements PowerableMob { } // CraftBukkit end } @@ -11628,7 +11178,7 @@ index 9657796d08f4a102d9d5ff7685f2a152d1a87fda..54315fb84e3289f0ad8305c2c2cec980 } private void spawnLingeringCloud() { -@@ -325,6 +436,7 @@ public class Creeper extends Monster implements PowerableMob { +@@ -323,6 +434,7 @@ public class Creeper extends Monster implements PowerableMob { 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(Creeper.DATA_IS_IGNITED, event.isIgnited()); @@ -11637,7 +11187,7 @@ index 9657796d08f4a102d9d5ff7685f2a152d1a87fda..54315fb84e3289f0ad8305c2c2cec980 } // Paper end - CreeperIgniteEvent diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -index 01897af1e6253b987734a24c052daf2ce1314092..7600e747d91ae888eb801cfafcb09bffb76c8e62 100644 +index cff1b5e0e3fd32d82157d5f13d83d4abdfad7378..15afee3c4f6307557321424560d2340e23cd472b 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java +++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java @@ -29,6 +29,7 @@ import net.minecraft.world.entity.ai.goal.MoveToBlockGoal; @@ -11648,8 +11198,8 @@ index 01897af1e6253b987734a24c052daf2ce1314092..7600e747d91ae888eb801cfafcb09bff import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -@@ -68,6 +69,58 @@ public class Drowned extends Zombie implements RangedAttackMob { - this.groundNavigation = new GroundPathNavigation(this, world); +@@ -71,6 +72,58 @@ public class Drowned extends Zombie implements RangedAttackMob { + return Zombie.createAttributes().add(Attributes.STEP_HEIGHT, 1.0D); } + // Purpur start @@ -11707,7 +11257,7 @@ index 01897af1e6253b987734a24c052daf2ce1314092..7600e747d91ae888eb801cfafcb09bff @Override protected void addBehaviourGoals() { this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0D)); -@@ -75,10 +128,23 @@ public class Drowned extends Zombie implements RangedAttackMob { +@@ -78,10 +131,23 @@ public class Drowned extends Zombie implements RangedAttackMob { this.goalSelector.addGoal(2, new Drowned.DrownedAttackGoal(this, 1.0D, false)); this.goalSelector.addGoal(5, new Drowned.DrownedGoToBeachGoal(this, 1.0D)); this.goalSelector.addGoal(6, new Drowned.DrownedSwimUpGoal(this, 1.0D, this.level().getSeaLevel())); @@ -11732,7 +11282,7 @@ index 01897af1e6253b987734a24c052daf2ce1314092..7600e747d91ae888eb801cfafcb09bff this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Axolotl.class, true, false)); this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); -@@ -112,7 +178,7 @@ public class Drowned extends Zombie implements RangedAttackMob { +@@ -115,7 +181,7 @@ public class Drowned extends Zombie implements RangedAttackMob { @Override public boolean supportsBreakDoorGoal() { @@ -11741,7 +11291,7 @@ index 01897af1e6253b987734a24c052daf2ce1314092..7600e747d91ae888eb801cfafcb09bff } @Override -@@ -259,8 +325,7 @@ public class Drowned extends Zombie implements RangedAttackMob { +@@ -262,8 +328,7 @@ public class Drowned extends Zombie implements RangedAttackMob { this.searchingForLand = targetingUnderwater; } @@ -11751,7 +11301,7 @@ index 01897af1e6253b987734a24c052daf2ce1314092..7600e747d91ae888eb801cfafcb09bff private final Drowned drowned; public DrownedMoveControl(Drowned drowned) { -@@ -269,7 +334,7 @@ public class Drowned extends Zombie implements RangedAttackMob { +@@ -272,7 +337,7 @@ public class Drowned extends Zombie implements RangedAttackMob { } @Override @@ -11760,7 +11310,7 @@ index 01897af1e6253b987734a24c052daf2ce1314092..7600e747d91ae888eb801cfafcb09bff LivingEntity entityliving = this.drowned.getTarget(); if (this.drowned.wantsToSwim() && this.drowned.isInWater()) { -@@ -292,7 +357,7 @@ public class Drowned extends Zombie implements RangedAttackMob { +@@ -295,7 +360,7 @@ public class Drowned extends Zombie implements RangedAttackMob { this.drowned.setYRot(this.rotlerp(this.drowned.getYRot(), f, 90.0F)); this.drowned.yBodyRot = this.drowned.getYRot(); @@ -11769,7 +11319,7 @@ index 01897af1e6253b987734a24c052daf2ce1314092..7600e747d91ae888eb801cfafcb09bff float f2 = Mth.lerp(0.125F, this.drowned.getSpeed(), f1); this.drowned.setSpeed(f2); -@@ -302,7 +367,7 @@ public class Drowned extends Zombie implements RangedAttackMob { +@@ -305,7 +370,7 @@ public class Drowned extends Zombie implements RangedAttackMob { this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(0.0D, -0.008D, 0.0D)); } @@ -11779,10 +11329,10 @@ index 01897af1e6253b987734a24c052daf2ce1314092..7600e747d91ae888eb801cfafcb09bff } diff --git a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -index 91ff663b2260d1cdd1388c93068e4cd9d0331aea..cb189457305916f509d624beb303feff35d0c358 100644 +index fd995b1f29c47884e9db2cb92f1dd615d62ae032..7e8603ef5df722f19e85b9c5cdd4ebfdd6481e42 100644 --- a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java +++ b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -@@ -36,6 +36,33 @@ public class ElderGuardian extends Guardian { +@@ -33,6 +33,33 @@ public class ElderGuardian extends Guardian { } @@ -11817,15 +11367,15 @@ index 91ff663b2260d1cdd1388c93068e4cd9d0331aea..cb189457305916f509d624beb303feff return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.30000001192092896D).add(Attributes.ATTACK_DAMAGE, 8.0D).add(Attributes.MAX_HEALTH, 80.0D); } diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f37ba78f67 100644 +index 260202fab3ac300552c557b44dcf251f083c6a78..5b49a6b1884c33bedafca5cff0214cdfccd87302 100644 --- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -95,12 +95,40 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -90,12 +90,40 @@ public class EnderMan extends Monster implements NeutralMob { + public EnderMan(EntityType type, Level world) { super(type, world); - this.setMaxUpStep(1.0F); -- this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); -+ if (isSensitiveToWater()) this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); // Purpur +- this.setPathfindingMalus(PathType.WATER, -1.0F); ++ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur + } + + // Purpur start @@ -11862,7 +11412,7 @@ index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f3 this.goalSelector.addGoal(1, new EnderMan.EndermanFreezeWhenLookedAt(this)); this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false)); this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D, 0.0F)); -@@ -108,9 +136,10 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -103,9 +131,10 @@ 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)); @@ -11874,7 +11424,7 @@ index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f3 this.targetSelector.addGoal(4, new ResetUniversalAngerTargetGoal<>(this, false)); } -@@ -247,7 +276,7 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -242,7 +271,7 @@ public class EnderMan extends Monster implements NeutralMob { // Paper end - EndermanAttackPlayerEvent ItemStack itemstack = (ItemStack) player.getInventory().armor.get(3); @@ -11883,7 +11433,7 @@ index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f3 return false; } else { Vec3 vec3d = player.getViewVector(1.0F).normalize(); -@@ -289,12 +318,12 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -274,12 +303,12 @@ public class EnderMan extends Monster implements NeutralMob { @Override public boolean isSensitiveToWater() { @@ -11898,7 +11448,7 @@ index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f3 float f = this.getLightLevelDependentMagicValue(); if (f > 0.5F && this.level().canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper - EndermanEscapeEvent -@@ -415,6 +444,8 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -394,6 +423,8 @@ public class EnderMan extends Monster implements NeutralMob { public boolean hurt(DamageSource source, float amount) { if (this.isInvulnerableTo(source)) { return false; @@ -11907,7 +11457,7 @@ index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f3 } else { boolean flag = source.getDirectEntity() instanceof ThrownPotion; boolean flag1; -@@ -429,6 +460,7 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -408,6 +439,7 @@ public class EnderMan extends Monster implements NeutralMob { } else { flag1 = flag && this.hurtWithCleanWater(source, (ThrownPotion) source.getDirectEntity(), amount); @@ -11915,7 +11465,7 @@ index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f3 if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent for (int i = 0; i < 64; ++i) { if (this.teleport()) { -@@ -475,7 +507,7 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -452,7 +484,7 @@ public class EnderMan extends Monster implements NeutralMob { @Override public boolean requiresCustomPersistence() { @@ -11924,7 +11474,7 @@ index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f3 } private static class EndermanFreezeWhenLookedAt extends Goal { -@@ -522,7 +554,16 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -499,7 +531,16 @@ public class EnderMan extends Monster implements NeutralMob { @Override public boolean canUse() { @@ -11942,7 +11492,7 @@ index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f3 } @Override -@@ -567,7 +608,16 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -544,7 +585,16 @@ public class EnderMan extends Monster implements NeutralMob { @Override public boolean canUse() { @@ -11961,10 +11511,10 @@ index 6563e625ebae47fc68e5010d36bd4b4d327c07b7..13bc6389652f8868d7539676ee6d85f3 @Override diff --git a/src/main/java/net/minecraft/world/entity/monster/Endermite.java b/src/main/java/net/minecraft/world/entity/monster/Endermite.java -index b8ce2a9ad151b20f0f4e9e8e34a57069d8d77128..965362c281315c15fb70a83a6949d7825bebf15b 100644 +index 9c78905762d9a484878fa9cf03a2ca3850e7e613..14d6796a124a85b8cbf5f3b719d89d99e0cf8db5 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Endermite.java +++ b/src/main/java/net/minecraft/world/entity/monster/Endermite.java -@@ -37,20 +37,63 @@ public class Endermite extends Monster { +@@ -32,20 +32,63 @@ public class Endermite extends Monster { private static final int MAX_LIFE = 2400; public int life; @@ -12028,7 +11578,7 @@ index b8ce2a9ad151b20f0f4e9e8e34a57069d8d77128..965362c281315c15fb70a83a6949d782 this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers()); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); } -@@ -93,12 +136,14 @@ public class Endermite extends Monster { +@@ -83,12 +126,14 @@ public class Endermite extends Monster { public void readAdditionalSaveData(CompoundTag nbt) { super.readAdditionalSaveData(nbt); this.life = nbt.getInt("Lifetime"); @@ -12044,10 +11594,10 @@ index b8ce2a9ad151b20f0f4e9e8e34a57069d8d77128..965362c281315c15fb70a83a6949d782 @Override diff --git a/src/main/java/net/minecraft/world/entity/monster/Evoker.java b/src/main/java/net/minecraft/world/entity/monster/Evoker.java -index e67cb165a0d706d38e4970fb3d63f59a29808a76..daee6c4c0c2d43b65cdfd691bbbdc72465702dfe 100644 +index 38e866571c35ebc4843a8d4fa39691902a5fcc91..f92f93c780f4c176d6c02c4b98ffe3a4ef3993f6 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Evoker.java +++ b/src/main/java/net/minecraft/world/entity/monster/Evoker.java -@@ -51,10 +51,43 @@ public class Evoker extends SpellcasterIllager { +@@ -52,10 +52,43 @@ public class Evoker extends SpellcasterIllager { this.xpReward = 10; } @@ -12091,7 +11641,7 @@ index e67cb165a0d706d38e4970fb3d63f59a29808a76..daee6c4c0c2d43b65cdfd691bbbdc724 this.goalSelector.addGoal(1, new Evoker.EvokerCastingSpellGoal()); this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 0.6D, 1.0D)); this.goalSelector.addGoal(4, new Evoker.EvokerSummonSpellGoal()); -@@ -63,6 +96,7 @@ public class Evoker extends SpellcasterIllager { +@@ -64,6 +97,7 @@ public class Evoker extends SpellcasterIllager { this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D)); this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); @@ -12099,7 +11649,7 @@ index e67cb165a0d706d38e4970fb3d63f59a29808a76..daee6c4c0c2d43b65cdfd691bbbdc724 this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{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)); -@@ -327,7 +361,7 @@ public class Evoker extends SpellcasterIllager { +@@ -340,7 +374,7 @@ public class Evoker extends SpellcasterIllager { return false; } else if (Evoker.this.tickCount < this.nextAttackTickCount) { return false; @@ -12109,10 +11659,10 @@ index e67cb165a0d706d38e4970fb3d63f59a29808a76..daee6c4c0c2d43b65cdfd691bbbdc724 } else { List list = Evoker.this.level().getNearbyEntities(Sheep.class, this.wololoTargeting, Evoker.this, Evoker.this.getBoundingBox().inflate(16.0D, 4.0D, 16.0D)); diff --git a/src/main/java/net/minecraft/world/entity/monster/Ghast.java b/src/main/java/net/minecraft/world/entity/monster/Ghast.java -index c135bc245f59a1af706f98b9d140dee77016b12f..640f0c378a18cf0a820ad544bb3b172b698c6bfc 100644 +index 373a4f036157017b0d95e8f1849780582235a549..a25c82be45e3db5143f6bf617fedc2fa85bd89ca 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Ghast.java +++ b/src/main/java/net/minecraft/world/entity/monster/Ghast.java -@@ -45,11 +45,47 @@ public class Ghast extends FlyingMob implements Enemy { +@@ -43,11 +43,47 @@ public class Ghast extends FlyingMob implements Enemy { this.moveControl = new Ghast.GhastMoveControl(this); } @@ -12160,7 +11710,7 @@ index c135bc245f59a1af706f98b9d140dee77016b12f..640f0c378a18cf0a820ad544bb3b172b this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entityliving) -> { return Math.abs(entityliving.getY() - this.getY()) <= 4.0D; })); -@@ -97,6 +133,21 @@ public class Ghast extends FlyingMob implements Enemy { +@@ -95,6 +131,21 @@ public class Ghast extends FlyingMob implements Enemy { } } @@ -12180,9 +11730,9 @@ index c135bc245f59a1af706f98b9d140dee77016b12f..640f0c378a18cf0a820ad544bb3b172b + } + @Override - protected void defineSynchedData() { - super.defineSynchedData(); -@@ -104,7 +155,7 @@ public class Ghast extends FlyingMob implements Enemy { + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +@@ -102,7 +153,7 @@ public class Ghast extends FlyingMob implements Enemy { } public static AttributeSupplier.Builder createAttributes() { @@ -12191,8 +11741,8 @@ index c135bc245f59a1af706f98b9d140dee77016b12f..640f0c378a18cf0a820ad544bb3b172b } @Override -@@ -171,7 +222,7 @@ public class Ghast extends FlyingMob implements Enemy { - return 2.6F; +@@ -154,7 +205,7 @@ public class Ghast extends FlyingMob implements Enemy { + } - private static class GhastMoveControl extends MoveControl { @@ -12200,7 +11750,7 @@ index c135bc245f59a1af706f98b9d140dee77016b12f..640f0c378a18cf0a820ad544bb3b172b private final Ghast ghast; private int floatDuration; -@@ -182,7 +233,7 @@ public class Ghast extends FlyingMob implements Enemy { +@@ -165,7 +216,7 @@ public class Ghast extends FlyingMob implements Enemy { } @Override @@ -12210,22 +11760,19 @@ index c135bc245f59a1af706f98b9d140dee77016b12f..640f0c378a18cf0a820ad544bb3b172b if (this.floatDuration-- <= 0) { this.floatDuration += this.ghast.getRandom().nextInt(5) + 2; diff --git a/src/main/java/net/minecraft/world/entity/monster/Giant.java b/src/main/java/net/minecraft/world/entity/monster/Giant.java -index a329395dd8ff2d5428de19018111373806fc8796..20d6fd08cc7b5964f74b7dd99ee117ac30273426 100644 +index 118521ae54254b0a73bb7cba7b2871c9c26f89fc..5c2881d0be519c52cbba74d7b7ca3ea9b4536463 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Giant.java +++ b/src/main/java/net/minecraft/world/entity/monster/Giant.java -@@ -1,18 +1,123 @@ +@@ -1,23 +1,128 @@ package net.minecraft.world.entity.monster; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.Difficulty; +import net.minecraft.world.DifficultyInstance; - import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.MobSpawnType; - import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; @@ -12252,9 +11799,8 @@ index a329395dd8ff2d5428de19018111373806fc8796..20d6fd08cc7b5964f74b7dd99ee117ac public class Giant extends Monster { public Giant(EntityType type, Level world) { super(type, world); -+ this.safeFallDistance = 10.0F; // Purpur -+ } -+ + } + + // Purpur start + @Override + public boolean isRidable() { @@ -12301,7 +11847,6 @@ index a329395dd8ff2d5428de19018111373806fc8796..20d6fd08cc7b5964f74b7dd99ee117ac + protected boolean isAlwaysExperienceDropper() { + return this.level().purpurConfig.giantAlwaysDropExp; + } -+ // Purpur end + + @Override + protected void initAttributes() { @@ -12310,9 +11855,15 @@ index a329395dd8ff2d5428de19018111373806fc8796..20d6fd08cc7b5964f74b7dd99ee117ac + this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.giantAttackDamage); + } + ++ // Purpur end ++ + 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); + } + + @Override -+ public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { -+ SpawnGroupData groupData = super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); ++ public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { ++ SpawnGroupData groupData = super.finalizeSpawn(world, difficulty, spawnReason, entityData); + if (groupData == null) { + populateDefaultEquipmentSlots(this.random, difficulty); + populateDefaultEquipmentEnchantments(this.random, difficulty); @@ -12334,11 +11885,8 @@ index a329395dd8ff2d5428de19018111373806fc8796..20d6fd08cc7b5964f74b7dd99ee117ac + // make giants jump as high as everything else relative to their size + // 1.0 makes bottom of feet about as high as their waist when they jump + return level().purpurConfig.giantJumpHeight; - } - - @Override -@@ -31,6 +136,6 @@ public class Giant extends Monster { - ++ } ++ @Override public float getWalkTargetValue(BlockPos pos, LevelReader world) { - return world.getPathfindingCostFromLightLevels(pos); @@ -12346,12 +11894,12 @@ index a329395dd8ff2d5428de19018111373806fc8796..20d6fd08cc7b5964f74b7dd99ee117ac } } diff --git a/src/main/java/net/minecraft/world/entity/monster/Guardian.java b/src/main/java/net/minecraft/world/entity/monster/Guardian.java -index fd41ef66e2e12ec3a888bb376ef4363343914fcd..01c558673f0bb5034bca9df0e473375e7b7e724e 100644 +index 6c2e2fd5826a5f8070502e20d1d140c3d70bd0d3..f9496126f75b4c1b89ec33617e577d83042e0290 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Guardian.java +++ b/src/main/java/net/minecraft/world/entity/monster/Guardian.java -@@ -70,15 +70,51 @@ public class Guardian extends Monster { +@@ -66,15 +66,51 @@ public class Guardian extends Monster { this.xpReward = 10; - this.setPathfindingMalus(BlockPathTypes.WATER, 0.0F); + this.setPathfindingMalus(PathType.WATER, 0.0F); this.moveControl = new Guardian.GuardianMoveControl(this); + // Purpur start + this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) { @@ -12401,7 +11949,7 @@ index fd41ef66e2e12ec3a888bb376ef4363343914fcd..01c558673f0bb5034bca9df0e473375e this.goalSelector.addGoal(4, this.guardianAttackGoal = new Guardian.GuardianAttackGoal(this)); // CraftBukkit - assign field this.goalSelector.addGoal(5, pathfindergoalmovetowardsrestriction); this.goalSelector.addGoal(7, this.randomStrollGoal); -@@ -87,6 +123,7 @@ public class Guardian extends Monster { +@@ -83,6 +119,7 @@ public class Guardian extends Monster { this.goalSelector.addGoal(9, new RandomLookAroundGoal(this)); this.randomStrollGoal.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); pathfindergoalmovetowardsrestriction.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); @@ -12409,7 +11957,7 @@ index fd41ef66e2e12ec3a888bb376ef4363343914fcd..01c558673f0bb5034bca9df0e473375e this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 10, true, false, new Guardian.GuardianAttackSelector(this))); } -@@ -347,7 +384,7 @@ public class Guardian extends Monster { +@@ -333,7 +370,7 @@ public class Guardian extends Monster { @Override public void travel(Vec3 movementInput) { if (this.isControlledByLocalInstance() && this.isInWater()) { @@ -12418,8 +11966,8 @@ index fd41ef66e2e12ec3a888bb376ef4363343914fcd..01c558673f0bb5034bca9df0e473375e this.move(MoverType.SELF, this.getDeltaMovement()); this.setDeltaMovement(this.getDeltaMovement().scale(0.9D)); if (!this.isMoving() && this.getTarget() == null) { -@@ -364,7 +401,7 @@ public class Guardian extends Monster { - return new Vector3f(0.0F, dimensions.height + 0.125F * scaleFactor, 0.0F); +@@ -345,7 +382,7 @@ public class Guardian extends Monster { + } - private static class GuardianMoveControl extends MoveControl { @@ -12427,7 +11975,7 @@ index fd41ef66e2e12ec3a888bb376ef4363343914fcd..01c558673f0bb5034bca9df0e473375e private final Guardian guardian; -@@ -373,8 +410,17 @@ public class Guardian extends Monster { +@@ -354,8 +391,17 @@ public class Guardian extends Monster { this.guardian = guardian; } @@ -12446,7 +11994,7 @@ index fd41ef66e2e12ec3a888bb376ef4363343914fcd..01c558673f0bb5034bca9df0e473375e if (this.operation == MoveControl.Operation.MOVE_TO && !this.guardian.getNavigation().isDone()) { Vec3 vec3d = new Vec3(this.wantedX - this.guardian.getX(), this.wantedY - this.guardian.getY(), this.wantedZ - this.guardian.getZ()); double d0 = vec3d.length(); -@@ -385,7 +431,7 @@ public class Guardian extends Monster { +@@ -366,7 +412,7 @@ public class Guardian extends Monster { this.guardian.setYRot(this.rotlerp(this.guardian.getYRot(), f, 90.0F)); this.guardian.yBodyRot = this.guardian.getYRot(); @@ -12456,10 +12004,10 @@ index fd41ef66e2e12ec3a888bb376ef4363343914fcd..01c558673f0bb5034bca9df0e473375e this.guardian.setSpeed(f2); diff --git a/src/main/java/net/minecraft/world/entity/monster/Husk.java b/src/main/java/net/minecraft/world/entity/monster/Husk.java -index 72b8290bebe8ed9bc3c464b30cfe5d2d664310f5..06a5106a94a44c1d21537410d801cdd945503d69 100644 +index c34c8483a026f61fe20935697d321d7ef5d8dfbc..95d3edc6c88d6ed0556c21c2623cdd5cfda35911 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Husk.java +++ b/src/main/java/net/minecraft/world/entity/monster/Husk.java -@@ -22,6 +22,59 @@ public class Husk extends Zombie { +@@ -20,6 +20,59 @@ public class Husk extends Zombie { public Husk(EntityType type, Level world) { super(type, world); @@ -12519,7 +12067,7 @@ index 72b8290bebe8ed9bc3c464b30cfe5d2d664310f5..06a5106a94a44c1d21537410d801cdd9 } public static boolean checkHuskSpawnRules(EntityType type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { -@@ -30,7 +83,7 @@ public class Husk extends Zombie { +@@ -28,7 +81,7 @@ public class Husk extends Zombie { @Override public boolean isSunSensitive() { @@ -12529,10 +12077,10 @@ index 72b8290bebe8ed9bc3c464b30cfe5d2d664310f5..06a5106a94a44c1d21537410d801cdd9 @Override diff --git a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -index fb84b35e34063075e69e00e430bc00e7c3b9d62c..a8b3431c67442c5440b063426a1adc423f5c0658 100644 +index a7964208c952cb4e34916ae6523850fc3921b07e..ae036a16e3677dfba451f4eb4505036d45e50cf3 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java +++ b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -@@ -59,10 +59,45 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { +@@ -56,10 +56,45 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { } @@ -12578,7 +12126,7 @@ index fb84b35e34063075e69e00e430bc00e7c3b9d62c..a8b3431c67442c5440b063426a1adc42 this.goalSelector.addGoal(1, new SpellcasterIllager.SpellcasterCastingSpellGoal()); this.goalSelector.addGoal(4, new Illusioner.IllusionerMirrorSpellGoal()); this.goalSelector.addGoal(5, new Illusioner.IllusionerBlindnessSpellGoal()); -@@ -70,6 +105,7 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { +@@ -67,6 +102,7 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D)); this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); @@ -12587,10 +12135,10 @@ index fb84b35e34063075e69e00e430bc00e7c3b9d62c..a8b3431c67442c5440b063426a1adc42 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/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -index c4b4ff79bfdf9e34bf73a7760369e24b28dbbd70..1bfd5ef9ce8a07375ff215d092368c3f5104ab13 100644 +index 7be2393dc3cb79556d9767b09f43be0f81308a12..e7c79e8c72226285eb5a4763dcf8ddd27078539c 100644 --- a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java +++ b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -@@ -25,6 +25,58 @@ public class MagmaCube extends Slime { +@@ -24,6 +24,58 @@ public class MagmaCube extends Slime { super(type, world); } @@ -12649,7 +12197,7 @@ index c4b4ff79bfdf9e34bf73a7760369e24b28dbbd70..1bfd5ef9ce8a07375ff215d092368c3f public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); } -@@ -70,11 +122,12 @@ public class MagmaCube extends Slime { +@@ -64,11 +116,12 @@ public class MagmaCube extends Slime { } @Override @@ -12683,10 +12231,10 @@ index 759839e912c54598b257ad738481364940f88a18..e60e6b3e5ae5a468cfe649ed2222412f return false; } else { diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75f65aa66b 100644 +index 68f8945292753535a3b73acb9f48c1594f0789a4..26077bd6eeedbdae84613188cb0f336abb3563d2 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java +++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -50,6 +50,8 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -48,6 +48,8 @@ public class Phantom extends FlyingMob implements Enemy { Vec3 moveTargetPoint; public BlockPos anchorPoint; Phantom.AttackPhase attackPhase; @@ -12695,10 +12243,10 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 public Phantom(EntityType type, Level world) { super(type, world); -@@ -59,6 +61,92 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -57,6 +59,92 @@ public class Phantom extends FlyingMob implements Enemy { this.xpReward = 5; this.moveControl = new Phantom.PhantomMoveControl(this); - this.lookControl = new Phantom.PhantomLookControl(this); + this.lookControl = new Phantom.PhantomLookControl(this, this); + this.setShouldBurnInDay(true); // Purpur + } + @@ -12788,7 +12336,7 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 } @Override -@@ -73,9 +161,17 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -71,9 +159,17 @@ public class Phantom extends FlyingMob implements Enemy { @Override protected void registerGoals() { @@ -12809,7 +12357,7 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal()); } -@@ -91,7 +187,10 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -89,7 +185,10 @@ public class Phantom extends FlyingMob implements Enemy { private void updatePhantomSizeInfo() { this.refreshDimensions(); @@ -12821,7 +12369,7 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 } public int getPhantomSize() { -@@ -121,6 +220,21 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -114,6 +213,21 @@ public class Phantom extends FlyingMob implements Enemy { return true; } @@ -12843,8 +12391,8 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 @Override public void tick() { super.tick(); -@@ -141,14 +255,12 @@ public class Phantom extends FlyingMob implements Enemy { - this.level().addParticle(ParticleTypes.MYCELIUM, this.getX() - (double) f2, this.getY() + (double) f4, this.getZ() - (double) f3, 0.0D, 0.0D, 0.0D); +@@ -134,14 +248,12 @@ public class Phantom extends FlyingMob implements Enemy { + this.level().addParticle(ParticleTypes.MYCELIUM, this.getX() - (double) f3, this.getY() + (double) f5, this.getZ() - (double) f4, 0.0D, 0.0D, 0.0D); } + if (level().purpurConfig.phantomFlamesOnSwoop && attackPhase == AttackPhase.SWOOP) shoot(); // Purpur @@ -12852,17 +12400,17 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 @Override public void aiStep() { -- if (this.isAlive() && shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API -- this.setSecondsOnFire(8); +- if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API +- this.igniteForSeconds(8); - } - + // Purpur - moved down to shouldBurnInDay() super.aiStep(); } -@@ -160,7 +272,11 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -153,7 +265,11 @@ public class Phantom extends FlyingMob implements Enemy { @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { this.anchorPoint = this.blockPosition().above(5); - this.setPhantomSize(0); + // Purpur start @@ -12870,10 +12418,10 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 + int max = world.getLevel().purpurConfig.phantomMaxSize; + this.setPhantomSize(min == max ? min : world.getRandom().nextInt(max + 1 - min) + min); + // Purpur end - return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } -@@ -176,7 +292,7 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -169,7 +285,7 @@ public class Phantom extends FlyingMob implements Enemy { if (nbt.hasUUID("Paper.SpawningEntity")) { this.spawningEntity = nbt.getUUID("Paper.SpawningEntity"); } @@ -12882,7 +12430,7 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); } // Paper end -@@ -193,7 +309,7 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -186,7 +302,7 @@ public class Phantom extends FlyingMob implements Enemy { if (this.spawningEntity != null) { nbt.putUUID("Paper.SpawningEntity", this.spawningEntity); } @@ -12891,8 +12439,8 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 // Paper end } -@@ -262,8 +378,15 @@ public class Phantom extends FlyingMob implements Enemy { - return spawningEntity; +@@ -242,8 +358,15 @@ public class Phantom extends FlyingMob implements Enemy { + return this.spawningEntity; } public void setSpawningEntity(java.util.UUID entity) { this.spawningEntity = entity; } - private boolean shouldBurnInDay = true; @@ -12908,8 +12456,8 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 + // Purpur End public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } // Paper end - private static enum AttackPhase { -@@ -273,7 +396,125 @@ public class Phantom extends FlyingMob implements Enemy { + +@@ -254,7 +377,125 @@ public class Phantom extends FlyingMob implements Enemy { private AttackPhase() {} } @@ -13036,7 +12584,7 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 private float speed = 0.1F; -@@ -281,8 +522,19 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -262,8 +503,19 @@ public class Phantom extends FlyingMob implements Enemy { super(entity); } @@ -13057,15 +12605,15 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 if (Phantom.this.horizontalCollision) { Phantom.this.setYRot(Phantom.this.getYRot() + 180.0F); this.speed = 0.1F; -@@ -328,14 +580,20 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -309,14 +561,20 @@ public class Phantom extends FlyingMob implements Enemy { } } - private class PhantomLookControl extends LookControl { + private class PhantomLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - public PhantomLookControl(Mob entity) { - super(entity); + public PhantomLookControl(final Phantom entity, final Mob phantom) { + super(phantom); } + // Purpur start @@ -13080,7 +12628,7 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 } private class PhantomBodyRotationControl extends BodyRotationControl { -@@ -422,6 +680,12 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -403,6 +661,12 @@ public class Phantom extends FlyingMob implements Enemy { return false; } else if (!entityliving.isAlive()) { return false; @@ -13093,7 +12641,7 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 } else { if (entityliving instanceof Player) { Player entityhuman = (Player) entityliving; -@@ -567,6 +831,7 @@ public class Phantom extends FlyingMob implements Enemy { +@@ -548,6 +812,7 @@ public class Phantom extends FlyingMob implements Enemy { this.nextScanTick = reducedTickDelay(60); List list = Phantom.this.level().getNearbyPlayers(this.attackTargeting, Phantom.this, Phantom.this.getBoundingBox().inflate(16.0D, 64.0D, 16.0D)); @@ -13102,10 +12650,10 @@ index 187037c43ebb5b245ffa4b50163d443490668744..44a24707530ca46a6a42e8a4d9049e75 list.sort(Comparator.comparing((Entity e) -> { return e.getY(); }).reversed()); // CraftBukkit - decompile error Iterator iterator = list.iterator(); diff --git a/src/main/java/net/minecraft/world/entity/monster/Pillager.java b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -index 05ed2f06a41f3b12e0432a37faf98d0b1fea7a8b..d5becd13774f9a2ead77d58e777ffc9aea10cb60 100644 +index ac411202c0029052a962b51b015da191b124de5f..ae3eb87af8d3853be82c2002507141e43ab644de 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Pillager.java +++ b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -@@ -66,15 +66,49 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve +@@ -58,15 +58,49 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve super(type, world); } @@ -13146,7 +12694,7 @@ index 05ed2f06a41f3b12e0432a37faf98d0b1fea7a8b..d5becd13774f9a2ead77d58e777ffc9a super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F)); + this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F)); // Paper - decomp fix this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0D, 8.0F)); this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D)); this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 15.0F, 1.0F)); @@ -13156,11 +12704,11 @@ index 05ed2f06a41f3b12e0432a37faf98d0b1fea7a8b..d5becd13774f9a2ead77d58e777ffc9a this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -index 151acc43c96b4545ce92d3d559d8e1591874b4b5..2d834e57253f666f04f8e0b47c8b8a45458c0a75 100644 +index 2d7b7c949faaaaae94c0043132a4a822f55df104..9551bd7c9bed37cf17910e7f71b82ed20fb2d759 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java +++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -71,14 +71,54 @@ public class Ravager extends Raider { - this.setPathfindingMalus(BlockPathTypes.LEAVES, 0.0F); +@@ -68,14 +68,54 @@ public class Ravager extends Raider { + this.setPathfindingMalus(PathType.LEAVES, 0.0F); } + // Purpur start @@ -13214,7 +12762,7 @@ index 151acc43c96b4545ce92d3d559d8e1591874b4b5..2d834e57253f666f04f8e0b47c8b8a45 this.targetSelector.addGoal(2, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers()); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true, (entityliving) -> { -@@ -136,7 +176,7 @@ public class Ravager extends Raider { +@@ -128,7 +168,7 @@ public class Ravager extends Raider { @Override public void aiStep() { super.aiStep(); @@ -13223,7 +12771,7 @@ index 151acc43c96b4545ce92d3d559d8e1591874b4b5..2d834e57253f666f04f8e0b47c8b8a45 if (this.isImmobile()) { this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.0D); } else { -@@ -146,7 +186,7 @@ public class Ravager extends Raider { +@@ -138,7 +178,7 @@ public class Ravager extends Raider { this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(Mth.lerp(0.1D, d1, d0)); } @@ -13232,7 +12780,7 @@ index 151acc43c96b4545ce92d3d559d8e1591874b4b5..2d834e57253f666f04f8e0b47c8b8a45 boolean flag = false; AABB axisalignedbb = this.getBoundingBox().inflate(0.2D); Iterator iterator = BlockPos.betweenClosed(Mth.floor(axisalignedbb.minX), Mth.floor(axisalignedbb.minY), Mth.floor(axisalignedbb.minZ), Mth.floor(axisalignedbb.maxX), Mth.floor(axisalignedbb.maxY), Mth.floor(axisalignedbb.maxZ)).iterator(); -@@ -156,7 +196,7 @@ public class Ravager extends Raider { +@@ -148,7 +188,7 @@ public class Ravager extends Raider { BlockState iblockdata = this.level().getBlockState(blockposition); Block block = iblockdata.getBlock(); @@ -13242,10 +12790,10 @@ index 151acc43c96b4545ce92d3d559d8e1591874b4b5..2d834e57253f666f04f8e0b47c8b8a45 if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state continue; diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -index f3c2a2ffb74daa89a516db4c188ce675c79932bf..ab21a44905a4154013cd65acdecbf55b741da086 100644 +index 5215fa54666979ef4da074ddfdb082e7274f2957..1afa6dc4f2a6437cd4cc3e49694e79641fcc13ad 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java +++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -@@ -22,6 +22,8 @@ import net.minecraft.tags.DamageTypeTags; +@@ -23,6 +23,8 @@ import net.minecraft.tags.DamageTypeTags; import net.minecraft.util.Mth; import net.minecraft.world.Difficulty; import net.minecraft.world.DifficultyInstance; @@ -13253,8 +12801,8 @@ index f3c2a2ffb74daa89a516db4c188ce675c79932bf..ab21a44905a4154013cd65acdecbf55b +import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntityDimensions; -@@ -49,6 +51,8 @@ import net.minecraft.world.entity.player.Player; + import net.minecraft.world.entity.EntitySelector; +@@ -48,6 +50,8 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.AbstractArrow; import net.minecraft.world.entity.projectile.ShulkerBullet; import net.minecraft.world.item.DyeColor; @@ -13323,7 +12871,7 @@ index f3c2a2ffb74daa89a516db4c188ce675c79932bf..ab21a44905a4154013cd65acdecbf55b this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{this.getClass()})).setAlertOthers()); this.targetSelector.addGoal(2, new Shulker.ShulkerNearestAttackGoal(this)); this.targetSelector.addGoal(3, new Shulker.ShulkerDefenseAttackGoal(this)); -@@ -474,12 +525,21 @@ public class Shulker extends AbstractGolem implements VariantHolder getVariant() { @@ -13359,20 +12907,20 @@ index f3c2a2ffb74daa89a516db4c188ce675c79932bf..ab21a44905a4154013cd65acdecbf55b } @Nullable -@@ -601,7 +661,7 @@ public class Shulker extends AbstractGolem implements VariantHolder(this, Player.class, true)); } -@@ -187,7 +221,7 @@ public class Silverfish extends Monster { +@@ -167,7 +201,7 @@ public class Silverfish extends Monster { continue; } // CraftBukkit end @@ -13430,7 +12978,7 @@ index fcd5cc3ff8d4b38f4dea08f78723db3dac53ffde..931412a5ab315d4080a9f5209d3e85d7 world.destroyBlock(blockposition1, true, this.silverfish); } else { world.setBlock(blockposition1, ((InfestedBlock) block).hostStateByInfested(world.getBlockState(blockposition1)), 3); -@@ -225,7 +259,7 @@ public class Silverfish extends Monster { +@@ -205,7 +239,7 @@ public class Silverfish extends Monster { } else { RandomSource randomsource = this.mob.getRandom(); @@ -13440,7 +12988,7 @@ index fcd5cc3ff8d4b38f4dea08f78723db3dac53ffde..931412a5ab315d4080a9f5209d3e85d7 BlockPos blockposition = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5D, this.mob.getZ()).relative(this.selectedDirection); BlockState iblockdata = this.mob.level().getBlockState(blockposition); diff --git a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -index 92974452d8f63fde8524cfac305ee2ef5212f840..30ff77f5f137614b5d0d2df6dc90f47c97e8ab13 100644 +index 5642bddc8268d70e5bb5446b65be1d8ce34feb9b..9eb6ed001bfc578311300977dda6f3f156d07190 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java +++ b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java @@ -14,6 +14,16 @@ import net.minecraft.world.item.Items; @@ -13460,7 +13008,7 @@ index 92974452d8f63fde8524cfac305ee2ef5212f840..30ff77f5f137614b5d0d2df6dc90f47c public class Skeleton extends AbstractSkeleton { private static final int TOTAL_CONVERSION_TIME = 300; -@@ -26,6 +36,38 @@ public class Skeleton extends AbstractSkeleton { +@@ -26,6 +36,40 @@ public class Skeleton extends AbstractSkeleton { super(type, world); } @@ -13486,10 +13034,12 @@ index 92974452d8f63fde8524cfac305ee2ef5212f840..30ff77f5f137614b5d0d2df6dc90f47c + this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.skeletonMaxHealth); + } + ++ // Purpur start + @Override + public boolean isSensitiveToWater() { + return this.level().purpurConfig.skeletonTakeDamageFromWater; + } ++ // Purpur end + + @Override + protected boolean isAlwaysExperienceDropper() { @@ -13497,9 +13047,9 @@ index 92974452d8f63fde8524cfac305ee2ef5212f840..30ff77f5f137614b5d0d2df6dc90f47c + } + @Override - protected void defineSynchedData() { - super.defineSynchedData(); -@@ -142,4 +184,67 @@ public class Skeleton extends AbstractSkeleton { + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +@@ -140,4 +184,67 @@ public class Skeleton extends AbstractSkeleton { } } @@ -13568,10 +13118,10 @@ index 92974452d8f63fde8524cfac305ee2ef5212f840..30ff77f5f137614b5d0d2df6dc90f47c + // Purpur end } diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java -index 3d9107d2c19a09215445aa0e0aacc32f9f82a536..0f77f00e9a02d1f982f285617604e7291b70a2a4 100644 +index f223e78eb1204bbf5f2de38a7ce5b663800f7dc4..ccf7fea215d3096e76db294daa5874fec00147ca 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Slime.java +++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java -@@ -62,6 +62,7 @@ public class Slime extends Mob implements Enemy { +@@ -61,6 +61,7 @@ public class Slime extends Mob implements Enemy { public float squish; public float oSquish; private boolean wasOnGround; @@ -13579,7 +13129,7 @@ index 3d9107d2c19a09215445aa0e0aacc32f9f82a536..0f77f00e9a02d1f982f285617604e729 public Slime(EntityType type, Level world) { super(type, world); -@@ -69,12 +70,89 @@ public class Slime extends Mob implements Enemy { +@@ -68,12 +69,89 @@ public class Slime extends Mob implements Enemy { this.moveControl = new Slime.SlimeMoveControl(this); } @@ -13669,7 +13219,7 @@ index 3d9107d2c19a09215445aa0e0aacc32f9f82a536..0f77f00e9a02d1f982f285617604e729 this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entityliving) -> { return Math.abs(entityliving.getY() - this.getY()) <= 4.0D; })); -@@ -99,9 +177,9 @@ public class Slime extends Mob implements Enemy { +@@ -98,9 +176,9 @@ public class Slime extends Mob implements Enemy { this.entityData.set(Slime.ID_SIZE, j); this.reapplyPosition(); this.refreshDimensions(); @@ -13681,7 +13231,7 @@ index 3d9107d2c19a09215445aa0e0aacc32f9f82a536..0f77f00e9a02d1f982f285617604e729 if (heal) { this.setHealth(this.getMaxHealth()); } -@@ -386,11 +464,12 @@ public class Slime extends Mob implements Enemy { +@@ -382,11 +460,12 @@ public class Slime extends Mob implements Enemy { } @Override @@ -13695,8 +13245,8 @@ index 3d9107d2c19a09215445aa0e0aacc32f9f82a536..0f77f00e9a02d1f982f285617604e729 } @Nullable -@@ -424,7 +503,7 @@ public class Slime extends Mob implements Enemy { - return super.getDimensions(pose).scale(0.255F * (float) this.getSize()); +@@ -420,7 +499,7 @@ public class Slime extends Mob implements Enemy { + return super.getDefaultDimensions(pose).scale((float) this.getSize()); } - private static class SlimeMoveControl extends MoveControl { @@ -13704,7 +13254,7 @@ index 3d9107d2c19a09215445aa0e0aacc32f9f82a536..0f77f00e9a02d1f982f285617604e729 private float yRot; private int jumpDelay; -@@ -443,21 +522,33 @@ public class Slime extends Mob implements Enemy { +@@ -439,21 +518,33 @@ public class Slime extends Mob implements Enemy { } public void setWantedMovement(double speed) { @@ -13741,7 +13291,7 @@ index 3d9107d2c19a09215445aa0e0aacc32f9f82a536..0f77f00e9a02d1f982f285617604e729 if (this.jumpDelay-- <= 0) { this.jumpDelay = this.slime.getJumpDelay(); if (this.isAggressive) { -@@ -474,7 +565,7 @@ public class Slime extends Mob implements Enemy { +@@ -470,7 +561,7 @@ public class Slime extends Mob implements Enemy { this.mob.setSpeed(0.0F); } } else { @@ -13751,10 +13301,10 @@ index 3d9107d2c19a09215445aa0e0aacc32f9f82a536..0f77f00e9a02d1f982f285617604e729 } diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java -index 7618364e5373fe17cfe45a5a4ee9ab25e591581c..b44ffeb4cc0ef63fdd25683f60c5a20fcdeb9135 100644 +index fa0316e9d2a4cf213982994dc8bf310299cca984..159740069aba59bffff444d933af32aaf752ba48 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Spider.java +++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java -@@ -53,14 +53,48 @@ public class Spider extends Monster { +@@ -51,9 +51,42 @@ public class Spider extends Monster { super(type, world); } @@ -13794,8 +13344,10 @@ index 7618364e5373fe17cfe45a5a4ee9ab25e591581c..b44ffeb4cc0ef63fdd25683f60c5a20f protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4F)); - this.goalSelector.addGoal(4, new Spider.SpiderAttackGoal(this)); + this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Armadillo.class, 6.0F, 1.0D, 1.2D, (entityliving) -> { + return !((Armadillo) entityliving).isScared(); + })); +@@ -62,6 +95,7 @@ public class Spider extends Monster { this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8D)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); @@ -13847,18 +13399,18 @@ index 207a649d737adff440bd3f7cba15b0dbca338a35..18c0cf991c2e8418d7fdd4c8dbd7487a BlockPos blockPos = pos; diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java -index 61162ecd43dc5e6f7898daecdec49f444e6d869b..2f49b528601a1feb7246fe7a9b83ce828c2d78fc 100644 +index fe85900a610afd0b237d8b5a164181c03afbdfc7..5ea5bf9c0e11b0e1f9fe50093899c6e35ee6cf4f 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Strider.java +++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java -@@ -94,12 +94,44 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { +@@ -91,12 +91,44 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { super(type, world); this.steering = new ItemBasedSteering(this.entityData, Strider.DATA_BOOST_TIME, Strider.DATA_SADDLE_ID); this.blocksBuilding = true; -- this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); -+ if (isSensitiveToWater()) this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); // Purpur - this.setPathfindingMalus(BlockPathTypes.LAVA, 0.0F); - this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 0.0F); - this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, 0.0F); +- this.setPathfindingMalus(PathType.WATER, -1.0F); ++ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur + this.setPathfindingMalus(PathType.LAVA, 0.0F); + this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); + this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); } + // Purpur start @@ -13896,14 +13448,14 @@ index 61162ecd43dc5e6f7898daecdec49f444e6d869b..2f49b528601a1feb7246fe7a9b83ce82 public static boolean checkStriderSpawnRules(EntityType type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); -@@ -161,6 +193,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { +@@ -158,6 +190,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { @Override protected void registerGoals() { this.goalSelector.addGoal(1, new PanicGoal(this, 1.65D)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); - this.temptGoal = new TemptGoal(this, 1.4D, Strider.TEMPT_ITEMS, false); - this.goalSelector.addGoal(3, this.temptGoal); + this.temptGoal = new TemptGoal(this, 1.4D, (itemstack) -> { + return itemstack.is(ItemTags.STRIDER_TEMPT_ITEMS); @@ -414,7 +447,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { @Override @@ -13943,10 +13495,10 @@ index 61162ecd43dc5e6f7898daecdec49f444e6d869b..2f49b528601a1feb7246fe7a9b83ce82 if (flag && !this.isSilent()) { this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.STRIDER_EAT, this.getSoundSource(), 1.0F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F); diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java -index f443006c1e32feee97b32312814e2447a50c45e2..834abf1160034543fe3e89fa1c8d4bb55ffc5dc1 100644 +index fd3b37dde54623ba38186efb2a64d364c86b81d2..691f319719280f873140df7d93c821417e32e8f7 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Vex.java +++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java -@@ -63,6 +63,65 @@ public class Vex extends Monster implements TraceableEntity { +@@ -60,6 +60,65 @@ public class Vex extends Monster implements TraceableEntity { this.xpReward = 3; } @@ -13992,7 +13544,6 @@ index f443006c1e32feee97b32312814e2447a50c45e2..834abf1160034543fe3e89fa1c8d4bb5 + public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) { + return false; // no fall damage please + } -+ // Purpur end + + @Override + public void initAttributes() { @@ -14008,11 +13559,12 @@ index f443006c1e32feee97b32312814e2447a50c45e2..834abf1160034543fe3e89fa1c8d4bb5 + protected boolean isAlwaysExperienceDropper() { + return this.level().purpurConfig.vexAlwaysDropExp; + } ++ // Purpur end + @Override - protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { - return dimensions.height - 0.28125F; -@@ -81,7 +140,7 @@ public class Vex extends Monster implements TraceableEntity { + public boolean isFlapping() { + return this.tickCount % Vex.TICKS_PER_FLAP == 0; +@@ -73,7 +132,7 @@ public class Vex extends Monster implements TraceableEntity { @Override public void tick() { @@ -14021,7 +13573,7 @@ index f443006c1e32feee97b32312814e2447a50c45e2..834abf1160034543fe3e89fa1c8d4bb5 super.tick(); this.noPhysics = false; this.setNoGravity(true); -@@ -96,17 +155,19 @@ public class Vex extends Monster implements TraceableEntity { +@@ -88,17 +147,19 @@ public class Vex extends Monster implements TraceableEntity { protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); @@ -14042,14 +13594,14 @@ index f443006c1e32feee97b32312814e2447a50c45e2..834abf1160034543fe3e89fa1c8d4bb5 } @Override -@@ -251,14 +312,14 @@ public class Vex extends Monster implements TraceableEntity { - return new Vector3f(0.0F, dimensions.height - 0.0625F * scaleFactor, 0.0F); +@@ -230,14 +291,14 @@ public class Vex extends Monster implements TraceableEntity { + this.setDropChance(EquipmentSlot.MAINHAND, 0.0F); } - private class VexMoveControl extends MoveControl { + private class VexMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - public VexMoveControl(Vex entityvex) { + public VexMoveControl(final Vex entityvex) { super(entityvex); } @@ -14059,7 +13611,7 @@ index f443006c1e32feee97b32312814e2447a50c45e2..834abf1160034543fe3e89fa1c8d4bb5 if (this.operation == MoveControl.Operation.MOVE_TO) { Vec3 vec3d = new Vec3(this.wantedX - Vex.this.getX(), this.wantedY - Vex.this.getY(), this.wantedZ - Vex.this.getZ()); double d0 = vec3d.length(); -@@ -267,7 +328,7 @@ public class Vex extends Monster implements TraceableEntity { +@@ -246,7 +307,7 @@ public class Vex extends Monster implements TraceableEntity { this.operation = MoveControl.Operation.WAIT; Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().scale(0.5D)); } else { @@ -14069,10 +13621,10 @@ index f443006c1e32feee97b32312814e2447a50c45e2..834abf1160034543fe3e89fa1c8d4bb5 Vec3 vec3d1 = Vex.this.getDeltaMovement(); diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -index 0ee020848cdfd0c069f1e8d3a9516a339d82467c..960b5e2c290f82501384f79d4653f47bedf926fb 100644 +index b3da310d6fd1d533da805c38c2f449cf06d01492..e7703aa5467e7551bff06fab4c11d76237bda2e0 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java +++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -@@ -56,14 +56,48 @@ public class Vindicator extends AbstractIllager { +@@ -50,14 +50,48 @@ public class Vindicator extends AbstractIllager { super(type, world); } @@ -14121,7 +13673,7 @@ index 0ee020848cdfd0c069f1e8d3a9516a339d82467c..960b5e2c290f82501384f79d4653f47b 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)); -@@ -136,6 +170,12 @@ public class Vindicator extends AbstractIllager { +@@ -124,6 +158,12 @@ public class Vindicator extends AbstractIllager { RandomSource randomSource = world.getRandom(); this.populateDefaultEquipmentSlots(randomSource, difficulty); this.populateDefaultEquipmentEnchantments(randomSource, difficulty); @@ -14135,10 +13687,10 @@ index 0ee020848cdfd0c069f1e8d3a9516a339d82467c..960b5e2c290f82501384f79d4653f47b } diff --git a/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java -index f9ffc5f4cbfdcf5c7351a883d2e5c26492175283..4af36f8d0647f881a842e248d02d747115e1cc70 100644 +index 5803c1d36b769f0186baa0665976749765b4cb61..b4aab57b9aaab2ed1322ca41d4bf3c60f155902c 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Witch.java +++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java -@@ -59,6 +59,38 @@ public class Witch extends Raider implements RangedAttackMob { +@@ -55,6 +55,38 @@ public class Witch extends Raider implements RangedAttackMob { super(type, world); } @@ -14177,7 +13729,7 @@ index f9ffc5f4cbfdcf5c7351a883d2e5c26492175283..4af36f8d0647f881a842e248d02d7471 @Override protected void registerGoals() { super.registerGoals(); -@@ -67,10 +99,12 @@ public class Witch extends Raider implements RangedAttackMob { +@@ -63,10 +95,12 @@ public class Witch extends Raider implements RangedAttackMob { }); this.attackPlayersGoal = new NearestAttackableWitchTargetGoal<>(this, Player.class, 10, true, false, (Predicate) null); this.goalSelector.addGoal(1, new FloatGoal(this)); @@ -14191,11 +13743,11 @@ index f9ffc5f4cbfdcf5c7351a883d2e5c26492175283..4af36f8d0647f881a842e248d02d7471 this.targetSelector.addGoal(2, this.healRaidersGoal); this.targetSelector.addGoal(3, this.attackPlayersGoal); diff --git a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -index 20a65c11ededcd7170704b70118da6200151fbab..e97cb4e166c2e9ac6d93ed5b15350758326e7e74 100644 +index 3f1191795e58f31b7e2fe34ef2774df13b9a789f..8c62d39c54acf274200667ae30c517cd4416b22f 100644 --- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java +++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -@@ -35,6 +35,38 @@ public class WitherSkeleton extends AbstractSkeleton { - this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F); +@@ -32,6 +32,38 @@ public class WitherSkeleton extends AbstractSkeleton { + this.setPathfindingMalus(PathType.LAVA, 8.0F); } + // Purpur start @@ -14234,10 +13786,10 @@ index 20a65c11ededcd7170704b70118da6200151fbab..e97cb4e166c2e9ac6d93ed5b15350758 protected void registerGoals() { this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); diff --git a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -index 728f3dff42678ed48c8921ea0e960f48724a9183..abafb15ab1294e11810798795bd103fb8bd5f64a 100644 +index cfdb2b793f11544ec5e2d1e726134089994b2b0f..f9bb83f35a41e5b076ae438af613a97b8e60c0c3 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -@@ -82,6 +82,38 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { +@@ -80,6 +80,38 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { this.xpReward = 5; } @@ -14276,7 +13828,7 @@ index 728f3dff42678ed48c8921ea0e960f48724a9183..abafb15ab1294e11810798795bd103fb @Override protected Brain.Provider brainProvider() { return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); -@@ -241,9 +273,10 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { +@@ -234,9 +266,10 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { @Override protected void customServerAiStep() { @@ -14290,10 +13842,10 @@ index 728f3dff42678ed48c8921ea0e960f48724a9183..abafb15ab1294e11810798795bd103fb } diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50b80dbea5 100644 +index e42dfc62bb179be1ab01b0096c05c6549d38abbc..d48d22157a89f98c1bbabc70b0bb31187038176d 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java +++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -96,22 +96,69 @@ public class Zombie extends Monster { +@@ -93,22 +93,69 @@ public class Zombie extends Monster { private int inWaterTime; public int conversionTime; private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field @@ -14364,7 +13916,7 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 this.addBehaviourGoals(); } -@@ -121,7 +168,19 @@ public class Zombie extends Monster { +@@ -118,7 +165,19 @@ public class Zombie extends Monster { this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D)); this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers(ZombifiedPiglin.class)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); @@ -14385,7 +13937,7 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 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)); } -@@ -243,30 +302,7 @@ public class Zombie extends Monster { +@@ -240,30 +299,7 @@ public class Zombie extends Monster { @Override public void aiStep() { @@ -14408,7 +13960,7 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 - } - - if (flag) { -- this.setSecondsOnFire(8); +- this.igniteForSeconds(8); - } - } - } @@ -14417,7 +13969,7 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 super.aiStep(); } -@@ -304,6 +340,7 @@ public class Zombie extends Monster { +@@ -301,6 +337,7 @@ public class Zombie extends Monster { } @@ -14425,7 +13977,7 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 public boolean isSunSensitive() { return this.shouldBurnInDay; // Paper - Add more Zombie API } -@@ -433,7 +470,7 @@ public class Zombie extends Monster { +@@ -424,7 +461,7 @@ public class Zombie extends Monster { nbt.putBoolean("CanBreakDoors", this.canBreakDoors()); nbt.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1); nbt.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1); @@ -14434,7 +13986,7 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 } @Override -@@ -447,7 +484,7 @@ public class Zombie extends Monster { +@@ -438,7 +475,7 @@ public class Zombie extends Monster { } // Paper start - Add more Zombie API if (nbt.contains("Paper.ShouldBurnInDay")) { @@ -14443,10 +13995,10 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 } // Paper end - Add more Zombie API -@@ -520,19 +557,20 @@ public class Zombie extends Monster { - if (object instanceof Zombie.ZombieGroupData) { - Zombie.ZombieGroupData entityzombie_groupdatazombie = (Zombie.ZombieGroupData) object; +@@ -509,19 +546,20 @@ public class Zombie extends Monster { + } + if (object instanceof Zombie.ZombieGroupData entityzombie_groupdatazombie) { - if (entityzombie_groupdatazombie.isBaby) { - this.setBaby(true); + // Purpur start @@ -14470,7 +14022,7 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 Chicken entitychicken1 = (Chicken) EntityType.CHICKEN.create(this.level()); if (entitychicken1 != null) { -@@ -542,6 +580,7 @@ public class Zombie extends Monster { +@@ -531,6 +569,7 @@ public class Zombie extends Monster { this.startRiding(entitychicken1); world.addFreshEntity(entitychicken1, CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit } @@ -14478,7 +14030,7 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 } } } -@@ -552,11 +591,7 @@ public class Zombie extends Monster { +@@ -541,11 +580,7 @@ public class Zombie extends Monster { } if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { @@ -14491,7 +14043,7 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; } -@@ -588,7 +623,7 @@ public class Zombie extends Monster { +@@ -577,7 +612,7 @@ public class Zombie extends Monster { } protected void randomizeReinforcementsChance() { @@ -14501,10 +14053,10 @@ index 5c40e994007dbf46ebc12c1e6a6ca90379471b74..c531d830f4d6b2d2213e160d7e1a5b50 @Override diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index 7de9d012e7416eaa0189b513a0972c846e93c4b6..712f77d4ddad04c7cd89d51c6d0c79c2f3ab9347 100644 +index f38acc96f71298e40ce9433e7759fd223ca55e48..091095d1690bdd4d0870910b19e5e4ee3a3f9e7c 100644 --- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java +++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -82,6 +82,58 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { +@@ -80,6 +80,58 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { }); } @@ -14561,18 +14113,15 @@ index 7de9d012e7416eaa0189b513a0972c846e93c4b6..712f77d4ddad04c7cd89d51c6d0c79c2 + } + @Override - protected void defineSynchedData() { - super.defineSynchedData(); -@@ -168,13 +220,13 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +@@ -172,10 +224,10 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.is(Items.GOLDEN_APPLE)) { - if (this.hasEffect(MobEffects.WEAKNESS)) { + if (this.hasEffect(MobEffects.WEAKNESS) && level().purpurConfig.zombieVillagerCureEnabled) { // Purpur - if (!player.getAbilities().instabuild) { - itemstack.shrink(1); - } - + itemstack.consume(1, player); 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 @@ -14580,11 +14129,11 @@ index 7de9d012e7416eaa0189b513a0972c846e93c4b6..712f77d4ddad04c7cd89d51c6d0c79c2 return InteractionResult.SUCCESS; diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -index fbabbd0808304f5d0d12f987d00c9e43a89fb1c9..feba8a264bae656244f60296d0511a8046297f73 100644 +index a6def4133f06c41be287e9942643e80a7b8e8218..5bae3215ee0bf222c3bd77b3131f3d01ac6c9c41 100644 --- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -@@ -64,6 +64,53 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F); +@@ -62,6 +62,53 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + this.setPathfindingMalus(PathType.LAVA, 8.0F); } + // Purpur start @@ -14637,7 +14186,7 @@ index fbabbd0808304f5d0d12f987d00c9e43a89fb1c9..feba8a264bae656244f60296d0511a80 @Override public void setPersistentAngerTarget(@Nullable UUID angryAt) { this.persistentAngerTarget = angryAt; -@@ -111,7 +158,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { +@@ -109,7 +156,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { this.maybeAlertOthers(); } @@ -14646,7 +14195,7 @@ index fbabbd0808304f5d0d12f987d00c9e43a89fb1c9..feba8a264bae656244f60296d0511a80 this.lastHurtByPlayerTime = this.tickCount; } -@@ -166,7 +213,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { +@@ -164,7 +211,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { this.ticksUntilNextAlert = ZombifiedPiglin.ALERT_INTERVAL.sample(this.random); } @@ -14655,7 +14204,7 @@ index fbabbd0808304f5d0d12f987d00c9e43a89fb1c9..feba8a264bae656244f60296d0511a80 this.setLastHurtByPlayer((Player) entityliving); } -@@ -246,7 +293,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { +@@ -244,7 +291,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { @Override protected void randomizeReinforcementsChance() { @@ -14665,10 +14214,10 @@ index fbabbd0808304f5d0d12f987d00c9e43a89fb1c9..feba8a264bae656244f60296d0511a80 @Nullable diff --git a/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java b/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java -index b5ef8d9e55656100085a4d9858c3530bb08d3c16..aa27c014ce53e2dd49f02d413d5c4d763261a803 100644 +index 796ce24185ab9e80864116f9523c4289fcaad243..82391c84789c27353212d3142c036cc5aedb98f9 100644 --- a/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java +++ b/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java -@@ -202,10 +202,10 @@ public class Breeze extends Monster { +@@ -226,11 +226,11 @@ public class Breeze extends Monster { @Override protected void customServerAiStep() { @@ -14676,17 +14225,18 @@ index b5ef8d9e55656100085a4d9858c3530bb08d3c16..aa27c014ce53e2dd49f02d413d5c4d76 + //this.level().getProfiler().push("breezeBrain"); // Purpur this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().popPush("breezeActivityUpdate"); -- this.level().getProfiler().pop(); + //this.level().getProfiler().popPush("breezeActivityUpdate"); // Purpur + BreezeAi.updateActivity(this); +- this.level().getProfiler().pop(); + //this.level().getProfiler().pop(); // Purpur super.customServerAiStep(); } diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index 1299f93d4f983e6715e447add65df91ef9e9090a..cfa7ec9b5b3125cb80b591e80f8d42815c25f568 100644 +index c583d883118ded5e1884c757427dc5e73c10dd27..757d2b7bcb83f5bdcddf85a00e90288f3b82a2d6 100644 --- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -92,6 +92,43 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { +@@ -90,6 +90,43 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { this.xpReward = 5; } @@ -14730,14 +14280,13 @@ index 1299f93d4f983e6715e447add65df91ef9e9090a..cfa7ec9b5b3125cb80b591e80f8d4281 @Override public boolean canBeLeashed(Player player) { return !this.isLeashed(); -@@ -158,10 +195,10 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - private int behaviorTick; // Pufferfish +@@ -155,9 +192,10 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { + @Override protected void customServerAiStep() { - this.level().getProfiler().push("hoglinBrain"); -- if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish + //this.level().getProfiler().push("hoglinBrain"); // Purpur -+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); + //this.level().getProfiler().pop(); // Purpur @@ -14745,10 +14294,10 @@ index 1299f93d4f983e6715e447add65df91ef9e9090a..cfa7ec9b5b3125cb80b591e80f8d4281 if (this.isConverting()) { this.timeInOverworld++; diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index 83d83e3f84bb6bd58761671c6cd4c8683545ff4c..1422c0f4ff6a3e61f229574cd7b50971bdbd8451 100644 +index a8ab486c7e11ec137da48174af6f1030dfd48056..1b5977aa14d9a7254e7692bb152cc2808d52107a 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -96,6 +96,38 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento +@@ -94,6 +94,38 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento this.xpReward = 5; } @@ -14787,21 +14336,20 @@ index 83d83e3f84bb6bd58761671c6cd4c8683545ff4c..1422c0f4ff6a3e61f229574cd7b50971 @Override public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); -@@ -303,10 +335,10 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - private int behaviorTick; // Pufferfish +@@ -296,9 +328,10 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento + @Override protected void customServerAiStep() { - this.level().getProfiler().push("piglinBrain"); -- if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish + //this.level().getProfiler().push("piglinBrain"); // Purpur -+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); + //this.level().getProfiler().pop(); // Purpur PiglinAi.updateActivity(this); super.customServerAiStep(); } -@@ -402,7 +434,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento +@@ -389,7 +422,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento @Override public boolean wantsToPickUp(ItemStack stack) { @@ -14811,39 +14359,23 @@ index 83d83e3f84bb6bd58761671c6cd4c8683545ff4c..1422c0f4ff6a3e61f229574cd7b50971 protected boolean canReplaceCurrentItem(ItemStack stack) { diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -index 4f4f557b7f4232ec3b90dda43c6bed30521318ba..dd4313e0507d3adda0ec84c79f1af13ecc2d7ef3 100644 +index e25af9af8f87e6762716749c367658bf6bda9e34..b7d5c0b0e3741fcf04c4bac21a82fc41e2eeed5d 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java +++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -@@ -599,20 +599,33 @@ public class PiglinAi { - Iterator iterator = iterable.iterator(); - - Item item; -+ ItemStack itemstack; // Purpur - - do { - if (!iterator.hasNext()) { - return false; - } - -- ItemStack itemstack = (ItemStack) iterator.next(); -+ itemstack = (ItemStack) iterator.next(); // Purpur +@@ -606,11 +606,18 @@ public class PiglinAi { + ItemStack itemstack = (ItemStack) iterator.next(); item = itemstack.getItem(); -- } while (!(item instanceof ArmorItem) || ((ArmorItem) item).getMaterial() != ArmorMaterials.GOLD); -+ } while (!(item instanceof ArmorItem) || ((ArmorItem) item).getMaterial() != ArmorMaterials.GOLD && (!entity.level().purpurConfig.piglinIgnoresArmorWithGoldTrim || !isWearingGoldTrim(entity, itemstack))); // Purpur +- } while (!(item instanceof ArmorItem) || !((ArmorItem) item).getMaterial().is(ArmorMaterials.GOLD)); ++ } while (!(item instanceof ArmorItem) || !((ArmorItem) item).getMaterial().is(ArmorMaterials.GOLD) && (!entity.level().purpurConfig.piglinIgnoresArmorWithGoldTrim || !isWearingGoldTrim(item))); // Purpur return true; } + // Purpur start -+ private static boolean isWearingGoldTrim(LivingEntity entity, ItemStack itemstack) { -+ Optional optionalArmorTrim = net.minecraft.world.item.armortrim.ArmorTrim.getTrim(entity.level().registryAccess(), itemstack, true); -+ -+ if (optionalArmorTrim.isEmpty()) return false; -+ -+ net.minecraft.world.item.armortrim.ArmorTrim armorTrim = optionalArmorTrim.get(); -+ -+ return armorTrim.material().is(net.minecraft.world.item.armortrim.TrimMaterials.GOLD); ++ private static boolean isWearingGoldTrim(Item itemstack) { ++ net.minecraft.world.item.armortrim.ArmorTrim armorTrim = itemstack.components().get(net.minecraft.core.component.DataComponents.TRIM); ++ return armorTrim != null && armorTrim.material().is(net.minecraft.world.item.armortrim.TrimMaterials.GOLD); + } + // Purpur end + @@ -14851,10 +14383,10 @@ index 4f4f557b7f4232ec3b90dda43c6bed30521318ba..dd4313e0507d3adda0ec84c79f1af13e piglin.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET); piglin.getNavigation().stop(); diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -index 1afd5245267866c498d4b0d90ca55cda2ede8ca9..40f6af92d1fc58a6115fc16b02d296aef897b607 100644 +index fcadd7f28ccb81bbb36e97d8b8d8a8ba3f3d6a16..407a0f27719d3944b3a005c664d80246ea1c7cf4 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -@@ -63,6 +63,38 @@ public class PiglinBrute extends AbstractPiglin { +@@ -62,6 +62,38 @@ public class PiglinBrute extends AbstractPiglin { this.xpReward = 20; } @@ -14893,7 +14425,7 @@ index 1afd5245267866c498d4b0d90ca55cda2ede8ca9..40f6af92d1fc58a6115fc16b02d296ae public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 50.0).add(Attributes.MOVEMENT_SPEED, 0.35F).add(Attributes.ATTACK_DAMAGE, 7.0); } -@@ -113,9 +145,10 @@ public class PiglinBrute extends AbstractPiglin { +@@ -106,9 +138,10 @@ public class PiglinBrute extends AbstractPiglin { @Override protected void customServerAiStep() { @@ -14907,13 +14439,13 @@ index 1afd5245267866c498d4b0d90ca55cda2ede8ca9..40f6af92d1fc58a6115fc16b02d296ae PiglinBruteAi.maybePlayActivitySound(this); super.customServerAiStep(); diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index 0a151c679b0dc943598180942d6d4b3886211688..bf7ef72a7d92db8f11789a69583270644de0dac7 100644 +index ddd60be52dce5773c80934be5aa5705db239e3dd..0bb577ec9ba0d23a741ccf067ac35f6be68312ca 100644 --- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java +++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java @@ -123,8 +123,32 @@ public class Warden extends Monster implements VibrationSystem { - this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F); - this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, 0.0F); - this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 0.0F); + this.setPathfindingMalus(PathType.LAVA, 8.0F); + this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); + this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); + this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.5F); // Purpur } @@ -14943,29 +14475,27 @@ index 0a151c679b0dc943598180942d6d4b3886211688..bf7ef72a7d92db8f11789a6958327064 @Override public Packet getAddEntityPacket() { return new ClientboundAddEntityPacket(this, this.hasPose(Pose.EMERGING) ? 1 : 0); -@@ -278,10 +302,10 @@ public class Warden extends Monster implements VibrationSystem { +@@ -275,9 +299,10 @@ public class Warden extends Monster implements VibrationSystem { protected void customServerAiStep() { ServerLevel worldserver = (ServerLevel) this.level(); - worldserver.getProfiler().push("wardenBrain"); + //worldserver.getProfiler().push("wardenBrain"); // Purpur - if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish ++ //if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - TODO: Move to Ridables patch this.getBrain().tick(worldserver, this); - this.level().getProfiler().pop(); + //this.level().getProfiler().pop(); // Purpur super.customServerAiStep(); if ((this.tickCount + this.getId()) % 120 == 0) { Warden.applyDarknessAround(worldserver, this.position(), this, 20); -@@ -398,19 +422,16 @@ public class Warden extends Monster implements VibrationSystem { +@@ -392,17 +417,14 @@ public class Warden extends Monster implements VibrationSystem { @Contract("null->false") public boolean canTargetEntity(@Nullable Entity entity) { - boolean flag; - + if (getRider() != null && isControllable()) return false; // Purpur - if (entity instanceof LivingEntity) { - LivingEntity entityliving = (LivingEntity) entity; - + if (entity instanceof LivingEntity entityliving) { if (this.level() == entity.level() && EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity) && !this.isAlliedTo(entity) && entityliving.getType() != EntityType.ARMOR_STAND && entityliving.getType() != EntityType.WARDEN && !entityliving.isInvulnerable() && !entityliving.isDeadOrDying() && this.level().getWorldBorder().isWithinBounds(entityliving.getBoundingBox())) { - flag = true; - return flag; @@ -14980,10 +14510,10 @@ index 0a151c679b0dc943598180942d6d4b3886211688..bf7ef72a7d92db8f11789a6958327064 public static void applyDarknessAround(ServerLevel world, Vec3 pos, @Nullable Entity entity, int range) { diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -index 4e6c2f6b2e54a4c126e9a026b9cad05ce835ad66..69553b5b3c56998e4ae40876b1458929b335ad5d 100644 +index d323cf157f2a910916baa9ce3f7e5bc81648c47d..6cbbca1db5362fa2dd5c5704c7fbaa612d3cbab1 100644 --- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java +++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -@@ -42,6 +42,7 @@ import org.bukkit.event.entity.VillagerAcquireTradeEvent; +@@ -48,6 +48,7 @@ import org.bukkit.event.entity.VillagerAcquireTradeEvent; // CraftBukkit end public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, Npc, Merchant { @@ -14992,10 +14522,10 @@ index 4e6c2f6b2e54a4c126e9a026b9cad05ce835ad66..69553b5b3c56998e4ae40876b1458929 // CraftBukkit start private CraftMerchant craftMerchant; diff --git a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -index 5d1610eddcaf0cf65c726a5438b42e53bab85332..5665aa461f8c943bd7373df28d7d152251cce431 100644 +index e0e5046c84941a8d17e18c177f3daea9cb631940..d503d7a5837dbeb98e58dbe8f7e5de45f6d88990 100644 --- a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java +++ b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -@@ -28,7 +28,7 @@ public class CatSpawner implements CustomSpawner { +@@ -27,7 +27,7 @@ public class CatSpawner implements CustomSpawner { if (this.nextTick > 0) { return 0; } else { @@ -15004,7 +14534,7 @@ index 5d1610eddcaf0cf65c726a5438b42e53bab85332..5665aa461f8c943bd7373df28d7d1522 Player player = world.getRandomPlayer(); if (player == null) { return 0; -@@ -62,8 +62,12 @@ public class CatSpawner implements CustomSpawner { +@@ -61,8 +61,12 @@ public class CatSpawner implements CustomSpawner { private int spawnInVillage(ServerLevel world, BlockPos pos) { int i = 48; @@ -15019,7 +14549,7 @@ index 5d1610eddcaf0cf65c726a5438b42e53bab85332..5665aa461f8c943bd7373df28d7d1522 if (list.size() < 5) { return this.spawnCat(pos, world); } -@@ -74,7 +78,11 @@ public class CatSpawner implements CustomSpawner { +@@ -73,7 +77,11 @@ public class CatSpawner implements CustomSpawner { private int spawnInHut(ServerLevel world, BlockPos pos) { int i = 16; @@ -15033,7 +14563,7 @@ index 5d1610eddcaf0cf65c726a5438b42e53bab85332..5665aa461f8c943bd7373df28d7d1522 } diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d999718a9082cf 100644 +index a7930f9875aa4aca997caaead46ecdc21e5e11d7..4be218129188c1be8736940170a861adc10fdb7d 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java @@ -142,6 +142,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler @@ -15043,9 +14573,9 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 + private boolean isLobotomized = false; public boolean isLobotomized() { return this.isLobotomized; } // Purpur + private int notLobotomizedCount = 0; // Purpur - public long nextGolemPanic = -1; // Pufferfish - -@@ -156,6 +158,91 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + public Villager(EntityType entityType, Level world) { + this(entityType, world, VillagerType.PLAINS); +@@ -154,6 +156,91 @@ public class Villager extends AbstractVillager implements ReputationEventHandler this.getNavigation().setCanFloat(true); this.setCanPickUpLoot(true); this.setVillagerData(this.getVillagerData().setType(type).setProfession(VillagerProfession.NONE)); @@ -15137,7 +14667,7 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 } @Override -@@ -192,7 +279,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -190,7 +277,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler brain.addActivity(Activity.PLAY, VillagerGoalPackages.getPlayPackage(0.5F)); } else { brain.setSchedule(Schedule.VILLAGER_DEFAULT); @@ -15146,7 +14676,7 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 } brain.addActivity(Activity.CORE, VillagerGoalPackages.getCorePackage(villagerprofession, 0.5F)); -@@ -255,15 +342,21 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -252,11 +339,25 @@ public class Villager extends AbstractVillager implements ReputationEventHandler // Paper start this.customServerAiStep(false); } @@ -15154,9 +14684,6 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 + protected void customServerAiStep(boolean inactive) { // Purpur - not final // Paper end - this.level().getProfiler().push("villagerBrain"); -- // Pufferfish start -- if (!inactive && this.behaviorTick++ % this.activatedPriority == 0) { -- this.getBrain().tick((ServerLevel) this.level(), this); // Paper + //this.level().getProfiler().push("villagerBrain"); // Purpur + // Purpur start + if (this.level().purpurConfig.villagerLobotomizeEnabled) { @@ -15164,18 +14691,21 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 + inactive = inactive || checkLobotomized(); + } else { + this.isLobotomized = false; - } -- // Pufferfish end ++ } ++ // Purpur end + if (!inactive) this.getBrain().tick((ServerLevel) this.level(), this); // Paper - this.level().getProfiler().pop(); ++ else if (this.isLobotomized && shouldRestock()) restock(); // Purpur ++ /*// Purpur start // Purpur - TODO: Pufferfish + if (!inactive && (getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider + this.getBrain().tick((ServerLevel) this.level(), this); // Paper -+ } else if (this.isLobotomized && shouldRestock()) restock(); -+ // Purpur end ++ } ++ // Purpur end*/ // Purpur - TODO: Pufferfish + //this.level().getProfiler().pop(); // Purpur if (this.assignProfessionWhenSpawned) { this.assignProfessionWhenSpawned = false; } -@@ -319,7 +412,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -312,7 +413,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler if (!itemstack.is(Items.VILLAGER_SPAWN_EGG) && this.isAlive() && !this.isTrading() && !this.isSleeping()) { if (this.isBaby()) { this.setUnhappy(); @@ -15184,7 +14714,7 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 } else { boolean flag = this.getOffers().isEmpty(); -@@ -332,9 +425,10 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -325,9 +426,10 @@ public class Villager extends AbstractVillager implements ReputationEventHandler } if (flag) { @@ -15197,7 +14727,7 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 this.startTrading(player); } -@@ -503,7 +597,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -496,7 +598,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler while (iterator.hasNext()) { MerchantOffer merchantrecipe = (MerchantOffer) iterator.next(); @@ -15206,7 +14736,7 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 } } -@@ -753,7 +847,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -738,7 +840,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler @Override public boolean canBreed() { @@ -15215,7 +14745,7 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 } private boolean hungry() { -@@ -946,6 +1040,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -931,6 +1033,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler public boolean hasFarmSeeds() { return this.getInventory().hasAnyMatching((itemstack) -> { @@ -15227,7 +14757,7 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 return itemstack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS); }); } -@@ -1003,6 +1102,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -988,6 +1095,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler } public void spawnGolemIfNeeded(ServerLevel world, long time, int requiredCount) { @@ -15235,7 +14765,7 @@ index 96ca567af2d8fb2ba39f995be80b935344550124..50202286a0d83f7fe5331eb669d99971 if (this.wantsToSpawnGolem(time)) { AABB axisalignedbb = this.getBoundingBox().inflate(10.0D, 10.0D, 10.0D); List list = world.getEntitiesOfClass(Villager.class, axisalignedbb); -@@ -1067,6 +1167,12 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -1052,6 +1160,12 @@ public class Villager extends AbstractVillager implements ReputationEventHandler @Override public void startSleeping(BlockPos pos) { @@ -15262,7 +14792,7 @@ index 1316f4475802e17039800cc6128e1b065328beb7..d02e2d1aceac651e06a3a3698b7ac64d "farmer", PoiTypes.FARMER, diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index 8d1cc1a644415be251f469ab1cb2ebc09fe5c3eb..b133c186d2d1412aa623ba3db68091bc69c282a5 100644 +index 0854e9b7ee2e6b23b6c1ee6a324a5a253c9d4679..c1e573758539a151452b12466339ccf8b39c7d38 100644 --- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java +++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java @@ -71,6 +71,43 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill @@ -15340,10 +14870,10 @@ index 8d1cc1a644415be251f469ab1cb2ebc09fe5c3eb..b133c186d2d1412aa623ba3db68091bc this.openTradingScreen(player, this.getDisplayName(), 1); } diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -index d7bddedb19c10f62fd1f7d3128453ad706ed16be..752b38d45d59d8b3cd492246e5aa4f378a78734d 100644 +index c72b6ea5530e54fc373c701028e1c147cea34b59..96e9fce5f9084737d2fcf4deb83305733b480179 100644 --- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -@@ -159,7 +159,17 @@ public class WanderingTraderSpawner implements CustomSpawner { +@@ -160,7 +160,17 @@ public class WanderingTraderSpawner implements CustomSpawner { int k = pos.getX() + this.random.nextInt(range * 2) - range; int l = pos.getZ() + this.random.nextInt(range * 2) - range; int i1 = world.getHeight(Heightmap.Types.WORLD_SURFACE, k, l); @@ -15360,14 +14890,14 @@ index d7bddedb19c10f62fd1f7d3128453ad706ed16be..752b38d45d59d8b3cd492246e5aa4f37 + } + // Purpur end - if (NaturalSpawner.isSpawnPositionOk(SpawnPlacements.Type.ON_GROUND, world, blockposition2, EntityType.WANDERING_TRADER)) { + if (spawnplacementtype.isSpawnPositionOk(world, blockposition2, EntityType.WANDERING_TRADER)) { blockposition1 = blockposition2; diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 567704f61034363e48ef2a5b5566ebdc91682297..43199815ffe3d666577390b96187aa898ceb910e 100644 +index 093d1388ff90ad59110a37536b6639f939549068..845c4af5d5d38d54de4a1b20fe32bf5dd4776a29 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -183,17 +183,40 @@ public abstract class Player extends LivingEntity { - public float hurtDir; // Paper - protected -> public +@@ -195,17 +195,40 @@ public abstract class Player extends LivingEntity { + public boolean ignoreFallDamageFromCurrentImpulse; public boolean affectsSpawning = true; // Paper - Affects Spawning API public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage + public int sixRowEnderchestSlotCount = -1; // Purpur @@ -15407,7 +14937,7 @@ index 567704f61034363e48ef2a5b5566ebdc91682297..43199815ffe3d666577390b96187aa89 public Player(Level world, BlockPos pos, float yaw, GameProfile gameProfile) { super(EntityType.PLAYER, world); this.lastItemInMainHand = ItemStack.EMPTY; -@@ -238,6 +261,12 @@ public abstract class Player extends LivingEntity { +@@ -250,6 +273,12 @@ public abstract class Player extends LivingEntity { @Override public void tick() { @@ -15420,7 +14950,7 @@ index 567704f61034363e48ef2a5b5566ebdc91682297..43199815ffe3d666577390b96187aa89 this.noPhysics = this.isSpectator(); if (this.isSpectator()) { this.setOnGround(false); -@@ -348,6 +377,16 @@ public abstract class Player extends LivingEntity { +@@ -360,6 +389,16 @@ public abstract class Player extends LivingEntity { this.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 200, 0, false, false, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TURTLE_HELMET); // CraftBukkit } @@ -15437,7 +14967,7 @@ index 567704f61034363e48ef2a5b5566ebdc91682297..43199815ffe3d666577390b96187aa89 } protected ItemCooldowns createItemCooldowns() { -@@ -438,7 +477,7 @@ public abstract class Player extends LivingEntity { +@@ -450,7 +489,7 @@ public abstract class Player extends LivingEntity { @Override public int getPortalWaitTime() { @@ -15446,7 +14976,7 @@ index 567704f61034363e48ef2a5b5566ebdc91682297..43199815ffe3d666577390b96187aa89 } @Override -@@ -594,7 +633,7 @@ public abstract class Player extends LivingEntity { +@@ -593,7 +632,7 @@ public abstract class Player extends LivingEntity { while (iterator.hasNext()) { Entity entity = (Entity) iterator.next(); @@ -15455,16 +14985,16 @@ index 567704f61034363e48ef2a5b5566ebdc91682297..43199815ffe3d666577390b96187aa89 list1.add(entity); } else if (!entity.isRemoved()) { this.touch(entity); -@@ -1285,7 +1324,7 @@ public abstract class Player extends LivingEntity { - flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits - flag2 = flag2 && !this.isSprinting(); - if (flag2) { -- f *= 1.5F; -+ f *= this.level().purpurConfig.playerCriticalDamageMultiplier; // Purpur - } +@@ -1301,7 +1340,7 @@ public abstract class Player extends LivingEntity { - f += f1; -@@ -1923,9 +1962,19 @@ public abstract class Player extends LivingEntity { + flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits + if (flag2) { +- f *= 1.5F; ++ f *= this.level().purpurConfig.playerCriticalDamageMultiplier; // Purpur + } + + f += f1; +@@ -1941,9 +1980,19 @@ public abstract class Player extends LivingEntity { @Override public int getExperienceReward() { if (!this.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator()) { @@ -15487,40 +15017,34 @@ index 567704f61034363e48ef2a5b5566ebdc91682297..43199815ffe3d666577390b96187aa89 } else { return 0; } -@@ -2001,6 +2050,11 @@ public abstract class Player extends LivingEntity { - return this.inventory.armor; +@@ -2024,6 +2073,13 @@ public abstract class Player extends LivingEntity { + return slot != EquipmentSlot.BODY; } ++ // Purpur start + @Override + public boolean dismountsUnderwater() { + return !level().purpurConfig.playerRidableInWater; + } ++ // Purpur end + public boolean setEntityOnShoulder(CompoundTag entityNbt) { if (!this.isPassenger() && this.onGround() && !this.isInWater() && !this.isInPowderSnow) { if (this.getShoulderEntityLeft().isEmpty()) { -@@ -2281,7 +2335,7 @@ public abstract class Player extends LivingEntity { +@@ -2321,7 +2377,7 @@ public abstract class Player extends LivingEntity { public ItemStack eat(Level world, ItemStack stack) { - this.getFoodData().eat(stack.getItem(), stack); + this.getFoodData().eat(stack); this.awardStat(Stats.ITEM_USED.get(stack.getItem())); - world.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); + // world.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); // Purpur - moved to tick() if (this instanceof ServerPlayer) { CriteriaTriggers.CONSUME_ITEM.trigger((ServerPlayer) this, stack); } -@@ -2375,6 +2429,7 @@ public abstract class Player extends LivingEntity { - } - - public static boolean isValidUsername(String name) { -+ if (true) return org.purpurmc.purpur.PurpurConfig.usernameValidCharactersPattern.matcher(name).matches(); // Purpur - // Paper start - username validation overriding - if (name == null || name.isEmpty() || name.length() > 16) { - return false; diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -index e8faca6e443239968f0111519f9e5cd018ed3297..a9289c4179a78862361be87aaa83f49d6bf60714 100644 +index 31b8a8bf78d52b5f11b68e780ec09bf78e7bda84..06f7bc4d8d6679d6625a8d392777722fc97739ba 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -75,6 +75,7 @@ public abstract class AbstractArrow extends Projectile { +@@ -77,6 +77,7 @@ public abstract class AbstractArrow extends Projectile { @Nullable private List piercedAndKilledEntities; public ItemStack pickupItemStack; @@ -15528,7 +15052,7 @@ index e8faca6e443239968f0111519f9e5cd018ed3297..a9289c4179a78862361be87aaa83f49d // Spigot Start @Override -@@ -320,7 +321,7 @@ public abstract class AbstractArrow extends Projectile { +@@ -332,7 +333,7 @@ public abstract class AbstractArrow extends Projectile { Vec3 vec3d = this.getDeltaMovement(); this.setDeltaMovement(vec3d.multiply((double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F))); @@ -15537,7 +15061,7 @@ index e8faca6e443239968f0111519f9e5cd018ed3297..a9289c4179a78862361be87aaa83f49d } @Override -@@ -642,6 +643,12 @@ public abstract class AbstractArrow extends Projectile { +@@ -655,6 +656,12 @@ public abstract class AbstractArrow extends Projectile { this.knockback = punch; } @@ -15579,10 +15103,10 @@ index 9d89872c5958f3e8d6c1ef4fd93f9b8b85296851..6a94c86acce5afbf1e9c8e7d664b3eb2 // CraftBukkit start - fire ExplosionPrimeEvent ExplosionPrimeEvent event = new ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); diff --git a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java -index 8f5376543cca9cbfb2a014f67ec373d984b0df64..3673d1442778331ece25f8faca95b3499cafe46e 100644 +index ffd01d24cbfc90e2a8807757e61b2cf20a944354..a419820d5001079ed839e67c757bc8fa591a20b3 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java +++ b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java -@@ -29,6 +29,12 @@ public class LlamaSpit extends Projectile { +@@ -30,6 +30,12 @@ public class LlamaSpit extends Projectile { this.setPos(owner.getX() - (double) (owner.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(owner.yBodyRot * 0.017453292F), owner.getEyeY() - 0.10000000149011612D, owner.getZ() + (double) (owner.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(owner.yBodyRot * 0.017453292F)); } @@ -15593,22 +15117,13 @@ index 8f5376543cca9cbfb2a014f67ec373d984b0df64..3673d1442778331ece25f8faca95b349 + // Purpur end + @Override - public void tick() { - super.tick(); + protected double getDefaultGravity() { + return 0.06D; diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index 837f68825f601971f374be47952b23108bf66ba6..577df1ad8eb57ae7a53c9931c379824a6882fa5f 100644 +index 74c596264d4da551437bd2a23e1c70022cfc73fc..e4d4ff0ef4a0f3283aa42fe2304816cd6d9475a8 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -64,7 +64,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { - if (!isLoaded) { - if (Projectile.loadedThisTick > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerTick) { - if (++this.loadedLifetime > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerProjectile) { -- this.discard(); -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Purpur - } - return; - } -@@ -334,7 +334,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { +@@ -343,7 +343,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { public boolean mayInteract(Level world, BlockPos pos) { Entity entity = this.getOwner(); @@ -15618,7 +15133,7 @@ index 837f68825f601971f374be47952b23108bf66ba6..577df1ad8eb57ae7a53c9931c379824a public boolean mayBreak(Level world) { diff --git a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java -index 6724fe4470aeea338eb4cfd10a7e61fbcac1e5b7..dd38f32ac6a62905c9a79dacf85cf073fa6941b3 100644 +index 3a11ad32d95088a5aca713a1a6a984cc22d4fa9a..c078ccad4aabe469a9611331b415a4cef241973e 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java +++ b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java @@ -27,7 +27,7 @@ public class SmallFireball extends Fireball { @@ -15631,7 +15146,7 @@ index 6724fe4470aeea338eb4cfd10a7e61fbcac1e5b7..dd38f32ac6a62905c9a79dacf85cf073 // CraftBukkit end } diff --git a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java -index 5e82549ea2e80b3968b793b7b4b685c4891e9a91..bb61e1132c28274175215a679befdcfa2496b099 100644 +index 2b4d206c0d31ba38d7b2af654bd420e85145d441..1b9d0e28e518c501b4b93ae385ddd64aeade97d5 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java +++ b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java @@ -58,11 +58,41 @@ public class Snowball extends ThrowableItemProjectile { @@ -15704,10 +15219,10 @@ index 1fb1e729d6879568d8b4943071fa940325b2e5b0..d9761d8fe746e925a7a32dfc15eb8045 // CraftBukkit end this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_TELEPORT, SoundSource.PLAYERS); diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -index 8ae7d62b72fb72d893e68b02b645d48374595ae6..2bd77524313ae7b32f710e7d197e81a2ddd12965 100644 +index 3ff06cc6ad35567bcb1f29115db63c11a8e79dbb..f7dd785bdb0dbd0706b367b48235215ff1a0e08f 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java +++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -@@ -63,7 +63,7 @@ public class ThrownTrident extends AbstractArrow { +@@ -67,7 +67,7 @@ public class ThrownTrident extends AbstractArrow { Entity entity = this.getOwner(); byte b0 = (Byte) this.entityData.get(ThrownTrident.ID_LOYALTY); @@ -15717,7 +15232,7 @@ index 8ae7d62b72fb72d893e68b02b645d48374595ae6..2bd77524313ae7b32f710e7d197e81a2 if (!this.level().isClientSide && this.pickup == AbstractArrow.Pickup.ALLOWED) { this.spawnAtLocation(this.getPickupItem(), 0.1F); diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -index 6f49b9b8707d74330adb973e0db3cd5bccf138b6..b4a38621b58e16b2bf48b3d45d85130e8883b477 100644 +index 55b4b5ad5f084c9a271a716d076672478d6486ba..a60d7f7baab005afc532ecec7aa22c53db4f51e0 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java +++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java @@ -99,7 +99,7 @@ public class WitherSkull extends AbstractHurtingProjectile { @@ -15729,10 +15244,11 @@ index 6f49b9b8707d74330adb973e0db3cd5bccf138b6..b4a38621b58e16b2bf48b3d45d85130e this.level().getCraftServer().getPluginManager().callEvent(event); if (!event.isCancelled()) { -@@ -111,6 +111,17 @@ public class WitherSkull extends AbstractHurtingProjectile { +@@ -111,6 +111,19 @@ public class WitherSkull extends AbstractHurtingProjectile { } ++ // Purpur start + @Override + public boolean canHitEntity(Entity target) { + // do not hit rider @@ -15743,15 +15259,16 @@ index 6f49b9b8707d74330adb973e0db3cd5bccf138b6..b4a38621b58e16b2bf48b3d45d85130e + public boolean canSaveToDisk() { + return false; + } ++ // Purpur end + @Override - public boolean isPickable() { + public boolean hurt(DamageSource source, float amount) { return false; diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java -index 93bbf7556f9599e9dd90761085a57d78bd521867..b3912881892b4f1bca577761083c5da1568c8187 100644 +index 98e558338b5d9fb03869d2cc21b3e90eb45b95f6..4a8fa7e5844b5cd12ef6b113f988b715c7a3ef64 100644 --- a/src/main/java/net/minecraft/world/entity/raid/Raider.java +++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java -@@ -322,7 +322,7 @@ public abstract class Raider extends PatrollingMonster { +@@ -341,7 +341,7 @@ public abstract class Raider extends PatrollingMonster { @Override public boolean canUse() { @@ -15759,12 +15276,12 @@ index 93bbf7556f9599e9dd90761085a57d78bd521867..b3912881892b4f1bca577761083c5da1 + if ((!this.mob.level().purpurConfig.pillagerBypassMobGriefing && !this.mob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items // Purpur Raid raid = this.mob.getCurrentRaid(); - if (this.mob.hasActiveRaid() && !this.mob.getCurrentRaid().isOver() && this.mob.canBeLeader() && !ItemStack.matches(this.mob.getItemBySlot(EquipmentSlot.HEAD), Raid.getLeaderBannerInstance())) { + if (this.mob.hasActiveRaid() && !this.mob.getCurrentRaid().isOver() && this.mob.canBeLeader() && !ItemStack.matches(this.mob.getItemBySlot(EquipmentSlot.HEAD), Raid.getLeaderBannerInstance(this.mob.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)))) { diff --git a/src/main/java/net/minecraft/world/entity/raid/Raids.java b/src/main/java/net/minecraft/world/entity/raid/Raids.java -index 31831811ce16265e9828fa34d9e67d8ac195d723..a1f74718240da3dfb0fc53f337ec3bf1636def75 100644 +index 8c60f71270d909c10e6617eb64b8fdb42deb73e9..eedce2a3d67d875d5174ee125e2679480d4d412c 100644 --- a/src/main/java/net/minecraft/world/entity/raid/Raids.java +++ b/src/main/java/net/minecraft/world/entity/raid/Raids.java -@@ -29,6 +29,7 @@ import net.minecraft.world.phys.Vec3; +@@ -26,6 +26,7 @@ import net.minecraft.world.phys.Vec3; public class Raids extends SavedData { private static final String RAID_FILE_ID = "raids"; @@ -15772,7 +15289,7 @@ index 31831811ce16265e9828fa34d9e67d8ac195d723..a1f74718240da3dfb0fc53f337ec3bf1 public final Map raidMap = Maps.newHashMap(); private final ServerLevel level; private int nextAvailableID; -@@ -54,6 +55,17 @@ public class Raids extends SavedData { +@@ -51,6 +52,17 @@ public class Raids extends SavedData { public void tick() { ++this.tick; @@ -15787,28 +15304,28 @@ index 31831811ce16265e9828fa34d9e67d8ac195d723..a1f74718240da3dfb0fc53f337ec3bf1 + }); + } + // Purpur end - Iterator iterator = this.raidMap.values().iterator(); + Iterator iterator = this.raidMap.values().iterator(); while (iterator.hasNext()) { -@@ -138,11 +150,13 @@ public class Raids extends SavedData { - } +@@ -122,11 +134,13 @@ public class Raids extends SavedData { + */ - if (flag) { + if (!raid.isStarted() || (raid.isInProgress() && raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel())) { // CraftBukkit - fixed a bug with raid: players could add up Bad Omen level even when the raid had finished + if (level.purpurConfig.raidCooldownSeconds != 0 && playerCooldowns.containsKey(player.getUUID())) return null; // Purpur // CraftBukkit start if (!org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(raid, player)) { - player.removeEffect(MobEffects.BAD_OMEN); + player.removeEffect(net.minecraft.world.effect.MobEffects.RAID_OMEN); return null; } + if (level.purpurConfig.raidCooldownSeconds != 0) playerCooldowns.put(player.getUUID(), level.purpurConfig.raidCooldownSeconds); // Purpur - if (!this.raidMap.containsKey(raid.getId())) { + if (!raid.isStarted() && !this.raidMap.containsKey(raid.getId())) { this.raidMap.put(raid.getId(), raid); diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -index d514ec1e4cbdc579c3a61533998437903afdc8b6..eb5bd5cfd131042e366872bf599a315d83dc732b 100644 +index 4d7454e5a64fc18e63793a221daa94617f17c666..e7a1ce585c9e552e6f9ce9acd26fdfe5c43e0b5d 100644 --- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java +++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -@@ -105,12 +105,14 @@ public abstract class AbstractMinecart extends VehicleEntity { +@@ -102,12 +102,14 @@ public abstract class AbstractMinecart extends VehicleEntity { private double flyingY = 0.95; private double flyingZ = 0.95; public double maxSpeed = 0.4D; @@ -15823,7 +15340,7 @@ index d514ec1e4cbdc579c3a61533998437903afdc8b6..eb5bd5cfd131042e366872bf599a315d } protected AbstractMinecart(EntityType type, Level world, double x, double y, double z) { -@@ -294,6 +296,12 @@ public abstract class AbstractMinecart extends VehicleEntity { +@@ -296,6 +298,12 @@ public abstract class AbstractMinecart extends VehicleEntity { @Override public void tick() { @@ -15836,7 +15353,7 @@ index d514ec1e4cbdc579c3a61533998437903afdc8b6..eb5bd5cfd131042e366872bf599a315d // CraftBukkit start double prevX = this.getX(); double prevY = this.getY(); -@@ -451,16 +459,62 @@ public abstract class AbstractMinecart extends VehicleEntity { +@@ -448,16 +456,62 @@ public abstract class AbstractMinecart extends VehicleEntity { public void activateMinecart(int x, int y, int z, boolean powered) {} @@ -15899,7 +15416,7 @@ index d514ec1e4cbdc579c3a61533998437903afdc8b6..eb5bd5cfd131042e366872bf599a315d this.move(MoverType.SELF, this.getDeltaMovement()); if (!this.onGround()) { -@@ -622,7 +676,7 @@ public abstract class AbstractMinecart extends VehicleEntity { +@@ -619,7 +673,7 @@ public abstract class AbstractMinecart extends VehicleEntity { if (d18 > 0.01D) { double d20 = 0.06D; @@ -15909,10 +15426,10 @@ index d514ec1e4cbdc579c3a61533998437903afdc8b6..eb5bd5cfd131042e366872bf599a315d Vec3 vec3d5 = this.getDeltaMovement(); double d21 = vec3d5.x; diff --git a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -index db6aa75d642f4a7258f197933671907faf79c8f2..81e0930acccd014e977b88d22e10346627f0edb0 100644 +index b068cff9b5aa457d65b679529956e8210296d799..105e2b7d7cd7c64a9164e4114476e44f29433f49 100644 --- a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java +++ b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -@@ -521,6 +521,7 @@ public class Boat extends VehicleEntity implements VariantHolder { +@@ -514,6 +514,7 @@ public class Boat extends VehicleEntity implements VariantHolder { if (f > 0.0F) { this.landFriction = f; @@ -15920,15 +15437,15 @@ index db6aa75d642f4a7258f197933671907faf79c8f2..81e0930acccd014e977b88d22e103466 return Boat.Status.ON_LAND; } else { return Boat.Status.IN_AIR; -@@ -967,7 +968,13 @@ public class Boat extends VehicleEntity implements VariantHolder { +@@ -962,7 +963,13 @@ public class Boat extends VehicleEntity implements VariantHolder { @Override public ItemStack getPickResult() { - return new ItemStack(this.getDropItem()); + // Purpur start + final ItemStack boat = new ItemStack(this.getDropItem()); -+ if (this.level().purpurConfig.persistentDroppableEntityDisplayNames && this.hasCustomName()) { -+ boat.setHoverName(this.getCustomName()); ++ if (!this.level().purpurConfig.persistentDroppableEntityDisplayNames) { ++ boat.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME, null); + } + return boat; + // Purpur end @@ -15936,21 +15453,20 @@ index db6aa75d642f4a7258f197933671907faf79c8f2..81e0930acccd014e977b88d22e103466 public static enum Type implements StringRepresentable { diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java -index c3448707fd8a632b457cc97b35d08a9c6933d5ee..e8079d126e6c0cf0b15c01afb6498922ee05964c 100644 +index b89860d451d92ddda64b7e4144542b7fc5fd86f0..dd72d6a79139ff33f26a32b71283ce0b8d084ecc 100644 --- a/src/main/java/net/minecraft/world/food/FoodData.java +++ b/src/main/java/net/minecraft/world/food/FoodData.java -@@ -33,8 +33,10 @@ public class FoodData { - // CraftBukkit end +@@ -38,7 +38,9 @@ public class FoodData { + } public void eat(int food, float saturationModifier) { + int oldValue = this.foodLevel; // Purpur - this.foodLevel = Math.min(food + this.foodLevel, 20); - this.saturationLevel = Math.min(this.saturationLevel + (float) food * saturationModifier * 2.0F, (float) this.foodLevel); + this.add(food, FoodConstants.saturationByModifier(food, saturationModifier)); + if (this.entityhuman.level().purpurConfig.playerBurpWhenFull && this.foodLevel == 20 && oldValue < 20) this.entityhuman.burpDelay = this.entityhuman.level().purpurConfig.playerBurpDelay; // Purpur } - public void eat(Item item, ItemStack stack) { -@@ -100,7 +102,7 @@ public class FoodData { + public void eat(ItemStack stack) { +@@ -105,7 +107,7 @@ public class FoodData { ++this.tickTimer; if (this.tickTimer >= this.starvationRate) { // CraftBukkit - add regen rate manipulation if (player.getHealth() > 10.0F || enumdifficulty == Difficulty.HARD || player.getHealth() > 1.0F && enumdifficulty == Difficulty.NORMAL) { @@ -15959,53 +15475,8 @@ index c3448707fd8a632b457cc97b35d08a9c6933d5ee..e8079d126e6c0cf0b15c01afb6498922 } this.tickTimer = 0; -diff --git a/src/main/java/net/minecraft/world/food/FoodProperties.java b/src/main/java/net/minecraft/world/food/FoodProperties.java -index 9967ba762567631f2bdb1e4f8fe16a13ea927b46..6c945ae8fe8b1517e312c688f829fab41f12d9f4 100644 ---- a/src/main/java/net/minecraft/world/food/FoodProperties.java -+++ b/src/main/java/net/minecraft/world/food/FoodProperties.java -@@ -2,15 +2,22 @@ package net.minecraft.world.food; - - import com.google.common.collect.Lists; - import com.mojang.datafixers.util.Pair; -+ -+import java.util.ArrayList; - import java.util.List; - import net.minecraft.world.effect.MobEffectInstance; - - public class FoodProperties { -- private final int nutrition; -- private final float saturationModifier; -- private final boolean isMeat; -- private final boolean canAlwaysEat; -- private final boolean fastFood; -+ // Purpur start -+ private int nutrition; public void setNutrition(int nutrition) { this.nutrition = nutrition; } -+ private float saturationModifier; public void setSaturationModifier(float saturation) { this.saturationModifier = saturation; } -+ private boolean isMeat; public void setIsMeat(boolean isMeat) { this.isMeat = isMeat; } -+ private boolean canAlwaysEat; public void setCanAlwaysEat(boolean canAlwaysEat) { this.canAlwaysEat = canAlwaysEat; } -+ private boolean fastFood; public void setFastFood(boolean isFastFood) { this.fastFood = isFastFood; } -+ public FoodProperties copy() { -+ return new FoodProperties(this.nutrition, this.saturationModifier, this.isMeat, this.canAlwaysEat, this.fastFood, new ArrayList<>(this.effects)); -+ } -+ // Purpur end - private final List> effects; - - FoodProperties(int hunger, float saturationModifier, boolean meat, boolean alwaysEdible, boolean snack, List> statusEffects) { -diff --git a/src/main/java/net/minecraft/world/food/Foods.java b/src/main/java/net/minecraft/world/food/Foods.java -index 4569cf30b33167a415256a8542820557ad38f89e..9c65eefa855f3622b6c9ae2a698cf332ba225c7f 100644 ---- a/src/main/java/net/minecraft/world/food/Foods.java -+++ b/src/main/java/net/minecraft/world/food/Foods.java -@@ -4,6 +4,8 @@ import net.minecraft.world.effect.MobEffectInstance; - import net.minecraft.world.effect.MobEffects; - - public class Foods { -+ public static final java.util.Map ALL_PROPERTIES = new java.util.HashMap<>(); // Purpur -+ public static final java.util.Map DEFAULT_PROPERTIES = new java.util.HashMap<>(); // Purpur - public static final FoodProperties APPLE = new FoodProperties.Builder().nutrition(4).saturationMod(0.3F).build(); - public static final FoodProperties BAKED_POTATO = new FoodProperties.Builder().nutrition(5).saturationMod(0.6F).build(); - public static final FoodProperties BEEF = new FoodProperties.Builder().nutrition(3).saturationMod(0.3F).meat().build(); diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -index 48f634a7521d31c1e9dfd3cfc83139d428dbd37a..fa185a8145843edf44fc0aeedb6c36b2b13263ae 100644 +index 32910f677b0522ac8ec513fa0d00b714b52cfae4..f85eef14b91a0ada1f6f4b13ab3966f051ff92d3 100644 --- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java @@ -76,6 +76,7 @@ public abstract class AbstractContainerMenu { @@ -16036,10 +15507,10 @@ index 1af7e1548f0648890a1ef2fc0ff4e4c3a56c947c..decea1697c075e7549ccc7501c8e5935 } else if (this.isFuel(itemstack1)) { if (!this.moveItemStackTo(itemstack1, 1, 2, false)) { diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -index cab3e0ba471c93764b5949ad68a0f2cce4d00099..2913d69fcff4b6df68586146b7323cea33eba74b 100644 +index 2bd91b48eaa06f85a5b9b1ae052c70e966ae8e4c..2747f04e657154362af55eef1dd50455e02af371 100644 --- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java +++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -@@ -23,6 +23,13 @@ import org.slf4j.Logger; +@@ -25,6 +25,13 @@ import org.slf4j.Logger; import org.bukkit.craftbukkit.inventory.CraftInventoryView; // CraftBukkit end @@ -16053,7 +15524,7 @@ index cab3e0ba471c93764b5949ad68a0f2cce4d00099..2913d69fcff4b6df68586146b7323cea public class AnvilMenu extends ItemCombinerMenu { public static final int INPUT_SLOT = 0; -@@ -51,6 +58,8 @@ public class AnvilMenu extends ItemCombinerMenu { +@@ -53,6 +60,8 @@ public class AnvilMenu extends ItemCombinerMenu { public int maximumRepairCost = 40; private CraftInventoryView bukkitEntity; // CraftBukkit end @@ -16062,12 +15533,12 @@ index cab3e0ba471c93764b5949ad68a0f2cce4d00099..2913d69fcff4b6df68586146b7323cea public AnvilMenu(int syncId, Inventory inventory) { this(syncId, inventory, ContainerLevelAccess.NULL); -@@ -78,12 +87,15 @@ public class AnvilMenu extends ItemCombinerMenu { +@@ -80,12 +89,15 @@ public class AnvilMenu extends ItemCombinerMenu { @Override protected boolean mayPickup(Player player, boolean present) { -- return (player.getAbilities().instabuild || player.experienceLevel >= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && present; // CraftBukkit - allow cost 0 like a free item -+ return (player.getAbilities().instabuild || player.experienceLevel >= this.cost.get()) && (bypassCost || this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST) && present; // CraftBukkit - allow cost 0 like a free item // Purpur +- return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && present; // CraftBukkit - allow cost 0 like a free item ++ return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && (bypassCost || this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST) && present; // CraftBukkit - allow cost 0 like a free item // Purpur } @Override @@ -16079,7 +15550,7 @@ index cab3e0ba471c93764b5949ad68a0f2cce4d00099..2913d69fcff4b6df68586146b7323cea player.giveExperienceLevels(-this.cost.get()); } -@@ -134,6 +146,12 @@ public class AnvilMenu extends ItemCombinerMenu { +@@ -136,6 +148,12 @@ public class AnvilMenu extends ItemCombinerMenu { @Override public void createResult() { @@ -16092,44 +15563,53 @@ index cab3e0ba471c93764b5949ad68a0f2cce4d00099..2913d69fcff4b6df68586146b7323cea ItemStack itemstack = this.inputSlots.getItem(0); this.cost.set(1); +@@ -143,7 +161,7 @@ public class AnvilMenu extends ItemCombinerMenu { + long j = 0L; + byte b0 = 0; + +- if (!itemstack.isEmpty() && EnchantmentHelper.canStoreEnchantments(itemstack)) { ++ if (!itemstack.isEmpty() && canDoUnsafeEnchants || EnchantmentHelper.canStoreEnchantments(itemstack)) { // Purpur + ItemStack itemstack1 = itemstack.copy(); + ItemStack itemstack2 = this.inputSlots.getItem(1); + ItemEnchantments.Mutable itemenchantments_a = new ItemEnchantments.Mutable(EnchantmentHelper.getEnchantmentsForCrafting(itemstack1)); @@ -210,7 +228,8 @@ public class AnvilMenu extends ItemCombinerMenu { - int i2 = (Integer) map1.get(enchantment); + int i2 = entry.getIntValue(); - i2 = l1 == i2 ? i2 + 1 : Math.max(i2, l1); -- boolean flag3 = enchantment.canEnchant(itemstack); -+ boolean flag3 = canDoUnsafeEnchants || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants && org.purpurmc.purpur.PurpurConfig.allowInapplicableEnchants) || enchantment.canEnchant(itemstack); // Purpur -+ boolean flag4 = true; // Purpur + i2 = l1 == i2 ? i2 + 1 : Math.max(i2, l1); +- boolean flag3 = enchantment.canEnchant(itemstack); ++ boolean flag3 = canDoUnsafeEnchants || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants && org.purpurmc.purpur.PurpurConfig.allowInapplicableEnchants) || enchantment.canEnchant(itemstack); // Purpur ++ boolean flag4 = true; // Purpur - if (this.player.getAbilities().instabuild || itemstack.is(Items.ENCHANTED_BOOK)) { - flag3 = true; + if (this.player.getAbilities().instabuild || itemstack.is(Items.ENCHANTED_BOOK)) { + flag3 = true; @@ -222,16 +241,20 @@ public class AnvilMenu extends ItemCombinerMenu { - Enchantment enchantment1 = (Enchantment) iterator1.next(); + Holder holder1 = (Holder) iterator1.next(); - if (enchantment1 != enchantment && !enchantment.isCompatibleWith(enchantment1)) { -- flag3 = false; -+ flag4 = canDoUnsafeEnchants || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants && org.purpurmc.purpur.PurpurConfig.allowIncompatibleEnchants); // Purpur flag3 -> flag4 + if (!holder1.equals(holder) && !enchantment.isCompatibleWith((Enchantment) holder1.value())) { +- flag3 = false; ++ flag4 = canDoUnsafeEnchants || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants && org.purpurmc.purpur.PurpurConfig.allowIncompatibleEnchants); // Purpur flag3 -> flag4 + if (!flag4 && org.purpurmc.purpur.PurpurConfig.replaceIncompatibleEnchants) { + iterator1.remove(); + flag4 = true; + } - ++i; - } + ++i; + } + } + +- if (!flag3) { ++ if (!flag3 || !flag4) { // Purpur + flag2 = true; + } else { + flag1 = true; +- if (i2 > enchantment.getMaxLevel()) { ++ if ((!org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants || !org.purpurmc.purpur.PurpurConfig.allowHigherEnchantsLevels) && i2 > enchantment.getMaxLevel()) { // Purpur + i2 = enchantment.getMaxLevel(); } -- if (!flag3) { -+ if (!flag3 || !flag4) { // Purpur - flag2 = true; - } else { - flag1 = true; -- if (i2 > enchantment.getMaxLevel()) { -+ if ((!org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants || !org.purpurmc.purpur.PurpurConfig.allowHigherEnchantsLevels) && i2 > enchantment.getMaxLevel()) { // Purpur - i2 = enchantment.getMaxLevel(); - } - -@@ -276,6 +299,54 @@ public class AnvilMenu extends ItemCombinerMenu { +@@ -261,6 +284,54 @@ public class AnvilMenu extends ItemCombinerMenu { if (!this.itemName.equals(itemstack.getHoverName().getString())) { - b1 = 1; - i += b1; + b0 = 1; + i += b0; + // Purpur start + if (this.player != null) { + org.bukkit.craftbukkit.entity.CraftHumanEntity player = this.player.getBukkitEntity(); @@ -16174,20 +15654,19 @@ index cab3e0ba471c93764b5949ad68a0f2cce4d00099..2913d69fcff4b6df68586146b7323cea + if (removeItalics) { + component = component.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); + } -+ itemstack1.setHoverName(io.papermc.paper.adventure.PaperAdventure.asVanilla(component)); ++ itemstack1.set(DataComponents.CUSTOM_NAME, io.papermc.paper.adventure.PaperAdventure.asVanilla(component)); + } + else + // Purpur end - itemstack1.setHoverName(Component.literal(this.itemName)); + itemstack1.set(DataComponents.CUSTOM_NAME, Component.literal(this.itemName)); } - } else if (itemstack.hasCustomHoverName()) { -@@ -293,6 +364,13 @@ public class AnvilMenu extends ItemCombinerMenu { + } else if (itemstack.has(DataComponents.CUSTOM_NAME)) { +@@ -280,6 +351,12 @@ public class AnvilMenu extends ItemCombinerMenu { this.cost.set(this.maximumRepairCost - 1); // CraftBukkit } + // Purpur start + if (bypassCost && cost.get() >= maximumRepairCost) { -+ itemstack.addTagElement("Purpur.realCost", IntTag.valueOf(cost.get())); + cost.set(maximumRepairCost - 1); + } + // Purpur end @@ -16195,7 +15674,7 @@ index cab3e0ba471c93764b5949ad68a0f2cce4d00099..2913d69fcff4b6df68586146b7323cea if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit itemstack1 = ItemStack.EMPTY; } -@@ -315,11 +393,17 @@ public class AnvilMenu extends ItemCombinerMenu { +@@ -301,6 +378,12 @@ public class AnvilMenu extends ItemCombinerMenu { org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemstack1); // CraftBukkit this.sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client this.broadcastChanges(); @@ -16205,12 +15684,15 @@ index cab3e0ba471c93764b5949ad68a0f2cce4d00099..2913d69fcff4b6df68586146b7323cea + ((ServerPlayer) player).connection.send(new ClientboundContainerSetDataPacket(containerId, 0, cost.get())); + } + // Purpur end - } + } else { + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit + this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item +@@ -308,7 +391,7 @@ public class AnvilMenu extends ItemCombinerMenu { } public static int calculateIncreasedRepairCost(int cost) { -- return cost * 2 + 1; -+ return org.purpurmc.purpur.PurpurConfig.anvilCumulativeCost ? cost * 2 + 1 : 0; +- return (int) Math.min((long) cost * 2L + 1L, 2147483647L); ++ return org.purpurmc.purpur.PurpurConfig.anvilCumulativeCost ? (int) Math.min((long) cost * 2L + 1L, 2147483647L) : 0; } public boolean setItemName(String newItemName) { @@ -16250,23 +15732,23 @@ index 0dbfd23bbfc6ad203f048142f8c90ef741849fe1..9a80427d2bb470b6b1638e59aba57216 return new ChestMenu(MenuType.GENERIC_9x6, syncId, playerInventory, inventory, 6); } diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -index e6935b6632c7a7e07f4da459c95f564356242f98..1a686780e5aadcbdcfceb770ce8e283b38115209 100644 +index 5b3e33807e0e13480e3359c0cf067719e5749237..c3a644b0f8c7c5622acc9e1a496f95d432718806 100644 --- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java +++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -@@ -40,6 +40,12 @@ import org.bukkit.event.enchantment.PrepareItemEnchantEvent; +@@ -38,6 +38,12 @@ import org.bukkit.event.enchantment.PrepareItemEnchantEvent; import org.bukkit.entity.Player; // CraftBukkit end +// Purpur start +import net.minecraft.world.level.block.entity.BlockEntity; -+import net.minecraft.world.level.block.entity.EnchantmentTableBlockEntity; ++import net.minecraft.world.level.block.entity.EnchantingTableBlockEntity; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +// Purpur end + public class EnchantmentMenu extends AbstractContainerMenu { static final ResourceLocation EMPTY_SLOT_LAPIS_LAZULI = new ResourceLocation("item/empty_slot_lapis_lazuli"); -@@ -74,6 +80,22 @@ public class EnchantmentMenu extends AbstractContainerMenu { +@@ -72,6 +78,22 @@ public class EnchantmentMenu extends AbstractContainerMenu { return context.getLocation(); } // CraftBukkit end @@ -16279,7 +15761,7 @@ index e6935b6632c7a7e07f4da459c95f564356242f98..1a686780e5aadcbdcfceb770ce8e283b + if (who.getHandle().level().purpurConfig.enchantmentTableLapisPersists) { + access.execute((level, pos) -> { + BlockEntity blockEntity = level.getBlockEntity(pos); -+ if (blockEntity instanceof EnchantmentTableBlockEntity enchantmentTable) { ++ if (blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) { + enchantmentTable.setLapis(this.getItem(1).getCount()); + } + }); @@ -16289,7 +15771,7 @@ index e6935b6632c7a7e07f4da459c95f564356242f98..1a686780e5aadcbdcfceb770ce8e283b }; this.random = RandomSource.create(); this.enchantmentSeed = DataSlot.standalone(); -@@ -99,6 +121,17 @@ public class EnchantmentMenu extends AbstractContainerMenu { +@@ -97,6 +119,17 @@ public class EnchantmentMenu extends AbstractContainerMenu { } }); @@ -16297,7 +15779,7 @@ index e6935b6632c7a7e07f4da459c95f564356242f98..1a686780e5aadcbdcfceb770ce8e283b + access.execute((level, pos) -> { + if (level.purpurConfig.enchantmentTableLapisPersists) { + BlockEntity blockEntity = level.getBlockEntity(pos); -+ if (blockEntity instanceof EnchantmentTableBlockEntity enchantmentTable) { ++ if (blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) { + this.getSlot(1).set(new ItemStack(Items.LAPIS_LAZULI, enchantmentTable.getLapis())); + } + } @@ -16307,7 +15789,7 @@ index e6935b6632c7a7e07f4da459c95f564356242f98..1a686780e5aadcbdcfceb770ce8e283b int j; for (j = 0; j < 3; ++j) { -@@ -351,6 +384,7 @@ public class EnchantmentMenu extends AbstractContainerMenu { +@@ -332,6 +365,7 @@ public class EnchantmentMenu extends AbstractContainerMenu { public void removed(net.minecraft.world.entity.player.Player player) { super.removed(player); this.access.execute((world, blockposition) -> { @@ -16316,7 +15798,7 @@ index e6935b6632c7a7e07f4da459c95f564356242f98..1a686780e5aadcbdcfceb770ce8e283b }); } diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -index 23462de504932bd351b8dfacde514fe361343912..af99ce32872e079beb6ac1caf3a8ac4c3cae4648 100644 +index db9444dda248260372d96ce239a590e88a4c1142..1d181de9c8fd45b4d9f0230f80d5752ff5c1a432 100644 --- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java +++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java @@ -95,9 +95,11 @@ public class GrindstoneMenu extends AbstractContainerMenu { @@ -16333,54 +15815,120 @@ index 23462de504932bd351b8dfacde514fe361343912..af99ce32872e079beb6ac1caf3a8ac4c world.levelEvent(1042, blockposition, 0); @@ -130,7 +132,7 @@ public class GrindstoneMenu extends AbstractContainerMenu { - Enchantment enchantment = (Enchantment) entry.getKey(); - Integer integer = (Integer) entry.getValue(); + Enchantment enchantment = (Enchantment) ((Holder) entry.getKey()).value(); + int k = entry.getIntValue(); - if (!enchantment.isCurse()) { + if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(enchantment)) { // Purpur - j += enchantment.getMinCost(integer); + j += enchantment.getMinCost(k); } } -@@ -230,7 +232,7 @@ public class GrindstoneMenu extends AbstractContainerMenu { - Entry entry = (Entry) iterator.next(); - Enchantment enchantment = (Enchantment) entry.getKey(); +@@ -229,7 +231,7 @@ public class GrindstoneMenu extends AbstractContainerMenu { + Entry> entry = (Entry) iterator.next(); + Enchantment enchantment = (Enchantment) ((Holder) entry.getKey()).value(); -- if (!enchantment.isCurse() || EnchantmentHelper.getItemEnchantmentLevel(enchantment, itemstack2) == 0) { -+ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(enchantment) || EnchantmentHelper.getItemEnchantmentLevel(enchantment, itemstack2) == 0) { // Purpur - itemstack2.enchant(enchantment, (Integer) entry.getValue()); +- if (!enchantment.isCurse() || itemenchantments_a.getLevel(enchantment) == 0) { ++ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(enchantment) || itemenchantments_a.getLevel(enchantment) == 0) { // Purpur + itemenchantments_a.upgrade(enchantment, entry.getIntValue()); + } } - } -@@ -250,7 +252,7 @@ public class GrindstoneMenu extends AbstractContainerMenu { - } - - Map map = (Map) EnchantmentHelper.getEnchantments(item).entrySet().stream().filter((entry) -> { -- return ((Enchantment) entry.getKey()).isCurse(); -+ return org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains((Enchantment) entry.getKey()); // Purpur - }).collect(Collectors.toMap(Entry::getKey, Entry::getValue)); - - EnchantmentHelper.setEnchantments(map, itemstack1); -@@ -266,6 +268,20 @@ public class GrindstoneMenu extends AbstractContainerMenu { - itemstack1.setRepairCost(AnvilMenu.calculateIncreasedRepairCost(itemstack1.getBaseRepairCost())); - } - -+ // Purpur start -+ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveAttributes && itemstack1.getTag() != null) { -+ for (String key : itemstack1.getTag().getAllKeys()) { -+ if (!key.equals("display")) { -+ itemstack1.getTag().remove(key); -+ } -+ } -+ } -+ -+ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveDisplay && itemstack1.getTag() != null) { -+ itemstack1.getTag().remove("display"); -+ } -+ // Purpur end -+ - return itemstack1; +@@ -237,10 +239,70 @@ public class GrindstoneMenu extends AbstractContainerMenu { + }); } -@@ -327,7 +343,9 @@ public class GrindstoneMenu extends AbstractContainerMenu { ++ // Purpur start ++ private java.util.List> GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST = java.util.List.of( ++ // DataComponents.MAX_STACK_SIZE, ++ // DataComponents.DAMAGE, ++ // DataComponents.BLOCK_STATE, ++ DataComponents.CUSTOM_DATA, ++ // DataComponents.MAX_DAMAGE, ++ // DataComponents.UNBREAKABLE, ++ // DataComponents.CUSTOM_NAME, ++ // DataComponents.ITEM_NAME, ++ // DataComponents.LORE, ++ // DataComponents.RARITY, ++ // DataComponents.ENCHANTMENTS, ++ // DataComponents.CAN_PLACE_ON, ++ // DataComponents.CAN_BREAK, ++ DataComponents.ATTRIBUTE_MODIFIERS, ++ DataComponents.CUSTOM_MODEL_DATA, ++ // DataComponents.HIDE_ADDITIONAL_TOOLTIP, ++ // DataComponents.HIDE_TOOLTIP, ++ // DataComponents.REPAIR_COST, ++ // DataComponents.CREATIVE_SLOT_LOCK, ++ // DataComponents.ENCHANTMENT_GLINT_OVERRIDE, ++ // DataComponents.INTANGIBLE_PROJECTILE, ++ // DataComponents.FOOD, ++ // DataComponents.FIRE_RESISTANT, ++ // DataComponents.TOOL, ++ // DataComponents.STORED_ENCHANTMENTS, ++ DataComponents.DYED_COLOR, ++ // DataComponents.MAP_COLOR, ++ // DataComponents.MAP_ID, ++ // DataComponents.MAP_DECORATIONS, ++ // DataComponents.MAP_POST_PROCESSING, ++ // DataComponents.CHARGED_PROJECTILES, ++ // DataComponents.BUNDLE_CONTENTS, ++ // DataComponents.POTION_CONTENTS, ++ DataComponents.SUSPICIOUS_STEW_EFFECTS ++ // DataComponents.WRITABLE_BOOK_CONTENT, ++ // DataComponents.WRITTEN_BOOK_CONTENT, ++ // DataComponents.TRIM, ++ // DataComponents.DEBUG_STICK_STATE, ++ // DataComponents.ENTITY_DATA, ++ // DataComponents.BUCKET_ENTITY_DATA, ++ // DataComponents.BLOCK_ENTITY_DATA, ++ // DataComponents.INSTRUMENT, ++ // DataComponents.OMINOUS_BOTTLE_AMPLIFIER, ++ // DataComponents.RECIPES, ++ // DataComponents.LODESTONE_TRACKER, ++ // DataComponents.FIREWORK_EXPLOSION, ++ // DataComponents.FIREWORKS, ++ // DataComponents.PROFILE, ++ // DataComponents.NOTE_BLOCK_SOUND, ++ // DataComponents.BANNER_PATTERNS, ++ // DataComponents.BASE_COLOR, ++ // DataComponents.POT_DECORATIONS, ++ // DataComponents.CONTAINER, ++ // DataComponents.BEES, ++ // DataComponents.LOCK, ++ // DataComponents.CONTAINER_LOOT, ++ ); ++ // Purpur end + private ItemStack removeNonCursesFrom(ItemStack item) { + ItemEnchantments itemenchantments = EnchantmentHelper.updateEnchantments(item, (itemenchantments_a) -> { + itemenchantments_a.removeIf((holder) -> { +- return !((Enchantment) holder.value()).isCurse(); ++ return !org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value()); + }); + }); + +@@ -255,6 +317,23 @@ public class GrindstoneMenu extends AbstractContainerMenu { + } + + item.set(DataComponents.REPAIR_COST, i); ++ ++ // Purpur start ++ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder(); ++ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveAttributes) { ++ item.getComponents().forEach(typedDataComponent -> { ++ if (GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST.contains(typedDataComponent.type())) { ++ builder.remove(typedDataComponent.type()); ++ } ++ }); ++ } ++ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveDisplay) { ++ builder.remove(DataComponents.CUSTOM_NAME); ++ builder.remove(DataComponents.LORE); ++ } ++ item.applyComponents(builder.build()); ++ // Purpur end ++ + return item; + } + +@@ -316,7 +395,9 @@ public class GrindstoneMenu extends AbstractContainerMenu { return ItemStack.EMPTY; } @@ -16391,10 +15939,10 @@ index 23462de504932bd351b8dfacde514fe361343912..af99ce32872e079beb6ac1caf3a8ac4c return itemstack; diff --git a/src/main/java/net/minecraft/world/inventory/InventoryMenu.java b/src/main/java/net/minecraft/world/inventory/InventoryMenu.java -index 9af1da3858d6cf79b8bfaf99dde1370ccc50d023..1acb41fab25bdbc4109913b111dbe3b0e106af3f 100644 +index 9992599dbe4f4a430e822a44b03c00505abfbfaf..3fea9339420aa38b303ccf6c154aec246e617b5b 100644 --- a/src/main/java/net/minecraft/world/inventory/InventoryMenu.java +++ b/src/main/java/net/minecraft/world/inventory/InventoryMenu.java -@@ -95,7 +95,7 @@ public class InventoryMenu extends RecipeBookMenu { +@@ -97,7 +97,7 @@ public class InventoryMenu extends RecipeBookMenu { public boolean mayPickup(Player playerEntity) { ItemStack itemstack = this.getItem(); @@ -16404,7 +15952,7 @@ index 9af1da3858d6cf79b8bfaf99dde1370ccc50d023..1acb41fab25bdbc4109913b111dbe3b0 @Override diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -index 62e1b7096fa659778b737b3d520389e73138dc5d..3756de835ea87e3a4fb87cbf77365ffd87957ea9 100644 +index 7de5e47f9a54263734eeef855a2dc07ef64d30ea..7215af6cc91f48b040c23c54536d4aac8d293497 100644 --- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java +++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java @@ -178,7 +178,9 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { @@ -16418,10 +15966,10 @@ index 62e1b7096fa659778b737b3d520389e73138dc5d..3756de835ea87e3a4fb87cbf77365ffd return itemstack; diff --git a/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java b/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java -index 4703f23316f82a1a942907b46d2d6dcb7d70ec37..162798f57a05b78121fa6c4fadf5adee80fbe221 100644 +index a15d5ff872dbd77f3c3145e0328f3d02e431ff8c..1dcf36d502990d32fc4cd3ea69c3ea334baed69a 100644 --- a/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java +++ b/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java -@@ -30,11 +30,18 @@ public class PlayerEnderChestContainer extends SimpleContainer { +@@ -31,11 +31,18 @@ public class PlayerEnderChestContainer extends SimpleContainer { } public PlayerEnderChestContainer(Player owner) { @@ -16442,10 +15990,10 @@ index 4703f23316f82a1a942907b46d2d6dcb7d70ec37..162798f57a05b78121fa6c4fadf5adee this.activeChest = blockEntity; } diff --git a/src/main/java/net/minecraft/world/item/ArmorItem.java b/src/main/java/net/minecraft/world/item/ArmorItem.java -index 6b81be03f87967124b046708557e05d519aa79e4..b47cc957f9e4936b15b80a6f685ddddb5b289298 100644 +index 786e4a8700cb84b16dd9b8892a0d1d5803924d81..b108ca4c7900ccf6a14ebea01c21c103459054f8 100644 --- a/src/main/java/net/minecraft/world/item/ArmorItem.java +++ b/src/main/java/net/minecraft/world/item/ArmorItem.java -@@ -67,7 +67,7 @@ public class ArmorItem extends Item implements Equipable { +@@ -69,7 +69,7 @@ public class ArmorItem extends Item implements Equipable { return false; } else { LivingEntity entityliving = (LivingEntity) list.get(0); @@ -16455,7 +16003,7 @@ index 6b81be03f87967124b046708557e05d519aa79e4..b47cc957f9e4936b15b80a6f685ddddb // CraftBukkit start Level world = pointer.level(); diff --git a/src/main/java/net/minecraft/world/item/ArmorStandItem.java b/src/main/java/net/minecraft/world/item/ArmorStandItem.java -index 7cffc64573008502bdd14ae4906fe51166b12fb3..1feafdbb48cf760cb6ebf95d5be2c32bdb1ad44f 100644 +index 1634a7d5ff06583408cf2f02f2b5f90931b1e02a..dfe8473a880cbddfc3ac6a9c97f1a500624eeb38 100644 --- a/src/main/java/net/minecraft/world/item/ArmorStandItem.java +++ b/src/main/java/net/minecraft/world/item/ArmorStandItem.java @@ -58,6 +58,14 @@ public class ArmorStandItem extends Item { @@ -16463,21 +16011,21 @@ index 7cffc64573008502bdd14ae4906fe51166b12fb3..1feafdbb48cf760cb6ebf95d5be2c32b } // CraftBukkit end + // Purpur start -+ if (world.purpurConfig.persistentDroppableEntityDisplayNames && itemstack.hasCustomHoverName()) { -+ entityarmorstand.setCustomName(itemstack.getHoverName()); -+ if (world.purpurConfig.armorstandSetNameVisible) { -+ entityarmorstand.setCustomNameVisible(true); -+ } ++ if (!world.purpurConfig.persistentDroppableEntityDisplayNames) { ++ entityarmorstand.setCustomName(null); ++ } ++ if (world.purpurConfig.armorstandSetNameVisible) { ++ entityarmorstand.setCustomNameVisible(true); + } + // Purpur end worldserver.addFreshEntityWithPassengers(entityarmorstand); world.playSound((Player) null, entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F); entityarmorstand.gameEvent(GameEvent.ENTITY_PLACE, context.getPlayer()); diff --git a/src/main/java/net/minecraft/world/item/AxeItem.java b/src/main/java/net/minecraft/world/item/AxeItem.java -index 4f8689e8cbc8b6b9f44168126b95cc864a383c9e..b05bb4caf57965b82d841f52d6ea27985a5efc84 100644 +index 9fd2d97ff0e05578a3e6a0b86dc1974691845c5d..58343722399404530d497648155dbc254d6a865a 100644 --- a/src/main/java/net/minecraft/world/item/AxeItem.java +++ b/src/main/java/net/minecraft/world/item/AxeItem.java -@@ -55,13 +55,15 @@ public class AxeItem extends DiggerItem { +@@ -56,13 +56,15 @@ public class AxeItem extends DiggerItem { Level level = context.getLevel(); BlockPos blockPos = context.getClickedPos(); Player player = context.getPlayer(); @@ -16495,7 +16043,7 @@ index 4f8689e8cbc8b6b9f44168126b95cc864a383c9e..b05bb4caf57965b82d841f52d6ea2798 return InteractionResult.PASS; } // Paper end -@@ -69,32 +71,41 @@ public class AxeItem extends DiggerItem { +@@ -70,32 +72,41 @@ public class AxeItem extends DiggerItem { CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack); } @@ -16511,7 +16059,7 @@ index 4f8689e8cbc8b6b9f44168126b95cc864a383c9e..b05bb4caf57965b82d841f52d6ea2798 + level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, state)); + // Purpur end if (player != null) { - itemStack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(context.getHand())); + itemStack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(context.getHand())); } - return InteractionResult.sidedSuccess(level.isClientSide); @@ -16549,108 +16097,71 @@ index 4f8689e8cbc8b6b9f44168126b95cc864a383c9e..b05bb4caf57965b82d841f52d6ea2798 return optional3; } else { diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java -index 8d2c0accadaf0c5d28e7db6e62a05f6c619cf02f..f33fcd7bca6f315c4b4cf1f5063f4772790ad20d 100644 +index 96fb69ec6db2e7c8c728435f0c537b076259b2fb..2649188930653610b8aaaeb18797c80879cd572a 100644 --- a/src/main/java/net/minecraft/world/item/BlockItem.java +++ b/src/main/java/net/minecraft/world/item/BlockItem.java -@@ -152,7 +152,24 @@ public class BlockItem extends Item { - } +@@ -219,6 +219,7 @@ public class BlockItem extends Item { - protected boolean updateCustomBlockEntityTag(BlockPos pos, Level world, @Nullable Player player, ItemStack stack, BlockState state) { -- return BlockItem.updateCustomBlockEntityTag(world, player, pos, stack); -+ // Purpur start -+ boolean handled = updateCustomBlockEntityTag(world, player, pos, stack); -+ if (world.purpurConfig.persistentTileEntityDisplayNames && stack.hasTag()) { -+ CompoundTag display = stack.getTagElement("display"); -+ if (display != null) { -+ BlockEntity blockEntity = world.getBlockEntity(pos); -+ if (blockEntity != null) { -+ if (display.contains("Name", 8)) { -+ blockEntity.setPersistentDisplayName(display.getString("Name")); -+ } -+ if (display.contains("Lore", 9)) { -+ blockEntity.setPersistentLore(display.getList("Lore", 8)); -+ } -+ } -+ } -+ } -+ return handled; -+ // Purpur end - } + if (tileentity != null) { + if (!world.isClientSide && tileentity.onlyOpCanSetNbt() && (player == null || !(player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place"))))) { // Spigot - add permission ++ if (!(!world.isClientSide && world.purpurConfig.silkTouchEnabled && tileentity instanceof net.minecraft.world.level.block.entity.SpawnerBlockEntity && player.getBukkitEntity().hasPermission("purpur.drop.spawners"))) + return false; + } - @Nullable -@@ -287,7 +304,7 @@ public class BlockItem extends Item { +@@ -259,6 +260,7 @@ public class BlockItem extends Item { + ItemContainerContents itemcontainercontents = (ItemContainerContents) entity.getItem().set(DataComponents.CONTAINER, ItemContainerContents.EMPTY); - @Override - public void onDestroyed(ItemEntity entity) { -- if (this.block instanceof ShulkerBoxBlock) { -+ if (this.block instanceof ShulkerBoxBlock && entity.level().purpurConfig.shulkerBoxItemDropContentsWhenDestroyed) { - ItemStack itemstack = entity.getItem(); - CompoundTag nbttagcompound = BlockItem.getBlockEntityData(itemstack); + if (itemcontainercontents != null) { ++ if (entity.level().purpurConfig.shulkerBoxItemDropContentsWhenDestroyed && entity.getItem().is(Items.SHULKER_BOX)) // Purpur + ItemUtils.onContainerDestroyed(entity, itemcontainercontents.nonEmptyItemsCopy()); + } diff --git a/src/main/java/net/minecraft/world/item/BoatItem.java b/src/main/java/net/minecraft/world/item/BoatItem.java -index 67a5a201d0b26ca7b27e6d0c3ffb9f8b6e16bce0..ec3d60b561de45349b705b7f14592be930af4b91 100644 +index eb74d45ad458b80cf8455297c3bc550186adaea3..ef01856c487e4ab982996e01537618233592ac32 100644 --- a/src/main/java/net/minecraft/world/item/BoatItem.java +++ b/src/main/java/net/minecraft/world/item/BoatItem.java -@@ -71,6 +71,11 @@ public class BoatItem extends Item { +@@ -72,6 +72,11 @@ public class BoatItem extends Item { entityboat.setVariant(this.type); entityboat.setYRot(user.getYRot()); + // Purpur start -+ if (world.purpurConfig.persistentDroppableEntityDisplayNames && itemstack.hasCustomHoverName()) { -+ entityboat.setCustomName(itemstack.getHoverName()); ++ if (!world.purpurConfig.persistentDroppableEntityDisplayNames) { ++ entityboat.setCustomName(null); + } + // Purpur end if (!world.noCollision(entityboat, entityboat.getBoundingBox())) { return InteractionResultHolder.fail(itemstack); } else { diff --git a/src/main/java/net/minecraft/world/item/BowItem.java b/src/main/java/net/minecraft/world/item/BowItem.java -index 08d597db1a5345a343777a01427655e6bf2c926b..d45a2f49c82d00801578c34e5f5277fc5e82be87 100644 +index 5ca843df5b4caa668953e5e36a9b20fabeb35046..ff39d3614f360918d74b54b817bc227f89d34c9c 100644 --- a/src/main/java/net/minecraft/world/item/BowItem.java +++ b/src/main/java/net/minecraft/world/item/BowItem.java -@@ -38,13 +38,13 @@ public class BowItem extends ProjectileWeaponItem implements Vanishable { - float f = BowItem.getPowerForTime(j); +@@ -29,9 +29,9 @@ public class BowItem extends ProjectileWeaponItem { + int i = this.getUseDuration(stack) - remainingUseTicks; + float f = getPowerForTime(i); + if (!((double)f < 0.1)) { +- List list = draw(stack, itemStack, player); ++ List list = draw(stack, itemStack, player, !((itemStack.is(Items.ARROW) && world.purpurConfig.infinityWorksWithNormalArrows) || (itemStack.is(Items.TIPPED_ARROW) && world.purpurConfig.infinityWorksWithTippedArrows) || (itemStack.is(Items.SPECTRAL_ARROW) && world.purpurConfig.infinityWorksWithSpectralArrows))); + if (!world.isClientSide() && !list.isEmpty()) { +- this.shoot(world, player, player.getUsedItemHand(), stack, list, f * 3.0F, 1.0F, f == 1.0F, null); ++ this.shoot(world, player, player.getUsedItemHand(), stack, list, f * 3.0F, (float) world.purpurConfig.bowProjectileOffset, f == 1.0F, null); // Purpur + } - if ((double) f >= 0.1D) { -- boolean flag1 = flag && itemstack1.is(Items.ARROW); -+ boolean flag1 = flag && ((itemstack1.is(Items.ARROW) && world.purpurConfig.infinityWorksWithNormalArrows) || (itemstack1.is(Items.TIPPED_ARROW) && world.purpurConfig.infinityWorksWithTippedArrows) || (itemstack1.is(Items.SPECTRAL_ARROW) && world.purpurConfig.infinityWorksWithSpectralArrows)); // Purpur if (!world.isClientSide) { - - if (!world.isClientSide) { - ArrowItem itemarrow = (ArrowItem) (itemstack1.getItem() instanceof ArrowItem ? itemstack1.getItem() : Items.ARROW); - AbstractArrow entityarrow = itemarrow.createArrow(world, itemstack1, entityhuman); - -- entityarrow.shootFromRotation(entityhuman, entityhuman.getXRot(), entityhuman.getYRot(), 0.0F, f * 3.0F, 1.0F); -+ entityarrow.shootFromRotation(entityhuman, entityhuman.getXRot(), entityhuman.getYRot(), 0.0F, f * 3.0F, (float) world.purpurConfig.bowProjectileOffset); // Purpur - if (f == 1.0F) { - entityarrow.setCritArrow(true); - } -@@ -64,6 +64,13 @@ public class BowItem extends ProjectileWeaponItem implements Vanishable { - if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.FLAMING_ARROWS, stack) > 0) { - entityarrow.setSecondsOnFire(100); - } -+ // Purpur start -+ int lootingLevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.MOB_LOOTING, stack); -+ -+ if (lootingLevel > 0) { -+ entityarrow.setLootingLevel(lootingLevel); -+ } -+ // Purpur end - // CraftBukkit start - org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(entityhuman, stack, itemstack1, entityarrow, entityhuman.getUsedItemHand(), f, !flag1); - if (event.isCancelled()) { -@@ -132,7 +139,7 @@ public class BowItem extends ProjectileWeaponItem implements Vanishable { - ItemStack itemstack = user.getItemInHand(hand); - boolean flag = !user.getProjectile(itemstack).isEmpty(); - -- if (!user.getAbilities().instabuild && !flag) { -+ if (!(world.purpurConfig.infinityWorksWithoutArrows && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY_ARROWS, itemstack) > 0) && !user.getAbilities().instabuild && !flag) { // Purpur - return InteractionResultHolder.fail(itemstack); + world.playSound( +@@ -81,7 +81,7 @@ public class BowItem extends ProjectileWeaponItem { + public InteractionResultHolder use(Level world, Player user, InteractionHand hand) { + ItemStack itemStack = user.getItemInHand(hand); + boolean bl = !user.getProjectile(itemStack).isEmpty(); +- if (!user.hasInfiniteMaterials() && !bl) { ++ if (!(world.purpurConfig.infinityWorksWithoutArrows && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, itemStack) > 0) && !user.hasInfiniteMaterials() && !bl) { + return InteractionResultHolder.fail(itemStack); } else { user.startUsingItem(hand); diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java -index 6371f326fc86cfc53e39bf8ed13b646f7705fbbc..3dec0c5fc8dece5341634eaf8e94fe1964bf4038 100644 +index 49557d6f22c5725c663a231deab019d4f6fe95fa..046652e8f9c5dcdf7c90acb9391214cac46bd7d8 100644 --- a/src/main/java/net/minecraft/world/item/BucketItem.java +++ b/src/main/java/net/minecraft/world/item/BucketItem.java -@@ -195,7 +195,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { +@@ -194,7 +194,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { // CraftBukkit end if (!flag2) { return movingobjectpositionblock != null && this.emptyContents(entityhuman, world, movingobjectpositionblock.getBlockPos().relative(movingobjectpositionblock.getDirection()), (BlockHitResult) null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit @@ -16659,7 +16170,7 @@ index 6371f326fc86cfc53e39bf8ed13b646f7705fbbc..3dec0c5fc8dece5341634eaf8e94fe19 int i = blockposition.getX(); int j = blockposition.getY(); int k = blockposition.getZ(); -@@ -203,7 +203,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { +@@ -202,7 +202,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { world.playSound(entityhuman, blockposition, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); for (int l = 0; l < 8; ++l) { @@ -16669,56 +16180,32 @@ index 6371f326fc86cfc53e39bf8ed13b646f7705fbbc..3dec0c5fc8dece5341634eaf8e94fe19 return true; diff --git a/src/main/java/net/minecraft/world/item/CrossbowItem.java b/src/main/java/net/minecraft/world/item/CrossbowItem.java -index f3a428f80c265639250114498b10067b4bf1ada1..211d8e59a9b3460b346e5f8cf581df70b05d1b8f 100644 +index 0f6504a7160bc304b3af554f8740c65e2987cd37..9a8092602c96ddd77c8e6fcfe7a6f5ed733023a2 100644 --- a/src/main/java/net/minecraft/world/item/CrossbowItem.java +++ b/src/main/java/net/minecraft/world/item/CrossbowItem.java -@@ -64,7 +64,7 @@ public class CrossbowItem extends ProjectileWeaponItem implements Vanishable { - ItemStack itemstack = user.getItemInHand(hand); - - if (CrossbowItem.isCharged(itemstack)) { -- CrossbowItem.performShooting(world, user, hand, itemstack, CrossbowItem.getShootingPower(itemstack), 1.0F); -+ CrossbowItem.performShooting(world, user, hand, itemstack, CrossbowItem.getShootingPower(itemstack), (float) world.purpurConfig.crossbowProjectileOffset); // Purpur - CrossbowItem.setCharged(itemstack, false); - return InteractionResultHolder.consume(itemstack); - } else if (!user.getProjectile(itemstack).isEmpty()) { -@@ -114,7 +114,7 @@ public class CrossbowItem extends ProjectileWeaponItem implements Vanishable { - // Paper end - Add EntityLoadCrossbowEvent - int i = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.MULTISHOT, crossbow); - int j = i == 0 ? 1 : 3; -- boolean flag = !consume || shooter instanceof Player && ((Player) shooter).getAbilities().instabuild; // Paper - Add EntityLoadCrossbowEvent -+ boolean flag = !consume || shooter instanceof Player && ((Player) shooter).getAbilities().instabuild || (org.purpurmc.purpur.PurpurConfig.allowCrossbowInfinity && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY_ARROWS, crossbow) > 0); // Paper - Add EntityLoadCrossbowEvent // Purpur - ItemStack itemstack1 = shooter.getProjectile(crossbow); - ItemStack itemstack2 = itemstack1.copy(); - -@@ -291,6 +291,14 @@ public class CrossbowItem extends ProjectileWeaponItem implements Vanishable { - entityarrow.setPierceLevel((byte) i); - } - -+ // Purpur start -+ int lootingLevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.MOB_LOOTING, crossbow); -+ -+ if (lootingLevel > 0) { -+ entityarrow.setLootingLevel(lootingLevel); -+ } -+ // Purpur end -+ - return entityarrow; +@@ -60,7 +60,7 @@ public class CrossbowItem extends ProjectileWeaponItem { + ItemStack itemStack = user.getItemInHand(hand); + ChargedProjectiles chargedProjectiles = itemStack.get(DataComponents.CHARGED_PROJECTILES); + if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { +- this.performShooting(world, user, hand, itemStack, getShootingPower(chargedProjectiles), 1.0F, null); ++ this.performShooting(world, user, hand, itemStack, getShootingPower(chargedProjectiles), (float) world.purpurConfig.crossbowProjectileOffset, null); // Purpur + return InteractionResultHolder.consume(itemStack); + } else if (!user.getProjectile(itemStack).isEmpty()) { + this.startSoundPlayed = false; +@@ -107,7 +107,7 @@ public class CrossbowItem extends ProjectileWeaponItem { + return CrossbowItem.tryLoadProjectiles(shooter, crossbow, true); } - -@@ -300,7 +308,7 @@ public class CrossbowItem extends ProjectileWeaponItem implements Vanishable { - - for (int i = 0; i < list.size(); ++i) { - ItemStack itemstack1 = (ItemStack) list.get(i); -- boolean flag = entity instanceof Player && ((Player) entity).getAbilities().instabuild; -+ boolean flag = entity instanceof Player && ((Player) entity).getAbilities().instabuild || (org.purpurmc.purpur.PurpurConfig.allowCrossbowInfinity && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY_ARROWS, stack) > 0); // Purpur - - if (!itemstack1.isEmpty()) { - if (i == 0) { + private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow, boolean consume) { +- List list = draw(crossbow, shooter.getProjectile(crossbow), shooter, consume); ++ List list = draw(crossbow, shooter.getProjectile(crossbow), shooter, (org.purpurmc.purpur.PurpurConfig.allowCrossbowInfinity && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY, crossbow) > 0) || consume); + // Paper end - Add EntityLoadCrossbowEvent + if (!list.isEmpty()) { + crossbow.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(list)); diff --git a/src/main/java/net/minecraft/world/item/DyeColor.java b/src/main/java/net/minecraft/world/item/DyeColor.java -index 52ff8331f2859ee4bf39bf2fa6631bed7eed2f18..848a36a740576a0dd9e4ad50d1dd3ff07bd1d537 100644 +index 2202798612cad53aff28c499b8909a7292a37ad5..5ed2b7d15686fc9aa6dc7c03c337433cb3ee2cbd 100644 --- a/src/main/java/net/minecraft/world/item/DyeColor.java +++ b/src/main/java/net/minecraft/world/item/DyeColor.java -@@ -101,4 +101,10 @@ public enum DyeColor implements StringRepresentable { +@@ -105,4 +105,10 @@ public enum DyeColor implements StringRepresentable { public String getSerializedName() { return this.name; } @@ -16730,10 +16217,10 @@ index 52ff8331f2859ee4bf39bf2fa6631bed7eed2f18..848a36a740576a0dd9e4ad50d1dd3ff0 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/item/EggItem.java b/src/main/java/net/minecraft/world/item/EggItem.java -index a3bd507793994e9cc87a956871a8afbb8ca9460d..ef2197a23aef0a4215fae09bd4618e449e14c64e 100644 +index 4ebd634cff286b10868e26eeb3ecf34abdcab22e..7dc811335caa46870d1d895899a1e6c21980382d 100644 --- a/src/main/java/net/minecraft/world/item/EggItem.java +++ b/src/main/java/net/minecraft/world/item/EggItem.java -@@ -24,7 +24,7 @@ public class EggItem extends Item { +@@ -27,7 +27,7 @@ public class EggItem extends Item implements ProjectileItem { ThrownEgg entityegg = new ThrownEgg(world, user); entityegg.setItem(itemstack); @@ -16743,10 +16230,10 @@ index a3bd507793994e9cc87a956871a8afbb8ca9460d..ef2197a23aef0a4215fae09bd4618e44 com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entityegg.getBukkitEntity()); if (event.callEvent() && world.addFreshEntity(entityegg)) { diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -index faa3f62d22266a3c32d6c95c3ffebd4aa3880739..0cf62b1f64afa56c319392eafe0d444b7c5662c7 100644 +index dd1bdb4bb87a3a59c229ba76b36841d199717624..54607cea2622f259aedfe425b60e2317e4167bf9 100644 --- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java +++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -@@ -26,7 +26,7 @@ public class EndCrystalItem extends Item { +@@ -27,7 +27,7 @@ public class EndCrystalItem extends Item { BlockPos blockposition = context.getClickedPos(); BlockState iblockdata = world.getBlockState(blockposition); @@ -16756,7 +16243,7 @@ index faa3f62d22266a3c32d6c95c3ffebd4aa3880739..0cf62b1f64afa56c319392eafe0d444b } else { BlockPos blockposition1 = blockposition.above(); final BlockPos aboveBlockPosition = blockposition1; // Paper - OBFHELPER diff --git a/src/main/java/net/minecraft/world/item/EnderpearlItem.java b/src/main/java/net/minecraft/world/item/EnderpearlItem.java -index 8c8cf8705107c95d9a4eab28b5845ae13c4ffb3c..8031e38c66468676b3b4a7443d6678eec6b1e8a4 100644 +index 20a91d798d31a71b3c05efa2cc5bda55494e26cc..11b04455f09d8bfdf44499bb8359dc715c2daffd 100644 --- a/src/main/java/net/minecraft/world/item/EnderpearlItem.java +++ b/src/main/java/net/minecraft/world/item/EnderpearlItem.java @@ -24,7 +24,7 @@ public class EnderpearlItem extends Item { @@ -16778,62 +16265,45 @@ index 8c8cf8705107c95d9a4eab28b5845ae13c4ffb3c..8031e38c66468676b3b4a7443d6678ee // Paper end - PlayerLaunchProjectileEvent if (user instanceof net.minecraft.server.level.ServerPlayer) { diff --git a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java -index e1c8b24a92ea63a645406522a3c2fb5efd87f01a..0f6c1716103514dedf46e7068fd79e8b9b94e15d 100644 +index 218f2f085309f04438f8b07bc41cf242583db2dc..ea8e49b42b9dde74784189430be66ed6978015dd 100644 --- a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java +++ b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java -@@ -15,6 +15,7 @@ import net.minecraft.util.ByIdMap; - import net.minecraft.world.InteractionHand; - import net.minecraft.world.InteractionResult; - import net.minecraft.world.InteractionResultHolder; -+import net.minecraft.world.entity.EquipmentSlot; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.entity.projectile.FireworkRocketEntity; - import net.minecraft.world.item.context.UseOnContext; -@@ -76,6 +77,14 @@ public class FireworkRocketItem extends Item { +@@ -65,6 +65,14 @@ 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) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) fireworkRocketEntity.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand)); if (event.callEvent() && world.addFreshEntity(fireworkRocketEntity)) { user.awardStat(Stats.ITEM_USED.get(this)); + // Purpur start + if (world.purpurConfig.elytraDamagePerFireworkBoost > 0) { -+ ItemStack chestItem = user.getItemBySlot(EquipmentSlot.CHEST); ++ ItemStack chestItem = user.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.CHEST); + if (chestItem.getItem() == Items.ELYTRA) { -+ chestItem.hurtAndBreak(world.purpurConfig.elytraDamagePerFireworkBoost, user, (entityliving) -> entityliving.broadcastBreakEvent(EquipmentSlot.CHEST)); ++ chestItem.hurtAndBreak(world.purpurConfig.elytraDamagePerFireworkBoost, user, net.minecraft.world.entity.EquipmentSlot.CHEST); + } + } + // Purpur end - if (event.shouldConsume() && !user.getAbilities().instabuild) { - itemStack.shrink(1); + if (event.shouldConsume() && !user.hasInfiniteMaterials()) { + itemStack.shrink(1); } else ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory(); diff --git a/src/main/java/net/minecraft/world/item/HangingEntityItem.java b/src/main/java/net/minecraft/world/item/HangingEntityItem.java -index b2ad6d230de2c29f371178bccde1111c7532ee70..6667926519a0f1c151e53f59cce36e7417dfc1cd 100644 +index 530167ce8e5bb72a418f8ec61411e38a5892fd72..35dc7546793dba34bf6debad3f214f61a8fb4f4e 100644 --- a/src/main/java/net/minecraft/world/item/HangingEntityItem.java +++ b/src/main/java/net/minecraft/world/item/HangingEntityItem.java -@@ -48,7 +48,7 @@ public class HangingEntityItem extends Item { - return InteractionResult.FAIL; - } else { - Level world = context.getLevel(); -- Object object; -+ Entity object; // Purpur +@@ -73,6 +73,11 @@ public class HangingEntityItem extends Item { - if (this.type == EntityType.PAINTING) { - Optional optional = Painting.create(world, blockposition1, enumdirection); -@@ -72,6 +72,11 @@ public class HangingEntityItem extends Item { - - if (nbttagcompound != null) { - EntityType.updateCustomEntityTag(world, entityhuman, (Entity) object, nbttagcompound); + if (!customdata.isEmpty()) { + EntityType.updateCustomEntityTag(world, entityhuman, (Entity) object, customdata); + // Purpur start -+ if (world.purpurConfig.persistentDroppableEntityDisplayNames && itemstack.hasCustomHoverName()) { -+ object.setCustomName(itemstack.getHoverName()); ++ if (!world.purpurConfig.persistentDroppableEntityDisplayNames) { ++ ((Entity) object).setCustomName(null); + } + // Purpur end } if (((HangingEntity) object).survives()) { diff --git a/src/main/java/net/minecraft/world/item/HoeItem.java b/src/main/java/net/minecraft/world/item/HoeItem.java -index 9e5695eabd4c3ea165121b22fff93f09b170bc6b..18cbcfcd331f7b7a112383311e3e2b9984857028 100644 +index 06497b5141e611cc7a1b6030a7b9c54b5c4eda06..28df1b3230762e52b5458ac93a85c9a5d41eb6a6 100644 --- a/src/main/java/net/minecraft/world/item/HoeItem.java +++ b/src/main/java/net/minecraft/world/item/HoeItem.java -@@ -45,15 +45,23 @@ public class HoeItem extends DiggerItem { +@@ -46,15 +46,23 @@ public class HoeItem extends DiggerItem { public InteractionResult useOn(UseOnContext context) { Level level = context.getLevel(); BlockPos blockPos = context.getClickedPos(); @@ -16864,7 +16334,7 @@ index 9e5695eabd4c3ea165121b22fff93f09b170bc6b..18cbcfcd331f7b7a112383311e3e2b99 if (!level.isClientSide) { consumer.accept(context); if (player != null) { -@@ -61,7 +69,7 @@ public class HoeItem extends DiggerItem { +@@ -62,7 +70,7 @@ public class HoeItem extends DiggerItem { } } @@ -16874,10 +16344,10 @@ index 9e5695eabd4c3ea165121b22fff93f09b170bc6b..18cbcfcd331f7b7a112383311e3e2b99 return InteractionResult.PASS; } diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 1ad126d992d95062a3db08374db7a927f23a0cac..f6664447c45b1d6f3371af7bed8b1175b17f25e2 100644 +index a45389d64c04cd4c2a35fbc511595be0535a8665..fb614432722ea27cd044d6cfd3c6a72f797979f1 100644 --- a/src/main/java/net/minecraft/world/item/ItemStack.java +++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -454,6 +454,7 @@ public final class ItemStack { +@@ -475,6 +475,7 @@ public final class ItemStack implements DataComponentHolder { world.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710 for (BlockState blockstate : blocks) { blockstate.update(true, false); @@ -16885,22 +16355,22 @@ index 1ad126d992d95062a3db08374db7a927f23a0cac..f6664447c45b1d6f3371af7bed8b1175 } world.preventPoiUpdated = false; -@@ -485,6 +486,7 @@ public final class ItemStack { +@@ -506,6 +507,7 @@ public final class ItemStack implements DataComponentHolder { if (!(block.getBlock() instanceof BaseEntityBlock)) { // Containers get placed automatically - block.getBlock().onPlace(block, world, newblockposition, oldBlock, true, context); // Paper - pass context + block.onPlace(world, newblockposition, oldBlock, true, context); // Paper - pass context } + block.getBlock().forgetPlacer(); // Purpur world.notifyAndUpdatePhysics(newblockposition, null, oldBlock, block, world.getBlockState(newblockposition), updateFlag, 512); // send null chunk as chunk.k() returns false by this point } -@@ -613,6 +615,16 @@ public final class ItemStack { +@@ -636,6 +638,16 @@ public final class ItemStack implements DataComponentHolder { return this.isDamageableItem() && this.getDamageValue() > 0; } + // Purpur start + public float getDamagePercent() { + if (isDamaged()) { -+ return (float) getDamageValue() / (float) getItem().getMaxDamage(); ++ return (float) getDamageValue() / (float) getMaxDamage(); + } else { + return 0F; + } @@ -16908,9 +16378,9 @@ index 1ad126d992d95062a3db08374db7a927f23a0cac..f6664447c45b1d6f3371af7bed8b1175 + // Purpur end + public int getDamageValue() { - return this.tag == null ? 0 : this.tag.getInt("Damage"); + return Mth.clamp((Integer) this.getOrDefault(DataComponents.DAMAGE, 0), 0, this.getMaxDamage()); } -@@ -632,7 +644,7 @@ public final class ItemStack { +@@ -653,7 +665,7 @@ public final class ItemStack implements DataComponentHolder { int j; if (amount > 0) { @@ -16919,117 +16389,89 @@ index 1ad126d992d95062a3db08374db7a927f23a0cac..f6664447c45b1d6f3371af7bed8b1175 int k = 0; for (int l = 0; j > 0 && l < amount; ++l) { -@@ -687,6 +699,12 @@ public final class ItemStack { - if (this.hurt(amount, entity.getRandom(), entity /*instanceof ServerPlayer ? (ServerPlayer) entity : null*/)) { // Paper - Add EntityDamageItemEvent - breakCallback.accept(entity); - Item item = this.getItem(); -+ // Purpur start -+ if (item == Items.ELYTRA) { -+ setDamageValue(item.getMaxDamage() - 1); -+ return; -+ } -+ // Purpur end - // CraftBukkit start - Check for item breaking - if (this.count == 1 && entity instanceof net.minecraft.world.entity.player.Player) { - org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent((net.minecraft.world.entity.player.Player) entity, this); -@@ -1217,7 +1235,7 @@ public final class ItemStack { - - ListTag nbttaglist = this.tag.getList("Enchantments", 10); - -- nbttaglist.add(EnchantmentHelper.storeEnchantment(EnchantmentHelper.getEnchantmentId(enchantment), (byte) level)); -+ nbttaglist.add(EnchantmentHelper.storeEnchantment(EnchantmentHelper.getEnchantmentId(enchantment), (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels) ? (byte) level : (short) level)); // Purpur - processEnchantOrder(this.tag); // Paper - } - -@@ -1225,6 +1243,12 @@ public final class ItemStack { - return this.tag != null && this.tag.contains("Enchantments", 9) ? !this.tag.getList("Enchantments", 10).isEmpty() : false; +@@ -729,6 +741,12 @@ public final class ItemStack implements DataComponentHolder { + this.hurtAndBreak(amount, randomsource, entity, () -> { // Paper - Add EntityDamageItemEvent + entity.broadcastBreakEvent(slot); + Item item = this.getItem(); ++ // Purpur start ++ if (item == Items.ELYTRA) { ++ setDamageValue(getMaxDamage() - 1); ++ return; ++ } ++ // Purpur end + // CraftBukkit start - Check for item breaking + if (this.count == 1 && entity instanceof net.minecraft.world.entity.player.Player) { + org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent((net.minecraft.world.entity.player.Player) entity, this); +@@ -1210,6 +1228,16 @@ public final class ItemStack implements DataComponentHolder { + return !((ItemEnchantments) this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY)).isEmpty(); } + // Purpur start + public boolean hasEnchantment(Enchantment enchantment) { -+ return isEnchanted() && EnchantmentHelper.deserializeEnchantments(getEnchantmentTags()).containsKey(enchantment); ++ if (isEnchanted()) { ++ ItemEnchantments enchantments = this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); ++ return new net.minecraft.advancements.critereon.EnchantmentPredicate(enchantment, net.minecraft.advancements.critereon.MinMaxBounds.Ints.atLeast(1)).containedIn(enchantments); ++ } ++ return false; + } + // Purpur end + - public void addTagElement(String key, Tag element) { - this.getOrCreateTag().put(key, element); + public ItemEnchantments getEnchantments() { + return (ItemEnchantments) this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); } diff --git a/src/main/java/net/minecraft/world/item/Items.java b/src/main/java/net/minecraft/world/item/Items.java -index b43598ee4035d9c53a40629dd4021b58c04132c8..249c887af68f56739c3609bad2405ba2cbe11762 100644 +index d00b59efb754594cf532f8598f4b6d3b29693232..42b322879629afb2d2fc64a215f010f5d5ce9e02 100644 --- a/src/main/java/net/minecraft/world/item/Items.java +++ b/src/main/java/net/minecraft/world/item/Items.java -@@ -316,7 +316,7 @@ public class Items { +@@ -338,7 +338,7 @@ public class Items { public static final Item PURPUR_BLOCK = registerBlock(Blocks.PURPUR_BLOCK); public static final Item PURPUR_PILLAR = registerBlock(Blocks.PURPUR_PILLAR); public static final Item PURPUR_STAIRS = registerBlock(Blocks.PURPUR_STAIRS); - public static final Item SPAWNER = registerBlock(Blocks.SPAWNER); + public static final Item SPAWNER = registerBlock(new org.purpurmc.purpur.item.SpawnerItem(Blocks.SPAWNER, new Item.Properties().rarity(Rarity.EPIC))); // Purpur - public static final Item CHEST = registerBlock(Blocks.CHEST); + public static final Item CHEST = registerBlock(Blocks.CHEST, settings -> settings.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY)); public static final Item CRAFTING_TABLE = registerBlock(Blocks.CRAFTING_TABLE); public static final Item FARMLAND = registerBlock(Blocks.FARMLAND); -@@ -1535,7 +1535,7 @@ public class Items { +@@ -1909,7 +1909,7 @@ public class Items { "sweet_berries", new ItemNameBlockItem(Blocks.SWEET_BERRY_BUSH, new Item.Properties().food(Foods.SWEET_BERRIES)) ); public static final Item GLOW_BERRIES = registerItem( - "glow_berries", new ItemNameBlockItem(Blocks.CAVE_VINES, new Item.Properties().food(Foods.GLOW_BERRIES)) + "glow_berries", new org.purpurmc.purpur.item.GlowBerryItem(Blocks.CAVE_VINES, new Item.Properties().food(Foods.GLOW_BERRIES)) // Purpur ); - public static final Item CAMPFIRE = registerBlock(Blocks.CAMPFIRE); - public static final Item SOUL_CAMPFIRE = registerBlock(Blocks.SOUL_CAMPFIRE); -@@ -1715,6 +1715,13 @@ public class Items { - ((BlockItem)item).registerBlocks(Item.BY_BLOCK, item); - } - -+ // Purpur start -+ if (item.getFoodProperties() != null) { -+ Foods.ALL_PROPERTIES.put(key.location().getPath(), item.getFoodProperties()); -+ Foods.DEFAULT_PROPERTIES.put(key.location().getPath(), item.getFoodProperties().copy()); -+ } -+ // Purpur end -+ - return Registry.register(BuiltInRegistries.ITEM, key, item); - } - } + public static final Item CAMPFIRE = registerBlock(Blocks.CAMPFIRE, settings -> settings.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY)); + public static final Item SOUL_CAMPFIRE = registerBlock( diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java -index d8dd99ec8bf7444c5a3c426db3a9c13e334dc0ff..8d3c1897044f9a2bbe1911e1a72dc9a00fb246df 100644 +index ce461b1a8d7fab87ae28e30205f6fab67f1808b6..608390ed36710a419de1542b80340dd3fcc7299c 100644 --- a/src/main/java/net/minecraft/world/item/MapItem.java +++ b/src/main/java/net/minecraft/world/item/MapItem.java -@@ -235,6 +235,7 @@ public class MapItem extends ComplexItem { - MapItemSavedData worldmap = MapItem.getSavedData(map, world); - - if (worldmap != null) { -+ worldmap.isExplorerMap = true; // Purpur - if (world.dimension() == worldmap.dimension) { - int i = 1 << worldmap.scale; - int j = worldmap.centerX; +@@ -195,6 +195,7 @@ public class MapItem extends ComplexItem { + public static void renderBiomePreviewMap(ServerLevel world, ItemStack map) { + MapItemSavedData mapItemSavedData = getSavedData(map, world); + if (mapItemSavedData != null) { ++ mapItemSavedData.isExplorerMap = true; // Purpur + if (world.dimension() == mapItemSavedData.dimension) { + int i = 1 << mapItemSavedData.scale; + int j = mapItemSavedData.centerX; diff --git a/src/main/java/net/minecraft/world/item/MilkBucketItem.java b/src/main/java/net/minecraft/world/item/MilkBucketItem.java -index f33977d95b6db473be4f95075ba99caf90ad0220..56dc04d8875971ee9a5d077a695509af74fe2473 100644 +index 0f83ae4b0d5f52ff9ccfff6bbcc31153d45bd619..d0751274e89042715cab8e9e72387042356e3244 100644 --- a/src/main/java/net/minecraft/world/item/MilkBucketItem.java +++ b/src/main/java/net/minecraft/world/item/MilkBucketItem.java -@@ -5,6 +5,8 @@ import net.minecraft.server.level.ServerPlayer; - import net.minecraft.stats.Stats; - import net.minecraft.world.InteractionHand; - import net.minecraft.world.InteractionResultHolder; -+import net.minecraft.world.effect.MobEffectInstance; -+import net.minecraft.world.effect.MobEffects; - import net.minecraft.world.entity.LivingEntity; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.level.Level; -@@ -31,7 +33,9 @@ public class MilkBucketItem extends Item { - } +@@ -26,7 +26,9 @@ public class MilkBucketItem extends Item { + stack.consume(1, user); if (!world.isClientSide) { -+ MobEffectInstance badOmen = user.getEffect(MobEffects.BAD_OMEN); ++ net.minecraft.world.effect.MobEffectInstance badOmen = user.getEffect(net.minecraft.world.effect.MobEffects.BAD_OMEN); // Purpur user.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.MILK); // CraftBukkit + if (!world.purpurConfig.milkCuresBadOmen && badOmen != null) user.addEffect(badOmen); // Purpur } return stack.isEmpty() ? new ItemStack(Items.BUCKET) : stack; diff --git a/src/main/java/net/minecraft/world/item/MinecartItem.java b/src/main/java/net/minecraft/world/item/MinecartItem.java -index 3aa73cd44aa8c86b78c35bc1788e4f83018c49ed..66a8b28275619079e3bcbcc460146976d533d54e 100644 +index 66074445d3908b9bb1c8d70e1e27d057720ec8e5..0fd4f2ab929df479360755a3f1e58a933ae59520 100644 --- a/src/main/java/net/minecraft/world/item/MinecartItem.java +++ b/src/main/java/net/minecraft/world/item/MinecartItem.java -@@ -119,8 +119,9 @@ public class MinecartItem extends Item { +@@ -120,8 +120,9 @@ public class MinecartItem extends Item { BlockState iblockdata = world.getBlockState(blockposition); if (!iblockdata.is(BlockTags.RAILS)) { @@ -17041,7 +16483,7 @@ index 3aa73cd44aa8c86b78c35bc1788e4f83018c49ed..66a8b28275619079e3bcbcc460146976 ItemStack itemstack = context.getItemInHand(); if (world instanceof ServerLevel) { -@@ -145,6 +146,6 @@ public class MinecartItem extends Item { +@@ -146,6 +147,6 @@ public class MinecartItem extends Item { itemstack.shrink(1); return InteractionResult.sidedSuccess(world.isClientSide); @@ -17050,22 +16492,41 @@ index 3aa73cd44aa8c86b78c35bc1788e4f83018c49ed..66a8b28275619079e3bcbcc460146976 } } diff --git a/src/main/java/net/minecraft/world/item/NameTagItem.java b/src/main/java/net/minecraft/world/item/NameTagItem.java -index a0b3c2d3b3f86ecd6cb80ff767839d29ca4f4f68..61b4430d6dd73b5406c4879e41ff80a1b6f67f84 100644 +index 774c982f28b4f127fc3f036c19dfb47fb9ae3264..d49b60e7e643498b49c03593dc0da2f8e4459902 100644 --- a/src/main/java/net/minecraft/world/item/NameTagItem.java +++ b/src/main/java/net/minecraft/world/item/NameTagItem.java -@@ -20,6 +20,7 @@ public class NameTagItem extends Item { +@@ -23,6 +23,7 @@ public class NameTagItem extends Item { if (!event.callEvent()) return InteractionResult.PASS; LivingEntity newEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getEntity()).getHandle(); newEntity.setCustomName(event.getName() != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(event.getName()) : null); + if (user.level().purpurConfig.armorstandFixNametags && entity instanceof net.minecraft.world.entity.decoration.ArmorStand) entity.setCustomNameVisible(true); // Purpur - if (event.isPersistent() && newEntity instanceof Mob) { - ((Mob) newEntity).setPersistenceRequired(); - // Paper end - Add PlayerNameEntityEvent + if (event.isPersistent() && newEntity instanceof Mob mob) { + // Paper end - Add PlayerNameEntityEvent + mob.setPersistenceRequired(); +diff --git a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java +index f91ce87491b18f4f4ae6458192d1f320b308102a..aec96d297401b705ca2af97904739afdf1134574 100644 +--- a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java ++++ b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java +@@ -131,6 +131,14 @@ public abstract class ProjectileWeaponItem extends Item { + entityarrow.setPierceLevel((byte) k); + } + ++ // Purpur start ++ int lootingLevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.LOOTING, weaponStack); ++ ++ if (lootingLevel > 0) { ++ entityarrow.setLootingLevel(lootingLevel); ++ } ++ // Purpur end ++ + return entityarrow; + } + diff --git a/src/main/java/net/minecraft/world/item/ShovelItem.java b/src/main/java/net/minecraft/world/item/ShovelItem.java -index 9aba0211f37501bbd19b583d22fa83eae32390d9..f44e28bf44b9d39267d21eaf6a025b5f28f3cd72 100644 +index 24f6a158e4759aac3be8da4cf5e0d40bd295355b..6b7dbb570f8a698c87c6bce992d84d87b55176e6 100644 --- a/src/main/java/net/minecraft/world/item/ShovelItem.java +++ b/src/main/java/net/minecraft/world/item/ShovelItem.java -@@ -46,9 +46,12 @@ public class ShovelItem extends DiggerItem { +@@ -47,9 +47,12 @@ public class ShovelItem extends DiggerItem { BlockState blockState2 = FLATTENABLES.get(blockState.getBlock()); BlockState blockState3 = null; Runnable afterAction = null; // Paper @@ -17081,7 +16542,7 @@ index 9aba0211f37501bbd19b583d22fa83eae32390d9..f44e28bf44b9d39267d21eaf6a025b5f } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { afterAction = () -> { // Paper if (!level.isClientSide()) { -@@ -75,7 +78,7 @@ public class ShovelItem extends DiggerItem { +@@ -76,7 +79,7 @@ public class ShovelItem extends DiggerItem { } } @@ -17091,10 +16552,10 @@ index 9aba0211f37501bbd19b583d22fa83eae32390d9..f44e28bf44b9d39267d21eaf6a025b5f return InteractionResult.PASS; } diff --git a/src/main/java/net/minecraft/world/item/SnowballItem.java b/src/main/java/net/minecraft/world/item/SnowballItem.java -index bc8186a5bc3a98b35fad570729dd4ba52efab238..caab0c1e2bc5696080750797cbf1c93f57799f7d 100644 +index 32b170551a2f5bdc88d29f4d03750bfe3974e71b..a41fb0dd26af367fc2470a7913a84d864bc505f7 100644 --- a/src/main/java/net/minecraft/world/item/SnowballItem.java +++ b/src/main/java/net/minecraft/world/item/SnowballItem.java -@@ -25,7 +25,7 @@ public class SnowballItem extends Item { +@@ -28,7 +28,7 @@ public class SnowballItem extends Item implements ProjectileItem { Snowball entitysnowball = new Snowball(world, user); entitysnowball.setItem(itemstack); @@ -17104,13 +16565,13 @@ index bc8186a5bc3a98b35fad570729dd4ba52efab238..caab0c1e2bc5696080750797cbf1c93f com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entitysnowball.getBukkitEntity()); if (event.callEvent() && world.addFreshEntity(entitysnowball)) { diff --git a/src/main/java/net/minecraft/world/item/SpawnEggItem.java b/src/main/java/net/minecraft/world/item/SpawnEggItem.java -index 3bfbf7daa190b03f978b9fc72233c18c383b6659..32996934bb47f4b7b2aa65dfd8739d8f67c740ef 100644 +index 9cea8da84f39bb3f687139ef213ccea358724dee..076e6858222b92f8409f1f5cad398582c1fd6bcb 100644 --- a/src/main/java/net/minecraft/world/item/SpawnEggItem.java +++ b/src/main/java/net/minecraft/world/item/SpawnEggItem.java -@@ -68,6 +68,16 @@ public class SpawnEggItem extends Item { +@@ -74,6 +74,15 @@ public class SpawnEggItem extends Item { Spawner spawner = (Spawner) tileentity; - entitytypes = this.getType(itemstack.getTag()); + entitytypes = this.getType(itemstack); + + // Purpur start + org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); @@ -17120,15 +16581,14 @@ index 3bfbf7daa190b03f978b9fc72233c18c383b6659..32996934bb47f4b7b2aa65dfd8739d8f + } + entitytypes = EntityType.getFromBukkitType(event.getEntityType()); + // Purpur end -+ spawner.setEntityId(entitytypes, world.getRandom()); world.sendBlockUpdated(blockposition, iblockdata, iblockdata, 3); - world.gameEvent((Entity) context.getPlayer(), GameEvent.BLOCK_CHANGE, blockposition); + world.gameEvent((Entity) context.getPlayer(), (Holder) GameEvent.BLOCK_CHANGE, blockposition); diff --git a/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java b/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java -index f47f793c62a919fb65c081ddb82d597a978d3b20..3bbb44ae3da68afbd6012df68dee277a7dbf98c0 100644 +index 369955746f4b51f69fa01103e3771dd74fc6c8f0..e6edd3a0fa2578900cdbe8bd588219dc3fd3af5f 100644 --- a/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java +++ b/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java -@@ -18,7 +18,7 @@ public class ThrowablePotionItem extends PotionItem { +@@ -21,7 +21,7 @@ public class ThrowablePotionItem extends PotionItem implements ProjectileItem { if (!world.isClientSide) { ThrownPotion thrownPotion = new ThrownPotion(world, user); thrownPotion.setItem(itemStack); @@ -17138,21 +16598,21 @@ index f47f793c62a919fb65c081ddb82d597a978d3b20..3bbb44ae3da68afbd6012df68dee277a com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownPotion.getBukkitEntity()); if (event.callEvent() && world.addFreshEntity(thrownPotion)) { diff --git a/src/main/java/net/minecraft/world/item/TridentItem.java b/src/main/java/net/minecraft/world/item/TridentItem.java -index a792c7b7a6179aa88fc473b27ef0ca13bd91a395..95f9dd3f8fbf593fd6898335454951868c867a06 100644 +index 47de500fddb0716d142f8f5876a82a95afaa06fa..905a020dd7b365d51d5addadbbeb9555d03c5238 100644 --- a/src/main/java/net/minecraft/world/item/TridentItem.java +++ b/src/main/java/net/minecraft/world/item/TridentItem.java -@@ -77,11 +77,19 @@ public class TridentItem extends Item implements Vanishable { +@@ -76,11 +76,19 @@ public class TridentItem extends Item implements ProjectileItem { if (k == 0) { ThrownTrident entitythrowntrident = new ThrownTrident(world, entityhuman, stack); - entitythrowntrident.shootFromRotation(entityhuman, entityhuman.getXRot(), entityhuman.getYRot(), 0.0F, 2.5F + (float) k * 0.5F, 1.0F); + entitythrowntrident.shootFromRotation(entityhuman, entityhuman.getXRot(), entityhuman.getYRot(), 0.0F, 2.5F + (float) k * 0.5F, (float) world.purpurConfig.tridentProjectileOffset); // Purpur - if (entityhuman.getAbilities().instabuild) { + if (entityhuman.hasInfiniteMaterials()) { entitythrowntrident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; } + // Purpur start -+ int lootingLevel = EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.MOB_LOOTING, stack); ++ int lootingLevel = EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.LOOTING, stack); + + if (lootingLevel > 0) { + entitythrowntrident.setLootingLevel(lootingLevel); @@ -17162,7 +16622,7 @@ index a792c7b7a6179aa88fc473b27ef0ca13bd91a395..95f9dd3f8fbf593fd689833545495186 // CraftBukkit start // Paper start - PlayerLaunchProjectileEvent com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) entitythrowntrident.getBukkitEntity()); -@@ -128,6 +136,14 @@ public class TridentItem extends Item implements Vanishable { +@@ -123,6 +131,14 @@ public class TridentItem extends Item implements ProjectileItem { f3 *= f6 / f5; f4 *= f6 / f5; org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(entityhuman, stack, f2, f3, f4); // CraftBukkit @@ -17170,7 +16630,7 @@ index a792c7b7a6179aa88fc473b27ef0ca13bd91a395..95f9dd3f8fbf593fd689833545495186 + // Purpur start + ItemStack chestItem = entityhuman.getItemBySlot(EquipmentSlot.CHEST); + if (chestItem.getItem() == Items.ELYTRA && world.purpurConfig.elytraDamagePerTridentBoost > 0) { -+ chestItem.hurtAndBreak(world.purpurConfig.elytraDamagePerTridentBoost, entityhuman, (entity) -> entity.broadcastBreakEvent(EquipmentSlot.CHEST)); ++ chestItem.hurtAndBreak(world.purpurConfig.elytraDamagePerTridentBoost, entityhuman, EquipmentSlot.CHEST); + } + // Purpur end + @@ -17178,10 +16638,10 @@ index a792c7b7a6179aa88fc473b27ef0ca13bd91a395..95f9dd3f8fbf593fd689833545495186 entityhuman.startAutoSpinAttack(20); if (entityhuman.onGround()) { diff --git a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java -index 7c29750e534eae4266bf7a63c50e3827401d6569..e8e9a3370ba07dc0ca47c8352f6f04a449f2268f 100644 +index e314f36951e9ac15c57137e24fce8c410373130a..21dfb8e91c5427ac12133de2c05d923d87adf5ba 100644 --- a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java +++ b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java -@@ -36,6 +36,7 @@ public final class Ingredient implements Predicate { +@@ -41,6 +41,7 @@ public final class Ingredient implements Predicate { @Nullable private IntList stackingIds; public boolean exact; // CraftBukkit @@ -17189,7 +16649,7 @@ index 7c29750e534eae4266bf7a63c50e3827401d6569..e8e9a3370ba07dc0ca47c8352f6f04a4 public static final Codec CODEC = Ingredient.codec(true); public static final Codec CODEC_NONEMPTY = Ingredient.codec(false); -@@ -67,6 +68,12 @@ public final class Ingredient implements Predicate { +@@ -72,6 +73,12 @@ public final class Ingredient implements Predicate { } else if (this.isEmpty()) { return itemstack.isEmpty(); } else { @@ -17203,25 +16663,10 @@ index 7c29750e534eae4266bf7a63c50e3827401d6569..e8e9a3370ba07dc0ca47c8352f6f04a4 int i = aitemstack.length; diff --git a/src/main/java/net/minecraft/world/item/enchantment/ArrowInfiniteEnchantment.java b/src/main/java/net/minecraft/world/item/enchantment/ArrowInfiniteEnchantment.java -index 04c39359585d909dedbdfd78f6cbdc06b926607a..127950c54ae057b3d0eb62e8f81d5eef6f11a36c 100644 +index 81cc05c929d612898609965d82454b89cd18f9f5..fa73c3d4b58ad8379963a9866d8f09e1d6abd663 100644 --- a/src/main/java/net/minecraft/world/item/enchantment/ArrowInfiniteEnchantment.java +++ b/src/main/java/net/minecraft/world/item/enchantment/ArrowInfiniteEnchantment.java -@@ -7,6 +7,14 @@ public class ArrowInfiniteEnchantment extends Enchantment { - super(weight, EnchantmentCategory.BOW, slotTypes); - } - -+ // Purpur start -+ @Override -+ public boolean canEnchant(net.minecraft.world.item.ItemStack stack) { -+ // we have to cheat the system because this class is loaded before purpur's config is loaded -+ return (org.purpurmc.purpur.PurpurConfig.allowCrossbowInfinity ? EnchantmentCategory.BOW_AND_CROSSBOW : EnchantmentCategory.BOW).canEnchant(stack.getItem()); -+ } -+ // Purpur end -+ - @Override - public int getMinCost(int level) { - return 20; -@@ -19,6 +27,6 @@ public class ArrowInfiniteEnchantment extends Enchantment { +@@ -7,6 +7,6 @@ public class ArrowInfiniteEnchantment extends Enchantment { @Override public boolean checkCompatibility(Enchantment other) { @@ -17229,45 +16674,11 @@ index 04c39359585d909dedbdfd78f6cbdc06b926607a..127950c54ae057b3d0eb62e8f81d5eef + return !(other instanceof MendingEnchantment) && super.checkCompatibility(other) || other instanceof MendingEnchantment && org.purpurmc.purpur.PurpurConfig.allowInfinityMending; // Purpur } } -diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentCategory.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentCategory.java -index afd74b274aa46b1e2187935ebeb2a8824a133867..4f8d8665cb90b746dc59913ec270839c4e5dba91 100644 ---- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentCategory.java -+++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentCategory.java -@@ -113,6 +113,20 @@ public enum EnchantmentCategory { - public boolean canEnchant(Item item) { - return item instanceof Vanishable || Block.byItem(item) instanceof Vanishable || BREAKABLE.canEnchant(item); - } -+ // Purpur start -+ }, -+ BOW_AND_CROSSBOW { -+ @Override -+ public boolean canEnchant(Item item) { -+ return item instanceof BowItem || item instanceof CrossbowItem; -+ } -+ }, -+ WEAPON_AND_SHEARS { -+ @Override -+ public boolean canEnchant(Item item) { -+ return WEAPON.canEnchant(item) || item instanceof net.minecraft.world.item.ShearsItem; -+ } -+ // Purpur end - }; - - public abstract boolean canEnchant(Item item); diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java -index 496a9b9b095bd322fba8229a5d47e2a0107aeb96..8ffa04b583da86a9aa6cabe7d978373825b82b32 100644 +index d2f0463b0e74983eb2e3dfca9a268e9502b86257..6d0363cec691996be416ab22ef9d825196399158 100644 --- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java +++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java -@@ -47,7 +47,7 @@ public class EnchantmentHelper { - } - - public static int getEnchantmentLevel(CompoundTag nbt) { -- return Mth.clamp(nbt.getInt("lvl"), 0, 255); -+ return Mth.clamp(nbt.getInt("lvl"), 0, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels) ? 255 : 32767); // Purpur - } - - @Nullable -@@ -266,6 +266,29 @@ public class EnchantmentHelper { +@@ -237,6 +237,29 @@ public class EnchantmentHelper { return getItemEnchantmentLevel(Enchantments.CHANNELING, stack) > 0; } @@ -17295,32 +16706,51 @@ index 496a9b9b095bd322fba8229a5d47e2a0107aeb96..8ffa04b583da86a9aa6cabe7d9783738 + // Purpur end + @Nullable - public static Entry getRandomItemWith(Enchantment enchantment, LivingEntity entity) { + public static java.util.Map.Entry getRandomItemWith(Enchantment enchantment, LivingEntity entity) { return getRandomItemWith(enchantment, entity, stack -> true); -diff --git a/src/main/java/net/minecraft/world/item/enchantment/LootBonusEnchantment.java b/src/main/java/net/minecraft/world/item/enchantment/LootBonusEnchantment.java -index 7f1ffc0ac402fcf0ec086986e959ecc9f78dde03..1351d52374d1c2367932e5ecd5f4637955fb14c9 100644 ---- a/src/main/java/net/minecraft/world/item/enchantment/LootBonusEnchantment.java -+++ b/src/main/java/net/minecraft/world/item/enchantment/LootBonusEnchantment.java -@@ -7,6 +7,14 @@ public class LootBonusEnchantment extends Enchantment { - super(rarity, target, slotTypes); - } +diff --git a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java +index af18de11dd55938b6091f5ab183bd3fe4e8df152..2c741860afa1fa4d5798c68b84ec3fe13157ff09 100644 +--- a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java ++++ b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java +@@ -37,7 +37,7 @@ public class ItemEnchantments implements TooltipProvider { + public static final ItemEnchantments EMPTY = new ItemEnchantments(new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), true); + // Paper end + public static final int MAX_LEVEL = 255; +- private static final Codec LEVEL_CODEC = Codec.intRange(0, 255); ++ private static final Codec LEVEL_CODEC = Codec.intRange(0, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)); // Purpur + private static final Codec>> LEVELS_CODEC = Codec.unboundedMap( // Paper + BuiltInRegistries.ENCHANTMENT.holderByNameCodec(), LEVEL_CODEC + ) +@@ -72,7 +72,7 @@ public class ItemEnchantments implements TooltipProvider { + + for (Entry> entry : enchantments.object2IntEntrySet()) { + int i = entry.getIntValue(); +- if (i < 0 || i > 255) { ++ if (i < 0 || i > (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)) { // Purpur + throw new IllegalArgumentException("Enchantment " + entry.getKey() + " has invalid level " + i); + } + } +@@ -169,13 +169,13 @@ public class ItemEnchantments implements TooltipProvider { + if (level <= 0) { + this.enchantments.removeInt(enchantment.builtInRegistryHolder()); + } else { +- this.enchantments.put(enchantment.builtInRegistryHolder(), Math.min(level, 255)); ++ this.enchantments.put(enchantment.builtInRegistryHolder(), Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767))); + } + } + + public void upgrade(Enchantment enchantment, int level) { + if (level > 0) { +- this.enchantments.merge(enchantment.builtInRegistryHolder(), Math.min(level, 255), Integer::max); ++ this.enchantments.merge(enchantment.builtInRegistryHolder(), Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)), Integer::max); + } + } -+ // Purpur start -+ @Override -+ public boolean canEnchant(net.minecraft.world.item.ItemStack stack) { -+ // we have to cheat the system because this class is loaded before purpur's config is loaded -+ return (org.purpurmc.purpur.PurpurConfig.allowShearsLooting && this.category == EnchantmentCategory.WEAPON ? EnchantmentCategory.WEAPON_AND_SHEARS : this.category).canEnchant(stack.getItem()); -+ } -+ // Purpur end -+ - @Override - public int getMinCost(int level) { - return 15 + (level - 1) * 9; diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -index 02feea12c998f37098b72becf6bfaf6b27d155de..9c89a85d934955c9388cfe1361f13e70e699d279 100644 +index 0efc8d997b34302c3e0a5d7ec73a11a940dbeefe..af157881d440b34cfe79fbc9b03cc9ef28515eb8 100644 --- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java +++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -@@ -149,7 +149,12 @@ public class MerchantOffer { +@@ -131,7 +131,12 @@ public class MerchantOffer { } public void updateDemand() { @@ -17335,10 +16765,10 @@ index 02feea12c998f37098b72becf6bfaf6b27d155de..9c89a85d934955c9388cfe1361f13e70 public ItemStack assemble() { diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java -index 65c3e91ac4541c0150057dc9f012eb1ee566516e..40c199812ecf7b16fe5a17c18cb0d6d3ce258910 100644 +index f57e1b78204dff661ad5d3ee93a88a00330af2dc..967af8771ff8564c715d89f4b4b69b16c25add59 100644 --- a/src/main/java/net/minecraft/world/level/BaseSpawner.java +++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java -@@ -57,6 +57,7 @@ public abstract class BaseSpawner { +@@ -59,6 +59,7 @@ public abstract class BaseSpawner { } public boolean isNearPlayer(Level world, BlockPos pos) { @@ -17360,10 +16790,10 @@ index ea0aee88c7d901034427db201c1b2430f8a1d522..1f28bfb435c1e4d97da713f96c452aba if (range < 0.0 || d < range * range) { return true; diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java -index 90a82bd7977ebe520bdcc2ab99e11452d5cf4a21..0be03430d8257d918b7cf646af518473ae027399 100644 +index dc88014c4d9f172cc54e5d77b488128f9ffbc73d..f5e84bf8817e2d53557e0909d8c9e0e0e8206a16 100644 --- a/src/main/java/net/minecraft/world/level/Explosion.java +++ b/src/main/java/net/minecraft/world/level/Explosion.java -@@ -97,7 +97,7 @@ public class Explosion { +@@ -98,7 +98,7 @@ public class Explosion { this.hitPlayers = Maps.newHashMap(); this.level = world; this.source = entity; @@ -17372,7 +16802,7 @@ index 90a82bd7977ebe520bdcc2ab99e11452d5cf4a21..0be03430d8257d918b7cf646af518473 this.x = x; this.y = y; this.z = z; -@@ -425,10 +425,27 @@ public class Explosion { +@@ -426,10 +426,29 @@ public class Explosion { public void explode() { // CraftBukkit start @@ -17391,17 +16821,19 @@ index 90a82bd7977ebe520bdcc2ab99e11452d5cf4a21..0be03430d8257d918b7cf646af518473 + } + }else { + Location location = new Location(this.level.getWorld(), this.x, this.y, this.z); -+ if(!new org.purpurmc.purpur.event.PreBlockExplodeEvent(location.getBlock(), this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F, this.damageSource.explodedBlockState).callEvent()) { ++ org.bukkit.block.Block block = location.getBlock(); ++ org.bukkit.block.BlockState blockState = (this.damageSource.blockState != null) ? this.damageSource.blockState : block.getState(); ++ if(!new org.purpurmc.purpur.event.PreBlockExplodeEvent(location.getBlock(), this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F, blockState).callEvent()) { + this.wasCanceled = true; + return; + } + } + //Purpur end + - this.level.gameEvent(this.source, GameEvent.EXPLODE, new Vec3(this.x, this.y, this.z)); + this.level.gameEvent(this.source, (Holder) GameEvent.EXPLODE, new Vec3(this.x, this.y, this.z)); Set set = Sets.newHashSet(); boolean flag = true; -@@ -675,7 +692,7 @@ public class Explosion { +@@ -681,7 +700,7 @@ public class Explosion { } if (flag1) { @@ -17410,7 +16842,7 @@ index 90a82bd7977ebe520bdcc2ab99e11452d5cf4a21..0be03430d8257d918b7cf646af518473 List> list = new ArrayList(); Util.shuffle(this.toBlow, this.level.random); -@@ -751,7 +768,7 @@ public class Explosion { +@@ -759,7 +778,7 @@ public class Explosion { Block.popResource(this.level, (BlockPos) pair.getSecond(), (ItemStack) pair.getFirst()); } @@ -17420,10 +16852,10 @@ index 90a82bd7977ebe520bdcc2ab99e11452d5cf4a21..0be03430d8257d918b7cf646af518473 if (this.fire) { diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index a82de7111915b19cdc3f065910465a5e7e843aff..311c853f2150247350ab6ccb2dd92d58dbfc645c 100644 +index b4ef3ad2c17168085372f1fe46809f02d9dfe74a..eda2f8cc034cf46293be1be117a60cf8b663c303 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -173,6 +173,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -170,6 +170,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // Paper end - add paper world config public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray @@ -17431,7 +16863,7 @@ index a82de7111915b19cdc3f065910465a5e7e843aff..311c853f2150247350ab6ccb2dd92d58 public final co.aikar.timings.WorldTimingsHandler timings; // Paper public static BlockPos lastPhysicsProblem; // Spigot private org.spigotmc.TickLimiter entityLimiter; -@@ -190,6 +191,49 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -187,6 +188,49 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } // Paper end - fix and optimise world upgrading @@ -17481,15 +16913,7 @@ index a82de7111915b19cdc3f065910465a5e7e843aff..311c853f2150247350ab6ccb2dd92d58 public CraftWorld getWorld() { return this.world; } -@@ -215,12 +259,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - // Paper end - - public abstract ResourceKey getTypeKey(); -- -- protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); public net.minecraft.util.RandomSource getThreadUnsafeRandom() { return this.randomTickRandom; } // Pufferfish - move thread unsafe random initialization // Pufferfish - getter -+ -+ //protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); public net.minecraft.util.RandomSource getThreadUnsafeRandom() { return this.randomTickRandom; } // Pufferfish - move thread unsafe random initialization // Pufferfish - getter // Purpur - dont break ABI - +@@ -216,6 +260,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config; Async-Anti-Xray: Pass executor this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config @@ -17498,7 +16922,7 @@ index a82de7111915b19cdc3f065910465a5e7e843aff..311c853f2150247350ab6ccb2dd92d58 this.generator = gen; this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); -@@ -1268,18 +1314,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1257,18 +1303,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } protected void tickBlockEntities() { @@ -17522,7 +16946,7 @@ index a82de7111915b19cdc3f065910465a5e7e843aff..311c853f2150247350ab6ccb2dd92d58 // Spigot start // Iterator iterator = this.blockEntityTickers.iterator(); boolean flag = this.tickRateManager().runsNormally(); -@@ -1308,10 +1354,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1297,10 +1343,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 @@ -17535,7 +16959,7 @@ index a82de7111915b19cdc3f065910465a5e7e843aff..311c853f2150247350ab6ccb2dd92d58 this.spigotConfig.currentPrimedTnt = 0; // Spigot } -@@ -1521,7 +1567,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1515,7 +1561,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Override public List getEntities(@Nullable Entity except, AABB box, Predicate predicate) { @@ -17544,7 +16968,7 @@ index a82de7111915b19cdc3f065910465a5e7e843aff..311c853f2150247350ab6ccb2dd92d58 List list = Lists.newArrayList(); ((ServerLevel)this).getEntityLookup().getEntities(except, box, list, predicate); // Paper - optimise this call return list; -@@ -1540,7 +1586,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1534,7 +1580,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } public void getEntities(EntityTypeTest filter, AABB box, Predicate predicate, List result, int limit) { @@ -17553,16 +16977,15 @@ index a82de7111915b19cdc3f065910465a5e7e843aff..311c853f2150247350ab6ccb2dd92d58 // Paper start - optimise this call //TODO use limit if (filter instanceof net.minecraft.world.entity.EntityType entityTypeTest) { -@@ -1799,7 +1845,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1789,6 +1835,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } public ProfilerFiller getProfiler() { -- if (gg.pufferfish.pufferfish.PufferfishConfig.disableMethodProfiler) return net.minecraft.util.profiling.InactiveProfiler.INSTANCE; // Pufferfish -+ if (true || gg.pufferfish.pufferfish.PufferfishConfig.disableMethodProfiler) return net.minecraft.util.profiling.InactiveProfiler.INSTANCE; // Pufferfish // Purpur ++ //if (true || gg.pufferfish.pufferfish.PufferfishConfig.disableMethodProfiler) return net.minecraft.util.profiling.InactiveProfiler.INSTANCE; // Pufferfish // Purpur // Purpur - TODO: Pufferfish return (ProfilerFiller) this.profiler.get(); } -@@ -1909,4 +1955,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1900,4 +1947,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return null; } // Paper end - optimize redstone (Alternate Current) @@ -17577,10 +17000,10 @@ index a82de7111915b19cdc3f065910465a5e7e843aff..311c853f2150247350ab6ccb2dd92d58 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 661acdf4b1f33d150b0caf179e925d3162d7be35..a2026900948e9157cb35ba0183dc3af20c63214f 100644 +index ed8032495af9ce9c23419224814b8d27e4a97c17..0f90a6803851eba51e164772c984b1cd1193d882 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -132,8 +132,8 @@ public final class NaturalSpawner { +@@ -127,8 +127,8 @@ public final class NaturalSpawner { } public static void spawnForChunk(ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnState info, boolean spawnAnimals, boolean spawnMonsters, boolean rareSpawn) { @@ -17591,7 +17014,7 @@ index 661acdf4b1f33d150b0caf179e925d3162d7be35..a2026900948e9157cb35ba0183dc3af2 MobCategory[] aenumcreaturetype = NaturalSpawner.SPAWNING_CATEGORIES; int i = aenumcreaturetype.length; -@@ -186,8 +186,8 @@ public final class NaturalSpawner { +@@ -181,8 +181,8 @@ public final class NaturalSpawner { } } @@ -17602,7 +17025,7 @@ index 661acdf4b1f33d150b0caf179e925d3162d7be35..a2026900948e9157cb35ba0183dc3af2 } // Paper start - Add mobcaps commands -@@ -258,7 +258,7 @@ public final class NaturalSpawner { +@@ -253,7 +253,7 @@ public final class NaturalSpawner { blockposition_mutableblockposition.set(l, i, i1); double d0 = (double) l + 0.5D; double d1 = (double) i1 + 0.5D; @@ -17612,66 +17035,65 @@ index 661acdf4b1f33d150b0caf179e925d3162d7be35..a2026900948e9157cb35ba0183dc3af2 if (entityhuman != null) { double d2 = entityhuman.distanceToSqr(d0, (double) i, d1); diff --git a/src/main/java/net/minecraft/world/level/block/AnvilBlock.java b/src/main/java/net/minecraft/world/level/block/AnvilBlock.java -index 18d2ff1baa2db0b97f2565eac006fbc4e81022fa..58d29c89e8e54fac143982c40c9aecc855b6cfd5 100644 +index 923357251ad950ec4f893e8771fcfa99de8a60c5..78a341ac80806f86f2ca0bd895fb091a9257519e 100644 --- a/src/main/java/net/minecraft/world/level/block/AnvilBlock.java +++ b/src/main/java/net/minecraft/world/level/block/AnvilBlock.java -@@ -62,6 +62,54 @@ public class AnvilBlock extends FallingBlock { +@@ -59,6 +59,53 @@ public class AnvilBlock extends FallingBlock { + return this.defaultBlockState().setValue(FACING, ctx.getHorizontalDirection().getClockWise()); + } ++ // Purpur start - repairable/damageable anvils ++ @Override ++ protected net.minecraft.world.ItemInteractionResult useItemOn(final net.minecraft.world.item.ItemStack stack, final BlockState state, final Level world, final BlockPos pos, final Player player, final net.minecraft.world.InteractionHand hand, final BlockHitResult hit) { ++ if (world.purpurConfig.anvilRepairIngotsAmount > 0 && stack.is(net.minecraft.world.item.Items.IRON_INGOT)) { ++ if (stack.getCount() < world.purpurConfig.anvilRepairIngotsAmount) { ++ // not enough iron ingots, play "error" sound and consume ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.ItemInteractionResult.CONSUME; ++ } ++ if (state.is(Blocks.DAMAGED_ANVIL)) { ++ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); ++ } else if (state.is(Blocks.CHIPPED_ANVIL)) { ++ world.setBlock(pos, Blocks.ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); ++ } else if (state.is(Blocks.ANVIL)) { ++ // anvil is already fully repaired, play "error" sound and consume ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.ItemInteractionResult.CONSUME; ++ } ++ if (!player.getAbilities().instabuild) { ++ stack.shrink(world.purpurConfig.anvilRepairIngotsAmount); ++ } ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_PLACE, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.ItemInteractionResult.CONSUME; ++ } ++ if (world.purpurConfig.anvilDamageObsidianAmount > 0 && stack.is(net.minecraft.world.item.Items.OBSIDIAN)) { ++ if (stack.getCount() < world.purpurConfig.anvilDamageObsidianAmount) { ++ // not enough obsidian, play "error" sound and consume ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.ItemInteractionResult.CONSUME; ++ } ++ if (state.is(Blocks.DAMAGED_ANVIL)) { ++ world.destroyBlock(pos, false); ++ } else if (state.is(Blocks.CHIPPED_ANVIL)) { ++ world.setBlock(pos, Blocks.DAMAGED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); ++ } else if (state.is(Blocks.ANVIL)) { ++ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); ++ } ++ if (!player.getAbilities().instabuild) { ++ stack.shrink(world.purpurConfig.anvilDamageObsidianAmount); ++ } ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_LAND, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.ItemInteractionResult.CONSUME; ++ } ++ return net.minecraft.world.ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; ++ } ++ // Purpur end ++ @Override - public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { -+ // Purpur start - repairable/damageable anvils -+ if (world.purpurConfig.anvilRepairIngotsAmount > 0) { -+ net.minecraft.world.item.ItemStack itemstack = player.getItemInHand(hand); -+ if (itemstack.is(net.minecraft.world.item.Items.IRON_INGOT)) { -+ if (itemstack.getCount() < world.purpurConfig.anvilRepairIngotsAmount) { -+ // not enough iron ingots, play "error" sound and consume -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return InteractionResult.CONSUME; -+ } -+ if (state.is(Blocks.DAMAGED_ANVIL)) { -+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); -+ } else if (state.is(Blocks.CHIPPED_ANVIL)) { -+ world.setBlock(pos, Blocks.ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); -+ } else if (state.is(Blocks.ANVIL)) { -+ // anvil is already fully repaired, play "error" sound and consume -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return InteractionResult.CONSUME; -+ } -+ if (!player.getAbilities().instabuild) { -+ itemstack.shrink(world.purpurConfig.anvilRepairIngotsAmount); -+ } -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_PLACE, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return InteractionResult.CONSUME; -+ } -+ } -+ if (world.purpurConfig.anvilDamageObsidianAmount > 0) { -+ net.minecraft.world.item.ItemStack itemstack = player.getItemInHand(hand); -+ if (itemstack.is(net.minecraft.world.item.Items.OBSIDIAN)) { -+ if (itemstack.getCount() < world.purpurConfig.anvilDamageObsidianAmount) { -+ // not enough obsidian, play "error" sound and consume -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return InteractionResult.CONSUME; -+ } -+ if (state.is(Blocks.DAMAGED_ANVIL)) { -+ world.destroyBlock(pos, false); -+ } else if (state.is(Blocks.CHIPPED_ANVIL)) { -+ world.setBlock(pos, Blocks.DAMAGED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); -+ } else if (state.is(Blocks.ANVIL)) { -+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); -+ } -+ if (!player.getAbilities().instabuild) { -+ itemstack.shrink(world.purpurConfig.anvilDamageObsidianAmount); -+ } -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_LAND, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return InteractionResult.CONSUME; -+ } -+ } -+ // Purpur end + protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { if (world.isClientSide) { - return InteractionResult.SUCCESS; - } else { diff --git a/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java b/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java -index 85484d061090d989de8246df81f8e9e5f8906072..472e5d52e948d172b678b0f8e60b442b4d65bb5b 100644 +index fad69dfc20574ab23634b14252b50929cca75b21..7082486f6b760bed2a61938f493d5124722b58e2 100644 --- a/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java +++ b/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java @@ -49,6 +49,20 @@ public class AzaleaBlock extends BushBlock implements BonemealableBlock { @@ -17696,7 +17118,7 @@ index 85484d061090d989de8246df81f8e9e5f8906072..472e5d52e948d172b678b0f8e60b442b } diff --git a/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java b/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java -index ffcb4849d83e0f02adbb106f4543bb4898678267..700108e84cf3836a0542c5e04856a9fe254794e9 100644 +index ce9f189bdafec26360bfadd0f36a8bc2726e132b..d5465b48531fd4b4094874c135274abf985ee71a 100644 --- a/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java +++ b/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java @@ -38,6 +38,7 @@ public abstract class BaseCoralPlantTypeBlock extends Block implements SimpleWat @@ -17708,28 +17130,28 @@ index ffcb4849d83e0f02adbb106f4543bb4898678267..700108e84cf3836a0542c5e04856a9fe return true; } else { diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java -index 38fcde81d797dc46409f5a9ed426fe296d79bdfa..83fa72b5a8fde431e7035fe5cacc50e33ae506bf 100644 +index f726c3839ab93cc81fee26bfeb821bead3533b5e..a4bae9631acfc363d22b89fb76965183d9dc79f1 100644 --- a/src/main/java/net/minecraft/world/level/block/BedBlock.java +++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java -@@ -106,7 +106,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock +@@ -104,7 +104,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock Vec3 vec3d = pos.getCenter(); -- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, explodedBlockState), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); // Paper - add exploded state -+ if (world.purpurConfig.bedExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, explodedBlockState), (ExplosionDamageCalculator) null, vec3d, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // Paper - add exploded state // Purpur +- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); ++ if (world.purpurConfig.bedExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d), (ExplosionDamageCalculator) null, vec3d, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // Purpur return InteractionResult.SUCCESS; } else if ((Boolean) state.getValue(BedBlock.OCCUPIED)) { if (!BedBlock.canSetSpawn(world)) return this.explodeBed(state, world, pos); // Paper - check explode first -@@ -159,7 +159,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock +@@ -156,7 +156,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock Vec3 vec3d = blockposition.getCenter(); -- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, explodedBlockState), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); // Paper - add exploded state -+ if (world.purpurConfig.bedExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, explodedBlockState), (ExplosionDamageCalculator) null, vec3d, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // Paper - add exploded state // Purpur +- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, world, iblockdata, blockposition), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state ++ if (world.purpurConfig.bedExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, world, iblockdata, blockposition), (ExplosionDamageCalculator) null, vec3d, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // CraftBukkit - add state // Purpur return InteractionResult.SUCCESS; } } -@@ -183,7 +183,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock +@@ -180,7 +180,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock @Override public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { @@ -17739,10 +17161,10 @@ index 38fcde81d797dc46409f5a9ed426fe296d79bdfa..83fa72b5a8fde431e7035fe5cacc50e3 @Override diff --git a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java -index 0d92bd6f1e4f3470a62f573add3490220e60ef7a..2e89b22de852f43f2694be52043799f07f14800b 100644 +index 8240c32d676a88aa23dcd052ee0136767e54fb0d..372c4ab9d390d5afd98947f21c79aae06b15064d 100644 --- a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java +++ b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java -@@ -243,7 +243,7 @@ public class BigDripleafBlock extends HorizontalDirectionalBlock implements Bone +@@ -244,7 +244,7 @@ public class BigDripleafBlock extends HorizontalDirectionalBlock implements Bone BigDripleafBlock.playTiltSound(world, blockposition, soundeffect); } @@ -17752,24 +17174,10 @@ index 0d92bd6f1e4f3470a62f573add3490220e60ef7a..2e89b22de852f43f2694be52043799f0 if (i != -1) { world.scheduleTick(blockposition, (Block) this, i); diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 22036ed3ea0629bc12981a8d91a03e55cc2117d6..284149925440f413d23a9ec3ce704e70a74f4c08 100644 +index cf8b8c8efd1c9c81eb5f02d75bd75875eb66771f..c6ed00f89127a2857dfb9ce9e04513e5cf510dfb 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java +++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -63,6 +63,13 @@ import net.minecraft.world.phys.shapes.Shapes; - import net.minecraft.world.phys.shapes.VoxelShape; - import org.slf4j.Logger; - -+// Purpur start -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.ListTag; -+import net.minecraft.nbt.StringTag; -+import net.minecraft.world.Nameable; -+// Purpur end -+ - public class Block extends BlockBehaviour implements ItemLike { - - public static final MapCodec CODEC = simpleCodec(Block::new); -@@ -89,6 +96,10 @@ public class Block extends BlockBehaviour implements ItemLike { +@@ -89,6 +89,10 @@ public class Block extends BlockBehaviour implements ItemLike { public static final int UPDATE_LIMIT = 512; protected final StateDefinition stateDefinition; private BlockState defaultBlockState; @@ -17780,80 +17188,7 @@ index 22036ed3ea0629bc12981a8d91a03e55cc2117d6..284149925440f413d23a9ec3ce704e70 // Paper start public final boolean isDestroyable() { return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || -@@ -320,7 +331,7 @@ public class Block extends BlockBehaviour implements ItemLike { - public static void dropResources(BlockState state, LevelAccessor world, BlockPos pos, @Nullable BlockEntity blockEntity) { - if (world instanceof ServerLevel) { - Block.getDrops(state, (ServerLevel) world, pos, blockEntity).forEach((itemstack) -> { -- Block.popResource((ServerLevel) world, pos, itemstack); -+ Block.popResource((ServerLevel) world, pos, applyDisplayNameAndLoreFromTile(itemstack, blockEntity)); // Purpur - }); - state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY, true); - } -@@ -339,7 +350,7 @@ public class Block extends BlockBehaviour implements ItemLike { - event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping - event.callEvent(); - for (org.bukkit.inventory.ItemStack drop : event.getDrops()) { -- popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop)); -+ popResource(serverLevel, pos, applyDisplayNameAndLoreFromTile(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop), blockEntity)); // Purpur - } - state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping - block.popExperience(serverLevel, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping -@@ -356,13 +367,53 @@ public class Block extends BlockBehaviour implements ItemLike { - // Paper end - Properly handle xp dropping - if (world instanceof ServerLevel) { - Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> { -- Block.popResource(world, pos, itemstack1); -+ Block.popResource(world, pos, applyDisplayNameAndLoreFromTile(itemstack1, blockEntity)); // Purpur - }); - state.spawnAfterBreak((ServerLevel) world, pos, tool, dropExperience); // Paper - Properly handle xp dropping - } - - } - -+ // Purpur start -+ private static ItemStack applyDisplayNameAndLoreFromTile(ItemStack stack, BlockEntity blockEntity) { -+ if (stack.getItem() instanceof BlockItem) { -+ if (blockEntity != null && blockEntity.getLevel() instanceof ServerLevel && blockEntity.getLevel().purpurConfig.persistentTileEntityDisplayNames) { -+ String name = blockEntity.getPersistentDisplayName(); -+ ListTag lore = blockEntity.getPersistentLore(); -+ if (blockEntity instanceof Nameable) { -+ Nameable namedTile = (Nameable) blockEntity; -+ if (namedTile.hasCustomName()) { -+ name = Component.Serializer.toJson(namedTile.getCustomName()); -+ } -+ } -+ -+ if (name != null || lore != null) { -+ CompoundTag display = stack.getTagElement("display"); -+ if (display == null) { -+ display = new CompoundTag(); -+ } -+ -+ if (name != null) { -+ display.put("Name", StringTag.valueOf(name)); -+ } -+ if (lore != null) { -+ display.put("Lore", lore); -+ } -+ -+ CompoundTag tag = stack.getTag(); -+ if (tag == null) { -+ tag = new CompoundTag(); -+ } -+ tag.put("display", display); -+ -+ stack.setTag(tag); -+ } -+ } -+ } -+ return stack; -+ } -+ // Purpur end -+ - public static void popResource(Level world, BlockPos pos, ItemStack stack) { - double d0 = (double) EntityType.ITEM.getHeight() / 2.0D; - double d1 = (double) pos.getX() + 0.5D + Mth.nextDouble(world.random, -0.25D, 0.25D); -@@ -446,7 +497,17 @@ public class Block extends BlockBehaviour implements ItemLike { +@@ -438,7 +442,17 @@ public class Block extends BlockBehaviour implements ItemLike { } // Paper - fix drops not preventing stats/food exhaustion } @@ -17872,7 +17207,7 @@ index 22036ed3ea0629bc12981a8d91a03e55cc2117d6..284149925440f413d23a9ec3ce704e70 public boolean isPossibleToRespawnInThis(BlockState state) { return !state.isSolid() && !state.liquid(); -@@ -465,7 +526,7 @@ public class Block extends BlockBehaviour implements ItemLike { +@@ -457,7 +471,7 @@ public class Block extends BlockBehaviour implements ItemLike { } public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { @@ -17882,10 +17217,10 @@ index 22036ed3ea0629bc12981a8d91a03e55cc2117d6..284149925440f413d23a9ec3ce704e70 public void updateEntityAfterFallOn(BlockGetter world, Entity entity) { diff --git a/src/main/java/net/minecraft/world/level/block/Blocks.java b/src/main/java/net/minecraft/world/level/block/Blocks.java -index e7c8313cafc25858ac002e3c45e63db9e8cefee9..04eace0873f1133ccca9696282948dc7ebc6f398 100644 +index 260906f493416d98ab574a7262fce5e9b7e40c64..ce639e4a2d87202a10ef4fc73274c4b2c4e95720 100644 --- a/src/main/java/net/minecraft/world/level/block/Blocks.java +++ b/src/main/java/net/minecraft/world/level/block/Blocks.java -@@ -7380,6 +7380,7 @@ public class Blocks { +@@ -7389,6 +7389,7 @@ public class Blocks { BlockBehaviour.Properties.of() .mapColor(MapColor.PLANT) .forceSolidOff() @@ -17893,7 +17228,7 @@ index e7c8313cafc25858ac002e3c45e63db9e8cefee9..04eace0873f1133ccca9696282948dc7 .instabreak() .sound(SoundType.AZALEA) .noOcclusion() -@@ -7392,6 +7393,7 @@ public class Blocks { +@@ -7401,6 +7402,7 @@ public class Blocks { BlockBehaviour.Properties.of() .mapColor(MapColor.PLANT) .forceSolidOff() @@ -17902,12 +17237,12 @@ index e7c8313cafc25858ac002e3c45e63db9e8cefee9..04eace0873f1133ccca9696282948dc7 .sound(SoundType.FLOWERING_AZALEA) .noOcclusion() diff --git a/src/main/java/net/minecraft/world/level/block/BushBlock.java b/src/main/java/net/minecraft/world/level/block/BushBlock.java -index bed3d9c781c7d3ca260027b4737970889a54689c..db1941ed32d141327a8b11e54b3ff9900072ad36 100644 +index a7b4b5600e3c889c69ac22294899713d50b5fe5c..a27e298ffdfa6956be9cde429d2cd45483a51fed 100644 --- a/src/main/java/net/minecraft/world/level/block/BushBlock.java +++ b/src/main/java/net/minecraft/world/level/block/BushBlock.java @@ -52,4 +52,24 @@ public abstract class BushBlock extends Block { - public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) { - return type == PathComputationType.AIR && !this.hasCollision ? true : super.isPathfindable(state, world, pos, type); + protected boolean isPathfindable(BlockState state, PathComputationType type) { + return type == PathComputationType.AIR && !this.hasCollision ? true : super.isPathfindable(state, type); } + + // Purpur start @@ -17931,7 +17266,7 @@ index bed3d9c781c7d3ca260027b4737970889a54689c..db1941ed32d141327a8b11e54b3ff990 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/CactusBlock.java b/src/main/java/net/minecraft/world/level/block/CactusBlock.java -index ba4aaf850af36a84517c70581e141157c4f15b99..02ea708a5b5df9f753194cdc9312fc830af85c68 100644 +index ff4dda48116a2969704b355ff96407ba869b466e..066181ed274a492762baebf05bf51ac7848878cc 100644 --- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java +++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java @@ -23,7 +23,7 @@ import net.minecraft.world.phys.shapes.CollisionContext; @@ -17953,7 +17288,7 @@ index ba4aaf850af36a84517c70581e141157c4f15b99..02ea708a5b5df9f753194cdc9312fc83 return false; } @@ -134,4 +134,34 @@ public class CactusBlock extends Block { - public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) { + protected boolean isPathfindable(BlockState state, PathComputationType type) { return false; } + @@ -17988,7 +17323,7 @@ index ba4aaf850af36a84517c70581e141157c4f15b99..02ea708a5b5df9f753194cdc9312fc83 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java -index 9c7ee02d3aa3c33b45db4dc5c079495a69d60b15..5eed401d3d722c6553240aba4a8e2337ee32b263 100644 +index d6fffb0953494e8667cc456137cac0f5deebfbb6..f7a2244b998aebe354d38eec7aa22fd94ce404c9 100644 --- a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java +++ b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java @@ -133,7 +133,7 @@ public class CampfireBlock extends BaseEntityBlock implements SimpleWaterloggedB @@ -18001,7 +17336,7 @@ index 9c7ee02d3aa3c33b45db4dc5c079495a69d60b15..5eed401d3d722c6553240aba4a8e2337 @Override diff --git a/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java b/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java -index cdd7ab3fe589d089c0c03508721f46f6c136fc8a..6f148028c0fe503e9f6b327596d0954ce9e53269 100644 +index 655f51902e5d24643d41c4ec981743543c0890a5..e6a299eeda5d18274fa3b1fb542b217a074c1d83 100644 --- a/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java +++ b/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java @@ -71,7 +71,7 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock { @@ -18040,10 +17375,10 @@ index cdd7ab3fe589d089c0c03508721f46f6c136fc8a..6f148028c0fe503e9f6b327596d0954c entity.moveTo((double) pos.getX() + 0.5D, (double) pos.getY() + 0.05D, (double) pos.getZ() + 0.5D, 0.0F, 0.0F); // CraftBukkit start diff --git a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java -index 47b6b83842201620bd6620f5acf11bb14334e35d..b4d2499ae39fd3f14b2600a9663ea8a823bdfbe4 100644 +index c9968934f4ecaa8d81e545f279b3001c7b1ce545..03e4fce6f8226451365fc2831b5bf1e5e6091730 100644 --- a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java +++ b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java -@@ -36,7 +36,7 @@ public class CauldronBlock extends AbstractCauldronBlock { +@@ -37,7 +37,7 @@ public class CauldronBlock extends AbstractCauldronBlock { } protected static boolean shouldHandlePrecipitation(Level world, Biome.Precipitation precipitation) { @@ -18053,10 +17388,10 @@ index 47b6b83842201620bd6620f5acf11bb14334e35d..b4d2499ae39fd3f14b2600a9663ea8a8 @Override diff --git a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java -index bdd9f38dcb16b74c5916b75713dbe5082b32497d..65bae6630a11aa1d8d1b08d1f8e2519545ad850c 100644 +index 635fc086d832c641f840cf36d18cdc0fcc3beef3..e3ff7b8059da499cfde1106f6d51156931b292dc 100644 --- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java +++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java -@@ -95,4 +95,11 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements Bonemealabl +@@ -94,4 +94,11 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements Bonemealabl public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { world.setBlock(pos, state.setValue(BERRIES, Boolean.valueOf(true)), 2); } @@ -18082,10 +17417,10 @@ index daae7fd6e0148cfba8e359d990748a0c83a3376e..0e06b1bcd906e92c083dc74d56d6d0a2 return random.nextFloat() < f1 ? this.getNext(state) : Optional.empty(); } diff --git a/src/main/java/net/minecraft/world/level/block/ChestBlock.java b/src/main/java/net/minecraft/world/level/block/ChestBlock.java -index 305bce4d833116cc21e64fdcdfe13f03e94ff4ba..58838f3c443f80eb53c33f8aa764645240263da2 100644 +index 491474b66856fccb038ee436968c9a5d3e4bf75c..a66499c9bd9af9da5d261a3c1aa23b1d436d4008 100644 --- a/src/main/java/net/minecraft/world/level/block/ChestBlock.java +++ b/src/main/java/net/minecraft/world/level/block/ChestBlock.java -@@ -358,6 +358,7 @@ public class ChestBlock extends AbstractChestBlock implements +@@ -343,6 +343,7 @@ public class ChestBlock extends AbstractChestBlock implements } private static boolean isBlockedChestByBlock(BlockGetter world, BlockPos pos) { @@ -18094,79 +17429,76 @@ index 305bce4d833116cc21e64fdcdfe13f03e94ff4ba..58838f3c443f80eb53c33f8aa7646452 return world.getBlockState(blockposition1).isRedstoneConductor(world, blockposition1); diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -index f9084e2605d7403721fe6b714bfad051f932aaef..47b7baa41f341087bcd5dfec1d2a13b96f8357ca 100644 +index d3d12f9114173f4971f95d7ef895a4374705bd3f..f34159f8d6c51af2341bf49db0d6d6f0417919cf 100644 --- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java +++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -@@ -236,20 +236,28 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { - ItemStack itemstack = player.getItemInHand(hand); +@@ -237,18 +237,27 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + int i = (Integer) state.getValue(ComposterBlock.LEVEL); - if (i < 8 && ComposterBlock.COMPOSTABLES.containsKey(itemstack.getItem())) { + if (i < 8 && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem())) { - if (i < 7 && !world.isClientSide) { -- BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, itemstack); +- BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, stack); - // Paper start - handle cancelled events - if (iblockdata1 == null) { -- return InteractionResult.PASS; +- return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; - } - // Paper end -+ // Purpur start -+ BlockState newState = process(i, state, world, itemstack, pos, player); -+ if (newState == null) { -+ return InteractionResult.PASS; -+ } - +- - world.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0); -- player.awardStat(Stats.ITEM_USED.get(itemstack.getItem())); -- if (!player.getAbilities().instabuild) { -- itemstack.shrink(1); -- } +- player.awardStat(Stats.ITEM_USED.get(stack.getItem())); +- stack.consume(1, player); ++ // Purpur start - sneak to bulk process composter ++ BlockState newState = process(i, player, state, world, pos, stack); ++ if (newState == null) { ++ return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; + } + if (world.purpurConfig.composterBulkProcess && player.isShiftKeyDown() && newState != state) { + BlockState oldState; + int oldCount, newCount, oldLevel, newLevel; + do { + oldState = newState; -+ oldCount = itemstack.getCount(); ++ oldCount = stack.getCount(); + oldLevel = oldState.getValue(ComposterBlock.LEVEL); -+ newState = process(oldLevel, oldState, world, itemstack, pos, player); ++ newState = process(oldLevel, player, oldState, world, pos, stack); + if (newState == null) { -+ return InteractionResult.PASS; ++ return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; + } -+ newCount = itemstack.getCount(); ++ newCount = stack.getCount(); + newLevel = newState.getValue(ComposterBlock.LEVEL); + } while (newCount > 0 && (newCount != oldCount || newLevel != oldLevel || newState != oldState)); - } ++ } + // Purpur end - return InteractionResult.sidedSuccess(world.isClientSide); - } else if (i == 8) { -@@ -260,6 +268,26 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + return ItemInteractionResult.sidedSuccess(world.isClientSide); + } else { +@@ -256,6 +265,25 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { } } -+ private static BlockState process(int level, BlockState state, Level world, ItemStack itemstack, BlockPos pos, Player player) { ++ // Purpur start - sneak to bulk process composter ++ private static @Nullable BlockState process(int level, Player player, BlockState state, Level world, BlockPos pos, ItemStack stack) { + if (level < 7 && !world.isClientSide) { -+ BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, itemstack); ++ BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, stack); + // Paper start - handle cancelled events + if (iblockdata1 == null) { -+ return iblockdata1; ++ return null; + } + // Paper end + + world.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0); -+ player.awardStat(Stats.ITEM_USED.get(itemstack.getItem())); -+ if (!player.getAbilities().instabuild) { -+ itemstack.shrink(1); -+ } ++ player.awardStat(Stats.ITEM_USED.get(stack.getItem())); ++ stack.consume(1, player); + return iblockdata1; + } + return state; + } + // Purpur end + - public static BlockState insertItem(Entity user, BlockState state, ServerLevel world, ItemStack stack, BlockPos pos) { + @Override + protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { int i = (Integer) state.getValue(ComposterBlock.LEVEL); - diff --git a/src/main/java/net/minecraft/world/level/block/CoralBlock.java b/src/main/java/net/minecraft/world/level/block/CoralBlock.java -index 8fd8285e07de4a0457da507501e49a807542f3b1..e580c5a141bebdc45893b5abde01e633c864fc13 100644 +index 81fe0dea8e6e23c4a78f07fc2f9c0d68cd683f11..bff97b7d3909f2ec9e58a341b901b3741927543f 100644 --- a/src/main/java/net/minecraft/world/level/block/CoralBlock.java +++ b/src/main/java/net/minecraft/world/level/block/CoralBlock.java @@ -59,6 +59,7 @@ public class CoralBlock extends Block { @@ -18178,12 +17510,12 @@ index 8fd8285e07de4a0457da507501e49a807542f3b1..e580c5a141bebdc45893b5abde01e633 int i = aenumdirection.length; diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java -index 5b96d1ae4bd8546311e986bc312b1f85883a67f4..2077cb5dcf2352c9d5b502744aeb9a66df256939 100644 +index 112d2feba5f75a2a873b595617780515945c10e4..5a190834baef60c7b61074393f8856a933902d81 100644 --- a/src/main/java/net/minecraft/world/level/block/CropBlock.java +++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java @@ -179,7 +179,7 @@ public class CropBlock extends BushBlock implements BonemealableBlock { @Override - public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { + protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (entity instanceof Ravager && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit + if (entity instanceof Ravager && world.purpurConfig.ravagerGriefableBlocks.contains(world.getBlockState(pos).getBlock()) && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), (!world.purpurConfig.ravagerBypassMobGriefing && !world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)))) { // CraftBukkit // Purpur @@ -18207,18 +17539,18 @@ index 5b96d1ae4bd8546311e986bc312b1f85883a67f4..2077cb5dcf2352c9d5b502744aeb9a66 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/DoorBlock.java b/src/main/java/net/minecraft/world/level/block/DoorBlock.java -index ed57fbcfcff29a71026b0600b02daf4178d78429..31a5d3a5642123983b8c7df49be04f25141d15a2 100644 +index 42d43b7a7e3b7c53cc80b8706c130e660f2c72da..96199441202ad929ad0274574704635c538a93c7 100644 --- a/src/main/java/net/minecraft/world/level/block/DoorBlock.java +++ b/src/main/java/net/minecraft/world/level/block/DoorBlock.java @@ -198,6 +198,7 @@ public class DoorBlock extends Block { - public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { if (!this.type.canOpenByHand()) { return InteractionResult.PASS; + } else if (requiresRedstone(world, state, pos)) { return InteractionResult.CONSUME; // Purpur } else { state = (BlockState) state.cycle(DoorBlock.OPEN); world.setBlock(pos, state, 10); -@@ -301,4 +302,18 @@ public class DoorBlock extends Block { +@@ -299,4 +300,18 @@ public class DoorBlock extends Block { flag = false; return flag; } @@ -18238,10 +17570,10 @@ index ed57fbcfcff29a71026b0600b02daf4178d78429..31a5d3a5642123983b8c7df49be04f25 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java b/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java -index 7f365143ce5c62e734eceb855ba0a02ab3a99b27..bbb266cbe23da2573d3dfb3a6edd57461988d3c5 100644 +index fbe15cdd5b9bca2ab4b1e871abbbdbff49ade8a4..23d113842bf774bdc74e0dffcc97b642bc8684f1 100644 --- a/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java +++ b/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java -@@ -49,8 +49,8 @@ public class DragonEggBlock extends FallingBlock { +@@ -48,8 +48,8 @@ public class DragonEggBlock extends FallingBlock { } private void teleport(BlockState state, Level world, BlockPos pos) { @@ -18251,21 +17583,12 @@ index 7f365143ce5c62e734eceb855ba0a02ab3a99b27..bbb266cbe23da2573d3dfb3a6edd5746 for (int i = 0; i < 1000; ++i) { BlockPos blockposition1 = pos.offset(world.random.nextInt(16) - world.random.nextInt(16), world.random.nextInt(8) - world.random.nextInt(8), world.random.nextInt(16) - world.random.nextInt(16)); -diff --git a/src/main/java/net/minecraft/world/level/block/EnchantmentTableBlock.java b/src/main/java/net/minecraft/world/level/block/EnchantmentTableBlock.java -index f2157de3b52095657401a780a467da1f816eff98..b19461aafdb281a4eb6db6701fe7f97572ca321c 100644 ---- a/src/main/java/net/minecraft/world/level/block/EnchantmentTableBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EnchantmentTableBlock.java -@@ -30,6 +30,8 @@ import net.minecraft.world.level.pathfinder.PathComputationType; - import net.minecraft.world.phys.BlockHitResult; - import net.minecraft.world.phys.shapes.CollisionContext; - import net.minecraft.world.phys.shapes.VoxelShape; -+import net.minecraft.world.Containers; // Purpur -+import net.minecraft.world.item.Items; // Purpur - - public class EnchantmentTableBlock extends BaseEntityBlock { - public static final MapCodec CODEC = simpleCodec(EnchantmentTableBlock::new); -@@ -137,4 +139,18 @@ public class EnchantmentTableBlock extends BaseEntityBlock { - public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) { +diff --git a/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java b/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java +index 151e856dda3aa262c846ce8793650ee582bfb749..be0ed8a14e5726d5fcea1864302b18fb75fde2b4 100644 +--- a/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java +@@ -124,4 +124,18 @@ public class EnchantingTableBlock extends BaseEntityBlock { + protected boolean isPathfindable(BlockState state, PathComputationType type) { return false; } + @@ -18274,8 +17597,8 @@ index f2157de3b52095657401a780a467da1f816eff98..b19461aafdb281a4eb6db6701fe7f975 + public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean moved) { + BlockEntity blockEntity = level.getBlockEntity(pos); + -+ if (level.purpurConfig.enchantmentTableLapisPersists && blockEntity instanceof EnchantmentTableBlockEntity enchantmentTable) { -+ Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), new ItemStack(Items.LAPIS_LAZULI, enchantmentTable.getLapis())); ++ if (level.purpurConfig.enchantmentTableLapisPersists && blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) { ++ net.minecraft.world.Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.LAPIS_LAZULI, enchantmentTable.getLapis())); + level.updateNeighbourForOutputSignal(pos, this); + } + @@ -18284,11 +17607,11 @@ index f2157de3b52095657401a780a467da1f816eff98..b19461aafdb281a4eb6db6701fe7f975 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -index 4ba24bced9a2de4616a0418857d3738e0e322ea0..6660bea735dda46ab9493601f1f53b8e0075ca83 100644 +index 7272d70c672b54dcf595beafd7a2ed33c96e35cb..d7f33c676bba279661583d908d3a58c86d853545 100644 --- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java +++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java @@ -54,6 +54,14 @@ public class EndPortalBlock extends BaseEntityBlock { - public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { + protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (world instanceof ServerLevel && entity.canChangeDimensions() && Shapes.joinIsNotEmpty(Shapes.create(entity.getBoundingBox().move((double) (-pos.getX()), (double) (-pos.getY()), (double) (-pos.getZ()))), state.getShape(world, pos), BooleanOp.AND)) { + // Purpur start @@ -18303,19 +17626,19 @@ index 4ba24bced9a2de4616a0418857d3738e0e322ea0..6660bea735dda46ab9493601f1f53b8e ServerLevel worldserver = ((ServerLevel) world).getServer().getLevel(resourcekey); diff --git a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -index 280041cc5f2a630571d9f4c8610c46e175ccf0c1..82c99b3e21f23d9142921159eebb6d80de3529b6 100644 +index 5f9858ef8d0ec1a74d469ab4426eb1db068873fd..d7ef772444b301d0a3f167679027195e4150b064 100644 --- a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java +++ b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -@@ -92,7 +92,7 @@ public class EnderChestBlock extends AbstractChestBlock i +@@ -91,7 +91,7 @@ public class EnderChestBlock extends AbstractChestBlock i EnderChestBlockEntity enderChestBlockEntity = (EnderChestBlockEntity)blockEntity; playerEnderChestContainer.setActiveChest(enderChestBlockEntity); player.openMenu( -- new SimpleMenuProvider((syncId, inventory, playerx) -> ChestMenu.threeRows(syncId, inventory, playerEnderChestContainer), CONTAINER_TITLE) -+ new SimpleMenuProvider((syncId, inventory, playerx) -> org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? getEnderChestSixRows(syncId, inventory, player, playerEnderChestContainer) : ChestMenu.threeRows(syncId, inventory, playerEnderChestContainer), CONTAINER_TITLE) // Purpur +- new SimpleMenuProvider((i, inventory, playerx) -> ChestMenu.threeRows(i, inventory, playerEnderChestContainer), CONTAINER_TITLE) ++ new SimpleMenuProvider((i, inventory, playerx) -> org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? getEnderChestSixRows(i, inventory, player, playerEnderChestContainer) : ChestMenu.threeRows(i, inventory, playerEnderChestContainer), CONTAINER_TITLE) // Purpur ); player.awardStat(Stats.OPEN_ENDERCHEST); PiglinAi.angerNearbyPiglins(player, true); -@@ -103,6 +103,35 @@ public class EnderChestBlock extends AbstractChestBlock i +@@ -102,6 +102,35 @@ public class EnderChestBlock extends AbstractChestBlock i } } @@ -18352,10 +17675,10 @@ index 280041cc5f2a630571d9f4c8610c46e175ccf0c1..82c99b3e21f23d9142921159eebb6d80 public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { return new EnderChestBlockEntity(pos, state); diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index 6e4c852c93f2418ea69e485ed3a10cbe3a6e3bd2..0c39126ce51439cce05747161aba43bce33a12d8 100644 +index d59e33e7326489c6d55d316d0130f22235f4c63c..d0ec0722496ed931b48c4e7076fddbb1ed36e111 100644 --- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -110,7 +110,7 @@ public class FarmBlock extends Block { +@@ -111,7 +111,7 @@ public class FarmBlock extends Block { @Override public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { super.fallOn(world, state, pos, entity, fallDistance); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage. @@ -18364,7 +17687,7 @@ index 6e4c852c93f2418ea69e485ed3a10cbe3a6e3bd2..0c39126ce51439cce05747161aba43bc // CraftBukkit start - Interact soil org.bukkit.event.Cancellable cancellable; if (entity instanceof Player) { -@@ -124,6 +124,22 @@ public class FarmBlock extends Block { +@@ -125,6 +125,22 @@ public class FarmBlock extends Block { return; } @@ -18378,8 +17701,8 @@ index 6e4c852c93f2418ea69e485ed3a10cbe3a6e3bd2..0c39126ce51439cce05747161aba43bc + } + } + if (world.purpurConfig.farmlandTramplingFeatherFalling) { -+ Iterator armor = entity.getArmorSlots().iterator(); -+ if (armor.hasNext() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FALL_PROTECTION, armor.next()) >= (int) entity.fallDistance) { ++ Iterator armor = ((LivingEntity) entity).getArmorSlots().iterator(); ++ if (armor.hasNext() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) >= (int) entity.fallDistance) { + return; + } + } @@ -18387,7 +17710,7 @@ index 6e4c852c93f2418ea69e485ed3a10cbe3a6e3bd2..0c39126ce51439cce05747161aba43bc if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.DIRT.defaultBlockState())) { return; } -@@ -171,7 +187,7 @@ public class FarmBlock extends Block { +@@ -172,7 +188,7 @@ public class FarmBlock extends Block { } } @@ -18397,7 +17720,7 @@ index 6e4c852c93f2418ea69e485ed3a10cbe3a6e3bd2..0c39126ce51439cce05747161aba43bc } diff --git a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java -index 30300ef3ec839dfa944c992ab50db4d3859bb02e..0d64b19dbbca9d563d90cabf0e2d32f76bfc0c62 100644 +index cf05da1c86e3018db11dc079bf50317b6639e5cc..8e9903899ac91e9431f00675c1f5ac4a18e61593 100644 --- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java +++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java @@ -34,12 +34,12 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements @@ -18409,7 +17732,7 @@ index 30300ef3ec839dfa944c992ab50db4d3859bb02e..0d64b19dbbca9d563d90cabf0e2d32f7 } @Override - public boolean isRandomlyTicking(BlockState state) { + protected boolean isRandomlyTicking(BlockState state) { - return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25; + return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) < getMaxGrowthAge(); // Purpur } @@ -18474,7 +17797,7 @@ index ef364aa171a48482a45bc18cfe730ec20c3f7be6..74971d90506aa253d5ee821b5390fb25 } } diff --git a/src/main/java/net/minecraft/world/level/block/IceBlock.java b/src/main/java/net/minecraft/world/level/block/IceBlock.java -index 9c8c1df5187daefb1c8098b4d4a0976c71a7bbfd..cf4c1097d54c84b309ab02e9892d1b9e39d57490 100644 +index 013302623d3ca3ff88f242d740af935dcf4844a6..13dd8bc7d2f6b71a5f1779dde53c5c84d83538ce 100644 --- a/src/main/java/net/minecraft/world/level/block/IceBlock.java +++ b/src/main/java/net/minecraft/world/level/block/IceBlock.java @@ -41,7 +41,7 @@ public class IceBlock extends HalfTransparentBlock { @@ -18496,11 +17819,11 @@ index 9c8c1df5187daefb1c8098b4d4a0976c71a7bbfd..cf4c1097d54c84b309ab02e9892d1b9e } else { world.setBlockAndUpdate(pos, IceBlock.meltsInto()); diff --git a/src/main/java/net/minecraft/world/level/block/KelpBlock.java b/src/main/java/net/minecraft/world/level/block/KelpBlock.java -index 1b83d44291029ce978187467832595b6dfd76dd5..69f2c6cae089aa7e1306c9dbe83d4ff582ec777c 100644 +index 784b19bc78c8ad9476b6dac37b6778a409a7c675..d49dd8b20d3785cc9482ed2a34fbd7aed4c9e537 100644 --- a/src/main/java/net/minecraft/world/level/block/KelpBlock.java +++ b/src/main/java/net/minecraft/world/level/block/KelpBlock.java @@ -72,4 +72,11 @@ public class KelpBlock extends GrowingPlantHeadBlock implements LiquidBlockConta - public FluidState getFluidState(BlockState state) { + protected FluidState getFluidState(BlockState state) { return Fluids.WATER.getSource(false); } + @@ -18512,38 +17835,38 @@ index 1b83d44291029ce978187467832595b6dfd76dd5..69f2c6cae089aa7e1306c9dbe83d4ff5 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java -index 9b3dcf1a4d4cece92a629506d341f6bfe79d13d0..0ed39daf88a98f7fa887fb45d4f7c0348a607551 100644 +index 84623c632d8c2f0fa7ec939c711316d757117d23..1851035b9fdcc076442d0699567a3b020e6425d6 100644 --- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java +++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java -@@ -139,7 +139,7 @@ public class LiquidBlock extends Block implements BucketPickup { +@@ -137,7 +137,7 @@ public class LiquidBlock extends Block implements BucketPickup { @Override - public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { + protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { - if (this.shouldSpreadLiquid(world, pos, state)) { + if (world.purpurConfig.tickFluids && this.shouldSpreadLiquid(world, pos, state)) { // Purpur world.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper - Configurable speed for water flowing over lava } -@@ -167,7 +167,7 @@ public class LiquidBlock extends Block implements BucketPickup { +@@ -165,7 +165,7 @@ public class LiquidBlock extends Block implements BucketPickup { @Override - public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { + protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { - if (state.getFluidState().isSource() || neighborState.getFluidState().isSource()) { + if (world.getMinecraftWorld().purpurConfig.tickFluids && state.getFluidState().isSource() || neighborState.getFluidState().isSource()) { // Purpur world.scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay(world)); } -@@ -176,7 +176,7 @@ public class LiquidBlock extends Block implements BucketPickup { +@@ -174,7 +174,7 @@ public class LiquidBlock extends Block implements BucketPickup { @Override - public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { + protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { - if (this.shouldSpreadLiquid(world, pos, state)) { + if (world.purpurConfig.tickFluids && this.shouldSpreadLiquid(world, pos, state)) { // Purpur world.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper - Configurable speed for water flowing over lava } diff --git a/src/main/java/net/minecraft/world/level/block/MagmaBlock.java b/src/main/java/net/minecraft/world/level/block/MagmaBlock.java -index 746c211b575ca588deadbbcd5c55b614e8660ba8..2f38bac9efc224084505e802546623260830b6d4 100644 +index 77bbdc15472d656fd40e841a70e34d3d31580819..55ae530fac54236ea5614f8e92c30febc744f179 100644 --- a/src/main/java/net/minecraft/world/level/block/MagmaBlock.java +++ b/src/main/java/net/minecraft/world/level/block/MagmaBlock.java @@ -29,7 +29,7 @@ public class MagmaBlock extends Block { @@ -18556,20 +17879,20 @@ index 746c211b575ca588deadbbcd5c55b614e8660ba8..2f38bac9efc224084505e80254662326 } diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -index 1b5cc5d6aa0b4313da980ce175c54145852d0db0..f7b724696151b73343feac1ce406fca9377f2508 100644 +index a9e3078cefcae8cc4672d514a7add162590d48df..8d5e841d8cc69bf09a9f1b6248633a72ce5fe1d7 100644 --- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java @@ -60,7 +60,7 @@ public class NetherPortalBlock extends Block { @Override - public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { + protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { - if (world.spigotConfig.enableZombiePigmenPortalSpawns && world.dimensionType().natural() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && random.nextInt(2000) < world.getDifficulty().getId()) { // Spigot + if (world.spigotConfig.enableZombiePigmenPortalSpawns && world.dimensionType().natural() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && random.nextInt(world.purpurConfig.piglinPortalSpawnModifier) < world.getDifficulty().getId()) { // Spigot // Purpur while (world.getBlockState(pos).is((Block) this)) { pos = pos.below(); } @@ -92,6 +92,14 @@ public class NetherPortalBlock extends Block { - public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { + protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (entity.canChangeDimensions()) { + // Purpur start @@ -18584,7 +17907,7 @@ index 1b5cc5d6aa0b4313da980ce175c54145852d0db0..f7b724696151b73343feac1ce406fca9 EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); world.getCraftServer().getPluginManager().callEvent(event); diff --git a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java -index 0fc333f240d6918e841a9221be42973839408802..13eb4dffd60ea7902d620f484df5e3f2c4688402 100644 +index acbd60a2f162fe0e254e36d0e8e7face3fc8a7b3..b8355ea1de26c4b6905f477fb4e110f1762447b4 100644 --- a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java +++ b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java @@ -16,7 +16,7 @@ import net.minecraft.world.level.block.state.properties.IntegerProperty; @@ -18630,10 +17953,10 @@ index 0fc333f240d6918e841a9221be42973839408802..13eb4dffd60ea7902d620f484df5e3f2 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java -index a541dc3a6e373b30fff0abf5305e77854c190f10..ac88cb949808752a340637ffcb9d7256b7d09478 100644 +index 1d82cfe7af0dc42f88901fb0c44896771fdf8a93..43dd972b374daa1072608f3a68e812e7fb733a2b 100644 --- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java +++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java -@@ -94,7 +94,7 @@ public class NoteBlock extends Block { +@@ -95,7 +95,7 @@ public class NoteBlock extends Block { } private void playNote(@Nullable Entity entity, BlockState state, Level world, BlockPos pos) { @@ -18643,22 +17966,22 @@ index a541dc3a6e373b30fff0abf5305e77854c190f10..ac88cb949808752a340637ffcb9d7256 // org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE)); // if (event.isCancelled()) { diff --git a/src/main/java/net/minecraft/world/level/block/ObserverBlock.java b/src/main/java/net/minecraft/world/level/block/ObserverBlock.java -index 713352b68f82d4c4a19a712d5207de0f99456713..d056e80c98973e9ba64adc5a8554acc8a5f3eac9 100644 +index b38fbe5121f293f425d7673a6ce49b11d0ced0d9..2a74f42672b92393b52a61c27c5b8af77c8c6070 100644 --- a/src/main/java/net/minecraft/world/level/block/ObserverBlock.java +++ b/src/main/java/net/minecraft/world/level/block/ObserverBlock.java @@ -71,6 +71,7 @@ public class ObserverBlock extends DirectionalBlock { @Override - public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { + protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { if (state.getValue(ObserverBlock.FACING) == direction && !(Boolean) state.getValue(ObserverBlock.POWERED)) { + if (!world.getMinecraftWorld().purpurConfig.disableObserverClocks || !(neighborState.getBlock() instanceof ObserverBlock) || neighborState.getValue(ObserverBlock.FACING).getOpposite() != direction) // Purpur this.startSignal(world, pos); } diff --git a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -index 5835872df922b859a31b44e3723c67097f21a641..ecb595ddf21b593175c27d59fd9587e7f2d56517 100644 +index a2bd54dae4b0460d200f6d5300194a7ef5a28830..bf189a171530abfc9bba5db5a305feb391f2cbee 100644 --- a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java +++ b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -@@ -189,7 +189,7 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate +@@ -190,7 +190,7 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate @VisibleForTesting public static void maybeTransferFluid(BlockState state, ServerLevel world, BlockPos pos, float dripChance) { @@ -18667,7 +17990,7 @@ index 5835872df922b859a31b44e3723c67097f21a641..ecb595ddf21b593175c27d59fd9587e7 if (PointedDripstoneBlock.isStalactiteStartPos(state, world, pos)) { Optional optional = PointedDripstoneBlock.getFluidAboveStalactite(world, pos, state); -@@ -198,13 +198,13 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate +@@ -199,13 +199,13 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate float f1; if (fluidtype == Fluids.WATER) { @@ -18684,7 +18007,7 @@ index 5835872df922b859a31b44e3723c67097f21a641..ecb595ddf21b593175c27d59fd9587e7 if (dripChance < f1) { diff --git a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java -index 0dfcac8cfcbb09fe04486bff60119f7985714454..2dbf71e421156093c8bc387941eae991f5e6c957 100644 +index a6e6545402904141ffc6218a0158b0e9c67217c8..5eac1a54398dfa5571b98fb6eefca9d2bf9b2793 100644 --- a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java +++ b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java @@ -80,7 +80,7 @@ public class PowderSnowBlock extends Block implements BucketPickup { @@ -18697,7 +18020,7 @@ index 0dfcac8cfcbb09fe04486bff60119f7985714454..2dbf71e421156093c8bc387941eae991 } // CraftBukkit end diff --git a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java -index b84c48902ef24fdae17578a304e6c93dc20c5dce..e03125281767845564c48c98c3e6b6bbd269ade1 100644 +index 9603d8c84ff483030dc08e82d3579b89e5c1f6e9..8fc65c32a3c6e6842a76b36f45e1b1c23abbc480 100644 --- a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java +++ b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java @@ -30,7 +30,7 @@ public class PoweredRailBlock extends BaseRailBlock { @@ -18710,23 +18033,23 @@ index b84c48902ef24fdae17578a304e6c93dc20c5dce..e03125281767845564c48c98c3e6b6bb } else { int j = pos.getX(); diff --git a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java -index 088262f306755a9cb785c7a0cf0a9c66ed0965a8..a3621a126a286a2789d069382940e8aa24c4caf2 100644 +index be85535767bc79875c38da78a209d33d4be87c8a..2b840a5516073da46207552688428d86fc99975b 100644 --- a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java +++ b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java -@@ -148,7 +148,7 @@ public class RespawnAnchorBlock extends Block { +@@ -149,7 +149,7 @@ public class RespawnAnchorBlock extends Block { }; Vec3 vec3d = explodedPos.getCenter(); -- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, explodedBlockState), explosiondamagecalculator, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); // Paper - add exploded state -+ if (world.purpurConfig.respawnAnchorExplode)world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, explodedBlockState), explosiondamagecalculator, vec3d, (float) world.purpurConfig.respawnAnchorExplosionPower, world.purpurConfig.respawnAnchorExplosionFire, world.purpurConfig.respawnAnchorExplosionEffect);// Paper - add exploded state // Purpur +- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, world, state, explodedPos), explosiondamagecalculator, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state ++ if (world.purpurConfig.respawnAnchorExplode)world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, world, state, explodedPos), explosiondamagecalculator, vec3d, (float) world.purpurConfig.respawnAnchorExplosionPower, world.purpurConfig.respawnAnchorExplosionFire, world.purpurConfig.respawnAnchorExplosionEffect);// CraftBukkit - add state // Purpur } public static boolean canSetSpawn(Level world) { diff --git a/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java b/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java -index 09c61eb5ba129e9630a756b452ef6aa61745c533..837c8399b2f490d98ca556e66018bfd471cf05bf 100644 +index b6b367492ebe2af3e63381bef935c6077f6ddb27..09f34c30d9a03751ed826b26375ac5aee778cce4 100644 --- a/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java +++ b/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java -@@ -137,7 +137,7 @@ public class SculkShriekerBlock extends BaseEntityBlock implements SimpleWaterlo +@@ -134,7 +134,7 @@ public class SculkShriekerBlock extends BaseEntityBlock implements SimpleWaterlo @Nullable @Override public BlockState getStateForPlacement(BlockPlaceContext ctx) { @@ -18736,7 +18059,7 @@ index 09c61eb5ba129e9630a756b452ef6aa61745c533..837c8399b2f490d98ca556e66018bfd4 @Override diff --git a/src/main/java/net/minecraft/world/level/block/SlabBlock.java b/src/main/java/net/minecraft/world/level/block/SlabBlock.java -index 481611d1759c161925524a8756060fb2cc0c0bf4..04852b896fc57028a970cce04d15c304749b592d 100644 +index fa29eb15934b3dad171d27c21d99b2451cfe553b..ba4aa69425d796d306791ea193f9c6b21a065f0b 100644 --- a/src/main/java/net/minecraft/world/level/block/SlabBlock.java +++ b/src/main/java/net/minecraft/world/level/block/SlabBlock.java @@ -138,4 +138,25 @@ public class SlabBlock extends Block implements SimpleWaterloggedBlock { @@ -18766,11 +18089,11 @@ index 481611d1759c161925524a8756060fb2cc0c0bf4..04852b896fc57028a970cce04d15c304 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java b/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java -index a3da9536c3a3ad33d1c795673bdd7b05d6534054..9b057f3967aae5d0ca621b19d1212db91aaaee22 100644 +index 93e8e5107ac047c1f2579b4fe6b0a202edb695f6..f82d275aac7bf3949d3dcc412c7e39e115c69458 100644 --- a/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java +++ b/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java @@ -88,6 +88,12 @@ public class SnowLayerBlock extends Block { - public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { + protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { BlockState iblockdata1 = world.getBlockState(pos.below()); + // Purpur start @@ -18783,10 +18106,10 @@ index a3da9536c3a3ad33d1c795673bdd7b05d6534054..9b057f3967aae5d0ca621b19d1212db9 } diff --git a/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java b/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java -index e8b1c44da90f60cde20cda65aba2aa1e30f89d25..1ac38424a44aa2225b9bd3fa0fbbe61b7b24875c 100644 +index 4f190a40b8474aa06a92c8afcc06d0044120ff7b..66c17bdfecdfbcfb2d853e561432dd51a8f7ed46 100644 --- a/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java +++ b/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java -@@ -42,6 +42,60 @@ public class SpawnerBlock extends BaseEntityBlock { +@@ -42,6 +42,57 @@ public class SpawnerBlock extends BaseEntityBlock { return createTickerHelper(type, BlockEntityType.MOB_SPAWNER, world.isClientSide ? SpawnerBlockEntity::clientTick : SpawnerBlockEntity::serverTick); } @@ -18794,46 +18117,43 @@ index e8b1c44da90f60cde20cda65aba2aa1e30f89d25..1ac38424a44aa2225b9bd3fa0fbbe61b + @Override + public void playerDestroy(Level level, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, boolean includeDrops, boolean dropExp) { + if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.drop.spawners") && isSilkTouch(level, stack)) { -+ java.util.Optional> type = net.minecraft.world.entity.EntityType.by(((SpawnerBlockEntity) blockEntity).getSpawner().nextSpawnData.getEntityToSpawn()); -+ -+ net.minecraft.world.entity.EntityType entityType = type.orElse(null); -+ final net.kyori.adventure.text.Component mobName = io.papermc.paper.adventure.PaperAdventure.asAdventure(entityType == null ? Component.empty() : entityType.getDescription()); -+ net.minecraft.nbt.CompoundTag display = new net.minecraft.nbt.CompoundTag(); -+ net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); -+ net.minecraft.nbt.CompoundTag blockEntityTag = blockEntity.getUpdateTag(); -+ blockEntityTag.remove("Delay"); // remove this tag to allow stacking duplicate spawners -+ tag.put("BlockEntityTag", blockEntityTag); -+ -+ String name = level.purpurConfig.silkTouchSpawnerName; -+ if (name != null && !name.isEmpty() && !name.equals("Monster Spawner")) { -+ net.kyori.adventure.text.Component displayName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName)); -+ if (name.startsWith("")) { -+ displayName = displayName.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); -+ } -+ display.put("Name", net.minecraft.nbt.StringTag.valueOf(io.papermc.paper.adventure.PaperAdventure.asJsonString(displayName, java.util.Locale.ROOT))); -+ tag.put("display", display); -+ } -+ -+ List lore = level.purpurConfig.silkTouchSpawnerLore; -+ if (lore != null && !lore.isEmpty()) { -+ net.minecraft.nbt.ListTag list = new net.minecraft.nbt.ListTag(); -+ for (String line : lore) { -+ net.kyori.adventure.text.Component lineComponent = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(line, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName)); -+ if (line.startsWith("")) { -+ lineComponent = lineComponent.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); -+ } -+ list.add(net.minecraft.nbt.StringTag.valueOf(io.papermc.paper.adventure.PaperAdventure.asJsonString(lineComponent, java.util.Locale.ROOT))); -+ } -+ display.put("Lore", list); -+ tag.put("display", display); -+ } -+ + ItemStack item = new ItemStack(Blocks.SPAWNER.asItem()); -+ if (entityType != null) { -+ tag.putDouble("HideFlags", ItemStack.TooltipPart.ADDITIONAL.getMask()); // hides the "Interact with Spawn Egg" tooltip -+ item.setTag(tag); ++ ++ net.minecraft.world.level.SpawnData nextSpawnData = blockEntity instanceof SpawnerBlockEntity spawnerBlock ? spawnerBlock.getSpawner().nextSpawnData : null; ++ java.util.Optional> type = java.util.Optional.empty(); ++ if (nextSpawnData != null) { ++ type = net.minecraft.world.entity.EntityType.by(nextSpawnData.getEntityToSpawn()); ++ net.minecraft.world.level.SpawnData.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, nextSpawnData).result().ifPresent(tag -> item.set(net.minecraft.core.component.DataComponents.CUSTOM_DATA, net.minecraft.world.item.component.CustomData.EMPTY.update(compoundTag -> compoundTag.put("Purpur.SpawnData", tag)))); + } + ++ if (type.isPresent()) { ++ final net.kyori.adventure.text.Component mobName = io.papermc.paper.adventure.PaperAdventure.asAdventure(type.get().getDescription()); ++ ++ String name = level.purpurConfig.silkTouchSpawnerName; ++ if (name != null && !name.isEmpty() && !name.equals("Monster Spawner")) { ++ net.kyori.adventure.text.Component displayName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName)); ++ if (name.startsWith("")) { ++ displayName = displayName.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); ++ } ++ item.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME, io.papermc.paper.adventure.PaperAdventure.asVanilla(displayName)); ++ } ++ ++ List lore = level.purpurConfig.silkTouchSpawnerLore; ++ if (lore != null && !lore.isEmpty()) { ++ ++ List loreComponentList = new java.util.ArrayList<>(); ++ for (String line : lore) { ++ net.kyori.adventure.text.Component lineComponent = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(line, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName)); ++ if (line.startsWith("")) { ++ lineComponent = lineComponent.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); ++ } ++ loreComponentList.add(io.papermc.paper.adventure.PaperAdventure.asVanilla(lineComponent)); ++ } ++ ++ item.set(net.minecraft.core.component.DataComponents.LORE, new net.minecraft.world.item.component.ItemLore(loreComponentList, loreComponentList)); ++ } ++ item.set(net.minecraft.core.component.DataComponents.HIDE_ADDITIONAL_TOOLTIP, net.minecraft.util.Unit.INSTANCE); ++ } + popResource(level, pos, item); + } + super.playerDestroy(level, player, pos, state, blockEntity, stack, includeDrops, dropExp); @@ -18845,9 +18165,9 @@ index e8b1c44da90f60cde20cda65aba2aa1e30f89d25..1ac38424a44aa2225b9bd3fa0fbbe61b + // Purpur end + @Override - public void spawnAfterBreak(BlockState state, ServerLevel world, BlockPos pos, ItemStack tool, boolean dropExperience) { + protected void spawnAfterBreak(BlockState state, ServerLevel world, BlockPos pos, ItemStack tool, boolean dropExperience) { super.spawnAfterBreak(state, world, pos, tool, dropExperience); -@@ -50,6 +104,7 @@ public class SpawnerBlock extends BaseEntityBlock { +@@ -50,6 +101,7 @@ public class SpawnerBlock extends BaseEntityBlock { @Override public int getExpDrop(BlockState iblockdata, ServerLevel worldserver, BlockPos blockposition, ItemStack itemstack, boolean flag) { @@ -18856,7 +18176,7 @@ index e8b1c44da90f60cde20cda65aba2aa1e30f89d25..1ac38424a44aa2225b9bd3fa0fbbe61b int i = 15 + worldserver.random.nextInt(15) + worldserver.random.nextInt(15); diff --git a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java -index 8f3cca228f8ec1ea9379fa43af4baa7b18012dd2..7e87b4299979c9e46abb582da7a8e54a36e8dfc5 100644 +index 902825ec9ea05f4418b45f56a008d73f217bd178..6fe44572e34ad3e3a1851e73138bd8b778eb7849 100644 --- a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java +++ b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java @@ -58,7 +58,7 @@ public class SpongeBlock extends Block { @@ -18889,11 +18209,11 @@ index 8f3cca228f8ec1ea9379fa43af4baa7b18012dd2..7e87b4299979c9e46abb582da7a8e54a if (!iblockdata.is(Blocks.KELP) && !iblockdata.is(Blocks.KELP_PLANT) && !iblockdata.is(Blocks.SEAGRASS) && !iblockdata.is(Blocks.TALL_SEAGRASS)) { return false; diff --git a/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java b/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java -index 7c41b940dd915a27856f6fa6f9e536e296deeb53..51ba321172acc9908aac456f8209dd6af6987aa8 100644 +index c6ecb378d0cb2ac05b8f22f92fb85df060038f77..b0199a8ffb1ea4cafeadedb8b833063db177b3cd 100644 --- a/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java +++ b/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java -@@ -99,4 +99,14 @@ public class StonecutterBlock extends Block { - public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) { +@@ -98,4 +98,14 @@ public class StonecutterBlock extends Block { + protected boolean isPathfindable(BlockState state, PathComputationType type) { return false; } + @@ -18908,7 +18228,7 @@ index 7c41b940dd915a27856f6fa6f9e536e296deeb53..51ba321172acc9908aac456f8209dd6a + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java -index 04957d461d0e968d443737068aaeec1d0bce78b2..7a283fbe4663cb321739f8e42ade4039d84e462b 100644 +index c48c622e92cedeaa46b929c7adfedec98dd5a3fb..6449b5c424443b5f0ee7e3fce803449418fbed2a 100644 --- a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java +++ b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java @@ -20,7 +20,7 @@ import net.minecraft.world.level.material.FluidState; @@ -18956,10 +18276,10 @@ index 04957d461d0e968d443737068aaeec1d0bce78b2..7a283fbe4663cb321739f8e42ade4039 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -index b4646e26965e0f1f26c5019e7c6a13fdf22bdb47..9a76665c6369b4106d152370dc3d2f5645cb02b1 100644 +index a6f408e56fa6c9de82fd93555fe21e1b11ce1022..08ba90f760abb9fb62311dddd7b5bdbd0d9518d7 100644 --- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java +++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -@@ -169,7 +169,7 @@ public class TurtleEggBlock extends Block { +@@ -170,7 +170,7 @@ public class TurtleEggBlock extends Block { private boolean shouldUpdateHatchLevel(Level world) { float f = world.getTimeOfDay(1.0F); @@ -18968,7 +18288,7 @@ index b4646e26965e0f1f26c5019e7c6a13fdf22bdb47..9a76665c6369b4106d152370dc3d2f56 } @Override -@@ -202,6 +202,31 @@ public class TurtleEggBlock extends Block { +@@ -203,6 +203,31 @@ public class TurtleEggBlock extends Block { } private boolean canDestroyEgg(Level world, Entity entity) { @@ -18990,8 +18310,8 @@ index b4646e26965e0f1f26c5019e7c6a13fdf22bdb47..9a76665c6369b4106d152370dc3d2f56 + return false; + } + if (world.purpurConfig.turtleEggsTramplingFeatherFalling) { -+ java.util.Iterator armor = entity.getArmorSlots().iterator(); -+ return !armor.hasNext() || net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FALL_PROTECTION, armor.next()) < (int) entity.fallDistance; ++ java.util.Iterator armor = ((LivingEntity) entity).getArmorSlots().iterator(); ++ return !armor.hasNext() || net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) < (int) entity.fallDistance; + } + if (entity instanceof Player) { + return true; @@ -19034,10 +18354,10 @@ index 3dec5a082606ee35a8c8d7f746480262d6a189c5..b2f6ccae9576c176263e51a232e17a08 + // Purpur end } diff --git a/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java b/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java -index fb180f0bcd20e51d41cfc924029c0b23d3d26258..688d161cd6725f494366c23668ebd6ff709b1587 100644 +index bbf59b2577812e74ffd45f694b83a42e043273c0..5cb06959aeaceeb98cfee34b1df804e6642f305f 100644 --- a/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java +++ b/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java -@@ -76,6 +76,7 @@ public class WitherSkullBlock extends SkullBlock { +@@ -79,6 +79,7 @@ public class WitherSkullBlock extends SkullBlock { entitywither.moveTo((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.55D, (double) blockposition1.getZ() + 0.5D, shapedetector_shapedetectorcollection.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F, 0.0F); entitywither.yBodyRot = shapedetector_shapedetectorcollection.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F; entitywither.makeInvulnerable(); @@ -19046,10 +18366,10 @@ index fb180f0bcd20e51d41cfc924029c0b23d3d26258..688d161cd6725f494366c23668ebd6ff if (!world.addFreshEntity(entitywither, SpawnReason.BUILD_WITHER)) { return; diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -index 89d06253b00604114e543ebbe12a9993ae95dc41..5a3a619c4b936a4d186c0593f5af7b2493b85825 100644 +index a99fe191c429bb528209dd0f31b509acf9cccbb5..c02d638b8f117156c815821207a91c55796f00b2 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -44,6 +44,7 @@ import net.minecraft.world.level.Level; +@@ -45,6 +45,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.AbstractFurnaceBlock; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; @@ -19057,8 +18377,8 @@ index 89d06253b00604114e543ebbe12a9993ae95dc41..5a3a619c4b936a4d186c0593f5af7b24 import net.minecraft.world.phys.Vec3; // CraftBukkit start import org.bukkit.craftbukkit.block.CraftBlock; -@@ -208,6 +209,22 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - // Paper end - cache burn durations +@@ -213,6 +214,22 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit + } } + // Purpur start @@ -19066,21 +18386,21 @@ index 89d06253b00604114e543ebbe12a9993ae95dc41..5a3a619c4b936a4d186c0593f5af7b24 + Map map = Maps.newLinkedHashMap(); + map.putAll(getFuel()); + map.put(itemStack.getItem(), burnTime); -+ cachedBurnDurations = com.google.common.collect.ImmutableMap.copyOf(map); ++ AbstractFurnaceBlockEntity.fuelCache = com.google.common.collect.ImmutableMap.copyOf(map); + } + + public static void removeFuel(ItemStack itemStack) { + Map map = Maps.newLinkedHashMap(); + map.putAll(getFuel()); + map.remove(itemStack.getItem()); -+ cachedBurnDurations = com.google.common.collect.ImmutableMap.copyOf(map); ++ AbstractFurnaceBlockEntity.fuelCache = com.google.common.collect.ImmutableMap.copyOf(map); + } + // Purpur End + // CraftBukkit start - add fields and methods private int maxStack = MAX_STACK; public List transaction = new java.util.ArrayList(); -@@ -330,6 +347,21 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit +@@ -335,6 +352,21 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit } ItemStack itemstack = (ItemStack) blockEntity.items.get(1); @@ -19102,7 +18422,7 @@ index 89d06253b00604114e543ebbe12a9993ae95dc41..5a3a619c4b936a4d186c0593f5af7b24 boolean flag2 = !((ItemStack) blockEntity.items.get(0)).isEmpty(); boolean flag3 = !itemstack.isEmpty(); -@@ -415,6 +447,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit +@@ -420,6 +452,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit setChanged(world, pos, state); } @@ -19111,10 +18431,10 @@ index 89d06253b00604114e543ebbe12a9993ae95dc41..5a3a619c4b936a4d186c0593f5af7b24 private static boolean canBurn(RegistryAccess registryManager, @Nullable RecipeHolder recipe, NonNullList slots, int count) { diff --git a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -index 416aa989ebb18a8741cc9d605a1180ab830f6643..e38a0adf5463c48311ad08b8d2e5b5c2d989a3b5 100644 +index 6186e55014bbb9d5bedaa0e9d196879c55339d42..f4f11292d6d00f4a7c65e3e2a157bba595f70889 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -@@ -67,7 +67,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { +@@ -68,7 +68,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { public BarrelBlockEntity(BlockPos pos, BlockState state) { super(BlockEntityType.BARREL, pos, state); @@ -19132,7 +18452,7 @@ index 416aa989ebb18a8741cc9d605a1180ab830f6643..e38a0adf5463c48311ad08b8d2e5b5c2 this.openersCounter = new ContainerOpenersCounter() { @Override protected void onOpen(Level world, BlockPos pos, BlockState state) { -@@ -118,7 +127,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { +@@ -119,7 +128,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { @Override public int getContainerSize() { @@ -19150,7 +18470,7 @@ index 416aa989ebb18a8741cc9d605a1180ab830f6643..e38a0adf5463c48311ad08b8d2e5b5c2 } @Override -@@ -138,7 +156,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { +@@ -139,7 +157,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { @Override protected AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) { @@ -19169,10 +18489,10 @@ index 416aa989ebb18a8741cc9d605a1180ab830f6643..e38a0adf5463c48311ad08b8d2e5b5c2 @Override diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index 4b81b0180dfc96fc6a88646838a886ca5b5d301b..428773361d12ecbcf3a6bf790aedfe12a384f511 100644 +index a6ffbbc1b5021564864e42c0756342352c2b8290..5ad48d2003fbd83e60f6faa68532496131935828 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -88,6 +88,16 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name +@@ -92,6 +92,16 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name public double getEffectRange() { if (this.effectRange < 0) { @@ -19189,7 +18509,7 @@ index 4b81b0180dfc96fc6a88646838a886ca5b5d301b..428773361d12ecbcf3a6bf790aedfe12 return this.levels * 10 + 10; } else { return effectRange; -@@ -164,6 +174,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name +@@ -168,6 +178,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name int j = pos.getY(); int k = pos.getZ(); BlockPos blockposition1; @@ -19197,7 +18517,7 @@ index 4b81b0180dfc96fc6a88646838a886ca5b5d301b..428773361d12ecbcf3a6bf790aedfe12 if (blockEntity.lastCheckY < j) { blockposition1 = pos; -@@ -197,6 +208,9 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name +@@ -201,6 +212,9 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name } } } else { @@ -19207,7 +18527,7 @@ index 4b81b0180dfc96fc6a88646838a886ca5b5d301b..428773361d12ecbcf3a6bf790aedfe12 if (tileentitybeacon_beaconcolortracker == null || iblockdata1.getLightBlock(world, blockposition1) >= 15 && !iblockdata1.is(Blocks.BEDROCK)) { blockEntity.checkingBeamSections.clear(); blockEntity.lastCheckY = l; -@@ -216,7 +230,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name +@@ -220,7 +234,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name blockEntity.levels = BeaconBlockEntity.updateBase(world, i, j, k); } @@ -19217,10 +18537,10 @@ index 4b81b0180dfc96fc6a88646838a886ca5b5d301b..428773361d12ecbcf3a6bf790aedfe12 BeaconBlockEntity.playSound(world, pos, SoundEvents.BEACON_AMBIENT); } diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -index d445ed0895293dd45c36226051f5809be8587ebe..6afaab31539667667481f7e9bfc0c6846abe661a 100644 +index 7b263fab4f0014400b3b8e7e33db32f9a125f6ba..f7a6ab35c95ffda73f17843916ddb624ad290b42 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -@@ -47,7 +47,7 @@ public class BeehiveBlockEntity extends BlockEntity { +@@ -59,7 +59,7 @@ public class BeehiveBlockEntity extends BlockEntity { private final List stored = Lists.newArrayList(); @Nullable public BlockPos savedFlowerPos; @@ -19229,15 +18549,15 @@ index d445ed0895293dd45c36226051f5809be8587ebe..6afaab31539667667481f7e9bfc0c684 public BeehiveBlockEntity(BlockPos pos, BlockState state) { super(BlockEntityType.BEEHIVE, pos, state); -@@ -134,6 +134,22 @@ public class BeehiveBlockEntity extends BlockEntity { +@@ -146,11 +146,33 @@ public class BeehiveBlockEntity extends BlockEntity { return list; } + // Purpur start -+ public List releaseBee(BlockState iblockdata, BeeData data, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, boolean force) { ++ public List releaseBee(BlockState iblockdata, BeehiveBlockEntity.BeeData data, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, boolean force) { + List list = Lists.newArrayList(); + -+ BeehiveBlockEntity.releaseBee(this.level, this.worldPosition, iblockdata, data, list, tileentitybeehive_releasestatus, this.savedFlowerPos, force); ++ BeehiveBlockEntity.releaseOccupant(this.level, this.worldPosition, iblockdata, data.occupant, list, tileentitybeehive_releasestatus, this.savedFlowerPos, force); + + if (!list.isEmpty()) { + stored.remove(data); @@ -19249,10 +18569,8 @@ index d445ed0895293dd45c36226051f5809be8587ebe..6afaab31539667667481f7e9bfc0c684 + } + // Purpur end + - public void addOccupant(Entity entity, boolean hasNectar) { - this.addOccupantWithPresetTicks(entity, hasNectar, 0); - } -@@ -143,6 +159,12 @@ public class BeehiveBlockEntity extends BlockEntity { + @VisibleForDebug + public int getOccupantCount() { return this.stored.size(); } @@ -19265,124 +18583,32 @@ index d445ed0895293dd45c36226051f5809be8587ebe..6afaab31539667667481f7e9bfc0c684 // Paper start - Add EntityBlockStorage clearEntities public void clearBees() { this.stored.clear(); -@@ -207,7 +229,7 @@ public class BeehiveBlockEntity extends BlockEntity { +@@ -212,7 +234,7 @@ public class BeehiveBlockEntity extends BlockEntity { } - private static boolean releaseBee(Level world, BlockPos blockposition, BlockState iblockdata, BeehiveBlockEntity.BeeData tileentitybeehive_hivebee, @Nullable List list, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, @Nullable BlockPos blockposition1, boolean force) { + private static boolean releaseOccupant(Level world, BlockPos blockposition, BlockState iblockdata, BeehiveBlockEntity.Occupant tileentitybeehive_c, @Nullable List list, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, @Nullable BlockPos blockposition1, boolean force) { - if (!force && (world.isNight() || world.isRaining()) && tileentitybeehive_releasestatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) { + if (!force && ((world.isNight() && !world.purpurConfig.beeCanWorkAtNight) || (world.isRaining() && !world.purpurConfig.beeCanWorkInRain)) && tileentitybeehive_releasestatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) { // Purpur // CraftBukkit end return false; } else { -@@ -435,9 +457,9 @@ public class BeehiveBlockEntity extends BlockEntity { - private BeeReleaseStatus() {} +@@ -471,9 +493,9 @@ public class BeehiveBlockEntity extends BlockEntity { + } } - private static class BeeData { + public static class BeeData { // Purpur - change from private to public -- final CompoundTag entityData; -+ public final CompoundTag entityData; // Purpur - make public - int ticksInHive; - int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts - final int minOccupationTicks; -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -index 9ea74d37cd951e0dc76d20ed8234b5871035566c..e9701ed4e5b35ace1accd2b46f082191d8ab6497 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -6,6 +6,8 @@ import net.minecraft.CrashReportCategory; - import net.minecraft.core.BlockPos; - import net.minecraft.core.registries.BuiltInRegistries; - import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.ListTag; -+import net.minecraft.nbt.StringTag; - import net.minecraft.network.protocol.Packet; - import net.minecraft.network.protocol.game.ClientGamePacketListener; - import net.minecraft.resources.ResourceLocation; -@@ -73,10 +75,27 @@ public abstract class BlockEntity { - if (persistentDataTag instanceof CompoundTag) { - this.persistentDataContainer.putAll((CompoundTag) persistentDataTag); - } -+ // Purpur start -+ if (nbt.contains("Purpur.persistentDisplayName")) { -+ this.persistentDisplayName = nbt.getString("Purpur.persistentDisplayName"); -+ } -+ if (nbt.contains("Purpur.persistentLore")) { -+ this.persistentLore = nbt.getList("Purpur.persistentLore", 8); -+ } -+ // Purpur end - } - // CraftBukkit end +- private final BeehiveBlockEntity.Occupant occupant; ++ public final BeehiveBlockEntity.Occupant occupant; // Purpur - make public + private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts + private int ticksInHive; -- protected void saveAdditional(CompoundTag nbt) {} -+ protected void saveAdditional(CompoundTag nbt) { -+ // Purpur start -+ if (this.persistentDisplayName != null) { -+ nbt.put("Purpur.persistentDisplayName", StringTag.valueOf(this.persistentDisplayName)); -+ } -+ if (this.persistentLore != null) { -+ nbt.put("Purpur.persistentLore", this.persistentLore); -+ } -+ // Purpur end -+ } - - public final CompoundTag saveWithFullMetadata() { - CompoundTag nbttagcompound = this.saveWithoutMetadata(); -@@ -186,10 +205,24 @@ public abstract class BlockEntity { - - @Nullable - public Packet getUpdatePacket() { -+ // Purpur start -+ if (this instanceof net.minecraft.world.Nameable nameable && nameable.hasCustomName()) { -+ CompoundTag nbt = this.saveWithoutMetadata(); -+ nbt.remove("Items"); -+ return net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket.create(this, $ -> nbt); -+ } -+ // Purpur end - return null; - } - - public CompoundTag getUpdateTag() { -+ // Purpur start -+ if (this instanceof net.minecraft.world.Nameable nameable && nameable.hasCustomName()) { -+ CompoundTag nbt = this.saveWithoutMetadata(); -+ nbt.remove("Items"); -+ return nbt; -+ } -+ // Purpur end - return new CompoundTag(); - } - -@@ -262,4 +295,24 @@ public abstract class BlockEntity { - return tag; - } - // Paper end - Sanitize sent data -+ // Purpur start -+ private String persistentDisplayName = null; -+ private ListTag persistentLore = null; -+ -+ public void setPersistentDisplayName(String json) { -+ this.persistentDisplayName = json; -+ } -+ -+ public void setPersistentLore(ListTag lore) { -+ this.persistentLore = lore; -+ } -+ -+ public String getPersistentDisplayName() { -+ return this.persistentDisplayName; -+ } -+ -+ public ListTag getPersistentLore() { -+ return this.persistentLore; -+ } -+ // Purpur end - } diff --git a/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java -index 37e0b762b86e74f607a4541ecb7b24ad7a591d0e..7e3edd41f3a39ef14382e18b20af21e63ce0677b 100644 +index 73e532dc998e5701c1a73da846da3d3a79871b81..ff6fea842ca80c2ba51693fe62e5b74f9affdc19 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java -@@ -167,7 +167,7 @@ public class ConduitBlockEntity extends BlockEntity { +@@ -168,7 +168,7 @@ public class ConduitBlockEntity extends BlockEntity { if ((l > 1 || i1 > 1 || j1 > 1) && (i == 0 && (i1 == 2 || j1 == 2) || j == 0 && (l == 2 || j1 == 2) || k == 0 && (l == 2 || i1 == 2))) { BlockPos blockposition2 = pos.offset(i, j, k); BlockState iblockdata = world.getBlockState(blockposition2); @@ -19391,43 +18617,51 @@ index 37e0b762b86e74f607a4541ecb7b24ad7a591d0e..7e3edd41f3a39ef14382e18b20af21e6 int k1 = ablock.length; for (int l1 = 0; l1 < k1; ++l1) { -@@ -187,7 +187,7 @@ public class ConduitBlockEntity extends BlockEntity { +@@ -188,13 +188,13 @@ public class ConduitBlockEntity extends BlockEntity { private static void applyEffects(Level world, BlockPos pos, List activatingBlocks) { - int i = activatingBlocks.size(); -- int j = i / 7 * 16; // Paper - Conduit API; diff on change -+ int j = i / 7 * world.purpurConfig.conduitDistance; // Paper - Conduit API; diff on change // Purpur - int k = pos.getX(); - int l = pos.getY(); - int i1 = pos.getZ(); -@@ -218,20 +218,20 @@ public class ConduitBlockEntity extends BlockEntity { - blockEntity.destroyTarget = ConduitBlockEntity.findDestroyTarget(world, pos, blockEntity.destroyTargetUUID); - blockEntity.destroyTargetUUID = null; - } else if (blockEntity.destroyTarget == null) { -- List list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(pos), (entityliving1) -> { -+ List list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(pos, world), (entityliving1) -> { // Purpur + // CraftBukkit start +- ConduitBlockEntity.applyEffects(world, pos, ConduitBlockEntity.getRange(activatingBlocks)); ++ ConduitBlockEntity.applyEffects(world, pos, ConduitBlockEntity.getRange(activatingBlocks, world)); // Purpur + } + +- public static int getRange(List list) { ++ public static int getRange(List list, Level world) { // Purpur + // CraftBukkit end + int i = list.size(); +- int j = i / 7 * 16; ++ int j = i / 7 * world.purpurConfig.conduitDistance; // Purpur + // CraftBukkit start + return j; + } +@@ -237,20 +237,20 @@ public class ConduitBlockEntity extends BlockEntity { + tileentityconduit.destroyTarget = ConduitBlockEntity.findDestroyTarget(world, blockposition, tileentityconduit.destroyTargetUUID); + tileentityconduit.destroyTargetUUID = null; + } else if (tileentityconduit.destroyTarget == null) { +- List list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(blockposition), (entityliving1) -> { ++ List list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(blockposition, world), (entityliving1) -> { // Purpur return entityliving1 instanceof Enemy && entityliving1.isInWaterOrRain(); }); if (!list1.isEmpty()) { - blockEntity.destroyTarget = (LivingEntity) list1.get(world.random.nextInt(list1.size())); + tileentityconduit.destroyTarget = (LivingEntity) list1.get(world.random.nextInt(list1.size())); } -- } else if (!blockEntity.destroyTarget.isAlive() || !pos.closerThan(blockEntity.destroyTarget.blockPosition(), 8.0D)) { -+ } else if (!blockEntity.destroyTarget.isAlive() || !pos.closerThan(blockEntity.destroyTarget.blockPosition(), world.purpurConfig.conduitDamageDistance)) { // Purpur - blockEntity.destroyTarget = null; +- } else if (!tileentityconduit.destroyTarget.isAlive() || !blockposition.closerThan(tileentityconduit.destroyTarget.blockPosition(), 8.0D)) { ++ } else if (!tileentityconduit.destroyTarget.isAlive() || !blockposition.closerThan(tileentityconduit.destroyTarget.blockPosition(), world.purpurConfig.conduitDamageDistance)) { // Purpur + tileentityconduit.destroyTarget = null; } - if (blockEntity.destroyTarget != null) { - // CraftBukkit start -- if (blockEntity.destroyTarget.hurt(world.damageSources().magic().directBlock(world, pos), 4.0F)) { // CraftBukkit -+ if (blockEntity.destroyTarget.hurt(world.damageSources().magic().directBlock(world, pos), world.purpurConfig.conduitDamageAmount)) { // CraftBukkit // Purpur - world.playSound(null, blockEntity.destroyTarget.getX(), blockEntity.destroyTarget.getY(), blockEntity.destroyTarget.getZ(), SoundEvents.CONDUIT_ATTACK_TARGET, SoundSource.BLOCKS, 1.0F, 1.0F); + // CraftBukkit start + if (damageTarget && tileentityconduit.destroyTarget != null) { +- if (tileentityconduit.destroyTarget.hurt(world.damageSources().magic().directBlock(world, blockposition), 4.0F)) { ++ if (tileentityconduit.destroyTarget.hurt(world.damageSources().magic().directBlock(world, blockposition), world.purpurConfig.conduitDamageAmount)) { // Purpur + world.playSound(null, tileentityconduit.destroyTarget.getX(), tileentityconduit.destroyTarget.getY(), tileentityconduit.destroyTarget.getZ(), SoundEvents.CONDUIT_ATTACK_TARGET, SoundSource.BLOCKS, 1.0F, 1.0F); } // CraftBukkit end -@@ -256,16 +256,22 @@ public class ConduitBlockEntity extends BlockEntity { +@@ -275,16 +275,22 @@ public class ConduitBlockEntity extends BlockEntity { } - private static AABB getDestroyRangeAABB(BlockPos pos) { + public static AABB getDestroyRangeAABB(BlockPos pos) { + // Purpur start + return getDestroyRangeAABB(pos, null); + } @@ -19449,37 +18683,37 @@ index 37e0b762b86e74f607a4541ecb7b24ad7a591d0e..7e3edd41f3a39ef14382e18b20af21e6 return entityliving.getUUID().equals(uuid); }); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java -index 4d1a895f3749bdcb132de199e81a9d93330c0ee6..5978f6bee32d31db8dd6af5c22ff0282fd81416a 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java -@@ -24,6 +24,7 @@ public class EnchantmentTableBlockEntity extends BlockEntity implements Nameable - public float tRot; +diff --git a/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java +index d47bc2f54c4722a0b8c419b99ee57eb3cb25d750..fdeabdcc781b605d6f3ee18528fd380ffff95660 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java +@@ -28,6 +28,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable private static final RandomSource RANDOM = RandomSource.create(); + @Nullable private Component name; + private int lapis = 0; // Purpur - public EnchantmentTableBlockEntity(BlockPos pos, BlockState state) { + public EnchantingTableBlockEntity(BlockPos pos, BlockState state) { super(BlockEntityType.ENCHANTING_TABLE, pos, state); -@@ -35,6 +36,7 @@ public class EnchantmentTableBlockEntity extends BlockEntity implements Nameable +@@ -39,6 +40,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable if (this.hasCustomName()) { - nbt.putString("CustomName", Component.Serializer.toJson(this.name)); + nbt.putString("CustomName", Component.Serializer.toJson(this.name, registryLookup)); } + nbt.putInt("Purpur.Lapis", this.lapis); // Purpur } @Override -@@ -43,6 +45,7 @@ public class EnchantmentTableBlockEntity extends BlockEntity implements Nameable +@@ -47,6 +49,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable if (nbt.contains("CustomName", 8)) { - this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException + this.name = parseCustomNameSafe(nbt.getString("CustomName"), registryLookup); } + this.lapis = nbt.getInt("Purpur.Lapis"); // Purpur } - public static void bookAnimationTick(Level world, BlockPos pos, BlockState state, EnchantmentTableBlockEntity blockEntity) { -@@ -117,4 +120,14 @@ public class EnchantmentTableBlockEntity extends BlockEntity implements Nameable - public Component getCustomName() { - return this.name; + public static void bookAnimationTick(Level world, BlockPos pos, BlockState state, EnchantingTableBlockEntity blockEntity) { +@@ -138,4 +141,14 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable + public void removeComponentsFromTag(CompoundTag nbt) { + nbt.remove("CustomName"); } + + // Purpur start @@ -19492,81 +18726,14 @@ index 4d1a895f3749bdcb132de199e81a9d93330c0ee6..5978f6bee32d31db8dd6af5c22ff0282 + } + // Purpur } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -index 927c7ea03560be0c86884cec70ee8e408e66cb07..93764bf849ad8e427bf119f6ff3dbcbcc4c2415e 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -@@ -200,16 +200,31 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C - return this.setText((SignText) textChanger.apply(signtext), front); - } - -+ // Purpur start -+ private Component translateColors(org.bukkit.entity.Player player, String line, Style style) { -+ if (level.purpurConfig.signAllowColors) { -+ if (player.hasPermission("purpur.sign.color")) line = line.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1"); -+ if (player.hasPermission("purpur.sign.style")) line = line.replaceAll("(?i)&([l-or])", "\u00a7$1"); -+ if (player.hasPermission("purpur.sign.magic")) line = line.replaceAll("(?i)&([kr])", "\u00a7$1"); -+ -+ return io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line)); -+ } else { -+ return Component.literal(line).setStyle(style); -+ } -+ } -+ // Purpur end -+ - private SignText setMessages(net.minecraft.world.entity.player.Player entityhuman, List list, SignText signtext, boolean front) { // CraftBukkit - SignText originalText = signtext; // CraftBukkit - for (int i = 0; i < list.size(); ++i) { - FilteredText filteredtext = (FilteredText) list.get(i); - Style chatmodifier = signtext.getMessage(i, entityhuman.isTextFilteringEnabled()).getStyle(); - -+ org.bukkit.entity.Player player = (org.bukkit.craftbukkit.entity.CraftPlayer) entityhuman.getBukkitEntity(); // Purpur - if (entityhuman.isTextFilteringEnabled()) { -- signtext = signtext.setMessage(i, Component.literal(net.minecraft.SharedConstants.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only -+ signtext = signtext.setMessage(i, translateColors(player, net.minecraft.SharedConstants.filterText(filteredtext.filteredOrEmpty()), chatmodifier)); // Paper - filter sign text to chat only // Purpur - } else { -- signtext = signtext.setMessage(i, Component.literal(net.minecraft.SharedConstants.filterText(filteredtext.raw())).setStyle(chatmodifier), Component.literal(net.minecraft.SharedConstants.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only -+ signtext = signtext.setMessage(i, translateColors(player, net.minecraft.SharedConstants.filterText(filteredtext.raw()), chatmodifier), translateColors(player, net.minecraft.SharedConstants.filterText(filteredtext.filteredOrEmpty()), chatmodifier)); // Paper - filter sign text to chat only // Purpur - } - } - -@@ -349,6 +364,28 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C - return ClientboundBlockEntityDataPacket.create(this); - } - -+ // Purpur start -+ public ClientboundBlockEntityDataPacket getTranslatedUpdatePacket(boolean filtered, boolean front) { -+ final CompoundTag nbt = new CompoundTag(); -+ this.saveAdditional(nbt); -+ final Component[] lines = front ? frontText.getMessages(filtered) : backText.getMessages(filtered); -+ final String side = front ? "front_text" : "back_text"; -+ for (int i = 0; i < 4; i++) { -+ final var component = io.papermc.paper.adventure.PaperAdventure.asAdventure(lines[i]); -+ final String line = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().serialize(component); -+ final var text = net.kyori.adventure.text.Component.text(line); -+ final String json = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(text); -+ if (!nbt.contains(side)) nbt.put(side, new CompoundTag()); -+ final CompoundTag sideNbt = nbt.getCompound(side); -+ if (!sideNbt.contains("messages")) sideNbt.put("messages", new net.minecraft.nbt.ListTag()); -+ final net.minecraft.nbt.ListTag messagesNbt = sideNbt.getList("messages", Tag.TAG_STRING); -+ messagesNbt.set(i, net.minecraft.nbt.StringTag.valueOf(json)); -+ } -+ nbt.putString("PurpurEditor", "true"); -+ return ClientboundBlockEntityDataPacket.create(this, entity -> nbt); -+ } -+ // Purpur end -+ - @Override - public CompoundTag getUpdateTag() { - return this.saveWithoutMetadata(); diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -index 098fde8200a11f91f934ddab6b1486dac4014dfe..4997f120aa9877c199fbcaa0c2f65226e13b5a23 100644 +index 93bd70c1dc2ba8b893a6087730071c81fb1132f4..fb9611866671880fc7a1a969da928b8f2ad15269 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -@@ -171,6 +171,15 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity { +@@ -167,6 +167,15 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity { public static void teleportEntity(Level world, BlockPos pos, BlockState state, Entity entity, TheEndGatewayBlockEntity blockEntity) { - if (world instanceof ServerLevel && !blockEntity.isCoolingDown()) { + if (world instanceof ServerLevel worldserver && !blockEntity.isCoolingDown()) { + if (!entity.canChangeDimensions()) return; // Purpur + // Purpur start + if (world.purpurConfig.imposeTeleportRestrictionsOnGateways && (entity.isVehicle() || entity.isPassenger())) { @@ -19576,9 +18743,9 @@ index 098fde8200a11f91f934ddab6b1486dac4014dfe..4997f120aa9877c199fbcaa0c2f65226 + return; + } + // Purpur end - ServerLevel worldserver = (ServerLevel) world; - blockEntity.teleportCooldown = 100; + BlockPos blockposition1; + diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java b/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java index 205e223c356634bd6bc6bd58c6f0b7fda61a6f5f..bea05cb928d540a2f19b51bb7352d032b2dd69cd 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java @@ -19611,10 +18778,10 @@ index 205e223c356634bd6bc6bd58c6f0b7fda61a6f5f..bea05cb928d540a2f19b51bb7352d032 } diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -index 2892e586146cbc560f0bcf4b9af6d0575cb0a82e..d38d8fc7ef22fb68e867cc29dab1171c9aa6ac35 100644 +index 2034ca2edd3aff61d94416266e75402babd3e741..031fc626d2075cbe0941fecc188406712ab9953f 100644 --- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -@@ -84,7 +84,7 @@ public abstract class BlockBehaviour implements FeatureElement { +@@ -86,7 +86,7 @@ public abstract class BlockBehaviour implements FeatureElement { protected static final Direction[] UPDATE_SHAPE_ORDER = new Direction[]{Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH, Direction.DOWN, Direction.UP}; public final boolean hasCollision; @@ -19623,29 +18790,20 @@ index 2892e586146cbc560f0bcf4b9af6d0575cb0a82e..d38d8fc7ef22fb68e867cc29dab1171c protected final boolean isRandomlyTicking; protected final SoundType soundType; protected final float friction; -@@ -92,7 +92,7 @@ public abstract class BlockBehaviour implements FeatureElement { +@@ -94,7 +94,7 @@ public abstract class BlockBehaviour implements FeatureElement { protected final float jumpFactor; protected final boolean dynamicShape; protected final FeatureFlagSet requiredFeatures; - protected final BlockBehaviour.Properties properties; + public final BlockBehaviour.Properties properties; // Purpur - protected -> public @Nullable - protected ResourceLocation drops; + protected ResourceKey drops; diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 270a892373ecbb3982990d6201d79c8a66de4f60..97724cbd6c1bf172379e98d4a3f6e8cda5cda823 100644 +index 2a8609e33716949ff1877b6d10f64a9d7a7c81e9..fd637415625fdabcac07e120e9168d09c06141d4 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -122,7 +122,7 @@ public class LevelChunk extends ChunkAccess { - this.blockTicks = blockTickScheduler; - this.fluidTicks = fluidTickScheduler; - -- this.lightningTick = this.level.getThreadUnsafeRandom().nextInt(100000) << 1; // Pufferfish - initialize lightning tick -+ this.lightningTick = java.util.concurrent.ThreadLocalRandom.current().nextInt(100000) << 1; // Pufferfish - initialize lightning tick // Purpur - any random will do - } - - // CraftBukkit start -@@ -457,11 +457,11 @@ public class LevelChunk extends ChunkAccess { +@@ -443,11 +443,11 @@ public class LevelChunk extends ChunkAccess { if (LightEngine.hasDifferentLightProperties(this, blockposition, iblockdata1, iblockdata)) { ProfilerFiller gameprofilerfiller = this.level.getProfiler(); @@ -19660,7 +18818,7 @@ index 270a892373ecbb3982990d6201d79c8a66de4f60..97724cbd6c1bf172379e98d4a3f6e8cd } boolean flag3 = iblockdata1.hasBlockEntity(); -@@ -799,7 +799,7 @@ public class LevelChunk extends ChunkAccess { +@@ -785,7 +785,7 @@ public class LevelChunk extends ChunkAccess { this.chunkHolder.getEntityChunk().callEntitiesLoadEvent(); // Paper - rewrite chunk system if (this.needsDecoration) { @@ -19669,7 +18827,7 @@ index 270a892373ecbb3982990d6201d79c8a66de4f60..97724cbd6c1bf172379e98d4a3f6e8cd this.needsDecoration = false; java.util.Random random = new java.util.Random(); random.setSeed(this.level.getSeed()); -@@ -819,7 +819,7 @@ public class LevelChunk extends ChunkAccess { +@@ -805,7 +805,7 @@ public class LevelChunk extends ChunkAccess { } } server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk)); @@ -19678,7 +18836,7 @@ index 270a892373ecbb3982990d6201d79c8a66de4f60..97724cbd6c1bf172379e98d4a3f6e8cd } } } -@@ -1174,10 +1174,10 @@ public class LevelChunk extends ChunkAccess { +@@ -1158,10 +1158,10 @@ public class LevelChunk extends ChunkAccess { if (LevelChunk.this.isTicking(blockposition)) { try { @@ -19692,7 +18850,7 @@ index 270a892373ecbb3982990d6201d79c8a66de4f60..97724cbd6c1bf172379e98d4a3f6e8cd BlockState iblockdata = LevelChunk.this.getBlockState(blockposition); if (this.blockEntity.getType().isValid(iblockdata)) { -@@ -1193,7 +1193,7 @@ public class LevelChunk extends ChunkAccess { +@@ -1177,7 +1177,7 @@ public class LevelChunk extends ChunkAccess { // Paper end - Remove the Block Entity if it's invalid } @@ -19701,7 +18859,7 @@ index 270a892373ecbb3982990d6201d79c8a66de4f60..97724cbd6c1bf172379e98d4a3f6e8cd } catch (Throwable throwable) { if (throwable instanceof ThreadDeath) throw throwable; // Paper // Paper start - Prevent block entity and entity crashes -@@ -1204,7 +1204,7 @@ public class LevelChunk extends ChunkAccess { +@@ -1188,7 +1188,7 @@ public class LevelChunk extends ChunkAccess { // Paper end - Prevent block entity and entity crashes // Spigot start } finally { @@ -19711,10 +18869,10 @@ index 270a892373ecbb3982990d6201d79c8a66de4f60..97724cbd6c1bf172379e98d4a3f6e8cd } } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -index 995fbfa225efe40274c20608b9b30b8afa847698..c70f04cdee1e8ba6f8a15c9e38edbe0023b5ab96 100644 +index bee39dee1b96023c907407877aedf3aafaf5e1b8..5b6bc200381a486c99061f9f5b7121c2c355b477 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -@@ -111,6 +111,7 @@ public class EntityStorage implements EntityPersistentStorage { +@@ -107,6 +107,7 @@ public class EntityStorage implements EntityPersistentStorage { ListTag listTag = new ListTag(); final java.util.Map, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk entities.forEach((entity) -> { // diff here: use entities parameter @@ -19723,10 +18881,10 @@ index 995fbfa225efe40274c20608b9b30b8afa847698..c70f04cdee1e8ba6f8a15c9e38edbe00 final EntityType entityType = entity.getType(); final int saveLimit = level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1); diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -index ed80960777b18faca2d6a99783e53daf5fa19e09..0847aef56d8608cb1403485f231f30b2527f35ab 100644 +index 1b1b475ca27e799e251d6f8a8c9fe1a4fd8bae83..04f67f7b43d2f461c776c76614dc3e5f060aea63 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java +++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -@@ -49,7 +49,7 @@ public class PhantomSpawner implements CustomSpawner { +@@ -48,7 +48,7 @@ public class PhantomSpawner implements CustomSpawner { int spawnAttemptMaxSeconds = world.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds; this.nextTick += (spawnAttemptMinSeconds + randomsource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; // Paper end - Ability to control player's insomnia and phantoms @@ -19735,7 +18893,7 @@ index ed80960777b18faca2d6a99783e53daf5fa19e09..0847aef56d8608cb1403485f231f30b2 return 0; } else { int i = 0; -@@ -61,10 +61,10 @@ public class PhantomSpawner implements CustomSpawner { +@@ -60,10 +60,10 @@ public class PhantomSpawner implements CustomSpawner { if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper - Add phantom creative and insomniac controls BlockPos blockposition = entityplayer.blockPosition(); @@ -19748,7 +18906,7 @@ index ed80960777b18faca2d6a99783e53daf5fa19e09..0847aef56d8608cb1403485f231f30b2 ServerStatsCounter serverstatisticmanager = entityplayer.getStats(); int j = Mth.clamp(serverstatisticmanager.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE); boolean flag2 = true; -@@ -76,7 +76,7 @@ public class PhantomSpawner implements CustomSpawner { +@@ -75,7 +75,7 @@ public class PhantomSpawner implements CustomSpawner { if (NaturalSpawner.isValidEmptySpawnBlock(world, blockposition1, iblockdata, fluid, EntityType.PHANTOM)) { SpawnGroupData groupdataentity = null; @@ -19758,10 +18916,10 @@ index ed80960777b18faca2d6a99783e53daf5fa19e09..0847aef56d8608cb1403485f231f30b2 for (int l = 0; l < k; ++l) { // Paper start - PhantomPreSpawnEvent diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -index 6411aa4ff6bd4cabb25c426fa8f4a7eedb969c03..0fe597d32a0e15ea67b32925c1a62e8c143ff81d 100644 +index c2943d892b067b3f1fb3b93301a092e912d71f08..a091c51476214977d7a9729b5c72e8478fe4a391 100644 --- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java +++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -@@ -227,7 +227,7 @@ public abstract class FlowingFluid extends Fluid { +@@ -217,7 +217,7 @@ public abstract class FlowingFluid extends Fluid { } } @@ -19770,7 +18928,7 @@ index 6411aa4ff6bd4cabb25c426fa8f4a7eedb969c03..0fe597d32a0e15ea67b32925c1a62e8c BlockState iblockdata2 = world.getBlockState(pos.below()); FluidState fluid1 = iblockdata2.getFluidState(); -@@ -336,6 +336,12 @@ public abstract class FlowingFluid extends Fluid { +@@ -301,6 +301,12 @@ public abstract class FlowingFluid extends Fluid { protected abstract boolean canConvertToSource(Level world); @@ -19829,7 +18987,7 @@ index 109f71401c65f476ccf6813137386fc9fef10254..9dcdb2f4001115db0c26fdbf86531dbe @Override protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state, BlockPos source) { diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java -index d1e1f12451058f7f276f8277536a4c0a4d736601..2046ac397f5c46cc45f233e36abbdbe717753fc7 100644 +index 18bbb3f8f99849333ff4bc020c8ce758a69312a5..404080976208c30e9e95e5bee47c2a749e709a45 100644 --- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java +++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java @@ -53,8 +53,8 @@ public class PathFinder { @@ -19853,38 +19011,29 @@ index d1e1f12451058f7f276f8277536a4c0a4d736601..2046ac397f5c46cc45f233e36abbdbe7 // Paper end - Perf: remove streams and optimize collection } diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -index 1cd7f0f1c7d62552e6609997c83f3df8dae13316..a6f745d21d982dfcbfb458472a7b2a8867d13504 100644 +index d5004290e40a1ff5e0fcfe75f8da34ae15962359..f26383cf896785333dbd6f86348d5a5f67a6731f 100644 --- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java +++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -@@ -259,7 +259,7 @@ public class WalkNodeEvaluator extends NodeEvaluator { +@@ -240,7 +240,7 @@ public class WalkNodeEvaluator extends NodeEvaluator { if ((node == null || node.costMalus < 0.0F) && maxYStep > 0 - && (blockPathTypes != BlockPathTypes.FENCE || this.canWalkOverFences()) -- && blockPathTypes != BlockPathTypes.UNPASSABLE_RAIL -+ && (this.mob.level().purpurConfig.mobsIgnoreRails || blockPathTypes != BlockPathTypes.UNPASSABLE_RAIL) // Purpur - && blockPathTypes != BlockPathTypes.TRAPDOOR - && blockPathTypes != BlockPathTypes.POWDER_SNOW) { - node = this.findAcceptedNode(x, y + 1, z, maxYStep - 1, prevFeetY, direction, nodeType); -@@ -475,7 +475,7 @@ public class WalkNodeEvaluator extends NodeEvaluator { - return BlockPathTypes.BLOCKED; - } else { - // Paper end - Do not load chunks during pathfinding -- if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH)) { -+ if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH) || blockState.is(Blocks.STONECUTTER)) { // Purpur - return BlockPathTypes.DANGER_OTHER; - } - -@@ -509,7 +509,7 @@ public class WalkNodeEvaluator extends NodeEvaluator { - return BlockPathTypes.TRAPDOOR; + && (pathType != PathType.FENCE || this.canWalkOverFences()) +- && pathType != PathType.UNPASSABLE_RAIL ++ && (this.mob.level().purpurConfig.mobsIgnoreRails || pathType != PathType.UNPASSABLE_RAIL) // Purpur + && pathType != PathType.TRAPDOOR + && pathType != PathType.POWDER_SNOW) { + node = this.tryJumpOn(x, y, z, maxYStep, prevFeetY, direction, nodeType, mutableBlockPos); +@@ -491,7 +491,7 @@ public class WalkNodeEvaluator extends NodeEvaluator { + return PathType.TRAPDOOR; } else if (blockState.is(Blocks.POWDER_SNOW)) { - return BlockPathTypes.POWDER_SNOW; + return PathType.POWDER_SNOW; - } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH)) { + } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH) || blockState.is(Blocks.STONECUTTER)) { // Purpur - return BlockPathTypes.DAMAGE_OTHER; + return PathType.DAMAGE_OTHER; } else if (blockState.is(Blocks.HONEY_BLOCK)) { - return BlockPathTypes.STICKY_HONEY; + return PathType.STICKY_HONEY; diff --git a/src/main/java/net/minecraft/world/level/portal/PortalShape.java b/src/main/java/net/minecraft/world/level/portal/PortalShape.java -index 912cee9ec45876f831ca230b59a1be3b48ce6aa5..46910a3bdacc9df1835e16b300f9e107744d2660 100644 +index af24467ee37cfc06f692b3b02e68f6cfbaaa8d59..afe6b2170846273b41b694aa53dca4c31bf78b3f 100644 --- a/src/main/java/net/minecraft/world/level/portal/PortalShape.java +++ b/src/main/java/net/minecraft/world/level/portal/PortalShape.java @@ -33,7 +33,7 @@ public class PortalShape { @@ -19897,10 +19046,10 @@ index 912cee9ec45876f831ca230b59a1be3b48ce6aa5..46910a3bdacc9df1835e16b300f9e107 private static final float SAFE_TRAVEL_MAX_ENTITY_XY = 4.0F; private static final double SAFE_TRAVEL_MAX_VERTICAL_DELTA = 1.0D; diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -index 45269115e63cfc3bd7dc740a5694e2cc7c35bcb1..e1498d496aa01c433b6fa198608e33916eadecf3 100644 +index cf8ae635fce7ea66d4e1ab1dc05575f035fa95ef..e26f6215ca42885cb0635a3183a8df93a924ba7f 100644 --- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -67,6 +67,7 @@ public class MapItemSavedData extends SavedData { +@@ -79,6 +79,7 @@ public class MapItemSavedData extends SavedData { private final Map frameMarkers = Maps.newHashMap(); private int trackedDecorationCount; private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper @@ -19909,7 +19058,7 @@ index 45269115e63cfc3bd7dc740a5694e2cc7c35bcb1..e1498d496aa01c433b6fa198608e3391 // CraftBukkit start public final CraftMapView mapView; diff --git a/src/main/java/net/minecraft/world/level/storage/loot/functions/LootingEnchantFunction.java b/src/main/java/net/minecraft/world/level/storage/loot/functions/LootingEnchantFunction.java -index 3fb1e558c3510243c94981211f9a0e5e0ef1895b..e5177e5ffcac360f935f2139db4554c6586b551e 100644 +index cfe953bc924f46b570e37395ac0f05ebcb82eb39..5500e7ada2dd783cc1317968a3e54696bdd73bf8 100644 --- a/src/main/java/net/minecraft/world/level/storage/loot/functions/LootingEnchantFunction.java +++ b/src/main/java/net/minecraft/world/level/storage/loot/functions/LootingEnchantFunction.java @@ -57,6 +57,13 @@ public class LootingEnchantFunction extends LootItemConditionalFunction { @@ -19975,7 +19124,7 @@ index 7a69564572357a7acc043e35b9c113beeb738951..a6d62abd3102770652f914b9d697c6d3 this.rescheduleLeftoverContainers(); } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -index 4a875bce9563f3b9351ebecde9b0eb1287beb50e..42d83cfd9318d6ebe9a5392edef3b667c9e4dac0 100644 +index 9d93130f23addb18b97d7f5ec013faef17a74529..29d2fb87a65778926aea2cfc7a5b486cad596515 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java @@ -335,14 +335,26 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa @@ -20213,19 +19362,19 @@ index 4a875bce9563f3b9351ebecde9b0eb1287beb50e..42d83cfd9318d6ebe9a5392edef3b667 + // Purpur end - OfflinePlayer API } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 18bfe2fb7efad66f5fae07a30593d640c597bf77..dabaf0cff6dafe8ca411996e67ead9a2cf84dfb8 100644 +index 05e304f9fc8d0291fa779da589bd060ef4165b49..8d754bf77cb88d8ddf964f3221183e4097f06d13 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -266,7 +266,7 @@ import javax.annotation.Nullable; // Paper +@@ -268,7 +268,7 @@ import javax.annotation.Nullable; // Paper import javax.annotation.Nonnull; // Paper public final class CraftServer implements Server { -- private final String serverName = "Pufferfish"; // Paper // Pufferfish +- private final String serverName = "Paper"; // Paper + private final String serverName = "Purpur"; // Paper // Pufferfish // Purpur private final String serverVersion; private final String bukkitVersion = Versioning.getBukkitVersion(); private final Logger logger = Logger.getLogger("Minecraft"); -@@ -400,6 +400,20 @@ public final class CraftServer implements Server { +@@ -403,6 +403,20 @@ public final class CraftServer implements Server { this.serverTickManager = new CraftServerTickManager(console.tickRateManager()); Bukkit.setServer(this); @@ -20326,7 +19475,7 @@ index 18bfe2fb7efad66f5fae07a30593d640c597bf77..dabaf0cff6dafe8ca411996e67ead9a2 @Override public List getRecipesFor(ItemStack result) { Preconditions.checkArgument(result != null, "ItemStack cannot be null"); -@@ -3033,6 +3099,18 @@ public final class CraftServer implements Server { +@@ -3048,6 +3114,18 @@ public final class CraftServer implements Server { return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console); } @@ -20345,7 +19494,7 @@ index 18bfe2fb7efad66f5fae07a30593d640c597bf77..dabaf0cff6dafe8ca411996e67ead9a2 @Override public void restart() { org.spigotmc.RestartCommand.restart(); -@@ -3062,6 +3140,7 @@ public final class CraftServer implements Server { +@@ -3077,6 +3155,7 @@ public final class CraftServer implements Server { @Override public double[] getTPS() { return new double[] { @@ -20353,9 +19502,9 @@ index 18bfe2fb7efad66f5fae07a30593d640c597bf77..dabaf0cff6dafe8ca411996e67ead9a2 net.minecraft.server.MinecraftServer.getServer().tps1.getAverage(), net.minecraft.server.MinecraftServer.getServer().tps5.getAverage(), net.minecraft.server.MinecraftServer.getServer().tps15.getAverage() -@@ -3264,4 +3343,16 @@ public final class CraftServer implements Server { +@@ -3278,4 +3357,16 @@ public final class CraftServer implements Server { + return this.potionBrewer; } - // Paper end + + // Purpur start @@ -20371,10 +19520,10 @@ index 18bfe2fb7efad66f5fae07a30593d640c597bf77..dabaf0cff6dafe8ca411996e67ead9a2 + // Purpur end } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 00357d78182b3ff87e3d9a45705b072af56739c8..69c12d9049af908380c48c7f13d3d5c7220f8e39 100644 +index f2b20ed5063a293f0b464548f590d652170cd1d8..226ff7c6048b510be2e71ecc5d5ff3581092aa5e 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2416,6 +2416,48 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2424,6 +2424,48 @@ public class CraftWorld extends CraftRegionAccessor implements World { return (this.getHandle().getDragonFight() == null) ? null : new CraftDragonBattle(this.getHandle().getDragonFight()); } @@ -20424,10 +19573,10 @@ index 00357d78182b3ff87e3d9a45705b072af56739c8..69c12d9049af908380c48c7f13d3d5c7 public Collection getStructures(int x, int z) { return this.getStructures(x, z, struct -> true); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 8d626fadcd4743b6472a2954d2b1b2ec89669814..409c0e81571e23c9d535b541c61538424259d60a 100644 +index c097f5d5fbd51cbbc01bbd54101905c59b3f3a4c..222865a3cee62f244a566092a7d814efe478ee01 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -174,6 +174,20 @@ public class Main { +@@ -175,6 +175,14 @@ public class Main { .describedAs("Jar file"); // Paper end @@ -20437,18 +19586,12 @@ index 8d626fadcd4743b6472a2954d2b1b2ec89669814..409c0e81571e23c9d535b541c6153842 + .ofType(File.class) + .defaultsTo(new File("purpur.yml")) + .describedAs("Yml file"); -+ -+ acceptsAll(asList("pufferfish", "pufferfish-settings"), "File for pufferfish settings") -+ .withRequiredArg() -+ .ofType(File.class) -+ .defaultsTo(new File("pufferfish.yml")) -+ .describedAs("Yml file"); + // Purpur end + // Paper start acceptsAll(asList("server-name"), "Name of the server") .withRequiredArg() -@@ -293,7 +307,7 @@ public class Main { +@@ -294,7 +302,7 @@ public class Main { System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper } @@ -20458,7 +19601,7 @@ index 8d626fadcd4743b6472a2954d2b1b2ec89669814..409c0e81571e23c9d535b541c6153842 Calendar deadline = Calendar.getInstance(); diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java -index 2e51fab98d95c93d2095f7be6dbb5d5474158bfb..32285c8e0f42897793759fba85a1e8658750c843 100644 +index 1a2a05160ba51d9c75f1ae6ae61d944d81428722..3beb26ad2ef0fded49a8da8c5dec64f9508c1995 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java @@ -16,8 +16,15 @@ import org.bukkit.entity.Bee; @@ -20476,7 +19619,7 @@ index 2e51fab98d95c93d2095f7be6dbb5d5474158bfb..32285c8e0f42897793759fba85a1e865 + // Purpur end } - protected CraftBeehive(CraftBeehive state) { + protected CraftBeehive(CraftBeehive state, Location location) { @@ -75,15 +82,54 @@ public class CraftBeehive extends CraftBlockEntityState impl bees.add((Bee) bee.getBukkitEntity()); } @@ -20521,20 +19664,20 @@ index 2e51fab98d95c93d2095f7be6dbb5d5474158bfb..32285c8e0f42897793759fba85a1e865 public void addEntity(Bee entity) { Preconditions.checkArgument(entity != null, "Entity must not be null"); -- this.getSnapshot().addOccupant(((CraftBee) entity).getHandle(), false); +- this.getSnapshot().addOccupant(((CraftBee) entity).getHandle()); + int length = this.getSnapshot().getStored().size(); // Purpur -+ getSnapshot().addOccupant(((CraftBee) entity).getHandle(), false); ++ getSnapshot().addOccupant(((CraftBee) entity).getHandle()); + + // Purpur start - check if new bee was added, and if yes, add to stored bees -+ List s = this.getSnapshot().getStored(); -+ if(length < s.size()) { -+ storage.add(new org.purpurmc.purpur.entity.PurpurStoredBee(s.get(s.size() - 1), this)); ++ List storedBeeData = this.getSnapshot().getStored(); ++ if(length < storedBeeData.size()) { ++ storage.add(new org.purpurmc.purpur.entity.PurpurStoredBee(storedBeeData.getLast(), this)); + } + // Purpur end } @Override -@@ -95,6 +141,7 @@ public class CraftBeehive extends CraftBlockEntityState impl +@@ -100,6 +146,7 @@ public class CraftBeehive extends CraftBlockEntityState impl @Override public void clearEntities() { getSnapshot().clearBees(); @@ -20543,15 +19686,15 @@ index 2e51fab98d95c93d2095f7be6dbb5d5474158bfb..32285c8e0f42897793759fba85a1e865 // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java b/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java -index f0b0348e105fb27c829ec29e638433c57bfd5f64..57ce4b7c5fcfe7a88928cd4124f29af39e117ed9 100644 +index c1759aeb3e6ad0e4eb66cba3da1b120dd1dce812..1a91bc2e422db0eba65694ac046f1b362c6b0cd6 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java -@@ -29,7 +29,7 @@ public class CraftConduit extends CraftBlockEntityState impl - @Override +@@ -73,7 +73,7 @@ public class CraftConduit extends CraftBlockEntityState impl public int getRange() { - requirePlaced(); -- return this.getTileEntity().effectBlocks.size() / 7 * 16; -+ return this.getTileEntity().effectBlocks.size() / 7 * this.world.getHandle().purpurConfig.conduitDistance; // Purpur + this.ensureNoWorldGeneration(); + ConduitBlockEntity conduit = (ConduitBlockEntity) this.getTileEntityFromWorld(); +- return (conduit != null) ? ConduitBlockEntity.getRange(conduit.effectBlocks) : 0; ++ return (conduit != null) ? ConduitBlockEntity.getRange(conduit.effectBlocks, this.world.getHandle()) : 0; // Purpur } @Override @@ -20582,19 +19725,6 @@ index 4e56018b64d11f76c8da43fd8f85c6de72204e36..9607675e6c5bff2183c4420d11fc63ee } @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java -index a151b5d7c6e41b08e57c806bc43e067af48263ed..40d385c7865726545bb66f9a1856ed4e73e60202 100644 ---- a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java -+++ b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java -@@ -71,6 +71,8 @@ public class CraftEnchantment extends Enchantment implements Handleable EnchantmentTarget.TRIDENT; - case CROSSBOW -> EnchantmentTarget.CROSSBOW; - case VANISHABLE -> EnchantmentTarget.VANISHABLE; -+ case BOW_AND_CROSSBOW -> EnchantmentTarget.BOW_AND_CROSSBOW; // Purpur -+ case WEAPON_AND_SHEARS -> EnchantmentTarget.WEAPON_AND_SHEARS; // Purpur - }; - } - diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java index d657fd2c507a5b215aeab0a5f3e9c2ee892a27c8..985e9ec21c60a1f47973bd5fc53b96a6f9b7d04a 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java @@ -20615,7 +19745,7 @@ index d657fd2c507a5b215aeab0a5f3e9c2ee892a27c8..985e9ec21c60a1f47973bd5fc53b96a6 // Paper start @Override diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index e8e4489bcd64fde1b3226bdc7a7cc612508bda3f..7121de7f623b4a57937a9c60c8fc0f4307e538dc 100644 +index a2d336ceb52b63db5c03432ee7bc94dc6a742b82..0ed18542fd8e2a992dc56a5f421eaa840e0af193 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -84,6 +84,21 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { @@ -20651,7 +19781,7 @@ index e8e4489bcd64fde1b3226bdc7a7cc612508bda3f..7121de7f623b4a57937a9c60c8fc0f43 return false; } -@@ -1270,4 +1289,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -1280,4 +1299,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { return this.getHandle().getScoreboardName(); } // Paper end - entity scoreboard name @@ -20680,10 +19810,10 @@ index e8e4489bcd64fde1b3226bdc7a7cc612508bda3f..7121de7f623b4a57937a9c60c8fc0f43 + // Purpur end } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 7984365c8290ac9e526a413b56e1c8c0841e330c..a8b30fa294e088c0b604a5d8ac5667e32ed1b287 100644 +index 41f3cdec7deabf34358b8087df77169f85a5b919..90265b6f2acd43713b61e277799dd31311b6b7e2 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -267,6 +267,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { +@@ -265,6 +265,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { @Override public void recalculatePermissions() { this.perm.recalculatePermissions(); @@ -20770,10 +19900,10 @@ index 30d62ee4d5cd2ddacb8783b5bbbf475d592b3e02..5c1cda88080850314dac196dbe71ff12 + // Purpur end } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index c4a166a0c226c6083c25c58145d9631d4296e615..64c73cc7370c23c9ce68b68476fd0ddb3ca6beca 100644 +index aa351df679f300018367244c7ccb3e5a59e9276f..b452ebbe11145987fb5e66b39993898457322080 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -506,7 +506,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { +@@ -505,7 +505,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { net.minecraft.server.level.ServerPlayer entityPlayer = killer == null ? null : ((CraftPlayer) killer).getHandle(); getHandle().lastHurtByPlayer = entityPlayer; getHandle().lastHurtByMob = entityPlayer; @@ -20782,32 +19912,13 @@ index c4a166a0c226c6083c25c58145d9631d4296e615..64c73cc7370c23c9ce68b68476fd0ddb } // Paper end -@@ -969,7 +969,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - return EntityCategory.WATER; - } - -- throw new UnsupportedOperationException("Unsupported monster type: " + type + ". This is a bug, report this to Spigot."); -+ throw new UnsupportedOperationException("Unsupported monster type: " + type + ". This is a bug, report this to Purpur."); // Purpur - } - - @Override -@@ -1210,4 +1210,32 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { +@@ -1173,4 +1173,22 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { this.getHandle().setYBodyRot(bodyYaw); } // Paper end - body yaw API + + // Purpur start + @Override -+ public float getSafeFallDistance() { -+ return getHandle().safeFallDistance; -+ } -+ -+ @Override -+ public void setSafeFallDistance(float safeFallDistance) { -+ getHandle().safeFallDistance = safeFallDistance; -+ } -+ -+ @Override + public void broadcastItemBreak(org.bukkit.inventory.EquipmentSlot slot) { + if (slot == null) return; + getHandle().broadcastBreakEvent(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot)); @@ -20846,10 +19957,10 @@ index 0ad16ee7b33582d214dab41eeee378d52c8e38ed..16bd1294c219f15ada653ef810bc2d74 + // Purpur end } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 44f4665db613c558078df5bb49106e4ca5679dfe..fb2d05e43df3bfb72b1f6e325736dd3cbc6c3096 100644 +index eddbbd0e9be3cb81d1030c0c9da829b9193ebc16..90338017ebcb2a690dff7dad57aa6fbb95e0ff93 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -489,10 +489,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -565,10 +565,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void setPlayerListName(String name) { @@ -20866,7 +19977,7 @@ index 44f4665db613c558078df5bb49106e4ca5679dfe..fb2d05e43df3bfb72b1f6e325736dd3c if (this.getHandle().connection == null) return; // Paper - Updates are possible before the player has fully joined for (ServerPlayer player : (List) this.server.getHandle().players) { if (player.getBukkitEntity().canSee(this)) { -@@ -1353,6 +1358,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1429,6 +1434,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API @@ -20877,7 +19988,7 @@ index 44f4665db613c558078df5bb49106e4ca5679dfe..fb2d05e43df3bfb72b1f6e325736dd3c return false; } -@@ -2661,6 +2670,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2727,6 +2736,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return this.getHandle().getAbilities().walkingSpeed * 2f; } @@ -20906,7 +20017,7 @@ index 44f4665db613c558078df5bb49106e4ca5679dfe..fb2d05e43df3bfb72b1f6e325736dd3c private void validateSpeed(float value) { Preconditions.checkArgument(value <= 1f && value >= -1f, "Speed value (%s) need to be between -1f and 1f", value); } -@@ -3456,4 +3487,70 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -3513,4 +3544,70 @@ public class CraftPlayer extends CraftHumanEntity implements Player { public void setSendViewDistance(final int viewDistance) { this.getHandle().setSendViewDistance(viewDistance); } @@ -21038,12 +20149,12 @@ index 7a8ce6956db56061af93ba9761f5d1057a90bc49..6d286b23806666f7b00ac88c59221446 + // Purpur end } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java -index 38b6d2c377800134de592a780b737b45c8096a11..449acd9dc983be1cd51208bc8f8d843d2ddaa923 100644 +index 86574da257731de7646a712ed73384955fe35aa3..e223234dd64b0e41441c3b9f649f0b64dc6d98c4 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java -@@ -57,4 +57,16 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf { - public void setInterested(boolean flag) { - this.getHandle().setIsInterested(flag); +@@ -146,4 +146,16 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf { + return this.getKey().hashCode(); + } } + + // Purpur start @@ -21059,10 +20170,10 @@ index 38b6d2c377800134de592a780b737b45c8096a11..449acd9dc983be1cd51208bc8f8d843d + // Purpur end } diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index c0823c612de9dc2a64cc797f061eef25c5f31359..b82a6143526bd1d4ecd4591c1253cdb0b913fe09 100644 +index 547ab158cd0cbf51da06ea97740cfce34bca651b..6fed586c9a778f7a57e1b4ca2e6f2dbc15c8769d 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -593,6 +593,15 @@ public class CraftEventFactory { +@@ -592,6 +592,15 @@ public class CraftEventFactory { // Paper end craftServer.getPluginManager().callEvent(event); @@ -21078,7 +20189,7 @@ index c0823c612de9dc2a64cc797f061eef25c5f31359..b82a6143526bd1d4ecd4591c1253cdb0 return event; } -@@ -1124,7 +1133,7 @@ public class CraftEventFactory { +@@ -1121,7 +1130,7 @@ public class CraftEventFactory { return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), entity, DamageCause.LAVA, bukkitDamageSource, modifiers, modifierFunctions, cancelled); } else if (source.getDirectBlock() != null) { DamageCause cause; @@ -21087,7 +20198,7 @@ index c0823c612de9dc2a64cc797f061eef25c5f31359..b82a6143526bd1d4ecd4591c1253cdb0 cause = DamageCause.CONTACT; } else if (source.is(DamageTypes.HOT_FLOOR)) { cause = DamageCause.HOT_FLOOR; -@@ -1182,6 +1191,7 @@ public class CraftEventFactory { +@@ -1179,6 +1188,7 @@ public class CraftEventFactory { EntityDamageEvent event; if (damager != null) { event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions, critical); @@ -21173,76 +20284,6 @@ index 9ee14589d63bbfc0880f2eee5e924fe946ee0035..0a5841fa26698e60bdeadbb58b9343fe + } + // Purpur end } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -index 71aac5d4cf29cea9daa378fc8ac584750de4d1ca..0496871db7437322d3932ca3d3504d84af832d90 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -@@ -596,4 +596,17 @@ public final class CraftItemFactory implements ItemFactory { - return CraftItemStack.asCraftMirror(enchanted); - } - // Paper end - enchantWithLevels API -+ -+ // Purpur start -+ @Override -+ public @org.jetbrains.annotations.NotNull java.util.List getHoverLines(@org.jetbrains.annotations.NotNull ItemStack itemStack, boolean advanced) { -+ return io.papermc.paper.adventure.PaperAdventure.asAdventure( -+ CraftItemStack.asNMSCopy(itemStack).getTooltipLines( -+ null, -+ advanced ? net.minecraft.world.item.TooltipFlag.ADVANCED -+ : net.minecraft.world.item.TooltipFlag.NORMAL -+ ) -+ ); -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -index bac3a5c378054481e1a5abaec1f83afde5d64ac1..f1050bf2b9efc54a894426b08989d44566acd875 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -@@ -45,6 +45,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - static final ItemMetaKey POTION_COLOR = new ItemMetaKey("CustomPotionColor", "custom-color"); - static final ItemMetaKey ID = new ItemMetaKey("id", "potion-id"); - static final ItemMetaKey DEFAULT_POTION = new ItemMetaKey("Potion", "potion-type"); -+ static final ItemMetaKey KEY = new ItemMetaKey("key", "namespacedkey"); // Purpur - add key - - // Having an initial "state" in ItemMeta seems bit dirty but the UNCRAFTABLE potion type - // is treated as the empty form of the meta because it represents an empty potion with no effect -@@ -97,7 +98,13 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - boolean ambient = effect.getBoolean(CraftMetaPotion.AMBIENT.NBT); - boolean particles = effect.contains(CraftMetaPotion.SHOW_PARTICLES.NBT, CraftMagicNumbers.NBT.TAG_BYTE) ? effect.getBoolean(CraftMetaPotion.SHOW_PARTICLES.NBT) : true; - boolean icon = effect.contains(CraftMetaPotion.SHOW_ICON.NBT, CraftMagicNumbers.NBT.TAG_BYTE) ? effect.getBoolean(CraftMetaPotion.SHOW_ICON.NBT) : particles; -- this.customEffects.add(new PotionEffect(type, duration, amp, ambient, particles, icon)); -+ // Purpur start -+ NamespacedKey key = null; -+ if (tag.contains(CraftMetaPotion.KEY.NBT)) { -+ key = NamespacedKey.fromString(effect.getString(CraftMetaPotion.KEY.NBT)); -+ } -+ this.customEffects.add(new PotionEffect(type, duration, amp, ambient, particles, icon, key)); -+ // Purpur end - } - } - } -@@ -150,6 +157,11 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - effectData.putBoolean(CraftMetaPotion.AMBIENT.NBT, effect.isAmbient()); - effectData.putBoolean(CraftMetaPotion.SHOW_PARTICLES.NBT, effect.hasParticles()); - effectData.putBoolean(CraftMetaPotion.SHOW_ICON.NBT, effect.hasIcon()); -+ // Purpur start -+ if (effect.hasKey()) { -+ effectData.putString(CraftMetaPotion.KEY.NBT, effect.getKey().toString()); -+ } -+ // Purpur end - effectList.add(effectData); - } - } -@@ -225,7 +237,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - if (index != -1) { - if (overwrite) { - PotionEffect old = this.customEffects.get(index); -- if (old.getAmplifier() == effect.getAmplifier() && old.getDuration() == effect.getDuration() && old.isAmbient() == effect.isAmbient()) { -+ if (old.getAmplifier() == effect.getAmplifier() && old.getDuration() == effect.getDuration() && old.isAmbient() == effect.isAmbient() && old.getKey() == effect.getKey()) { // Purpur - add key - return false; - } - this.customEffects.set(index, effect); diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java index 6ba29875d78ede4aa7978ff689e588f7fed11528..4afec4387971612f62b825e9e56c2ead7424a7c2 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java @@ -21256,7 +20297,7 @@ index 6ba29875d78ede4aa7978ff689e588f7fed11528..4afec4387971612f62b825e9e56c2ead throw new IllegalArgumentException("Unknown recipe stack instance " + bukkit); } diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java -index fde9aadd6c688b9797a6755f9d214918047598a0..ffaa80b645da3ddf2da828071090e01aa667504d 100644 +index 71d057dc8c7362f8e7aaca5e31c9f02b2bf3f281..9d9405af0db28c0f3ffff2881b54f1dc84675a9d 100644 --- a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java +++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java @@ -256,6 +256,7 @@ public final class CraftLegacy { @@ -21268,10 +20309,10 @@ index fde9aadd6c688b9797a6755f9d214918047598a0..ffaa80b645da3ddf2da828071090e01a if (MinecraftServer.getServer() != null && MinecraftServer.getServer().isDebugging()) { new Exception().printStackTrace(); diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java -index 15e9dd8844f893de5e8372b847c9e8295d6f69ca..b4b105c0190502328d5aeb680dd8e67c2875618f 100644 +index 0cbbd915631904fe8c6effefb92895422b33eff6..aef19cfbecb4ddfc8dc71c4f3b2a011364c12dc2 100644 --- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java +++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java -@@ -46,4 +46,10 @@ public class CraftMapRenderer extends MapRenderer { +@@ -47,4 +47,10 @@ public class CraftMapRenderer extends MapRenderer { } } @@ -21282,28 +20323,6 @@ index 15e9dd8844f893de5e8372b847c9e8295d6f69ca..b4b105c0190502328d5aeb680dd8e67c + } + // Purpur - end } -diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java -index e938255fcc5db0c289d3e132175a541187e4a748..f7a747ea73a80c97d863e0fd3772a0c333aef3c8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java -+++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java -@@ -74,7 +74,7 @@ public class CraftPotionUtil { - public static MobEffectInstance fromBukkit(PotionEffect effect) { - MobEffect type = CraftPotionEffectType.bukkitToMinecraft(effect.getType()); - // Paper - Note: do not copy over the hidden effect, as this method is only used for applying to entities which we do not want to convert over. -- return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()); // Paper -+ return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon(), effect.getKey()); // Paper // Purpur - add key - } - - public static PotionEffect toBukkit(MobEffectInstance effect) { -@@ -83,7 +83,7 @@ public class CraftPotionUtil { - int duration = effect.getDuration(); - boolean ambient = effect.isAmbient(); - boolean particles = effect.isVisible(); -- return new PotionEffect(type, duration, amp, ambient, particles, effect.showIcon(), effect.hiddenEffect == null ? null : toBukkit(effect.hiddenEffect)); // Paper -+ return new PotionEffect(type, duration, amp, ambient, particles, effect.showIcon(), effect.hiddenEffect == null ? null : toBukkit(effect.hiddenEffect), effect.getKey()); // Paper // Purpur - add key - } - - public static boolean equals(MobEffect mobEffect, PotionEffectType type) { diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java index e85b9bb3f9c225d289a4959921970b9963881199..ca8ae8e1c51b937dac916e0b0dc94b5e2e61efeb 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -21391,33 +20410,33 @@ index b3e1adeb932da9b3bed16acd94e2f16da48a7c72..d3ec817e95628f1fc8be4a29c9a0f13c // Paper end - add timings for scoreboard search } diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 94681c5d807019be5caf0b5d5156c0d670f45f8f..e29dc1101c7aa4b7b2a2d2e732e27a1a14a2a234 100644 +index a1c9989df460d7ae3666fffe7968750832a30b85..ad7f21566271260270db452e2f15c32f8a829d28 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -502,7 +502,7 @@ public final class CraftMagicNumbers implements UnsafeValues { +@@ -507,7 +507,7 @@ public final class CraftMagicNumbers implements UnsafeValues { @Override public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { -- return new gg.pufferfish.pufferfish.PufferfishVersionFetcher(); // Pufferfish -+ return new com.destroystokyo.paper.PaperVersionFetcher(); // Purpur +- return new com.destroystokyo.paper.PaperVersionFetcher(); ++ return new com.destroystokyo.paper.PaperVersionFetcher(); // Purpur - TODO: Pufferfish } @Override diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -index 80553face9c70c2a3d897681e7761df85b22d464..99597258e8e88cd9e2c901c4ac3ff7faeeabee2b 100644 +index 774556a62eb240da42e84db4502e2ed43495be17..99597258e8e88cd9e2c901c4ac3ff7faeeabee2b 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java +++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java @@ -11,7 +11,7 @@ public final class Versioning { public static String getBukkitVersion() { String result = "Unknown-Version"; -- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/gg.pufferfish.pufferfish/pufferfish-api/pom.properties"); // Pufferfish +- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties"); + InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/org.purpurmc.purpur/purpur-api/pom.properties"); // Pufferfish // Purpur Properties properties = new Properties(); if (stream != null) { diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java -index dd95b3bfe59f2bb635afe92317288efcd2986326..11f43f44f359ce57d3a8f3322e58b9f5dfdaf00a 100644 +index 52649f82351ab4f675c3cc3cd6640956b0f76b91..eb51c88c7a0658190d3a8bfd5d18dca79d85fba0 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java +++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java @@ -23,7 +23,15 @@ public final class CommandPermissions { @@ -21439,10 +20458,10 @@ index dd95b3bfe59f2bb635afe92317288efcd2986326..11f43f44f359ce57d3a8f3322e58b9f5 DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "seed", "Allows the user to view the seed of the world", PermissionDefault.OP, commands); diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java new file mode 100644 -index 0000000000000000000000000000000000000000..efe25d3894f3ad000257c72d9a5e06ef22446d41 +index 0000000000000000000000000000000000000000..046304d9149472eaffb3ff5f4fa22a230969de86 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -0,0 +1,665 @@ +@@ -0,0 +1,589 @@ +package org.purpurmc.purpur; + +import com.google.common.base.Throwables; @@ -21860,7 +20879,7 @@ index 0000000000000000000000000000000000000000..efe25d3894f3ad000257c72d9a5e06ef + } + + public static boolean allowInfinityMending = false; -+ public static boolean allowCrossbowInfinity = false; ++ public static boolean allowCrossbowInfinity = true; + public static boolean allowShearsLooting = false; + public static boolean allowUnsafeEnchants = false; + public static boolean allowInapplicableEnchants = true; @@ -21946,82 +20965,6 @@ index 0000000000000000000000000000000000000000..efe25d3894f3ad000257c72d9a5e06ef + usernameValidCharactersPattern = java.util.regex.Pattern.compile(setPattern == null || setPattern.isBlank() ? defaultPattern : setPattern); + } + -+ private static void foodSettings() { -+ ConfigurationSection properties = config.getConfigurationSection("settings.food-properties"); -+ if (properties == null) { -+ config.addDefault("settings.food-properties", new HashMap<>()); -+ return; -+ } -+ -+ Map> effectDefaults = new HashMap<>(); -+ Map EFFECT_DEFAULT = Map.of( -+ "chance", 0.0F, -+ "duration", 0, -+ "amplifier", 0, -+ "ambient", false, -+ "visible", true, -+ "show-icon", true -+ ); -+ -+ properties.getKeys(false).forEach(foodKey -> { -+ FoodProperties food = Foods.ALL_PROPERTIES.get(foodKey); -+ if (food == null) { -+ PurpurConfig.log(Level.SEVERE, "Invalid food property: " + foodKey); -+ return; -+ } -+ FoodProperties foodDefaults = Foods.DEFAULT_PROPERTIES.get(foodKey); -+ food.setNutrition(properties.getInt(foodKey + ".nutrition", foodDefaults.getNutrition())); -+ food.setSaturationModifier((float) properties.getDouble(foodKey + ".saturation-modifier", foodDefaults.getSaturationModifier())); -+ food.setIsMeat(properties.getBoolean(foodKey + ".is-meat", foodDefaults.isMeat())); -+ food.setCanAlwaysEat(properties.getBoolean(foodKey + ".can-always-eat", foodDefaults.canAlwaysEat())); -+ food.setFastFood(properties.getBoolean(foodKey + ".fast-food", foodDefaults.isFastFood())); -+ ConfigurationSection effects = properties.getConfigurationSection(foodKey + ".effects"); -+ if (effects != null) { -+ effectDefaults.clear(); -+ foodDefaults.getEffects().forEach(pair -> { -+ MobEffectInstance effect = pair.getFirst(); -+ effectDefaults.put(effect.getEffect(), Map.of( -+ "chance", pair.getSecond(), -+ "duration", effect.getDuration(), -+ "amplifier", effect.getAmplifier(), -+ "ambient", effect.isAmbient(), -+ "visible", effect.isVisible(), -+ "show-icon", effect.showIcon() -+ )); -+ }); -+ effects.getKeys(false).forEach(effectKey -> { -+ MobEffect effect = BuiltInRegistries.MOB_EFFECT.get(new ResourceLocation(effectKey)); -+ if (effect == null) { -+ PurpurConfig.log(Level.SEVERE, "Invalid food property effect for " + foodKey + ": " + effectKey); -+ return; -+ } -+ -+ Map effectDefault = effectDefaults.get(effect); -+ if (effectDefault == null) { -+ effectDefault = EFFECT_DEFAULT; -+ } -+ -+ food.getEffects().removeIf(pair -> pair.getFirst().getEffect() == effect); -+ float chance = (float) effects.getDouble(effectKey + ".chance", ((Float) effectDefault.get("chance")).doubleValue()); -+ int duration = effects.getInt(effectKey + ".duration", (int) effectDefault.get("duration")); -+ if (chance <= 0.0F || duration < 0) { -+ return; -+ } -+ int amplifier = effects.getInt(effectKey + ".amplifier", (int) effectDefault.get("amplifier")); -+ boolean ambient = effects.getBoolean(effectKey + ".ambient", (boolean) effectDefault.get("ambient")); -+ boolean visible = effects.getBoolean(effectKey + ".visible", (boolean) effectDefault.get("visible")); -+ boolean showIcon = effects.getBoolean(effectKey + ".show-icon", (boolean) effectDefault.get("show-icon")); -+ food.getEffects().add(Pair.of(new MobEffectInstance(effect, duration, amplifier, ambient, visible, showIcon), chance)); -+ }); -+ } -+ }); -+ } -+ -+ public static boolean fixNetworkSerializedItemsInCreative = false; -+ private static void fixNetworkSerializedCreativeItems() { -+ fixNetworkSerializedItemsInCreative = getBoolean("settings.fix-network-serialized-items-in-creative", fixNetworkSerializedItemsInCreative); -+ } -+ + public static boolean fixProjectileLootingTransfer = false; + private static void fixProjectileLootingTransfer() { + fixProjectileLootingTransfer = getBoolean("settings.fix-projectile-looting-transfer", fixProjectileLootingTransfer); @@ -22110,10 +21053,10 @@ index 0000000000000000000000000000000000000000..efe25d3894f3ad000257c72d9a5e06ef +} diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java new file mode 100644 -index 0000000000000000000000000000000000000000..7dc82ffccc157a17335f1bc56ab81be3813294f6 +index 0000000000000000000000000000000000000000..8704cc621937beda692bf484cf5ef11b2d7d7e4c --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -0,0 +1,3298 @@ +@@ -0,0 +1,3289 @@ +package org.purpurmc.purpur; + +import net.minecraft.core.registries.BuiltInRegistries; @@ -22248,7 +21191,6 @@ index 0000000000000000000000000000000000000000..7dc82ffccc157a17335f1bc56ab81be3 + public boolean milkClearsBeneficialEffects = true; + public boolean noteBlockIgnoreAbove = false; + public boolean persistentDroppableEntityDisplayNames = true; -+ public boolean persistentTileEntityDisplayNames = false; + public boolean projectilesBypassMobGriefing = false; + public boolean tickFluids = true; + public double mobsBlindnessMultiplier = 1; @@ -22276,7 +21218,6 @@ index 0000000000000000000000000000000000000000..7dc82ffccc157a17335f1bc56ab81be3 + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); + milkClearsBeneficialEffects = getBoolean("gameplay-mechanics.milk-clears-beneficial-effects", milkClearsBeneficialEffects); + noteBlockIgnoreAbove = getBoolean("gameplay-mechanics.note-block-ignore-above", noteBlockIgnoreAbove); -+ persistentTileEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityDisplayNames); + persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); + projectilesBypassMobGriefing = getBoolean("gameplay-mechanics.projectiles-bypass-mob-griefing", projectilesBypassMobGriefing); + tickFluids = getBoolean("gameplay-mechanics.tick-fluids", tickFluids); @@ -22586,61 +21527,6 @@ index 0000000000000000000000000000000000000000..7dc82ffccc157a17335f1bc56ab81be3 + playerVoidTrading = getBoolean("gameplay-mechanics.player.allow-void-trading", playerVoidTrading); + } + -+ private static boolean projectileDespawnRateSettingsMigrated = false; -+ private void projectileDespawnRateSettings() { -+ if (PurpurConfig.version < 28 && !projectileDespawnRateSettingsMigrated) { -+ migrateProjectileDespawnRateSettings(EntityType.DRAGON_FIREBALL); -+ migrateProjectileDespawnRateSettings(EntityType.EGG); -+ migrateProjectileDespawnRateSettings(EntityType.ENDER_PEARL); -+ migrateProjectileDespawnRateSettings(EntityType.EXPERIENCE_BOTTLE); -+ migrateProjectileDespawnRateSettings(EntityType.FIREWORK_ROCKET); -+ migrateProjectileDespawnRateSettings(EntityType.FISHING_BOBBER); -+ migrateProjectileDespawnRateSettings(EntityType.FIREBALL); -+ migrateProjectileDespawnRateSettings(EntityType.LLAMA_SPIT); -+ migrateProjectileDespawnRateSettings(EntityType.POTION); -+ migrateProjectileDespawnRateSettings(EntityType.SHULKER_BULLET); -+ migrateProjectileDespawnRateSettings(EntityType.SMALL_FIREBALL); -+ migrateProjectileDespawnRateSettings(EntityType.SNOWBALL); -+ migrateProjectileDespawnRateSettings(EntityType.WITHER_SKULL); -+ //PufferfishConfig.save(); -+ set("gameplay-mechanics.projectile-despawn-rates", null); -+ // pufferfish's entity_timeout is a global config -+ // we only want to migrate values from the -+ // default world (first world loaded) -+ projectileDespawnRateSettingsMigrated = true; -+ } -+ } -+ private void migrateProjectileDespawnRateSettings(EntityType type) { -+ //String pufferName = "entity_timeouts." + type.id.toUpperCase(Locale.ROOT); -+ //int value = getInt("gameplay-mechanics.projectile-despawn-rates." + type.id, -1); -+ //if (value != -1 && PufferfishConfig.getRawInt(pufferName, -1) == -1) { -+ // PufferfishConfig.setInt(pufferName, value); -+ // type.ttl = value; -+ //} -+ } -+ -+ public double bowProjectileOffset = 1.0D; -+ public double crossbowProjectileOffset = 1.0D; -+ public double eggProjectileOffset = 1.0D; -+ public double enderPearlProjectileOffset = 1.0D; -+ public double throwablePotionProjectileOffset = 1.0D; -+ public double tridentProjectileOffset = 1.0D; -+ public double snowballProjectileOffset = 1.0D; -+ private void projectileOffsetSettings() { -+ bowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.bow", bowProjectileOffset); -+ crossbowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.crossbow", crossbowProjectileOffset); -+ eggProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.egg", eggProjectileOffset); -+ enderPearlProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.ender-pearl", enderPearlProjectileOffset); -+ throwablePotionProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.throwable-potion", throwablePotionProjectileOffset); -+ tridentProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.trident", tridentProjectileOffset); -+ snowballProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.snowball", snowballProjectileOffset); -+ } -+ -+ public int snowballDamage = -1; -+ private void snowballSettings() { -+ snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage); -+ } -+ + public boolean silkTouchEnabled = false; + public String silkTouchSpawnerName = "Monster Spawner"; + public List silkTouchSpawnerLore = new ArrayList<>(); @@ -22673,6 +21559,62 @@ index 0000000000000000000000000000000000000000..7dc82ffccc157a17335f1bc56ab81be3 + }); + } + ++ private static boolean projectileDespawnRateSettingsMigrated = false; ++ private void projectileDespawnRateSettings() { ++ if (PurpurConfig.version < 28 && !projectileDespawnRateSettingsMigrated) { ++ migrateProjectileDespawnRateSettings(EntityType.DRAGON_FIREBALL); ++ migrateProjectileDespawnRateSettings(EntityType.EGG); ++ migrateProjectileDespawnRateSettings(EntityType.ENDER_PEARL); ++ migrateProjectileDespawnRateSettings(EntityType.EXPERIENCE_BOTTLE); ++ migrateProjectileDespawnRateSettings(EntityType.FIREWORK_ROCKET); ++ migrateProjectileDespawnRateSettings(EntityType.FISHING_BOBBER); ++ migrateProjectileDespawnRateSettings(EntityType.FIREBALL); ++ migrateProjectileDespawnRateSettings(EntityType.LLAMA_SPIT); ++ migrateProjectileDespawnRateSettings(EntityType.POTION); ++ migrateProjectileDespawnRateSettings(EntityType.SHULKER_BULLET); ++ migrateProjectileDespawnRateSettings(EntityType.SMALL_FIREBALL); ++ migrateProjectileDespawnRateSettings(EntityType.SNOWBALL); ++ migrateProjectileDespawnRateSettings(EntityType.WITHER_SKULL); ++ //PufferfishConfig.save(); // TODO: Pufferfish ++ set("gameplay-mechanics.projectile-despawn-rates", null); ++ // pufferfish's entity_timeout is a global config ++ // we only want to migrate values from the ++ // default world (first world loaded) ++ projectileDespawnRateSettingsMigrated = true; ++ } ++ } ++ private void migrateProjectileDespawnRateSettings(EntityType type) { ++ // TODO: Pufferfish ++ //String pufferName = "entity_timeouts." + type.id.toUpperCase(Locale.ROOT); ++ //int value = getInt("gameplay-mechanics.projectile-despawn-rates." + type.id, -1); ++ //if (value != -1 && PufferfishConfig.getRawInt(pufferName, -1) == -1) { ++ // PufferfishConfig.setInt(pufferName, value); ++ // type.ttl = value; ++ //} ++ } ++ ++ public double bowProjectileOffset = 1.0D; ++ public double crossbowProjectileOffset = 1.0D; ++ public double eggProjectileOffset = 1.0D; ++ public double enderPearlProjectileOffset = 1.0D; ++ public double throwablePotionProjectileOffset = 1.0D; ++ public double tridentProjectileOffset = 1.0D; ++ public double snowballProjectileOffset = 1.0D; ++ private void projectileOffsetSettings() { ++ bowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.bow", bowProjectileOffset); ++ crossbowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.crossbow", crossbowProjectileOffset); ++ eggProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.egg", eggProjectileOffset); ++ enderPearlProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.ender-pearl", enderPearlProjectileOffset); ++ throwablePotionProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.throwable-potion", throwablePotionProjectileOffset); ++ tridentProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.trident", tridentProjectileOffset); ++ snowballProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.snowball", snowballProjectileOffset); ++ } ++ ++ public int snowballDamage = -1; ++ private void snowballSettings() { ++ snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage); ++ } ++ + public Map axeStrippables = new HashMap<>(); + public Map axeWaxables = new HashMap<>(); + public Map axeWeatherables = new HashMap<>(); @@ -23218,11 +22160,6 @@ index 0000000000000000000000000000000000000000..7dc82ffccc157a17335f1bc56ab81be3 + sculkShriekerCanSummonDefault = getBoolean("blocks.sculk_shrieker.can-summon-default", sculkShriekerCanSummonDefault); + } + -+ public boolean signAllowColors = false; -+ private void signSettings() { -+ signAllowColors = getBoolean("blocks.sign.allow-colors", signAllowColors); -+ } -+ + public boolean slabHalfBreak = false; + private void slabSettings() { + slabHalfBreak = getBoolean("blocks.slab.break-individual-slabs-when-sneaking", slabHalfBreak); @@ -23285,13 +22222,10 @@ index 0000000000000000000000000000000000000000..7dc82ffccc157a17335f1bc56ab81be3 + public boolean allayRidable = false; + public boolean allayRidableInWater = true; + public boolean allayControllable = true; -+ public List allayRespectNBT = new ArrayList<>(); + private void allaySettings() { + allayRidable = getBoolean("mobs.allay.ridable", allayRidable); + allayRidableInWater = getBoolean("mobs.allay.ridable-in-water", allayRidableInWater); + allayControllable = getBoolean("mobs.allay.controllable", allayControllable); -+ allayRespectNBT.clear(); -+ getList("mobs.allay.respect-nbt", new ArrayList<>()).forEach(key -> allayRespectNBT.add(key.toString())); + } + + public boolean axolotlRidable = false; @@ -26216,7 +25150,7 @@ index 0000000000000000000000000000000000000000..ba2a37dad43e238e54632975abea8ee6 +} diff --git a/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java b/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java new file mode 100644 -index 0000000000000000000000000000000000000000..3e846f38902024875d1961b16a60c50201df309d +index 0000000000000000000000000000000000000000..f25abee6dbf99c8d08f8e09db02b41df86115faa --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java @@ -0,0 +1,107 @@ @@ -26271,7 +25205,7 @@ index 0000000000000000000000000000000000000000..3e846f38902024875d1961b16a60c502 + Vec3 mot = this.getDeltaMovement(); + HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); + -+ this.preOnHit(hitResult); ++ this.preHitTargetOrDeflectSelf(hitResult); + + double x = this.getX() + mot.x; + double y = this.getY() + mot.y; @@ -26329,7 +25263,7 @@ index 0000000000000000000000000000000000000000..3e846f38902024875d1961b16a60c502 +} diff --git a/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java b/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java new file mode 100644 -index 0000000000000000000000000000000000000000..11825590af9346c61d5d15e5ef446b3c77b81b54 +index 0000000000000000000000000000000000000000..75e31aee6e706f042398444f272888f9ad0fa3f4 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java @@ -0,0 +1,121 @@ @@ -26386,7 +25320,7 @@ index 0000000000000000000000000000000000000000..11825590af9346c61d5d15e5ef446b3c + Vec3 mot = this.getDeltaMovement(); + HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); + -+ this.preOnHit(hitResult); ++ this.preHitTargetOrDeflectSelf(hitResult); + + double x = this.getX() + mot.x; + double y = this.getY() + mot.y; @@ -26436,7 +25370,7 @@ index 0000000000000000000000000000000000000000..11825590af9346c61d5d15e5ef446b3c + if (canGrief || (target instanceof LivingEntity && !(target instanceof ArmorStand))) { + boolean hurt = target.hurt(target.damageSources().mobProjectile(this, (LivingEntity) shooter), level().purpurConfig.phantomFlameDamage); + if (hurt && level().purpurConfig.phantomFlameFireTime > 0) { -+ target.setSecondsOnFire(level().purpurConfig.phantomFlameFireTime); ++ target.igniteForSeconds(level().purpurConfig.phantomFlameFireTime); + } + } + } @@ -26456,15 +25390,18 @@ index 0000000000000000000000000000000000000000..11825590af9346c61d5d15e5ef446b3c +} diff --git a/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java b/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java new file mode 100644 -index 0000000000000000000000000000000000000000..8efca1d91188ac4db911a8eb0fa9ea2cc3c48e28 +index 0000000000000000000000000000000000000000..7608bf0981fa0d37031e51e57e4086cb5ec4c88b --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java -@@ -0,0 +1,102 @@ +@@ -0,0 +1,106 @@ +package org.purpurmc.purpur.entity; + +import io.papermc.paper.adventure.PaperAdventure; +import net.kyori.adventure.text.Component; ++import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.block.entity.BeehiveBlockEntity; +import org.bukkit.block.EntityBlockStorage; +import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer; @@ -26490,12 +25427,13 @@ index 0000000000000000000000000000000000000000..8efca1d91188ac4db911a8eb0fa9ea2c + this.handle = data; + this.blockStorage = blockStorage; + -+ this.customName = handle.entityData.contains("CustomName", Tag.TAG_STRING) -+ ? PaperAdventure.asAdventure(net.minecraft.network.chat.Component.Serializer.fromJson(handle.entityData.getString("CustomName"))) ++ CompoundTag customData = handle.occupant.entityData().copyTag(); ++ this.customName = customData.contains("CustomName") ++ ? PaperAdventure.asAdventure(net.minecraft.network.chat.Component.Serializer.fromJson(customData.getString("CustomName"), MinecraftServer.getDefaultRegistryAccess())) + : null; + -+ if(handle.entityData.contains("BukkitValues", Tag.TAG_COMPOUND)) { -+ this.persistentDataContainer.putAll(handle.entityData.getCompound("BukkitValues")); ++ if(customData.contains("BukkitValues", Tag.TAG_COMPOUND)) { ++ this.persistentDataContainer.putAll(customData.getCompound("BukkitValues")); + } + } + @@ -26554,11 +25492,11 @@ index 0000000000000000000000000000000000000000..8efca1d91188ac4db911a8eb0fa9ea2c + + @Override + public void update() { -+ handle.entityData.put("BukkitValues", this.persistentDataContainer.toTagCompound()); ++ handle.occupant.entityData().copyTag().put("BukkitValues", this.persistentDataContainer.toTagCompound()); + if(customName == null) { -+ handle.entityData.remove("CustomName"); ++ handle.occupant.entityData().copyTag().remove("CustomName"); + } else { -+ handle.entityData.putString("CustomName", net.minecraft.network.chat.Component.Serializer.toJson(PaperAdventure.asVanilla(customName))); ++ handle.occupant.entityData().copyTag().putString("CustomName", net.minecraft.network.chat.Component.Serializer.toJson(PaperAdventure.asVanilla(customName), MinecraftServer.getDefaultRegistryAccess())); + } + } +} @@ -26918,18 +25856,20 @@ index 0000000000000000000000000000000000000000..7f526883495b3222746de3d0442e9e4f +} diff --git a/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java b/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java new file mode 100644 -index 0000000000000000000000000000000000000000..d6cc7e434cb2bacc00e4cad9e1f4be7fcf5d0bee +index 0000000000000000000000000000000000000000..ed50cb2115401c9039df4136caf5a087a5f5991c --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java -@@ -0,0 +1,38 @@ +@@ -0,0 +1,40 @@ +package org.purpurmc.purpur.item; + +import net.minecraft.core.BlockPos; ++import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; @@ -26946,37 +25886,95 @@ index 0000000000000000000000000000000000000000..d6cc7e434cb2bacc00e4cad9e1f4be7f + protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, Player player, ItemStack stack, BlockState state) { + boolean handled = super.updateCustomBlockEntityTag(pos, level, player, stack, state); + if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.place.spawners")) { -+ BlockEntity spawner = level.getBlockEntity(pos); -+ if (spawner instanceof SpawnerBlockEntity && stack.hasTag()) { -+ CompoundTag tag = stack.getTag(); -+ if (tag.contains("Purpur.mob_type")) { -+ EntityType.byString(tag.getString("Purpur.mob_type")).ifPresent(type -> -+ ((SpawnerBlockEntity) spawner).getSpawner().setEntityId(type, level, level.random, pos)); -+ } else if (tag.contains("BlockEntityTag")) { -+ spawner.load(tag.getCompound("BlockEntityTag")); ++ BlockEntity blockEntity = level.getBlockEntity(pos); ++ if (blockEntity instanceof SpawnerBlockEntity spawner) { ++ CompoundTag customData = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); ++ if (customData.contains("Purpur.mob_type")) { ++ EntityType.byString(customData.getString("Purpur.mob_type")).ifPresent(type -> spawner.getSpawner().setEntityId(type, level, level.random, pos)); ++ } else if (customData.contains("Purpur.SpawnData")) { ++ net.minecraft.world.level.SpawnData.CODEC.parse(net.minecraft.nbt.NbtOps.INSTANCE, customData.getCompound("Purpur.SpawnData")).result() ++ .ifPresent(spawnData -> spawner.getSpawner().nextSpawnData = spawnData); + } + } + } + return handled; + } +} -diff --git a/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java +diff --git a/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java b/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java new file mode 100644 -index 0000000000000000000000000000000000000000..15e760d5c0465b24969df3e25bf8409faab8b62e +index 0000000000000000000000000000000000000000..57e195fd2d457295cda6c366684be5577aeef071 --- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java -@@ -0,0 +1,96 @@ -+package org.purpurmc.purpur.task; ++++ b/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java +@@ -0,0 +1,27 @@ ++package org.purpurmc.purpur.network; + -+import com.google.common.io.ByteArrayDataInput; -+import com.google.common.io.ByteArrayDataOutput; -+import com.google.common.io.ByteStreams; -+import io.netty.buffer.Unpooled; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; ++import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; ++import org.jetbrains.annotations.NotNull; ++ ++public record ClientboundBeehivePayload(BlockPos pos, int numOfBees) implements CustomPacketPayload { ++ public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec(ClientboundBeehivePayload::write, ClientboundBeehivePayload::new); ++ public static final Type TYPE = new Type<>(new ResourceLocation("purpur", "beehive_s2c")); ++ ++ public ClientboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) { ++ this(friendlyByteBuf.readBlockPos(), friendlyByteBuf.readInt()); ++ } ++ ++ private void write(FriendlyByteBuf friendlyByteBuf) { ++ friendlyByteBuf.writeBlockPos(this.pos); ++ friendlyByteBuf.writeInt(this.numOfBees); ++ } ++ ++ @Override ++ public @NotNull Type type() { ++ return TYPE; ++ } ++} +diff --git a/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java b/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java +new file mode 100644 +index 0000000000000000000000000000000000000000..27689754565bf048d1206d540913495d7194a54d +--- /dev/null ++++ b/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java +@@ -0,0 +1,26 @@ ++package org.purpurmc.purpur.network; ++ ++import net.minecraft.core.BlockPos; ++import net.minecraft.network.FriendlyByteBuf; ++import net.minecraft.network.codec.StreamCodec; ++import net.minecraft.network.protocol.common.custom.CustomPacketPayload; ++import net.minecraft.resources.ResourceLocation; ++import org.jetbrains.annotations.NotNull; ++ ++public record ServerboundBeehivePayload(BlockPos pos) implements CustomPacketPayload { ++ public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec(ServerboundBeehivePayload::write, ServerboundBeehivePayload::new); ++ public static final Type TYPE = new Type<>(new ResourceLocation("purpur", "beehive_c2s")); ++ ++ public ServerboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) { ++ this(friendlyByteBuf.readBlockPos()); ++ } ++ ++ private void write(FriendlyByteBuf friendlyByteBuf) { ++ friendlyByteBuf.writeBlockPos(this.pos); ++ } ++ ++ @Override ++ public @NotNull Type type() { ++ return TYPE; ++ } ++} +diff --git a/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java +new file mode 100644 +index 0000000000000000000000000000000000000000..56fc359ea32228c2589ac30c9d00a9c4bea30db7 +--- /dev/null ++++ b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java +@@ -0,0 +1,67 @@ ++package org.purpurmc.purpur.task; ++ ++import io.netty.buffer.Unpooled; ++import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.block.entity.BeehiveBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; @@ -26987,10 +25985,10 @@ index 0000000000000000000000000000000000000000..15e760d5c0465b24969df3e25bf8409f +import org.bukkit.plugin.PluginBase; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.jetbrains.annotations.NotNull; ++import org.purpurmc.purpur.network.ClientboundBeehivePayload; ++import org.purpurmc.purpur.network.ServerboundBeehivePayload; + +public class BeehiveTask implements PluginMessageListener { -+ public static final ResourceLocation BEEHIVE_C2S = new ResourceLocation("purpur", "beehive_c2s"); -+ public static final ResourceLocation BEEHIVE_S2C = new ResourceLocation("purpur", "beehive_s2c"); + + private static BeehiveTask instance; + @@ -27007,59 +26005,37 @@ index 0000000000000000000000000000000000000000..15e760d5c0465b24969df3e25bf8409f + } + + public void register() { -+ Bukkit.getMessenger().registerOutgoingPluginChannel(this.plugin, BEEHIVE_S2C.toString()); -+ Bukkit.getMessenger().registerIncomingPluginChannel(this.plugin, BEEHIVE_C2S.toString(), this); ++ Bukkit.getMessenger().registerOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString()); ++ Bukkit.getMessenger().registerIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString(), this); + } + + public void unregister() { -+ Bukkit.getMessenger().unregisterOutgoingPluginChannel(this.plugin, BEEHIVE_S2C.toString()); -+ Bukkit.getMessenger().unregisterIncomingPluginChannel(this.plugin, BEEHIVE_C2S.toString()); ++ Bukkit.getMessenger().unregisterOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString()); ++ Bukkit.getMessenger().unregisterIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString()); + } + + @Override -+ public void onPluginMessageReceived(@NotNull String channel, Player player, byte[] bytes) { -+ ByteArrayDataInput in = in(bytes); -+ long packedPos = in.readLong(); -+ BlockPos pos = BlockPos.of(packedPos); ++ public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] bytes) { ++ FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.copiedBuffer(bytes)); ++ ServerboundBeehivePayload payload = ServerboundBeehivePayload.STREAM_CODEC.decode(byteBuf); + + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + + // targeted block info max range specified in client at net.minecraft.client.gui.hud.DebugHud#render -+ if (!pos.getCenter().closerThan(serverPlayer.position(), 20)) return; // Targeted Block info max range is 20 -+ if (serverPlayer.level().getChunkIfLoaded(pos) == null) return; ++ if (!payload.pos().getCenter().closerThan(serverPlayer.position(), 20)) return; // Targeted Block info max range is 20 ++ if (serverPlayer.level().getChunkIfLoaded(payload.pos()) == null) return; + -+ BlockEntity blockEntity = serverPlayer.level().getBlockEntity(pos); ++ BlockEntity blockEntity = serverPlayer.level().getBlockEntity(payload.pos()); + if (!(blockEntity instanceof BeehiveBlockEntity beehive)) { + return; + } + -+ ByteArrayDataOutput out = out(); -+ -+ out.writeInt(beehive.getOccupantCount()); -+ out.writeLong(packedPos); -+ -+ FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(out.toByteArray())); -+ serverPlayer.connection.send(new ClientboundCustomPayloadPacket(new CustomPacketPayload() { -+ @Override -+ public void write(final FriendlyByteBuf buf) { -+ buf.writeBytes(byteBuf.copy()); -+ } -+ -+ @Override -+ public ResourceLocation id() { -+ return BEEHIVE_S2C; -+ } -+ })); -+ } -+ -+ @SuppressWarnings("UnstableApiUsage") -+ private static ByteArrayDataOutput out() { -+ return ByteStreams.newDataOutput(); -+ } -+ -+ @SuppressWarnings("UnstableApiUsage") -+ private static ByteArrayDataInput in(byte[] bytes) { -+ return ByteStreams.newDataInput(bytes); ++ ClientboundBeehivePayload customPacketPayload = new ClientboundBeehivePayload(payload.pos(), beehive.getOccupantCount()); ++ FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); ++ ClientboundBeehivePayload.STREAM_CODEC.encode(friendlyByteBuf, customPacketPayload); ++ byte[] byteArray = new byte[friendlyByteBuf.readableBytes()]; ++ friendlyByteBuf.readBytes(byteArray); ++ player.sendPluginMessage(this.plugin, customPacketPayload.type().id().toString(), byteArray); + } +} diff --git a/src/main/java/org/purpurmc/purpur/task/BossBarTask.java b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java @@ -27693,7 +26669,7 @@ index 0000000000000000000000000000000000000000..b7586f494528f30eb0da82420d3bcf5b + } +} diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index d7c7e12c0b8f77e59d94de130972f762ed227726..56e52b16b419c882440a15947f037ae1a902bc70 100644 +index 3283ed99c35ffed6805567705e0518d9f84feedc..de2b469f06f6679aed1d20156052bfbef5e7c30b 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java @@ -15,6 +15,7 @@ import net.minecraft.world.entity.ambient.AmbientCreature; @@ -27704,7 +26680,7 @@ index d7c7e12c0b8f77e59d94de130972f762ed227726..56e52b16b419c882440a15947f037ae1 import net.minecraft.world.entity.animal.WaterAnimal; import net.minecraft.world.entity.animal.horse.Llama; import net.minecraft.world.entity.boss.EnderDragonPart; -@@ -171,7 +172,7 @@ public class ActivationRange +@@ -167,7 +168,7 @@ public class ActivationRange */ public static void activateEntities(Level world) { @@ -27713,7 +26689,7 @@ index d7c7e12c0b8f77e59d94de130972f762ed227726..56e52b16b419c882440a15947f037ae1 final int miscActivationRange = world.spigotConfig.miscActivationRange; final int raiderActivationRange = world.spigotConfig.raiderActivationRange; final int animalActivationRange = world.spigotConfig.animalActivationRange; -@@ -205,6 +206,7 @@ public class ActivationRange +@@ -201,6 +202,7 @@ public class ActivationRange continue; } @@ -27721,7 +26697,7 @@ index d7c7e12c0b8f77e59d94de130972f762ed227726..56e52b16b419c882440a15947f037ae1 // Paper start int worldHeight = world.getHeight(); ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, worldHeight, maxRange ); -@@ -249,7 +251,7 @@ public class ActivationRange +@@ -226,7 +228,7 @@ public class ActivationRange } // Paper end } @@ -27730,7 +26706,7 @@ index d7c7e12c0b8f77e59d94de130972f762ed227726..56e52b16b419c882440a15947f037ae1 } /** -@@ -402,6 +404,7 @@ public class ActivationRange +@@ -379,6 +381,7 @@ public class ActivationRange */ public static boolean checkIfActive(Entity entity) { @@ -27752,7 +26728,7 @@ index 9eb2823cc8f83bad2626fc77578b0162d9ed5782..f144a08e88f8268b84eb188a36bf4704 sender.sendMessage(builder.asComponent()); if (args.length > 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) { diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java -index 9e638f72f180ff5ef63ec3dd6cf548c53f7bd4a5..f7296691cb4af7814de1520347b307ff209082e4 100644 +index 6db566e3111ec08a99aa429624979cb83a85e272..a353eb9f45af7b7f9bfd92a4a89403335b841840 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java @@ -96,7 +96,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa @@ -27807,14 +26783,14 @@ index 9e638f72f180ff5ef63ec3dd6cf548c53f7bd4a5..f7296691cb4af7814de1520347b307ff log.log( Level.SEVERE, "------------------------------" ); diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml -index 675cd61221e807aadf28322b46c3daa1370241b5..0769f5c4711a3b7f59489e611ed01ad8367e5db1 100644 +index d2a75850af9c6ad2aca66a5f994f1b587d73eac4..a056aa167887abef9e6d531a9edd2cda433567d2 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -2,7 +2,16 @@ - + -- +- + + + @@ -28337,18 +27313,18 @@ z&|M6FI|A*^d_U+Of-3`+w(c~-YsQby|NH)g|G7xv|Nek^|Jex)g~z+)I0xPC0460S LFIp>X81%mY^Bg|U diff --git a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java -index afeb4271fffb7546209f1e651214065187c88302..81bc3af856b8af019fd13e1da1f7cccd526b7cf0 100644 +index 2f3ff50bf3f70b6b404d02d5ffcc079162a63bc1..4e57fdf21d4b7789cd7c3d3a18ddc6227bc77792 100644 --- a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java +++ b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java -@@ -45,6 +45,7 @@ public class MinecraftCommandPermissionsTest extends AbstractTestingBase { - Set foundPerms = new HashSet<>(); - for (CommandNode child : root.getChildren()) { - final String vanillaPerm = VanillaCommandWrapper.getPermission(child); +@@ -48,6 +48,7 @@ public class MinecraftCommandPermissionsTest extends AbstractTestingBase { + if ("bukkit.command.paper.pgive".equals(vanillaPerm)) { // skip our custom give command + continue; + } + if (TO_SKIP.contains(vanillaPerm)) continue; // Purpur if (!perms.contains(vanillaPerm)) { missing.add("Missing permission for " + child.getName() + " (" + vanillaPerm + ") command"); } else { -@@ -57,6 +58,25 @@ public class MinecraftCommandPermissionsTest extends AbstractTestingBase { +@@ -60,6 +61,25 @@ public class MinecraftCommandPermissionsTest extends AbstractTestingBase { } private static final List TO_SKIP = List.of( @@ -28374,43 +27350,3 @@ index afeb4271fffb7546209f1e651214065187c88302..81bc3af856b8af019fd13e1da1f7cccd "minecraft.command.selector" ); -diff --git a/src/test/java/org/bukkit/potion/PotionTest.java b/src/test/java/org/bukkit/potion/PotionTest.java -index 8963d93e99bdaf719fa160c11dd5af6a1d86f9a4..d852d8b14f5000415cbb4f06601059b3934b7efc 100644 ---- a/src/test/java/org/bukkit/potion/PotionTest.java -+++ b/src/test/java/org/bukkit/potion/PotionTest.java -@@ -9,6 +9,7 @@ import net.minecraft.resources.ResourceLocation; - import net.minecraft.world.effect.MobEffect; - import net.minecraft.world.effect.MobEffectInstance; - import net.minecraft.world.item.alchemy.Potion; -+import org.bukkit.NamespacedKey; - import org.bukkit.craftbukkit.potion.CraftPotionEffectType; - import org.bukkit.support.AbstractTestingBase; - import org.junit.jupiter.api.Test; -@@ -46,4 +47,27 @@ public class PotionTest extends AbstractTestingBase { - assertEquals(bukkit, byName, "Same type not returned by name " + key); - } - } -+ -+ // Purpur start -+ @Test -+ public void testNamespacedKey() { -+ NamespacedKey key = new NamespacedKey("testnamespace", "testkey"); -+ PotionEffect namedSpacedEffect = new PotionEffect(PotionEffectType.DOLPHINS_GRACE, 20, 0, true, true, true, key); -+ assertNotNull(namedSpacedEffect.getKey()); -+ assertTrue(namedSpacedEffect.hasKey()); -+ assertFalse(namedSpacedEffect.withKey(null).hasKey()); -+ -+ PotionEffect effect = new PotionEffect(PotionEffectType.DOLPHINS_GRACE, 20, 0, true, true, true); -+ assertNull(effect.getKey()); -+ assertFalse(effect.hasKey()); -+ assertTrue(namedSpacedEffect.withKey(key).hasKey()); -+ -+ Map s1 = namedSpacedEffect.serialize(); -+ Map s2 = effect.serialize(); -+ assertTrue(s1.containsKey("namespacedKey")); -+ assertFalse(s2.containsKey("namespacedKey")); -+ assertNotNull(new PotionEffect(s1).getKey()); -+ assertNull(new PotionEffect(s2).getKey()); -+ } -+ // Purpur end - }