- Fixed "fake" enchantments being allowed on armored elytras (only 1 kind of protection enchantment can be active at the same time, now only 1 can be put on an AE).

- Fixed invalid Armored Elytras showing up in the result slot.
This commit is contained in:
Pim van der Loos 2018-01-20 22:04:53 +01:00
parent 8ca829675e
commit 8eb6f094c8
8 changed files with 191 additions and 163 deletions

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>nl.pim16aap2</groupId> <groupId>nl.pim16aap2</groupId>
<artifactId>ArmoredElytra</artifactId> <artifactId>ArmoredElytra</artifactId>
<version>2.1-SNAPSHOT</version> <version>2.1.9-SNAPSHOT</version>
<repositories> <repositories>

View File

@ -1,13 +1,17 @@
package nl.pim16aap2.armoredElytra.handlers; package nl.pim16aap2.armoredElytra.handlers;
import java.lang.reflect.Field;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.logging.Level; import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_10_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftInventoryAnvil;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -17,12 +21,16 @@ import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.AnvilInventory; import org.bukkit.inventory.AnvilInventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import net.minecraft.server.v1_12_R1.ContainerAnvil;
import net.minecraft.server.v1_12_R1.Container;
import net.minecraft.server.v1_12_R1.ContainerDispenser;
import nl.pim16aap2.armoredElytra.ArmoredElytra; import nl.pim16aap2.armoredElytra.ArmoredElytra;
import nl.pim16aap2.armoredElytra.nms.NBTEditor; import nl.pim16aap2.armoredElytra.nms.NBTEditor;
import nl.pim16aap2.armoredElytra.util.Action; import nl.pim16aap2.armoredElytra.util.Action;
@ -65,12 +73,6 @@ public class EventHandlers implements Listener
anvilInventory.getItem(2).setAmount(0); anvilInventory.getItem(2).setAmount(0);
} }
// Accessor for this.plugin
public ArmoredElytra getPlugin()
{
return this.plugin;
}
// Check if the enchantment is allowed on elytras. // Check if the enchantment is allowed on elytras.
public boolean isAllowedEnchantment(Enchantment enchant) public boolean isAllowedEnchantment(Enchantment enchant)
{ {
@ -93,12 +95,12 @@ public class EventHandlers implements Listener
// Combine 2 maps of enchantments (and remove any invalid ones). // Combine 2 maps of enchantments (and remove any invalid ones).
public Map<Enchantment, Integer> combineEnchantments(Map<Enchantment, Integer> enchantments0, Map<Enchantment, Integer> enchantments1) public Map<Enchantment, Integer> combineEnchantments(Map<Enchantment, Integer> enchantments0, Map<Enchantment, Integer> enchantments1)
{ {
fixEnchantments(enchantments0); enchantments0 = fixEnchantments(enchantments0);
Map<Enchantment, Integer> combined = new HashMap<Enchantment, Integer>(enchantments0); Map<Enchantment, Integer> combined = new HashMap<Enchantment, Integer>(fixEnchantments(enchantments0));
if (enchantments1 != null) if (enchantments1 != null)
{ {
fixEnchantments(enchantments1); enchantments1 = fixEnchantments(enchantments1);
// Loop through the enchantments of item1. // Loop through the enchantments of item1.
for (Map.Entry<Enchantment, Integer > entry : enchantments1.entrySet()) for (Map.Entry<Enchantment, Integer > entry : enchantments1.entrySet())
{ {
@ -124,10 +126,54 @@ public class EventHandlers implements Listener
else if (enchantLevel == null) else if (enchantLevel == null)
combined.put(entry.getKey(), entry.getValue()); combined.put(entry.getKey(), entry.getValue());
} }
// Get the protection enchantment rating for both enchantment sets.
int protVal0 = getProtectionEnchantmentsVal(enchantments0);
int protVal1 = getProtectionEnchantmentsVal(enchantments1);
// If they have different
if (protVal0 != 0 && protVal1 != 0 && protVal0 != protVal1)
{
switch(protVal0)
{
case 1:
combined.remove(Enchantment.PROTECTION_ENVIRONMENTAL);
break;
case 2:
combined.remove(Enchantment.PROTECTION_EXPLOSIONS);
break;
case 4:
combined.remove(Enchantment.PROTECTION_FALL);
break;
case 8:
combined.remove(Enchantment.PROTECTION_FIRE);
break;
case 16:
combined.remove(Enchantment.PROTECTION_PROJECTILE);
break;
}
}
} }
return combined; return combined;
} }
// Function that returns which/how many protection enchantments there are.
public int getProtectionEnchantmentsVal(Map<Enchantment, Integer> enchantments)
{
int ret = 0;
if (enchantments.containsKey(Enchantment.PROTECTION_ENVIRONMENTAL))
ret += 1;
if ( enchantments.containsKey(Enchantment.PROTECTION_EXPLOSIONS))
ret += 2;
if ( enchantments.containsKey(Enchantment.PROTECTION_FALL))
ret += 4;
if ( enchantments.containsKey(Enchantment.PROTECTION_FIRE))
ret += 8;
if ( enchantments.containsKey(Enchantment.PROTECTION_PROJECTILE))
ret += 16;
return ret;
}
// Repair an Armored Elytra // Repair an Armored Elytra
public short repairItem(short curDur, ItemStack repairItem) public short repairItem(short curDur, ItemStack repairItem)
{ {
@ -150,39 +196,25 @@ public class EventHandlers implements Listener
return (short) (newDurability <= 0 ? 0 : newDurability); return (short) (newDurability <= 0 ? 0 : newDurability);
} }
// Check if there aren't any disallowed enchantments / curses in the map.
public boolean verifyEnchants(Map<Enchantment, Integer> enchantments)
{
for (Map.Entry<Enchantment, Integer > entry : enchantments.entrySet())
{
// If it's a cursed enchantment, while it's not allowed, it's false.
if (isCursedEnchantment(entry.getKey()) && !cursesAllowed)
return false;
// If the enchantment is not allowed, it's false.
else if (!isAllowedEnchantment(entry.getKey()))
return false;
}
return true;
}
// Remove any disallowed enchantments / curses in the map. // Remove any disallowed enchantments / curses in the map.
public Map<Enchantment, Integer> fixEnchantments(Map<Enchantment, Integer> enchantments) public Map<Enchantment, Integer> fixEnchantments(Map<Enchantment, Integer> enchantments)
{ {
Map<Enchantment, Integer> ret = new HashMap<Enchantment, Integer>(enchantments); Map<Enchantment, Integer> ret = new HashMap<Enchantment, Integer>(enchantments);
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet())
if (isAllowedEnchantment(entry.getKey()) == false && (cursesAllowed && isCursedEnchantment(entry.getKey())) == false) // If it is not an allowed enchantment OR a curse while it's not allowed
if (!isAllowedEnchantment(entry.getKey()) || (!cursesAllowed && isCursedEnchantment(entry.getKey())))
ret.remove(entry.getKey()); ret.remove(entry.getKey());
return ret; return ret;
} }
// Fix enchantments on an item. // Verify there aren't any disallowed enchantments / curses in the map.
public ItemStack fixEnchantments(ItemStack item) public boolean verifyEnchantments(Map<Enchantment, Integer> enchantments)
{ {
ItemStack result = item.clone(); for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet())
for (Map.Entry<Enchantment, Integer> entry : result.getEnchantments().entrySet()) // If it is not an allowed enchantment OR a curse while it's not allowed
if (isAllowedEnchantment(entry.getKey()) == false && (cursesAllowed && isCursedEnchantment(entry.getKey())) == false) if (!isAllowedEnchantment(entry.getKey()) || (!cursesAllowed && isCursedEnchantment(entry.getKey())))
result.removeEnchantment(entry.getKey()); return false;
return result; return true;
} }
// Get the armor tier from a chest plate. // Get the armor tier from a chest plate.
@ -248,6 +280,9 @@ public class EventHandlers implements Listener
itemTwo = tmp; itemTwo = tmp;
} }
if (itemOne.getType() != Material.ELYTRA)
return Action.NONE;
Material matTwo = itemTwo.getType(); Material matTwo = itemTwo.getType();
// If the elytra is to be combined with chest armor... // If the elytra is to be combined with chest armor...
@ -272,13 +307,96 @@ public class EventHandlers implements Listener
// If the armored elytra is not of the leather tier, but itemTwo is leather, // If the armored elytra is not of the leather tier, but itemTwo is leather,
// Pick the block action, as that would repair the elytra by default (vanilla). // Pick the block action, as that would repair the elytra by default (vanilla).
if (tier != ArmorTier.LEATHER && matTwo == Material.LEATHER) // Also block Armored Elytra + Elytra.
if (tier != ArmorTier.LEATHER && matTwo == Material.LEATHER || matTwo == Material.ELYTRA)
return Action.BLOCK; return Action.BLOCK;
} }
return Action.NONE; return Action.NONE;
} }
// Handle the anvil related parts. // Handle all anvil related stuff for this plugin.
@EventHandler
public void onAnvilInventoryOpen(PrepareAnvilEvent event)
{
Player p = (Player) event.getView().getPlayer();
ItemStack itemA = event.getInventory().getItem(0);
ItemStack itemB = event.getInventory().getItem(1);
ItemStack result = null;
if (itemA != null && itemB != null)
{
// If itemB is the elytra, while itemA isn't, switch itemA and itemB.
if (itemB.getType() == Material.ELYTRA && itemA.getType() != Material.ELYTRA)
{
result = itemA;
itemA = itemB;
itemB = result;
result = null;
}
}
// Check if there are items in both input slots.
if (itemA != null && itemB != null)
{
Action action = isValidInput(itemA, itemB);
ArmorTier newTier = ArmorTier.NONE;
ArmorTier curTier = nbtEditor.getArmorTier(itemA);
short durability = 0;
Map<Enchantment, Integer> enchantments = itemA.getEnchantments();
enchantments = fixEnchantments(enchantments);
switch (action)
{
case REPAIR:
newTier = curTier;
durability = repairItem(itemA.getDurability(), itemB);
break;
case COMBINE:
newTier = curTier;
durability = (short) (- itemA.getType().getMaxDurability() - itemA.getDurability() - itemB.getDurability());
durability = durability < 0 ? 0 : durability;
enchantments = combineEnchantments(enchantments, itemB.getEnchantments());
break;
case CREATE:
newTier = armorToTier(itemB.getType());
durability = 0;
enchantments = combineEnchantments(enchantments, itemB.getEnchantments());
break;
case ENCHANT:
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) itemB.getItemMeta();
newTier = curTier;
durability = itemA.getDurability();
// If there aren't any illegal enchantments on the book, continue as normal.
// Otherwise... Block.
if (verifyEnchantments(meta.getStoredEnchants()))
{
enchantments = combineEnchantments(enchantments, meta.getStoredEnchants());
break;
}
case BLOCK:
event.setResult(null);
p.updateInventory();
case NONE:
return;
}
result = new ItemStack(Material.ELYTRA, 1);
if (enchantments != null)
result.addUnsafeEnchantments(enchantments);
result.setDurability(durability);
result = nbtEditor.addArmorNBTTags(result, newTier, plugin.getConfigLoader().getBool("unbreakable"));
event.setResult(result);
}
// Check if either itemA or itemB is unoccupied.
if (itemA == null || itemB == null)
// If Item2 is occupied despite itemA or itemB not being occupied.
event.setResult(null);
p.updateInventory();
}
// Let the player take items out of the anvil.
@EventHandler @EventHandler
public void onInventoryClick(InventoryClickEvent e) public void onInventoryClick(InventoryClickEvent e)
{ {
@ -303,120 +421,27 @@ public class EventHandlers implements Listener
return; return;
} }
int slot = e.getRawSlot(); // Get slot int slot = e.getRawSlot();
if (slot == 2 && anvilInventory.getItem(0) != null && anvilInventory.getItem(1) != null && anvilInventory.getItem(2) != null) if (slot == 2 && anvilInventory.getItem(0) != null && anvilInventory.getItem(1) != null && anvilInventory.getItem(2) != null)
{ {
ArmorTier armortier = nbtEditor.getArmorTier(anvilInventory.getItem(2));
// If there's an armored elytra in the final slot... // If there's an armored elytra in the final slot...
if (anvilInventory.getItem(2).getType() == Material.ELYTRA && nbtEditor.getArmorTier(anvilInventory.getItem(2)) != ArmorTier.NONE) if (armortier != ArmorTier.NONE)
{ {
Action action = isValidInput(anvilInventory.getItem(0), anvilInventory.getItem(1)); // Create a new armored elytra and give that one to the player instead of the result.
// If there is no action to be taken, take no action... // This is done because after putting item0 in AFTER item1, the first letter of the color code shows up, this gets rid of that problem.
if (action == Action.NONE) ItemStack result = nbtEditor.addArmorNBTTags(anvilInventory.getItem(2), armortier, plugin.getConfigLoader().getBool("unbreakable"));
return;
// If the action is to block... Well, Block! (get rid of the end result!)
// Also check if there are any disallowed enchantments/curses on the result, delete the result.
if (action == Action.BLOCK)
{
// Send message to player that the recipe is invalid, as clearing the inventory doesn't work properly.
plugin.messagePlayer(p, ChatColor.RED, "Invalid recipe!");
anvilInventory.setItem(2, null);
anvilInventory.clear(2);
p.updateInventory();
p.updateInventory();
p.updateInventory();
return;
}
// Give the result to the player and clear the anvil's inventory. // Give the result to the player and clear the anvil's inventory.
if (e.isShiftClick()) if (e.isShiftClick())
p.getInventory().addItem(fixEnchantments(anvilInventory.getItem(2))); p.getInventory().addItem(result);
else else
p.setItemOnCursor(fixEnchantments(anvilInventory.getItem(2))); p.setItemOnCursor(result);
// Clean the anvil's inventory after transferring the items. // Clean the anvil's inventory after transferring the items.
cleanAnvil(anvilInventory); cleanAnvil(anvilInventory);
return; return;
} }
} }
new BukkitRunnable()
{
@Override
public void run()
{
ItemStack itemA = anvilInventory.getItem(0);
ItemStack itemB = anvilInventory.getItem(1);
ItemStack result = null;
if (itemA != null && itemB != null)
{
// If itemB is the elytra, while itemA isn't, switch itemA and itemB.
if (itemB.getType() == Material.ELYTRA && itemA.getType() != Material.ELYTRA)
{
result = itemA;
itemA = itemB;
itemB = result;
result = null;
}
}
// Check if there are items in both input slots.
if (itemA != null && itemB != null)
{
Action action = isValidInput(itemA, itemB);
ArmorTier newTier = ArmorTier.NONE;
ArmorTier curTier = nbtEditor.getArmorTier(itemA);
short durability = 0;
Map<Enchantment, Integer> enchantments = itemA.getEnchantments();
enchantments = fixEnchantments(enchantments);
switch (action)
{
case REPAIR:
newTier = curTier;
durability = repairItem(itemA.getDurability(), itemB);
break;
case ENCHANT:
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) itemB.getItemMeta();
newTier = curTier;
durability = itemA.getDurability();
enchantments = combineEnchantments(enchantments, meta.getStoredEnchants());
break;
case COMBINE:
newTier = curTier;
durability = (short) (- itemA.getType().getMaxDurability() - itemA.getDurability() - itemB.getDurability());
durability = durability < 0 ? 0 : durability;
enchantments = combineEnchantments(enchantments, itemB.getEnchantments());
break;
case CREATE:
newTier = armorToTier(itemB.getType());
durability = 0;
enchantments = combineEnchantments(enchantments, itemB.getEnchantments());
break;
case BLOCK:
if (anvilInventory.getItem(2) != null)
anvilInventory.getItem(2).setAmount(0);
p.updateInventory();
case NONE:
return;
}
result = new ItemStack(Material.ELYTRA, 1);
if (enchantments != null)
result.addUnsafeEnchantments(enchantments);
result.setDurability(durability);
result = nbtEditor.addArmorNBTTags(result, newTier, plugin.getConfigLoader().getBool("unbreakable"));
anvilInventory.setItem(2, result);
}
// Check if either itemA or itemB is unoccupied.
if (itemA == null || itemB == null)
// If Item2 is occupied despite Item1 not being occupied.
if (anvilInventory.getItem(2) != null)
// Then set the amount to 0.
anvilInventory.getItem(2).setAmount(0);
p.updateInventory();
}
}.runTaskLater(this.plugin, 1);
} }
} }
} }

