From d257d03a16cd92ef7d9a57aba1c9856379f96d89 Mon Sep 17 00:00:00 2001
From: Bukkit/Spigot <noreply+git-bukkit@papermc.io>
Date: Sat, 21 Oct 2023 13:42:07 +1100
Subject: [PATCH] #923: Back Particle by a minecraft registry

By: DerFrZocker <derrieple@gmail.com>
---
 .../src/main/java/org/bukkit/Particle.java    | 242 ++++++++++--------
 .../src/main/java/org/bukkit/Registry.java    |   6 +
 2 files changed, 143 insertions(+), 105 deletions(-)

diff --git a/paper-api/src/main/java/org/bukkit/Particle.java b/paper-api/src/main/java/org/bukkit/Particle.java
index 73b782c397..e2adb9901c 100644
--- a/paper-api/src/main/java/org/bukkit/Particle.java
+++ b/paper-api/src/main/java/org/bukkit/Particle.java
@@ -6,151 +6,173 @@ import org.bukkit.inventory.ItemStack;
 import org.bukkit.material.MaterialData;
 import org.jetbrains.annotations.NotNull;
 
-public enum Particle {
-    EXPLOSION_NORMAL,
-    EXPLOSION_LARGE,
-    EXPLOSION_HUGE,
-    FIREWORKS_SPARK,
-    WATER_BUBBLE,
-    WATER_SPLASH,
-    WATER_WAKE,
-    SUSPENDED,
-    SUSPENDED_DEPTH,
-    CRIT,
-    CRIT_MAGIC,
-    SMOKE_NORMAL,
-    SMOKE_LARGE,
-    SPELL,
-    SPELL_INSTANT,
-    SPELL_MOB,
-    SPELL_MOB_AMBIENT,
-    SPELL_WITCH,
-    DRIP_WATER,
-    DRIP_LAVA,
-    VILLAGER_ANGRY,
-    VILLAGER_HAPPY,
-    TOWN_AURA,
-    NOTE,
-    PORTAL,
-    ENCHANTMENT_TABLE,
-    FLAME,
-    LAVA,
-    CLOUD,
+public enum Particle implements Keyed {
+    EXPLOSION_NORMAL("poof"),
+    EXPLOSION_LARGE("explosion"),
+    EXPLOSION_HUGE("explosion_emitter"),
+    FIREWORKS_SPARK("firework"),
+    WATER_BUBBLE("bubble"),
+    WATER_SPLASH("splash"),
+    WATER_WAKE("fishing"),
+    SUSPENDED("underwater"),
+    SUSPENDED_DEPTH("underwater", false),
+    CRIT("crit"),
+    CRIT_MAGIC("enchanted_hit"),
+    SMOKE_NORMAL("smoke"),
+    SMOKE_LARGE("large_smoke"),
+    SPELL("effect"),
+    SPELL_INSTANT("instant_effect"),
+    SPELL_MOB("entity_effect"),
+    SPELL_MOB_AMBIENT("ambient_entity_effect"),
+    SPELL_WITCH("witch"),
+    DRIP_WATER("dripping_water"),
+    DRIP_LAVA("dripping_lava"),
+    VILLAGER_ANGRY("angry_villager"),
+    VILLAGER_HAPPY("happy_villager"),
+    TOWN_AURA("mycelium"),
+    NOTE("note"),
+    PORTAL("portal"),
+    ENCHANTMENT_TABLE("enchant"),
+    FLAME("flame"),
+    LAVA("lava"),
+    CLOUD("cloud"),
     /**
      * Uses {@link Particle.DustOptions} as DataType
      */
-    REDSTONE(DustOptions.class),
-    SNOWBALL,
-    SNOW_SHOVEL,
-    SLIME,
-    HEART,
+    REDSTONE("dust", DustOptions.class),
+    SNOWBALL("item_snowball"),
+    SNOW_SHOVEL("item_snowball", false),
+    SLIME("item_slime"),
+    HEART("heart"),
     /**
      * Uses {@link ItemStack} as DataType
      */
-    ITEM_CRACK(ItemStack.class),
+    ITEM_CRACK("item", ItemStack.class),
     /**
      * Uses {@link BlockData} as DataType
      */
-    BLOCK_CRACK(BlockData.class),
+    BLOCK_CRACK("block", BlockData.class),
     /**
      * Uses {@link BlockData} as DataType
      */
-    BLOCK_DUST(BlockData.class),
-    WATER_DROP,
-    MOB_APPEARANCE,
-    DRAGON_BREATH,
-    END_ROD,
-    DAMAGE_INDICATOR,
-    SWEEP_ATTACK,
+    BLOCK_DUST("block", BlockData.class, false),
+    WATER_DROP("rain"),
+    MOB_APPEARANCE("elder_guardian"),
+    DRAGON_BREATH("dragon_breath"),
+    END_ROD("end_rod"),
+    DAMAGE_INDICATOR("damage_indicator"),
+    SWEEP_ATTACK("sweep_attack"),
     /**
      * Uses {@link BlockData} as DataType
      */
-    FALLING_DUST(BlockData.class),
-    TOTEM,
-    SPIT,
-    SQUID_INK,
-    BUBBLE_POP,
-    CURRENT_DOWN,
-    BUBBLE_COLUMN_UP,
-    NAUTILUS,
-    DOLPHIN,
-    SNEEZE,
-    CAMPFIRE_COSY_SMOKE,
-    CAMPFIRE_SIGNAL_SMOKE,
-    COMPOSTER,
-    FLASH,
-    FALLING_LAVA,
-    LANDING_LAVA,
-    FALLING_WATER,
-    DRIPPING_HONEY,
-    FALLING_HONEY,
-    LANDING_HONEY,
-    FALLING_NECTAR,
-    SOUL_FIRE_FLAME,
-    ASH,
-    CRIMSON_SPORE,
-    WARPED_SPORE,
-    SOUL,
-    DRIPPING_OBSIDIAN_TEAR,
-    FALLING_OBSIDIAN_TEAR,
-    LANDING_OBSIDIAN_TEAR,
-    REVERSE_PORTAL,
-    WHITE_ASH,
+    FALLING_DUST("falling_dust", BlockData.class),
+    TOTEM("totem_of_undying"),
+    SPIT("spit"),
+    SQUID_INK("squid_ink"),
+    BUBBLE_POP("bubble_pop"),
+    CURRENT_DOWN("current_down"),
+    BUBBLE_COLUMN_UP("bubble_column_up"),
+    NAUTILUS("nautilus"),
+    DOLPHIN("dolphin"),
+    SNEEZE("sneeze"),
+    CAMPFIRE_COSY_SMOKE("campfire_cosy_smoke"),
+    CAMPFIRE_SIGNAL_SMOKE("campfire_signal_smoke"),
+    COMPOSTER("composter"),
+    FLASH("flash"),
+    FALLING_LAVA("falling_lava"),
+    LANDING_LAVA("landing_lava"),
+    FALLING_WATER("falling_water"),
+    DRIPPING_HONEY("dripping_honey"),
+    FALLING_HONEY("falling_honey"),
+    LANDING_HONEY("landing_honey"),
+    FALLING_NECTAR("falling_nectar"),
+    SOUL_FIRE_FLAME("soul_fire_flame"),
+    ASH("ash"),
+    CRIMSON_SPORE("crimson_spore"),
+    WARPED_SPORE("warped_spore"),
+    SOUL("soul"),
+    DRIPPING_OBSIDIAN_TEAR("dripping_obsidian_tear"),
+    FALLING_OBSIDIAN_TEAR("falling_obsidian_tear"),
+    LANDING_OBSIDIAN_TEAR("landing_obsidian_tear"),
+    REVERSE_PORTAL("reverse_portal"),
+    WHITE_ASH("white_ash"),
     /**
      * Uses {@link DustTransition} as DataType
      */
-    DUST_COLOR_TRANSITION(DustTransition.class),
+    DUST_COLOR_TRANSITION("dust_color_transition", DustTransition.class),
     /**
      * Uses {@link Vibration} as DataType
      */
-    VIBRATION(Vibration.class),
-    FALLING_SPORE_BLOSSOM,
-    SPORE_BLOSSOM_AIR,
-    SMALL_FLAME,
-    SNOWFLAKE,
-    DRIPPING_DRIPSTONE_LAVA,
-    FALLING_DRIPSTONE_LAVA,
-    DRIPPING_DRIPSTONE_WATER,
-    FALLING_DRIPSTONE_WATER,
-    GLOW_SQUID_INK,
-    GLOW,
-    WAX_ON,
-    WAX_OFF,
-    ELECTRIC_SPARK,
-    SCRAPE,
-    SONIC_BOOM,
-    SCULK_SOUL,
-    SCULK_CHARGE(Float.class),
-    SCULK_CHARGE_POP,
-    SHRIEK(Integer.class),
-    CHERRY_LEAVES,
-    EGG_CRACK,
+    VIBRATION("vibration", Vibration.class),
+    FALLING_SPORE_BLOSSOM("falling_spore_blossom"),
+    SPORE_BLOSSOM_AIR("spore_blossom_air"),
+    SMALL_FLAME("small_flame"),
+    SNOWFLAKE("snowflake"),
+    DRIPPING_DRIPSTONE_LAVA("dripping_dripstone_lava"),
+    FALLING_DRIPSTONE_LAVA("falling_dripstone_lava"),
+    DRIPPING_DRIPSTONE_WATER("dripping_dripstone_water"),
+    FALLING_DRIPSTONE_WATER("falling_dripstone_water"),
+    GLOW_SQUID_INK("glow_squid_ink"),
+    GLOW("glow"),
+    WAX_ON("wax_on"),
+    WAX_OFF("wax_off"),
+    ELECTRIC_SPARK("electric_spark"),
+    SCRAPE("scrape"),
+    SONIC_BOOM("sonic_boom"),
+    SCULK_SOUL("sculk_soul"),
+    /**
+     * Use {@link Float} as DataType
+     */
+    SCULK_CHARGE("sculk_charge", Float.class),
+    SCULK_CHARGE_POP("sculk_charge_pop"),
+    /**
+     * Use {@link Integer} as DataType
+     */
+    SHRIEK("shriek", Integer.class),
+    CHERRY_LEAVES("cherry_leaves"),
+    EGG_CRACK("egg_crack"),
     /**
      * Uses {@link BlockData} as DataType
      */
-    BLOCK_MARKER(BlockData.class),
+    BLOCK_MARKER("block_marker", BlockData.class),
     // ----- Legacy Separator -----
     /**
      * Uses {@link MaterialData} as DataType
      */
-    LEGACY_BLOCK_CRACK(MaterialData.class),
+    LEGACY_BLOCK_CRACK(null, MaterialData.class, false),
     /**
      * Uses {@link MaterialData} as DataType
      */
-    LEGACY_BLOCK_DUST(MaterialData.class),
+    LEGACY_BLOCK_DUST(null, MaterialData.class, false),
     /**
      * Uses {@link MaterialData} as DataType
      */
-    LEGACY_FALLING_DUST(MaterialData.class);
+    LEGACY_FALLING_DUST(null, MaterialData.class, false);
 
+    private final NamespacedKey key;
     private final Class<?> dataType;
+    final boolean register;
 
-    Particle() {
-        dataType = Void.class;
+    Particle(String key) {
+        this(key, Void.class);
     }
 
-    Particle(/*@NotNull*/ Class<?> data) {
+    Particle(String key, boolean register) {
+        this(key, Void.class, register);
+    }
+
+    Particle(String key, /*@NotNull*/ Class<?> data) {
+        this(key, data, true);
+    }
+
+    Particle(String key, /*@NotNull*/ Class<?> data, boolean register) {
+        if (key != null) {
+            this.key = NamespacedKey.minecraft(key);
+        } else {
+            this.key = null;
+        }
         dataType = data;
+        this.register = register;
     }
 
     /**
@@ -162,6 +184,16 @@ public enum Particle {
         return dataType;
     }
 
+    @NotNull
+    @Override
+    public NamespacedKey getKey() {
+        if (key == null) {
+            throw new UnsupportedOperationException("Cannot get key from legacy particle");
+        }
+
+        return key;
+    }
+
     /**
      * Options which can be applied to redstone dust particles - a particle
      * color and size.
diff --git a/paper-api/src/main/java/org/bukkit/Registry.java b/paper-api/src/main/java/org/bukkit/Registry.java
index f79f4f20ee..c373614a86 100644
--- a/paper-api/src/main/java/org/bukkit/Registry.java
+++ b/paper-api/src/main/java/org/bukkit/Registry.java
@@ -156,6 +156,12 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
      * @see Material
      */
     Registry<Material> MATERIAL = new SimpleRegistry<>(Material.class, (mat) -> !mat.isLegacy());
+    /**
+     * Server particles.
+     *
+     * @see Particle
+     */
+    Registry<Particle> PARTICLE_TYPE = new SimpleRegistry<>(Particle.class, (par) -> par.register);
     /**
      * Server potions.
      *