Skip to content

Custom Enchantment API#401

Closed
NickAcPT wants to merge 1 commit into
PurpurMC:ver/1.17from
NickAcPT:feat/custom-enchantments
Closed

Custom Enchantment API#401
NickAcPT wants to merge 1 commit into
PurpurMC:ver/1.17from
NickAcPT:feat/custom-enchantments

Conversation

@NickAcPT

@NickAcPT NickAcPT commented Jun 22, 2021

Copy link
Copy Markdown

This PR aims to allow plugins that depend on the Purpur API to create custom NamespaceKey based enchantments.

As it's clear by the PR status, this is still very much WIP and I'd like to receive feedback along the way. More so when it comes to git stuff, as I'm not very used to rebasing and reordering commits.

Goals

There are a few goals that I want this PR to achieve before it gets merged:

  • Allow plugins to add custom enchantments with the Bukkit API
  • Allow plugins to query and interact with custom enchantments without having to query new APIs (interop with old bukkit enchantments API)
  • Allow players to apply custom enchantments with the vanilla enchant command (vanilla interop)
  • Make sure not to break other custom enchantment plugins

Considerations

Since this feature is supposed to be flexible for a lot of use-cases, there are some things that need to be considered:

  • The package where the code resides. Is org.bukkit.enchantments.custom even good enough? Should it be on a Purpur package? It is on a purpur package now.
  • API structure. Should plugins have to implement a separate interface or extend from a Bukkit class? Should our CustomEnchantment class/interface extend/implement any Bukkit class/interface? Custom Enchantments extend our CustomEnchantment class and are registered within the server. Our CustomEnchantment class extends Bukkit's Enchantment class.
  • How to show it for clients. Show custom enchantments follow the same layout as regular enchantments? Should this change introduce a way to modify the layout of the enchantments as a configuration setting? Custom Enchantments can have their display name fully customised. Still unsure about the second question.
  • Anvil support. Does Vanilla even handle custom enchantments well with Anvils? What about books? Can we apply custom enchantments to items with an anvil? What about enchantment merging?
  • Exposing enchantments properly. Is this API flexible enough for anyone to use it? What about when enchantments need Listeners to function?

Comment thread patches/api/0042-Custom-enchantments-API.patch Outdated
@NickAcPT

Copy link
Copy Markdown
Author

Please excuse the inactivity. I am still working on this, just not here.

This is mainly because I don't have a lot of experience with Git when it comes to properly working with patches and merging them when they get added to the main branch.

While working on this, I somehow managed to locally reorder commits when merging from upstream.

Sadly, there's not much documentation regarding this (things like making sure that patches are up-to-date and properly applied while working on a PR on a separate branch), and there's no way for me to get in contact to get proper support for this.

@NickAcPT

Copy link
Copy Markdown
Author

Okay, I made some progress regarding custom enchantments:

2021-06-25_11-04-56.mp4

But before I can move any further, I need to ask the team (mainly @BillyGalbreath @jpenilla) about their thoughts on this PR.

Will this get merged once it's finished, or is it something that will be on hold forever (Paper moment™)? What is the general opinion of the team regarding this?

I remember speaking earlier with Billy and it appeared that they were okay with this PR, but I just want confirmation if that is still the case.

@katekerllenevich

Copy link
Copy Markdown
Member

This PR looks great so far, I'm excited to see what you create. As a member of the team, I think that you should keep going on this PR and that it will almost definitely get merged (with some critique).

@NickAcPT NickAcPT closed this Jun 25, 2021
@NickAcPT NickAcPT force-pushed the feat/custom-enchantments branch from 64dbad7 to 58ae05b Compare June 25, 2021 11:11
@NickAcPT

NickAcPT commented Jun 25, 2021

Copy link
Copy Markdown
Author

Oops, accidentally closed this by mistake when I reset with Purpur's branch.
Let me commit the code I have so far and I'll reopen this

@NickAcPT NickAcPT reopened this Jun 25, 2021
Comment on lines +15 to +30
+ // Purpur start - intercept lore and display custom enchantments
+ if (ItemStack.shouldShowInTooltip(stack.getHideFlags(), ItemStack.TooltipPart.ENCHANTMENTS)) {
+ java.util.Set<Map.Entry<net.minecraft.world.item.enchantment.Enchantment, Integer>> enchantments = net.minecraft.world.item.enchantment.EnchantmentHelper.deserializeEnchantments(stack.getEnchantmentTags()).entrySet();
+ for (Map.Entry<net.minecraft.world.item.enchantment.Enchantment, Integer> enchantment : enchantments) {
+ if (enchantment.getKey() instanceof net.pl3x.purpur.enchantments.CraftCustomEnchantment customEnchantment) {
+ org.bukkit.inventory.ItemStack itemStack = stack.asBukkitMirror();
+ java.util.List<net.kyori.adventure.text.Component> loreList = itemStack.lore();
+ if (loreList == null) loreList = new java.util.ArrayList<>();
+
+ loreList.add(customEnchantment.getCustomEnchantment().displayName(enchantment.getValue()).decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false).append(net.pl3x.purpur.enchantments.CraftCustomEnchantment.customEnchantmentMagicSuffix));
+
+ itemStack.lore(loreList);
+ }
+ }
+ }
+ // Purpur end

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that this might be a bit "sketchy", if there's any other ideas that don't involve me messing with raw NBT, let me know.

Comment on lines +38 to +50
+ // Purpur start - intercept lore and remove custom enchantments if they come from itemstacks
+ org.bukkit.inventory.ItemStack bukkitStackMirror = itemstack.asBukkitMirror();
+ if (ItemStack.shouldShowInTooltip(itemstack.getHideFlags(), ItemStack.TooltipPart.ENCHANTMENTS)) {
+ java.util.List<net.kyori.adventure.text.Component> loreList = bukkitStackMirror.lore();
+ if (loreList != null) {
+ loreList.removeIf(c -> {
+ net.kyori.adventure.text.Component customEnchantmentMagicSuffix = net.pl3x.purpur.enchantments.CraftCustomEnchantment.customEnchantmentMagicSuffix;
+ return c.contains(customEnchantmentMagicSuffix, net.kyori.adventure.text.Component.EQUALS);
+ });
+ bukkitStackMirror.lore(loreList);
+ }
+ }
+ // Purpur end

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that this might be a bit "sketchy", if there's any other ideas that don't involve me messing with raw NBT, let me know.

Comment on lines +74 to +75
- }).then(Commands.argument("targets", EntityArgument.entities()).then(Commands.argument("enchantment", ItemEnchantmentArgument.enchantment()).executes((context) -> {
+ }).then(Commands.argument("targets", EntityArgument.entities()).then(Commands.argument("enchantment", ItemEnchantmentArgument.enchantment()).suggests(SUGGEST_ENCHANTMENTS).executes((context) -> { // Purpur - Make enchantment suggestions server side

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is required to let the client know that the server is proving the completion. Client still shows command in red, although the enchantment is valid server-side.
image

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will probably have to edit brigadier node for enchant command and redo the argument completion for that specific argument. Shouldn't be too hard afaik

Comment on lines +105 to +110
+ },
+ TOOL {
+ @Override
+ public boolean canEnchant(Item item) {
+ return item instanceof net.minecraft.world.item.ShovelItem || item instanceof net.minecraft.world.item.PickaxeItem || item instanceof net.minecraft.world.item.AxeItem || item instanceof net.minecraft.world.item.HoeItem;
+ }

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added to bring the EnchantmentCategory enum into parity with it's NMS version

Comment on lines +138 to +139
+ //Invisible suffix used to skip custom enchantment lore lines
+ public final static net.kyori.adventure.text.Component customEnchantmentMagicSuffix = net.kyori.adventure.text.Component.space().color(TextColor.color(0xfa02ff)).append(net.kyori.adventure.text.Component.space().color(TextColor.color(0x26b8ff)));

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit questionable, I know.
This is here because the lore needs to be filtered when reading items because creative players override the items on the server when interacting with them.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe see where creative packets are parsed and do some funky filtering logic there? Seems like filtering this out asap could be a good idea, would love some input from others tho.

@NickAcPT NickAcPT Jul 1, 2021

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Items are read and written to the protocol in multiple places.
I think having the filtering/processing being done once on the read/writeItemStack method is for the best since that means that we only have to do it in one central place. I'll be waiting for other reviewers to get their opinion on this.

(cc: @YouHaveTrouble)

@NickAcPT

NickAcPT commented Aug 22, 2021

Copy link
Copy Markdown
Author

Closing PR as development of these changes is now being done downstream.

@NickAcPT NickAcPT closed this Aug 22, 2021
@NickAcPT NickAcPT deleted the feat/custom-enchantments branch August 22, 2021 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants