From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 26 May 2023 18:14:44 -0700
Subject: [PATCH] Code Generation

Currently includes generated key holder classes for types
used in the Registry Modification API

diff --git a/build.gradle.kts b/build.gradle.kts
index 768024b2b4584fd7dd86f068c0e79c89ffc5faa1..f11a22ab01e97e51619c96f2d8a78a99297efc59 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,6 +1,7 @@
 plugins {
     `java-library`
     `maven-publish`
+    idea // Paper
 }
 
 java {
@@ -45,6 +46,22 @@ dependencies {
     testImplementation("org.ow2.asm:asm-tree:9.7")
 }
 
+// Paper start
+val generatedApiPath: java.nio.file.Path = rootProject.projectDir.toPath().resolve("paper-api-generator/generated")
+idea {
+    module {
+        generatedSourceDirs.add(generatedApiPath.toFile())
+    }
+}
+sourceSets {
+    main {
+        java {
+            srcDir(generatedApiPath)
+        }
+    }
+}
+// Paper end
+
 configure<PublishingExtension> {
     publications.create<MavenPublication>("maven") {
         from(components["java"])
@@ -121,3 +138,14 @@ tasks.check {
     dependsOn(scanJar)
 }
 // Paper end
+// Paper start
+val scanJarForOldGeneratedCode = tasks.register("scanJarForOldGeneratedCode", io.papermc.paperweight.tasks.ScanJarForOldGeneratedCode::class) {
+    mcVersion.set(providers.gradleProperty("mcVersion"))
+    annotation.set("Lio/papermc/paper/generated/GeneratedFrom;")
+    jarToScan.set(tasks.jar.flatMap { it.archiveFile })
+    classpath.from(configurations.compileClasspath)
+}
+tasks.check {
+    dependsOn(scanJarForOldGeneratedCode)
+}
+// Paper end
diff --git a/src/main/java/io/papermc/paper/generated/GeneratedFrom.java b/src/main/java/io/papermc/paper/generated/GeneratedFrom.java
new file mode 100644
index 0000000000000000000000000000000000000000..2512dba27edfdccbc4430815b6cba048e3d93484
--- /dev/null
+++ b/src/main/java/io/papermc/paper/generated/GeneratedFrom.java
@@ -0,0 +1,21 @@
+package io.papermc.paper.generated;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * Used to mark classes which are generated from
+ * a specific version of minecraft.
+ */
+@ApiStatus.Internal
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface GeneratedFrom {
+
+    String value();
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..a505064565f7f029be8727b1951d9ef67c3acf2c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java
@@ -0,0 +1,128 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Keyed;
+import org.bukkit.Art;
+import org.bukkit.Fluid;
+import org.bukkit.GameEvent;
+import org.bukkit.MusicInstrument;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.block.Biome;
+import org.bukkit.block.banner.PatternType;
+import org.bukkit.damage.DamageType;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Cat;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Frog;
+import org.bukkit.entity.Villager;
+import org.bukkit.entity.Wolf;
+import org.bukkit.entity.memory.MemoryKey;
+import org.bukkit.generator.structure.Structure;
+import org.bukkit.generator.structure.StructureType;
+import org.bukkit.inventory.meta.trim.TrimMaterial;
+import org.bukkit.inventory.meta.trim.TrimPattern;
+import org.bukkit.map.MapCursor;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.potion.PotionType;
+
+import static io.papermc.paper.registry.RegistryKeyImpl.create;
+
+/**
+ * Identifier for a specific registry. For use with
+ * {@link TypedKey} and the registry modification API.
+ * <p>
+ * There are 2 types of registries, identified as "built-in"
+ * or "data-driven". The former are not changeable by datapacks (which
+ * doesn't necessarily mean they aren't changeable in the API) and
+ * are loaded first. "Data-driven" registries are all created by
+ * reading in data from the vanilla and other datapacks.
+ *
+ * @param <T> the value type
+ */
+@SuppressWarnings("unused")
+public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl {
+
+    /* ******************* *
+     * Built-in Registries *
+     * ******************* */
+    /**
+     * Built-in registry for game events
+     * @see io.papermc.paper.registry.keys.GameEventKeys
+     */
+    RegistryKey<GameEvent> GAME_EVENT = create("game_event");
+    /**
+     * Built-in registry for structure types.
+     * @see io.papermc.paper.registry.keys.StructureTypeKeys
+     */
+    RegistryKey<StructureType> STRUCTURE_TYPE = create("worldgen/structure_type");
+    /**
+     * Built-in registry for instruments.
+     * @see io.papermc.paper.registry.keys.InstrumentKeys
+     */
+    RegistryKey<MusicInstrument> INSTRUMENT = create("instrument");
+    /**
+     * Built-in registry for enchantments.
+     * @see io.papermc.paper.registry.keys.EnchantmentKeys
+     */
+    RegistryKey<Enchantment> ENCHANTMENT = create("enchantment");
+    /**
+     * Built-in registry for potion effect types (mob effects).
+     * @see io.papermc.paper.registry.keys.MobEffectKeys
+     */
+    RegistryKey<PotionEffectType> MOB_EFFECT = create("mob_effect");
+
+
+    /* ********************** *
+     * Data-driven Registries *
+     * ********************** */
+    /**
+     * Data-driven registry for biomes.
+     * @see io.papermc.paper.registry.keys.BiomeKeys
+     */
+    RegistryKey<Biome> BIOME = create("worldgen/biome");
+    /**
+     * Data-driven registry for structures.
+     * @see io.papermc.paper.registry.keys.StructureKeys
+     */
+    RegistryKey<Structure> STRUCTURE = create("worldgen/structure");
+    /**
+     * Data-driven registry for trim materials.
+     * @see io.papermc.paper.registry.keys.TrimMaterialKeys
+     */
+    RegistryKey<TrimMaterial> TRIM_MATERIAL = create("trim_material");
+    /**
+     * Data-driven registry for trim patterns.
+     * @see io.papermc.paper.registry.keys.TrimPatternKeys
+     */
+    RegistryKey<TrimPattern> TRIM_PATTERN = create("trim_pattern");
+    /**
+     * Data-driven registry for damage types.
+     * @see io.papermc.paper.registry.keys.DamageTypeKeys
+     */
+    RegistryKey<DamageType> DAMAGE_TYPE = create("damage_type");
+    /**
+     * Data-driven registry for wolf variants
+     * @see io.papermc.paper.registry.keys.WolfVariantKeys
+     */
+    RegistryKey<Wolf.Variant> WOLF_VARIANT = create("wolf_variant");
+
+
+    /* ******************* *
+     * API-only Registries *
+     * ******************* */
+    RegistryKey<Art> PAINTING_VARIANT = create("painting_variant");
+    RegistryKey<Attribute> ATTRIBUTE = create("attribute");
+    RegistryKey<PatternType> BANNER_PATTERN = create("banner_pattern");
+    RegistryKey<Cat.Type> CAT_VARIANT = create("cat_variant");
+    RegistryKey<EntityType> ENTITY_TYPE = create("entity_type");
+    RegistryKey<Particle> PARTICLE_TYPE = create("particle_type");
+    RegistryKey<PotionType> POTION = create("potion");
+    RegistryKey<Sound> SOUND_EVENT = create("sound_event");
+    RegistryKey<Villager.Profession> VILLAGER_PROFESSION = create("villager_profession");
+    RegistryKey<Villager.Type> VILLAGER_TYPE = create("villager_type");
+    RegistryKey<MemoryKey<?>> MEMORY_MODULE_TYPE = create("memory_module_type");
+    RegistryKey<Fluid> FLUID = create("fluid");
+    RegistryKey<Frog.Variant> FROG_VARIANT = create("frog_variant");
+    RegistryKey<MapCursor.Type> MAP_DECORATION_TYPE = create("map_decoration_type");
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..791813220b2504214b1adecc69093cd600fb0f8c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
@@ -0,0 +1,24 @@
+package io.papermc.paper.registry;
+
+import com.google.common.collect.Sets;
+import java.util.Set;
+import net.kyori.adventure.key.Key;
+import org.intellij.lang.annotations.Subst;
+import org.jetbrains.annotations.NotNull;
+
+record RegistryKeyImpl<T>(@NotNull Key key) implements RegistryKey<T> {
+
+    static final Set<RegistryKey<?>> REGISTRY_KEYS = Sets.newIdentityHashSet();
+
+    static <T> RegistryKey<T> create(@Subst("some_key") final String key) {
+        final RegistryKey<T> registryKey = createInternal(key);
+        REGISTRY_KEYS.add(registryKey);
+        return registryKey;
+    }
+
+    // creates the key without adding to the internal set of keys
+    static <T> RegistryKey<T> createInternal(@Subst("some_key") final String key) {
+        return new RegistryKeyImpl<>(Key.key(Key.MINECRAFT_NAMESPACE, key));
+    }
+
+}
diff --git a/src/main/java/io/papermc/paper/registry/TypedKey.java b/src/main/java/io/papermc/paper/registry/TypedKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f5a062ba7ee7173468ecea3c1855a233bf3855e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/TypedKey.java
@@ -0,0 +1,44 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.key.Keyed;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Represents a key for a value in a specific registry.
+ *
+ * @param <T> the value type for the registry
+ */
+@ApiStatus.Experimental
+public sealed interface TypedKey<T> extends Keyed permits TypedKeyImpl {
+
+    /**
+     * Gets the key for the value in the registry.
+     *
+     * @return the value's key
+     */
+    @Override
+    @NotNull Key key();
+
+    /**
+     * Gets the registry key for the value this key
+     * represents.
+     *
+     * @return the registry key
+     */
+    @NotNull RegistryKey<T> registryKey();
+
+    /**
+     * Create a typed key from a key and a registry key.
+     *
+     * @param registryKey the registry this key is for
+     * @param key the key for the value in the registry
+     * @param <T> value type
+     * @return a new key for the value key and registry key
+     */
+    @ApiStatus.Experimental
+    static <T> @NotNull TypedKey<T> create(final @NotNull RegistryKey<T> registryKey, final @NotNull Key key) {
+        return new TypedKeyImpl<>(key, registryKey);
+    }
+}
diff --git a/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a97b3359c4ece5c29131da7c3f208aaa8fab66e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java
@@ -0,0 +1,8 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.key.Keyed;
+import org.jetbrains.annotations.NotNull;
+
+record TypedKeyImpl<T>(@NotNull Key key, @NotNull RegistryKey<T> registryKey) implements TypedKey<T> {
+}
diff --git a/src/main/java/org/bukkit/MinecraftExperimental.java b/src/main/java/org/bukkit/MinecraftExperimental.java
index b6f4810e387c22c4a70609ea1d605130245689a5..03824ae54e1bdb8b14f79b3c5e0294ae725e43f8 100644
--- a/src/main/java/org/bukkit/MinecraftExperimental.java
+++ b/src/main/java/org/bukkit/MinecraftExperimental.java
@@ -47,6 +47,6 @@ public @interface MinecraftExperimental {
     @ApiStatus.Internal
     public enum Requires {
 
-        UPDATE_1_21
+        UPDATE_1_21, BUNDLE, TRADE_REBALANCE // Paper
     }
 }