View File

@ -17,9 +17,9 @@ import nl.pim16aap2.armoredElytra.util.ArmorTier;
public class NBTEditor_V1_10_R1 implements NBTEditor public class NBTEditor_V1_10_R1 implements NBTEditor
{ {
String elytraName; private String elytraName;
String elytraLore; private String elytraLore;
ArmoredElytra plugin; private ArmoredElytra plugin;
// Get the names and lores for every tier of armor. // Get the names and lores for every tier of armor.
public NBTEditor_V1_10_R1(String elytraName, String elytraLore, ArmoredElytra plugin) public NBTEditor_V1_10_R1(String elytraName, String elytraLore, ArmoredElytra plugin)

View File

@ -18,9 +18,9 @@ import nl.pim16aap2.armoredElytra.util.ArmorTier;
public class NBTEditor_V1_11_R1 implements NBTEditor public class NBTEditor_V1_11_R1 implements NBTEditor
{ {
String elytraName; private String elytraName;
String elytraLore; private String elytraLore;
ArmoredElytra plugin; private ArmoredElytra plugin;
// Get the names and lores for every tier of armor. // Get the names and lores for every tier of armor.
public NBTEditor_V1_11_R1(String elytraName, String elytraLore, ArmoredElytra plugin) public NBTEditor_V1_11_R1(String elytraName, String elytraLore, ArmoredElytra plugin)

View File

@ -17,9 +17,9 @@ import nl.pim16aap2.armoredElytra.util.ArmorTier;
public class NBTEditor_V1_12_R1 implements NBTEditor public class NBTEditor_V1_12_R1 implements NBTEditor
{ {
String elytraName; private String elytraName;
String elytraLore; private String elytraLore;
ArmoredElytra plugin; private ArmoredElytra plugin;
// Get the names and lores for every tier of armor. // Get the names and lores for every tier of armor.
public NBTEditor_V1_12_R1(String elytraName, String elytraLore, ArmoredElytra plugin) public NBTEditor_V1_12_R1(String elytraName, String elytraLore, ArmoredElytra plugin)

View File

@ -137,14 +137,12 @@ public class ConfigLoader
{ {
File dataFolder = plugin.getDataFolder(); File dataFolder = plugin.getDataFolder();
if (!dataFolder.exists()) if (!dataFolder.exists())
{
dataFolder.mkdir(); dataFolder.mkdir();
}
File saveTo = new File(plugin.getDataFolder(), "config.yml"); File saveTo = new File(plugin.getDataFolder(), "config.yml");
if (!saveTo.exists()) if (!saveTo.exists())
{
saveTo.createNewFile(); saveTo.createNewFile();
} else else
{ {
saveTo.delete(); saveTo.delete();
saveTo.createNewFile(); saveTo.createNewFile();
@ -159,7 +157,7 @@ public class ConfigLoader
pw.close(); pw.close();
} catch (IOException e) } catch (IOException e)
{ {
Bukkit.getLogger().log(Level.SEVERE, "Could not save config.yml! Please contact the author and attach the following code:"); Bukkit.getLogger().log(Level.SEVERE, "Could not save config.yml! Please contact pim16aap2 and show him the following code:");
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -167,42 +165,32 @@ public class ConfigLoader
public Integer getInt(String path) public Integer getInt(String path)
{ {
for (ConfigOption configOption : configOptionsList) for (ConfigOption configOption : configOptionsList)
{
if (configOption.getName().equals(path)) if (configOption.getName().equals(path))
return configOption.getInt(); return configOption.getInt();
}
return null; return null;
} }
public Boolean getBool(String path) public Boolean getBool(String path)
{ {
for (ConfigOption configOption : configOptionsList) for (ConfigOption configOption : configOptionsList)
{
if (configOption.getName().equals(path)) if (configOption.getName().equals(path))
return configOption.getBool(); return configOption.getBool();
}
return null; return null;
} }
public String getString(String path) public String getString(String path)
{ {
for (ConfigOption configOption : configOptionsList) for (ConfigOption configOption : configOptionsList)
{
if (configOption.getName().equals(path)) if (configOption.getName().equals(path))
return configOption.getString(); return configOption.getString();
}
return null; return null;
} }
public List<String> getStringList(String path) public List<String> getStringList(String path)
{ {
for (ConfigOption configOption : configOptionsList) for (ConfigOption configOption : configOptionsList)
{
if (configOption.getName().equals(path)) if (configOption.getName().equals(path))
{
return configOption.getStringList(); return configOption.getStringList();
}
}
return null; return null;
} }
} }

View File

@ -9,6 +9,21 @@ goldRepair: 5
ironRepair: 4 ironRepair: 4
diamondsRepair: 3 diamondsRepair: 3
# Name colors for every tier.
leatherColor:
goldColor:
chainColor:
ironColor:
diamondColor:
# Name for every tier:
leather:
gold:
chain:
iron:
diamond:
# Will curses (vanishing, binding) be transferred when creating armored elytras? # Will curses (vanishing, binding) be transferred when creating armored elytras?
allowCurses: true allowCurses: true

View File

@ -1,6 +1,6 @@
name: ArmoredElytra name: ArmoredElytra
main: nl.pim16aap2.armoredElytra.ArmoredElytra main: nl.pim16aap2.armoredElytra.ArmoredElytra
version: 2.1 version: 2.1.9
author: Pim author: Pim
commands: commands:
ArmoredElytra: ArmoredElytra: