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
}

0 commit comments

Comments
 (0)