This commit is contained in:
Bjarne Koll
2024-10-24 23:03:27 +02:00
parent c8414e5d1d
commit 6ca02ef090
11 changed files with 53 additions and 53 deletions

View File

@@ -1,484 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bjarne Koll <git@lynxplay.dev>
Date: Thu, 13 Jun 2024 23:45:32 +0200
Subject: [PATCH] Add registry entry and builders
diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
@@ -0,0 +0,0 @@
package io.papermc.paper.registry;
import io.papermc.paper.adventure.PaperAdventure;
+import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
+import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntry;
import io.papermc.paper.registry.tag.TagKey;
import java.util.Collections;
@@ -0,0 +0,0 @@ public final class PaperRegistries {
static {
REGISTRY_ENTRIES = List.of(
// built-ins
- entry(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new),
+ writable(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new, PaperGameEventRegistryEntry.PaperBuilder::new),
entry(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new),
entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new),
entry(Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, PotionEffectType.class, CraftPotionEffectType::new),
@@ -0,0 +0,0 @@ public final class PaperRegistries {
entry(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN, TrimPattern.class, CraftTrimPattern::new).delayed(),
entry(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE, DamageType.class, CraftDamageType::new).delayed(),
entry(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT, Wolf.Variant.class, CraftWolf.CraftVariant::new).delayed(),
- entry(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, Enchantment.class, CraftEnchantment::new).withSerializationUpdater(FieldRename.ENCHANTMENT_RENAME).delayed(),
+ writable(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, Enchantment.class, CraftEnchantment::new, PaperEnchantmentRegistryEntry.PaperBuilder::new).withSerializationUpdater(FieldRename.ENCHANTMENT_RENAME).delayed(),
entry(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG, JukeboxSong.class, CraftJukeboxSong::new).delayed(),
entry(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN, PatternType.class, CraftPatternType::new).delayed(),
diff --git a/src/main/java/io/papermc/paper/registry/data/PaperEnchantmentRegistryEntry.java b/src/main/java/io/papermc/paper/registry/data/PaperEnchantmentRegistryEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/data/PaperEnchantmentRegistryEntry.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.registry.data;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import io.papermc.paper.registry.PaperRegistryBuilder;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.TypedKey;
+import io.papermc.paper.registry.data.util.Checks;
+import io.papermc.paper.registry.data.util.Conversions;
+import io.papermc.paper.registry.set.PaperRegistrySets;
+import io.papermc.paper.registry.set.RegistryKeySet;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.OptionalInt;
+import net.minecraft.core.HolderSet;
+import net.minecraft.core.component.DataComponentMap;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.network.chat.Component;
+import net.minecraft.world.entity.EquipmentSlotGroup;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.enchantment.Enchantment;
+import org.bukkit.craftbukkit.CraftEquipmentSlot;
+import org.bukkit.inventory.ItemType;
+import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.jetbrains.annotations.Range;
+
+import static io.papermc.paper.registry.data.util.Checks.asArgument;
+import static io.papermc.paper.registry.data.util.Checks.asArgumentMin;
+import static io.papermc.paper.registry.data.util.Checks.asConfigured;
+
+@DefaultQualifier(NonNull.class)
+public class PaperEnchantmentRegistryEntry implements EnchantmentRegistryEntry {
+
+ // Top level
+ protected @MonotonicNonNull Component description;
+
+ // Definition
+ protected @MonotonicNonNull HolderSet<Item> supportedItems;
+ protected @Nullable HolderSet<Item> primaryItems;
+ protected OptionalInt weight = OptionalInt.empty();
+ protected OptionalInt maxLevel = OptionalInt.empty();
+ protected Enchantment.@MonotonicNonNull Cost minimumCost;
+ protected Enchantment.@MonotonicNonNull Cost maximumCost;
+ protected OptionalInt anvilCost = OptionalInt.empty();
+ protected @MonotonicNonNull List<EquipmentSlotGroup> activeSlots;
+
+ // Exclusive
+ protected HolderSet<Enchantment> exclusiveWith = HolderSet.empty(); // Paper added default to empty.
+
+ // Effects
+ protected DataComponentMap effects;
+
+ protected final Conversions conversions;
+
+ public PaperEnchantmentRegistryEntry(
+ final Conversions conversions,
+ final TypedKey<org.bukkit.enchantments.Enchantment> ignoredKey,
+ final @Nullable Enchantment internal
+ ) {
+ this.conversions = conversions;
+ if (internal == null) {
+ this.effects = DataComponentMap.EMPTY;
+ return;
+ }
+
+ // top level
+ this.description = internal.description();
+
+ // definition
+ final Enchantment.EnchantmentDefinition definition = internal.definition();
+ this.supportedItems = definition.supportedItems();
+ this.primaryItems = definition.primaryItems().orElse(null);
+ this.weight = OptionalInt.of(definition.weight());
+ this.maxLevel = OptionalInt.of(definition.maxLevel());
+ this.minimumCost = definition.minCost();
+ this.maximumCost = definition.maxCost();
+ this.anvilCost = OptionalInt.of(definition.anvilCost());
+ this.activeSlots = definition.slots();
+
+ // exclusive
+ this.exclusiveWith = internal.exclusiveSet();
+
+ // effects
+ this.effects = internal.effects();
+ }
+
+ @Override
+ public net.kyori.adventure.text.Component description() {
+ return this.conversions.asAdventure(asConfigured(this.description, "description"));
+ }
+
+ @Override
+ public RegistryKeySet<ItemType> supportedItems() {
+ return PaperRegistrySets.convertToApi(RegistryKey.ITEM, asConfigured(this.supportedItems, "supportedItems"));
+ }
+
+ @Override
+ public @Nullable RegistryKeySet<ItemType> primaryItems() {
+ return this.primaryItems == null ? null : PaperRegistrySets.convertToApi(RegistryKey.ITEM, this.primaryItems);
+ }
+
+ @Override
+ public @Range(from = 1, to = 1024) int weight() {
+ return asConfigured(this.weight, "weight");
+ }
+
+ @Override
+ public @Range(from = 1, to = 255) int maxLevel() {
+ return asConfigured(this.maxLevel, "maxLevel");
+ }
+
+ @Override
+ public EnchantmentCost minimumCost() {
+ final Enchantment.@MonotonicNonNull Cost cost = asConfigured(this.minimumCost, "minimumCost");
+ return EnchantmentRegistryEntry.EnchantmentCost.of(cost.base(), cost.perLevelAboveFirst());
+ }
+
+ @Override
+ public EnchantmentCost maximumCost() {
+ final Enchantment.@MonotonicNonNull Cost cost = asConfigured(this.maximumCost, "maximumCost");
+ return EnchantmentRegistryEntry.EnchantmentCost.of(cost.base(), cost.perLevelAboveFirst());
+ }
+
+ @Override
+ public @Range(from = 0, to = Integer.MAX_VALUE) int anvilCost() {
+ return asConfigured(this.anvilCost, "anvilCost");
+ }
+
+ @Override
+ public List<org.bukkit.inventory.EquipmentSlotGroup> activeSlots() {
+ return Collections.unmodifiableList(Lists.transform(asConfigured(this.activeSlots, "activeSlots"), CraftEquipmentSlot::getSlot));
+ }
+
+ @Override
+ public RegistryKeySet<org.bukkit.enchantments.Enchantment> exclusiveWith() {
+ return PaperRegistrySets.convertToApi(RegistryKey.ENCHANTMENT, this.exclusiveWith);
+ }
+
+ public static final class PaperBuilder extends PaperEnchantmentRegistryEntry implements EnchantmentRegistryEntry.Builder,
+ PaperRegistryBuilder<Enchantment, org.bukkit.enchantments.Enchantment> {
+
+ public PaperBuilder(final Conversions conversions, final TypedKey<org.bukkit.enchantments.Enchantment> key, final @Nullable Enchantment internal) {
+ super(conversions, key, internal);
+ }
+
+ @Override
+ public Builder description(final net.kyori.adventure.text.Component description) {
+ this.description = this.conversions.asVanilla(asArgument(description, "description"));
+ return this;
+ }
+
+ @Override
+ public Builder supportedItems(final RegistryKeySet<ItemType> supportedItems) {
+ this.supportedItems = PaperRegistrySets.convertToNms(Registries.ITEM, this.conversions.lookup(), asArgument(supportedItems, "supportedItems"));
+ return this;
+ }
+
+ @Override
+ public Builder primaryItems(final @Nullable RegistryKeySet<ItemType> primaryItems) {
+ this.primaryItems = primaryItems == null ? null : PaperRegistrySets.convertToNms(Registries.ITEM, this.conversions.lookup(), primaryItems);
+ return this;
+ }
+
+ @Override
+ public Builder weight(final @Range(from = 1, to = 1024) int weight) {
+ this.weight = OptionalInt.of(Checks.asArgumentRange(weight, "weight", 1, 1024));
+ return this;
+ }
+
+ @Override
+ public Builder maxLevel(final @Range(from = 1, to = 255) int maxLevel) {
+ this.maxLevel = OptionalInt.of(Checks.asArgumentRange(maxLevel, "maxLevel", 1, 255));
+ return this;
+ }
+
+ @Override
+ public Builder minimumCost(final EnchantmentCost minimumCost) {
+ final EnchantmentCost validCost = asArgument(minimumCost, "minimumCost");
+ this.minimumCost = Enchantment.dynamicCost(validCost.baseCost(), validCost.additionalPerLevelCost());
+ return this;
+ }
+
+ @Override
+ public Builder maximumCost(final EnchantmentCost maximumCost) {
+ final EnchantmentCost validCost = asArgument(maximumCost, "maximumCost");
+ this.maximumCost = Enchantment.dynamicCost(validCost.baseCost(), validCost.additionalPerLevelCost());
+ return this;
+ }
+
+ @Override
+ public Builder anvilCost(final @Range(from = 0, to = Integer.MAX_VALUE) int anvilCost) {
+ Preconditions.checkArgument(anvilCost >= 0, "anvilCost must be non-negative");
+ this.anvilCost = OptionalInt.of(asArgumentMin(anvilCost, "anvilCost", 0));
+ return this;
+ }
+
+ @Override
+ public Builder activeSlots(final Iterable<org.bukkit.inventory.EquipmentSlotGroup> activeSlots) {
+ this.activeSlots = Lists.newArrayList(Iterables.transform(asArgument(activeSlots, "activeSlots"), CraftEquipmentSlot::getNMSGroup));
+ return this;
+ }
+
+ @Override
+ public Builder exclusiveWith(final RegistryKeySet<org.bukkit.enchantments.Enchantment> exclusiveWith) {
+ this.exclusiveWith = PaperRegistrySets.convertToNms(Registries.ENCHANTMENT, this.conversions.lookup(), asArgument(exclusiveWith, "exclusiveWith"));
+ return this;
+ }
+
+ @Override
+ public Enchantment build() {
+ final Enchantment.EnchantmentDefinition def = new Enchantment.EnchantmentDefinition(
+ asConfigured(this.supportedItems, "supportedItems"),
+ Optional.ofNullable(this.primaryItems),
+ this.weight(),
+ this.maxLevel(),
+ asConfigured(this.minimumCost, "minimumCost"),
+ asConfigured(this.maximumCost, "maximumCost"),
+ this.anvilCost(),
+ Collections.unmodifiableList(asConfigured(this.activeSlots, "activeSlots"))
+ );
+ return new Enchantment(
+ asConfigured(this.description, "description"),
+ def,
+ this.exclusiveWith,
+ this.effects
+ );
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/registry/data/PaperGameEventRegistryEntry.java b/src/main/java/io/papermc/paper/registry/data/PaperGameEventRegistryEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/data/PaperGameEventRegistryEntry.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.registry.data;
+
+import io.papermc.paper.registry.PaperRegistryBuilder;
+import io.papermc.paper.registry.data.util.Conversions;
+import java.util.OptionalInt;
+import net.minecraft.world.level.gameevent.GameEvent;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.jetbrains.annotations.Range;
+
+import static io.papermc.paper.registry.data.util.Checks.asArgumentMin;
+import static io.papermc.paper.registry.data.util.Checks.asConfigured;
+
+@DefaultQualifier(NonNull.class)
+public class PaperGameEventRegistryEntry implements GameEventRegistryEntry {
+
+ protected OptionalInt range = OptionalInt.empty();
+
+ public PaperGameEventRegistryEntry(
+ final Conversions ignoredConversions,
+ final io.papermc.paper.registry.TypedKey<org.bukkit.GameEvent> ignoredKey,
+ final @Nullable GameEvent nms
+ ) {
+ if (nms == null) return;
+
+ this.range = OptionalInt.of(nms.notificationRadius());
+ }
+
+ @Override
+ public @Range(from = 0, to = Integer.MAX_VALUE) int range() {
+ return asConfigured(this.range, "range");
+ }
+
+ public static final class PaperBuilder extends PaperGameEventRegistryEntry implements GameEventRegistryEntry.Builder,
+ PaperRegistryBuilder<GameEvent, org.bukkit.GameEvent> {
+
+ public PaperBuilder(
+ final Conversions conversions,
+ final io.papermc.paper.registry.TypedKey<org.bukkit.GameEvent> key,
+ final @Nullable GameEvent nms
+ ) {
+ super(conversions, key, nms);
+ }
+
+ @Override
+ public GameEventRegistryEntry.Builder range(final @Range(from = 0, to = Integer.MAX_VALUE) int range) {
+ this.range = OptionalInt.of(asArgumentMin(range, "range", 0));
+ return this;
+ }
+
+ @Override
+ public GameEvent build() {
+ return new GameEvent(this.range());
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/registry/data/util/Checks.java b/src/main/java/io/papermc/paper/registry/data/util/Checks.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/data/util/Checks.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.registry.data.util;
+
+import java.util.OptionalInt;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public final class Checks {
+
+ public static <T> T asConfigured(final @Nullable T value, final String field) {
+ if (value == null) {
+ throw new IllegalStateException(field + " has not been configured");
+ }
+ return value;
+ }
+
+ public static int asConfigured(final OptionalInt value, final String field) {
+ if (value.isEmpty()) {
+ throw new IllegalStateException(field + " has not been configured");
+ }
+ return value.getAsInt();
+ }
+
+ public static <T> T asArgument(final @Nullable T value, final String field) {
+ if (value == null) {
+ throw new IllegalArgumentException("argument " + field + " cannot be null");
+ }
+ return value;
+ }
+
+ public static int asArgumentRange(final int value, final String field, final int min, final int max) {
+ if (value < min || value > max) {
+ throw new IllegalArgumentException("argument " + field + " must be [" + min + ", " + max + "]");
+ }
+ return value;
+ }
+
+ public static int asArgumentMin(final int value, final String field, final int min) {
+ if (value < min) {
+ throw new IllegalArgumentException("argument " + field + " must be [" + min + ",+inf)");
+ }
+ return value;
+ }
+
+ private Checks() {
+ }
+}
diff --git a/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java b/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java
+++ b/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java
@@ -0,0 +0,0 @@ public record GameEvent(int notificationRadius) {
}
private static Holder.Reference<GameEvent> register(String id, int range) {
- return Registry.registerForHolder(BuiltInRegistries.GAME_EVENT, ResourceLocation.withDefaultNamespace(id), new GameEvent(range));
+ return io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerForHolderWithListeners(BuiltInRegistries.GAME_EVENT, ResourceLocation.withDefaultNamespace(id), new GameEvent(range)); // Paper - run with listeners
}
public static record Context(@Nullable Entity sourceEntity, @Nullable BlockState affectedState) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java b/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java
@@ -0,0 +0,0 @@ public class CraftGameEvent extends GameEvent implements Handleable<net.minecraf
}
private final NamespacedKey key;
+ private final net.minecraft.resources.ResourceKey<net.minecraft.world.level.gameevent.GameEvent> handleKey; // Paper
private final net.minecraft.world.level.gameevent.GameEvent handle;
public CraftGameEvent(NamespacedKey key, net.minecraft.world.level.gameevent.GameEvent handle) {
this.key = key;
+ this.handleKey = net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.GAME_EVENT, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(key)); // Paper
this.handle = handle;
}
@@ -0,0 +0,0 @@ public class CraftGameEvent extends GameEvent implements Handleable<net.minecraf
return this.handle;
}
+ // Paper start
+ @Override
+ public int getRange() {
+ return this.handle.notificationRadius();
+ }
+
+ @Override
+ public int getVibrationLevel() {
+ return net.minecraft.world.level.gameevent.vibrations.VibrationSystem.getGameEventFrequency(this.handleKey);
+ }
+ // Paper end
+
@NotNull
@Override
public NamespacedKey getKey() {
diff --git a/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java b/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java
+++ b/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java
@@ -0,0 +0,0 @@
package io.papermc.paper.registry;
+import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
+import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
import io.papermc.paper.registry.data.util.Conversions;
import java.util.List;
import java.util.Map;
import net.minecraft.core.Registry;
+import net.minecraft.core.registries.Registries;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
+import net.minecraft.world.item.enchantment.Enchantment;
+import net.minecraft.world.level.gameevent.GameEvent;
import org.bukkit.support.RegistryHelper;
import org.bukkit.support.environment.AllFeatures;
import org.junit.jupiter.api.Disabled;
@@ -0,0 +0,0 @@ import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
@AllFeatures
class RegistryBuilderTest {
static List<Arguments> registries() {
return List.of(
+ arguments(Registries.ENCHANTMENT, (PaperRegistryBuilder.Filler<Enchantment, org.bukkit.enchantments.Enchantment, PaperEnchantmentRegistryEntry.PaperBuilder>) PaperEnchantmentRegistryEntry.PaperBuilder::new),
+ arguments(Registries.GAME_EVENT, (PaperRegistryBuilder.Filler<GameEvent, org.bukkit.GameEvent, PaperGameEventRegistryEntry.PaperBuilder>) PaperGameEventRegistryEntry.PaperBuilder::new)
);
}
- @Disabled
@ParameterizedTest
@MethodSource("registries")
<M, T> void testEquality(final ResourceKey<? extends Registry<M>> resourceKey, final PaperRegistryBuilder.Filler<M, T, ?> filler) {

View File

@@ -1,68 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 2 Aug 2021 10:10:40 +0200
Subject: [PATCH] Check distance in entity interactions
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -0,0 +0,0 @@ public class Util {
.filter(fileSystemProvider -> fileSystemProvider.getScheme().equalsIgnoreCase("jar"))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No jar file system provider found"));
+ public static final double COLLISION_EPSILON = 1.0E-7; // Paper - Check distance in entity interactions
private static Consumer<String> thePauser = message -> {
};
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
if (!source.is(DamageTypeTags.IS_PROJECTILE)) {
Entity entity = source.getDirectEntity();
- if (entity instanceof LivingEntity) {
+ if (entity instanceof LivingEntity && entity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Check distance in entity interactions
LivingEntity entityliving = (LivingEntity) entity;
this.blockUsingShield(entityliving);
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
d0 = source.getSourcePosition().x() - this.getX();
d1 = source.getSourcePosition().z() - this.getZ();
}
+ // Paper start - Check distance in entity interactions; see for loop in knockback method
+ if (Math.abs(d0) > 200) {
+ d0 = Math.random() - Math.random();
+ }
+ if (Math.abs(d1) > 200) {
+ d1 = Math.random() - Math.random();
+ }
+ // Paper end - Check distance in entity interactions
this.knockback(0.4000000059604645D, d0, d1, entity1, entity1 == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events
if (!flag) {
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING));
Entity entity = damagesource.getDirectEntity();
- if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity) { // Paper - Fix shield disable inconsistency
+ if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity && entity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions
this.blockUsingShield((LivingEntity) entity);
}
}
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
@@ -0,0 +0,0 @@ public class Boat extends VehicleEntity implements Leashable, VariantHolder<Boat
double d2 = (double) (this.getWaterLevelAbove() - this.getBbHeight()) + 0.101D;
if (this.level().noCollision(this, this.getBoundingBox().move(0.0D, d2 - this.getY(), 0.0D))) {
- this.setPos(this.getX(), d2, this.getZ());
+ this.move(MoverType.SELF, new Vec3(0.0D, d2 - this.getY(), 0.0D)); // Paper - Check distance in entity interactions // TODO Still needed?
this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
this.lastYd = 0.0D;
}

View File

@@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sat, 15 Jun 2024 22:01:39 -0400
Subject: [PATCH] Configurable Sand Duping
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -0,0 +0,0 @@ public class FallingBlockEntity extends Entity {
boolean flag = (resourcekey1 == Level.END || resourcekey == Level.END) && resourcekey1 != resourcekey;
Entity entity = super.changeDimension(teleportTarget);
- this.forceTickAfterTeleportToDuplicate = entity != null && flag;
+ this.forceTickAfterTeleportToDuplicate = entity != null && flag && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation; // Paper
return entity;
}
}

View File

@@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 17 Jun 2024 17:41:09 -0700
Subject: [PATCH] Fix NPE for Jukebox#setRecord
Fallback to the global registry if no level exists
diff --git a/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
@@ -0,0 +0,0 @@ public class JukeboxBlockEntity extends BlockEntity implements Clearable, Contai
public void setSongItemWithoutPlaying(ItemStack itemstack, long ticksSinceSongStarted) { // CraftBukkit - add argument
this.item = itemstack;
this.jukeboxSongPlayer.song = null; // CraftBukkit - reset
- JukeboxSong.fromStack(this.level.registryAccess(), itemstack).ifPresent((holder) -> {
+ JukeboxSong.fromStack(this.level != null ? this.level.registryAccess() : org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry(), itemstack).ifPresent((holder) -> { // Paper - fallback to other RegistyrAccess if no level
this.jukeboxSongPlayer.setSongWithoutPlaying(holder, ticksSinceSongStarted); // CraftBukkit - add argument
});
// CraftBukkit start - add null check for level

View File

@@ -1,64 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 6 May 2020 05:00:57 -0400
Subject: [PATCH] Handle Oversized block entities in chunks
Splits out Extra Packets if too many TE's are encountered to prevent
creating too large of a packet to sed.
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
@@ -0,0 +0,0 @@ public class ClientboundLevelChunkPacketData {
private final CompoundTag heightmaps;
private final byte[] buffer;
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
+ // Paper start - Handle oversized block entities in chunks
+ private final java.util.List<net.minecraft.network.protocol.Packet<?>> extraPackets = new java.util.ArrayList<>();
+ private static final int TE_LIMIT = Integer.getInteger("Paper.excessiveTELimit", 750);
+
+ public List<net.minecraft.network.protocol.Packet<?>> getExtraPackets() {
+ return this.extraPackets;
+ }
+ // Paper end - Handle oversized block entities in chunks
// Paper start - Anti-Xray - Add chunk packet info
@Deprecated @io.papermc.paper.annotation.DoNotUse public ClientboundLevelChunkPacketData(LevelChunk chunk) { this(chunk, null); }
@@ -0,0 +0,0 @@ public class ClientboundLevelChunkPacketData {
extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), chunk, chunkPacketInfo);
// Paper end
this.blockEntitiesData = Lists.newArrayList();
+ int totalTileEntities = 0; // Paper - Handle oversized block entities in chunks
for (Entry<BlockPos, BlockEntity> entry2 : chunk.getBlockEntities().entrySet()) {
+ // Paper start - Handle oversized block entities in chunks
+ if (++totalTileEntities > TE_LIMIT) {
+ var packet = entry2.getValue().getUpdatePacket();
+ if (packet != null) {
+ this.extraPackets.add(packet);
+ continue;
+ }
+ }
+ // Paper end - Handle oversized block entities in chunks
this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(entry2.getValue()));
}
}
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
@@ -0,0 +0,0 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
public ClientboundLightUpdatePacketData getLightData() {
return this.lightData;
}
+
+ // Paper start - Handle oversized block entities in chunks
+ @Override
+ public java.util.List<Packet<?>> getExtraPackets() {
+ return this.chunkData.getExtraPackets();
+ }
+ // Paper end - Handle oversized block entities in chunks
}

View File

@@ -1,271 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 12 Jun 2024 10:29:40 -0700
Subject: [PATCH] Make a PDC view accessible directly from ItemStack
diff --git a/src/main/java/io/papermc/paper/persistence/PaperPersistentDataContainerView.java b/src/main/java/io/papermc/paper/persistence/PaperPersistentDataContainerView.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/persistence/PaperPersistentDataContainerView.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.persistence;
+
+import com.google.common.base.Preconditions;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.NbtIo;
+import net.minecraft.nbt.Tag;
+import org.bukkit.NamespacedKey;
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataAdapterContext;
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
+import org.bukkit.persistence.PersistentDataAdapterContext;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.bukkit.persistence.PersistentDataType;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+@NullMarked
+public abstract class PaperPersistentDataContainerView implements PersistentDataContainerView {
+
+ protected final CraftPersistentDataTypeRegistry registry;
+ protected final CraftPersistentDataAdapterContext adapterContext;
+
+ public PaperPersistentDataContainerView(final CraftPersistentDataTypeRegistry registry) {
+ this.registry = registry;
+ this.adapterContext = new CraftPersistentDataAdapterContext(this.registry);
+ }
+
+ public abstract @Nullable Tag getTag(final String key);
+
+ public abstract CompoundTag toTagCompound();
+
+ @Override
+ public <P, C> boolean has(final NamespacedKey key, final PersistentDataType<P, C> type) {
+ Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null");
+ Preconditions.checkArgument(type != null, "The provided type cannot be null");
+
+ final Tag value = this.getTag(key.toString());
+ if (value == null) {
+ return false;
+ }
+
+ return this.registry.isInstanceOf(type, value);
+ }
+
+ @Override
+ public boolean has(final NamespacedKey key) {
+ Preconditions.checkArgument(key != null, "The provided key for the custom value was null"); // Paper
+ return this.getTag(key.toString()) != null;
+ }
+
+ @Override
+ public <P, C> @Nullable C get(final NamespacedKey key, final PersistentDataType<P, C> type) {
+ Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null");
+ Preconditions.checkArgument(type != null, "The provided type cannot be null");
+
+ final Tag value = this.getTag(key.toString());
+ if (value == null) {
+ return null;
+ }
+
+ return type.fromPrimitive(this.registry.extract(type, value), this.adapterContext);
+ }
+
+ @Override
+ public <P, C> C getOrDefault(final NamespacedKey key, final PersistentDataType<P, C> type, final C defaultValue) {
+ final C c = this.get(key, type);
+ return c != null ? c : defaultValue;
+ }
+
+ @Override
+ public Set<NamespacedKey> getKeys() {
+ final Set<String> names = this.toTagCompound().getAllKeys();
+ final Set<NamespacedKey> keys = new HashSet<>(names.size());
+ names.forEach(key -> {
+ final String[] keyPart = key.split(":", 2);
+ if (keyPart.length == 2) {
+ keys.add(new NamespacedKey(keyPart[0], keyPart[1]));
+ }
+ });
+ return Collections.unmodifiableSet(keys);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.toTagCompound().isEmpty();
+ }
+
+ @Override
+ public void copyTo(final PersistentDataContainer other, final boolean replace) {
+ Preconditions.checkArgument(other != null, "The target container cannot be null");
+ final CraftPersistentDataContainer target = (CraftPersistentDataContainer) other;
+ final CompoundTag tag = this.toTagCompound();
+ for (final String key : tag.getAllKeys()) {
+ if (replace || !target.getRaw().containsKey(key)) {
+ target.getRaw().put(key, tag.get(key).copy());
+ }
+ }
+ }
+
+ @Override
+ public PersistentDataAdapterContext getAdapterContext() {
+ return this.adapterContext;
+ }
+
+ @Override
+ public byte[] serializeToBytes() throws IOException {
+ final CompoundTag root = this.toTagCompound();
+ final ByteArrayOutputStream byteArrayOutput = new ByteArrayOutputStream();
+ try (final DataOutputStream dataOutput = new DataOutputStream(byteArrayOutput)) {
+ NbtIo.write(root, dataOutput);
+ return byteArrayOutput.toByteArray();
+ }
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -0,0 +0,0 @@ public final class CraftItemStack extends ItemStack {
return mirrored;
}
// Paper end
+
+ // Paper start - pdc
+ private net.minecraft.nbt.CompoundTag getPdcTag() {
+ if (this.handle == null) {
+ return new net.minecraft.nbt.CompoundTag();
+ }
+ final net.minecraft.world.item.component.CustomData customData = this.handle.getOrDefault(DataComponents.CUSTOM_DATA, net.minecraft.world.item.component.CustomData.EMPTY);
+ // getUnsafe is OK here because we are only ever *reading* the data so immutability is preserved
+ //noinspection deprecation
+ return customData.getUnsafe().getCompound("PublicBukkitValues");
+ }
+
+ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
+ private final io.papermc.paper.persistence.PaperPersistentDataContainerView pdcView = new io.papermc.paper.persistence.PaperPersistentDataContainerView(REGISTRY) {
+
+ @Override
+ public net.minecraft.nbt.CompoundTag toTagCompound() {
+ return CraftItemStack.this.getPdcTag();
+ }
+
+ @Override
+ public net.minecraft.nbt.Tag getTag(final String key) {
+ return CraftItemStack.this.getPdcTag().get(key);
+ }
+ };
+ @Override
+ public io.papermc.paper.persistence.PersistentDataContainerView getPersistentDataContainer() {
+ return this.pdcView;
+ }
+ // Paper end - pdc
}
diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
@@ -0,0 +0,0 @@ import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
-public class CraftPersistentDataContainer implements PersistentDataContainer {
+public class CraftPersistentDataContainer extends io.papermc.paper.persistence.PaperPersistentDataContainerView implements PersistentDataContainer { // Paper - split up view and mutable
private final Map<String, Tag> customDataTags = new HashMap<>();
- private final CraftPersistentDataTypeRegistry registry;
- private final CraftPersistentDataAdapterContext adapterContext;
+ // Paper - move to PersistentDataContainerView
public CraftPersistentDataContainer(Map<String, Tag> customTags, CraftPersistentDataTypeRegistry registry) {
this(registry);
@@ -0,0 +0,0 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
}
public CraftPersistentDataContainer(CraftPersistentDataTypeRegistry registry) {
- this.registry = registry;
- this.adapterContext = new CraftPersistentDataAdapterContext(this.registry);
+ super(registry); // Paper - move to PersistentDataContainerView
}
+ // Paper start
+ @Override
+ public Tag getTag(final String key) {
+ return this.customDataTags.get(key);
+ }
+ // Paper end
@Override
public <T, Z> void set(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type, @NotNull Z value) {
@@ -0,0 +0,0 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
this.customDataTags.put(key.toString(), this.registry.wrap(type, type.toPrimitive(value, this.adapterContext)));
}
- @Override
- public <T, Z> boolean has(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type) {
- Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null");
- Preconditions.checkArgument(type != null, "The provided type cannot be null");
-
- Tag value = this.customDataTags.get(key.toString());
- if (value == null) {
- return false;
- }
-
- return this.registry.isInstanceOf(type, value);
- }
-
- @Override
- public boolean has(NamespacedKey key) {
- Preconditions.checkArgument(key != null, "The provided key for the custom value was null"); // Paper
- return this.customDataTags.get(key.toString()) != null;
- }
-
- @Override
- public <T, Z> Z get(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type) {
- Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null");
- Preconditions.checkArgument(type != null, "The provided type cannot be null");
-
- Tag value = this.customDataTags.get(key.toString());
- if (value == null) {
- return null;
- }
-
- return type.fromPrimitive(this.registry.extract(type, value), this.adapterContext);
- }
-
- @NotNull
- @Override
- public <T, Z> Z getOrDefault(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type, @NotNull Z defaultValue) {
- Z z = this.get(key, type);
- return z != null ? z : defaultValue;
- }
+ // Paper - move to PersistentDataContainerView
@NotNull
@Override
@@ -0,0 +0,0 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
// Paper end
// Paper start - byte array serialization
- @Override
- public byte[] serializeToBytes() throws java.io.IOException {
- final net.minecraft.nbt.CompoundTag root = this.toTagCompound();
- final java.io.ByteArrayOutputStream byteArrayOutput = new java.io.ByteArrayOutputStream();
- try (final java.io.DataOutputStream dataOutput = new java.io.DataOutputStream(byteArrayOutput)) {
- net.minecraft.nbt.NbtIo.write(root, dataOutput);
- return byteArrayOutput.toByteArray();
- }
- }
-
+ // Paper - move to PersistentDataContainerView
@Override
public void readFromBytes(final byte[] bytes, final boolean clear) throws java.io.IOException {
if (clear) {

View File

@@ -1,135 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Mon, 1 Jul 2024 11:58:49 -0700
Subject: [PATCH] Prioritize Minecraft commands in function parsing and command
blocks
diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java
+++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
@@ -0,0 +0,0 @@ public class CommandDispatcher<S> {
List<ParseResults<S>> potentials = null;
final int cursor = originalReader.getCursor();
- for (final CommandNode<S> child : node.getRelevantNodes(originalReader)) {
+ for (final CommandNode<S> child : node.getRelevantNodes(originalReader, source)) { // Paper - prioritize mc commands in function parsing
if (!child.canUse(source)) {
continue;
}
diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
@@ -0,0 +0,0 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
protected abstract String getSortedKey();
public Collection<? extends CommandNode<S>> getRelevantNodes(final StringReader input) {
+ // Paper start - prioritize mc commands in function parsing
+ return this.getRelevantNodes(input, null);
+ }
+ @org.jetbrains.annotations.ApiStatus.Internal
+ public Collection<? extends CommandNode<S>> getRelevantNodes(final StringReader input, final Object source) {
+ // Paper end - prioritize mc commands in function parsing
if (this.literals.size() > 0) {
final int cursor = input.getCursor();
while (input.canRead() && input.peek() != ' ') {
@@ -0,0 +0,0 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
}
final String text = input.getString().substring(cursor, input.getCursor());
input.setCursor(cursor);
- final LiteralCommandNode<S> literal = this.literals.get(text);
+ // Paper start - prioritize mc commands in function parsing
+ LiteralCommandNode<S> literal = null;
+ if (source instanceof CommandSourceStack css && css.source == net.minecraft.commands.CommandSource.NULL) {
+ if (!text.contains(":")) {
+ literal = this.literals.get("minecraft:" + text);
+ }
+ } else if (source instanceof CommandSourceStack css && css.source instanceof net.minecraft.world.level.BaseCommandBlock) {
+ if (css.getServer().server.getCommandBlockOverride(text) && !text.contains(":")) {
+ literal = this.literals.get("minecraft:" + text);
+ }
+ }
+ if (literal == null) {
+ literal = this.literals.get(text);
+ }
+ // Paper end - prioritize mc commands in function parsing
if (literal != null) {
return Collections.singleton(literal);
} else {
diff --git a/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java b/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java
+++ b/src/main/java/com/mojang/brigadier/tree/LiteralCommandNode.java
@@ -0,0 +0,0 @@ import java.util.function.Predicate;
public class LiteralCommandNode<S> extends CommandNode<S> {
private final String literal;
private final String literalLowerCase;
+ private final String nonPrefixed; // Paper - prioritize mc commands in function parsing
public LiteralCommandNode(final String literal, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks) {
super(command, requirement, redirect, modifier, forks);
this.literal = literal;
this.literalLowerCase = literal.toLowerCase(Locale.ROOT);
+ // Paper start - prioritize mc commands in function parsing
+ if (literal.startsWith("minecraft:")) {
+ this.nonPrefixed = literal.substring("minecraft:".length());
+ } else {
+ this.nonPrefixed = null;
+ }
+ // Paper end - prioritize mc commands in function parsing
}
public String getLiteral() {
@@ -0,0 +0,0 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
@Override
public void parse(final StringReader reader, final CommandContextBuilder<S> contextBuilder) throws CommandSyntaxException {
final int start = reader.getCursor();
- final int end = parse(reader);
+ // Paper start - prioritize mc commands in function parsing
+ int end = parse(reader, false);
+ if (end == -1 && this.nonPrefixed != null) {
+ end = parse(reader, true);
+ }
+ // Paper end - prioritize mc commands in function parsing
if (end > -1) {
contextBuilder.withNode(this, StringRange.between(start, end));
return;
@@ -0,0 +0,0 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.literalIncorrect().createWithContext(reader, literal);
}
- private int parse(final StringReader reader) {
+ // Paper start - prioritize mc commands in function parsing
+ private int parse(final StringReader reader, final boolean secondPass) {
+ String literal = secondPass ? this.nonPrefixed : this.literal;
+ // Paper end - prioritize mc commands in function parsing
final int start = reader.getCursor();
if (reader.canRead(literal.length())) {
final int end = start + literal.length();
@@ -0,0 +0,0 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
@Override
public boolean isValidInput(final String input) {
- return parse(new StringReader(input)) > -1;
+ return parse(new StringReader(input), false) > -1; // Paper - prioritize mc commands in function parsing
}
@Override
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -0,0 +0,0 @@ public class Commands {
// Paper - Fix permission levels for command blocks
- // Handle vanilla commands;
- if (sender.getLevel().getCraftServer().getCommandBlockOverride(args[0])) {
- args[0] = "minecraft:" + args[0];
- }
+ // Handle vanilla commands; // Paper - handled in CommandNode/CommandDispatcher
String newCommand = joiner.join(args);
this.performPrefixedCommand(sender, newCommand, newCommand);

View File

@@ -1,273 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Wed, 7 Dec 2022 17:25:19 -0500
Subject: [PATCH] Properly resend entities
This resolves some issues which caused entities to not be resent correctly.
Entities that are interacted with need to be resent to the client, so we resend all the entity
data to the player whilst making sure not to clear dirty entries from the tracker. This makes
sure that values will be correctly updated to other players.
This also adds utilities to aid in further preventing entity desyncs.
This also also fixes the bug causing cancelling PlayerInteractEvent to cause items to continue
to be used despite being cancelled on the server.
For example, items being consumed but never finishing, shields being put up, etc.
The underlying issue of this is that the client modifies their synced data values,
and so we have to (forcibly) resend them in order for the client to reset their using item state.
See: https://github.com/PaperMC/Paper/pull/1896
== AT ==
public net.minecraft.server.level.ChunkMap$TrackedEntity serverEntity
diff --git a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
+++ b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
@@ -0,0 +0,0 @@ public class SynchedEntityData {
}
}
- private <T> SynchedEntityData.DataItem<T> getItem(EntityDataAccessor<T> key) {
+ public <T> SynchedEntityData.DataItem<T> getItem(EntityDataAccessor<T> key) { // Paper - public
return (SynchedEntityData.DataItem<T>) this.itemsById[key.id()]; // CraftBukkit - decompile error
}
@@ -0,0 +0,0 @@ public class SynchedEntityData {
}
}
+ // Paper start
+ // We need to pack all as we cannot rely on "non default values" or "dirty" ones.
+ // Because these values can possibly be desynced on the client.
+ @Nullable
+ public List<SynchedEntityData.DataValue<?>> packAll() {
+ final List<SynchedEntityData.DataValue<?>> list = new ArrayList<>();
+ for (final DataItem<?> dataItem : this.itemsById) {
+ list.add(dataItem.value());
+ }
+
+ return list;
+ }
+ // Paper end
+
public static class DataItem<T> {
final EntityDataAccessor<T> accessor;
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -0,0 +0,0 @@ public class ServerPlayerGameMode {
}
// Paper end - extend Player Interact cancellation
player.getBukkitEntity().updateInventory(); // SPIGOT-2867
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
return (event.useItemInHand() != Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
} else if (this.gameModeForPlayer == GameType.SPECTATOR) {
MenuProvider itileinventory = iblockdata.getMenuProvider(world, blockposition);
@@ -0,0 +0,0 @@ public class ServerPlayerGameMode {
return enuminteractionresult;
} else {
+ // Paper start - Properly cancel usable items; Cancel only if cancelled + if the interact result is different from default response
+ if (this.interactResult && this.interactResult != cancelledItem) {
+ this.player.resyncUsingItem(this.player);
+ }
+ // Paper end - Properly cancel usable items
return InteractionResult.PASS;
}
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
if (cancelled) {
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524
return;
}
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
// Entity in bucket - SPIGOT-4048 and SPIGOT-6859a
if ((entity instanceof Bucketable && entity instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) {
- entity.getBukkitEntity().update(ServerGamePacketListenerImpl.this.player);
+ entity.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it
ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote();
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -0,0 +0,0 @@ public abstract class PlayerList {
((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now
// CraftBukkit end
- player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
+ //player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn // Paper - THIS IS NOT NEEDED ANYMORE
this.sendLevelInfo(player, worldserver1);
@@ -0,0 +0,0 @@ public abstract class PlayerList {
}
public void sendActiveEffects(LivingEntity entity, ServerGamePacketListenerImpl networkHandler) {
+ // Paper start - collect packets
+ this.sendActiveEffects(entity, networkHandler::send);
+ }
+ public void sendActiveEffects(LivingEntity entity, java.util.function.Consumer<Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> packetConsumer) {
+ // Paper end - collect packets
Iterator iterator = entity.getActiveEffects().iterator();
while (iterator.hasNext()) {
MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
- networkHandler.send(new ClientboundUpdateMobEffectPacket(entity.getId(), mobeffect, false));
+ packetConsumer.accept(new ClientboundUpdateMobEffectPacket(entity.getId(), mobeffect, false)); // Paper - collect packets
}
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
// CraftBukkit start
public void refreshEntityData(ServerPlayer to) {
- List<SynchedEntityData.DataValue<?>> list = this.getEntityData().getNonDefaultValues();
+ List<SynchedEntityData.DataValue<?>> list = this.entityData.packAll(); // Paper - Update EVERYTHING not just not default
- if (list != null) {
+ if (list != null && to.getBukkitEntity().canSee(this.getBukkitEntity())) { // Paper
to.connection.send(new ClientboundSetEntityDataPacket(this.getId(), list));
}
}
// CraftBukkit end
+ // Paper start
+ // This method should only be used if the data of an entity could have become desynced
+ // due to interactions on the client.
+ public void resendPossiblyDesyncedEntityData(net.minecraft.server.level.ServerPlayer player) {
+ if (player.getBukkitEntity().canSee(this.getBukkitEntity())) {
+ ServerLevel world = (net.minecraft.server.level.ServerLevel)this.level();
+ net.minecraft.server.level.ChunkMap.TrackedEntity tracker = world == null ? null : world.getChunkSource().chunkMap.entityMap.get(this.getId());
+ if (tracker == null) {
+ return;
+ }
+ final net.minecraft.server.level.ServerEntity serverEntity = tracker.serverEntity;
+ final List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> list = new java.util.ArrayList<>();
+ serverEntity.sendPairingData(player, list::add);
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(list));
+ }
+ }
+
+ // This method allows you to specifically resend certain data accessor keys to the client
+ public void resendPossiblyDesyncedDataValues(List<EntityDataAccessor<?>> keys, ServerPlayer to) {
+ if (!to.getBukkitEntity().canSee(this.getBukkitEntity())) {
+ return;
+ }
+
+ final List<SynchedEntityData.DataValue<?>> values = new java.util.ArrayList<>(keys.size());
+ for (final EntityDataAccessor<?> key : keys) {
+ final SynchedEntityData.DataItem<?> synchedValue = this.entityData.getItem(key);
+ values.add(synchedValue.value());
+ }
+
+ to.connection.send(new ClientboundSetEntityDataPacket(this.id, values));
+ }
+ // Paper end
public boolean equals(Object object) {
return object instanceof Entity ? ((Entity) object).id == this.id : false;
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
}
+ // Paper start - Properly cancel usable items
+ public void resyncUsingItem(ServerPlayer serverPlayer) {
+ this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_LIVING_ENTITY_FLAGS), serverPlayer);
+ }
+ // Paper end - Properly cancel usable items
private void updatingUsingItem() {
if (this.isUsingItem()) {
if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
@@ -0,0 +0,0 @@ public interface Bucketable {
itemstack1 = CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket());
if (playerBucketFishEvent.isCancelled()) {
((ServerPlayer) player).containerMenu.sendAllDataToRemote(); // We need to update inventory to resync client's bucket
- entity.getBukkitEntity().update((ServerPlayer) player); // We need to play out these packets as the client assumes the fish is gone
- entity.refreshEntityData((ServerPlayer) player); // Need to send data such as the display name to client
+ entity.resendPossiblyDesyncedEntityData((ServerPlayer) player); // Paper
return Optional.of(InteractionResult.FAIL);
}
entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F);
diff --git a/src/main/java/net/minecraft/world/item/SuspiciousStewItem.java b/src/main/java/net/minecraft/world/item/SuspiciousStewItem.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/item/SuspiciousStewItem.java
+++ b/src/main/java/net/minecraft/world/item/SuspiciousStewItem.java
@@ -0,0 +0,0 @@ public class SuspiciousStewItem extends Item {
public void cancelUsingItem(net.minecraft.server.level.ServerPlayer entityplayer, ItemStack itemstack) {
SuspiciousStewEffects suspicioussteweffects = (SuspiciousStewEffects) itemstack.getOrDefault(DataComponents.SUSPICIOUS_STEW_EFFECTS, SuspiciousStewEffects.EMPTY);
+ final List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> packets = new java.util.ArrayList<>(); // Paper - bundlize packets
for (SuspiciousStewEffects.Entry suspicioussteweffects_a : suspicioussteweffects.effects()) {
- entityplayer.connection.send(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), suspicioussteweffects_a.effect()));
+ packets.add(new net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket(entityplayer.getId(), suspicioussteweffects_a.effect())); // Paper - bundlize packets
}
- entityplayer.server.getPlayerList().sendActivePlayerEffects(entityplayer);
+ // Paper start - bundlize packets
+ entityplayer.server.getPlayerList().sendActiveEffects(entityplayer, packets::add);
+ entityplayer.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(packets));
+ // Paper end - bundlize packets
}
// CraftBukkit end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -0,0 +0,0 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return;
}
- entityTracker.broadcast(this.getHandle().getAddEntityPacket(entityTracker.serverEntity));
+ // Paper start - resend possibly desynced entity instead of add entity packet
+ for (final ServerPlayerConnection connection : entityTracker.seenBy) {
+ this.getHandle().resendPossiblyDesyncedEntityData(connection.getPlayer());
+ }
+ // Paper end - resend possibly desynced entity instead of add entity packet
}
public void update(ServerPlayer player) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
@@ -0,0 +0,0 @@ public class CraftItemFrame extends CraftHanging implements ItemFrame {
protected void update() {
super.update();
+ // Paper start, don't mark as dirty as this is handled in super.update()
// mark dirty, so that the client gets updated with item and rotation
- this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
- this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
+ //this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
+ //this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
+ // Paper end
// update redstone
if (!this.getHandle().generation) {

View File

@@ -1,302 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 14 May 2024 11:57:43 -0700
Subject: [PATCH] Proxy ItemStack to CraftItemStack
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.ApiStatus;
@DelegateDeserialization(ItemStack.class)
public final class CraftItemStack extends ItemStack {
- // Paper start - MC Utils
- public static net.minecraft.world.item.ItemStack unwrap(ItemStack bukkit) {
- if (bukkit instanceof CraftItemStack craftItemStack) {
- return craftItemStack.handle != null ? craftItemStack.handle : net.minecraft.world.item.ItemStack.EMPTY;
+ // Paper start - delegate api-ItemStack to CraftItemStack
+ private static final java.lang.invoke.VarHandle API_ITEM_STACK_CRAFT_DELEGATE_FIELD;
+ static {
+ try {
+ API_ITEM_STACK_CRAFT_DELEGATE_FIELD = java.lang.invoke.MethodHandles.privateLookupIn(
+ ItemStack.class,
+ java.lang.invoke.MethodHandles.lookup()
+ ).findVarHandle(ItemStack.class, "craftDelegate", ItemStack.class);
+ } catch (final IllegalAccessException | NoSuchFieldException exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ private static CraftItemStack getCraftStack(final ItemStack bukkit) {
+ if (bukkit instanceof final CraftItemStack craftItemStack) {
+ return craftItemStack;
} else {
- return asNMSCopy(bukkit);
+ return (CraftItemStack) API_ITEM_STACK_CRAFT_DELEGATE_FIELD.get(bukkit);
}
}
+ @Override
+ public int hashCode() {
+ if (this.handle == null || this.handle.isEmpty()) {
+ return net.minecraft.world.item.ItemStack.EMPTY.hashCode();
+ } else {
+ int hash = net.minecraft.world.item.ItemStack.hashItemAndComponents(this.handle);
+ hash = hash * 31 + this.handle.getCount();
+ return hash;
+ }
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof final org.bukkit.inventory.ItemStack bukkit)) return false;
+ final CraftItemStack craftStack = getCraftStack(bukkit);
+ if (this.handle == craftStack.handle) return true;
+ else if (this.handle == null || craftStack.handle == null) return false;
+ else if (this.handle.isEmpty() && craftStack.handle.isEmpty()) return true;
+ else return net.minecraft.world.item.ItemStack.matches(this.handle, craftStack.handle);
+ }
+ // Paper end
+
+ // Paper start - MC Utils
+ public static net.minecraft.world.item.ItemStack unwrap(ItemStack bukkit) {
+ // Paper start - re-implement after delegating all api ItemStack calls to CraftItemStack
+ final CraftItemStack craftItemStack = getCraftStack(bukkit);
+ return craftItemStack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : craftItemStack.handle;
+ // Paper end - re-implement after delegating all api ItemStack calls to CraftItemStack
+ }
+
public static net.minecraft.world.item.ItemStack getOrCloneOnMutation(ItemStack old, ItemStack newInstance) {
return old == newInstance ? unwrap(old) : asNMSCopy(newInstance);
}
@@ -0,0 +0,0 @@ public final class CraftItemStack extends ItemStack {
// Paper end - override isEmpty to use vanilla's impl
public static net.minecraft.world.item.ItemStack asNMSCopy(ItemStack original) {
- if (original instanceof CraftItemStack) {
- CraftItemStack stack = (CraftItemStack) original;
- return stack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : stack.handle.copy();
- }
- if (original == null || original.isEmpty()) { // Paper - override isEmpty to use vanilla's impl; use isEmpty
+ // Paper start - re-implement after delegating all api ItemStack calls to CraftItemStack
+ if (original == null || original.isEmpty()) {
return net.minecraft.world.item.ItemStack.EMPTY;
}
-
- Item item = CraftItemType.bukkitToMinecraft(original.getType());
-
- if (item == null) {
- return net.minecraft.world.item.ItemStack.EMPTY;
- }
-
- net.minecraft.world.item.ItemStack stack = new net.minecraft.world.item.ItemStack(item, original.getAmount());
- if (original.hasItemMeta()) {
- CraftItemStack.setItemMeta(stack, original.getItemMeta());
- }
- return stack;
+ final CraftItemStack stack = getCraftStack(original);
+ return stack.handle == null ? net.minecraft.world.item.ItemStack.EMPTY : stack.handle.copy();
+ // Paper end - re-implement after delegating all api ItemStack calls to CraftItemStack
}
// Paper start
@@ -0,0 +0,0 @@ public final class CraftItemStack extends ItemStack {
* Copies the NMS stack to return as a strictly-Bukkit stack
*/
public static ItemStack asBukkitCopy(net.minecraft.world.item.ItemStack original) {
- if (original.isEmpty()) {
- return new ItemStack(Material.AIR);
- }
- ItemStack stack = new ItemStack(CraftItemType.minecraftToBukkit(original.getItem()), original.getCount());
- if (CraftItemStack.hasItemMeta(original)) {
- stack.setItemMeta(CraftItemStack.getItemMeta(original));
- }
- return stack;
+ // Paper start - no such thing as a "strictly-Bukkit stack" anymore
+ // we copy the stack since it should be a complete copy not a mirror
+ return asCraftMirror(original.copy());
+ // Paper end
}
public static CraftItemStack asCraftMirror(net.minecraft.world.item.ItemStack original) {
@@ -0,0 +0,0 @@ public final class CraftItemStack extends ItemStack {
@Override
public CraftItemStack clone() {
- CraftItemStack itemStack = (CraftItemStack) super.clone();
- if (this.handle != null) {
- itemStack.handle = this.handle.copy();
- }
- return itemStack;
+ return new org.bukkit.craftbukkit.inventory.CraftItemStack(this.handle != null ? this.handle.copy() : null); // Paper
}
@Override
@@ -0,0 +0,0 @@ public final class CraftItemStack extends ItemStack {
if (stack == this) {
return true;
}
- if (!(stack instanceof CraftItemStack)) {
- return stack.getClass() == ItemStack.class && stack.isSimilar(this);
- }
-
- CraftItemStack that = (CraftItemStack) stack;
+ final CraftItemStack that = getCraftStack(stack); // Paper - re-implement after delegating all api ItemStack calls to CraftItemStack
if (this.handle == that.handle) {
return true;
}
if (this.handle == null || that.handle == null) {
return false;
}
- Material comparisonType = CraftLegacy.fromLegacy(that.getType()); // This may be called from legacy item stacks, try to get the right material
- if (!(comparisonType == this.getType() && this.getDurability() == that.getDurability())) {
- return false;
- }
- return this.hasItemMeta() ? that.hasItemMeta() && this.handle.getComponents().equals(that.handle.getComponents()) : !that.hasItemMeta();
+ return net.minecraft.world.item.ItemStack.isSameItemSameComponents(this.handle, that.handle); // Paper - re-implement after delegating all api ItemStack calls to CraftItemStack
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
@@ -0,0 +0,0 @@ public class CraftItemType<M extends ItemMeta> implements ItemType.Typed<M>, Han
@NotNull
@Override
public ItemStack createItemStack(final int amount, @Nullable final Consumer<? super M> metaConfigurator) {
- final ItemStack itemStack = new ItemStack(this.asMaterial(), amount);
+ // Paper start - re-implement to return CraftItemStack
+ final net.minecraft.world.item.ItemStack stack = new net.minecraft.world.item.ItemStack(this.item, amount);
+ final CraftItemStack mirror = CraftItemStack.asCraftMirror(stack);
if (metaConfigurator != null) {
- final ItemMeta itemMeta = itemStack.getItemMeta();
- metaConfigurator.accept((M) itemMeta);
- itemStack.setItemMeta(itemMeta);
+ mirror.editMeta(this.getItemMetaClass(), metaConfigurator);
}
- return itemStack;
+ return mirror;
+ // Paper start - reimplement to return CraftItemStack
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
+++ b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java
@@ -0,0 +0,0 @@ public class MaterialRerouting {
return itemStack.withType(material);
}
// Paper end - register paper API specific material consumers in rerouting
+
+ // Paper start - methods added post 1.13, no-op
+ @RerouteStatic("org/bukkit/inventory/ItemStack")
+ public static ItemStack of(final Material material) {
+ return ItemStack.of(material);
+ }
+
+ @RerouteStatic("org/bukkit/inventory/ItemStack")
+ public static ItemStack of(final Material material, final int amount) {
+ return ItemStack.of(material, amount);
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -0,0 +0,0 @@ public final class CraftMagicNumbers implements UnsafeValues {
}
// Paper end - hack to get tags for non server-backed registries
+ // Paper start - proxy ItemStack
+ @Override
+ public org.bukkit.inventory.ItemStack createEmptyStack() {
+ return CraftItemStack.asCraftMirror(null);
+ }
+ // Paper end - proxy ItemStack
+
/**
* This helper class represents the different NBT Tags.
* <p>
diff --git a/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java b/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.configuration;
+
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.support.environment.VanillaFeature;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public abstract class ConfigurationSectionTest {
+ public abstract ConfigurationSection getConfigurationSection();
+
+ @Test
+ public void testGetItemStack_String() {
+ ConfigurationSection section = getConfigurationSection();
+ String key = "exists";
+ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
+
+ section.set(key, value);
+
+ assertEquals(value, section.getItemStack(key));
+ assertNull(section.getString("doesntExist"));
+ }
+
+ @Test
+ public void testGetItemStack_String_ItemStack() {
+ ConfigurationSection section = getConfigurationSection();
+ String key = "exists";
+ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
+ ItemStack def = new ItemStack(Material.STONE, 1);
+
+ section.set(key, value);
+
+ assertEquals(value, section.getItemStack(key, def));
+ assertEquals(def, section.getItemStack("doesntExist", def));
+ }
+
+ @Test
+ public void testIsItemStack() {
+ ConfigurationSection section = getConfigurationSection();
+ String key = "exists";
+ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
+
+ section.set(key, value);
+
+ assertTrue(section.isItemStack(key));
+ assertFalse(section.isItemStack("doesntExist"));
+ }
+}
diff --git a/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java b/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.configuration;
+
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.MemoryConfiguration;
+import org.bukkit.support.environment.Normal;
+
+@Normal
+public class MemorySectionTest extends ConfigurationSectionTest {
+ @Override
+ public ConfigurationSection getConfigurationSection() {
+ return new MemoryConfiguration().createSection("section");
+ }
+}

File diff suppressed because it is too large Load Diff

View File

@@ -1,78 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: lukas81298 <lukas81298@gommehd.net>
Date: Fri, 22 Jan 2021 21:50:18 +0100
Subject: [PATCH] optimize dirt and snow spreading
diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
@@ -0,0 +0,0 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
}
private static boolean canBeGrass(BlockState state, LevelReader world, BlockPos pos) {
+ // Paper start - Perf: optimize dirt and snow spreading
+ return canBeGrass(world.getChunk(pos), state, world, pos);
+ }
+ private static boolean canBeGrass(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader world, BlockPos pos) {
+ // Paper end - Perf: optimize dirt and snow spreading
BlockPos blockposition1 = pos.above();
- BlockState iblockdata1 = world.getBlockState(blockposition1);
+ BlockState iblockdata1 = chunk.getBlockState(blockposition1); // Paper - Perf: optimize dirt and snow spreading
if (iblockdata1.is(Blocks.SNOW) && (Integer) iblockdata1.getValue(SnowLayerBlock.LAYERS) == 1) {
return true;
@@ -0,0 +0,0 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
protected abstract MapCodec<? extends SpreadingSnowyDirtBlock> codec();
private static boolean canPropagate(BlockState state, LevelReader world, BlockPos pos) {
+ // Paper start - Perf: optimize dirt and snow spreading
+ return canPropagate(world.getChunk(pos), state, world, pos);
+ }
+
+ private static boolean canPropagate(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader world, BlockPos pos) {
+ // Paper end - Perf: optimize dirt and snow spreading
BlockPos blockposition1 = pos.above();
- return SpreadingSnowyDirtBlock.canBeGrass(state, world, pos) && !world.getFluidState(blockposition1).is(FluidTags.WATER);
+ return SpreadingSnowyDirtBlock.canBeGrass(chunk, state, world, pos) && !chunk.getFluidState(blockposition1).is(FluidTags.WATER); // Paper - Perf: optimize dirt and snow spreading
}
@Override
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks
- if (!SpreadingSnowyDirtBlock.canBeGrass(state, world, pos)) {
+ // Paper start - Perf: optimize dirt and snow spreading
+ final net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = world.getChunkIfLoaded(pos);
+ if (cachedBlockChunk == null) { // Is this needed?
+ return;
+ }
+ if (!SpreadingSnowyDirtBlock.canBeGrass(cachedBlockChunk, state, world, pos)) {
+ // Paper end - Perf: optimize dirt and snow spreading
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) {
return;
@@ -0,0 +0,0 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
for (int i = 0; i < 4; ++i) {
BlockPos blockposition1 = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1);
-
- if (world.getBlockState(blockposition1).is(Blocks.DIRT) && SpreadingSnowyDirtBlock.canPropagate(iblockdata1, world, blockposition1)) {
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, (BlockState) iblockdata1.setValue(SpreadingSnowyDirtBlock.SNOWY, world.getBlockState(blockposition1.above()).is(Blocks.SNOW))); // CraftBukkit
+ // Paper start - Perf: optimize dirt and snow spreading
+ if (pos.getX() == blockposition1.getX() && pos.getY() == blockposition1.getY() && pos.getZ() == blockposition1.getZ()) {
+ continue;
+ }
+ net.minecraft.world.level.chunk.ChunkAccess access;
+ if (cachedBlockChunk.locX == blockposition1.getX() >> 4 && cachedBlockChunk.locZ == blockposition1.getZ() >> 4) {
+ access = cachedBlockChunk;
+ } else {
+ access = world.getChunkAt(blockposition1);
+ }
+ if (access.getBlockState(blockposition1).is(Blocks.DIRT) && SpreadingSnowyDirtBlock.canPropagate(access, iblockdata1, world, blockposition1)) {
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, (BlockState) iblockdata1.setValue(SpreadingSnowyDirtBlock.SNOWY, access.getBlockState(blockposition1.above()).is(Blocks.SNOW))); // CraftBukkit
+ // Paper end - Perf: optimize dirt and snow spreading
}
}
}