Guest User

Untitled

a guest
Jun 22nd, 2024
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.81 KB | None | 0 0
  1. package spot.testenchantments;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.HashSet;
  5. import java.util.IdentityHashMap;
  6. import java.util.List;
  7. import java.util.Set;
  8. import java.util.function.BiConsumer;
  9.  
  10. import org.bukkit.Bukkit;
  11. import org.bukkit.Material;
  12. import org.bukkit.craftbukkit.v1_21_R1.CraftEquipmentSlot;
  13. import org.bukkit.craftbukkit.v1_21_R1.CraftServer;
  14. import org.bukkit.craftbukkit.v1_21_R1.util.CraftNamespacedKey;
  15. import org.bukkit.event.Listener;
  16. import org.bukkit.inventory.EquipmentSlot;
  17. import org.bukkit.plugin.java.JavaPlugin;
  18.  
  19. import net.minecraft.core.Holder;
  20. import net.minecraft.core.HolderSet;
  21. import net.minecraft.core.Registry;
  22. import net.minecraft.core.component.DataComponentMap;
  23. import net.minecraft.core.registries.Registries;
  24. import net.minecraft.network.chat.Component;
  25. import net.minecraft.resources.ResourceKey;
  26. import net.minecraft.resources.ResourceLocation;
  27. import net.minecraft.server.MinecraftServer;
  28. import net.minecraft.tags.EnchantmentTags;
  29. import net.minecraft.tags.TagKey;
  30. import net.minecraft.world.item.Item;
  31. import net.minecraft.world.item.enchantment.Enchantment;
  32.  
  33.  
  34. public final class TestEnchantments extends JavaPlugin implements Listener {
  35.  
  36. // 3 - Get MinecraftServer and Enchantment Registry
  37. private static final MinecraftServer SERVER;
  38. private static final Registry<Enchantment> ENCHANTMENT_REGISTRY;
  39. static {
  40. SERVER = ((CraftServer)Bukkit.getServer()).getServer();
  41. ENCHANTMENT_REGISTRY = SERVER.registryAccess().registry(Registries.ENCHANTMENT).orElse(null);
  42. }
  43. // --
  44.  
  45. // 5.5 - Enchant Creation - Create Supported and Primary items sets:
  46. private static final String HOLDER_SET_NAMED_CONTENTS_FIELD = "c"; // 'contents' field of the HolderSet.Named
  47. private static final String HOLDER_REFERENCE_TAGS_FIELD = "b"; // 'tags' field of the Holder.Reference
  48. // --
  49.  
  50. @Override
  51. public void onEnable() {
  52. // 4 - Unfreeze Registry
  53. Reflex.setFieldValue(ENCHANTMENT_REGISTRY, "l", false); // MappedRegistry#frozen
  54. Reflex.setFieldValue(ENCHANTMENT_REGISTRY, "m", new IdentityHashMap<>()); // MappedRegistry#unregisteredIntrusiveHolders
  55. // --
  56.  
  57. // 5.1 - Enchant Creation - First, we need a ResourceKey for our enchantment(s):
  58. String enchantId = "custom_enchantment";
  59. ResourceKey<Enchantment> key = key(enchantId);
  60. // --
  61.  
  62. // 5.2 - Enchant Creation - Create name component:
  63. Component component = Component.literal("Custom Enchantment");
  64. // --
  65.  
  66. // 5.3 - Enchant Creation - Create set of exclusive enchantments:
  67. HolderSet<Enchantment> exclusiveSet = HolderSet.direct();
  68. // --
  69.  
  70. // 5.4 - Enchant Creation - Create effects map:
  71. DataComponentMap effects = DataComponentMap.builder().build();
  72. // --
  73.  
  74. // 5.5 - Enchant Creation - Create Supported and Primary items sets:
  75. HolderSet.Named<Item> supportedItems = createItemSet("enchant_supported", enchantId, Set.of(Material.DIAMOND_SWORD, Material.DIAMOND_AXE));
  76. HolderSet.Named<Item> primaryItems = createItemSet("enchant_primary", enchantId, Set.of(Material.DIAMOND_SWORD));
  77. // --
  78.  
  79. // 5.6 - Enchant Creation - Prepare Equipment Slots
  80. net.minecraft.world.entity.EquipmentSlotGroup[] slots = nmsSlots(new EquipmentSlot[]{ EquipmentSlot.HAND} );
  81. // --
  82.  
  83. // 5.7 - Enchant Creation - Create and register Enchantment
  84. int weight = 10;
  85. int maxLevel = 3;
  86. Enchantment.Cost minCost = new Enchantment.Cost(1, 11);
  87. Enchantment.Cost maxCost = new Enchantment.Cost(12, 11);
  88. int anvilCost = 2;
  89.  
  90. Enchantment.EnchantmentDefinition definition = Enchantment.definition(supportedItems, primaryItems, weight, maxLevel, minCost, maxCost, anvilCost, slots);
  91.  
  92. Enchantment enchantment = new Enchantment(component, definition, exclusiveSet, effects);
  93.  
  94. // You must create a holder, otherwise enchantment won't be registered.
  95. Holder.Reference<Enchantment> reference = ENCHANTMENT_REGISTRY.createIntrusiveHolder(enchantment);
  96. // Actual register code.
  97. Registry.register(ENCHANTMENT_REGISTRY, enchantId, enchantment);
  98. // --
  99.  
  100. // 6 - Modify Enchantment Tags
  101. boolean isCurse = false;
  102. boolean isTreasure = false;
  103. boolean isDiscoverable = true;
  104. boolean isTradeable = true;
  105.  
  106. if (isCurse) {
  107. addInTag(EnchantmentTags.CURSE, reference);
  108. }
  109. else {
  110. if (isTreasure) {
  111. addInTag(EnchantmentTags.TREASURE, reference);
  112. }
  113. else addInTag(EnchantmentTags.NON_TREASURE, reference);
  114.  
  115. if (isTradeable) {
  116. addInTag(EnchantmentTags.TRADEABLE, reference);
  117. }
  118. else removeFromTag(EnchantmentTags.TRADEABLE, reference);
  119.  
  120. if (isDiscoverable) {
  121. addInTag(EnchantmentTags.IN_ENCHANTING_TABLE, reference);
  122. }
  123. else removeFromTag(EnchantmentTags.IN_ENCHANTING_TABLE, reference);
  124. }
  125. // --
  126.  
  127. // 8 - Freeze Registry
  128. ENCHANTMENT_REGISTRY.freeze();
  129. // --
  130. }
  131.  
  132. // 2 - Resource Key Method
  133. private static ResourceKey<Enchantment> key(String name) {
  134. return ResourceKey.create(Registries.ENCHANTMENT, ResourceLocation.withDefaultNamespace(name));
  135. }
  136. // --
  137.  
  138. // 5.6 - Enchant Creation - Prepare Equipment Slots
  139. public static net.minecraft.world.entity.EquipmentSlotGroup[] nmsSlots(EquipmentSlot[] slots) {
  140. net.minecraft.world.entity.EquipmentSlotGroup[] nmsSlots = new net.minecraft.world.entity.EquipmentSlotGroup[slots.length];
  141.  
  142. for (int index = 0; index < nmsSlots.length; index++) {
  143. org.bukkit.inventory.EquipmentSlot bukkitSlot = slots[index];
  144. nmsSlots[index] = CraftEquipmentSlot.getNMSGroup(bukkitSlot.getGroup());
  145. }
  146.  
  147. return nmsSlots;
  148. }
  149. // --
  150.  
  151. // 6 - Modify Enchantment Tags
  152. private void addInTag(TagKey<Enchantment> tagKey, Holder.Reference<Enchantment> reference) {
  153. modfiyTag(tagKey, reference, List::add);
  154. }
  155.  
  156. private void removeFromTag(TagKey<Enchantment> tagKey, Holder.Reference<Enchantment> reference) {
  157. modfiyTag(tagKey, reference, List::remove);
  158. }
  159.  
  160. private void modfiyTag(TagKey<Enchantment> tagKey,
  161. Holder.Reference<Enchantment> reference,
  162. BiConsumer<List<Holder<Enchantment>>, Holder.Reference<Enchantment>> consumer) {
  163. // Get HolderSet of the TagKey
  164. HolderSet.Named<Enchantment> holders = ENCHANTMENT_REGISTRY.getTag(tagKey).orElse(null);
  165. if (holders == null) {
  166. // this.plugin.warn(tagKey + ": Could not modify HolderSet. HolderSet is NULL.");
  167. getLogger().warning(tagKey + ": Could not modify HolderSet. HolderSet is NULL.");
  168. return;
  169. }
  170.  
  171. modfiyHolderSetContents(holders, reference, consumer);
  172. }
  173.  
  174. @SuppressWarnings("unchecked")
  175. private static <T> void modfiyHolderSetContents(HolderSet.Named<T> holders,
  176. Holder.Reference<T> reference,
  177. BiConsumer<List<Holder<T>>, Holder.Reference<T>> consumer) {
  178.  
  179. // We must use reflection to get a mutable Holder list from the HolderSet.
  180. List<Holder<T>> contents = new ArrayList<>((List<Holder<T>>) Reflex.getFieldValue(holders, HOLDER_SET_NAMED_CONTENTS_FIELD));
  181. // Do something with it.
  182. consumer.accept(contents, reference);
  183. // Assign it back to the HolderSet.
  184. Reflex.setFieldValue(holders, HOLDER_SET_NAMED_CONTENTS_FIELD, contents);
  185. }
  186. // --
  187.  
  188. // 5.5 - Enchant Creation - Create Supported and Primary items sets:
  189. @SuppressWarnings("unchecked")
  190. private static HolderSet.Named<Item> createItemSet(String prefix, String enchantId, Set<Material> materials) {
  191. Registry<Item> items = SERVER.registryAccess().registry(Registries.ITEM).orElseThrow();
  192. TagKey<Item> customKey = TagKey.create(Registries.ITEM, ResourceLocation.withDefaultNamespace(prefix + "/" + enchantId));
  193. HolderSet.Named<Item> customItems = items.getOrCreateTag(customKey);
  194. List<Holder<Item>> holders = new ArrayList<>();
  195.  
  196. materials.forEach(material -> {
  197. ResourceLocation location = CraftNamespacedKey.toMinecraft(material.getKey());
  198. Holder.Reference<Item> holder = items.getHolder(location).orElse(null);
  199. if (holder == null) return;
  200.  
  201. // We must reassign the 'tags' field value because of the HolderSet#contains(Holder<T> holder) behavior.
  202. // It checks if Holder.Reference.is(this.key) -> Holder.Reference.tags.contains(key). Where 'key' is our custom key created above.
  203. // So, even if our HolderSet content is filled with items, we have to include their tag to the actual items in registry.
  204. Set<TagKey<Item>> holderTags = new HashSet<>((Set<TagKey<Item>>) Reflex.getFieldValue(holder, HOLDER_REFERENCE_TAGS_FIELD));
  205. holderTags.add(customKey);
  206. Reflex.setFieldValue(holder, HOLDER_REFERENCE_TAGS_FIELD, holderTags);
  207.  
  208. holders.add(holder);
  209. });
  210.  
  211. Reflex.setFieldValue(customItems, HOLDER_SET_NAMED_CONTENTS_FIELD, holders);
  212.  
  213. return customItems;
  214. }
  215. // --
  216.  
  217. }
  218.  
  219.  
Add Comment
Please, Sign In to add comment