PaperMC/patches/api/Add-FeatureFlag-API.patch
Nassim Jahnke 29b207245f Updated Upstream (Bukkit/CraftBukkit) (#11543)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

Bukkit Changes:
97c59261 PR-1073: Make Biome an interface
a38581aa Fix further javadoc errors
8271c490 Fix javadoc error
8a9ecf29 PR-1072: Fix bad naming for Vault State methods
6dd58108 PR-1071: Make Fluid an interface and add missing entry
ed2cdfc3 PR-1070: Make Attribute an interface and align names with the new minecraft ones
63472efb PR-1069: Add missing winter drop experimental annotation to pale boats

CraftBukkit Changes:
7235ad7b0 PR-1501: Make Biome an interface
602904003 PR-1500: Rename implementation for Vault State methods
75f26f79f PR-1499: Make Fluid an interface and add missing entry
4cfd87adc PR-1498: Make Attribute an interface and align names with the new minecraft ones
6bb0db5cb SPIGOT-7928: ExactChoice acts as MaterialChoice
3eaf3a13c SPIGOT-7929: Error when setting EquippableComponent
abbf57bac SPIGOT-7930: Fix spawning entities with SummonEntityEffect
92d6ab6cf PR-1497: Move boat field rename entries to below key renaming, so that keys are also renamed
abfe292aa PR-1496: Use correct Fluid class on Tags type check
c7aab7fa7 SPIGOT-7923: Fix Dispenser logic to avoid firing empty projectiles
2024-10-31 23:44:34 +01:00

373 lines
17 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 9 Mar 2023 11:24:43 -0800
Subject: [PATCH] Add FeatureFlag API
diff --git a/src/main/java/io/papermc/paper/world/flag/FeatureDependant.java b/src/main/java/io/papermc/paper/world/flag/FeatureDependant.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/world/flag/FeatureDependant.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.world.flag;
+
+import java.util.Set;
+import org.bukkit.FeatureFlag;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Unmodifiable;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Implemented by types in built-in registries that are controlled by {@link FeatureFlag FeatureFlags}.
+ * Types in data-driven registries that are controlled by feature flags just will not exist in that registry.
+ * @apiNote When a type that currently implements this interface transitions to being data-drive, this
+ * interface will be removed from that type in the following major version.
+ */
+@NullMarked
+@ApiStatus.NonExtendable
+public interface FeatureDependant {
+
+ /**
+ * Gets the set of required feature flags for this
+ * to be enabled.
+ *
+ * @return the immutable set of feature flags
+ */
+ default @Unmodifiable Set<FeatureFlag> requiredFeatures() {
+ return FeatureFlagProvider.provider().requiredFeatures(this);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/world/flag/FeatureFlagProvider.java b/src/main/java/io/papermc/paper/world/flag/FeatureFlagProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/world/flag/FeatureFlagProvider.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.world.flag;
+
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.Set;
+import org.bukkit.FeatureFlag;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+@ApiStatus.Internal
+interface FeatureFlagProvider {
+
+ Optional<FeatureFlagProvider> PROVIDER = ServiceLoader.load(FeatureFlagProvider.class).findFirst();
+
+ static FeatureFlagProvider provider() {
+ return PROVIDER.orElseThrow();
+ }
+
+ Set<FeatureFlag> requiredFeatures(FeatureDependant dependant);
+}
diff --git a/src/main/java/io/papermc/paper/world/flag/FeatureFlagSetHolder.java b/src/main/java/io/papermc/paper/world/flag/FeatureFlagSetHolder.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/world/flag/FeatureFlagSetHolder.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.world.flag;
+
+import java.util.Set;
+import org.bukkit.FeatureFlag;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Unmodifiable;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Implemented by types that hold {@link FeatureFlag FeatureFlags} like
+ * {@link org.bukkit.generator.WorldInfo} and {@link org.bukkit.RegionAccessor}.
+ */
+@NullMarked
+@ApiStatus.NonExtendable
+public interface FeatureFlagSetHolder {
+
+ /**
+ * Checks if this is enabled based on the loaded feature flags.
+ *
+ * @return true if enabled
+ */
+ default boolean isEnabled(final FeatureDependant featureDependant) {
+ return this.getFeatureFlags().containsAll(featureDependant.requiredFeatures());
+ }
+
+ /**
+ * Get all {@link FeatureFlag FeatureFlags} enabled in this world.
+ *
+ * @return all enabled {@link FeatureFlag FeatureFlags}
+ */
+ @Unmodifiable Set<FeatureFlag> getFeatureFlags();
+}
diff --git a/src/main/java/org/bukkit/FeatureFlag.java b/src/main/java/org/bukkit/FeatureFlag.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/FeatureFlag.java
+++ b/src/main/java/org/bukkit/FeatureFlag.java
@@ -0,0 +0,0 @@
package org.bukkit;
+// Paper start - overhaul FeatureFlag API
+import com.google.common.base.Preconditions;
+import java.util.List;
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.util.Index;
+import org.intellij.lang.annotations.Subst;
+// Paper end - overhaul FeatureFlag API
import org.jetbrains.annotations.ApiStatus;
/**
- * This represents a Feature Flag for a World.
- * <br>
- * Flags which are unavailable in the current version will be null and/or
- * removed.
+ * This represents a Feature Flag for a {@link io.papermc.paper.world.flag.FeatureFlagSetHolder}.
*/
-@ApiStatus.Experimental
public interface FeatureFlag extends Keyed {
- public static final FeatureFlag VANILLA = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("vanilla"));
+ // Paper start - overhaul FeatureFlag API
+ /**
+ * The {@code vanilla} feature flag.
+ */
+ FeatureFlag VANILLA = create("vanilla");
/**
* <strong>AVAILABLE BETWEEN VERSIONS:</strong> 1.19.3 - 1.21.1
@@ -0,0 +0,0 @@ public interface FeatureFlag extends Keyed {
* @deprecated not available since 1.21.2
*/
@Deprecated
- public static final FeatureFlag BUNDLE = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("bundle"));
+ FeatureFlag BUNDLE = deprecated("bundle");
/**
- * <strong>AVAILABLE BETWEEN VERSIONS:</strong> 1.19 - 1.19.4
- *
- * @deprecated not available since 1.20
+ * The {@code trade_rebalance} feature flag.
*/
- @Deprecated
- public static final FeatureFlag UPDATE_1_20 = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("update_1_20"));
-
@ApiStatus.Experimental // Paper - add missing annotation
- public static final FeatureFlag TRADE_REBALANCE = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("trade_rebalance"));
+ FeatureFlag TRADE_REBALANCE = create("trade_rebalance");
- /**
- * <strong>AVAILABLE BETWEEN VERSIONS:</strong> 1.20.5 - 1.20.6
- *
- * @deprecated not available since 1.21
- */
- @Deprecated
- public static final FeatureFlag UPDATE_121 = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("update_1_21"));
+ @Deprecated(since = "1.20")
+ FeatureFlag UPDATE_1_20 = deprecated("update_1_20");
+
+ @Deprecated(since = "1.21")
+ FeatureFlag UPDATE_121 = deprecated("update_1_21");
@ApiStatus.Experimental // Paper - add missing annotation
- public static final FeatureFlag WINTER_DROP = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("winter_drop"));
+ FeatureFlag WINTER_DROP = create("winter_drop");
@ApiStatus.Experimental // Paper - add missing annotation
- public static final FeatureFlag REDSTONE_EXPERIMENTS = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("redstone_experiments"));
+ FeatureFlag REDSTONE_EXPERIMENTS = create("redstone_experiments");
@ApiStatus.Experimental // Paper - add missing annotation
- public static final FeatureFlag MINECART_IMPROVEMENTS = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("minecart_improvements"));
+ FeatureFlag MINECART_IMPROVEMENTS = create("minecart_improvements");
+
+ /**
+ * An index of all feature flags.
+ */
+ Index<Key, FeatureFlag> ALL_FLAGS = Index.create(FeatureFlag::key, List.copyOf(FeatureFlagImpl.ALL_FLAGS));
+
+ private static FeatureFlag create(@Subst("vanilla") final String name) {
+ final FeatureFlag flag = new FeatureFlagImpl(NamespacedKey.minecraft(name));
+ Preconditions.checkState(FeatureFlagImpl.ALL_FLAGS.add(flag), "Tried to add duplicate feature flag: " + name);
+ return flag;
+ }
+
+ private static FeatureFlag deprecated(@Subst("vanilla") final String name) {
+ return new FeatureFlagImpl.Deprecated(NamespacedKey.minecraft(name));
+ }
+ // Paper end - overhaul FeatureFlag API
}
diff --git a/src/main/java/org/bukkit/FeatureFlagImpl.java b/src/main/java/org/bukkit/FeatureFlagImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/org/bukkit/FeatureFlagImpl.java
@@ -0,0 +0,0 @@
+package org.bukkit;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+@ApiStatus.Internal
+@NullMarked
+record FeatureFlagImpl(NamespacedKey key) implements FeatureFlag {
+
+ static final Set<FeatureFlag> ALL_FLAGS = new HashSet<>();
+
+ @Override
+ public NamespacedKey getKey() {
+ return this.key;
+ }
+
+ @ApiStatus.Internal
+ record Deprecated(NamespacedKey key) implements FeatureFlag {
+
+ @Override
+ public NamespacedKey getKey() {
+ return this.key;
+ }
+ }
+}
diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/RegionAccessor.java
+++ b/src/main/java/org/bukkit/RegionAccessor.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
* A RegionAccessor gives access to getting, modifying and spawning {@link Biome}, {@link BlockState} and {@link Entity},
* as well as generating some basic structures.
*/
-public interface RegionAccessor extends Keyed { // Paper
+public interface RegionAccessor extends Keyed, io.papermc.paper.world.flag.FeatureFlagSetHolder { // Paper - feature flag API
/**
* Gets the {@link Biome} at the given {@link Location}.
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/UnsafeValues.java
+++ b/src/main/java/org/bukkit/UnsafeValues.java
@@ -0,0 +0,0 @@ public interface UnsafeValues {
@Deprecated(since = "1.21.3", forRemoval = true)
String getTranslationKey(Attribute attribute);
- @Nullable
- FeatureFlag getFeatureFlag(@NotNull NamespacedKey key);
+ // Paper - replace with better system
/**
* Do not use, method will get removed, and the plugin won't run
diff --git a/src/main/java/org/bukkit/block/BlockType.java b/src/main/java/org/bukkit/block/BlockType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/block/BlockType.java
+++ b/src/main/java/org/bukkit/block/BlockType.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
* changes may occur. Do not use this API in plugins.
*/
@ApiStatus.Internal
-public interface BlockType extends Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - add translatable
+public interface BlockType extends Keyed, Translatable, net.kyori.adventure.translation.Translatable, io.papermc.paper.world.flag.FeatureDependant { // Paper - add translatable & feature flag API
/**
* Typed represents a subtype of {@link BlockType}s that have a known block
@@ -0,0 +0,0 @@ public interface BlockType extends Keyed, Translatable, net.kyori.adventure.tran
*
* @param world the world to check
* @return true if this BlockType can be used in this World.
+ * @deprecated Use {@link io.papermc.paper.world.flag.FeatureFlagSetHolder#isEnabled(io.papermc.paper.world.flag.FeatureDependant)}
*/
+ @Deprecated(forRemoval = true, since = "1.21.1") // Paper
boolean isEnabledByFeature(@NotNull World world);
/**
diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/EntityType.java
+++ b/src/main/java/org/bukkit/entity/EntityType.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-public enum EntityType implements Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - translatable
+public enum EntityType implements Keyed, Translatable, net.kyori.adventure.translation.Translatable, io.papermc.paper.world.flag.FeatureDependant { // Paper - translatable
// These strings MUST match the strings in nms.EntityTypes and are case sensitive.
/**
diff --git a/src/main/java/org/bukkit/generator/WorldInfo.java b/src/main/java/org/bukkit/generator/WorldInfo.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/generator/WorldInfo.java
+++ b/src/main/java/org/bukkit/generator/WorldInfo.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull;
/**
* Holds various information of a World
*/
-public interface WorldInfo {
+public interface WorldInfo extends io.papermc.paper.world.flag.FeatureFlagSetHolder { // Paper - feature flag API
/**
* Gets the unique name of this world
diff --git a/src/main/java/org/bukkit/inventory/ItemType.java b/src/main/java/org/bukkit/inventory/ItemType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/inventory/ItemType.java
+++ b/src/main/java/org/bukkit/inventory/ItemType.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
* changes may occur. Do not use this API in plugins.
*/
@ApiStatus.Experimental // Paper - already required for registry builders
-public interface ItemType extends Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - add Translatable
+public interface ItemType extends Keyed, Translatable, net.kyori.adventure.translation.Translatable, io.papermc.paper.world.flag.FeatureDependant { // Paper - add Translatable & feature flag API
/**
* Typed represents a subtype of {@link ItemType}s that have a known item meta type
@@ -0,0 +0,0 @@ public interface ItemType extends Keyed, Translatable, net.kyori.adventure.trans
*
* @param world the world to check
* @return true if this ItemType can be used in this World.
+ * @deprecated use {@link io.papermc.paper.world.flag.FeatureFlagSetHolder#isEnabled(io.papermc.paper.world.flag.FeatureDependant)}
*/
+ @Deprecated(forRemoval = true, since = "1.21.1") // Paper
boolean isEnabledByFeature(@NotNull World world);
/**
diff --git a/src/main/java/org/bukkit/inventory/MenuType.java b/src/main/java/org/bukkit/inventory/MenuType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/inventory/MenuType.java
+++ b/src/main/java/org/bukkit/inventory/MenuType.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull;
* created and viewed by the player.
*/
@ApiStatus.Experimental
-public interface MenuType extends Keyed {
+public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDependant { // Paper - make FeatureDependant
/**
* A MenuType which represents a chest with 1 row.
diff --git a/src/main/java/org/bukkit/potion/PotionEffectType.java b/src/main/java/org/bukkit/potion/PotionEffectType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/potion/PotionEffectType.java
+++ b/src/main/java/org/bukkit/potion/PotionEffectType.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
/**
* Represents a type of potion and its effect on an entity.
*/
-public abstract class PotionEffectType implements Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - implement Translatable
+public abstract class PotionEffectType implements Keyed, Translatable, net.kyori.adventure.translation.Translatable, io.papermc.paper.world.flag.FeatureDependant { // Paper - implement Translatable & feature flag API
private static final BiMap<Integer, PotionEffectType> ID_MAP = HashBiMap.create();
/**
diff --git a/src/main/java/org/bukkit/potion/PotionType.java b/src/main/java/org/bukkit/potion/PotionType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/potion/PotionType.java
+++ b/src/main/java/org/bukkit/potion/PotionType.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
* This enum reflects and matches each potion state that can be obtained from
* the Creative mode inventory
*/
-public enum PotionType implements Keyed {
+public enum PotionType implements Keyed, io.papermc.paper.world.flag.FeatureDependant { // Paper - feature flag API
WATER("water"),
MUNDANE("mundane"),
THICK("thick"),