aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJake Potrebic <[email protected]>2023-03-18 14:39:05 -0700
committerJake Potrebic <[email protected]>2023-03-19 11:59:44 -0700
commit6f51aee4061eb73f8e347aaf9097a354a933f786 (patch)
treeb86cc3264fafb458ff766b988e0a0b404fe4dace
parenteb0950290d55e43ea8f59d02d43e619c00e9d920 (diff)
downloadPaper-6f51aee4061eb73f8e347aaf9097a354a933f786.tar.gz
Paper-6f51aee4061eb73f8e347aaf9097a354a933f786.zip
Tag Modification API
-rw-r--r--patches/api/0420-Tag-Modification-API.patch144
-rw-r--r--patches/server/0010-Adventure.patch11
-rw-r--r--patches/server/0969-Tag-Modification-API.patch135
3 files changed, 288 insertions, 2 deletions
diff --git a/patches/api/0420-Tag-Modification-API.patch b/patches/api/0420-Tag-Modification-API.patch
new file mode 100644
index 0000000000..990ecfd3f8
--- /dev/null
+++ b/patches/api/0420-Tag-Modification-API.patch
@@ -0,0 +1,144 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Sat, 18 Mar 2023 14:36:47 -0700
+Subject: [PATCH] Tag Modification API
+
+
+diff --git a/src/main/java/io/papermc/paper/tag/TagUpdate.java b/src/main/java/io/papermc/paper/tag/TagUpdate.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..8ec1289f25521f6c8bc1910c7c60e809a2ea08d1
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/tag/TagUpdate.java
+@@ -0,0 +1,24 @@
++package io.papermc.paper.tag;
++
++import java.util.Map;
++import java.util.Set;
++import net.kyori.adventure.key.Key;
++import net.kyori.adventure.key.Keyed;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Unmodifiable;
++
++/**
++ * Represents an update to a set of tags that can be
++ * sent to any number of players or a single player.
++ */
++public interface TagUpdate<T extends Keyed> {
++
++ /**
++ * Get the set of updated tags.
++ *
++ * @return an immutable map describing tags
++ */
++ @NotNull @Unmodifiable Map<Key, Set<T>> updatedTags();
++}
+diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java
+index 0a3a41ae4c488b148266129d3663be3f8830d509..1c3e941c3322ab39a99e5c4f08fcb64bee8f32c5 100644
+--- a/src/main/java/org/bukkit/Registry.java
++++ b/src/main/java/org/bukkit/Registry.java
+@@ -271,6 +271,20 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
+ return (namespacedKey != null) ? get(namespacedKey) : null;
+ }
+
++ // Paper start - tag updates
++ /**
++ * Edits the tags the server and client use to determine various behaviors.
++ * In the consumer parameter, the map and initial sets will be mutable to make
++ * changes and after the consumer, they will be sent to the client.
++ *
++ * @param editConsumer the consumer to edit the map of tags
++ * @throws UnsupportedOperationException if this registry doesn't support editing tags
++ */
++ default io.papermc.paper.tag.TagUpdate<T> createTagUpdate(final java.util.function.@NotNull Consumer<Map<net.kyori.adventure.key.Key, java.util.Set<T>>> editConsumer) {
++ throw new UnsupportedOperationException("This registry doesn't support editing tags");
++ }
++ // Paper end
++
+ static final class SimpleRegistry<T extends Enum<T> & Keyed> implements Registry<T> {
+
+ private final Map<NamespacedKey, T> map;
+diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
+index 2204336d8800311b65e894739ab1b27273e7c6f2..87cba207c54cb53e5491cdaf250ce751fb8e52c5 100644
+--- a/src/main/java/org/bukkit/Server.java
++++ b/src/main/java/org/bukkit/Server.java
+@@ -2139,4 +2139,36 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
+ */
+ @NotNull org.bukkit.potion.PotionBrewer getPotionBrewer();
+ // Paper end
++ // Paper start - tag updates
++ /**
++ * Applies this tag update to the tags on the server. After
++ * applying the changes, updates will be sent to all connected
++ * clients with the new tags.
++ * <p>
++ * These changes will be reset when the server is restarted
++ * or reloaded through {@code /bukkit:reload} or {@code /minecraft:reload}.
++ * Listen to {@link io.papermc.paper.event.server.ServerResourcesReloadedEvent} if
++ * you want to preserve your changes through reloads.
++ *
++ * @param tagUpdate the tag update to send
++ * @see #applyTagUpdate(Iterable) for multiple updates at once
++ */
++ default void applyTagUpdate(io.papermc.paper.tag.@NotNull TagUpdate<?> tagUpdate) {
++ this.applyTagUpdate(java.util.Set.of(tagUpdate));
++ }
++
++ /**
++ * Applies this tag update to the tags on the server. After
++ * applying the changes, updates will be sent to all connected
++ * clients with the new tags.
++ * <p>
++ * These changes will be reset when the server is restarted
++ * or reloaded through {@code /bukkit:reload} or {@code /minecraft:reload}.
++ * Listen to {@link io.papermc.paper.event.server.ServerResourcesReloadedEvent} if
++ * you want to preserve your changes through reloads.
++ *
++ * @param tagUpdates the tag updates to send
++ */
++ void applyTagUpdate(@NotNull Iterable<io.papermc.paper.tag.TagUpdate<?>> tagUpdates);
++ // Paper end
+ }
+diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java
+index 660f28e371176c62e38a84b187958aceb235c8e3..935fdae93a3a5abdb5643993895b22542a5bd97c 100644
+--- a/src/main/java/org/bukkit/entity/Player.java
++++ b/src/main/java/org/bukkit/entity/Player.java
+@@ -3000,4 +3000,37 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
+ @Override
+ Spigot spigot();
+ // Spigot end
++
++ // Paper start - tag updates
++ /**
++ * Send a tag update to this player. The player's client
++ * will apply this tag change and update its behavior
++ * accordingly.
++ * <p>
++ * These changes will be reset when the server is restarted
++ * or reloaded through {@code /bukkit:reload} or {@code /minecraft:reload}.
++ * Listen to {@link io.papermc.paper.event.server.ServerResourcesReloadedEvent} if
++ * you want to preserve your changes through reloads.
++ *
++ * @param tagUpdate the tag update to send
++ * @see #sendTagUpdates(Iterable) for multiple updates at once
++ */
++ default void sendTagUpdate(io.papermc.paper.tag.@NotNull TagUpdate<?> tagUpdate) {
++ this.sendTagUpdates(java.util.Set.of(tagUpdate));
++ }
++
++ /**
++ * Send a group of tag updates to this player. The player's client
++ * will apply these tag changes and update its behavior
++ * accordingly.
++ * <p>
++ * These changes will be reset when the server is restarted
++ * or reloaded through {@code /bukkit:reload} or {@code /minecraft:reload}.
++ * Listen to {@link io.papermc.paper.event.server.ServerResourcesReloadedEvent} if
++ * you want to preserve your changes through reloads.
++ *
++ * @param tagUpdates the tag updates to send
++ */
++ void sendTagUpdates(@NotNull Iterable<io.papermc.paper.tag.TagUpdate<?>> tagUpdates);
++ // Paper end
+ }
diff --git a/patches/server/0010-Adventure.patch b/patches/server/0010-Adventure.patch
index ecf70ed5d8..f256704264 100644
--- a/patches/server/0010-Adventure.patch
+++ b/patches/server/0010-Adventure.patch
@@ -735,10 +735,10 @@ index 0000000000000000000000000000000000000000..2fd6c3e65354071af71c7d8ebb97b559
+}
diff --git a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
new file mode 100644
-index 0000000000000000000000000000000000000000..01e424792f68bac73ec41726031ebbb53df13da7
+index 0000000000000000000000000000000000000000..3e45741833b8652951beb61ced05630507541a88
--- /dev/null
+++ b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
-@@ -0,0 +1,354 @@
+@@ -0,0 +1,361 @@
+package io.papermc.paper.adventure;
+
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
@@ -783,6 +783,7 @@ index 0000000000000000000000000000000000000000..01e424792f68bac73ec41726031ebbb5
+import org.bukkit.craftbukkit.command.VanillaCommandWrapper;
+import org.bukkit.craftbukkit.entity.CraftEntity;
+import org.bukkit.entity.Entity;
++import org.intellij.lang.annotations.Subst;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
@@ -871,6 +872,12 @@ index 0000000000000000000000000000000000000000..01e424792f68bac73ec41726031ebbb5
+ return asVanilla(key);
+ }
+
++ public static Key asAdventure(final ResourceLocation location) {
++ @Subst("minecraft") final String namespace = location.getNamespace();
++ @Subst("some_path") final String path = location.getPath();
++ return Key.key(namespace, path);
++ }
++
+ // Component
+
+ public static Component asAdventure(final net.minecraft.network.chat.Component component) {
diff --git a/patches/server/0969-Tag-Modification-API.patch b/patches/server/0969-Tag-Modification-API.patch
new file mode 100644
index 0000000000..83ec09831f
--- /dev/null
+++ b/patches/server/0969-Tag-Modification-API.patch
@@ -0,0 +1,135 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Sat, 18 Mar 2023 14:37:29 -0700
+Subject: [PATCH] Tag Modification API
+
+== AT ==
+public net.minecraft.tags.TagNetworkSerialization$NetworkPayload <init>(Ljava/util/Map;)V
+
+diff --git a/src/main/java/io/papermc/paper/tag/PaperTagUpdate.java b/src/main/java/io/papermc/paper/tag/PaperTagUpdate.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..c744e7bcf59fbd3007f8506d024546e0d7f2b11d
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/tag/PaperTagUpdate.java
+@@ -0,0 +1,48 @@
++package io.papermc.paper.tag;
++
++import com.google.common.collect.ImmutableMap;
++import it.unimi.dsi.fastutil.ints.IntArrayList;
++import it.unimi.dsi.fastutil.ints.IntList;
++import java.util.Map;
++import java.util.Set;
++import net.kyori.adventure.key.Key;
++import net.kyori.adventure.key.Keyed;
++import net.minecraft.core.Holder;
++import net.minecraft.core.Registry;
++import net.minecraft.core.RegistryAccess;
++import net.minecraft.resources.ResourceKey;
++import net.minecraft.resources.ResourceLocation;
++import net.minecraft.tags.TagNetworkSerialization;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.framework.qual.DefaultQualifier;
++
++@DefaultQualifier(NonNull.class)
++public record PaperTagUpdate<B extends Keyed, M>(
++ ResourceKey<? extends Registry<M>> registryKey,
++ Map<Key, Set<B>> updatedTags,
++ Map<net.minecraft.tags.TagKey<M>, java.util.List<net.minecraft.core.Holder<M>>> nmsTags
++) implements TagUpdate<B> {
++
++ // logic was adapted from TagNetworkSerialization#serializeToNetwork
++ public void addToNetworkPayloadMap(final Map<ResourceKey<? extends Registry<?>>, TagNetworkSerialization.NetworkPayload> networkPayload, final RegistryAccess registryAccess) {
++ final ImmutableMap.Builder<ResourceLocation, IntList> map = ImmutableMap.builder();
++ final Registry<M> registry = registryAccess.registryOrThrow(this.registryKey);
++ this.nmsTags.forEach((key, tagValues) -> {
++ final IntList idList = new IntArrayList(tagValues.size());
++ for(Holder<M> holder : tagValues) {
++ if (holder.kind() != Holder.Kind.REFERENCE) {
++ throw new IllegalStateException("Can't serialize unregistered value " + holder);
++ }
++
++ idList.add(registry.getId(holder.value()));
++ }
++
++ map.put(key.location(), idList);
++ });
++ networkPayload.put(this.registryKey, new TagNetworkSerialization.NetworkPayload(map.build()));
++ }
++
++ public void applyToRegistry(final RegistryAccess registryAccess) {
++ registryAccess.registryOrThrow(this.registryKey).bindTags(this.nmsTags);
++ }
++}
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java
+index 34888b525fd35ac64e6e5e66036ad965a6769959..59ddba449d49c7f9d447b665eb52c765ff6b15ec 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java
+@@ -78,4 +78,25 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
+ public Stream<B> values() {
+ return this.minecraftRegistry.keySet().stream().map(minecraftKey -> this.get(CraftNamespacedKey.fromMinecraft(minecraftKey)));
+ }
++ // Paper start - tag updates
++ @Override
++ public io.papermc.paper.tag.TagUpdate<B> createTagUpdate(final java.util.function.Consumer<Map<net.kyori.adventure.key.Key, java.util.Set<B>>> editConsumer) {
++ final Map<net.kyori.adventure.key.Key, java.util.Set<B>> map = this.minecraftRegistry.getTags().collect(
++ java.util.stream.Collectors.toMap(
++ pair -> io.papermc.paper.adventure.PaperAdventure.asAdventure(pair.getFirst().location()),
++ pair -> pair.getSecond().stream().map(holder -> java.util.Objects.requireNonNull(this.get(CraftNamespacedKey.fromMinecraft(holder.unwrapKey().orElseThrow().location())), () -> "Couldn't get bukkit object for key " + holder.unwrapKey())).collect(java.util.stream.Collectors.toSet()),
++ (bs, bs2) -> { throw new IllegalStateException("No duplicate tag keys"); },
++ HashMap::new
++ )
++ );
++ editConsumer.accept(map);
++ final Map<net.minecraft.tags.TagKey<M>, java.util.List<net.minecraft.core.Holder<M>>> newTags = map.entrySet().stream().collect(
++ java.util.stream.Collectors.toMap(
++ entry -> net.minecraft.tags.TagKey.create(this.minecraftRegistry.key(), io.papermc.paper.adventure.PaperAdventure.asVanilla(entry.getKey())),
++ entry -> entry.getValue().stream().map(b -> (net.minecraft.core.Holder<M>) this.minecraftRegistry.getHolderOrThrow(net.minecraft.resources.ResourceKey.create(this.minecraftRegistry.key(), io.papermc.paper.adventure.PaperAdventure.asVanilla(b.key())))).toList()
++ )
++ );
++ return new io.papermc.paper.tag.PaperTagUpdate<>(this.minecraftRegistry.key(), map, newTags);
++ }
++ // Paper end
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+index f9a9d2bb7b6d1bf4a0931438de4d8c7ee0757479..ddddfdb95e9936a560e435b807d9cc3e7ac0b234 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+@@ -2919,4 +2919,22 @@ public final class CraftServer implements Server {
+ }
+
+ // Paper end
++ // Paper start - tag updates
++ @Override
++ public void applyTagUpdate(final Iterable<io.papermc.paper.tag.TagUpdate<?>> tagUpdates) {
++ for (final io.papermc.paper.tag.TagUpdate<?> update : tagUpdates) {
++ ((io.papermc.paper.tag.PaperTagUpdate<?, ?>) update).applyToRegistry(this.console.registryAccess());
++ }
++ net.minecraft.world.level.block.Blocks.rebuildCache();
++ this.playerList.broadcastAll(createTagUpdatePacket(tagUpdates, this.console.registryAccess()));
++ }
++
++ public static net.minecraft.network.protocol.game.ClientboundUpdateTagsPacket createTagUpdatePacket(final Iterable<io.papermc.paper.tag.TagUpdate<?>> tagUpdates, final net.minecraft.core.RegistryAccess registryAccess) {
++ final Map<ResourceKey<? extends net.minecraft.core.Registry<?>>, net.minecraft.tags.TagNetworkSerialization.NetworkPayload> map = new java.util.HashMap<>();
++ for (final io.papermc.paper.tag.TagUpdate<?> update : tagUpdates) {
++ ((io.papermc.paper.tag.PaperTagUpdate<?, ?>) update).addToNetworkPayloadMap(map, registryAccess);
++ }
++ return new net.minecraft.network.protocol.game.ClientboundUpdateTagsPacket(map);
++ }
++ // Paper end
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+index eca5e6b93dd84307bf9dbadf32414d6f506e69dc..cf350b2d6969f20cc0d1933a9ba51475f9d942d8 100644
+--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+@@ -3148,4 +3148,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
+ return this.spigot;
+ }
+ // Spigot end
++
++ // Paper start - tag updates
++ @Override
++ public void sendTagUpdates(final Iterable<io.papermc.paper.tag.TagUpdate<?>> tagUpdates) {
++ this.getHandle().connection.send(CraftServer.createTagUpdatePacket(tagUpdates, this.getHandle().getLevel().registryAccess()));
++ }
++ // Paper end
+ }