aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorkokiriglade <[email protected]>2024-11-23 22:10:54 +0000
committerGitHub <[email protected]>2024-11-23 23:10:54 +0100
commit6051dac82bbd12d2f4b2a331f2eb553604dfa18c (patch)
tree9feac2e2b988dafecf5f662069deb076a0b9a37d
parentedabff8a35f60642e680c7e9d61689a58bd84103 (diff)
downloadPaper-6051dac82bbd12d2f4b2a331f2eb553604dfa18c.tar.gz
Paper-6051dac82bbd12d2f4b2a331f2eb553604dfa18c.zip
Painting variant registry modification API (#11648)
-rw-r--r--patches/api/0472-Introduce-registry-entry-and-builders.patch151
-rw-r--r--patches/api/0478-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch2
-rw-r--r--patches/api/0484-Add-FeatureFlag-API.patch2
-rw-r--r--patches/api/0486-Item-serialization-as-json.patch2
-rw-r--r--patches/api/0492-Void-damage-configuration-API.patch2
-rw-r--r--patches/api/0495-DataComponent-API.patch2
-rw-r--r--patches/api/0500-Expanded-Art-API.patch40
-rw-r--r--patches/server/0992-Registry-Modification-API.patch2
-rw-r--r--patches/server/0993-Add-registry-entry-and-builders.patch141
-rw-r--r--patches/server/1019-Add-FeatureFlag-API.patch2
-rw-r--r--patches/server/1021-Item-serialization-as-json.patch2
-rw-r--r--patches/server/1035-DataComponent-API.patch6
-rw-r--r--patches/server/1037-Rewrite-dataconverter-system.patch2
-rw-r--r--patches/server/1053-Optional-per-player-mob-spawns.patch2
-rw-r--r--patches/server/1054-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch2
-rw-r--r--patches/server/1070-Expanded-Art-API.patch53
16 files changed, 391 insertions, 22 deletions
diff --git a/patches/api/0472-Introduce-registry-entry-and-builders.patch b/patches/api/0472-Introduce-registry-entry-and-builders.patch
index 0a25fd735e..631eaf3f55 100644
--- a/patches/api/0472-Introduce-registry-entry-and-builders.patch
+++ b/patches/api/0472-Introduce-registry-entry-and-builders.patch
@@ -3,6 +3,7 @@ From: Bjarne Koll <[email protected]>
Date: Thu, 13 Jun 2024 22:35:05 +0200
Subject: [PATCH] Introduce registry entry and builders
+Co-authored-by: kokiriglade <[email protected]>
diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java
index 647f6a1ec1f9d3c203b41f90a99bfd415bf67366..9b39e33514b15a9d07104e2ad826d0da11f569d6 100644
@@ -414,6 +415,147 @@ index 0000000000000000000000000000000000000000..980fe12b75258b51cc2498590cadb9de
+ Builder range(@Range(from = 0, to = Integer.MAX_VALUE) int range);
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/registry/data/PaintingVariantRegistryEntry.java b/src/main/java/io/papermc/paper/registry/data/PaintingVariantRegistryEntry.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..b8d133afa82da1b5b9e7a18e1c332ae3aefea50d
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/data/PaintingVariantRegistryEntry.java
+@@ -0,0 +1,135 @@
++package io.papermc.paper.registry.data;
++
++import io.papermc.paper.registry.RegistryBuilder;
++import java.util.Optional;
++import net.kyori.adventure.key.Key;
++import net.kyori.adventure.text.Component;
++import org.bukkit.Art;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.Contract;
++import org.jetbrains.annotations.Range;
++import org.jspecify.annotations.NullMarked;
++import org.jspecify.annotations.Nullable;
++
++/**
++ * A data-centric version-specific registry entry for the {@link Art} type.
++ */
++@NullMarked
++public interface PaintingVariantRegistryEntry {
++
++ /**
++ * Provides the width of this variant in blocks.
++ *
++ * @return the width
++ * @see Art#getBlockWidth()
++ */
++ @Range(from = 1, to = 16)
++ int width();
++
++ /**
++ * Provides the height of this variant in blocks.
++ *
++ * @return the height
++ * @see Art#getBlockHeight()
++ */
++ @Range(from = 1, to = 16)
++ int height();
++
++ /**
++ * Provides the title of the painting visible in the creative inventory.
++ *
++ * @return the title
++ * @see Art#title()
++ */
++ @Nullable Component title();
++
++ /**
++ * Provides the author of the painting visible in the creative inventory.
++ *
++ * @return the author
++ * @see Art#author()
++ */
++ @Nullable Component author();
++
++ /**
++ * Provides the assetId of the variant, which is the location of the sprite to use.
++ *
++ * @return the asset id
++ * @see Art#assetId()
++ */
++ Key assetId();
++
++ /**
++ * A mutable builder for the {@link PaintingVariantRegistryEntry} plugins may change in applicable registry events.
++ * <p>
++ * The following values are required for each builder:
++ * <ul>
++ * <li>{@link #width(int)}</li>
++ * <li>{@link #height(int)}</li>
++ * <li>{@link #assetId(Key)}</li>
++ * </ul>
++ */
++ @ApiStatus.Experimental
++ @ApiStatus.NonExtendable
++ interface Builder extends PaintingVariantRegistryEntry, RegistryBuilder<Art> {
++
++ /**
++ * Sets the width of the painting in blocks.
++ *
++ * @param width the width in blocks
++ * @return this builder instance
++ * @see PaintingVariantRegistryEntry#width()
++ * @see Art#getBlockWidth()
++ */
++ @Contract(value = "_ -> this", mutates = "this")
++ Builder width(@Range(from = 0, to = 16) int width);
++
++ /**
++ * Sets the height of the painting in blocks.
++ *
++ * @param height the height in blocks
++ * @return this builder instance
++ * @see PaintingVariantRegistryEntry#height()
++ * @see Art#getBlockHeight()
++ */
++ @Contract(value = "_ -> this", mutates = "this")
++ Builder height(@Range(from = 0, to = 16) int height);
++
++ /**
++ * Sets the title of the painting.
++ *
++ * @param title the title
++ * @return this builder instance
++ * @see PaintingVariantRegistryEntry#title()
++ * @see Art#title()
++ */
++ @Contract(value = "_ -> this", mutates = "this")
++ Builder title(@Nullable Component title);
++
++ /**
++ * Sets the author of the painting.
++ *
++ * @param author the author
++ * @return this builder instance
++ * @see PaintingVariantRegistryEntry#author()
++ * @see Art#author()
++ */
++ @Contract(value = "_ -> this", mutates = "this")
++ Builder author(@Nullable Component author);
++
++ /**
++ * Sets the assetId of the variant, which is the location of the sprite to use.
++ *
++ * @param assetId the asset id
++ * @return this builder instance
++ * @see PaintingVariantRegistryEntry#assetId()
++ * @see Art#assetId()
++ */
++ @Contract(value = "_ -> this", mutates = "this")
++ Builder assetId(Key assetId);
++
++ }
++
++}
diff --git a/src/main/java/io/papermc/paper/registry/data/package-info.java b/src/main/java/io/papermc/paper/registry/data/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f8f536f437c5f483ac7bce393e664fd7bc38477
@@ -430,15 +572,17 @@ index 0000000000000000000000000000000000000000..4f8f536f437c5f483ac7bce393e664fd
+ */
+package io.papermc.paper.registry.data;
diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java
-index 91ae9c0d3ec55ce417d4b447bf3d1b0d0c174b5e..1c8e77c7243cfedef6c4d1491cf98e6ec8f1690f 100644
+index 91ae9c0d3ec55ce417d4b447bf3d1b0d0c174b5e..40deffbd0930508bb04e9aedfd62ad2144855198 100644
--- a/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java
+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java
-@@ -1,8 +1,15 @@
+@@ -1,8 +1,17 @@
package io.papermc.paper.registry.event;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.data.EnchantmentRegistryEntry;
+import io.papermc.paper.registry.data.GameEventRegistryEntry;
++import io.papermc.paper.registry.data.PaintingVariantRegistryEntry;
++import org.bukkit.Art;
+import org.bukkit.GameEvent;
+import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.ApiStatus;
@@ -449,12 +593,13 @@ index 91ae9c0d3ec55ce417d4b447bf3d1b0d0c174b5e..1c8e77c7243cfedef6c4d1491cf98e6e
/**
* Holds providers for {@link RegistryEntryAddEvent} and {@link RegistryFreezeEvent}
* handlers for each applicable registry.
-@@ -11,6 +18,9 @@ import org.jspecify.annotations.NullMarked;
+@@ -11,6 +20,10 @@ import org.jspecify.annotations.NullMarked;
@NullMarked
public final class RegistryEvents {
+ public static final RegistryEventProvider<GameEvent, GameEventRegistryEntry.Builder> GAME_EVENT = create(RegistryKey.GAME_EVENT);
+ public static final RegistryEventProvider<Enchantment, EnchantmentRegistryEntry.Builder> ENCHANTMENT = create(RegistryKey.ENCHANTMENT);
++ public static final RegistryEventProvider<Art, PaintingVariantRegistryEntry.Builder> PAINTING_VARIANT = create(RegistryKey.PAINTING_VARIANT);
+
private RegistryEvents() {
}
diff --git a/patches/api/0478-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch b/patches/api/0478-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch
index 9ee5f867c6..61318cd604 100644
--- a/patches/api/0478-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch
+++ b/patches/api/0478-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch
@@ -228,7 +228,7 @@ index 7ff6d60deb129e23b2a4d772aee123eb6c0b6433..52a2763773b234c581b2dcc6f0584f8d
return key;
}
diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java
-index fc089b796f5a0f2e1ab081cc710e4bb5c3f5ee7b..2a86e599175549a3021a63a837f8cc9d8da5697d 100644
+index 3fdba38fd5e75ddcbfca9cee70a606bfa4a539bf..66219e3855aef885341132a7456af54cf315475f 100644
--- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java
+++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java
@@ -1010,4 +1010,98 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste
diff --git a/patches/api/0484-Add-FeatureFlag-API.patch b/patches/api/0484-Add-FeatureFlag-API.patch
index 9a535e20f5..008c2d793c 100644
--- a/patches/api/0484-Add-FeatureFlag-API.patch
+++ b/patches/api/0484-Add-FeatureFlag-API.patch
@@ -247,7 +247,7 @@ index eb33e8e671972aa308ad75a7ce9aa9ac526f470f..05ecf3cb38ff42c8b52405d900197e6b
/**
* 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 56d16c887b7663aab7db2f7be532d9912aeb3570..2dd4c16ac107f58752c725540ab414ff79c46ff4 100644
+index 307439827b401acb96f0df1cf4ef31835bd1d513..e8dc8a6abebf6c31cb095ca3646eb4909e42f105 100644
--- a/src/main/java/org/bukkit/UnsafeValues.java
+++ b/src/main/java/org/bukkit/UnsafeValues.java
@@ -111,8 +111,7 @@ public interface UnsafeValues {
diff --git a/patches/api/0486-Item-serialization-as-json.patch b/patches/api/0486-Item-serialization-as-json.patch
index e7d391dc20..eae7e05be8 100644
--- a/patches/api/0486-Item-serialization-as-json.patch
+++ b/patches/api/0486-Item-serialization-as-json.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Item serialization as json
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
-index 2dd4c16ac107f58752c725540ab414ff79c46ff4..79312bdda8ef0799e2d46decc52cfdac95b97d37 100644
+index e8dc8a6abebf6c31cb095ca3646eb4909e42f105..a491dc40093e19b8d1900443ad613223fd7f3119 100644
--- a/src/main/java/org/bukkit/UnsafeValues.java
+++ b/src/main/java/org/bukkit/UnsafeValues.java
@@ -168,6 +168,36 @@ public interface UnsafeValues {
diff --git a/patches/api/0492-Void-damage-configuration-API.patch b/patches/api/0492-Void-damage-configuration-API.patch
index 26cbd83b18..6863ef168c 100644
--- a/patches/api/0492-Void-damage-configuration-API.patch
+++ b/patches/api/0492-Void-damage-configuration-API.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Void damage configuration API
diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
-index adcd8161846b06fd1a7895750f98b629204a8406..ef32a937e6faf1e8a5d6b1207986715bae5a246c 100644
+index b462f2a9f7b6acbdc826d093b1de826ca682f25b..7a439c99fc4c5ee17d674460c8e58a9fe0c64e02 100644
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
@@ -52,6 +52,54 @@ import org.jetbrains.annotations.Nullable;
diff --git a/patches/api/0495-DataComponent-API.patch b/patches/api/0495-DataComponent-API.patch
index 1079253459..5f86c0b8e6 100644
--- a/patches/api/0495-DataComponent-API.patch
+++ b/patches/api/0495-DataComponent-API.patch
@@ -3916,7 +3916,7 @@ index 615eb24ffdd8f6d55ccd4f21760b809c1098bc68..c7ce8fa1ff9feda66d5a4e497112a24f
+ // Paper end - data component API
}
diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java
-index 7cf7c6d05aa6cbf3f0c8612831404552c6a7b84a..c60e31425efd7b863941f5538faef6c0552290ae 100644
+index 87907918c42b11780b285b6d82e7297628a07376..d55c33ca14257be5005520e18e465da87a58dbaf 100644
--- a/src/main/java/org/bukkit/Registry.java
+++ b/src/main/java/org/bukkit/Registry.java
@@ -376,6 +376,7 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
diff --git a/patches/api/0500-Expanded-Art-API.patch b/patches/api/0500-Expanded-Art-API.patch
new file mode 100644
index 0000000000..171995d80b
--- /dev/null
+++ b/patches/api/0500-Expanded-Art-API.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: kokiriglade <[email protected]>
+Date: Sat, 23 Nov 2024 18:08:13 +0000
+Subject: [PATCH] Expanded Art API
+
+
+diff --git a/src/main/java/org/bukkit/Art.java b/src/main/java/org/bukkit/Art.java
+index 00a290f1bf58cdc2238c13fd5a6048a26b7871da..ed2263450e98460250e431d2ee6debd03204c175 100644
+--- a/src/main/java/org/bukkit/Art.java
++++ b/src/main/java/org/bukkit/Art.java
+@@ -107,6 +107,29 @@ public interface Art extends OldEnum<Art>, Keyed {
+ @NotNull NamespacedKey getKey();
+ // Paper end - deprecate getKey
+
++ // Paper start - name and author components, assetId key
++ /**
++ * Get the painting's title.
++ *
++ * @return the title
++ */
++ net.kyori.adventure.text.@Nullable Component title();
++
++ /**
++ * Get the painting's author.
++ *
++ * @return the author
++ */
++ net.kyori.adventure.text.@Nullable Component author();
++
++ /**
++ * Get the painting's asset id
++ *
++ * @return the asset id
++ */
++ net.kyori.adventure.key.@NotNull Key assetId();
++ // Paper end - name and author components, assetId key
++
+ /**
+ * Get a painting by its numeric ID
+ *
diff --git a/patches/server/0992-Registry-Modification-API.patch b/patches/server/0992-Registry-Modification-API.patch
index 26a3c631f9..73fc9c9d38 100644
--- a/patches/server/0992-Registry-Modification-API.patch
+++ b/patches/server/0992-Registry-Modification-API.patch
@@ -11,7 +11,7 @@ public net.minecraft.resources.RegistryOps lookupProvider
public net.minecraft.resources.RegistryOps$HolderLookupAdapter
diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
-index c6969f968b45eff2aeb44e647712abda10c7c113..d34ffad8a36abbb215491d74ae8d9b490a0bc64f 100644
+index 2f22f46f80b80be43a2cc1cd8afb51f4d1fd0e91..3ec2aa5da045b62809afd2c13fc9ae74189dbdad 100644
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
@@ -3,6 +3,7 @@ package io.papermc.paper.registry;
diff --git a/patches/server/0993-Add-registry-entry-and-builders.patch b/patches/server/0993-Add-registry-entry-and-builders.patch
index 4b036de3ac..4c2d2a81a2 100644
--- a/patches/server/0993-Add-registry-entry-and-builders.patch
+++ b/patches/server/0993-Add-registry-entry-and-builders.patch
@@ -6,19 +6,20 @@ Subject: [PATCH] Add registry entry and builders
Feature patch
diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
-index 3ec2aa5da045b62809afd2c13fc9ae74189dbdad..82fc79fb78be6e5d77060717e28d75cb9e8c388b 100644
+index 3ec2aa5da045b62809afd2c13fc9ae74189dbdad..31d660bbbe62cd2c26715e8d90fef58b8e024e34 100644
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
-@@ -2,6 +2,8 @@ package io.papermc.paper.registry;
+@@ -2,6 +2,9 @@ package io.papermc.paper.registry;
import com.google.common.base.Preconditions;
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.data.PaperPaintingVariantRegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntry;
import io.papermc.paper.registry.tag.TagKey;
import java.util.Collections;
-@@ -81,7 +83,7 @@ public final class PaperRegistries {
+@@ -81,7 +84,7 @@ public final class PaperRegistries {
static {
REGISTRY_ENTRIES = List.of(
// built-ins
@@ -27,7 +28,7 @@ index 3ec2aa5da045b62809afd2c13fc9ae74189dbdad..82fc79fb78be6e5d77060717e28d75cb
entry(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new),
entry(Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, PotionEffectType.class, CraftPotionEffectType::new),
entry(Registries.BLOCK, RegistryKey.BLOCK, BlockType.class, CraftBlockType::new),
-@@ -103,7 +105,7 @@ public final class PaperRegistries {
+@@ -103,10 +106,10 @@ 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(),
@@ -35,7 +36,11 @@ index 3ec2aa5da045b62809afd2c13fc9ae74189dbdad..82fc79fb78be6e5d77060717e28d75cb
+ 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(),
- entry(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT, Art.class, CraftArt::new).delayed(),
+- entry(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT, Art.class, CraftArt::new).delayed(),
++ writable(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT, Art.class, CraftArt::new, PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(),
+ entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new).delayed(),
+
+ // api-only
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..481f5f0cfae1fada3bc3f873fb7e04c3086ea9bf
@@ -339,6 +344,132 @@ index 0000000000000000000000000000000000000000..18f9463ae23ba2d9c65ffb7531a87c92
+ }
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/registry/data/PaperPaintingVariantRegistryEntry.java b/src/main/java/io/papermc/paper/registry/data/PaperPaintingVariantRegistryEntry.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..21cb8c28c0027b4b2446279f6cf9dbedfc8945d5
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/data/PaperPaintingVariantRegistryEntry.java
+@@ -0,0 +1,120 @@
++package io.papermc.paper.registry.data;
++
++import io.papermc.paper.adventure.PaperAdventure;
++import io.papermc.paper.registry.PaperRegistryBuilder;
++import io.papermc.paper.registry.TypedKey;
++import io.papermc.paper.registry.data.util.Conversions;
++import java.util.Optional;
++import java.util.OptionalInt;
++import net.kyori.adventure.key.Key;
++import net.minecraft.network.chat.Component;
++import net.minecraft.resources.ResourceLocation;
++import net.minecraft.world.entity.decoration.PaintingVariant;
++import org.bukkit.Art;
++import org.jetbrains.annotations.Range;
++import org.jspecify.annotations.NullMarked;
++import org.jspecify.annotations.Nullable;
++
++import static io.papermc.paper.registry.data.util.Checks.asArgument;
++import static io.papermc.paper.registry.data.util.Checks.asArgumentRange;
++import static io.papermc.paper.registry.data.util.Checks.asConfigured;
++
++@NullMarked
++public class PaperPaintingVariantRegistryEntry implements PaintingVariantRegistryEntry {
++
++ protected OptionalInt width = OptionalInt.empty();
++ protected OptionalInt height = OptionalInt.empty();
++ protected @Nullable Component title;
++ protected @Nullable Component author;
++ protected @Nullable ResourceLocation assetId;
++
++ protected final Conversions conversions;
++
++ public PaperPaintingVariantRegistryEntry(
++ final Conversions conversions,
++ final TypedKey<Art> ignoredKey,
++ final @Nullable PaintingVariant nms
++ ) {
++ this.conversions = conversions;
++ if(nms == null) return;
++
++ this.width = OptionalInt.of(nms.width());
++ this.height = OptionalInt.of(nms.height());
++ this.title = nms.title().orElse(null);
++ this.author = nms.title().orElse(null);
++ this.assetId = nms.assetId();
++ }
++
++ @Override
++ public @Range(from = 1, to = 16) int width() {
++ return asConfigured(this.width, "width");
++ }
++
++ @Override
++ public @Range(from = 1, to = 16) int height() {
++ return asConfigured(this.height, "height");
++ }
++
++ @Override
++ public net.kyori.adventure.text.@Nullable Component title() {
++ return this.title == null ? null : this.conversions.asAdventure(this.title);
++ }
++
++ @Override
++ public net.kyori.adventure.text.@Nullable Component author() {
++ return this.author == null ? null : this.conversions.asAdventure(this.author);
++ }
++
++ @Override
++ public Key assetId() {
++ return PaperAdventure.asAdventure(asConfigured(this.assetId, "assetId"));
++ }
++
++ public static final class PaperBuilder extends PaperPaintingVariantRegistryEntry implements PaintingVariantRegistryEntry.Builder, PaperRegistryBuilder<PaintingVariant, Art> {
++
++ public PaperBuilder(final Conversions conversions, final TypedKey<Art> key, final @Nullable PaintingVariant nms) {
++ super(conversions, key, nms);
++ }
++
++ @Override
++ public Builder width(@Range(from = 0, to = 16) final int width) {
++ this.width = OptionalInt.of(asArgumentRange(width, "width", 1, 16));
++ return this;
++ }
++
++ @Override
++ public Builder height(@Range(from = 0, to = 16) final int height) {
++ this.height = OptionalInt.of(asArgumentRange(height, "height", 1, 16));
++ return this;
++ }
++
++ @Override
++ public Builder title(final net.kyori.adventure.text.@Nullable Component title) {
++ this.title = this.conversions.asVanilla(title);
++ return this;
++ }
++
++ @Override
++ public Builder author(final net.kyori.adventure.text.@Nullable Component author) {
++ this.author = this.conversions.asVanilla(author);
++ return this;
++ }
++
++ @Override
++ public Builder assetId(final Key assetId) {
++ this.assetId = PaperAdventure.asVanilla(asArgument(assetId, "assetId"));
++ return this;
++ }
++
++ @Override
++ public PaintingVariant build() {
++ return new PaintingVariant(
++ this.width(),
++ this.height(),
++ asConfigured(this.assetId, "assetId"),
++ Optional.ofNullable(this.title),
++ Optional.ofNullable(this.author)
++ );
++ }
++ }
++}
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..3241a94731fe8163876614efdcf30f8b551535af
diff --git a/patches/server/1019-Add-FeatureFlag-API.patch b/patches/server/1019-Add-FeatureFlag-API.patch
index ed2a09b0c6..15ab16d841 100644
--- a/patches/server/1019-Add-FeatureFlag-API.patch
+++ b/patches/server/1019-Add-FeatureFlag-API.patch
@@ -284,7 +284,7 @@ index 6cf790c9fa23ea313423fdaeb7c181bf530828c6..0bcb9df1103050441f8922a688b163dc
public static PotionEffectType minecraftHolderToBukkit(Holder<MobEffect> minecraft) {
return CraftPotionEffectType.minecraftToBukkit(minecraft.value());
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
-index 8af9ac9e22a15457da12f0746d0e411942c278fb..f4ccdd848dd64e97796ef952d2aeacb3219da1bd 100644
+index 2539802c0a02b6a564bdbd58e93ffe5685e775b9..44c9127c71402afd6f98215b9e66fe5b848db50b 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -48,7 +48,7 @@ import org.bukkit.attribute.Attribute;
diff --git a/patches/server/1021-Item-serialization-as-json.patch b/patches/server/1021-Item-serialization-as-json.patch
index ea3fc2b9a6..1e422d7da9 100644
--- a/patches/server/1021-Item-serialization-as-json.patch
+++ b/patches/server/1021-Item-serialization-as-json.patch
@@ -28,7 +28,7 @@ index c80fd4960dfbb0fde37363e7df25b0a5411bdb11..ff7f6916f65466c25a7bde35d64682c1
public static final Codec<CustomData> CODEC_WITH_ID = CODEC.validate(
component -> component.getUnsafe().contains("id", 8) ? DataResult.success(component) : DataResult.error(() -> "Missing id for entity in: " + component)
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
-index f4ccdd848dd64e97796ef952d2aeacb3219da1bd..29d5fa49730d2161bb1b024995a533a08c57939b 100644
+index 44c9127c71402afd6f98215b9e66fe5b848db50b..4c82dae4c2d764c8310832b1a209846d4352bae9 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -527,6 +527,39 @@ public final class CraftMagicNumbers implements UnsafeValues {
diff --git a/patches/server/1035-DataComponent-API.patch b/patches/server/1035-DataComponent-API.patch
index d88ad8497c..1b469c83f7 100644
--- a/patches/server/1035-DataComponent-API.patch
+++ b/patches/server/1035-DataComponent-API.patch
@@ -3589,7 +3589,7 @@ index 0000000000000000000000000000000000000000..62aa1061c35d5358e6dec16a52574b42
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
-index 82fc79fb78be6e5d77060717e28d75cb9e8c388b..a42e3298cac463a431fea973d2961d98a026c148 100644
+index 31d660bbbe62cd2c26715e8d90fef58b8e024e34..7e5d1d4f563dfd4beef9cd73b3670714c96bacaf 100644
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
@@ -2,6 +2,8 @@ package io.papermc.paper.registry;
@@ -3600,8 +3600,8 @@ index 82fc79fb78be6e5d77060717e28d75cb9e8c388b..a42e3298cac463a431fea973d2961d98
+import io.papermc.paper.datacomponent.PaperComponentType;
import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
- import io.papermc.paper.registry.entry.RegistryEntry;
-@@ -97,6 +99,7 @@ public final class PaperRegistries {
+ import io.papermc.paper.registry.data.PaperPaintingVariantRegistryEntry;
+@@ -98,6 +100,7 @@ public final class PaperRegistries {
entry(Registries.ATTRIBUTE, RegistryKey.ATTRIBUTE, Attribute.class, CraftAttribute::new),
entry(Registries.FLUID, RegistryKey.FLUID, Fluid.class, CraftFluid::new),
entry(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT, Sound.class, CraftSound::new),
diff --git a/patches/server/1037-Rewrite-dataconverter-system.patch b/patches/server/1037-Rewrite-dataconverter-system.patch
index 71437e89b2..7f88441f12 100644
--- a/patches/server/1037-Rewrite-dataconverter-system.patch
+++ b/patches/server/1037-Rewrite-dataconverter-system.patch
@@ -30384,7 +30384,7 @@ index b54a3741cd3ba615c83c98985cb4b3c4c586ed7a..b148cf247acdd36f856d0495cde4cc5a
return nbttagcompound;
});
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
-index 29d5fa49730d2161bb1b024995a533a08c57939b..83020837e29ee627b1081daddb4bdee147b95af3 100644
+index 4c82dae4c2d764c8310832b1a209846d4352bae9..507f908916cbeb592496f963b46e4c2121a7b5e3 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -523,7 +523,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
diff --git a/patches/server/1053-Optional-per-player-mob-spawns.patch b/patches/server/1053-Optional-per-player-mob-spawns.patch
index 90f5fa951b..45f24f3663 100644
--- a/patches/server/1053-Optional-per-player-mob-spawns.patch
+++ b/patches/server/1053-Optional-per-player-mob-spawns.patch
@@ -38,7 +38,7 @@ index f1999729cd1c00071c5e1835ee49ea5fcafa7b05..4896c3ba81ead769972fa9efdbe563d4
// Paper end
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-index 38ac7fd8e68f535a5e9bdd816997e865b7694af1..b1ecc218034944533967375d11297705c3fc01a3 100644
+index 10a9406e96ab0ab2404c0e0a9bef08e86a6a12a2..078a14ee8956a56b129be92a26d19c1c536c9589 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -492,7 +492,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
diff --git a/patches/server/1054-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch b/patches/server/1054-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch
index a4379980b1..9980b9f1cb 100644
--- a/patches/server/1054-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch
+++ b/patches/server/1054-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch
@@ -37,7 +37,7 @@ index 4896c3ba81ead769972fa9efdbe563d4006e4401..5b3a886c624b36557cbfaccdc3fb05a4
}
// Paper end
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-index b1ecc218034944533967375d11297705c3fc01a3..aaaadb7be8abf867624a1ca83371595bef4ab633 100644
+index 078a14ee8956a56b129be92a26d19c1c536c9589..61a73a234d9bdd22958ae261b7d0359179f7a57b 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -555,7 +555,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
diff --git a/patches/server/1070-Expanded-Art-API.patch b/patches/server/1070-Expanded-Art-API.patch
new file mode 100644
index 0000000000..a088282574
--- /dev/null
+++ b/patches/server/1070-Expanded-Art-API.patch
@@ -0,0 +1,53 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: kokiriglade <[email protected]>
+Date: Sat, 23 Nov 2024 18:58:49 +0000
+Subject: [PATCH] Expanded Art API
+
+
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftArt.java b/src/main/java/org/bukkit/craftbukkit/CraftArt.java
+index 40af940193d0df66bbcdcf5f46132e304016a4d7..932118f5e5bfc765c852acaf21f9721d8fa5fb6a 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftArt.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftArt.java
+@@ -42,6 +42,9 @@ public class CraftArt implements Art, Handleable<PaintingVariant> {
+
+ private final NamespacedKey key;
+ private final PaintingVariant paintingVariant;
++ private final [email protected] Component adventureTitle; // Paper - name and author components, assetId key
++ private final [email protected] Component adventureAuthor; // Paper - name and author components, assetId key
++ private final [email protected] Key adventureAssetId; // Paper - name and author components, assetId key
+ private final String name;
+ private final int ordinal;
+
+@@ -58,6 +61,9 @@ public class CraftArt implements Art, Handleable<PaintingVariant> {
+ this.name = key.toString();
+ }
+ this.ordinal = CraftArt.count++;
++ this.adventureTitle = paintingVariant.title().map(io.papermc.paper.adventure.PaperAdventure::asAdventure).orElse(null); // Paper - name and author components, assetId key
++ this.adventureAuthor = paintingVariant.author().map(io.papermc.paper.adventure.PaperAdventure::asAdventure).orElse(null); // Paper - name and author components, assetId key
++ this.adventureAssetId = io.papermc.paper.adventure.PaperAdventure.asAdventure(paintingVariant.assetId()); // Paper - name and author components, assetId key
+ }
+
+ @Override
+@@ -75,6 +81,22 @@ public class CraftArt implements Art, Handleable<PaintingVariant> {
+ return this.paintingVariant.height();
+ }
+
++ // Paper start - name and author components, assetId key
++ @Override
++ public [email protected] Component title() {
++ return this.adventureTitle;
++ }
++
++ @Override
++ public [email protected] Component author() {
++ return this.adventureAuthor;
++ }
++
++ public [email protected] Key assetId() {
++ return this.adventureAssetId;
++ }
++ // Paper end - name and author components, assetId key
++
+ @Override
+ public int getId() {
+ return CraftRegistry.getMinecraftRegistry(Registries.PAINTING_VARIANT).getId(this.paintingVariant);