PaperMC/patches/server/1055-Tag-Lifecycle-Events.patch
Bjarne Koll d1a72eac31
Updated Upstream (Bukkit/CraftBukkit/Spigot) (#11405)
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:
1fc1020a PR-1049: Add MenuType API
8ae2e3be PR-1055: Expand riptiding API
cac68bfb SPIGOT-7890: AttributeModifier#getUniqueId() doesn't match the UUID passed to its constructor
7004fcf2 SPIGOT-7886: Fix mistake in AttributeModifier UUID shim
1ac7f950 PR-1054: Add FireworkMeta#hasPower
4cfb565f SPIGOT-7873: Add powered state for skulls

CraftBukkit Changes:
bbb30e7a8 SPIGOT-7894: NPE when sending tile entity update
ba21e9472 SPIGOT-7895: PlayerItemBreakEvent not firing
0fb24bbe0 SPIGOT-7875: Fix PlayerItemConsumeEvent cancellation causing client-side desync
815066449 SPIGOT-7891: Can't remove second ingredient of MerchantRecipe
45c206f2c PR-1458: Add MenuType API
19c8ef9ae SPIGOT-7867: Merchant instanceof AbstractVillager always returns false
4e006d28f PR-1468: Expand riptiding API
bd8aded7d Ignore checks in CraftPlayerProfile for ResolvableProfile used in profile components
8679620b5 SPIGOT-7889: Fix tool component deserialisation without speed and/or correct-for-drops
8d5222691 SPIGOT-7882, PR-1467: Fix conversion of name in Profile Component to empty if it is missing
63f91669a SPIGOT-7887: Remove duplicate ProjectileHitEvent for fireballs
7070de8c8 SPIGOT-7878: Server#getLootTable does not return null on invalid loot table
060ee6cae SPIGOT-7876: Can't kick player or disconnect player in PlayerLoginEvent when checking for cookies
7ccb86cc0 PR-1465: Add FireworkMeta#hasPower
804ad6491 SPIGOT-7873: Add powered state for skulls
f9610cdcb Improve minecart movement

Spigot Changes:
a759b629 Rebuild patches

Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
2024-09-15 21:39:53 +02:00

537 lines
27 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 20 Jun 2024 09:40:57 -0700
Subject: [PATCH] Tag Lifecycle Events
== AT ==
public net/minecraft/tags/TagEntry id
public net/minecraft/tags/TagEntry tag
public net/minecraft/tags/TagEntry required
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java
index 7e84e0acd50ef04fa1ee2577f49e51c63f5ba5c3..05ceb6a0556c5e958237cd8e17525343dc3e8458 100644
--- a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProviderImpl.java
@@ -13,6 +13,8 @@ public final class LifecycleEventTypeProviderImpl implements LifecycleEventTypeP
return (LifecycleEventTypeProviderImpl) LifecycleEventTypeProvider.provider();
}
+ private final PaperTagEventTypeProvider provider = new PaperTagEventTypeProvider();
+
@Override
public <O extends LifecycleEventOwner, E extends LifecycleEvent> LifecycleEventType.Monitorable<O, E> monitor(final String name, final Class<? extends O> ownerType) {
return LifecycleEventRunner.INSTANCE.addEventType(new MonitorableLifecycleEventType<>(name, ownerType));
@@ -22,4 +24,9 @@ public final class LifecycleEventTypeProviderImpl implements LifecycleEventTypeP
public <O extends LifecycleEventOwner, E extends LifecycleEvent> LifecycleEventType.Prioritizable<O, E> prioritized(final String name, final Class<? extends O> ownerType) {
return LifecycleEventRunner.INSTANCE.addEventType(new PrioritizableLifecycleEventType.Simple<>(name, ownerType));
}
+
+ @Override
+ public PaperTagEventTypeProvider tagProvider() {
+ return this.provider;
+ }
}
diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PaperTagEventTypeProvider.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PaperTagEventTypeProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..1cf4a3caa8d630e95eb569eef2cd577bba1a97a9
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/PaperTagEventTypeProvider.java
@@ -0,0 +1,24 @@
+package io.papermc.paper.plugin.lifecycle.event.types;
+
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.tag.PaperTagListenerManager;
+import io.papermc.paper.tag.PostFlattenTagRegistrar;
+import io.papermc.paper.tag.PreFlattenTagRegistrar;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public class PaperTagEventTypeProvider implements TagEventTypeProvider {
+
+ @Override
+ public <T> PrioritizableLifecycleEventType.Simple<BootstrapContext, ReloadableRegistrarEvent<PreFlattenTagRegistrar<T>>> preFlatten(final RegistryKey<T> registryKey) {
+ return PaperTagListenerManager.INSTANCE.getPreFlattenType(registryKey);
+ }
+
+ @Override
+ public <T> PrioritizableLifecycleEventType.Simple<BootstrapContext, ReloadableRegistrarEvent<PostFlattenTagRegistrar<T>>> postFlatten(final RegistryKey<T> registryKey) {
+ return PaperTagListenerManager.INSTANCE.getPostFlattenType(registryKey);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/tag/PaperPostFlattenTagRegistrar.java b/src/main/java/io/papermc/paper/tag/PaperPostFlattenTagRegistrar.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc37618cbbad7f21d65c7753f4dd4416042d2146
--- /dev/null
+++ b/src/main/java/io/papermc/paper/tag/PaperPostFlattenTagRegistrar.java
@@ -0,0 +1,118 @@
+package io.papermc.paper.tag;
+
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableMap;
+import io.papermc.paper.adventure.PaperAdventure;
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.registrar.PaperRegistrar;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.TypedKey;
+import io.papermc.paper.registry.tag.TagKey;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.function.Function;
+import net.minecraft.resources.ResourceLocation;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@SuppressWarnings("BoundedWildcard")
+@DefaultQualifier(NonNull.class)
+public class PaperPostFlattenTagRegistrar<M, T> implements PaperRegistrar<BootstrapContext>, PostFlattenTagRegistrar<T> {
+
+ public final Map<ResourceLocation, Collection<M>> tags;
+ private final Function<ResourceLocation, Optional<? extends M>> fromIdConverter;
+ private final Function<M, ResourceLocation> toIdConverter;
+ private final RegistryKey<T> registryKey;
+
+ public PaperPostFlattenTagRegistrar(
+ final Map<ResourceLocation, Collection<M>> tags,
+ final TagEventConfig<M, T> config
+ ) {
+ this.tags = tags;
+ this.fromIdConverter = config.fromIdConverter();
+ this.toIdConverter = config.toIdConverter();
+ this.registryKey = config.apiRegistryKey();
+ }
+
+ @Override
+ public void setCurrentContext(final @Nullable BootstrapContext owner) {
+ }
+
+ @Override
+ public RegistryKey<T> registryKey() {
+ return this.registryKey;
+ }
+
+ @Override
+ public Map<TagKey<T>, Collection<TypedKey<T>>> getAllTags() {
+ final ImmutableMap.Builder<TagKey<T>, Collection<TypedKey<T>>> tags = ImmutableMap.builderWithExpectedSize(this.tags.size());
+ for (final Map.Entry<ResourceLocation, Collection<M>> entry : this.tags.entrySet()) {
+ final TagKey<T> key = TagKey.create(this.registryKey, CraftNamespacedKey.fromMinecraft(entry.getKey()));
+ tags.put(key, this.convert(entry.getValue()));
+ }
+ return tags.build();
+ }
+
+ private Collection<TypedKey<T>> convert(final Collection<M> nms) {
+ return Collections.unmodifiableCollection(
+ Collections2.transform(nms, m -> this.convert(this.toIdConverter.apply(m)))
+ );
+ }
+
+ private TypedKey<T> convert(final ResourceLocation location) {
+ return TypedKey.create(this.registryKey, CraftNamespacedKey.fromMinecraft(location));
+ }
+
+ private M convert(final TypedKey<T> key) {
+ final Optional<? extends M> optional = this.fromIdConverter.apply(PaperAdventure.asVanilla(key.key()));
+ if (optional.isEmpty()) {
+ throw new IllegalArgumentException(key + " doesn't exist");
+ }
+ return optional.get();
+ }
+
+ @Override
+ public boolean hasTag(final TagKey<T> tagKey) {
+ return this.tags.containsKey(PaperAdventure.asVanilla(tagKey.key()));
+ }
+
+ private Collection<M> getNmsTag(final TagKey<T> tagKey, final boolean create) {
+ final ResourceLocation vanillaKey = PaperAdventure.asVanilla(tagKey.key());
+ Collection<M> tag = this.tags.get(vanillaKey);
+ if (tag == null) {
+ if (create) {
+ tag = this.tags.computeIfAbsent(vanillaKey, k -> new ArrayList<>());
+ } else {
+ throw new NoSuchElementException("Tag " + tagKey + " is not present");
+ }
+ }
+ return tag;
+ }
+
+ @Override
+ public Collection<TypedKey<T>> getTag(final TagKey<T> tagKey) {
+ return this.convert(this.getNmsTag(tagKey, false));
+ }
+
+ @Override
+ public void addToTag(final TagKey<T> tagKey, final Collection<TypedKey<T>> values) {
+ final Collection<M> nmsTag = new ArrayList<>(this.getNmsTag(tagKey, true));
+ for (final TypedKey<T> key : values) {
+ nmsTag.add(this.convert(key));
+ }
+ this.tags.put(PaperAdventure.asVanilla(tagKey.key()), nmsTag);
+ }
+
+ @Override
+ public void setTag(final TagKey<T> tagKey, final Collection<TypedKey<T>> values) {
+ final List<M> newList = List.copyOf(Collections2.transform(values, this::convert));
+ this.tags.put(PaperAdventure.asVanilla(tagKey.key()), newList);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/tag/PaperPreFlattenTagRegistrar.java b/src/main/java/io/papermc/paper/tag/PaperPreFlattenTagRegistrar.java
new file mode 100644
index 0000000000000000000000000000000000000000..44111b55eaa6d1cc93e2c556b23bb5c97953caac
--- /dev/null
+++ b/src/main/java/io/papermc/paper/tag/PaperPreFlattenTagRegistrar.java
@@ -0,0 +1,128 @@
+package io.papermc.paper.tag;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import io.papermc.paper.adventure.PaperAdventure;
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.registrar.PaperRegistrar;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.tag.TagKey;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.tags.TagLoader;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@SuppressWarnings("BoundedWildcard")
+@DefaultQualifier(NonNull.class)
+public class PaperPreFlattenTagRegistrar<T> implements PaperRegistrar<BootstrapContext>, PreFlattenTagRegistrar<T> {
+
+ public final Map<ResourceLocation, List<TagLoader.EntryWithSource>> tags;
+ private final RegistryKey<T> registryKey;
+
+ private @Nullable BootstrapContext owner;
+
+ public PaperPreFlattenTagRegistrar(
+ final Map<ResourceLocation, List<TagLoader.EntryWithSource>> tags,
+ final TagEventConfig<?, T> config
+ ) {
+ this.tags = new HashMap<>(tags);
+ this.registryKey = config.apiRegistryKey();
+ }
+
+ @Override
+ public void setCurrentContext(final @Nullable BootstrapContext owner) {
+ this.owner = owner;
+ }
+
+ @Override
+ public RegistryKey<T> registryKey() {
+ return this.registryKey;
+ }
+
+ @Override
+ public Map<TagKey<T>, Collection<TagEntry<T>>> getAllTags() {
+ final ImmutableMap.Builder<TagKey<T>, Collection<io.papermc.paper.tag.TagEntry<T>>> builder = ImmutableMap.builderWithExpectedSize(this.tags.size());
+ for (final Map.Entry<ResourceLocation, List<TagLoader.EntryWithSource>> entry : this.tags.entrySet()) {
+ final TagKey<T> key = TagKey.create(this.registryKey, CraftNamespacedKey.fromMinecraft(entry.getKey()));
+ builder.put(key, convert(entry.getValue()));
+ }
+ return builder.build();
+ }
+
+ private static <T> List<io.papermc.paper.tag.TagEntry<T>> convert(final List<TagLoader.EntryWithSource> nmsEntries) {
+ return Collections.unmodifiableList(Lists.transform(nmsEntries, PaperPreFlattenTagRegistrar::convert));
+ }
+
+ private static <T> io.papermc.paper.tag.TagEntry<T> convert(final TagLoader.EntryWithSource nmsEntry) {
+ return new TagEntryImpl<>(CraftNamespacedKey.fromMinecraft(nmsEntry.entry().id), nmsEntry.entry().tag, nmsEntry.entry().required);
+ }
+
+ private TagLoader.EntryWithSource convert(final TagEntry<T> entry) {
+ Preconditions.checkState(this.owner != null, "Owner is not set");
+ final ResourceLocation vanilla = PaperAdventure.asVanilla(entry.key());
+ final net.minecraft.tags.TagEntry nmsEntry;
+ if (entry.isTag()) {
+ if (entry.isRequired()) {
+ nmsEntry = net.minecraft.tags.TagEntry.tag(vanilla);
+ } else {
+ nmsEntry = net.minecraft.tags.TagEntry.optionalTag(vanilla);
+ }
+ } else {
+ if (entry.isRequired()) {
+ nmsEntry = net.minecraft.tags.TagEntry.element(vanilla);
+ } else {
+ nmsEntry = net.minecraft.tags.TagEntry.optionalElement(vanilla);
+ }
+ }
+ return new TagLoader.EntryWithSource(nmsEntry, this.owner.getPluginMeta().getDisplayName());
+ }
+
+ @Override
+ public boolean hasTag(final TagKey<T> tagKey) {
+ return this.tags.containsKey(PaperAdventure.asVanilla(tagKey.key()));
+ }
+
+ private List<TagLoader.EntryWithSource> getNmsTag(final TagKey<T> tagKey, boolean create) {
+ final ResourceLocation vanillaKey = PaperAdventure.asVanilla(tagKey.key());
+ List<TagLoader.EntryWithSource> tag = this.tags.get(vanillaKey);
+ if (tag == null) {
+ if (create) {
+ tag = this.tags.computeIfAbsent(vanillaKey, k -> new ArrayList<>());
+ } else {
+ throw new NoSuchElementException("Tag " + tagKey + " is not present");
+ }
+ }
+ return tag;
+ }
+
+ @Override
+ public List<TagEntry<T>> getTag(final TagKey<T> tagKey) {
+ return convert(this.getNmsTag(tagKey, false));
+ }
+
+ @Override
+ public void addToTag(final TagKey<T> tagKey, final Collection<TagEntry<T>> entries) {
+ final List<TagLoader.EntryWithSource> nmsTag = new ArrayList<>(this.getNmsTag(tagKey, true));
+ for (final TagEntry<T> tagEntry : entries) {
+ nmsTag.add(this.convert(tagEntry));
+ }
+ this.tags.put(PaperAdventure.asVanilla(tagKey.key()), nmsTag);
+ }
+
+ @Override
+ public void setTag(final TagKey<T> tagKey, final Collection<TagEntry<T>> entries) {
+ final List<TagLoader.EntryWithSource> newList = List.copyOf(Collections2.transform(entries, this::convert));
+ this.tags.put(PaperAdventure.asVanilla(tagKey.key()), newList);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/tag/PaperTagListenerManager.java b/src/main/java/io/papermc/paper/tag/PaperTagListenerManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3e4019f9d55d3cce34248a806bf0ccb37c8e7b1
--- /dev/null
+++ b/src/main/java/io/papermc/paper/tag/PaperTagListenerManager.java
@@ -0,0 +1,105 @@
+package io.papermc.paper.tag;
+
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner;
+import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent;
+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType;
+import io.papermc.paper.plugin.lifecycle.event.types.PrioritizableLifecycleEventType;
+import io.papermc.paper.registry.PaperRegistries;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.event.RegistryEventMap;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import net.minecraft.core.Holder;
+import net.minecraft.core.Registry;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.tags.TagLoader;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public class PaperTagListenerManager {
+
+ public static final String PRE_FLATTEN_EVENT_NAME = "pre-flatten";
+ public static final String POST_FLATTEN_EVENT_NAME = "post-flatten";
+
+ public static final PaperTagListenerManager INSTANCE = new PaperTagListenerManager();
+
+ public final RegistryEventMap preFlatten = new RegistryEventMap(PRE_FLATTEN_EVENT_NAME);
+ public final RegistryEventMap postFlatten = new RegistryEventMap(POST_FLATTEN_EVENT_NAME);
+
+ private PaperTagListenerManager() {
+ }
+
+ public <A> Map<ResourceLocation, List<TagLoader.EntryWithSource>> firePreFlattenEvent(
+ final Map<ResourceLocation, List<TagLoader.EntryWithSource>> initial,
+ final @Nullable TagEventConfig<?, A> config
+ ) {
+ if (config == null || config.preFlatten() == null || !config.preFlatten().hasHandlers()) {
+ return initial;
+ }
+ final PaperPreFlattenTagRegistrar<A> registrar = new PaperPreFlattenTagRegistrar<>(initial, config);
+ LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(
+ config.preFlatten(),
+ registrar,
+ BootstrapContext.class,
+ config.cause()
+ );
+ return Map.copyOf(registrar.tags);
+ }
+
+ public <M, A> Map<ResourceLocation, Collection<M>> firePostFlattenEvent(
+ final Map<ResourceLocation, Collection<M>> initial,
+ final @Nullable TagEventConfig<M, A> config
+ ) {
+ if (config == null || config.postFlatten() == null || !config.postFlatten().hasHandlers()) {
+ return initial;
+ }
+ final PaperPostFlattenTagRegistrar<M, A> registrar = new PaperPostFlattenTagRegistrar<>(initial, config);
+ LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(
+ config.postFlatten(),
+ registrar,
+ BootstrapContext.class,
+ config.cause()
+ );
+ return Map.copyOf(registrar.tags);
+ }
+
+ public <M, B> @Nullable TagEventConfig<Holder<M>, B> createEventConfig(final Registry<M> registry, final ReloadableRegistrarEvent.Cause cause) {
+ if (PaperRegistries.getEntry(registry.key()) == null) {
+ // TODO probably should be able to modify every registry
+ return null;
+ }
+ final RegistryKey<B> registryKey = PaperRegistries.registryFromNms(registry.key());
+ @Nullable AbstractLifecycleEventType<BootstrapContext, ReloadableRegistrarEvent<PreFlattenTagRegistrar<B>>, ?> preFlatten = null;
+ if (this.preFlatten.hasHandlers(registryKey)) {
+ preFlatten = (AbstractLifecycleEventType<BootstrapContext, ReloadableRegistrarEvent<PreFlattenTagRegistrar<B>>, ?>) this.preFlatten.<B, ReloadableRegistrarEvent<PreFlattenTagRegistrar<B>>>getEventType(registryKey);
+ }
+ @Nullable AbstractLifecycleEventType<BootstrapContext, ReloadableRegistrarEvent<PostFlattenTagRegistrar<B>>, ?> postFlatten = null;
+ if (this.postFlatten.hasHandlers(registryKey)) {
+ postFlatten = (AbstractLifecycleEventType<BootstrapContext, ReloadableRegistrarEvent<PostFlattenTagRegistrar<B>>, ?>) this.postFlatten.<B, ReloadableRegistrarEvent<PostFlattenTagRegistrar<B>>>getEventType(registryKey);
+ }
+ return new TagEventConfig<>(
+ preFlatten,
+ postFlatten,
+ cause,
+ registry::getHolder,
+ h -> ((Holder.Reference<M>) h).key().location(),
+ PaperRegistries.registryFromNms(registry.key())
+ );
+ }
+
+ public <T> PrioritizableLifecycleEventType.Simple<BootstrapContext, ReloadableRegistrarEvent<PreFlattenTagRegistrar<T>>> getPreFlattenType(final RegistryKey<T> registryKey) {
+ return this.preFlatten.getOrCreate(registryKey, (ignored, name) -> {
+ return new PrioritizableLifecycleEventType.Simple<>(name, BootstrapContext.class);
+ });
+ }
+
+ public <T> PrioritizableLifecycleEventType.Simple<BootstrapContext, ReloadableRegistrarEvent<PostFlattenTagRegistrar<T>>> getPostFlattenType(final RegistryKey<T> registryKey) {
+ return this.postFlatten.getOrCreate(registryKey, (ignored, name) -> {
+ return new PrioritizableLifecycleEventType.Simple<>(name, BootstrapContext.class);
+ });
+ }
+}
diff --git a/src/main/java/io/papermc/paper/tag/TagEventConfig.java b/src/main/java/io/papermc/paper/tag/TagEventConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6d4bfc6f45d646afeace422a038c670e10aaf80
--- /dev/null
+++ b/src/main/java/io/papermc/paper/tag/TagEventConfig.java
@@ -0,0 +1,23 @@
+package io.papermc.paper.tag;
+
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent;
+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType;
+import io.papermc.paper.registry.RegistryKey;
+import java.util.Optional;
+import java.util.function.Function;
+import net.minecraft.resources.ResourceLocation;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public record TagEventConfig<M, A>(
+ @Nullable AbstractLifecycleEventType<BootstrapContext, ? extends ReloadableRegistrarEvent<PreFlattenTagRegistrar<A>>, ?> preFlatten,
+ @Nullable AbstractLifecycleEventType<BootstrapContext, ? extends ReloadableRegistrarEvent<PostFlattenTagRegistrar<A>>, ?> postFlatten,
+ ReloadableRegistrarEvent.Cause cause,
+ Function<ResourceLocation, Optional<? extends M>> fromIdConverter,
+ Function<M, ResourceLocation> toIdConverter,
+ RegistryKey<A> apiRegistryKey
+) {
+}
diff --git a/src/main/java/net/minecraft/server/ServerFunctionLibrary.java b/src/main/java/net/minecraft/server/ServerFunctionLibrary.java
index 8ae2ca2435d84fee930d2931e45ad440245cbe0f..9fff5ca1e9707e4e6be5ecb92be936332d24bb96 100644
--- a/src/main/java/net/minecraft/server/ServerFunctionLibrary.java
+++ b/src/main/java/net/minecraft/server/ServerFunctionLibrary.java
@@ -118,7 +118,7 @@ public class ServerFunctionLibrary implements PreparableReloadListener {
return null;
}).join());
this.functions = builder.build();
- this.tags = this.tagsLoader.build((Map<ResourceLocation, List<TagLoader.EntryWithSource>>)intermediate.getFirst());
+ this.tags = this.tagsLoader.build((Map<ResourceLocation, List<TagLoader.EntryWithSource>>)intermediate.getFirst(), null); // Paper - command function tags are not implemented yet
},
applyExecutor
);
diff --git a/src/main/java/net/minecraft/tags/TagLoader.java b/src/main/java/net/minecraft/tags/TagLoader.java
index b47afb0ce8d9517ac7ee9c651c160f99d70f8a98..0bde4f7ae7d1897c630513261d1d5fb75a762634 100644
--- a/src/main/java/net/minecraft/tags/TagLoader.java
+++ b/src/main/java/net/minecraft/tags/TagLoader.java
@@ -79,7 +79,10 @@ public class TagLoader<T> {
return list.isEmpty() ? Either.right(builder.build()) : Either.left(list);
}
- public Map<ResourceLocation, Collection<T>> build(Map<ResourceLocation, List<TagLoader.EntryWithSource>> tags) {
+ // Paper start - fire tag registrar events
+ public Map<ResourceLocation, Collection<T>> build(Map<ResourceLocation, List<TagLoader.EntryWithSource>> tags, @Nullable io.papermc.paper.tag.TagEventConfig<T, ?> eventConfig) {
+ tags = io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.firePreFlattenEvent(tags, eventConfig);
+ // Paper end - fire tag registrar events
final Map<ResourceLocation, Collection<T>> map = Maps.newHashMap();
TagEntry.Lookup<T> lookup = new TagEntry.Lookup<T>() {
@Nullable
@@ -107,11 +110,13 @@ public class TagLoader<T> {
)
.ifRight(resolvedEntries -> map.put(id, (Collection<T>)resolvedEntries))
);
- return map;
+ return io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.firePostFlattenEvent(map, eventConfig); // Paper - fire tag registrar events
}
- public Map<ResourceLocation, Collection<T>> loadAndBuild(ResourceManager manager) {
- return this.build(this.load(manager));
+ // Paper start - fire tag registrar events
+ public Map<ResourceLocation, Collection<T>> loadAndBuild(ResourceManager manager, @Nullable io.papermc.paper.tag.TagEventConfig<T, ?> eventConfig) {
+ return this.build(this.load(manager), eventConfig);
+ // Paper end - fire tag registrar events
}
public static record EntryWithSource(TagEntry entry, String source) {
diff --git a/src/main/java/net/minecraft/tags/TagManager.java b/src/main/java/net/minecraft/tags/TagManager.java
index 7116362d798d7c28a4880c873a60507afa4673e6..2188274de5d1fe1aa5419be6247da6a3a2414a3b 100644
--- a/src/main/java/net/minecraft/tags/TagManager.java
+++ b/src/main/java/net/minecraft/tags/TagManager.java
@@ -39,7 +39,7 @@ public class TagManager implements PreparableReloadListener {
) {
List<? extends CompletableFuture<? extends TagManager.LoadResult<?>>> list = this.registryAccess
.registries()
- .map(registry -> this.createLoader(manager, prepareExecutor, (RegistryAccess.RegistryEntry<?>)registry))
+ .map(registry -> this.createLoader(manager, prepareExecutor, (RegistryAccess.RegistryEntry<?>)registry, applyExecutor instanceof net.minecraft.server.MinecraftServer ? io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL : io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD)) // Paper - add registrar event cause
.toList();
return CompletableFuture.allOf(list.toArray(CompletableFuture[]::new))
.thenCompose(synchronizer::wait)
@@ -48,11 +48,15 @@ public class TagManager implements PreparableReloadListener {
private <T> CompletableFuture<TagManager.LoadResult<T>> createLoader(
ResourceManager resourceManager, Executor prepareExecutor, RegistryAccess.RegistryEntry<T> requirement
+ , io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause // Paper - add registrar event cause
) {
ResourceKey<? extends Registry<T>> resourceKey = requirement.key();
Registry<T> registry = requirement.value();
TagLoader<Holder<T>> tagLoader = new TagLoader<>(registry::getHolder, Registries.tagsDirPath(resourceKey));
- return CompletableFuture.supplyAsync(() -> new TagManager.LoadResult<>(resourceKey, tagLoader.loadAndBuild(resourceManager)), prepareExecutor);
+ // Paper start - fire tag registrar events
+ final io.papermc.paper.tag.TagEventConfig<Holder<T>, ?> config = io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.createEventConfig(registry, cause);
+ return CompletableFuture.supplyAsync(() -> new TagManager.LoadResult<>(resourceKey, tagLoader.loadAndBuild(resourceManager, config)), prepareExecutor);
+ // Paper end - fire tag registrar events
}
public static record LoadResult<T>(ResourceKey<? extends Registry<T>> key, Map<ResourceLocation, Collection<Holder<T>>> tags) {