Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package spot.testenchantments;
- import java.util.ArrayList;
- import java.util.HashSet;
- import java.util.IdentityHashMap;
- import java.util.List;
- import java.util.Set;
- import java.util.function.BiConsumer;
- import org.bukkit.Bukkit;
- import org.bukkit.Material;
- import org.bukkit.craftbukkit.v1_21_R1.CraftEquipmentSlot;
- import org.bukkit.craftbukkit.v1_21_R1.CraftServer;
- import org.bukkit.craftbukkit.v1_21_R1.util.CraftNamespacedKey;
- import org.bukkit.event.Listener;
- import org.bukkit.inventory.EquipmentSlot;
- import org.bukkit.plugin.java.JavaPlugin;
- import net.minecraft.core.Holder;
- import net.minecraft.core.HolderSet;
- import net.minecraft.core.Registry;
- import net.minecraft.core.component.DataComponentMap;
- import net.minecraft.core.registries.Registries;
- import net.minecraft.network.chat.Component;
- import net.minecraft.resources.ResourceKey;
- import net.minecraft.resources.ResourceLocation;
- import net.minecraft.server.MinecraftServer;
- import net.minecraft.tags.EnchantmentTags;
- import net.minecraft.tags.TagKey;
- import net.minecraft.world.item.Item;
- import net.minecraft.world.item.enchantment.Enchantment;
- public final class TestEnchantments extends JavaPlugin implements Listener {
- // 3 - Get MinecraftServer and Enchantment Registry
- private static final MinecraftServer SERVER;
- private static final Registry<Enchantment> ENCHANTMENT_REGISTRY;
- static {
- SERVER = ((CraftServer)Bukkit.getServer()).getServer();
- ENCHANTMENT_REGISTRY = SERVER.registryAccess().registry(Registries.ENCHANTMENT).orElse(null);
- }
- // --
- // 5.5 - Enchant Creation - Create Supported and Primary items sets:
- private static final String HOLDER_SET_NAMED_CONTENTS_FIELD = "c"; // 'contents' field of the HolderSet.Named
- private static final String HOLDER_REFERENCE_TAGS_FIELD = "b"; // 'tags' field of the Holder.Reference
- // --
- @Override
- public void onEnable() {
- // 4 - Unfreeze Registry
- Reflex.setFieldValue(ENCHANTMENT_REGISTRY, "l", false); // MappedRegistry#frozen
- Reflex.setFieldValue(ENCHANTMENT_REGISTRY, "m", new IdentityHashMap<>()); // MappedRegistry#unregisteredIntrusiveHolders
- // --
- // 5.1 - Enchant Creation - First, we need a ResourceKey for our enchantment(s):
- String enchantId = "custom_enchantment";
- ResourceKey<Enchantment> key = key(enchantId);
- // --
- // 5.2 - Enchant Creation - Create name component:
- Component component = Component.literal("Custom Enchantment");
- // --
- // 5.3 - Enchant Creation - Create set of exclusive enchantments:
- HolderSet<Enchantment> exclusiveSet = HolderSet.direct();
- // --
- // 5.4 - Enchant Creation - Create effects map:
- DataComponentMap effects = DataComponentMap.builder().build();
- // --
- // 5.5 - Enchant Creation - Create Supported and Primary items sets:
- HolderSet.Named<Item> supportedItems = createItemSet("enchant_supported", enchantId, Set.of(Material.DIAMOND_SWORD, Material.DIAMOND_AXE));
- HolderSet.Named<Item> primaryItems = createItemSet("enchant_primary", enchantId, Set.of(Material.DIAMOND_SWORD));
- // --
- // 5.6 - Enchant Creation - Prepare Equipment Slots
- net.minecraft.world.entity.EquipmentSlotGroup[] slots = nmsSlots(new EquipmentSlot[]{ EquipmentSlot.HAND} );
- // --
- // 5.7 - Enchant Creation - Create and register Enchantment
- int weight = 10;
- int maxLevel = 3;
- Enchantment.Cost minCost = new Enchantment.Cost(1, 11);
- Enchantment.Cost maxCost = new Enchantment.Cost(12, 11);
- int anvilCost = 2;
- Enchantment.EnchantmentDefinition definition = Enchantment.definition(supportedItems, primaryItems, weight, maxLevel, minCost, maxCost, anvilCost, slots);
- Enchantment enchantment = new Enchantment(component, definition, exclusiveSet, effects);
- // You must create a holder, otherwise enchantment won't be registered.
- Holder.Reference<Enchantment> reference = ENCHANTMENT_REGISTRY.createIntrusiveHolder(enchantment);
- // Actual register code.
- Registry.register(ENCHANTMENT_REGISTRY, enchantId, enchantment);
- // --
- // 6 - Modify Enchantment Tags
- boolean isCurse = false;
- boolean isTreasure = false;
- boolean isDiscoverable = true;
- boolean isTradeable = true;
- if (isCurse) {
- addInTag(EnchantmentTags.CURSE, reference);
- }
- else {
- if (isTreasure) {
- addInTag(EnchantmentTags.TREASURE, reference);
- }
- else addInTag(EnchantmentTags.NON_TREASURE, reference);
- if (isTradeable) {
- addInTag(EnchantmentTags.TRADEABLE, reference);
- }
- else removeFromTag(EnchantmentTags.TRADEABLE, reference);
- if (isDiscoverable) {
- addInTag(EnchantmentTags.IN_ENCHANTING_TABLE, reference);
- }
- else removeFromTag(EnchantmentTags.IN_ENCHANTING_TABLE, reference);
- }
- // --
- // 8 - Freeze Registry
- ENCHANTMENT_REGISTRY.freeze();
- // --
- }
- // 2 - Resource Key Method
- private static ResourceKey<Enchantment> key(String name) {
- return ResourceKey.create(Registries.ENCHANTMENT, ResourceLocation.withDefaultNamespace(name));
- }
- // --
- // 5.6 - Enchant Creation - Prepare Equipment Slots
- public static net.minecraft.world.entity.EquipmentSlotGroup[] nmsSlots(EquipmentSlot[] slots) {
- net.minecraft.world.entity.EquipmentSlotGroup[] nmsSlots = new net.minecraft.world.entity.EquipmentSlotGroup[slots.length];
- for (int index = 0; index < nmsSlots.length; index++) {
- org.bukkit.inventory.EquipmentSlot bukkitSlot = slots[index];
- nmsSlots[index] = CraftEquipmentSlot.getNMSGroup(bukkitSlot.getGroup());
- }
- return nmsSlots;
- }
- // --
- // 6 - Modify Enchantment Tags
- private void addInTag(TagKey<Enchantment> tagKey, Holder.Reference<Enchantment> reference) {
- modfiyTag(tagKey, reference, List::add);
- }
- private void removeFromTag(TagKey<Enchantment> tagKey, Holder.Reference<Enchantment> reference) {
- modfiyTag(tagKey, reference, List::remove);
- }
- private void modfiyTag(TagKey<Enchantment> tagKey,
- Holder.Reference<Enchantment> reference,
- BiConsumer<List<Holder<Enchantment>>, Holder.Reference<Enchantment>> consumer) {
- // Get HolderSet of the TagKey
- HolderSet.Named<Enchantment> holders = ENCHANTMENT_REGISTRY.getTag(tagKey).orElse(null);
- if (holders == null) {
- // this.plugin.warn(tagKey + ": Could not modify HolderSet. HolderSet is NULL.");
- getLogger().warning(tagKey + ": Could not modify HolderSet. HolderSet is NULL.");
- return;
- }
- modfiyHolderSetContents(holders, reference, consumer);
- }
- @SuppressWarnings("unchecked")
- private static <T> void modfiyHolderSetContents(HolderSet.Named<T> holders,
- Holder.Reference<T> reference,
- BiConsumer<List<Holder<T>>, Holder.Reference<T>> consumer) {
- // We must use reflection to get a mutable Holder list from the HolderSet.
- List<Holder<T>> contents = new ArrayList<>((List<Holder<T>>) Reflex.getFieldValue(holders, HOLDER_SET_NAMED_CONTENTS_FIELD));
- // Do something with it.
- consumer.accept(contents, reference);
- // Assign it back to the HolderSet.
- Reflex.setFieldValue(holders, HOLDER_SET_NAMED_CONTENTS_FIELD, contents);
- }
- // --
- // 5.5 - Enchant Creation - Create Supported and Primary items sets:
- @SuppressWarnings("unchecked")
- private static HolderSet.Named<Item> createItemSet(String prefix, String enchantId, Set<Material> materials) {
- Registry<Item> items = SERVER.registryAccess().registry(Registries.ITEM).orElseThrow();
- TagKey<Item> customKey = TagKey.create(Registries.ITEM, ResourceLocation.withDefaultNamespace(prefix + "/" + enchantId));
- HolderSet.Named<Item> customItems = items.getOrCreateTag(customKey);
- List<Holder<Item>> holders = new ArrayList<>();
- materials.forEach(material -> {
- ResourceLocation location = CraftNamespacedKey.toMinecraft(material.getKey());
- Holder.Reference<Item> holder = items.getHolder(location).orElse(null);
- if (holder == null) return;
- // We must reassign the 'tags' field value because of the HolderSet#contains(Holder<T> holder) behavior.
- // It checks if Holder.Reference.is(this.key) -> Holder.Reference.tags.contains(key). Where 'key' is our custom key created above.
- // So, even if our HolderSet content is filled with items, we have to include their tag to the actual items in registry.
- Set<TagKey<Item>> holderTags = new HashSet<>((Set<TagKey<Item>>) Reflex.getFieldValue(holder, HOLDER_REFERENCE_TAGS_FIELD));
- holderTags.add(customKey);
- Reflex.setFieldValue(holder, HOLDER_REFERENCE_TAGS_FIELD, holderTags);
- holders.add(holder);
- });
- Reflex.setFieldValue(customItems, HOLDER_SET_NAMED_CONTENTS_FIELD, holders);
- return customItems;
- }
- // --
- }
Add Comment
Please, Sign In to add comment