Patch
This commit is contained in:
parent
26f7b4c72e
commit
89bf08158b
28 changed files with 234 additions and 295 deletions
785
patches/server/0919-Add-Lifecycle-Event-system.patch
Normal file
785
patches/server/0919-Add-Lifecycle-Event-system.patch
Normal file
|
@ -0,0 +1,785 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Tue, 18 Jul 2023 17:49:38 -0700
|
||||
Subject: [PATCH] Add Lifecycle Event system
|
||||
|
||||
This event system is separate from Bukkit's event system and is
|
||||
meant for managing resources across reloads and from points in the
|
||||
PluginBootstrap.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java
|
||||
index 30b50e6294c6eaade5e17cfaf34600d122e6251c..0bb7694188d5fb75bb756ce75d0060ea980027ee 100644
|
||||
--- a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrapContextImpl.java
|
||||
@@ -1,6 +1,8 @@
|
||||
package io.papermc.paper.plugin.bootstrap;
|
||||
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEventManager;
|
||||
import io.papermc.paper.plugin.provider.PluginProvider;
|
||||
import java.nio.file.Path;
|
||||
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||
@@ -12,6 +14,10 @@ public final class PluginBootstrapContextImpl implements BootstrapContext {
|
||||
private final Path dataFolder;
|
||||
private final ComponentLogger logger;
|
||||
private final Path pluginSource;
|
||||
+ // Paper start - lifecycle events
|
||||
+ private boolean allowsLifecycleRegistration = true;
|
||||
+ private final PaperLifecycleEventManager<BootstrapContext> lifecycleEventManager = new PaperLifecycleEventManager<>(this, () -> this.allowsLifecycleRegistration); // Paper - lifecycle events
|
||||
+ // Paper end - lifecycle events
|
||||
|
||||
public PluginBootstrapContextImpl(PluginMeta config, Path dataFolder, ComponentLogger logger, Path pluginSource) {
|
||||
this.config = config;
|
||||
@@ -45,4 +51,20 @@ public final class PluginBootstrapContextImpl implements BootstrapContext {
|
||||
public @NotNull Path getPluginSource() {
|
||||
return this.pluginSource;
|
||||
}
|
||||
+
|
||||
+ // Paper start - lifecycle event system
|
||||
+ @Override
|
||||
+ public @NotNull PluginMeta getPluginMeta() {
|
||||
+ return this.config;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public LifecycleEventManager<BootstrapContext> getLifecycleManager() {
|
||||
+ return this.lifecycleEventManager;
|
||||
+ }
|
||||
+
|
||||
+ public void lockLifecycleEventRegistration() {
|
||||
+ this.allowsLifecycleRegistration = false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ce808520d639581696689a2ab85de00d85aa0ee3
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java
|
||||
@@ -0,0 +1,100 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event;
|
||||
+
|
||||
+import io.papermc.paper.plugin.lifecycle.event.registrar.PaperRegistrar;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.registrar.RegistrarEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.registrar.RegistrarEventImpl;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.types.OwnerAwareLifecycleEvent;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.List;
|
||||
+import java.util.function.Predicate;
|
||||
+import org.bukkit.plugin.Plugin;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class LifecycleEventRunner {
|
||||
+
|
||||
+ public static final LifecycleEventRunner INSTANCE = new LifecycleEventRunner();
|
||||
+
|
||||
+ private final List<LifecycleEventType<?, ?, ?>> lifecycleEventTypes = new ArrayList<>();
|
||||
+ private boolean blockPluginReloading = false;
|
||||
+
|
||||
+ public <O extends LifecycleEventOwner> void checkRegisteredHandler(final O owner, final AbstractLifecycleEventType<O, ?, ?> eventType) {
|
||||
+ /*
|
||||
+ Lifecycle event handlers for reloadable events that are registered from the BootstrapContext prevent
|
||||
+ the server from reloading plugins. This is because reloading plugins requires disabling all the plugins,
|
||||
+ running the reload logic (which would include places where these events should fire) and then re-enabling plugins.
|
||||
+ */
|
||||
+ if (eventType.blocksReloading(owner)) {
|
||||
+ this.blockPluginReloading = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public boolean blocksPluginReloading() {
|
||||
+ return this.blockPluginReloading;
|
||||
+ }
|
||||
+
|
||||
+ public <O extends LifecycleEventOwner, E extends LifecycleEvent, ET extends LifecycleEventType<O, E, ?>> void addEventType(final ET eventType) {
|
||||
+ this.lifecycleEventTypes.add(eventType);
|
||||
+ }
|
||||
+
|
||||
+ public <O extends LifecycleEventOwner, E extends PaperLifecycleEvent> void callEvent(final LifecycleEventType<O, ? super E, ?> eventType, final E event) {
|
||||
+ this.callEvent(eventType, event, $ -> true);
|
||||
+ }
|
||||
+
|
||||
+ public <O extends LifecycleEventOwner, E extends PaperLifecycleEvent> void callEvent(final LifecycleEventType<O, ? super E, ?> eventType, final E event, final Predicate<? super O> ownerPredicate) {
|
||||
+ final AbstractLifecycleEventType<O, ? super E, ?> lifecycleEventType = (AbstractLifecycleEventType<O, ? super E, ?>) eventType;
|
||||
+ lifecycleEventType.forEachHandler(event, registeredHandler -> {
|
||||
+ try {
|
||||
+ if (event instanceof final OwnerAwareLifecycleEvent<?> ownerAwareEvent) {
|
||||
+ ownerAwareGenericHelper(ownerAwareEvent, registeredHandler.owner());
|
||||
+ }
|
||||
+ registeredHandler.lifecycleEventHandler().run(event);
|
||||
+ } catch (final Throwable ex) {
|
||||
+ throw new RuntimeException("Could not run '%s' lifecycle event handler from %s".formatted(lifecycleEventType.name(), registeredHandler.owner().getPluginMeta().getDisplayName()), ex);
|
||||
+ } finally {
|
||||
+ if (event instanceof final OwnerAwareLifecycleEvent<?> ownerAwareEvent) {
|
||||
+ ownerAwareEvent.setOwner(null);
|
||||
+ }
|
||||
+ }
|
||||
+ }, handler -> ownerPredicate.test(handler.owner()));
|
||||
+ event.invalidate();
|
||||
+ }
|
||||
+
|
||||
+ private static <O extends LifecycleEventOwner> void ownerAwareGenericHelper(final OwnerAwareLifecycleEvent<O> event, final LifecycleEventOwner possibleOwner) {
|
||||
+ final @Nullable O owner = event.castOwner(possibleOwner);
|
||||
+ if (owner != null) {
|
||||
+ event.setOwner(owner);
|
||||
+ } else {
|
||||
+ throw new IllegalStateException("Found invalid owner " + possibleOwner + " for event " + event);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void unregisterAllEventHandlersFor(final Plugin plugin) {
|
||||
+ for (final LifecycleEventType<?, ?, ?> lifecycleEventType : this.lifecycleEventTypes) {
|
||||
+ this.removeEventHandlersOwnedBy(lifecycleEventType, plugin);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private <O extends LifecycleEventOwner> void removeEventHandlersOwnedBy(final LifecycleEventType<O, ?, ?> eventType, final Plugin possibleOwner) {
|
||||
+ final AbstractLifecycleEventType<O, ?, ?> lifecycleEventType = (AbstractLifecycleEventType<O, ?, ?>) eventType;
|
||||
+ lifecycleEventType.removeMatching(registeredHandler -> registeredHandler.owner().getPluginMeta().getName().equals(possibleOwner.getPluginMeta().getName()));
|
||||
+ }
|
||||
+
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ public <O extends LifecycleEventOwner, R extends PaperRegistrar<? super O>> void callStaticRegistrarEvent(final LifecycleEventType<O, ? extends RegistrarEvent<? super R>, ?> lifecycleEventType, final R registrar, final Class<? extends O> ownerClass) {
|
||||
+ this.callEvent((LifecycleEventType<O, RegistrarEvent<? super R>, ?>) lifecycleEventType, new RegistrarEventImpl<>(registrar, ownerClass), ownerClass::isInstance);
|
||||
+ }
|
||||
+
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ public <O extends LifecycleEventOwner, R extends PaperRegistrar<? super O>> void callReloadableRegistrarEvent(final LifecycleEventType<O, ? extends ReloadableRegistrarEvent<? super R>, ?> lifecycleEventType, final R registrar, final Class<? extends O> ownerClass, final ReloadableRegistrarEvent.Cause cause) {
|
||||
+ this.callEvent((LifecycleEventType<O, ReloadableRegistrarEvent<? super R>, ?>) lifecycleEventType, new RegistrarEventImpl.ReloadableImpl<>(registrar, ownerClass, cause), ownerClass::isInstance);
|
||||
+ }
|
||||
+
|
||||
+ private LifecycleEventRunner() {
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEvent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e941405269a773e8a77e26ffd1afd84f53fadff5
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEvent.java
|
||||
@@ -0,0 +1,10 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event;
|
||||
+
|
||||
+public interface PaperLifecycleEvent extends LifecycleEvent {
|
||||
+
|
||||
+ // called after all handlers have been run. Can be
|
||||
+ // used to invalid various contexts to plugins can't
|
||||
+ // try to re-use them by storing them from the event
|
||||
+ default void invalidate() {
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEventManager.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEventManager.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d05334016bd01201c755dea04c0cea56b6dfcb50
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/PaperLifecycleEventManager.java
|
||||
@@ -0,0 +1,26 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event;
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration;
|
||||
+import java.util.function.BooleanSupplier;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class PaperLifecycleEventManager<O extends LifecycleEventOwner> implements LifecycleEventManager<O> {
|
||||
+
|
||||
+ private final O owner;
|
||||
+ public final BooleanSupplier registrationCheck;
|
||||
+
|
||||
+ public PaperLifecycleEventManager(final O owner, final BooleanSupplier registrationCheck) {
|
||||
+ this.owner = owner;
|
||||
+ this.registrationCheck = registrationCheck;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void registerEventHandler(final LifecycleEventHandlerConfiguration<? super O> handlerConfiguration) {
|
||||
+ Preconditions.checkState(this.registrationCheck.getAsBoolean(), "Cannot register lifecycle event handlers");
|
||||
+ ((AbstractLifecycleEventHandlerConfiguration<? super O, ?>) handlerConfiguration).registerFrom(this.owner);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/AbstractLifecycleEventHandlerConfiguration.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/AbstractLifecycleEventHandlerConfiguration.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..fa216e6fd804859293385ed43c53dfca057f317f
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/AbstractLifecycleEventHandlerConfiguration.java
|
||||
@@ -0,0 +1,28 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.handler.configuration;
|
||||
+
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public abstract class AbstractLifecycleEventHandlerConfiguration<O extends LifecycleEventOwner, E extends LifecycleEvent> implements LifecycleEventHandlerConfiguration<O> {
|
||||
+
|
||||
+ private final LifecycleEventHandler<? super E> handler;
|
||||
+ private final AbstractLifecycleEventType<O, E, ?> type;
|
||||
+
|
||||
+ protected AbstractLifecycleEventHandlerConfiguration(final LifecycleEventHandler<? super E> handler, final AbstractLifecycleEventType<O, E, ?> type) {
|
||||
+ this.handler = handler;
|
||||
+ this.type = type;
|
||||
+ }
|
||||
+
|
||||
+ public final void registerFrom(final O owner) {
|
||||
+ this.type.tryRegister(owner, this);
|
||||
+ }
|
||||
+
|
||||
+ public LifecycleEventHandler<? super E> handler() {
|
||||
+ return this.handler;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfigurationImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfigurationImpl.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ab444d60d72bd692843052df5d7b24fbb5621cf7
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfigurationImpl.java
|
||||
@@ -0,0 +1,28 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.handler.configuration;
|
||||
+
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class MonitorLifecycleEventHandlerConfigurationImpl<O extends LifecycleEventOwner, E extends LifecycleEvent> extends AbstractLifecycleEventHandlerConfiguration<O, E> implements MonitorLifecycleEventHandlerConfiguration<O> {
|
||||
+
|
||||
+ private boolean monitor = false;
|
||||
+
|
||||
+ public MonitorLifecycleEventHandlerConfigurationImpl(final LifecycleEventHandler<? super E> handler, final AbstractLifecycleEventType<O, E, ?> eventType) {
|
||||
+ super(handler, eventType);
|
||||
+ }
|
||||
+
|
||||
+ public boolean isMonitor() {
|
||||
+ return this.monitor;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public MonitorLifecycleEventHandlerConfiguration<O> monitor() {
|
||||
+ this.monitor = true;
|
||||
+ return this;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfigurationImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfigurationImpl.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ccdad31717bf12b844cbeaf11a49247485ec77f1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfigurationImpl.java
|
||||
@@ -0,0 +1,40 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.handler.configuration;
|
||||
+
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType;
|
||||
+import java.util.OptionalInt;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class PrioritizedLifecycleEventHandlerConfigurationImpl<O extends LifecycleEventOwner, E extends LifecycleEvent>
|
||||
+ extends AbstractLifecycleEventHandlerConfiguration<O, E>
|
||||
+ implements PrioritizedLifecycleEventHandlerConfiguration<O> {
|
||||
+
|
||||
+ private static final OptionalInt DEFAULT_PRIORITY = OptionalInt.of(0);
|
||||
+ private static final OptionalInt MONITOR_PRIORITY = OptionalInt.empty();
|
||||
+
|
||||
+ private OptionalInt priority = DEFAULT_PRIORITY;
|
||||
+
|
||||
+ public PrioritizedLifecycleEventHandlerConfigurationImpl(final LifecycleEventHandler<? super E> handler, final AbstractLifecycleEventType<O, E, ?> eventType) {
|
||||
+ super(handler, eventType);
|
||||
+ }
|
||||
+
|
||||
+ public OptionalInt priority() {
|
||||
+ return this.priority;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public PrioritizedLifecycleEventHandlerConfiguration<O> priority(final int priority) {
|
||||
+ this.priority = OptionalInt.of(priority);
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public PrioritizedLifecycleEventHandlerConfiguration<O> monitor() {
|
||||
+ this.priority = MONITOR_PRIORITY;
|
||||
+ return this;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/PaperRegistrar.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/PaperRegistrar.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b2586c881988fbabe07eef1b43eb1b55f2d3fa52
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/PaperRegistrar.java
|
||||
@@ -0,0 +1,15 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.registrar;
|
||||
+
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public interface PaperRegistrar<O extends LifecycleEventOwner> extends Registrar {
|
||||
+
|
||||
+ void setCurrentContext(@Nullable O owner);
|
||||
+
|
||||
+ default void invalidate() {
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEventImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEventImpl.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6d530c52aaf0dc2cdfe3bd56af557274a7f44256
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEventImpl.java
|
||||
@@ -0,0 +1,70 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.registrar;
|
||||
+
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.types.OwnerAwareLifecycleEvent;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class RegistrarEventImpl<R extends PaperRegistrar<? super O>, O extends LifecycleEventOwner> implements PaperLifecycleEvent, OwnerAwareLifecycleEvent<O>, RegistrarEvent<R> {
|
||||
+
|
||||
+ private final R registrar;
|
||||
+ private final Class<? extends O> ownerClass;
|
||||
+
|
||||
+ public RegistrarEventImpl(final R registrar, final Class<? extends O> ownerClass) {
|
||||
+ this.registrar = registrar;
|
||||
+ this.ownerClass = ownerClass;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public R registrar() {
|
||||
+ return this.registrar;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final void setOwner(final @Nullable O owner) {
|
||||
+ this.registrar.setCurrentContext(owner);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final @Nullable O castOwner(final LifecycleEventOwner owner) {
|
||||
+ return this.ownerClass.isInstance(owner) ? this.ownerClass.cast(owner) : null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void invalidate() {
|
||||
+ this.registrar.invalidate();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String toString() {
|
||||
+ return "RegistrarEventImpl{" +
|
||||
+ "registrar=" + this.registrar +
|
||||
+ ", ownerClass=" + this.ownerClass +
|
||||
+ '}';
|
||||
+ }
|
||||
+
|
||||
+ public static class ReloadableImpl<R extends PaperRegistrar<? super O>, O extends LifecycleEventOwner> extends RegistrarEventImpl<R, O> implements ReloadableRegistrarEvent<R> {
|
||||
+
|
||||
+ private final ReloadableRegistrarEvent.Cause cause;
|
||||
+
|
||||
+ public ReloadableImpl(final R registrar, final Class<? extends O> ownerClass, final Cause cause) {
|
||||
+ super(registrar, ownerClass);
|
||||
+ this.cause = cause;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Cause cause() {
|
||||
+ return this.cause;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String toString() {
|
||||
+ return "ReloadableImpl{" +
|
||||
+ "cause=" + this.cause +
|
||||
+ "} " + super.toString();
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/AbstractLifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/AbstractLifecycleEventType.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..01a4e9a36a9970f30ed9f9236fc5a4a1cf71844e
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/AbstractLifecycleEventType.java
|
||||
@@ -0,0 +1,62 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.types;
|
||||
+
|
||||
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration;
|
||||
+import java.util.function.Consumer;
|
||||
+import java.util.function.Predicate;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public abstract class AbstractLifecycleEventType<O extends LifecycleEventOwner, E extends LifecycleEvent, C extends LifecycleEventHandlerConfiguration<O>> implements LifecycleEventType<O, E, C> {
|
||||
+
|
||||
+ private final String name;
|
||||
+ private final Class<? extends O> ownerType;
|
||||
+
|
||||
+ protected AbstractLifecycleEventType(final String name, final Class<? extends O> ownerType) {
|
||||
+ this.name = name;
|
||||
+ this.ownerType = ownerType;
|
||||
+ LifecycleEventRunner.INSTANCE.addEventType(this);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String name() {
|
||||
+ return this.name;
|
||||
+ }
|
||||
+
|
||||
+ private void verifyOwner(final O owner) {
|
||||
+ if (!this.ownerType.isInstance(owner)) {
|
||||
+ throw new IllegalArgumentException("You cannot register the lifecycle event '" + this.name + "' on " + owner);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public boolean blocksReloading(final O eventOwner) {
|
||||
+ return eventOwner instanceof BootstrapContext;
|
||||
+ }
|
||||
+
|
||||
+ public abstract boolean hasHandlers();
|
||||
+
|
||||
+ public abstract void forEachHandler(E event, Consumer<RegisteredHandler<O, E>> consumer, Predicate<RegisteredHandler<O, E>> predicate);
|
||||
+
|
||||
+ public abstract void removeMatching(Predicate<RegisteredHandler<O, E>> predicate);
|
||||
+
|
||||
+ protected abstract void register(O owner, AbstractLifecycleEventHandlerConfiguration<O, E> config);
|
||||
+
|
||||
+ public final void tryRegister(final O owner, final AbstractLifecycleEventHandlerConfiguration<O, E> config) {
|
||||
+ this.verifyOwner(owner);
|
||||
+ LifecycleEventRunner.INSTANCE.checkRegisteredHandler(owner, this);
|
||||
+ this.register(owner, config);
|
||||
+ }
|
||||
+
|
||||
+ public record RegisteredHandler<O extends LifecycleEventOwner, E extends LifecycleEvent>(O owner, AbstractLifecycleEventHandlerConfiguration<O, E> config) {
|
||||
+
|
||||
+ public LifecycleEventHandler<? super E> lifecycleEventHandler() {
|
||||
+ return this.config().handler();
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b11346e04bb16c3238f32deb87dbd680e261d4d2
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java
|
||||
@@ -0,0 +1,25 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.types;
|
||||
+
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class LifecycleEventTypeProviderImpl implements LifecycleEventTypeProvider {
|
||||
+
|
||||
+ public static LifecycleEventTypeProviderImpl instance() {
|
||||
+ return (LifecycleEventTypeProviderImpl) LifecycleEventTypeProvider.provider();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <O extends LifecycleEventOwner, E extends LifecycleEvent> LifecycleEventType.Monitorable<O, E> monitor(final String name, final Class<? extends O> ownerType) {
|
||||
+ return new MonitorableLifecycleEventType<>(name, ownerType);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <O extends LifecycleEventOwner, E extends LifecycleEvent> LifecycleEventType.Prioritizable<O, E> prioritized(final String name, final Class<? extends O> ownerType) {
|
||||
+ return new PrioritizableLifecycleEventType.Simple<>(name, ownerType);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/MonitorableLifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/MonitorableLifecycleEventType.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..abb969cf6ed967fe7720c56d3b3157bd1b74700d
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/MonitorableLifecycleEventType.java
|
||||
@@ -0,0 +1,63 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.types;
|
||||
+
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.MonitorLifecycleEventHandlerConfiguration;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.MonitorLifecycleEventHandlerConfigurationImpl;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.List;
|
||||
+import java.util.function.Consumer;
|
||||
+import java.util.function.Predicate;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class MonitorableLifecycleEventType<O extends LifecycleEventOwner, E extends LifecycleEvent> extends AbstractLifecycleEventType<O, E, MonitorLifecycleEventHandlerConfiguration<O>> implements LifecycleEventType.Monitorable<O, E> {
|
||||
+
|
||||
+ final List<RegisteredHandler<O, E>> handlers = new ArrayList<>();
|
||||
+ int nonMonitorIdx = 0;
|
||||
+
|
||||
+ public MonitorableLifecycleEventType(final String name, final Class<? extends O> ownerType) {
|
||||
+ super(name, ownerType);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasHandlers() {
|
||||
+ return !this.handlers.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public MonitorLifecycleEventHandlerConfigurationImpl<O, E> newHandler(final LifecycleEventHandler<? super E> handler) {
|
||||
+ return new MonitorLifecycleEventHandlerConfigurationImpl<>(handler, this);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void register(final O owner, final AbstractLifecycleEventHandlerConfiguration<O, E> config) {
|
||||
+ if (!(config instanceof final MonitorLifecycleEventHandlerConfigurationImpl<?,?> monitor)) {
|
||||
+ throw new IllegalArgumentException("Configuration must be a MonitorLifecycleEventHandlerConfiguration");
|
||||
+ }
|
||||
+ final RegisteredHandler<O, E> registeredHandler = new RegisteredHandler<>(owner, config);
|
||||
+ if (!monitor.isMonitor()) {
|
||||
+ this.handlers.add(this.nonMonitorIdx, registeredHandler);
|
||||
+ this.nonMonitorIdx++;
|
||||
+ } else {
|
||||
+ this.handlers.add(registeredHandler);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void forEachHandler(final E event, final Consumer<RegisteredHandler<O, E>> consumer, final Predicate<RegisteredHandler<O, E>> predicate) {
|
||||
+ for (final RegisteredHandler<O, E> handler : this.handlers) {
|
||||
+ if (predicate.test(handler)) {
|
||||
+ consumer.accept(handler);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void removeMatching(final Predicate<RegisteredHandler<O, E>> predicate) {
|
||||
+ this.handlers.removeIf(predicate);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/OwnerAwareLifecycleEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/OwnerAwareLifecycleEvent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3e7e7474f301c0725fa2bcd6e19e476fc35f2d5a
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/OwnerAwareLifecycleEvent.java
|
||||
@@ -0,0 +1,15 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.types;
|
||||
+
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public interface OwnerAwareLifecycleEvent<O extends LifecycleEventOwner> extends LifecycleEvent {
|
||||
+
|
||||
+ void setOwner(@Nullable O owner);
|
||||
+
|
||||
+ @Nullable O castOwner(LifecycleEventOwner owner);
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PrioritizableLifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PrioritizableLifecycleEventType.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..2ed622a61ddc37b11888867770b513909b9a2ecc
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PrioritizableLifecycleEventType.java
|
||||
@@ -0,0 +1,79 @@
|
||||
+package io.papermc.paper.plugin.lifecycle.event.types;
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.AbstractLifecycleEventHandlerConfiguration;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration;
|
||||
+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfigurationImpl;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Comparator;
|
||||
+import java.util.List;
|
||||
+import java.util.function.Consumer;
|
||||
+import java.util.function.Predicate;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public abstract class PrioritizableLifecycleEventType<
|
||||
+ O extends LifecycleEventOwner,
|
||||
+ E extends LifecycleEvent,
|
||||
+ C extends PrioritizedLifecycleEventHandlerConfiguration<O>
|
||||
+> extends AbstractLifecycleEventType<O, E, C> {
|
||||
+
|
||||
+ private static final Comparator<RegisteredHandler<?, ?>> COMPARATOR = Comparator.comparing(handler -> ((PrioritizedLifecycleEventHandlerConfigurationImpl<?, ?>) handler.config()).priority(), (o1, o2) -> {
|
||||
+ if (o1.equals(o2)) {
|
||||
+ return 0;
|
||||
+ } else if (o1.isEmpty()) {
|
||||
+ return 1;
|
||||
+ } else if (o2.isEmpty()) {
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ return Integer.compare(o1.getAsInt(), o2.getAsInt());
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ private final List<RegisteredHandler<O, E>> handlers = new ArrayList<>();
|
||||
+
|
||||
+ public PrioritizableLifecycleEventType(final String name, final Class<? extends O> ownerType) {
|
||||
+ super(name, ownerType);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasHandlers() {
|
||||
+ return !this.handlers.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void register(final O owner, final AbstractLifecycleEventHandlerConfiguration<O, E> config) {
|
||||
+ Preconditions.checkArgument(config instanceof PrioritizedLifecycleEventHandlerConfigurationImpl<?, ?>, "Configuration must be a PrioritizedLifecycleEventHandlerConfiguration");
|
||||
+ this.handlers.add(new RegisteredHandler<>(owner, config));
|
||||
+ this.handlers.sort(COMPARATOR);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void forEachHandler(final E event, final Consumer<RegisteredHandler<O, E>> consumer, final Predicate<RegisteredHandler<O, E>> predicate) {
|
||||
+ for (final RegisteredHandler<O, E> handler : this.handlers) {
|
||||
+ if (predicate.test(handler)) {
|
||||
+ consumer.accept(handler);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void removeMatching(final Predicate<RegisteredHandler<O, E>> predicate) {
|
||||
+ this.handlers.removeIf(predicate);
|
||||
+ }
|
||||
+
|
||||
+ public static class Simple<O extends LifecycleEventOwner, E extends LifecycleEvent> extends PrioritizableLifecycleEventType<O, E, PrioritizedLifecycleEventHandlerConfiguration<O>> implements LifecycleEventType.Prioritizable<O, E> {
|
||||
+ public Simple(final String name, final Class<? extends O> ownerType) {
|
||||
+ super(name, ownerType);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public PrioritizedLifecycleEventHandlerConfiguration<O> newHandler(final LifecycleEventHandler<? super E> handler) {
|
||||
+ return new PrioritizedLifecycleEventHandlerConfigurationImpl<>(handler, this);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java
|
||||
index 834b85f24df023642f8abf7213fe578ac8c17a3e..3e82ea07ca4194844c5528446e2c4a46ff4acee5 100644
|
||||
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java
|
||||
@@ -293,6 +293,15 @@ class PaperPluginInstanceManager {
|
||||
+ pluginName + " (Is it up to date?)", ex, plugin); // Paper
|
||||
}
|
||||
|
||||
+ // Paper start - lifecycle event system
|
||||
+ try {
|
||||
+ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.unregisterAllEventHandlersFor(plugin);
|
||||
+ } catch (Throwable ex) {
|
||||
+ this.handlePluginException("Error occurred (in the plugin loader) while unregistering lifecycle event handlers for "
|
||||
+ + pluginName + " (Is it up to date?)", ex, plugin);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
try {
|
||||
this.server.getMessenger().unregisterIncomingPluginChannel(plugin);
|
||||
this.server.getMessenger().unregisterOutgoingPluginChannel(plugin);
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java b/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java
|
||||
index 2e96308696e131f3f013469a395e5ddda2c5d529..65a66e484c1c39c5f41d97db52f31c67b4479d20 100644
|
||||
--- a/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/storage/BootstrapProviderStorage.java
|
||||
@@ -32,8 +32,9 @@ public class BootstrapProviderStorage extends SimpleProviderStorage<PluginBootst
|
||||
@Override
|
||||
public boolean load(PluginProvider<PluginBootstrap> provider, PluginBootstrap provided) {
|
||||
try {
|
||||
- BootstrapContext context = PluginBootstrapContextImpl.create(provider, PluginInitializerManager.instance().pluginDirectoryPath());
|
||||
+ PluginBootstrapContextImpl context = PluginBootstrapContextImpl.create(provider, PluginInitializerManager.instance().pluginDirectoryPath()); // Paper - lifecycle events
|
||||
provided.bootstrap(context);
|
||||
+ context.lockLifecycleEventRegistration(); // Paper - lifecycle events
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Failed to run bootstrapper for %s. This plugin will not be loaded.".formatted(provider.getSource()), e);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 2934e232c84603224470fdaba0103d42fc06e8b4..4dc64ab006399d62251f4a238d9c2caebd595301 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1051,6 +1051,11 @@ public final class CraftServer implements Server {
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
+ // Paper start - lifecycle events
|
||||
+ if (io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.blocksPluginReloading()) {
|
||||
+ throw new IllegalStateException("A lifecycle event handler has been registered which makes reloading plugins not possible");
|
||||
+ }
|
||||
+ // Paper end - lifecycle events
|
||||
org.spigotmc.WatchdogThread.hasStarted = false; // Paper - Disable watchdog early timeout on reload
|
||||
this.reloadCount++;
|
||||
this.configuration = YamlConfiguration.loadConfiguration(this.getConfigFile());
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index b6591836a8d9301b8cf909223426df0e8e675c1f..6396af834c5ca2328896613c5d97e43624eb305d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -652,6 +652,13 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
}
|
||||
// Paper end - spawn egg color visibility
|
||||
|
||||
+ // Paper start - lifecycle event API
|
||||
+ @Override
|
||||
+ public io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager<org.bukkit.plugin.Plugin> createPluginLifecycleEventManager(final org.bukkit.plugin.java.JavaPlugin plugin, final java.util.function.BooleanSupplier registrationCheck) {
|
||||
+ return new io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEventManager<>(plugin, registrationCheck);
|
||||
+ }
|
||||
+ // Paper end - lifecycle event API
|
||||
+
|
||||
/**
|
||||
* This helper class represents the different NBT Tags.
|
||||
* <p>
|
||||
diff --git a/src/main/resources/META-INF/services/io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProvider b/src/main/resources/META-INF/services/io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProvider
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..808b1192b60348ad05f0bfbdeda6f94df4876743
|
||||
--- /dev/null
|
||||
+++ b/src/main/resources/META-INF/services/io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProvider
|
||||
@@ -0,0 +1 @@
|
||||
+io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventTypeProviderImpl
|
||||
diff --git a/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java b/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java
|
||||
index 1d14f530ef888102e47eeeaf0d1a6076e51871c4..90cf0c702ca2ff9de64d9718ecba5f2d128953a6 100644
|
||||
--- a/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java
|
||||
+++ b/src/test/java/io/papermc/paper/plugin/PaperTestPlugin.java
|
||||
@@ -143,4 +143,11 @@ public class PaperTestPlugin extends PluginBase {
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
throw new UnsupportedOperationException("Not supported.");
|
||||
}
|
||||
+
|
||||
+ // Paper start - lifecycle events
|
||||
+ @Override
|
||||
+ public io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager<org.bukkit.plugin.Plugin> getLifecycleManager() {
|
||||
+ throw new UnsupportedOperationException("Not supported.");
|
||||
+ }
|
||||
+ // Paper end - lifecycle events
|
||||
}
|
32
patches/server/0920-ItemStack-Tooltip-API.patch
Normal file
32
patches/server/0920-ItemStack-Tooltip-API.patch
Normal file
|
@ -0,0 +1,32 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yannick Lamprecht <yannicklamprecht@live.de>
|
||||
Date: Mon, 22 Jan 2024 13:27:30 +0100
|
||||
Subject: [PATCH] ItemStack Tooltip API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index 6396af834c5ca2328896613c5d97e43624eb305d..6e070dada87083656a19b4abf78db63f4b2513e6 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -628,6 +628,21 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
}
|
||||
// Paper end - fix custom stats criteria creation
|
||||
|
||||
+ // Paper start - expose itemstack tooltip lines
|
||||
+ @Override
|
||||
+ public java.util.List<net.kyori.adventure.text.Component> computeTooltipLines(final ItemStack itemStack, final io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, final org.bukkit.entity.Player player) {
|
||||
+ Preconditions.checkArgument(tooltipContext != null, "tooltipContext cannot be null");
|
||||
+ net.minecraft.world.item.TooltipFlag.Default flag = tooltipContext.isAdvanced() ? net.minecraft.world.item.TooltipFlag.ADVANCED : net.minecraft.world.item.TooltipFlag.NORMAL;
|
||||
+ if (tooltipContext.isCreative()) {
|
||||
+ flag = flag.asCreative();
|
||||
+ }
|
||||
+ final java.util.List<net.minecraft.network.chat.Component> lines = CraftItemStack.asNMSCopy(itemStack).getTooltipLines(
|
||||
+ net.minecraft.world.item.Item.TooltipContext.of(player == null ? net.minecraft.server.MinecraftServer.getServer().registryAccess() : ((org.bukkit.craftbukkit.entity.CraftPlayer) player).getHandle().level().registryAccess()),
|
||||
+ player == null ? null : ((org.bukkit.craftbukkit.entity.CraftPlayer) player).getHandle(), flag);
|
||||
+ return lines.stream().map(io.papermc.paper.adventure.PaperAdventure::asAdventure).toList();
|
||||
+ }
|
||||
+ // Paper end - expose itemstack tooltip lines
|
||||
+
|
||||
@Override
|
||||
public String get(Class<?> aClass, String s) {
|
||||
if (aClass == Enchantment.class) {
|
|
@ -0,0 +1,70 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Warrior <50800980+Warriorrrr@users.noreply.github.com>
|
||||
Date: Sat, 10 Feb 2024 10:03:48 +0100
|
||||
Subject: [PATCH] Add getChunkSnapshot includeLightData parameter
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
index 887a17a0833064eb5701222e5fb6f5ccf9511588..5fc9e8e969debb3e15ed474b36a1c48b086d0449 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
@@ -328,12 +328,21 @@ public class CraftChunk implements Chunk {
|
||||
|
||||
@Override
|
||||
public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeBiome, boolean includeBiomeTempRain) {
|
||||
+ // Paper start - Add getChunkSnapshot includeLightData parameter
|
||||
+ return getChunkSnapshot(includeMaxBlockY, includeBiome, includeBiomeTempRain, true);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeBiome, boolean includeBiomeTempRain, boolean includeLightData) {
|
||||
+ // Paper end - Add getChunkSnapshot includeLightData parameter
|
||||
ChunkAccess chunk = this.getHandle(ChunkStatus.FULL);
|
||||
|
||||
LevelChunkSection[] cs = chunk.getSections();
|
||||
PalettedContainer[] sectionBlockIDs = new PalettedContainer[cs.length];
|
||||
- byte[][] sectionSkyLights = new byte[cs.length][];
|
||||
- byte[][] sectionEmitLights = new byte[cs.length][];
|
||||
+ // Paper start - Add getChunkSnapshot includeLightData parameter
|
||||
+ byte[][] sectionSkyLights = includeLightData ? new byte[cs.length][] : null;
|
||||
+ byte[][] sectionEmitLights = includeLightData ? new byte[cs.length][] : null;
|
||||
+ // Paper end - Add getChunkSnapshot includeLightData parameter
|
||||
boolean[] sectionEmpty = new boolean[cs.length];
|
||||
PalettedContainerRO<Holder<net.minecraft.world.level.biome.Biome>>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null;
|
||||
|
||||
@@ -350,6 +359,7 @@ public class CraftChunk implements Chunk {
|
||||
}
|
||||
// Paper end - Fix ChunkSnapshot#isSectionEmpty(int)
|
||||
|
||||
+ if (includeLightData) { // Paper - Add getChunkSnapshot includeLightData parameter
|
||||
LevelLightEngine lightengine = this.worldServer.getLightEngine();
|
||||
DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(this.x, chunk.getSectionYFromSectionIndex(i), this.z)); // SPIGOT-7498: Convert section index
|
||||
if (skyLightArray == null) {
|
||||
@@ -365,6 +375,7 @@ public class CraftChunk implements Chunk {
|
||||
sectionEmitLights[i] = new byte[2048];
|
||||
System.arraycopy(emitLightArray.getData(), 0, sectionEmitLights[i], 0, 2048);
|
||||
}
|
||||
+ } // Paper - Add getChunkSnapshot includeLightData parameter
|
||||
|
||||
if (biome != null) {
|
||||
biome[i] = ((PalettedContainer<Holder<net.minecraft.world.level.biome.Biome>>) cs[i].getBiomes()).copy(); // Paper - Perf: use copy instead of round tripping with codecs
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java
|
||||
index c88e4ba701b2a2325b76478b7f47278157afd2ef..ddcbdbcbfeb6efe0a587b1181505423cc9d2c951 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java
|
||||
@@ -119,6 +119,7 @@ public class CraftChunkSnapshot implements ChunkSnapshot {
|
||||
|
||||
@Override
|
||||
public final int getBlockSkyLight(int x, int y, int z) {
|
||||
+ Preconditions.checkState(this.skylight != null, "ChunkSnapshot created without light data. Please call getSnapshot with includeLightData=true"); // Paper - Add getChunkSnapshot includeLightData parameter
|
||||
this.validateChunkCoordinates(x, y, z);
|
||||
|
||||
int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1);
|
||||
@@ -127,6 +128,7 @@ public class CraftChunkSnapshot implements ChunkSnapshot {
|
||||
|
||||
@Override
|
||||
public final int getBlockEmittedLight(int x, int y, int z) {
|
||||
+ Preconditions.checkState(this.emitlight != null, "ChunkSnapshot created without light data. Please call getSnapshot with includeLightData=true"); // Paper - Add getChunkSnapshot includeLightData parameter
|
||||
this.validateChunkCoordinates(x, y, z);
|
||||
|
||||
int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1);
|
208
patches/server/0922-Add-FluidState-API.patch
Normal file
208
patches/server/0922-Add-FluidState-API.patch
Normal file
|
@ -0,0 +1,208 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: vicisacat <victor.branchu@gmail.com>
|
||||
Date: Fri, 17 Nov 2023 20:22:43 +0100
|
||||
Subject: [PATCH] Add FluidState API
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java b/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..479bc32241ebadf8bbc1080b601f61391ad37fa4
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java
|
||||
@@ -0,0 +1,110 @@
|
||||
+package io.papermc.paper.block.fluid;
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import io.papermc.paper.block.fluid.type.PaperFallingFluidData;
|
||||
+import io.papermc.paper.block.fluid.type.PaperFlowingFluidData;
|
||||
+import io.papermc.paper.util.MCUtil;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.Map;
|
||||
+import java.util.function.Function;
|
||||
+import net.minecraft.world.level.material.FluidState;
|
||||
+import net.minecraft.world.level.material.LavaFluid;
|
||||
+import net.minecraft.world.level.material.WaterFluid;
|
||||
+import org.bukkit.Fluid;
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.craftbukkit.CraftFluid;
|
||||
+import org.bukkit.craftbukkit.CraftWorld;
|
||||
+import org.bukkit.craftbukkit.util.CraftVector;
|
||||
+import org.bukkit.util.Vector;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+public class PaperFluidData implements FluidData {
|
||||
+
|
||||
+ private final FluidState state;
|
||||
+
|
||||
+ protected PaperFluidData(final FluidState state) {
|
||||
+ this.state = state;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Provides the internal server representation of this fluid data.
|
||||
+ * @return the fluid state.
|
||||
+ */
|
||||
+ public FluidState getState() {
|
||||
+ return this.state;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final @NotNull Fluid getFluidType() {
|
||||
+ return CraftFluid.minecraftToBukkit(this.state.getType());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull PaperFluidData clone() {
|
||||
+ try {
|
||||
+ return (PaperFluidData) super.clone();
|
||||
+ } catch (final CloneNotSupportedException ex) {
|
||||
+ throw new AssertionError("Clone not supported", ex);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull Vector computeFlowDirection(final Location location) {
|
||||
+ Preconditions.checkArgument(location.getWorld() != null, "Cannot compute flow direction on world-less location");
|
||||
+ return CraftVector.toBukkit(this.state.getFlow(
|
||||
+ ((CraftWorld) location.getWorld()).getHandle(),
|
||||
+ MCUtil.toBlockPosition(location)
|
||||
+ ));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getLevel() {
|
||||
+ return this.state.getAmount();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public float computeHeight(@NotNull final Location location) {
|
||||
+ Preconditions.checkArgument(location.getWorld() != null, "Cannot compute height on world-less location");
|
||||
+ return this.state.getHeight(((CraftWorld) location.getWorld()).getHandle(), MCUtil.toBlockPos(location));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isSource() {
|
||||
+ return this.state.isSource();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ return this.state.hashCode();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(final Object obj) {
|
||||
+ return obj instanceof final PaperFluidData paperFluidData && this.state.equals(paperFluidData.state);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String toString() {
|
||||
+ return "PaperFluidData{" + this.state + "}";
|
||||
+ }
|
||||
+
|
||||
+ /* Registry */
|
||||
+ private static final Map<Class<? extends net.minecraft.world.level.material.Fluid>, Function<FluidState, PaperFluidData>> MAP = new HashMap<>();
|
||||
+ static {
|
||||
+ //<editor-fold desc="PaperFluidData Registration" defaultstate="collapsed">
|
||||
+ register(LavaFluid.Source.class, PaperFallingFluidData::new);
|
||||
+ register(WaterFluid.Source.class, PaperFallingFluidData::new);
|
||||
+ register(LavaFluid.Flowing.class, PaperFlowingFluidData::new);
|
||||
+ register(WaterFluid.Flowing.class, PaperFlowingFluidData::new);
|
||||
+ //</editor-fold>
|
||||
+ }
|
||||
+
|
||||
+ static void register(final Class<? extends net.minecraft.world.level.material.Fluid> fluid, final Function<FluidState, PaperFluidData> creator) {
|
||||
+ Preconditions.checkState(MAP.put(fluid, creator) == null, "Duplicate mapping %s->%s", fluid, creator);
|
||||
+ MAP.put(fluid, creator);
|
||||
+ }
|
||||
+
|
||||
+ public static PaperFluidData createData(final FluidState state) {
|
||||
+ return MAP.getOrDefault(state.getType().getClass(), PaperFluidData::new).apply(state);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/block/fluid/package-info.java b/src/main/java/io/papermc/paper/block/fluid/package-info.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..cfabb814ebd281aab299c6c655266ff357e08806
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/block/fluid/package-info.java
|
||||
@@ -0,0 +1,5 @@
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+package io.papermc.paper.block.fluid;
|
||||
+
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
diff --git a/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..655dbd83ff4e632f1168b75e9b402b05aa9d8edf
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java
|
||||
@@ -0,0 +1,18 @@
|
||||
+
|
||||
+package io.papermc.paper.block.fluid.type;
|
||||
+
|
||||
+import io.papermc.paper.block.fluid.PaperFluidData;
|
||||
+import net.minecraft.world.level.material.FlowingFluid;
|
||||
+import net.minecraft.world.level.material.FluidState;
|
||||
+
|
||||
+public class PaperFallingFluidData extends PaperFluidData implements FallingFluidData {
|
||||
+
|
||||
+ public PaperFallingFluidData(final FluidState state) {
|
||||
+ super(state);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isFalling() {
|
||||
+ return this.getState().getValue(FlowingFluid.FALLING);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c0c2805cb045cdd835b402776a6923fe2ecc2a99
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java
|
||||
@@ -0,0 +1,11 @@
|
||||
+package io.papermc.paper.block.fluid.type;
|
||||
+
|
||||
+import net.minecraft.world.level.material.FluidState;
|
||||
+
|
||||
+public class PaperFlowingFluidData extends PaperFallingFluidData implements FlowingFluidData {
|
||||
+
|
||||
+ public PaperFlowingFluidData(final FluidState state) {
|
||||
+ super(state);
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
|
||||
index 29825ea687827c075b87e88c45672e7b0093ed17..9af491e6e9ac96fc766462a1f672f44f8fc50ef1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
|
||||
@@ -108,6 +108,13 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
|
||||
return CraftBlock.at(this.getHandle(), new BlockPos(x, y, z)).getState();
|
||||
}
|
||||
|
||||
+ // Paper start - FluidState API
|
||||
+ @Override
|
||||
+ public io.papermc.paper.block.fluid.FluidData getFluidData(final int x, final int y, final int z) {
|
||||
+ return io.papermc.paper.block.fluid.PaperFluidData.createData(getHandle().getFluidState(new BlockPos(x, y, z)));
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public BlockData getBlockData(Location location) {
|
||||
return this.getBlockData(location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
|
||||
index a23269e3bdb83f85a1d08d5f7b54742025223ada..a57ac9dc8d08b12ec00ad41d9a1779e5a81e4e8b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
|
||||
@@ -304,4 +304,11 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe
|
||||
return centerChunkZ;
|
||||
}
|
||||
// Paper end - Add more LimitedRegion API
|
||||
+ // Paper start - Fluid API
|
||||
+ @Override
|
||||
+ public io.papermc.paper.block.fluid.FluidData getFluidData(int x, int y, int z) {
|
||||
+ Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
|
||||
+ return super.getFluidData(x, y, z);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
138
patches/server/0923-add-number-format-api.patch
Normal file
138
patches/server/0923-add-number-format-api.patch
Normal file
|
@ -0,0 +1,138 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: David Mayr <davidliebtkekse@gmail.com>
|
||||
Date: Sat, 16 Dec 2023 10:40:29 +0100
|
||||
Subject: [PATCH] add number format api
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.network.chat.numbers.FixedFormat value
|
||||
public net.minecraft.network.chat.numbers.StyledFormat style
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/PaperScoreboardFormat.java b/src/main/java/io/papermc/paper/util/PaperScoreboardFormat.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6064086cc76ef0df999c7057121d0ac22bd4df65
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/PaperScoreboardFormat.java
|
||||
@@ -0,0 +1,38 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import io.papermc.paper.adventure.PaperAdventure;
|
||||
+import io.papermc.paper.scoreboard.numbers.NumberFormat;
|
||||
+
|
||||
+public final class PaperScoreboardFormat {
|
||||
+
|
||||
+ private PaperScoreboardFormat() {
|
||||
+ }
|
||||
+
|
||||
+ public static net.minecraft.network.chat.numbers.NumberFormat asVanilla(final NumberFormat format) {
|
||||
+ final net.minecraft.network.chat.numbers.NumberFormat vanilla;
|
||||
+ if (format instanceof final io.papermc.paper.scoreboard.numbers.StyledFormat styled) {
|
||||
+ vanilla = new net.minecraft.network.chat.numbers.StyledFormat(PaperAdventure.asVanilla(styled.style()));
|
||||
+ } else if (format instanceof final io.papermc.paper.scoreboard.numbers.FixedFormat fixed) {
|
||||
+ vanilla = new net.minecraft.network.chat.numbers.FixedFormat(io.papermc.paper.adventure.PaperAdventure
|
||||
+ .asVanilla(fixed.component()));
|
||||
+ } else if (format.equals(NumberFormat.blank())) {
|
||||
+ vanilla = net.minecraft.network.chat.numbers.BlankFormat.INSTANCE;
|
||||
+ } else {
|
||||
+ throw new IllegalArgumentException("Unknown format type " + format.getClass());
|
||||
+ }
|
||||
+
|
||||
+ return vanilla;
|
||||
+ }
|
||||
+
|
||||
+ public static NumberFormat asPaper(final net.minecraft.network.chat.numbers.NumberFormat vanilla) {
|
||||
+ if (vanilla instanceof final net.minecraft.network.chat.numbers.StyledFormat styled) {
|
||||
+ return NumberFormat.styled(PaperAdventure.asAdventure(styled.style));
|
||||
+ } else if (vanilla instanceof final net.minecraft.network.chat.numbers.FixedFormat fixed) {
|
||||
+ return NumberFormat.fixed(io.papermc.paper.adventure.PaperAdventure.asAdventure(fixed.value));
|
||||
+ } else if (vanilla instanceof net.minecraft.network.chat.numbers.BlankFormat) {
|
||||
+ return NumberFormat.blank();
|
||||
+ }
|
||||
+
|
||||
+ throw new IllegalArgumentException("Unknown format type " + vanilla.getClass());
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
|
||||
index 2d3abf2a1da487ead74d698cc5ea4eb729c35c8d..1fec80c4f02aab3770c05bac8bfa2b622625e630 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
|
||||
@@ -153,6 +153,34 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+ // Paper start - add number format
|
||||
+ @Override
|
||||
+ public io.papermc.paper.scoreboard.numbers.NumberFormat numberFormat() {
|
||||
+ this.checkState();
|
||||
+
|
||||
+ net.minecraft.network.chat.numbers.NumberFormat vanilla = this.objective.numberFormat();
|
||||
+
|
||||
+ if (vanilla == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return io.papermc.paper.util.PaperScoreboardFormat.asPaper(vanilla);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ @Override
|
||||
+ public void numberFormat(io.papermc.paper.scoreboard.numbers.NumberFormat format) {
|
||||
+ this.checkState();
|
||||
+
|
||||
+ if (format == null) {
|
||||
+ this.objective.setNumberFormat(null);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ this.objective.setNumberFormat(io.papermc.paper.util.PaperScoreboardFormat.asVanilla(format));
|
||||
+ }
|
||||
+ // Paper end - add number format
|
||||
+
|
||||
@Override
|
||||
public void unregister() {
|
||||
CraftScoreboard scoreboard = this.checkState();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java
|
||||
index 74d9c407e971804bed420370f7b684d8658eb5aa..e307e897d6e1ba4cb21883dfeaf334bfbf56cfc4 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java
|
||||
@@ -55,6 +55,41 @@ final class CraftScore implements Score {
|
||||
this.objective.checkState().board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).set(score);
|
||||
}
|
||||
|
||||
+
|
||||
+ // Paper start - add number format
|
||||
+ @Override
|
||||
+ public io.papermc.paper.scoreboard.numbers.NumberFormat numberFormat() {
|
||||
+ ReadOnlyScoreInfo scoreInfo = this.objective.checkState().board
|
||||
+ .getPlayerScoreInfo(this.entry, this.objective.getHandle());
|
||||
+
|
||||
+ if (scoreInfo == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ net.minecraft.network.chat.numbers.NumberFormat vanilla = scoreInfo.numberFormat();
|
||||
+
|
||||
+ if (vanilla == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return io.papermc.paper.util.PaperScoreboardFormat.asPaper(vanilla);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ @Override
|
||||
+ public void numberFormat(io.papermc.paper.scoreboard.numbers.NumberFormat format) {
|
||||
+ final net.minecraft.world.scores.ScoreAccess access = this.objective.checkState()
|
||||
+ .board.getOrCreatePlayerScore(this.entry, this.objective.getHandle());
|
||||
+
|
||||
+ if (format == null) {
|
||||
+ access.numberFormatOverride(null);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ access.numberFormatOverride(io.papermc.paper.util.PaperScoreboardFormat.asVanilla(format));
|
||||
+ }
|
||||
+ // Paper end - add number format
|
||||
+
|
||||
@Override
|
||||
public boolean isScoreSet() {
|
||||
Scoreboard board = this.objective.checkState().board;
|
32
patches/server/0924-improve-BanList-types.patch
Normal file
32
patches/server/0924-improve-BanList-types.patch
Normal file
|
@ -0,0 +1,32 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yannick Lamprecht <yannicklamprecht@live.de>
|
||||
Date: Sat, 10 Feb 2024 20:50:01 +0100
|
||||
Subject: [PATCH] improve BanList types
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 4dc64ab006399d62251f4a238d9c2caebd595301..97850b3111dfa86d15186fa200937b28bec428de 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2223,6 +2223,21 @@ public final class CraftServer implements Server {
|
||||
};
|
||||
}
|
||||
|
||||
+ // Paper start - add BanListType (which has a generic)
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ @Override
|
||||
+ public <B extends BanList<E>, E> B getBanList(final io.papermc.paper.ban.BanListType<B> type) {
|
||||
+ Preconditions.checkArgument(type != null, "BanList.BanType cannot be null");
|
||||
+ if (type == io.papermc.paper.ban.BanListType.IP) {
|
||||
+ return (B) new CraftIpBanList(this.playerList.getIpBans());
|
||||
+ } else if (type == io.papermc.paper.ban.BanListType.PROFILE) {
|
||||
+ return (B) new CraftProfileBanList(this.playerList.getBans());
|
||||
+ } else {
|
||||
+ throw new IllegalArgumentException("Unknown BanListType: " + type);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - add BanListType (which has a generic)
|
||||
+
|
||||
@Override
|
||||
public void setWhitelist(boolean value) {
|
||||
this.playerList.setUsingWhiteList(value);
|
31
patches/server/0925-Expanded-Hopper-API.patch
Normal file
31
patches/server/0925-Expanded-Hopper-API.patch
Normal file
|
@ -0,0 +1,31 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: vicisacat <victor.branchu@gmail.com>
|
||||
Date: Fri, 15 Mar 2024 17:35:40 +0100
|
||||
Subject: [PATCH] Expanded Hopper API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.level.block.entity.HopperBlockEntity setCooldown(I)V
|
||||
public net.minecraft.world.level.block.entity.HopperBlockEntity cooldownTime
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
|
||||
index 2995b407415c77288a54c3f4eb8cb93e1a289283..f3c4d3835a18475e2cd2f519ac3dd9d9b59c454d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
|
||||
@@ -40,4 +40,17 @@ public class CraftHopper extends CraftLootable<HopperBlockEntity> implements Hop
|
||||
public CraftHopper copy(Location location) {
|
||||
return new CraftHopper(this, location);
|
||||
}
|
||||
+
|
||||
+ // Paper start - Expanded Hopper API
|
||||
+ @Override
|
||||
+ public void setTransferCooldown(final int cooldown) {
|
||||
+ com.google.common.base.Preconditions.checkArgument(cooldown >= 0, "Hooper transfer cooldown cannot be negative (" + cooldown + ")");
|
||||
+ getSnapshot().setCooldown(cooldown);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getTransferCooldown() {
|
||||
+ return getSnapshot().cooldownTime;
|
||||
+ }
|
||||
+ // Paper end - Expanded Hopper API
|
||||
}
|
28
patches/server/0926-Add-BlockBreakProgressUpdateEvent.patch
Normal file
28
patches/server/0926-Add-BlockBreakProgressUpdateEvent.patch
Normal file
|
@ -0,0 +1,28 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Badbird5907 <50347938+Badbird5907@users.noreply.github.com>
|
||||
Date: Mon, 4 Mar 2024 22:18:28 -0500
|
||||
Subject: [PATCH] Add BlockBreakProgressUpdateEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index e3df141a2a49f10e83fe132514a9b1d969cc4417..3f0e5bd457e3231d84b9d14396d8d8859989f3f4 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1315,6 +1315,17 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
if (entity instanceof Player) entityhuman = (Player) entity;
|
||||
// CraftBukkit end
|
||||
|
||||
+ // Paper start - Add BlockBreakProgressUpdateEvent
|
||||
+ // If a plugin is using this method to send destroy packets for a client-side only entity id, no block progress occurred on the server.
|
||||
+ // Hence, do not call the event.
|
||||
+ if (entity != null) {
|
||||
+ float progressFloat = Mth.clamp(progress, 0, 10) / 10.0f;
|
||||
+ org.bukkit.craftbukkit.block.CraftBlock bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(this, pos);
|
||||
+ new io.papermc.paper.event.block.BlockBreakProgressUpdateEvent(bukkitBlock, progressFloat, entity.getBukkitEntity())
|
||||
+ .callEvent();
|
||||
+ }
|
||||
+ // Paper end - Add BlockBreakProgressUpdateEvent
|
||||
+
|
||||
while (iterator.hasNext()) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
||||
|
35
patches/server/0927-Deprecate-ItemStack-setType.patch
Normal file
35
patches/server/0927-Deprecate-ItemStack-setType.patch
Normal file
|
@ -0,0 +1,35 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
Date: Tue, 26 Mar 2024 21:42:23 -0400
|
||||
Subject: [PATCH] Deprecate ItemStack#setType
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
index ffd7ba14be38a117f5a7d7035a8d71a20fb1c4fc..7228d43d331de16cbaa0e97c7e3fa45c0bc89558 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
||||
@@ -429,4 +429,24 @@ public final class CraftItemStack extends ItemStack {
|
||||
static boolean hasItemMeta(net.minecraft.world.item.ItemStack item) {
|
||||
return !(item == null || item.getComponentsPatch().isEmpty());
|
||||
}
|
||||
+ // Paper start - with type
|
||||
+ @Override
|
||||
+ public ItemStack withType(final Material type) {
|
||||
+ if (type == Material.AIR) {
|
||||
+ return CraftItemStack.asCraftMirror(null);
|
||||
+ }
|
||||
+
|
||||
+ final net.minecraft.world.item.ItemStack copy = new net.minecraft.world.item.ItemStack(
|
||||
+ CraftItemType.bukkitToMinecraft(type), this.getAmount()
|
||||
+ );
|
||||
+
|
||||
+ if (this.handle != null) {
|
||||
+ copy.applyComponents(this.handle.getComponentsPatch());
|
||||
+ }
|
||||
+
|
||||
+ final CraftItemStack mirrored = CraftItemStack.asCraftMirror(copy);
|
||||
+ mirrored.setItemMeta(mirrored.getItemMeta());
|
||||
+ return mirrored;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
43
patches/server/0928-Add-CartographyItemEvent.patch
Normal file
43
patches/server/0928-Add-CartographyItemEvent.patch
Normal file
|
@ -0,0 +1,43 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Janet Blackquill <uhhadd@gmail.com>
|
||||
Date: Sun, 7 Apr 2024 16:52:42 -0400
|
||||
Subject: [PATCH] Add CartographyItemEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 8b5be8870a0077b82e345027b323b8b4f448f231..80755a80dfd484af361c208fd4de309ca7ef8553 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3125,6 +3125,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - cartography item event
|
||||
+ if (packet.getSlotNum() == net.minecraft.world.inventory.CartographyTableMenu.RESULT_SLOT && top instanceof org.bukkit.inventory.CartographyInventory cartographyInventory) {
|
||||
+ org.bukkit.inventory.ItemStack result = cartographyInventory.getResult();
|
||||
+ if (result != null && !result.isEmpty()) {
|
||||
+ if (click == ClickType.NUMBER_KEY) {
|
||||
+ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, packet.getSlotNum(), click, action, packet.getButtonNum());
|
||||
+ } else {
|
||||
+ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, packet.getSlotNum(), click, action);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - cartography item event
|
||||
+
|
||||
event.setCancelled(cancelled);
|
||||
AbstractContainerMenu oldContainer = this.player.containerMenu; // SPIGOT-1224
|
||||
this.cserver.getPluginManager().callEvent(event);
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
|
||||
index b3a16b024e46ee8203b225ee429a5c973eab12c6..dc42d42ef91bc3e49f967c0a30a0d1b56e09cf21 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
|
||||
@@ -71,7 +71,7 @@ public class CartographyTableMenu extends AbstractContainerMenu {
|
||||
this.resultContainer = new ResultContainer(this.createBlockHolder(context)) { // Paper - Add missing InventoryHolders
|
||||
@Override
|
||||
public void setChanged() {
|
||||
- CartographyTableMenu.this.slotsChanged(this);
|
||||
+ // CartographyTableMenu.this.slotsChanged(this); // Paper - Add CatographyItemEvent - do not recompute results if the result slot changes - allows to set the result slot via api
|
||||
super.setChanged();
|
||||
}
|
||||
|
106
patches/server/0929-More-Raid-API.patch
Normal file
106
patches/server/0929-More-Raid-API.patch
Normal file
|
@ -0,0 +1,106 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Fri, 4 Mar 2022 09:46:33 -0800
|
||||
Subject: [PATCH] More Raid API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.raid.Raid raidEvent
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java
|
||||
index 28922f2a1cf4762d5d7d09635b9268c6091300c3..11cf2d9def087b0898c828eaa21eb5f7b8811d5f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/raid/Raid.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java
|
||||
@@ -107,6 +107,11 @@ public class Raid {
|
||||
private Raid.RaidStatus status;
|
||||
private int celebrationTicks;
|
||||
private Optional<BlockPos> waveSpawnPos;
|
||||
+ // Paper start
|
||||
+ private static final String PDC_NBT_KEY = "BukkitValues";
|
||||
+ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry PDC_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
||||
+ public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(PDC_TYPE_REGISTRY);
|
||||
+ // Paper end
|
||||
|
||||
public Raid(int id, ServerLevel world, BlockPos pos) {
|
||||
this.raidEvent = new ServerBossEvent(Raid.RAID_NAME_COMPONENT, BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.NOTCHED_10);
|
||||
@@ -150,6 +155,11 @@ public class Raid {
|
||||
this.heroesOfTheVillage.add(NbtUtils.loadUUID(nbtbase));
|
||||
}
|
||||
}
|
||||
+ // Paper start
|
||||
+ if (nbt.contains(PDC_NBT_KEY, net.minecraft.nbt.Tag.TAG_COMPOUND)) {
|
||||
+ this.persistentDataContainer.putAll(nbt.getCompound(PDC_NBT_KEY));
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
}
|
||||
|
||||
@@ -862,6 +872,11 @@ public class Raid {
|
||||
}
|
||||
|
||||
nbt.put("HeroesOfTheVillage", nbttaglist);
|
||||
+ // Paper start
|
||||
+ if (!this.persistentDataContainer.isEmpty()) {
|
||||
+ nbt.put(PDC_NBT_KEY, this.persistentDataContainer.toTagCompound());
|
||||
+ }
|
||||
+ // Paper end
|
||||
return nbt;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRaid.java b/src/main/java/org/bukkit/craftbukkit/CraftRaid.java
|
||||
index b8ce1c1c2447f9cff1717bfcfd6eb911ade0d4b3..51f21af9d75769abdcba713b9aa33392e994d9b0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftRaid.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRaid.java
|
||||
@@ -103,4 +103,34 @@ public final class CraftRaid implements Raid {
|
||||
public net.minecraft.world.entity.raid.Raid getHandle() {
|
||||
return this.handle;
|
||||
}
|
||||
+
|
||||
+ // Paper start - more Raid API
|
||||
+ @Override
|
||||
+ public int getId() {
|
||||
+ return this.handle.getId();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.boss.BossBar getBossBar() {
|
||||
+ return new org.bukkit.craftbukkit.boss.CraftBossBar(this.handle.raidEvent);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.persistence.PersistentDataContainer getPersistentDataContainer() {
|
||||
+ return this.handle.persistentDataContainer;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(final Object o) {
|
||||
+ if (this == o) return true;
|
||||
+ if (o == null || this.getClass() != o.getClass()) return false;
|
||||
+ final org.bukkit.craftbukkit.CraftRaid craftRaid = (org.bukkit.craftbukkit.CraftRaid) o;
|
||||
+ return this.handle.equals(craftRaid.handle);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ return this.handle.hashCode();
|
||||
+ }
|
||||
+ // Paper end - more Raid API
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 1675ad5818340f21c7e5b6982af315bcad30240b..149377347fc632358a8bb97e644b1c4ab9be413d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -2326,6 +2326,14 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
return (raid == null) ? null : new CraftRaid(raid);
|
||||
}
|
||||
|
||||
+ // Paper start - more Raid API
|
||||
+ @Override
|
||||
+ public @Nullable Raid getRaid(final int id) {
|
||||
+ final net.minecraft.world.entity.raid.@Nullable Raid nmsRaid = this.world.getRaids().raidMap.get(id);
|
||||
+ return nmsRaid != null ? new CraftRaid(nmsRaid) : null;
|
||||
+ }
|
||||
+ // Paper end - more Raid API
|
||||
+
|
||||
@Override
|
||||
public List<Raid> getRaids() {
|
||||
Raids persistentRaid = this.world.getRaids();
|
|
@ -0,0 +1,103 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: leguan <longboard.noah@gmail.com>
|
||||
Date: Sun, 10 Mar 2024 20:10:41 +0100
|
||||
Subject: [PATCH] Add onboarding message for initial server start
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/configuration/Configurations.java b/src/main/java/io/papermc/paper/configuration/Configurations.java
|
||||
index d9502ba028a96f9cc846f9ed428bd8066b857ca3..87e5f614ba988547a827486740db217e28585773 100644
|
||||
--- a/src/main/java/io/papermc/paper/configuration/Configurations.java
|
||||
+++ b/src/main/java/io/papermc/paper/configuration/Configurations.java
|
||||
@@ -129,6 +129,7 @@ public abstract class Configurations<G, W> {
|
||||
if (Files.notExists(configFile)) {
|
||||
node = CommentedConfigurationNode.root(loader.defaultOptions());
|
||||
node.node(Configuration.VERSION_FIELD).raw(this.globalConfigVersion());
|
||||
+ GlobalConfiguration.isFirstStart = true;
|
||||
} else {
|
||||
node = loader.load();
|
||||
this.verifyGlobalConfigVersion(node);
|
||||
diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
|
||||
index 73e8a524925ed6f2580d3bd01616646fabafda78..450a1cc8f1624dce2daf52210d017e0732b1bdf7 100644
|
||||
--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
|
||||
+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
|
||||
@@ -27,6 +27,7 @@ public class GlobalConfiguration extends ConfigurationPart {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
static final int CURRENT_VERSION = 29; // (when you change the version, change the comment, so it conflicts on rebases): <insert changes here>
|
||||
private static GlobalConfiguration instance;
|
||||
+ public static boolean isFirstStart = false;
|
||||
public static GlobalConfiguration get() {
|
||||
return instance;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index f1b1be0caff83720d77454d333abae4613c66e72..f575c0042f67c70df0ddb1d1db68e0138cf0b534 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1151,6 +1151,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
long tickSection = Util.getNanos();
|
||||
long currentTime;
|
||||
// Paper end - further improve server tick loop
|
||||
+ // Paper start - Add onboarding message for initial server start
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.isFirstStart) {
|
||||
+ LOGGER.info("*************************************************************************************");
|
||||
+ LOGGER.info("This is the first time you're starting this server.");
|
||||
+ LOGGER.info("It's recommended you read our 'Getting Started' documentation for guidance.");
|
||||
+ LOGGER.info("View this and more helpful information here: https://docs.papermc.io/paper/next-steps");
|
||||
+ LOGGER.info("*************************************************************************************");
|
||||
+ }
|
||||
+ // Paper end - Add onboarding message for initial server start
|
||||
+
|
||||
while (this.running) {
|
||||
long i;
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
index 4d3fe4f56e0b264fa030409919caf52d5f421d46..759062d219ff490a3cb19e710c4d18e3e08288e0 100644
|
||||
--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
+++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
|
||||
@@ -90,6 +90,7 @@ public class MinecraftServerGui extends JComponent {
|
||||
this.setLayout(new BorderLayout());
|
||||
|
||||
try {
|
||||
+ this.add(this.buildOnboardingPanel(), "North"); // Paper - Add onboarding message for initial server start
|
||||
this.add(this.buildChatPanel(), "Center");
|
||||
this.add(this.buildInfoPanel(), "West");
|
||||
} catch (Exception exception) {
|
||||
@@ -115,6 +116,39 @@ public class MinecraftServerGui extends JComponent {
|
||||
return jpanel;
|
||||
}
|
||||
|
||||
+ // Paper start - Add onboarding message for initial server start
|
||||
+ private JComponent buildOnboardingPanel() {
|
||||
+ String onboardingLink = "https://docs.papermc.io/paper/next-steps";
|
||||
+ JPanel jPanel = new JPanel();
|
||||
+
|
||||
+ javax.swing.JLabel jLabel = new javax.swing.JLabel("If you need help setting up your server you can visit:");
|
||||
+ jLabel.setFont(MinecraftServerGui.MONOSPACED);
|
||||
+
|
||||
+ javax.swing.JLabel link = new javax.swing.JLabel("<html><u> " + onboardingLink + "</u></html>");
|
||||
+ link.setFont(MinecraftServerGui.MONOSPACED);
|
||||
+ link.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
|
||||
+ link.addMouseListener(new java.awt.event.MouseAdapter() {
|
||||
+ @Override
|
||||
+ public void mouseClicked(final java.awt.event.MouseEvent e) {
|
||||
+ try {
|
||||
+ java.awt.Desktop.getDesktop().browse(java.net.URI.create(onboardingLink));
|
||||
+ } catch (java.io.IOException exception) {
|
||||
+ LOGGER.error("Unable to find a default browser. Please manually visit the website: " + onboardingLink, exception);
|
||||
+ } catch (UnsupportedOperationException exception) {
|
||||
+ LOGGER.error("This platform does not support the BROWSE action. Please manually visit the website: " + onboardingLink, exception);
|
||||
+ } catch (SecurityException exception) {
|
||||
+ LOGGER.error("This action has been denied by the security manager. Please manually visit the website: " + onboardingLink, exception);
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ jPanel.add(jLabel);
|
||||
+ jPanel.add(link);
|
||||
+
|
||||
+ return jPanel;
|
||||
+ }
|
||||
+ // Paper end - Add onboarding message for initial server start
|
||||
+
|
||||
private JComponent buildPlayerPanel() {
|
||||
JList<?> jlist = new PlayerListComponent(this.server);
|
||||
JScrollPane jscrollpane = new JScrollPane(jlist, 22, 30);
|
22
patches/server/0931-Configurable-max-block-fluid-ticks.patch
Normal file
22
patches/server/0931-Configurable-max-block-fluid-ticks.patch
Normal file
|
@ -0,0 +1,22 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gero <gecam59@gmail.com>
|
||||
Date: Mon, 19 Feb 2024 17:39:59 +0100
|
||||
Subject: [PATCH] Configurable max block/fluid ticks
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 3f0e5bd457e3231d84b9d14396d8d8859989f3f4..2aa4437a76d29cdd793680734a36a41c6133ab91 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -492,9 +492,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
if (!this.isDebug() && flag) {
|
||||
j = this.getGameTime();
|
||||
gameprofilerfiller.push("blockTicks");
|
||||
- this.blockTicks.tick(j, 65536, this::tickBlock);
|
||||
+ this.blockTicks.tick(j, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks
|
||||
gameprofilerfiller.popPush("fluidTicks");
|
||||
- this.fluidTicks.tick(j, 65536, this::tickFluid);
|
||||
+ this.fluidTicks.tick(j, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks
|
||||
gameprofilerfiller.pop();
|
||||
}
|
||||
this.timings.scheduledBlocks.stopTiming(); // Paper
|
41
patches/server/0932-Fix-bees-aging-inside-hives.patch
Normal file
41
patches/server/0932-Fix-bees-aging-inside-hives.patch
Normal file
|
@ -0,0 +1,41 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sat, 21 Aug 2021 21:54:16 -0700
|
||||
Subject: [PATCH] Fix bees aging inside hives
|
||||
|
||||
Fixes bees incorrectly being aged up due to upstream's
|
||||
resetting the ticks inside hive on a failed release
|
||||
|
||||
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 f8828dc8334af19d7b2118e8cf34d94be5e09ee8..83ad45aed0894e90825d22e078632352c3a06816 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
|
||||
@@ -315,7 +315,7 @@ public class BeehiveBlockEntity extends BlockEntity {
|
||||
iterator.remove();
|
||||
// CraftBukkit start
|
||||
} else {
|
||||
- tileentitybeehive_hivebee.ticksInHive = tileentitybeehive_hivebee.occupant.minTicksInHive / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable
|
||||
+ tileentitybeehive_hivebee.exitTickCounter = tileentitybeehive_hivebee.occupant.minTicksInHive / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable // Paper - Fix bees aging inside hives; use exitTickCounter to keep actual bee life
|
||||
// CraftBukkit end
|
||||
}
|
||||
}
|
||||
@@ -475,15 +475,18 @@ public class BeehiveBlockEntity extends BlockEntity {
|
||||
private static class BeeData {
|
||||
|
||||
private final BeehiveBlockEntity.Occupant occupant;
|
||||
+ private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts
|
||||
private int ticksInHive;
|
||||
|
||||
BeeData(BeehiveBlockEntity.Occupant data) {
|
||||
this.occupant = data;
|
||||
this.ticksInHive = data.ticksInHive();
|
||||
+ this.exitTickCounter = this.ticksInHive; // Paper - Fix bees aging inside hives
|
||||
}
|
||||
|
||||
public boolean tick() {
|
||||
- return this.ticksInHive++ > this.occupant.minTicksInHive;
|
||||
+ this.ticksInHive++; // Paper - Fix bees aging inside hives
|
||||
+ return this.exitTickCounter++ > this.occupant.minTicksInHive; // Paper - Fix bees aging inside hives
|
||||
}
|
||||
|
||||
public BeehiveBlockEntity.Occupant toOccupant() {
|
19
patches/server/0933-Disable-memory-reserve-allocating.patch
Normal file
19
patches/server/0933-Disable-memory-reserve-allocating.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Warrior <50800980+Warriorrrr@users.noreply.github.com>
|
||||
Date: Thu, 18 Jan 2024 23:25:09 +0100
|
||||
Subject: [PATCH] Disable memory reserve allocating
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
|
||||
index 268310642181a715815d3b2d1c0f090e6252971a..589a8bf75be6ccc59f1e5dd5d8d9afed41c4772d 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReport.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReport.java
|
||||
@@ -253,7 +253,7 @@ public class CrashReport {
|
||||
}
|
||||
|
||||
public static void preload() {
|
||||
- MemoryReserve.allocate();
|
||||
+ // MemoryReserve.allocate(); // Paper - Disable memory reserve allocating
|
||||
(new CrashReport("Don't panic!", new Throwable())).getFriendlyReport(ReportType.CRASH);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: RodneyMKay <36546810+RodneyMKay@users.noreply.github.com>
|
||||
Date: Sun, 11 Feb 2024 20:05:11 +0100
|
||||
Subject: [PATCH] Fire EntityDamageByEntityEvent for unowned wither skulls
|
||||
|
||||
|
||||
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 8c17bed56c4659a8e226e88e113884160c3fa959..8831af1000d17d5a60302e3b0c522b2d2f082484 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
|
||||
@@ -77,7 +77,7 @@ public class WitherSkull extends AbstractHurtingProjectile {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
- flag = entity.hurtServer(worldserver, this.damageSources().magic(), 5.0F);
|
||||
+ flag = entity.hurtServer(worldserver, this.damageSources().magic().customCausingEntity(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls
|
||||
}
|
||||
|
||||
if (flag && entity instanceof LivingEntity entityliving) {
|
234
patches/server/0935-Fix-DamageSource-API.patch
Normal file
234
patches/server/0935-Fix-DamageSource-API.patch
Normal file
|
@ -0,0 +1,234 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sat, 9 Mar 2024 14:13:04 -0800
|
||||
Subject: [PATCH] Fix DamageSource API
|
||||
|
||||
Uses the correct entity in the EntityDamageByEntity event
|
||||
Returns the correct entity for API's DamageSource#getCausingEntity
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java
|
||||
index aee26dd78953ff43306aaa64161f5b9edcdd4b83..bb1a60180e58c1333e7bb33e8acf1b0225eda8a8 100644
|
||||
--- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java
|
||||
+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java
|
||||
@@ -29,8 +29,8 @@ public class DamageSource {
|
||||
private boolean sweep = false;
|
||||
private boolean melting = false;
|
||||
private boolean poison = false;
|
||||
- private Entity customEntityDamager = null; // This field is a helper for when direct entity damage is not set by vanilla
|
||||
- private Entity customCausingEntityDamager = null; // This field is a helper for when causing entity damage is not set by vanilla
|
||||
+ @Nullable
|
||||
+ private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API
|
||||
|
||||
public DamageSource sweep() {
|
||||
this.sweep = true;
|
||||
@@ -59,33 +59,19 @@ public class DamageSource {
|
||||
return this.poison;
|
||||
}
|
||||
|
||||
- public Entity getDamager() {
|
||||
- return (this.customEntityDamager != null) ? this.customEntityDamager : this.directEntity;
|
||||
- }
|
||||
-
|
||||
- public Entity getCausingDamager() {
|
||||
- return (this.customCausingEntityDamager != null) ? this.customCausingEntityDamager : this.causingEntity;
|
||||
- }
|
||||
-
|
||||
- public DamageSource customEntityDamager(Entity entity) {
|
||||
- // This method is not intended for change the causing entity if is already set
|
||||
- // also is only necessary if the entity passed is not the direct entity or different from the current causingEntity
|
||||
- if (this.customEntityDamager != null || this.directEntity == entity || this.causingEntity == entity) {
|
||||
- return this;
|
||||
- }
|
||||
- DamageSource damageSource = this.cloneInstance();
|
||||
- damageSource.customEntityDamager = entity;
|
||||
- return damageSource;
|
||||
+ // Paper start - fix DamageSource API
|
||||
+ @Nullable
|
||||
+ public Entity getCustomEventDamager() {
|
||||
+ return (this.customEventDamager != null) ? this.customEventDamager : this.directEntity;
|
||||
}
|
||||
|
||||
- public DamageSource customCausingEntityDamager(Entity entity) {
|
||||
- // This method is not intended for change the causing entity if is already set
|
||||
- // also is only necessary if the entity passed is not the direct entity or different from the current causingEntity
|
||||
- if (this.customCausingEntityDamager != null || this.directEntity == entity || this.causingEntity == entity) {
|
||||
- return this;
|
||||
+ public DamageSource customEventDamager(Entity entity) {
|
||||
+ if (this.directEntity != null) {
|
||||
+ throw new IllegalStateException("Cannot set custom event damager when direct entity is already set (report a bug to Paper)");
|
||||
}
|
||||
DamageSource damageSource = this.cloneInstance();
|
||||
- damageSource.customCausingEntityDamager = entity;
|
||||
+ damageSource.customEventDamager = entity;
|
||||
+ // Paper end - fix DamageSource API
|
||||
return damageSource;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSources.java b/src/main/java/net/minecraft/world/damagesource/DamageSources.java
|
||||
index fddbdb7322a2063996a28c5c3d93c265188b1256..be87cb3cfa15a7d889118cdc4b87232e30749023 100644
|
||||
--- a/src/main/java/net/minecraft/world/damagesource/DamageSources.java
|
||||
+++ b/src/main/java/net/minecraft/world/damagesource/DamageSources.java
|
||||
@@ -270,13 +270,7 @@ public class DamageSources {
|
||||
}
|
||||
|
||||
public DamageSource explosion(@Nullable Entity source, @Nullable Entity attacker) {
|
||||
- // CraftBukkit start
|
||||
- return this.explosion(source, attacker, attacker != null && source != null ? DamageTypes.PLAYER_EXPLOSION : DamageTypes.EXPLOSION);
|
||||
- }
|
||||
-
|
||||
- public DamageSource explosion(@Nullable Entity entity, @Nullable Entity entity1, ResourceKey<DamageType> resourceKey) {
|
||||
- return this.source(resourceKey, entity, entity1);
|
||||
- // CraftBukkit end
|
||||
+ return this.source(attacker != null && source != null ? DamageTypes.PLAYER_EXPLOSION : DamageTypes.EXPLOSION, source, attacker); // Paper - revert to vanilla
|
||||
}
|
||||
|
||||
public DamageSource sonicBoom(Entity attacker) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 0223f2e282a85882645f4ed52891c566a268f37b..3d4bb855dec45685d6e336d913903341f0ca4a11 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -3388,7 +3388,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return;
|
||||
}
|
||||
|
||||
- if (!this.hurtServer(world, this.damageSources().lightningBolt().customEntityDamager(lightning), 5.0F)) {
|
||||
+ if (!this.hurtServer(world, this.damageSources().lightningBolt().customEventDamager(lightning), 5.0F)) { // Paper - fix DamageSource API
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
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 8e91f930e19a91db44274e4ecd98841362867609..79e1e911333d4a009c0b4e2462b41a0c146b9a06 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
@@ -341,7 +341,7 @@ public class Turtle extends Animal {
|
||||
|
||||
@Override
|
||||
public void thunderHit(ServerLevel world, LightningBolt lightning) {
|
||||
- this.hurtServer(world, this.damageSources().lightningBolt().customEntityDamager(lightning), Float.MAX_VALUE); // CraftBukkit
|
||||
+ this.hurtServer(world, this.damageSources().lightningBolt().customEventDamager(lightning), Float.MAX_VALUE); // CraftBukkit // Paper - fix DamageSource API
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
|
||||
index 608acb4f3cb8f9a0dc10b819ed4bf577c229dd2c..7ed127a0a0c0d6e7b726216c48ef37af4db37628 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
|
||||
@@ -108,7 +108,7 @@ public abstract class BlockAttachedEntity extends Entity {
|
||||
} else {
|
||||
if (!this.isRemoved()) {
|
||||
// CraftBukkit start - fire break events
|
||||
- Entity damager = (source.isDirect()) ? source.getDirectEntity() : source.getEntity();
|
||||
+ Entity damager = (!source.isDirect() && source.getEntity() != null) ? source.getEntity() : source.getDirectEntity(); // Paper - fix DamageSource API
|
||||
HangingBreakEvent event;
|
||||
if (damager != null) {
|
||||
event = new HangingBreakByEntityEvent((Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), source.is(DamageTypeTags.IS_EXPLOSION) ? HangingBreakEvent.RemoveCause.EXPLOSION : HangingBreakEvent.RemoveCause.ENTITY);
|
||||
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 7a18dc59aed5294cd442994aa2d34ea00b877f46..1906dfc22af208d6e801ad4a8f2f9e9702432691 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
|
||||
@@ -271,7 +271,7 @@ public class Creeper extends Monster {
|
||||
if (!event.isCancelled()) {
|
||||
// CraftBukkit end
|
||||
this.dead = true;
|
||||
- worldserver.explode(this, net.minecraft.world.level.Explosion.getDefaultDamageSource(this.level(), this).customCausingEntityDamager(this.entityIgniter), null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit
|
||||
+ worldserver.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this)
|
||||
this.spawnLingeringCloud();
|
||||
this.triggerOnDeathMobEffects(worldserver, Entity.RemovalReason.KILLED);
|
||||
this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java b/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java
|
||||
index c08074d43d105b30ed5093614062a3bcafadfb74..ccc72a2cf02a633655b95f961be310879d8f904f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/EvokerFangs.java
|
||||
@@ -135,7 +135,7 @@ public class EvokerFangs extends Entity implements TraceableEntity {
|
||||
|
||||
if (target.isAlive() && !target.isInvulnerable() && target != entityliving1) {
|
||||
if (entityliving1 == null) {
|
||||
- target.hurt(this.damageSources().magic().customEntityDamager(this), 6.0F); // CraftBukkit
|
||||
+ target.hurt(this.damageSources().magic().customEventDamager(this), 6.0F); // CraftBukkit // Paper - fix DamageSource API
|
||||
} else {
|
||||
if (entityliving1.isAlliedTo((Entity) target)) {
|
||||
return;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
|
||||
index 080d886008e1f596733ea5331b32db35adef2e9b..5f790dd24f2bdae827c6dc597064b9b265089751 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
|
||||
@@ -170,7 +170,7 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
|
||||
if (entityplayer1 != null) {
|
||||
entityplayer1.resetFallDistance();
|
||||
entityplayer1.resetCurrentImpulseContext();
|
||||
- entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl().customEntityDamager(this), 5.0F); // CraftBukkit
|
||||
+ entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API
|
||||
}
|
||||
|
||||
this.playSound(worldserver, vec3d);
|
||||
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 8831af1000d17d5a60302e3b0c522b2d2f082484..4c47b30867e30d84908abf93dbefc252bc8c3453 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
|
||||
@@ -77,7 +77,7 @@ public class WitherSkull extends AbstractHurtingProjectile {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
- flag = entity.hurtServer(worldserver, this.damageSources().magic().customCausingEntity(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls
|
||||
+ flag = entity.hurtServer(worldserver, this.damageSources().magic().customEventDamager(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls // Paper - fix DamageSource API
|
||||
}
|
||||
|
||||
if (flag && entity instanceof LivingEntity entityliving) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java
|
||||
index 8532324060eed772a10e2a3429890438cf32f9ba..7df86e7124a9ed359f05324b8fc4c8862f7e4b79 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java
|
||||
@@ -41,13 +41,13 @@ public class CraftDamageSource implements DamageSource {
|
||||
|
||||
@Override
|
||||
public org.bukkit.entity.Entity getCausingEntity() {
|
||||
- net.minecraft.world.entity.Entity entity = this.getHandle().getCausingDamager();
|
||||
+ net.minecraft.world.entity.Entity entity = this.getHandle().getEntity(); // Paper - fix DamageSource API - revert to vanilla
|
||||
return (entity != null) ? entity.getBukkitEntity() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.entity.Entity getDirectEntity() {
|
||||
- net.minecraft.world.entity.Entity entity = this.getHandle().getDamager();
|
||||
+ net.minecraft.world.entity.Entity entity = this.getHandle().getDirectEntity(); // Paper - fix DamageSource API
|
||||
return (entity != null) ? entity.getBukkitEntity() : null;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class CraftDamageSource implements DamageSource {
|
||||
|
||||
@Override
|
||||
public boolean isIndirect() {
|
||||
- return this.getHandle().getCausingDamager() != this.getHandle().getDamager();
|
||||
+ return !this.getHandle().isDirect(); // Paper - fix DamageSource API
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java
|
||||
index 4c6e15535fa40aad8cf1920f392589404f9ba79c..35eb95ef6fb6a0f7ea63351e90741c489fdd15f9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSourceBuilder.java
|
||||
@@ -41,6 +41,11 @@ public class CraftDamageSourceBuilder implements DamageSource.Builder {
|
||||
|
||||
@Override
|
||||
public DamageSource build() {
|
||||
+ // Paper start - fix DamageCause API
|
||||
+ if (this.causingEntity != null && this.directEntity == null) {
|
||||
+ throw new IllegalArgumentException("Direct entity must be set if causing entity is set");
|
||||
+ }
|
||||
+ // Paper end - fix DamageCause API
|
||||
return CraftDamageSource.buildFromBukkit(this.damageType, this.causingEntity, this.directEntity, this.damageLocation);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index 89109bf9ad85b1859ce6ae0808ac0a1fb2cb6816..b0e7d1841d71e377d5ad596a22dfafb90d4f80cc 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -1092,7 +1092,7 @@ public class CraftEventFactory {
|
||||
|
||||
private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSource source, Map<DamageModifier, Double> modifiers, Map<DamageModifier, Function<? super Double, Double>> modifierFunctions, boolean cancelled) {
|
||||
CraftDamageSource bukkitDamageSource = new CraftDamageSource(source);
|
||||
- Entity damager = (source.getDamager() != null) ? source.getDamager() : source.getEntity();
|
||||
+ final Entity damager = source.getCustomEventDamager(); // Paper - fix DamageSource API
|
||||
if (source.is(DamageTypeTags.IS_EXPLOSION)) {
|
||||
if (damager == null) {
|
||||
return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.BLOCK_EXPLOSION, bukkitDamageSource, modifiers, modifierFunctions, cancelled);
|
|
@ -0,0 +1,59 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Pierpaolo Coletta <p.coletta@glyart.com>
|
||||
Date: Sat, 30 Mar 2024 21:06:10 +0100
|
||||
Subject: [PATCH] Fix creation of invalid block entity during world generation
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
|
||||
index 2e72e92762877b28dd908711671e1dfb933de9b0..b7d29389a357f142237cecd75f8ca91cf1eb6b5b 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
|
||||
@@ -324,7 +324,7 @@ public class WorldGenRegion implements WorldGenLevel {
|
||||
return false;
|
||||
} else {
|
||||
ChunkAccess ichunkaccess = this.getChunk(pos);
|
||||
- BlockState iblockdata1 = ichunkaccess.setBlockState(pos, state, false);
|
||||
+ BlockState iblockdata1 = ichunkaccess.setBlockState(pos, state, false); final BlockState previousBlockState = iblockdata1; // Paper - Clear block entity before setting up a DUMMY block entity - obfhelper
|
||||
|
||||
if (iblockdata1 != null) {
|
||||
this.level.onBlockStateChange(pos, iblockdata1, state);
|
||||
@@ -340,6 +340,17 @@ public class WorldGenRegion implements WorldGenLevel {
|
||||
ichunkaccess.removeBlockEntity(pos);
|
||||
}
|
||||
} else {
|
||||
+ // Paper start - Clear block entity before setting up a DUMMY block entity
|
||||
+ // The concept of removing a block entity when the block itself changes is generally lifted
|
||||
+ // from LevelChunk#setBlockState.
|
||||
+ // It is however to note that this may only run if the block actually changes.
|
||||
+ // Otherwise a chest block entity generated by a structure template that is later "updated" to
|
||||
+ // be waterlogged would remove its existing block entity (see PaperMC/Paper#10750)
|
||||
+ // This logic is *also* found in LevelChunk#setBlockState.
|
||||
+ if (previousBlockState != null && !java.util.Objects.equals(previousBlockState.getBlock(), state.getBlock())) {
|
||||
+ ichunkaccess.removeBlockEntity(pos);
|
||||
+ }
|
||||
+ // Paper end - Clear block entity before setting up a DUMMY block entity
|
||||
CompoundTag nbttagcompound = new CompoundTag();
|
||||
|
||||
nbttagcompound.putInt("x", pos.getX());
|
||||
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 7181acfafad91aa5f6ab7ce663d9be4a1b65b02a..5dd1df0da1f954778aebe0f40611ae0f3a7866ab 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -994,9 +994,14 @@ public class LevelChunk extends ChunkAccess {
|
||||
if (this.blockEntity.getType().isValid(iblockdata)) {
|
||||
this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), iblockdata, this.blockEntity);
|
||||
this.loggedInvalidBlockState = false;
|
||||
- } else if (!this.loggedInvalidBlockState) {
|
||||
- this.loggedInvalidBlockState = true;
|
||||
- LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata});
|
||||
+ // Paper start - Remove the Block Entity if it's invalid
|
||||
+ } else {
|
||||
+ LevelChunk.this.removeBlockEntity(this.getPos());
|
||||
+ if (!this.loggedInvalidBlockState) {
|
||||
+ this.loggedInvalidBlockState = true;
|
||||
+ LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata});
|
||||
+ }
|
||||
+ // Paper end - Remove the Block Entity if it's invalid
|
||||
}
|
||||
|
||||
gameprofilerfiller.pop();
|
|
@ -0,0 +1,95 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sat, 29 Oct 2022 17:02:42 -0700
|
||||
Subject: [PATCH] Fix possible StackOverflowError for some dispenses
|
||||
|
||||
For saddles, carpets, horse armor, and chests for horse-likes
|
||||
a BlockDispenseEvent handler that always mutated the item without
|
||||
changing the type would result in a SO error because when it went
|
||||
to find the replacement dispense behavior (since the item "changed")
|
||||
it didn't properly handle if the replacement was the same instance
|
||||
of dispense behavior.
|
||||
|
||||
Additionally equippable mob heads, wither skulls, and carved pumpkins
|
||||
are subject to the same possible error.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
index 18304349c9ab24657c4152aff800dba969174665..63b8c806b6ee0ea3cc5e6a7f613b5e57c94bfcf1 100644
|
||||
--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
@@ -232,7 +232,7 @@ public interface DispenseItemBehavior {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
|
||||
- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
|
||||
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError
|
||||
idispensebehavior.dispense(pointer, eventStack);
|
||||
return stack;
|
||||
}
|
||||
@@ -283,7 +283,7 @@ public interface DispenseItemBehavior {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
|
||||
- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
|
||||
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError
|
||||
idispensebehavior.dispense(pointer, eventStack);
|
||||
return stack;
|
||||
}
|
||||
@@ -645,7 +645,7 @@ public interface DispenseItemBehavior {
|
||||
stack.shrink(1);
|
||||
this.setSuccess(true);
|
||||
} else {
|
||||
- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack));
|
||||
+ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError
|
||||
}
|
||||
|
||||
return stack;
|
||||
@@ -691,7 +691,7 @@ public interface DispenseItemBehavior {
|
||||
stack.shrink(1);
|
||||
this.setSuccess(true);
|
||||
} else {
|
||||
- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack));
|
||||
+ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, this)); // Paper - fix possible StackOverflowError
|
||||
}
|
||||
|
||||
return stack;
|
||||
@@ -819,7 +819,7 @@ public interface DispenseItemBehavior {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
|
||||
- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
|
||||
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE && idispensebehavior != this) { // Paper - fix possible StackOverflowError
|
||||
idispensebehavior.dispense(pointer, eventStack);
|
||||
return stack;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
||||
index a03cc350973fda213251cad273a2db86f438904b..036dd3b15dfee4cd079710eba1255d2bdb4d7220 100644
|
||||
--- a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
||||
+++ b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
||||
@@ -23,10 +23,15 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior {
|
||||
|
||||
@Override
|
||||
protected ItemStack execute(BlockSource pointer, ItemStack stack) {
|
||||
- return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack) ? stack : super.execute(pointer, stack);
|
||||
+ return EquipmentDispenseItemBehavior.dispenseEquipment(pointer, stack, null) ? stack : super.execute(pointer, stack); // Paper - fix possible StackOverflowError
|
||||
}
|
||||
|
||||
- public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack) {
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper
|
||||
+ public static boolean dispenseEquipment(BlockSource pointer, ItemStack armor) {
|
||||
+ // Paper start
|
||||
+ return dispenseEquipment(pointer, armor, null);
|
||||
+ }
|
||||
+ public static boolean dispenseEquipment(BlockSource pointer, ItemStack stack, @javax.annotation.Nullable DispenseItemBehavior currentBehavior) {
|
||||
BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
|
||||
List<LivingEntity> list = pointer.level().getEntitiesOfClass(LivingEntity.class, new AABB(blockposition), (entityliving) -> {
|
||||
return entityliving.canEquipWithDispenser(stack);
|
||||
@@ -59,7 +64,7 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior {
|
||||
// Chain to handler for new item
|
||||
ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
|
||||
DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
|
||||
- if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE) {
|
||||
+ if (idispensebehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || idispensebehavior != EquipmentDispenseItemBehavior.INSTANCE)) { // Paper - fix possible StackOverflowError
|
||||
idispensebehavior.dispense(pointer, eventStack);
|
||||
return true;
|
||||
}
|
272
patches/server/0938-Improve-tag-parser-handling.patch
Normal file
272
patches/server/0938-Improve-tag-parser-handling.patch
Normal file
|
@ -0,0 +1,272 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Mon, 5 Feb 2024 11:54:04 +0100
|
||||
Subject: [PATCH] Improve tag parser handling
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
index 92848b64a78fce7a92e1657c2da6fc5ee53eea44..4b4f812eb13d5f03bcf3f8724d8aa8dbbc724e8b 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
@@ -304,9 +304,15 @@ public class CommandDispatcher<S> {
|
||||
}
|
||||
final CommandContextBuilder<S> context = contextSoFar.copy();
|
||||
final StringReader reader = new StringReader(originalReader);
|
||||
+ boolean stop = false; // Paper - Handle non-recoverable exceptions
|
||||
try {
|
||||
try {
|
||||
child.parse(reader, context);
|
||||
+ // Paper start - Handle non-recoverable exceptions
|
||||
+ } catch (final io.papermc.paper.brigadier.TagParseCommandSyntaxException e) {
|
||||
+ stop = true;
|
||||
+ throw e;
|
||||
+ // Paper end - Handle non-recoverable exceptions
|
||||
} catch (final RuntimeException ex) {
|
||||
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException().createWithContext(reader, ex.getMessage());
|
||||
}
|
||||
@@ -321,6 +327,7 @@ public class CommandDispatcher<S> {
|
||||
}
|
||||
errors.put(child, ex);
|
||||
reader.setCursor(cursor);
|
||||
+ if (stop) return new ParseResults<>(contextSoFar, originalReader, errors); // Paper - Handle non-recoverable exceptions
|
||||
continue;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/brigadier/TagParseCommandSyntaxException.java b/src/main/java/io/papermc/paper/brigadier/TagParseCommandSyntaxException.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a375ad4ba9db990b24a2b9ff366fcba66b753815
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/brigadier/TagParseCommandSyntaxException.java
|
||||
@@ -0,0 +1,15 @@
|
||||
+package io.papermc.paper.brigadier;
|
||||
+
|
||||
+import com.mojang.brigadier.LiteralMessage;
|
||||
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
+import net.minecraft.network.chat.Component;
|
||||
+
|
||||
+public final class TagParseCommandSyntaxException extends CommandSyntaxException {
|
||||
+
|
||||
+ private static final SimpleCommandExceptionType EXCEPTION_TYPE = new SimpleCommandExceptionType(new LiteralMessage("Error parsing NBT"));
|
||||
+
|
||||
+ public TagParseCommandSyntaxException(final String message) {
|
||||
+ super(EXCEPTION_TYPE, Component.literal(message));
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/nbt/TagParser.java b/src/main/java/net/minecraft/nbt/TagParser.java
|
||||
index da101bca71f4710812621b98f0a0d8cab180346a..3cd112584accb8e8f050ac99738eed11c902e60e 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/TagParser.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/TagParser.java
|
||||
@@ -49,6 +49,7 @@ public class TagParser {
|
||||
}, CompoundTag::toString);
|
||||
public static final Codec<CompoundTag> LENIENT_CODEC = Codec.withAlternative(AS_CODEC, CompoundTag.CODEC);
|
||||
private final StringReader reader;
|
||||
+ private int depth; // Paper
|
||||
|
||||
public static CompoundTag parseTag(String string) throws CommandSyntaxException {
|
||||
return new TagParser(new StringReader(string)).readSingleStruct();
|
||||
@@ -159,6 +160,7 @@ public class TagParser {
|
||||
|
||||
public CompoundTag readStruct() throws CommandSyntaxException {
|
||||
this.expect('{');
|
||||
+ this.increaseDepth(); // Paper
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
this.reader.skipWhitespace();
|
||||
|
||||
@@ -182,6 +184,7 @@ public class TagParser {
|
||||
}
|
||||
|
||||
this.expect('}');
|
||||
+ this.depth--; // Paper
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
@@ -191,6 +194,7 @@ public class TagParser {
|
||||
if (!this.reader.canRead()) {
|
||||
throw ERROR_EXPECTED_VALUE.createWithContext(this.reader);
|
||||
} else {
|
||||
+ this.increaseDepth(); // Paper
|
||||
ListTag listTag = new ListTag();
|
||||
TagType<?> tagType = null;
|
||||
|
||||
@@ -216,6 +220,7 @@ public class TagParser {
|
||||
}
|
||||
|
||||
this.expect(']');
|
||||
+ this.depth--; // Paper
|
||||
return listTag;
|
||||
}
|
||||
}
|
||||
@@ -288,4 +293,11 @@ public class TagParser {
|
||||
this.reader.skipWhitespace();
|
||||
this.reader.expect(c);
|
||||
}
|
||||
+
|
||||
+ private void increaseDepth() throws CommandSyntaxException {
|
||||
+ this.depth++;
|
||||
+ if (this.depth > 512) {
|
||||
+ throw new io.papermc.paper.brigadier.TagParseCommandSyntaxException("NBT tag is too complex, depth > 512");
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/chat/ComponentUtils.java b/src/main/java/net/minecraft/network/chat/ComponentUtils.java
|
||||
index 3365aed2b67ae0e4dd0410f5190ba474f146139b..8b776434a733b91129b089d702b2583b727bf3d2 100644
|
||||
--- a/src/main/java/net/minecraft/network/chat/ComponentUtils.java
|
||||
+++ b/src/main/java/net/minecraft/network/chat/ComponentUtils.java
|
||||
@@ -33,10 +33,30 @@ public class ComponentUtils {
|
||||
}
|
||||
}
|
||||
|
||||
+ @io.papermc.paper.annotation.DoNotUse // Paper - validate separators - right now this method is only used for separator evaluation. Error on build if this changes to re-evaluate.
|
||||
public static Optional<MutableComponent> updateForEntity(@Nullable CommandSourceStack source, Optional<Component> text, @Nullable Entity sender, int depth) throws CommandSyntaxException {
|
||||
return text.isPresent() ? Optional.of(updateForEntity(source, text.get(), sender, depth)) : Optional.empty();
|
||||
}
|
||||
|
||||
+ // Paper start - validate separator
|
||||
+ public static Optional<MutableComponent> updateSeparatorForEntity(@Nullable CommandSourceStack source, Optional<Component> text, @Nullable Entity sender, int depth) throws CommandSyntaxException {
|
||||
+ if (text.isEmpty() || !isValidSelector(text.get())) return Optional.empty();
|
||||
+ return Optional.of(updateForEntity(source, text.get(), sender, depth));
|
||||
+ }
|
||||
+ public static boolean isValidSelector(final Component component) {
|
||||
+ final ComponentContents contents = component.getContents();
|
||||
+
|
||||
+ if (contents instanceof net.minecraft.network.chat.contents.NbtContents || contents instanceof net.minecraft.network.chat.contents.SelectorContents) return false;
|
||||
+ if (contents instanceof final net.minecraft.network.chat.contents.TranslatableContents translatableContents) {
|
||||
+ for (final Object arg : translatableContents.getArgs()) {
|
||||
+ if (arg instanceof final Component argumentAsComponent && !isValidSelector(argumentAsComponent)) return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end - validate separator
|
||||
+
|
||||
public static MutableComponent updateForEntity(@Nullable CommandSourceStack source, Component text, @Nullable Entity sender, int depth) throws CommandSyntaxException {
|
||||
if (depth > 100) {
|
||||
return text.copy();
|
||||
diff --git a/src/main/java/net/minecraft/network/chat/contents/NbtContents.java b/src/main/java/net/minecraft/network/chat/contents/NbtContents.java
|
||||
index df26c39a2bb20e2021b50211dce905483a77f4e6..5634122dac8afeecab0cde623e9868d8e865e02a 100644
|
||||
--- a/src/main/java/net/minecraft/network/chat/contents/NbtContents.java
|
||||
+++ b/src/main/java/net/minecraft/network/chat/contents/NbtContents.java
|
||||
@@ -120,7 +120,7 @@ public class NbtContents implements ComponentContents {
|
||||
}).map(Tag::getAsString);
|
||||
if (this.interpreting) {
|
||||
Component component = DataFixUtils.orElse(
|
||||
- ComponentUtils.updateForEntity(source, this.separator, sender, depth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR
|
||||
+ ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR // Paper - validate separator
|
||||
);
|
||||
return stream.flatMap(text -> {
|
||||
try {
|
||||
@@ -132,7 +132,7 @@ public class NbtContents implements ComponentContents {
|
||||
}
|
||||
}).reduce((accumulator, current) -> accumulator.append(component).append(current)).orElseGet(Component::empty);
|
||||
} else {
|
||||
- return ComponentUtils.updateForEntity(source, this.separator, sender, depth)
|
||||
+ return ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth) // Paper - validate separator
|
||||
.map(
|
||||
text -> stream.map(Component::literal)
|
||||
.reduce((accumulator, current) -> accumulator.append(text).append(current))
|
||||
diff --git a/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java b/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java
|
||||
index 5e87f5a2bbffe2eba3fc4fb0da51acee99e72fc2..4131067620f723be28a6cdb7508e14d7e2aed48b 100644
|
||||
--- a/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java
|
||||
+++ b/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java
|
||||
@@ -36,7 +36,7 @@ public record SelectorContents(SelectorPattern selector, Optional<Component> sep
|
||||
if (source == null) {
|
||||
return Component.empty();
|
||||
} else {
|
||||
- Optional<? extends Component> optional = ComponentUtils.updateForEntity(source, this.separator, sender, depth);
|
||||
+ Optional<? extends Component> optional = ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth); // Paper - validate separator
|
||||
return ComponentUtils.formatList(this.selector.resolved().findEntities(source), optional, Entity::getDisplayName);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java b/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java
|
||||
index 56e641bc5f6edc657647993ea2efbb7bb9c2f732..4aa6232bf0f72fcde32d257100bd15b1c5192aaa 100644
|
||||
--- a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java
|
||||
+++ b/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java
|
||||
@@ -181,6 +181,15 @@ public class TranslatableContents implements ComponentContents {
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> visit(FormattedText.ContentConsumer<T> visitor) {
|
||||
+ // Paper start - Count visited parts
|
||||
+ try {
|
||||
+ return this.visit(new TranslatableContentConsumer<>(visitor));
|
||||
+ } catch (IllegalArgumentException ignored) {
|
||||
+ return visitor.accept("...");
|
||||
+ }
|
||||
+ }
|
||||
+ private <T> Optional<T> visit(TranslatableContentConsumer<T> visitor) {
|
||||
+ // Paper end - Count visited parts
|
||||
this.decompose();
|
||||
|
||||
for (FormattedText formattedText : this.decomposedParts) {
|
||||
@@ -192,6 +201,25 @@ public class TranslatableContents implements ComponentContents {
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
+ // Paper start - Count visited parts
|
||||
+ private static final class TranslatableContentConsumer<T> implements FormattedText.ContentConsumer<T> {
|
||||
+ private static final IllegalArgumentException EX = new IllegalArgumentException("Too long");
|
||||
+ private final FormattedText.ContentConsumer<T> visitor;
|
||||
+ private int visited;
|
||||
+
|
||||
+ private TranslatableContentConsumer(FormattedText.ContentConsumer<T> visitor) {
|
||||
+ this.visitor = visitor;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Optional<T> accept(final String asString) {
|
||||
+ if (visited++ > 32) {
|
||||
+ throw EX;
|
||||
+ }
|
||||
+ return this.visitor.accept(asString);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Count visited parts
|
||||
|
||||
@Override
|
||||
public MutableComponent resolve(@Nullable CommandSourceStack source, @Nullable Entity sender, int depth) throws CommandSyntaxException {
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java
|
||||
index 898b19887ed34c87003fc63cb5905df2ba6234a5..b47eeb23055b135d5567552ba983bfbc3e1fab67 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java
|
||||
@@ -19,7 +19,7 @@ public class ServerboundCommandSuggestionPacket implements Packet<ServerGamePack
|
||||
|
||||
private ServerboundCommandSuggestionPacket(FriendlyByteBuf buf) {
|
||||
this.id = buf.readVarInt();
|
||||
- this.command = buf.readUtf(32500);
|
||||
+ this.command = buf.readUtf(2048); // Paper
|
||||
}
|
||||
|
||||
private void write(FriendlyByteBuf buf) {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 80755a80dfd484af361c208fd4de309ca7ef8553..74b70c7a41d03bae57e1b2863b7ce947f951da46 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -770,6 +770,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
return;
|
||||
}
|
||||
// Paper end - Don't suggest if tab-complete is disabled
|
||||
+ // Paper start
|
||||
+ final int index;
|
||||
+ if (packet.getCommand().length() > 64 && ((index = packet.getCommand().indexOf(' ')) == -1 || index >= 64)) {
|
||||
+ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
// Paper start - AsyncTabCompleteEvent
|
||||
TAB_COMPLETE_EXECUTOR.execute(() -> this.handleCustomCommandSuggestions0(packet));
|
||||
}
|
||||
@@ -822,6 +829,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
private void sendServerSuggestions(final ServerboundCommandSuggestionPacket packet, final StringReader stringreader) {
|
||||
// Paper end - AsyncTabCompleteEvent
|
||||
ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
|
||||
+ // Paper start - Handle non-recoverable exceptions
|
||||
+ if (!parseresults.getExceptions().isEmpty()
|
||||
+ && parseresults.getExceptions().values().stream().anyMatch(e -> e instanceof io.papermc.paper.brigadier.TagParseCommandSyntaxException)) {
|
||||
+ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Handle non-recoverable exceptions
|
||||
|
||||
this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
|
||||
// Paper start - Don't tab-complete namespaced commands if send-namespaced is false
|
38
patches/server/0939-Item-Mutation-Fixes.patch
Normal file
38
patches/server/0939-Item-Mutation-Fixes.patch
Normal file
|
@ -0,0 +1,38 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
Date: Wed, 20 Mar 2024 20:41:35 -0400
|
||||
Subject: [PATCH] Item Mutation Fixes
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
|
||||
index 36496144dd6fa87163b692034570eba70c83678c..b7300052f3c3d496ea41b681a2d5d5b554e67c63 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
|
||||
@@ -220,7 +220,7 @@ public class EnchantmentMenu extends AbstractContainerMenu {
|
||||
return false;
|
||||
} else if (this.costs[id] > 0 && !itemstack.isEmpty() && (player.experienceLevel >= j && player.experienceLevel >= this.costs[id] || player.getAbilities().instabuild)) {
|
||||
this.access.execute((world, blockposition) -> {
|
||||
- ItemStack itemstack2 = itemstack;
|
||||
+ ItemStack itemstack2 = itemstack; // Paper - diff on change
|
||||
List<EnchantmentInstance> list = this.getEnchantmentList(world.registryAccess(), itemstack, id, this.costs[id]);
|
||||
|
||||
// CraftBukkit start
|
||||
@@ -243,10 +243,16 @@ public class EnchantmentMenu extends AbstractContainerMenu {
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
- if (itemstack.is(Items.BOOK)) {
|
||||
- itemstack2 = itemstack.transmuteCopy(Items.ENCHANTED_BOOK);
|
||||
+ // Paper start
|
||||
+ itemstack2 = org.bukkit.craftbukkit.inventory.CraftItemStack.getOrCloneOnMutation(item, event.getItem());
|
||||
+ if (itemstack2 != itemstack) {
|
||||
this.enchantSlots.setItem(0, itemstack2);
|
||||
}
|
||||
+ if (itemstack2.is(Items.BOOK)) {
|
||||
+ itemstack2 = itemstack2.transmuteCopy(Items.ENCHANTED_BOOK);
|
||||
+ this.enchantSlots.setItem(0, itemstack2);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
// CraftBukkit start
|
||||
for (Map.Entry<org.bukkit.enchantments.Enchantment, Integer> entry : event.getEnchantsToAdd().entrySet()) {
|
35
patches/server/0940-Per-world-ticks-per-spawn-settings.patch
Normal file
35
patches/server/0940-Per-world-ticks-per-spawn-settings.patch
Normal file
|
@ -0,0 +1,35 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sat, 13 Nov 2021 12:36:26 -0800
|
||||
Subject: [PATCH] Per world ticks per spawn settings
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 83537aa240ebff8dd19b450956730dc3d4f355a0..ffe894f3034a967f7e3d820c6416acb8adbcfb84 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -186,6 +186,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
return this.getChunkIfLoaded(chunkX, chunkZ) != null;
|
||||
}
|
||||
// Paper end - Use getChunkIfLoadedImmediately
|
||||
+ // Paper start - per world ticks per spawn
|
||||
+ private int getTicksPerSpawn(SpawnCategory spawnCategory) {
|
||||
+ final int perWorld = this.paperConfig().entities.spawning.ticksPerSpawn.getInt(CraftSpawnCategory.toNMS(spawnCategory));
|
||||
+ if (perWorld >= 0) {
|
||||
+ return perWorld;
|
||||
+ }
|
||||
+ return this.getCraftServer().getTicksPerSpawns(spawnCategory);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
|
||||
public abstract ResourceKey<LevelStem> getTypeKey();
|
||||
@@ -199,7 +208,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// CraftBukkit Ticks things
|
||||
for (SpawnCategory spawnCategory : SpawnCategory.values()) {
|
||||
if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
- this.ticksPerSpawnCategory.put(spawnCategory, (long) this.getCraftServer().getTicksPerSpawns(spawnCategory));
|
||||
+ this.ticksPerSpawnCategory.put(spawnCategory, this.getTicksPerSpawn(spawnCategory)); // Paper
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Mon, 12 Dec 2022 12:14:03 -0800
|
||||
Subject: [PATCH] Properly track the changed item from dispense events
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
index 63b8c806b6ee0ea3cc5e6a7f613b5e57c94bfcf1..cd77e86ff289634d2dd1c56002e569ff70d15f25 100644
|
||||
--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
@@ -129,10 +129,14 @@ public interface DispenseItemBehavior {
|
||||
idispensebehavior.dispense(pointer, eventStack);
|
||||
return stack;
|
||||
}
|
||||
+ // Paper start - track changed items in the dispense event
|
||||
+ itemstack1 = CraftItemStack.unwrap(event.getItem()); // unwrap is safe because the stack won't be modified
|
||||
+ entitytypes = ((SpawnEggItem) itemstack1.getItem()).getType(itemstack1);
|
||||
+ // Paper end - track changed item from dispense event
|
||||
}
|
||||
|
||||
try {
|
||||
- entitytypes.spawn(pointer.level(), stack, (Player) null, pointer.pos().relative(enumdirection), EntitySpawnReason.DISPENSER, enumdirection != Direction.UP, false);
|
||||
+ entitytypes.spawn(pointer.level(), itemstack1, (Player) null, pointer.pos().relative(enumdirection), EntitySpawnReason.DISPENSER, enumdirection != Direction.UP, false); // Paper - track changed item in dispense event
|
||||
} catch (Exception exception) {
|
||||
DispenseItemBehavior.LOGGER.error("Error while dispensing spawn egg from dispenser at {}", pointer.pos(), exception); // CraftBukkit - decompile error
|
||||
return ItemStack.EMPTY;
|
||||
@@ -186,9 +190,10 @@ public interface DispenseItemBehavior {
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
+ final ItemStack newStack = CraftItemStack.unwrap(event.getItem()); // Paper - use event itemstack (unwrap is fine here because the stack won't be modified)
|
||||
Consumer<ArmorStand> consumer = EntityType.appendDefaultStackConfig((entityarmorstand) -> {
|
||||
entityarmorstand.setYRot(enumdirection.toYRot());
|
||||
- }, worldserver, stack, (Player) null);
|
||||
+ }, worldserver, newStack, (Player) null); // Paper - track changed items in the dispense event
|
||||
ArmorStand entityarmorstand = (ArmorStand) EntityType.ARMOR_STAND.spawn(worldserver, consumer, blockposition, EntitySpawnReason.DISPENSER, false, false);
|
||||
|
||||
if (entityarmorstand != null) {
|
||||
@@ -237,7 +242,7 @@ public interface DispenseItemBehavior {
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
- ((Saddleable) list.get(0)).equipSaddle(itemstack1, SoundSource.BLOCKS);
|
||||
+ ((Saddleable) list.get(0)).equipSaddle(CraftItemStack.asNMSCopy(event.getItem()), SoundSource.BLOCKS); // Paper - track changed items in dispense event
|
||||
// CraftBukkit end
|
||||
this.setSuccess(true);
|
||||
return stack;
|
||||
@@ -330,6 +335,7 @@ public interface DispenseItemBehavior {
|
||||
int y = blockposition.getY();
|
||||
int z = blockposition.getZ();
|
||||
BlockState iblockdata = worldserver.getBlockState(blockposition);
|
||||
+ ItemStack dispensedItem = stack; // Paper - track changed item from the dispense event
|
||||
// Paper start - correctly check if the bucket place will succeed
|
||||
/* Taken from SolidBucketItem#emptyContents */
|
||||
boolean willEmptyContentsSolidBucketItem = dispensiblecontaineritem instanceof net.minecraft.world.item.SolidBucketItem && worldserver.isInWorldBounds(blockposition) && iblockdata.isAir();
|
||||
@@ -359,12 +365,15 @@ public interface DispenseItemBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
- dispensiblecontaineritem = (DispensibleContainerItem) CraftItemStack.asNMSCopy(event.getItem()).getItem();
|
||||
+ // Paper start - track changed item from dispense event
|
||||
+ dispensedItem = CraftItemStack.unwrap(event.getItem()); // unwrap is safe here as the stack isn't mutated
|
||||
+ dispensiblecontaineritem = (DispensibleContainerItem) dispensedItem.getItem();
|
||||
+ // Paper end - track changed item from dispense event
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (dispensiblecontaineritem.emptyContents((Player) null, worldserver, blockposition, (BlockHitResult) null)) {
|
||||
- dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, stack, blockposition);
|
||||
+ dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, dispensedItem, blockposition); // Paper - track changed item from dispense event
|
||||
return this.consumeWithRemainder(pointer, stack, new ItemStack(Items.BUCKET));
|
||||
} else {
|
||||
return this.defaultDispenseItemBehavior.dispense(pointer, stack);
|
||||
diff --git a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
|
||||
index a9d230d6ff22d5e3a11b2f31e7d751f44888a12c..df495161a5842cf38518adabd359bb35193ee2b3 100644
|
||||
--- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
|
||||
+++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
|
||||
@@ -64,7 +64,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
- Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, stack, enumdirection), worldserver, stack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty());
|
||||
+ Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, CraftItemStack.unwrap(event.getItem()), enumdirection), worldserver, stack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - mtrack changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies
|
||||
((Entity) iprojectile).projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(pointer.blockEntity());
|
||||
// itemstack.shrink(1); // CraftBukkit - Handled during event processing
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
|
||||
index f84987c36a16df19286d6f1badfb1ffb9cc7e770..8e089f7d5e7fa9ddeccd0691185555f279d55426 100644
|
||||
--- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
|
||||
+++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
|
||||
@@ -57,7 +57,12 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior {
|
||||
// CraftBukkit end
|
||||
|
||||
try {
|
||||
- this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(pointer.level(), blockposition, enumdirection, stack, enumdirection1)).consumesAction());
|
||||
+ // Paper start - track changed items in the dispense event
|
||||
+ this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(pointer.level(), blockposition, enumdirection, CraftItemStack.asNMSCopy(event.getItem()), enumdirection1)).consumesAction());
|
||||
+ if (this.isSuccess()) {
|
||||
+ stack.shrink(1); // vanilla shrink is in the place function above, manually handle it here
|
||||
+ }
|
||||
+ // Paper end - track changed items in the dispense event
|
||||
} catch (Exception exception) {
|
||||
ShulkerBoxDispenseBehavior.LOGGER.error("Error trying to place shulker box at {}", blockposition, exception);
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 13 May 2020 23:01:26 -0400
|
||||
Subject: [PATCH] Protect Bedrock and End Portal/Frames from being destroyed
|
||||
|
||||
This fixes exploits that let players destroy bedrock by Pistons, explosions
|
||||
and Mushrooom/Tree generation.
|
||||
|
||||
These blocks are designed to not be broken except by creative players/commands.
|
||||
So protect them from a multitude of methods of destroying them.
|
||||
|
||||
A config is provided if you rather let players use these exploits, and let
|
||||
them destroy the worlds End Portals and get on top of the nether easy.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index ffe894f3034a967f7e3d820c6416acb8adbcfb84..35b9a6d382e420844fc21c88b7d8044e3b8b8368 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -447,6 +447,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
|
||||
// CraftBukkit start - tree generation
|
||||
if (this.captureTreeGeneration) {
|
||||
+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
+ BlockState type = getBlockState(pos);
|
||||
+ if (!type.isDestroyable()) return false;
|
||||
+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
CraftBlockState blockstate = this.capturedBlockStates.get(pos);
|
||||
if (blockstate == null) {
|
||||
blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
index 86656de31b1e33381eddd3ef210122118b31e620..fd1ecedfab037e377e4dded61539689bacc90f80 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -150,6 +150,7 @@ public class ServerExplosion implements Explosion {
|
||||
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
|
||||
BlockPos blockposition = BlockPos.containing(d4, d5, d6);
|
||||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
+ if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions
|
||||
|
||||
if (!this.level.isInWorldBounds(blockposition)) {
|
||||
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 9917df070d9815b6915e4a0b022dfe4e5b7861e7..729c3d8279b13d21c65ede89ea50869b69d5bfe6 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
@@ -89,6 +89,19 @@ public class Block extends BlockBehaviour implements ItemLike {
|
||||
protected final StateDefinition<Block, BlockState> stateDefinition;
|
||||
private BlockState defaultBlockState;
|
||||
// Paper start
|
||||
+ public final boolean isDestroyable() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits ||
|
||||
+ this != Blocks.BARRIER &&
|
||||
+ this != Blocks.BEDROCK &&
|
||||
+ this != Blocks.END_PORTAL_FRAME &&
|
||||
+ this != Blocks.END_PORTAL &&
|
||||
+ this != Blocks.END_GATEWAY &&
|
||||
+ this != Blocks.COMMAND_BLOCK &&
|
||||
+ this != Blocks.REPEATING_COMMAND_BLOCK &&
|
||||
+ this != Blocks.CHAIN_COMMAND_BLOCK &&
|
||||
+ this != Blocks.STRUCTURE_BLOCK &&
|
||||
+ this != Blocks.JIGSAW;
|
||||
+ }
|
||||
public co.aikar.timings.Timing timing;
|
||||
public co.aikar.timings.Timing getTiming() {
|
||||
if (timing == null) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
index b27cf7d27672ba9ff8ade84b5a8454b19b935607..83bffe2ac011ed0cbd86149e3c803393d30a9e6e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
@@ -216,6 +216,12 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
@Override
|
||||
protected boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
|
||||
Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING);
|
||||
+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; prevent retracting when we're facing the wrong way (we were replaced before retraction could occur)
|
||||
+ Direction directionQueuedAs = Direction.from3DDataValue(data & 7); // Paper - copied from below
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && enumdirection != directionQueuedAs) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
BlockState iblockdata1 = (BlockState) state.setValue(PistonBaseBlock.EXTENDED, true);
|
||||
|
||||
if (!world.isClientSide) {
|
||||
@@ -256,7 +262,7 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
}
|
||||
// Paper end - Fix sticky pistons and BlockPistonRetractEvent
|
||||
world.setBlock(pos, iblockdata2, 20);
|
||||
- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true));
|
||||
+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed; diff on change
|
||||
world.blockUpdated(pos, iblockdata2.getBlock());
|
||||
iblockdata2.updateNeighbourShapes(world, pos, 2);
|
||||
if (this.isSticky) {
|
||||
@@ -292,7 +298,14 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
- world.removeBlock(pos.relative(enumdirection), false);
|
||||
+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; fix headless pistons breaking blocks
|
||||
+ BlockPos headPos = pos.relative(enumdirection);
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || world.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, enumdirection)) { // double check to make sure we're not a headless piston.
|
||||
+ world.removeBlock(headPos, false);
|
||||
+ } else {
|
||||
+ ((ServerLevel) world).getChunkSource().blockChanged(headPos); // ... fix client desync
|
||||
+ }
|
||||
+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
}
|
||||
|
||||
world.playSound((Player) null, pos, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.15F + 0.6F);
|
||||
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 1b988b92e80faa1ac224caf9f9e955ac43a4c45a..95d30c2db7e291d65c24feb114b0f3598d280912 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
|
||||
@@ -178,7 +178,7 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
}
|
||||
|
||||
protected void onExplosionHit(BlockState state, ServerLevel world, BlockPos pos, Explosion explosion, BiConsumer<ItemStack, BlockPos> stackMerger) {
|
||||
- if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK) {
|
||||
+ if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK && state.isDestroyable()) { // Paper - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
Block block = state.getBlock();
|
||||
boolean flag = explosion.getIndirectSourceEntity() instanceof Player;
|
||||
|
||||
@@ -257,7 +257,7 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
}
|
||||
|
||||
protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
|
||||
- return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem()));
|
||||
+ return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
}
|
||||
|
||||
protected boolean canBeReplaced(BlockState state, Fluid fluid) {
|
||||
@@ -945,6 +945,12 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
return this.legacySolid;
|
||||
}
|
||||
|
||||
+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
+ public final boolean isDestroyable() {
|
||||
+ return getBlock().isDestroyable();
|
||||
+ }
|
||||
+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
+
|
||||
public boolean isValidSpawn(BlockGetter world, BlockPos pos, EntityType<?> type) {
|
||||
return this.getBlock().properties.isValidSpawn.test(this.asState(), world, pos, type);
|
||||
}
|
||||
@@ -1048,7 +1054,7 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
}
|
||||
|
||||
public PushReaction getPistonPushReaction() {
|
||||
- return this.pushReaction;
|
||||
+ return !this.isDestroyable() ? PushReaction.BLOCK : this.pushReaction; // Paper - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
}
|
||||
|
||||
public boolean isSolidRender() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
index eb409fb5e673d2a343813946cc59cb5da2328eec..83d294f6f48b867d09ea0d339c779011bf4138a5 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
@@ -207,6 +207,13 @@ public class PortalForcer {
|
||||
for (int j = -1; j < 3; ++j) {
|
||||
for (int k = -1; k < 4; ++k) {
|
||||
temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal);
|
||||
+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) {
|
||||
+ if (!this.level.getBlockState(temp).isDestroyable()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
if (k < 0 && !this.level.getBlockState(temp).isSolid()) {
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Wed, 2 Dec 2020 21:03:02 -0800
|
||||
Subject: [PATCH] Add config for mobs immune to default effects
|
||||
|
||||
|
||||
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 e1be143959fbaa1d54af2a1a2c27187d70e6a9e9..244e38db508efa3eebebb6392c4ebb0805367baf 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
|
||||
@@ -602,7 +602,7 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
||||
|
||||
@Override
|
||||
public boolean canBeAffected(MobEffectInstance effect) {
|
||||
- return effect.is(MobEffects.WITHER) ? false : super.canBeAffected(effect);
|
||||
+ return effect.is(MobEffects.WITHER) && this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.wither ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects
|
||||
}
|
||||
|
||||
private class WitherDoNothingGoal extends Goal {
|
||||
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 72e42605c278028480c368762da18f61806d766a..91e521414c3ea5722aac7506b7589fbb399e9636 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Spider.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java
|
||||
@@ -126,7 +126,7 @@ public class Spider extends Monster {
|
||||
|
||||
@Override
|
||||
public boolean canBeAffected(MobEffectInstance effect) {
|
||||
- return effect.is(MobEffects.POISON) ? false : super.canBeAffected(effect);
|
||||
+ return effect.is(MobEffects.POISON) && this.level().paperConfig().entities.mobEffects.spidersImmuneToPoisonEffect ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects
|
||||
}
|
||||
|
||||
public boolean isClimbing() {
|
||||
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 c295b604f438c62d589ab05ea44c85dbefcb258b..37d3acda84a984bf4f1c44b3d27e2102839d3e8e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java
|
||||
@@ -114,6 +114,6 @@ public class WitherSkeleton extends AbstractSkeleton {
|
||||
|
||||
@Override
|
||||
public boolean canBeAffected(MobEffectInstance effect) {
|
||||
- return effect.is(MobEffects.WITHER) ? false : super.canBeAffected(effect);
|
||||
+ return effect.is(MobEffects.WITHER) && this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.witherSkeleton ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects
|
||||
}
|
||||
}
|
45
patches/server/0944-Deep-clone-nbt-tags-in-PDC.patch
Normal file
45
patches/server/0944-Deep-clone-nbt-tags-in-PDC.patch
Normal file
|
@ -0,0 +1,45 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: SoSeDiK <mrsosedik@gmail.com>
|
||||
Date: Thu, 26 May 2022 03:30:05 +0300
|
||||
Subject: [PATCH] Deep clone nbt tags in PDC
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
index 3bcc807005a677884255f1ee36cbf1653797ba55..8d13505c36d732f17293c6a6d65cac20919b8b7a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
@@ -372,7 +372,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
this.maxDamage = meta.maxDamage;
|
||||
this.unhandledTags.copy(meta.unhandledTags.build());
|
||||
this.removedTags.addAll(meta.removedTags);
|
||||
- this.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw());
|
||||
+ this.persistentDataContainer.putAll(meta.persistentDataContainer.getTagsCloned()); // Paper - deep clone NBT tags
|
||||
|
||||
this.customTag = meta.customTag;
|
||||
|
||||
@@ -1966,7 +1966,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
clone.customTag = this.customTag.copy();
|
||||
}
|
||||
clone.removedTags = Sets.newHashSet(this.removedTags);
|
||||
- clone.persistentDataContainer = new CraftPersistentDataContainer(this.persistentDataContainer.getRaw(), CraftMetaItem.DATA_TYPE_REGISTRY);
|
||||
+ clone.persistentDataContainer = new CraftPersistentDataContainer(this.persistentDataContainer.getTagsCloned(), CraftMetaItem.DATA_TYPE_REGISTRY); // Paper - deep clone NBT tags
|
||||
clone.hideFlag = this.hideFlag;
|
||||
clone.hideTooltip = this.hideTooltip;
|
||||
clone.tooltipStyle = this.tooltipStyle;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
|
||||
index 5a4e7e7150b7c137b077e0b393f17ed35b5aec34..f55fdd57ced259ad5a95878840e98ffaa3db2e05 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
|
||||
@@ -207,4 +207,12 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
|
||||
}
|
||||
}
|
||||
// Paper end - byte array serialization
|
||||
+
|
||||
+ // Paper start - deep clone tags
|
||||
+ public Map<String, Tag> getTagsCloned() {
|
||||
+ final Map<String, Tag> tags = new HashMap<>();
|
||||
+ this.customDataTags.forEach((key, tag) -> tags.put(key, tag.copy()));
|
||||
+ return tags;
|
||||
+ }
|
||||
+ // Paper end - deep clone tags
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue