Stores original metadata to all armored elytras

This commit is contained in:
Kristian Knarvik 2023-03-20 12:25:52 +01:00
parent 20e1bc4550
commit bb9710acfc
7 changed files with 176 additions and 54 deletions

View File

@ -7,6 +7,7 @@ import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -15,7 +16,11 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Integer>> {
/**
* A container for keeping track of enchantments, with additional filtering capabilities.
*/
public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Integer>>, Serializable {
private Map<Enchantment, Integer> enchantments;
/**
@ -219,9 +224,8 @@ public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Int
}
final List<Enchantment> blackList =
second.keySet().stream()
.flatMap(enchantment -> getMutuallyExclusiveEnchantments(enchantment).stream())
.toList();
second.keySet().stream().flatMap(enchantment ->
getMutuallyExclusiveEnchantments(enchantment).stream()).toList();
blackList.forEach(first.keySet()::remove);
final Map<Enchantment, Integer> combined = new HashMap<>(first);
@ -260,4 +264,5 @@ public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Int
public Iterator<Map.Entry<Enchantment, Integer>> iterator() {
return enchantments.entrySet().iterator();
}
}

View File

@ -260,7 +260,7 @@ public class NBTEditor {
* @param item <p>The item to get item meta for</p>
* @return <p>The existing or new item meta</p>
*/
private static ItemMeta getOrCreateItemMeta(ItemStack item) {
public static ItemMeta getOrCreateItemMeta(ItemStack item) {
final ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() :
Bukkit.getItemFactory().getItemMeta(item.getType());
if (meta == null) {

View File

@ -1,12 +1,11 @@
package net.knarcraft.armoredelytra.metadata;
import org.bukkit.enchantments.Enchantment;
import net.knarcraft.armoredelytra.container.EnchantmentContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.List;
/**
* An object for storing the original metadata for an armored elytra.
@ -18,11 +17,11 @@ import java.util.Set;
*/
public class OriginalMetadata implements Serializable {
private Set<Enchantment> armorEnchantments = new HashSet<>();
private Set<Enchantment> elytraEnchantments = new HashSet<>();
private String elytraLore;
private EnchantmentContainer armorEnchantments = new EnchantmentContainer();
private EnchantmentContainer elytraEnchantments = new EnchantmentContainer();
private List<String> elytraLore;
private String elytraName;
private String armorLore;
private List<String> armorLore;
private String armorName;
public OriginalMetadata() {
@ -34,8 +33,8 @@ public class OriginalMetadata implements Serializable {
*
* @return <p>The stored armor enchantments.</p>
*/
public @NotNull Set<Enchantment> getArmorEnchantments() {
return new HashSet<>(armorEnchantments);
public @NotNull EnchantmentContainer getArmorEnchantments() {
return armorEnchantments;
}
/**
@ -43,8 +42,8 @@ public class OriginalMetadata implements Serializable {
*
* @return <p>The stored elytra enchantments.</p>
*/
public @NotNull Set<Enchantment> getElytraEnchantments() {
return new HashSet<>(elytraEnchantments);
public @NotNull EnchantmentContainer getElytraEnchantments() {
return elytraEnchantments;
}
/**
@ -52,7 +51,7 @@ public class OriginalMetadata implements Serializable {
*
* @return <p>The original elytra lore.</p>
*/
public @Nullable String getElytraLore() {
public @Nullable List<String> getElytraLore() {
return this.elytraLore;
}
@ -70,7 +69,7 @@ public class OriginalMetadata implements Serializable {
*
* @return <p>The original armor lore.</p>
*/
public @Nullable String getArmorLore() {
public @Nullable List<String> getArmorLore() {
return this.armorLore;
}
@ -87,80 +86,54 @@ public class OriginalMetadata implements Serializable {
* Sets the stored lore of this armored elytra's armor.
*
* @param armorLore <p>The armor lore to store.</p>
* @return <p>This original metadata.</p>
*/
public OriginalMetadata setArmorLore(@NotNull String armorLore) {
public void setArmorLore(@NotNull List<String> armorLore) {
this.armorLore = armorLore;
return this;
}
/**
* Sets the stored elytra lore of this armored elytra's elytra.
*
* @param elytraLore <p>The elytra lore to store.</p>
* @return <p>This original metadata.</p>
*/
public OriginalMetadata setElytraLore(@NotNull String elytraLore) {
public void setElytraLore(@NotNull List<String> elytraLore) {
this.elytraLore = elytraLore;
return this;
}
/**
* Sets the stored elytra name of this armored elytra's elytra.
*
* @param elytraName <p>The elytra name to store.</p>
* @return <p>This original metadata.</p>
*/
public OriginalMetadata setElytraName(@NotNull String elytraName) {
public void setElytraName(@NotNull String elytraName) {
this.elytraName = elytraName;
return this;
}
/**
* Sets the stored armor name of this armored elytra's armor.
*
* @param armorName <p>The armor name to store.</p>
* @return <p>This original metadata.</p>
*/
public OriginalMetadata setArmorName(@NotNull String armorName) {
public void setArmorName(@NotNull String armorName) {
this.armorName = armorName;
return this;
}
/**
* Sets the stored enchantments for this armored elytra's armor.
*
* @param armorEnchantments <p>The armor enchantments to store.</p>
* @return <p>This original metadata.</p>
*/
public OriginalMetadata setArmorEnchantments(@NotNull Set<Enchantment> armorEnchantments) {
public void setArmorEnchantments(@NotNull EnchantmentContainer armorEnchantments) {
this.armorEnchantments = armorEnchantments;
return this;
}
/**
* Sets the stored enchantments for this armored elytra's elytra.
*
* @param elytraEnchantments <p>The elytra enchantments to store.</p>
* @return <p>This original metadata.</p>
*/
public OriginalMetadata setElytraEnchantments(@NotNull Set<Enchantment> elytraEnchantments) {
public void setElytraEnchantments(@NotNull EnchantmentContainer elytraEnchantments) {
this.elytraEnchantments = elytraEnchantments;
return this;
}
/**
* Adds the given enchantments to armor enchantments.
*
* <p>The purpose of this method is to combine enchantments for the original chestplate, and any chest-plates used
* to upgrade the armored elytra.</p>
*
* @param enchantments <p>The enchantments to add</p>
* @return <p>This original metadata.</p>
*/
public OriginalMetadata addArmorEnchantments(@NotNull Set<Enchantment> enchantments) {
this.armorEnchantments.addAll(enchantments);
return this;
}
}

View File

@ -5,6 +5,7 @@ import net.knarcraft.armoredelytra.config.ConfigLoader;
import net.knarcraft.armoredelytra.container.EnchantmentContainer;
import net.knarcraft.armoredelytra.metadata.DurabilityManager;
import net.knarcraft.armoredelytra.metadata.NBTEditor;
import net.knarcraft.armoredelytra.metadata.OriginalMetadata;
import net.knarcraft.armoredelytra.property.ArmorTier;
import org.bukkit.inventory.ItemStack;
@ -16,6 +17,7 @@ public class ArmoredElytraBuilder {
private final DurabilityManager durabilityManager;
private final ConfigLoader config;
private final ArmoredElytra plugin;
private final OriginalMetadataBuilder metadataBuilder;
public ArmoredElytraBuilder(NBTEditor nbtEditor, DurabilityManager durabilityManager,
ConfigLoader config, ArmoredElytra plugin) {
@ -24,6 +26,7 @@ public class ArmoredElytraBuilder {
this.durabilityManager = durabilityManager;
this.config = config;
this.plugin = plugin;
this.metadataBuilder = new OriginalMetadataBuilder(plugin, nbtEditor);
}
/**
@ -79,14 +82,16 @@ public class ArmoredElytraBuilder {
* @return The new armored elytra.
*/
public ItemStack combine(ItemStack elytra, ItemStack combiner, ArmorTier armorTier, @Nullable String name) {
return newBuilder().ofElytra(elytra).combineWith(combiner, armorTier).withName(name).build();
return getArmoredElytraWithOriginalMetadata(elytra, combiner,
newBuilder().ofElytra(elytra).combineWith(combiner, armorTier).withName(name).build());
}
/**
* See {@link #combine(ItemStack, ItemStack, ArmorTier, String)} for unknown armor tiers.
*/
public ItemStack combine(ItemStack elytra, ItemStack combiner, @Nullable String name) {
return newBuilder().ofElytra(elytra).combineWith(combiner).withName(name).build();
return getArmoredElytraWithOriginalMetadata(elytra, combiner,
newBuilder().ofElytra(elytra).combineWith(combiner).withName(name).build());
}
/**
@ -99,4 +104,18 @@ public class ArmoredElytraBuilder {
return newBuilder().newItem(armorTier).build();
}
/**
* Adds/Updates the original metadata for an armored elytra, and returns the armored elytra.
*
* @param elytra <p>The base elytra.</p>
* @param armor <p>The armor/armored elytra combined with the elytra.</p>
* @param armoredElytra <p>The combined armored elytra.</p>
* @return <p>The armored elytra with updated original metadata.</p>
*/
private ItemStack getArmoredElytraWithOriginalMetadata(ItemStack elytra, ItemStack armor, ItemStack armoredElytra) {
OriginalMetadata originalMetadata = metadataBuilder.getMergedOriginalMetaData(elytra, armor);
nbtEditor.updateOriginalMetadata(armoredElytra, originalMetadata);
return armoredElytra;
}
}

View File

@ -0,0 +1,125 @@
package net.knarcraft.armoredelytra.metadata.builder;
import net.knarcraft.armoredelytra.ArmoredElytra;
import net.knarcraft.armoredelytra.container.EnchantmentContainer;
import net.knarcraft.armoredelytra.metadata.NBTEditor;
import net.knarcraft.armoredelytra.metadata.OriginalMetadata;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Objects;
import java.util.function.Predicate;
/**
* A class for building the combined original metadata for the given items.
*/
public class OriginalMetadataBuilder {
private final ArmoredElytra plugin;
private final NBTEditor nbtEditor;
/**
* Instantiates a new original metadata builder
*
* @param plugin <p>A reference to the plugin class.</p>
* @param nbtEditor <p>A reference to the NBT editor</p>
*/
public OriginalMetadataBuilder(ArmoredElytra plugin, NBTEditor nbtEditor) {
this.plugin = plugin;
this.nbtEditor = nbtEditor;
}
/**
* Gets the merged original metadata for two items.
*
* @param elytra <p>The input (armored) elytra.</p>
* @param armor <p>The armored elytra or chestplate to be combined with the elytra.</p>
* @return <p>The combined original metadata for the two items.</p>
*/
public OriginalMetadata getMergedOriginalMetaData(ItemStack elytra, ItemStack armor) {
OriginalMetadata elytraMetadata = nbtEditor.getOriginalMetadata(elytra);
OriginalMetadata armorMetadata = nbtEditor.getOriginalMetadata(armor);
// If metadata is missing from one of the items, create new metadata
if (elytraMetadata == null) {
elytraMetadata = createElytraMetadata(elytra);
}
if (armorMetadata == null) {
armorMetadata = createArmorMetadata(armor);
}
// Merge elytra and armor enchantments
elytraMetadata.getElytraEnchantments().merge(armorMetadata.getElytraEnchantments());
elytraMetadata.getArmorEnchantments().merge(armorMetadata.getArmorEnchantments());
// Use the elytra name from the armor if not set for the elytra
if (useSecondValue(elytraMetadata.getElytraName(), armorMetadata.getElytraName(), (item) -> !item.isBlank())) {
elytraMetadata.setElytraName(Objects.requireNonNull(armorMetadata.getElytraName()));
}
// Use the armor name from the armor if not set for the elytra
if (useSecondValue(elytraMetadata.getArmorName(), armorMetadata.getArmorName(), (item) -> !item.isBlank())) {
elytraMetadata.setArmorName(Objects.requireNonNull(armorMetadata.getArmorName()));
}
// Use the elytra lore from the armor if not set for the elytra
if (useSecondValue(elytraMetadata.getElytraLore(), armorMetadata.getElytraLore(), (item) -> !item.isEmpty())) {
elytraMetadata.setElytraLore(Objects.requireNonNull(armorMetadata.getElytraLore()));
}
// Use the armor lore from the armor if not set for the elytra
if (useSecondValue(elytraMetadata.getArmorLore(), armorMetadata.getArmorLore(), (item) -> !item.isEmpty())) {
elytraMetadata.setArmorLore(Objects.requireNonNull(armorMetadata.getArmorLore()));
}
return elytraMetadata;
}
/**
* A test to see if the second value given matches the predicate, and the first one does not.
*
* @param value1 <p>The first value to test.</p>
* @param value2 <p>The second value to test.</p>
* @param predicate <p>The predicate to run.</p>
* @param <T> <p>The type of the values.</p>
* @return <p>True if the second value matches the predicate, but the first value does not.</p>
*/
private <T> boolean useSecondValue(T value1, T value2, Predicate<T> predicate) {
return (value1 == null || !predicate.test(value1)) && (value2 != null && predicate.test(value2));
}
/**
* Creates metadata for the given elytra item.
*
* @param elytra <p>The elytra to create original metadata for.</p>
* @return <p>The generated metadata.</p>
*/
private OriginalMetadata createElytraMetadata(ItemStack elytra) {
OriginalMetadata newMetadata = new OriginalMetadata();
newMetadata.setElytraEnchantments(new EnchantmentContainer(elytra.getEnchantments(), plugin));
ItemMeta meta = NBTEditor.getOrCreateItemMeta(elytra);
if (meta.getLore() != null) {
newMetadata.setElytraLore(meta.getLore());
}
newMetadata.setElytraName(meta.getDisplayName());
return newMetadata;
}
/**
* Creates metadata for the given armor item.
*
* @param armor <p>The armor to create original metadata for.</p>
* @return <p>The generated metadata.</p>
*/
private OriginalMetadata createArmorMetadata(ItemStack armor) {
OriginalMetadata newMetadata = new OriginalMetadata();
newMetadata.setArmorEnchantments(new EnchantmentContainer(armor.getEnchantments(), plugin));
ItemMeta meta = NBTEditor.getOrCreateItemMeta(armor);
if (meta.getLore() != null) {
newMetadata.setArmorLore(meta.getLore());
}
newMetadata.setArmorName(meta.getDisplayName());
return newMetadata;
}
}