Skip to content

Commit a7d9c48

Browse files
authored
MaterialTag.vanilla_tags 1.21 fixes (#2706)
* Use `NamespacedKey`s instead of `String`s for tags * `BlockTagsSetter` * Re-fill `VanillaTagHelper` on resources reload * TODOs * Fixup some TODO comments * Method order fixup * Batch reloads to handle lots of modifications * Cleanup `Plugin#getFile` Usage * Typo
1 parent 408a478 commit a7d9c48

File tree

15 files changed

+162
-85
lines changed

15 files changed

+162
-85
lines changed

paper/src/main/java/com/denizenscript/denizen/paper/PaperEventHelpers.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
import com.denizenscript.denizen.objects.InventoryTag;
44
import com.denizenscript.denizen.scripts.containers.core.InventoryScriptContainer;
5+
import com.denizenscript.denizen.utilities.VanillaTagHelper;
56
import com.denizenscript.denizen.utilities.inventory.InventoryViewUtil;
67
import com.denizenscript.denizencore.objects.core.ScriptTag;
78
import com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent;
9+
import io.papermc.paper.event.server.ServerResourcesReloadedEvent;
810
import org.bukkit.event.EventHandler;
11+
import org.bukkit.event.EventPriority;
912
import org.bukkit.event.Listener;
1013

1114
public class PaperEventHelpers implements Listener {
@@ -19,4 +22,9 @@ public void onRecipeBookClick(PlayerRecipeBookClickEvent event) {
1922
}
2023
}
2124
}
25+
26+
@EventHandler(priority = EventPriority.LOWEST)
27+
public void onServerResourcesReloaded(ServerResourcesReloadedEvent event) {
28+
VanillaTagHelper.loadTagsCache();
29+
}
2230
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.denizenscript.denizen.paper.utilities;
2+
3+
import com.denizenscript.denizen.Denizen;
4+
import com.denizenscript.denizen.utilities.Utilities;
5+
import com.denizenscript.denizen.utilities.VanillaTagHelper;
6+
import com.denizenscript.denizencore.utilities.ReflectionHelper;
7+
import com.denizenscript.denizencore.utilities.debugging.Debug;
8+
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
9+
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
10+
import io.papermc.paper.plugin.configuration.PluginMeta;
11+
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
12+
import io.papermc.paper.registry.RegistryKey;
13+
import io.papermc.paper.registry.TypedKey;
14+
import io.papermc.paper.registry.tag.TagKey;
15+
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
16+
import org.bukkit.Bukkit;
17+
import org.bukkit.Material;
18+
import org.bukkit.NamespacedKey;
19+
import org.bukkit.block.BlockType;
20+
import org.bukkit.event.EventHandler;
21+
import org.bukkit.event.Listener;
22+
23+
import java.lang.invoke.MethodHandle;
24+
import java.nio.file.Path;
25+
import java.util.*;
26+
import java.util.stream.Collectors;
27+
28+
public class BlockTagsSetter implements Listener {
29+
30+
public static final MethodHandle BOOTSTRAP_CONTEXT_CONSTRUCTOR;
31+
32+
static {
33+
try {
34+
Class<?> bootstrapContextImplClass = Class.forName("io.papermc.paper.plugin.bootstrap.PluginBootstrapContextImpl");
35+
BOOTSTRAP_CONTEXT_CONSTRUCTOR = ReflectionHelper.getConstructor(bootstrapContextImplClass, PluginMeta.class, Path.class, ComponentLogger.class, Path.class);
36+
}
37+
catch (Throwable e) {
38+
throw new RuntimeException("Failed to initialize BlockTagsSetter", e);
39+
}
40+
}
41+
42+
public static final BlockTagsSetter INSTANCE = new BlockTagsSetter(Denizen.getInstance());
43+
44+
public Map<TypedKey<BlockType>, Set<TagKey<BlockType>>> modifiedTags = new HashMap<>();
45+
public boolean batchReloadNeeded;
46+
47+
public BlockTagsSetter(Denizen plugin) {
48+
Bukkit.getPluginManager().registerEvents(this, plugin);
49+
try {
50+
BootstrapContext fakeContext = (BootstrapContext) BOOTSTRAP_CONTEXT_CONSTRUCTOR.invoke(plugin.getPluginMeta(), plugin.getDataPath(), plugin.getComponentLogger(), plugin.getFile().toPath());
51+
fakeContext.getLifecycleManager().registerEventHandler(LifecycleEvents.TAGS.postFlatten(RegistryKey.BLOCK), event -> {
52+
Map<TagKey<BlockType>, Collection<TypedKey<BlockType>>> allTags = event.registrar().getAllTags();
53+
for (Map.Entry<TypedKey<BlockType>, Set<TagKey<BlockType>>> entry : modifiedTags.entrySet()) {
54+
TypedKey<BlockType> blockType = entry.getKey();
55+
Set<TagKey<BlockType>> tags = entry.getValue();
56+
for (Map.Entry<TagKey<BlockType>, Collection<TypedKey<BlockType>>> tagEntry : allTags.entrySet()) {
57+
TagKey<BlockType> tagKey = tagEntry.getKey();
58+
Collection<TypedKey<BlockType>> values = tagEntry.getValue();
59+
if (values.contains(blockType) && !tags.contains(tagKey)) {
60+
List<TypedKey<BlockType>> modifiedValues = new ArrayList<>(values);
61+
modifiedValues.remove(blockType);
62+
event.registrar().setTag(tagKey, modifiedValues);
63+
}
64+
}
65+
for (TagKey<BlockType> tag : tags) {
66+
event.registrar().addToTag(tag, List.of(blockType));
67+
}
68+
}
69+
});
70+
}
71+
catch (Throwable e) {
72+
Debug.echoError(e);
73+
}
74+
}
75+
76+
@EventHandler
77+
public void onServerTickEnd(ServerTickEndEvent event) {
78+
if (batchReloadNeeded) {
79+
batchReloadNeeded = false;
80+
Bukkit.reloadData();
81+
}
82+
}
83+
84+
public void setTags(Material material, Set<NamespacedKey> tags) {
85+
TypedKey<BlockType> blockKey = TypedKey.create(RegistryKey.BLOCK, material.getKey());
86+
Set<TagKey<BlockType>> tagKeys = tags.stream().map(tag -> TagKey.create(RegistryKey.BLOCK, tag)).collect(Collectors.toCollection(HashSet::new));
87+
Set<TagKey<BlockType>> oldTagKeys = modifiedTags.put(blockKey, tagKeys);
88+
if (tagKeys.equals(oldTagKeys)) {
89+
return;
90+
}
91+
VanillaTagHelper.tagsByMaterial.put(material, tags.stream().map(Utilities::namespacedKeyToString).collect(Collectors.toCollection(HashSet::new)));
92+
batchReloadNeeded = true;
93+
}
94+
}

paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,4 +393,13 @@ public boolean canUseEquipmentSlot(LivingEntity entity, EquipmentSlot slot) {
393393
public boolean hasCustomName(PotionMeta meta) {
394394
return meta.hasCustomPotionName();
395395
}
396+
397+
@Override
398+
public void setMaterialTags(Material type, Set<NamespacedKey> tags) {
399+
if (!NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) {
400+
super.setMaterialTags(type, tags);
401+
return;
402+
}
403+
BlockTagsSetter.INSTANCE.setTags(type, tags);
404+
}
396405
}

plugin/src/main/java/com/denizenscript/denizen/Denizen.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,4 +618,9 @@ public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
618618
default -> null;
619619
};
620620
}
621+
622+
@Override
623+
public File getFile() {
624+
return super.getFile();
625+
}
621626
}

plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/BlockHelper.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
import com.denizenscript.denizen.nms.util.PlayerProfile;
44
import com.denizenscript.denizen.nms.util.jnbt.CompoundTag;
55
import com.denizenscript.denizen.objects.EntityTag;
6-
import org.bukkit.Color;
7-
import org.bukkit.Instrument;
8-
import org.bukkit.Location;
9-
import org.bukkit.Material;
6+
import org.bukkit.*;
107
import org.bukkit.block.*;
118
import org.bukkit.block.data.BlockData;
129
import org.bukkit.inventory.ItemStack;
@@ -92,7 +89,7 @@ default Color getMapColor(Block block) { // TODO: once 1.20 is the minimum suppo
9289
return block.getBlockData().getMapColor();
9390
}
9491

95-
default void setVanillaTags(Material material, Set<String> tags) {
92+
default void setVanillaTags(Material material, Set<NamespacedKey> tags) { // TODO: once 1.21 is the minimum supported version, remove this
9693
throw new UnsupportedOperationException();
9794
}
9895
}

plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/EntityHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ public void clientResetLoc(Entity entity) {
394394

395395
public abstract void setBoundingBox(Entity entity, BoundingBox box);
396396

397-
public List<Player> getPlayersThatSee(Entity entity) { // TODO: once the minimum supported version is 1.20, remove from NMS
397+
public List<Player> getPlayersThatSee(Entity entity) { // TODO: once 1.20 is the minimum supported version, remove from NMS
398398
return List.copyOf(entity.getTrackedBy());
399399
}
400400

@@ -406,7 +406,7 @@ public void sendAllUpdatePackets(Entity entity) {
406406

407407
public abstract void setHeadAngle(LivingEntity entity, float angle);
408408

409-
public void setGhastAttacking(Ghast ghast, boolean attacking) { // TODO: once minimum version is 1.19 or higher, remove from NMS
409+
public void setGhastAttacking(Ghast ghast, boolean attacking) { // TODO: once 1.19 is the minimum supported version, remove from NMS
410410
ghast.setCharging(attacking);
411411
}
412412

plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/PacketHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ default void showEquipment(Player player, LivingEntity entity, EquipmentSlot equ
9090
player.sendEquipmentChange(entity, equipmentSlot, itemStack);
9191
}
9292

93-
default void resetEquipment(Player player, LivingEntity entity) { // TODO: once minimum version is 1.19 or higher, remove from NMS
93+
default void resetEquipment(Player player, LivingEntity entity) { // TODO: once 1.19 is the minimum supported version, remove from NMS
9494
EntityEquipment equipment = entity.getEquipment();
9595
Map<EquipmentSlot, ItemStack> equipmentMap = new EnumMap<>(EquipmentSlot.class);
9696
for (EquipmentSlot slot : EquipmentSlot.values()) {

plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/PlayerHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public enum SkinLayer {
8686

8787
public enum ProfileEditMode { ADD, UPDATE_DISPLAY, UPDATE_LATENCY, UPDATE_GAME_MODE, UPDATE_LISTED }
8888

89-
public void sendPlayerInfoAddPacket(Player player, EnumSet<ProfileEditMode> editModes, String name, String display, UUID id, String texture, String signature, int latency, GameMode gameMode, boolean listed) { // TODO: once minimum version is 1.19 or higher, rename to 'sendPlayerInfoUpdatePacket'
89+
public void sendPlayerInfoAddPacket(Player player, EnumSet<ProfileEditMode> editModes, String name, String display, UUID id, String texture, String signature, int latency, GameMode gameMode, boolean listed) { // TODO: once 1.19 is the minimum supported version, rename to 'sendPlayerInfoUpdatePacket'
9090
throw new UnsupportedOperationException();
9191
}
9292

plugin/src/main/java/com/denizenscript/denizen/objects/MaterialTag.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.denizenscript.denizen.nms.interfaces.BlockHelper;
66
import com.denizenscript.denizen.objects.properties.material.*;
77
import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
8+
import com.denizenscript.denizen.utilities.PaperAPITools;
89
import com.denizenscript.denizen.utilities.VanillaTagHelper;
910
import com.denizenscript.denizencore.DenizenCore;
1011
import com.denizenscript.denizencore.events.ScriptEvent;
@@ -710,7 +711,7 @@ public void adjust(Mechanism mechanism) {
710711
// @description
711712
// Sets a material's vanilla tags.
712713
// Any tag name will be accepted - meaning, any tag name input will be added to the material, regardless of whether it previously existed or not.
713-
// Note that this gets reset once server resources are reloaded (see <@link event server resources reloaded>).
714+
// This will work at any time, but applying your changes once during <@link event server prestart> is recommended, as usages require a server resources reload.
714715
// @tags
715716
// <MaterialTag.vanilla_tags>
716717
// @example
@@ -725,15 +726,16 @@ public void adjust(Mechanism mechanism) {
725726
// -->
726727
if (!mechanism.isProperty && mechanism.matches("vanilla_tags") && mechanism.requireObject(ListTag.class)) {
727728
ListTag input = mechanism.valueAsType(ListTag.class);
728-
Set<String> tags = new HashSet<>();
729+
Set<NamespacedKey> tags = new HashSet<>();
729730
for (String tag : input) {
730-
if (!VanillaTagHelper.isValidTagName(tag)) {
731+
NamespacedKey tagKey = NamespacedKey.fromString(tag);
732+
if (tagKey == null) {
731733
mechanism.echoError("Invalid tag name '" + tag + "' inputted.");
732734
continue;
733735
}
734-
tags.add(tag);
736+
tags.add(tagKey);
735737
}
736-
NMSHandler.blockHelper.setVanillaTags(material, tags);
738+
PaperAPITools.instance.setMaterialTags(material, tags);
737739
}
738740

739741
// TODO: 1.20.6: need an ItemTag variant providing the proper functionality, and then deprecate this

plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.lang.invoke.MethodHandle;
2828
import java.util.List;
29+
import java.util.Set;
2930
import java.util.function.Predicate;
3031

3132
public class PaperAPITools {
@@ -223,4 +224,8 @@ public boolean canUseEquipmentSlot(LivingEntity entity, EquipmentSlot slot) {
223224
public boolean hasCustomName(PotionMeta meta) {
224225
return meta.hasCustomName();
225226
}
227+
228+
public void setMaterialTags(Material type, Set<NamespacedKey> tags) {
229+
NMSHandler.blockHelper.setVanillaTags(type, tags);
230+
}
226231
}

plugin/src/main/java/com/denizenscript/denizen/utilities/VanillaTagHelper.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
import com.denizenscript.denizen.nms.NMSHandler;
44
import com.denizenscript.denizen.nms.NMSVersion;
5-
import org.bukkit.*;
5+
import org.bukkit.Bukkit;
6+
import org.bukkit.Keyed;
7+
import org.bukkit.Material;
8+
import org.bukkit.Tag;
69
import org.bukkit.entity.EntityType;
710

811
import java.util.HashMap;
@@ -19,6 +22,10 @@ public class VanillaTagHelper {
1922

2023
public static HashMap<String, HashSet<EntityType>> entityTagsByKey = new HashMap<>();
2124

25+
static {
26+
loadTagsCache();
27+
}
28+
2229
public static void addOrUpdateMaterialTag(Tag<Material> tag) {
2330
if (materialTagsByKey.containsKey(tag.getKey().getKey())) {
2431
updateMaterialTag(tag);
@@ -37,6 +44,7 @@ public static void addOrUpdateEntityTag(Tag<EntityType> tag) {
3744
}
3845
}
3946

47+
// TODO: once 1.21 is the minimum supported version, remove this and related methods
4048
static <T extends Keyed> void update(Tag<T> tag, HashMap<T, HashSet<String>> tagByObj, HashMap<String, HashSet<T>> objByTag) {
4149
String tagName = Utilities.namespacedKeyToString(tag.getKey());
4250
Set<T> objs = objByTag.get(tagName);
@@ -84,7 +92,11 @@ static void addEntityTag(Tag<EntityType> tag) {
8492
add(tag, tagsByEntity, entityTagsByKey);
8593
}
8694

87-
static {
95+
public static void loadTagsCache() {
96+
tagsByMaterial.clear();
97+
materialTagsByKey.clear();
98+
tagsByEntity.clear();
99+
entityTagsByKey.clear();
88100
for (Tag<Material> tag : Bukkit.getTags("blocks", Material.class)) {
89101
addMaterialTag(tag);
90102
}
@@ -97,8 +109,4 @@ static void addEntityTag(Tag<EntityType> tag) {
97109
addMaterialTag(tag);
98110
}
99111
}
100-
101-
public static boolean isValidTagName(String name) {
102-
return name != null && !name.isEmpty() && NamespacedKey.fromString(name) != null;
103-
}
104112
}

v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/BlockHelperImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import net.minecraft.core.Registry;
1818
import net.minecraft.core.*;
1919
import net.minecraft.network.protocol.game.ClientboundUpdateTagsPacket;
20-
import net.minecraft.resources.ResourceLocation;
2120
import net.minecraft.server.level.ServerLevel;
2221
import net.minecraft.tags.TagKey;
2322
import net.minecraft.tags.TagNetworkSerialization;
@@ -48,6 +47,7 @@
4847
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
4948
import org.bukkit.craftbukkit.v1_18_R2.tag.CraftBlockTag;
5049
import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers;
50+
import org.bukkit.craftbukkit.v1_18_R2.util.CraftNamespacedKey;
5151
import org.bukkit.entity.Player;
5252

5353
import java.lang.invoke.MethodHandle;
@@ -337,7 +337,7 @@ public Color getMapColor(Block block) {
337337
public static MethodHandle Holder_Reference_bindTags = ReflectionHelper.getMethodHandle(Holder.Reference.class, ReflectionMappingsInfo.Holder_Reference_bindTags, Collection.class);
338338

339339
@Override
340-
public void setVanillaTags(Material material, Set<String> tags) {
340+
public void setVanillaTags(Material material, Set<NamespacedKey> tags) {
341341
Holder<net.minecraft.world.level.block.Block> nmsHolder = getMaterialBlock(material).builtInRegistryHolder();
342342
nmsHolder.tags().forEach(nmsTag -> {
343343
HolderSet.Named<net.minecraft.world.level.block.Block> nmsHolderSet = Registry.BLOCK.getTag(nmsTag).orElse(null);
@@ -355,8 +355,8 @@ public void setVanillaTags(Material material, Set<String> tags) {
355355
VanillaTagHelper.updateMaterialTag(new CraftBlockTag(Registry.BLOCK, nmsTag));
356356
});
357357
List<TagKey<net.minecraft.world.level.block.Block>> newNmsTags = new ArrayList<>();
358-
for (String tag : tags) {
359-
TagKey<net.minecraft.world.level.block.Block> newNmsTag = TagKey.create(Registry.BLOCK_REGISTRY, new ResourceLocation(tag));
358+
for (NamespacedKey tag : tags) {
359+
TagKey<net.minecraft.world.level.block.Block> newNmsTag = TagKey.create(Registry.BLOCK_REGISTRY, CraftNamespacedKey.toMinecraft(tag));
360360
HolderSet.Named<net.minecraft.world.level.block.Block> nmsHolderSet = Registry.BLOCK.getOrCreateTag(newNmsTag);
361361
List<Holder<net.minecraft.world.level.block.Block>> nmsHolders = nmsHolderSet.stream().collect(Collectors.toCollection(ArrayList::new));
362362
nmsHolders.add(nmsHolder);

v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/BlockHelperImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import net.minecraft.core.HolderSet;
2020
import net.minecraft.core.registries.BuiltInRegistries;
2121
import net.minecraft.network.protocol.game.ClientboundUpdateTagsPacket;
22-
import net.minecraft.resources.ResourceLocation;
2322
import net.minecraft.server.level.ServerLevel;
2423
import net.minecraft.tags.TagKey;
2524
import net.minecraft.tags.TagNetworkSerialization;
@@ -53,6 +52,7 @@
5352
import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack;
5453
import org.bukkit.craftbukkit.v1_19_R3.tag.CraftBlockTag;
5554
import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers;
55+
import org.bukkit.craftbukkit.v1_19_R3.util.CraftNamespacedKey;
5656
import org.bukkit.entity.Player;
5757

5858
import java.lang.invoke.MethodHandle;
@@ -316,7 +316,7 @@ public Color getMapColor(Block block) {
316316
public static MethodHandle Holder_Reference_bindTags = ReflectionHelper.getMethodHandle(Holder.Reference.class, ReflectionMappingsInfo.HolderReference_bindTags_method, Collection.class);
317317

318318
@Override
319-
public void setVanillaTags(Material material, Set<String> tags) {
319+
public void setVanillaTags(Material material, Set<NamespacedKey> tags) {
320320
Holder<net.minecraft.world.level.block.Block> nmsHolder = getMaterialBlock(material).builtInRegistryHolder();
321321
nmsHolder.tags().forEach(nmsTag -> {
322322
HolderSet.Named<net.minecraft.world.level.block.Block> nmsHolderSet = BuiltInRegistries.BLOCK.getTag(nmsTag).orElse(null);
@@ -334,8 +334,8 @@ public void setVanillaTags(Material material, Set<String> tags) {
334334
VanillaTagHelper.updateMaterialTag(new CraftBlockTag(BuiltInRegistries.BLOCK, nmsTag));
335335
});
336336
List<TagKey<net.minecraft.world.level.block.Block>> newNmsTags = new ArrayList<>();
337-
for (String tag : tags) {
338-
TagKey<net.minecraft.world.level.block.Block> newNmsTag = TagKey.create(BuiltInRegistries.BLOCK.key(), new ResourceLocation(tag));
337+
for (NamespacedKey tag : tags) {
338+
TagKey<net.minecraft.world.level.block.Block> newNmsTag = TagKey.create(BuiltInRegistries.BLOCK.key(), CraftNamespacedKey.toMinecraft(tag));
339339
HolderSet.Named<net.minecraft.world.level.block.Block> nmsHolderSet = BuiltInRegistries.BLOCK.getOrCreateTag(newNmsTag);
340340
List<Holder<net.minecraft.world.level.block.Block>> nmsHolders = nmsHolderSet.stream().collect(Collectors.toCollection(ArrayList::new));
341341
nmsHolders.add(nmsHolder);

0 commit comments

Comments
 (0)