QoL Improvements, bug fixes.

- Fixed 1.13 and 1.13.1/1.13.2 bug with armor value retrieval (nbt changed in 1.13).
- Added en_US.txt as translation file for easier translation stuff.
- Moved more strings to translation file.
- Added 1.13.1 and 1.13.2 support.
This commit is contained in:
Pim van der Loos 2018-10-26 14:53:58 +02:00
parent c3546c777c
commit e35c251827
No known key found for this signature in database
GPG Key ID: C16F020ADAE6D5A8
19 changed files with 1957 additions and 1679 deletions

View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>nl.pim16aap2</groupId>
<artifactId>ArmoredElytra</artifactId>
<version>2.4.2-SNAPSHOT</version>
<version>2.4.6-SNAPSHOT</version>
<repositories>
<repository>
@ -40,6 +40,12 @@
<version>1.13-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-1.13.1</artifactId>
<version>1.13.1-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!--bStats -->
<dependency>

View File

@ -20,27 +20,33 @@ import nl.pim16aap2.armoredElytra.nms.NBTEditor_V1_10_R1;
import nl.pim16aap2.armoredElytra.nms.NBTEditor_V1_11_R1;
import nl.pim16aap2.armoredElytra.nms.NBTEditor_V1_12_R1;
import nl.pim16aap2.armoredElytra.nms.NBTEditor_V1_13_R1;
import nl.pim16aap2.armoredElytra.nms.NBTEditor_V1_13_R2;
import nl.pim16aap2.armoredElytra.util.ArmorTier;
import nl.pim16aap2.armoredElytra.util.ConfigLoader;
import nl.pim16aap2.armoredElytra.util.Messages;
import nl.pim16aap2.armoredElytra.util.Metrics;
import nl.pim16aap2.armoredElytra.util.Update;
public class ArmoredElytra extends JavaPlugin implements Listener
{
private NBTEditor nbtEditor;
private Messages messages;
private ConfigLoader config;
private String usageDeniedMessage;
private String leatherName, ironName, goldName, chainName, diamondName;
private String elytraReceivedMessage;
private String usageDeniedMessage;
private boolean uninstallMode;
private String elytraLore;
private boolean upToDate;
private boolean uninstallMode;
private String leatherName, ironName, goldName, chainName, diamondName;
private String locale;
@Override
public void onEnable()
{
readConfigValues();
this.readConfigValues();
this.messages = new Messages(this);
this.readMessages();
// Check if the user allows checking for updates.
if (config.getBool("checkForUpdates"))
@ -65,10 +71,6 @@ public class ArmoredElytra extends JavaPlugin implements Listener
if (updateStatus > 0)
{
// TODO: Insert download link to latest version.
// TODO: Use Spiget as backup?
// TODO: Add auto update option?
// Load the loginHandler to show messages to the user when they join.
Bukkit.getPluginManager().registerEvents(new LoginHandler(plugin, "The Armored Elytra plugin is out of date!"), plugin);
plugin.myLogger(Level.INFO, "Plugin out of date! You are using version " + thisVersion + " but the latest version is version " + latestVersion + "!");
@ -88,9 +90,6 @@ public class ArmoredElytra extends JavaPlugin implements Listener
else
myLogger(Level.INFO, "Plugin update checking not enabled! You will not receive any messages about new updates for this plugin. Please consider turning this on in the config.");
// Are stats allowed?
if (config.getBool("allowStats"))
{
@ -102,7 +101,7 @@ public class ArmoredElytra extends JavaPlugin implements Listener
// Y u do dis? :(
myLogger(Level.INFO, "Stats disabled, not laoding stats :(... Please consider enabling it! I am a simple man, seeing higher user numbers helps me stay motivated!");
this.locale = config.getString("languageFile");
// Load the files for the correct version of Minecraft.
@ -117,9 +116,6 @@ public class ArmoredElytra extends JavaPlugin implements Listener
return;
}
// Load the plugin normally if not in uninstall mode.
if (!uninstallMode)
{
@ -128,10 +124,10 @@ public class ArmoredElytra extends JavaPlugin implements Listener
{
Bukkit.getPluginManager().registerEvents(new FlyDurabilityHandler(nbtEditor), this);
myLogger(Level.INFO, "Durability penalty for flying disabled!");
} else
}
else
myLogger(Level.INFO, "Durability penalty for flying enabled!");
// Log all allowed enchantments.
myLogger(Level.INFO, ("Allowed enchantments:"));
for (String s : config.getStringList("allowedEnchantments"))
@ -149,24 +145,32 @@ public class ArmoredElytra extends JavaPlugin implements Listener
// Load the settings from the config file.
this.config = new ConfigLoader(this);
// Replace color codes by the corresponding colors.
this.usageDeniedMessage = config.getString("usageDeniedMessage" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.elytraReceivedMessage = config.getString("elytraReceivedMessage" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.elytraLore = config.getString("elytraLore" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
// Check if the plugin should go into uninstall mode.
this.uninstallMode = config.getBool("uninstallMode");
}
this.leatherName = config.getString("leatherName" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.goldName = config.getString("goldName" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.chainName = config.getString("chainName" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.ironName = config.getString("ironName" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.diamondName = config.getString("diamondName" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
public Messages getMyMessages()
{
return this.messages;
}
private void readMessages()
{
// Replace color codes by the corresponding colors.
this.usageDeniedMessage = this.getMyMessages().getString("MESSAGES.UsageDenied" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.elytraReceivedMessage = this.getMyMessages().getString("MESSAGES.ElytraReceived").replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.elytraLore = this.getMyMessages().getString("MESSAGES.Lore" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.leatherName = this.getMyMessages().getString("TIER.Leather" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.goldName = this.getMyMessages().getString("TIER.Gold" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.chainName = this.getMyMessages().getString("TIER.Chain" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.ironName = this.getMyMessages().getString("TIER.Iron" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
this.diamondName = this.getMyMessages().getString("TIER.Diamond" ).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
// Change the string to null if it says "NONE".
this.usageDeniedMessage = (Objects.equals(usageDeniedMessage, new String("NONE")) ? null : usageDeniedMessage );
this.elytraReceivedMessage = (Objects.equals(elytraReceivedMessage, new String("NONE")) ? null : elytraReceivedMessage);
this.elytraLore = (Objects.equals(elytraLore, new String("NONE")) ? null : elytraLore );
// Check if the plugin should go into uninstall mode.
this.uninstallMode = config.getBool("uninstallMode");
}
// Returns true if this is the latest version of this plugin.
@ -188,15 +192,15 @@ public class ArmoredElytra extends JavaPlugin implements Listener
}
// Send a message to a player in a specific color.
public void messagePlayer(Player player, ChatColor color, String s)
public void messagePlayer(Player player, ChatColor color, String str)
{
player.sendMessage(color + s);
player.sendMessage(color + str);
}
// Send a message to a player.
public void messagePlayer(Player player, String s)
public void messagePlayer(Player player, String str)
{
messagePlayer(player, ChatColor.WHITE, s);
messagePlayer(player, ChatColor.WHITE, str);
}
// Send the usageDeniedMessage message to the player.
@ -225,6 +229,11 @@ public class ArmoredElytra extends JavaPlugin implements Listener
return string.replace("%ARMOR_TIER%", ChatColor.stripColor(getArmoredElytrName(armorTier)));
}
public String getLocale()
{
return locale == null ? "en_US" : locale;
}
// Print a string to the log.
public void myLogger(Level level, String str)
{
@ -267,6 +276,8 @@ public class ArmoredElytra extends JavaPlugin implements Listener
nbtEditor = new NBTEditor_V1_12_R1(this);
else if (version.equals("v1_13_R1"))
nbtEditor = new NBTEditor_V1_13_R1(this);
else if (version.equals("v1_13_R2"))
nbtEditor = new NBTEditor_V1_13_R2(this);
// Return true if compatible.
return nbtEditor != null;
}
@ -321,7 +332,6 @@ public class ArmoredElytra extends JavaPlugin implements Listener
}
}
public void setUpToDate(boolean upToDate)
{
this.upToDate = upToDate;

View File

@ -37,7 +37,7 @@ public class CommandHandler implements CommandExecutor
if (plugin.getUninstallMode())
{
plugin.messagePlayer(player, "Plugin in uninstall mode! New Armored Elytras are not allowed!");
plugin.messagePlayer(player, plugin.getMyMessages().getString("MESSAGES.UninstallMode"));
return true;
}
@ -67,10 +67,6 @@ public class CommandHandler implements CommandExecutor
tier = args[1];
}
// TODO: Use armorTier name from ArmorTier struct.
// Also, use AT-name for permission node verification.
// Leather armor.
if (tier.equalsIgnoreCase("leather"))
{
@ -111,7 +107,7 @@ public class CommandHandler implements CommandExecutor
allowed = true;
}
else
plugin.messagePlayer(player, "Not a supported armor tier! Try one of these: leather, gold, chain, iron, diamond.");
plugin.messagePlayer(player, plugin.getMyMessages().getString("MESSAGES.UnsupportedTier"));
if (allowed)
{
@ -120,7 +116,7 @@ public class CommandHandler implements CommandExecutor
plugin.giveArmoredElytraToPlayer(receiver, newElytra);
}
else
plugin.messagePlayer(player, "You do not have the required permission node to give " + plugin.getArmoredElytrName(armorTier));
plugin.messagePlayer(player, plugin.fillInArmorTierInStringNoColor(plugin.getMyMessages().getString("MESSAGES.UnsupportedTier"), armorTier));
return true;
}
}
@ -142,8 +138,6 @@ public class CommandHandler implements CommandExecutor
player = Bukkit.getPlayer(args[0]);
ArmorTier armorTier = ArmorTier.NONE;
// TODO: Again, use the ArmorTier struct for tier retrieval.
if (tier.equalsIgnoreCase("leather"))
armorTier = ArmorTier.LEATHER;
else if (tier.equalsIgnoreCase("gold"))

View File

@ -6,7 +6,6 @@ import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
@ -106,7 +105,9 @@ public class EventHandlers implements Listener
int protVal0 = getProtectionEnchantmentsVal(enchantments0);
int protVal1 = getProtectionEnchantmentsVal(enchantments1);
// If they have different
// If they have different protection enchantments, keep enchantment1's enchantments
// And remove the protection enchantment from enchantments0. Yes, this system only works
// If there is 1 protection enchantment on
if (protVal0 != 0 && protVal1 != 0 && protVal0 != protVal1)
{
switch(protVal0)
@ -292,7 +293,6 @@ public class EventHandlers implements Listener
public void onAnvilInventoryOpen(PrepareAnvilEvent event)
{
Player player = (Player) event.getView().getPlayer();
ItemStack itemA = event.getInventory().getItem(0);
ItemStack itemB = event.getInventory().getItem(1);
ItemStack result = null;
@ -435,7 +435,6 @@ public class EventHandlers implements Listener
public void onRightClick(PlayerInteractEvent event)
{
Player player = event.getPlayer();
ItemStack item = player.getItemInHand();
if (item != null)
@ -475,8 +474,9 @@ public class EventHandlers implements Listener
ArmorTier armorTier = nbtEditor.getArmorTier(chestplate);
if ((chestplate.getDurability() >= chestplate.getType().getMaxDurability()))
{
plugin.messagePlayer(player, ChatColor.RED + "You cannot equip this elytra! Please repair it in an anvil first.");
plugin.messagePlayer(player, plugin.getMyMessages().getString("MESSAGES.RepairNeeded"));
Util.unenquipChestPlayer(player);
player.updateInventory();
}
else if ((armorTier == ArmorTier.LEATHER && !player.hasPermission("armoredelytra.wear.leather")) ||
(armorTier == ArmorTier.GOLD && !player.hasPermission("armoredelytra.wear.gold" )) ||
@ -486,11 +486,11 @@ public class EventHandlers implements Listener
{
plugin.usageDeniedMessage(player, armorTier);
Util.unenquipChestPlayer(player);
}
player.updateInventory();
}
}
}
}
// Because the armored elytra doesn't actually give any armor, the damage received by players wearing an armored elytra is calculated here.
@EventHandler(ignoreCancelled = true)

View File

@ -1,6 +1,5 @@
package nl.pim16aap2.armoredElytra.handlers;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@ -36,7 +35,6 @@ public class Uninstaller implements Listener
if (is.getType() == Material.ELYTRA)
if (nbtEditor.getArmorTier(is) != ArmorTier.NONE)
{
Bukkit.broadcastMessage("An armored elytra even! Removing now!");
inv.remove(is);
++count;
}

View File

@ -95,7 +95,8 @@ public class NBTEditor_V1_10_R1 implements NBTEditor
pos--;
String stringAtPos = nbtTags.substring(pos, pos + 1);
armorValue = Integer.parseInt(stringAtPos);
} else
}
else
// Otherwise, the item has no armor, so return 0;
return ArmorTier.NONE;

View File

@ -95,7 +95,8 @@ public class NBTEditor_V1_11_R1 implements NBTEditor
pos--;
String stringAtPos = nbtTags.substring(pos, pos + 1);
armorValue = Integer.parseInt(stringAtPos);
} else
}
else
// Otherwise, the item has no armor, so return 0;
return ArmorTier.NONE;

View File

@ -95,7 +95,8 @@ public class NBTEditor_V1_12_R1 implements NBTEditor
pos--;
String stringAtPos = nbtTags.substring(pos, pos + 1);
armorValue = Integer.parseInt(stringAtPos);
} else
}
else
// Otherwise, the item has no armor, so return 0;
return ArmorTier.NONE;

View File

@ -87,18 +87,23 @@ public class NBTEditor_V1_13_R1 implements NBTEditor
// Check if the item has the generic.armor attribute.
// Format = <level>,Slot:"chest",AttributeName:"generic.armor so get pos of char before
// The start of the string, as that's the value of the generic.armor attribute.
// The level is now formatted as x.xd, e.g. 6.0d.
int pos = nbtTags.indexOf(",Slot:\"chest\",AttributeName:\"generic.armor\"");
int armorValue = 0;
if (pos > 0)
{
// If so, get the value of the generic.armor attribute.
pos--;
String stringAtPos = nbtTags.substring(pos, pos+1);
armorValue = Integer.parseInt(stringAtPos);
} else
// Otherwise, the item has no armor, so return 0;
if (pos <= 0)
return ArmorTier.NONE;
try
{
String stringAtPos = nbtTags.substring(pos - 4, pos - 1);
armorValue = (int) Double.parseDouble(stringAtPos);
}
catch (Exception e)
{
armorValue = 0;
}
switch (armorValue)
{
case 3:

View File

@ -0,0 +1,121 @@
package nl.pim16aap2.armoredElytra.nms;
import java.util.Arrays;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import net.minecraft.server.v1_13_R2.NBTTagByte;
import net.minecraft.server.v1_13_R2.NBTTagCompound;
import net.minecraft.server.v1_13_R2.NBTTagInt;
import net.minecraft.server.v1_13_R2.NBTTagList;
import net.minecraft.server.v1_13_R2.NBTTagString;
import nl.pim16aap2.armoredElytra.ArmoredElytra;
import nl.pim16aap2.armoredElytra.util.ArmorTier;
public class NBTEditor_V1_13_R2 implements NBTEditor
{
private ArmoredElytra plugin;
// Get the names and lores for every tier of armor.
public NBTEditor_V1_13_R2(ArmoredElytra plugin)
{
this.plugin = plugin;
}
// Add armor to the supplied item, based on the armorTier.
@Override
public ItemStack addArmorNBTTags(ItemStack item, ArmorTier armorTier, boolean unbreakable)
{
ItemMeta itemmeta = item.getItemMeta();
int armorProtection = ArmorTier.getArmor(armorTier);
int armorToughness = ArmorTier.getToughness(armorTier);
itemmeta.setDisplayName(plugin.getArmoredElytrName(armorTier));
if (plugin.getElytraLore() != null)
itemmeta.setLore(Arrays.asList(plugin.fillInArmorTierInStringNoColor(plugin.getElytraLore(), armorTier)));
item.setItemMeta(itemmeta);
net.minecraft.server.v1_13_R2.ItemStack nmsStack = CraftItemStack.asNMSCopy(item);
NBTTagCompound compound = (nmsStack.hasTag()) ? nmsStack.getTag() : new NBTTagCompound();
NBTTagList modifiers = new NBTTagList();
NBTTagCompound armor = new NBTTagCompound();
armor.set("AttributeName", new NBTTagString("generic.armor"));
armor.set("Name", new NBTTagString("generic.armor"));
armor.set("Amount", new NBTTagInt(armorProtection));
armor.set("Operation", new NBTTagInt(0));
armor.set("UUIDLeast", new NBTTagInt(894654));
armor.set("UUIDMost", new NBTTagInt(2872));
armor.set("Slot", new NBTTagString("chest"));
modifiers.add(armor);
NBTTagCompound armorTough = new NBTTagCompound();
armorTough.set("AttributeName", new NBTTagString("generic.armorToughness"));
armorTough.set("Name", new NBTTagString("generic.armorToughness"));
armorTough.set("Amount", new NBTTagInt(armorToughness));
armorTough.set("Operation", new NBTTagInt(0));
armorTough.set("UUIDLeast", new NBTTagInt(894654));
armorTough.set("UUIDMost", new NBTTagInt(2872));
armorTough.set("Slot", new NBTTagString("chest"));
modifiers.add(armorTough);
if (unbreakable)
compound.set("Unbreakable", new NBTTagByte((byte) 1));
compound.set("AttributeModifiers", modifiers);
item = CraftItemStack.asBukkitCopy(nmsStack);
return item;
}
// Get the armor tier of the supplied item.
@Override
public ArmorTier getArmorTier(ItemStack item)
{
if (item == null)
return ArmorTier.NONE;
if (item.getType() != Material.ELYTRA)
return ArmorTier.NONE;
// Get the NBT tags from the item.
NBTTagCompound compound = CraftItemStack.asNMSCopy(item).getTag();
if (compound == null)
return ArmorTier.NONE;
String nbtTags = compound.toString();
// Check if the item has the generic.armor attribute.
// Format = <level>,Slot:"chest",AttributeName:"generic.armor so get pos of char before
// The start of the string, as that's the value of the generic.armor attribute.
// The level is now formatted as x.xd, e.g. 6.0d.
int pos = nbtTags.indexOf(",Slot:\"chest\",AttributeName:\"generic.armor\"");
int armorValue = 0;
if (pos <= 0)
return ArmorTier.NONE;
try
{
String stringAtPos = nbtTags.substring(pos - 4, pos - 1);
armorValue = (int) Double.parseDouble(stringAtPos);
}
catch (Exception e)
{
armorValue = 0;
}
switch (armorValue)
{
case 3:
return ArmorTier.LEATHER;
case 5:
return ArmorTier.GOLD;
case 6:
return ArmorTier.IRON;
case 8:
return ArmorTier.DIAMOND;
default:
return ArmorTier.NONE;
}
}
}

View File

@ -12,68 +12,22 @@ import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import nl.pim16aap2.armoredElytra.ArmoredElytra;
import nl.pim16aap2.bigDoors.util.ConfigOption;
public class ConfigLoader
{
private boolean allowStats;
private boolean unbreakable;
private boolean noFlightDurability;
private int LEATHER_TO_FULL;
private boolean enableDebug;
private String languageFile;
private int GOLD_TO_FULL;
private int IRON_TO_FULL;
private int DIAMONDS_TO_FULL;
private String leatherName;
private String goldName;
private String chainName;
private String ironName;
private String diamondName;
private String elytraLore;
private List<String> allowedEnchantments;
private String usageDeniedMessage;
private String elytraReceivedMessage;
private boolean checkForUpdates;
private boolean allowStats;
private boolean enableDebug;
private boolean uninstallMode;
// All the comments for the various config options.
private String[] unbreakableComment =
{"Setting this to true will cause armored elytras to be unbreakable.",
"Changing this to false will NOT make unbreakable elytras breakable again!"};
private String[] flyDurabilityComment =
{"Setting this to true will cause armored elytras to not lose any durability while flying.",
"This is not a permanent option and will affect ALL elytras."};
private String[] repairComment =
{"Amount of items it takes to fully repair an armored elytra",
"Repair cost for every tier of armored elytra in number of items to repair 100%."};
private String[] tierNameComment =
{"Name for every armored elytra tier."};
private String[] enchantmentsComment =
{"List of enchantments that are allowed to be put on an armored elytra.",
"If you do not want to allow any enchantments at all, remove them all and add \"NONE\"",
"You can find supported enchantments here:",
"https://hub.spigotmc.org/javadocs/spigot/org/bukkit/enchantments/Enchantment.html",
"Note that only 1 protection enchantment (PROTECTION_FIRE, PROTECTION_ENVIRONMENTAL etc) can be active on an elytra."};
private String[] usageDeniedComment =
{"Message players receive when they lack the required permissions to wear a certain armor tier. \"NONE\" = no message. ",
"%ARMOR_TIER% is replaced by the name of the armor tier."};
private String[] elytraReceivedComment =
{"Message players receive when they are given an armored elytra using commands. \"NONE\" = no message. ",
"%ARMOR_TIER% is replaced by the name of the armor tier."};
private String[] elytraLoreComment =
{"The lore of armored elytras. \"NONE\" = no lore. %ARMOR_TIER% is replaced by the name of the armor tier."};
private String[] updateComment =
{"Allow this plugin to check for updates on startup. It will not download new versions!"};
private String[] bStatsComment =
{"Allow this plugin to send (anonymised) stats using bStats. Please consider keeping it enabled.",
"It has a negligible impact on performance and more users on stats keeps me more motivated to support this plugin!"};
private String[] debugComment =
{"Print debug messages to console. You will most likely never need this."};
private String[] uninstallComment =
{"Setting this to true will disable this plugin and remove any armored elytras it can find.",
"It will check player's inventories and their end chest upon login and any regular chest when it is opened.",
"This means it will take a while for all armored elytras to be removed from your server, but it doesn't take up ",
"a lot of resources, so you can just leave it installed and ignore it.",
"Please do not forget to MAKE A BACKUP before enabling this option!"};
private boolean checkForUpdates;
private int LEATHER_TO_FULL;
private int DIAMONDS_TO_FULL;
private boolean noFlightDurability;
private List<String> allowedEnchantments;
private ArrayList<ConfigOption> configOptionsList;
private ArmoredElytra plugin;
@ -88,6 +42,58 @@ public class ConfigLoader
// Read the current config, the make a new one based on the old one or default values, whichever is applicable.
public void makeConfig()
{
// All the comments for the various config options.
String[] unbreakableComment =
{
"Setting this to true will cause armored elytras to be unbreakable.",
"Changing this to false will NOT make unbreakable elytras breakable again!"
};
String[] flyDurabilityComment =
{
"Setting this to true will cause armored elytras to not lose any durability while flying.",
"This is not a permanent option and will affect ALL elytras."
};
String[] repairComment =
{
"Amount of items it takes to fully repair an armored elytra",
"Repair cost for every tier of armored elytra in number of items to repair 100%."
};
String[] enchantmentsComment =
{
"List of enchantments that are allowed to be put on an armored elytra.",
"If you do not want to allow any enchantments at all, remove them all and add \"NONE\"",
"You can find supported enchantments here:",
"https://hub.spigotmc.org/javadocs/spigot/org/bukkit/enchantments/Enchantment.html",
"Note that only 1 protection enchantment (PROTECTION_FIRE, PROTECTION_ENVIRONMENTAL etc) can be active on an elytra."
};
String[] updateComment =
{
"Allow this plugin to check for updates on startup. It will not download new versions!"
};
String[] bStatsComment =
{
"Allow this plugin to send (anonymised) stats using bStats. Please consider keeping it enabled.",
"It has a negligible impact on performance and more users on stats keeps me more motivated to support this plugin!"
};
String[] debugComment =
{
"Print debug messages to console. You will most likely never need this."
};
String[] uninstallComment =
{
"Setting this to true will disable this plugin and remove any armored elytras it can find.",
"It will check player's inventories and their end chest upon login and any regular chest when it is opened.",
"This means it will take a while for all armored elytras to be removed from your server, but it doesn't take up ",
"a lot of resources, so you can just leave it installed and ignore it.",
"Please do not forget to MAKE A BACKUP before enabling this option!"
};
String[] languageFileComment =
{
"Specify a language file to be used. Note that en_US.txt will get regenerated!"
};
FileConfiguration config = plugin.getConfig();
// Read all the options from the config, then put them in a configOption with their name, value and comment.
@ -106,25 +112,6 @@ public class ConfigLoader
DIAMONDS_TO_FULL = config.getInt ("diamondsRepair", 3);
configOptionsList.add(new ConfigOption ("diamondsRepair", DIAMONDS_TO_FULL));
leatherName = config.getString ("leatherName", "&2Leather Armored Elytra" );
configOptionsList.add(new ConfigOption ("leatherName", leatherName, tierNameComment));
goldName = config.getString ("goldName" , "&EGolden Armored Elytra" );
configOptionsList.add(new ConfigOption ("goldName" , goldName ));
chainName = config.getString ("chainName" , "&8Chain Armored Elytra" );
configOptionsList.add(new ConfigOption ("chainName" , chainName ));
ironName = config.getString ("ironName" , "&7Iron Armored Elytra" );
configOptionsList.add(new ConfigOption ("ironName" , ironName ));
diamondName = config.getString ("diamondName", "&BDiamond Armored Elytra" );
configOptionsList.add(new ConfigOption ("diamondName", diamondName ));
elytraLore = config.getString ("elytraLore");
configOptionsList.add(new ConfigOption ("elytraLore", elytraLore, elytraLoreComment));
usageDeniedMessage = config.getString ("usageDeniedMessage" );
configOptionsList.add(new ConfigOption ("usageDeniedMessage" , usageDeniedMessage , usageDeniedComment ));
elytraReceivedMessage = config.getString ("elytraReceivedMessage" );
configOptionsList.add(new ConfigOption ("elytraReceivedMessage", elytraReceivedMessage, elytraReceivedComment));
allowedEnchantments = config.getStringList("allowedEnchantments");
configOptionsList.add(new ConfigOption ("allowedEnchantments", allowedEnchantments, enchantmentsComment));
@ -136,6 +123,8 @@ public class ConfigLoader
configOptionsList.add(new ConfigOption ("enableDebug" , enableDebug, debugComment));
uninstallMode = config.getBoolean ("uninstallMode" , false);
configOptionsList.add(new ConfigOption ("uninstallMode" , uninstallMode, uninstallComment));
languageFile = config.getString ("languageFile" , "en_US");
configOptionsList.add(new ConfigOption ("languageFile" , languageFile, languageFileComment));
writeConfig();
}

View File

@ -100,7 +100,6 @@ public class ConfigOption
boolVal != null ? boolVal :
stringVal != null ? "\'" + stringVal + "\'" :
listVal != null ? "\n" + stringListToString() : null);
return string;
}
}

View File

@ -0,0 +1,79 @@
package nl.pim16aap2.armoredElytra.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import nl.pim16aap2.armoredElytra.ArmoredElytra;
public class Messages
{
private Map<String, String> messageMap = new HashMap<String, String>();
private ArmoredElytra plugin;
private String locale;
private File textFile;
public Messages(ArmoredElytra plugin)
{
this.plugin = plugin;
this.locale = plugin.getLocale();
textFile = new File(plugin.getDataFolder(), locale + ".txt");
readFile();
}
// Read locale file.
private void readFile()
{
// Load the default en_US from the resources.
plugin.saveResource("en_US.txt", true);
try (BufferedReader br = new BufferedReader(new FileReader(this.textFile)))
{
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null)
{
String key, value;
String[] parts = sCurrentLine.split("=", 2);
key = parts[0];
value = parts[1].replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
String[] newLineSplitter = value.split("\\\\n"); // Wut? Can I haz more backslash?
String values = newLineSplitter[0];
for (int idx = 1; idx < newLineSplitter.length; ++idx)
values += "\n" + newLineSplitter[idx];
this.messageMap.put(key, values);
}
br.close();
}
catch (FileNotFoundException e)
{
plugin.myLogger(Level.SEVERE, "Locale file " + this.locale + ".txt does not exist!");
}
catch (IOException e)
{
plugin.myLogger(Level.SEVERE, "Could not read locale file! (" + this.locale + ".txt)");
e.printStackTrace();
}
}
// Get a string from a key. Returns "null" if null.
public String getString(String key)
{
String value = null;
value = this.messageMap.get(key);
if (value == null)
{
value = "BigDoors: Translation not found! Contact server admin!";
plugin.myLogger(Level.WARNING, "Failed to get translation for key " + key);
}
return value;
}
}

View File

@ -31,17 +31,22 @@ import java.util.zip.GZIPOutputStream;
*
* Check out https://bStats.org/ to learn more about bStats!
*/
public class Metrics {
public class Metrics
{
static {
static
{
// You can use the property to disable the check in your test environment
if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) {
// Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D
final String defaultPackage = new String(
new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'});
if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false"))
{
// Maven's Relocate is clever and changes strings, too. So we have to use this
// little "trick" ... :D
final String defaultPackage = new String(new byte[] { 'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't' });
final String examplePackage = new String(new byte[] { 'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e' });
// We want to make sure nobody just copy & pastes the example and use the wrong package names
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) {
// We want to make sure nobody just copy & pastes the example and use the wrong
// package names
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage))
{
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
}
}
@ -70,8 +75,10 @@ public class Metrics {
*
* @param plugin The plugin which stats should be submitted.
*/
public Metrics(JavaPlugin plugin) {
if (plugin == null) {
public Metrics(JavaPlugin plugin)
{
if (plugin == null)
{
throw new IllegalArgumentException("Plugin cannot be null!");
}
this.plugin = plugin;
@ -82,7 +89,8 @@ public class Metrics {
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
// Check if the config file exists
if (!config.isSet("serverUuid")) {
if (!config.isSet("serverUuid"))
{
// Add default values
config.addDefault("enabled", true);
@ -92,15 +100,14 @@ public class Metrics {
config.addDefault("logFailedRequests", false);
// Inform the server owners about bStats
config.options().header(
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
"To honor their work, you should not disable it.\n" +
"This has nearly no effect on the server performance!\n" +
"Check out https://bStats.org/ to learn more :)"
).copyDefaults(true);
try {
config.options().header("bStats collects some data for plugin authors like how many servers are using their plugins.\n" + "To honor their work, you should not disable it.\n" + "This has nearly no effect on the server performance!\n" + "Check out https://bStats.org/ to learn more :)").copyDefaults(true);
try
{
config.save(configFile);
} catch (IOException ignored) { }
}
catch (IOException ignored)
{
}
}
// Load the data
@ -108,16 +115,22 @@ public class Metrics {
logFailedRequests = config.getBoolean("logFailedRequests", false);
boolean found = false;
// Search for all other bStats Metrics classes to see if we are the first one
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
for (Class<?> service : Bukkit.getServicesManager().getKnownServices())
{
try
{
service.getField("B_STATS_VERSION"); // Our identifier :)
found = true; // We aren't the first
break;
} catch (NoSuchFieldException ignored) { }
}
catch (NoSuchFieldException ignored)
{
}
}
// Register our service
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal);
if (!found) {
if (!found)
{
// We are the first!
startSubmitting();
}
@ -126,38 +139,48 @@ public class Metrics {
/**
* Starts the Scheduler which submits our data every 30 minutes.
*/
private void startSubmitting() {
private void startSubmitting()
{
final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags
timer.scheduleAtFixedRate(new TimerTask() {
timer.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run() {
if (!plugin.isEnabled()) { // Plugin was disabled
public void run()
{
if (!plugin.isEnabled())
{ // Plugin was disabled
timer.cancel();
return;
}
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
Bukkit.getScheduler().runTask(plugin, new Runnable() {
// Nevertheless we want our code to run in the Bukkit main thread, so we have to
// use the Bukkit scheduler
// Don't be afraid! The connection to the bStats server is still async, only the
// stats collection is sync ;)
Bukkit.getScheduler().runTask(plugin, new Runnable()
{
@Override
public void run() {
public void run()
{
submitData();
}
});
}
}, 1000 * 60 * 5, 1000 * 60 * 30);
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
// Submit the data every 30 minutes, first time after 5 minutes to give other
// plugins enough time to start
// WARNING: Changing the frequency has no effect but your plugin WILL be
// blocked/deleted!
// WARNING: Just don't do it!
}
/**
* Gets the plugin specific data.
* This method is called using Reflection.
* Gets the plugin specific data. This method is called using Reflection.
*
* @return The plugin specific data.
*/
@SuppressWarnings("unchecked")
public JSONObject getPluginData() {
public JSONObject getPluginData()
{
JSONObject data = new JSONObject();
String pluginName = plugin.getDescription().getName();
@ -166,10 +189,12 @@ public class Metrics {
data.put("pluginName", pluginName); // Append the name of the plugin
data.put("pluginVersion", pluginVersion); // Append the version of the plugin
JSONArray customCharts = new JSONArray();
for (CustomChart customChart : charts) {
for (CustomChart customChart : charts)
{
// Add the data of the custom charts
JSONObject chart = customChart.getRequestJsonObject();
if (chart == null) { // If the chart is null, we skip it
if (chart == null)
{ // If the chart is null, we skip it
continue;
}
customCharts.add(chart);
@ -185,17 +210,20 @@ public class Metrics {
* @return The server specific data.
*/
@SuppressWarnings("unchecked")
private JSONObject getServerData() {
private JSONObject getServerData()
{
// Minecraft specific data
int playerAmount;
try {
try
{
// Around MC 1.8 the return type was changed to a collection from an array,
// This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
// This fixes java.lang.NoSuchMethodError:
// org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class)
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
} catch (Exception e) {
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) ? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size() : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
}
catch (Exception e)
{
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
}
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
@ -230,35 +258,52 @@ public class Metrics {
* Collects the data and sends it afterwards.
*/
@SuppressWarnings("unchecked")
private void submitData() {
private void submitData()
{
final JSONObject data = getServerData();
JSONArray pluginData = new JSONArray();
// Search for all other bStats Metrics classes to get their plugin data
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
for (Class<?> service : Bukkit.getServicesManager().getKnownServices())
{
try
{
service.getField("B_STATS_VERSION"); // Our identifier :)
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
try {
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service))
{
try
{
pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider()));
} catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { }
}
} catch (NoSuchFieldException ignored) { }
catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored)
{
}
}
}
catch (NoSuchFieldException ignored)
{
}
}
data.put("plugins", pluginData);
// Create a new thread for the connection to the bStats server
new Thread(new Runnable() {
new Thread(new Runnable()
{
@Override
public void run() {
try {
public void run()
{
try
{
// Send the data
sendData(data);
} catch (Exception e) {
}
catch (Exception e)
{
// Something went wrong! :(
if (logFailedRequests) {
if (logFailedRequests)
{
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
}
}
@ -272,11 +317,14 @@ public class Metrics {
* @param data The data to send.
* @throws Exception If the request failed.
*/
private static void sendData(JSONObject data) throws Exception {
if (data == null) {
private static void sendData(JSONObject data) throws Exception
{
if (data == null)
{
throw new IllegalArgumentException("Data cannot be null!");
}
if (Bukkit.isPrimaryThread()) {
if (Bukkit.isPrimaryThread())
{
throw new IllegalAccessException("This method must not be called from the main thread!");
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
@ -310,8 +358,10 @@ public class Metrics {
* @return The gzipped String.
* @throws IOException If the compression failed.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
private static byte[] compress(final String str) throws IOException
{
if (str == null)
{
return null;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
@ -324,7 +374,8 @@ public class Metrics {
/**
* Represents a custom chart.
*/
public static abstract class CustomChart {
public static abstract class CustomChart
{
// The id of the chart
final String chartId;
@ -334,32 +385,41 @@ public class Metrics {
*
* @param chartId The id of the chart.
*/
CustomChart(String chartId) {
if (chartId == null || chartId.isEmpty()) {
CustomChart(String chartId)
{
if (chartId == null || chartId.isEmpty())
{
throw new IllegalArgumentException("ChartId cannot be null or empty!");
}
this.chartId = chartId;
}
@SuppressWarnings("unchecked")
private JSONObject getRequestJsonObject() {
private JSONObject getRequestJsonObject()
{
JSONObject chart = new JSONObject();
chart.put("chartId", chartId);
try {
try
{
JSONObject data = getChartData();
if (data == null) {
if (data == null)
{
// If the data is null we don't send the chart.
return null;
}
chart.put("data", data);
} catch (Throwable t) {
if (logFailedRequests) {
}
catch (Throwable t)
{
if (logFailedRequests)
{
Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
}
return null;
}
return chart;
}
protected abstract JSONObject getChartData() throws Exception;
}
}

View File

@ -13,7 +13,6 @@ import org.json.simple.JSONValue;
import nl.pim16aap2.armoredElytra.ArmoredElytra;
public class Update
{
@ -36,7 +35,8 @@ public class Update
/**
* Check for updates anonymously (keyless)
*
* @param projectID The BukkitDev Project ID, found in the "Facts" panel on the right-side of your project page.
* @param projectID The BukkitDev Project ID, found in the "Facts" panel on the
* right-side of your project page.
*/
public Update(int projectID, ArmoredElytra plugin)
{
@ -46,8 +46,10 @@ public class Update
/**
* Check for updates using your Curse account (with key)
*
* @param projectID The BukkitDev Project ID, found in the "Facts" panel on the right-side of your project page.
* @param apiKey Your ServerMods API key, found at https://dev.bukkit.org/home/servermods-apikey/
* @param projectID The BukkitDev Project ID, found in the "Facts" panel on the
* right-side of your project page.
* @param apiKey Your ServerMods API key, found at
* https://dev.bukkit.org/home/servermods-apikey/
*/
public Update(int projectID, String apiKey, ArmoredElytra plugin)
{
@ -58,8 +60,6 @@ public class Update
query();
}
public int versionCompare(String str1, String str2)
{
String[] vals1 = str1.split("\\.");
@ -87,7 +87,6 @@ public class Update
return versionName.replaceAll("Armored Elytra ", "");
}
/**
* Query the API to find the latest approved file's details.
*/
@ -140,8 +139,11 @@ public class Update
catch (IOException e)
{
// There was an error reading the query.
// Does not print stacktrace, so people won't see any errors from this plugin when Bukkit Dev's servers are down,
// So people won't think the plugin is broken, while the actualy problem is much, much smaller. latestVersion will be null, though, which will prompt a warning in the log instead.
// Does not print stacktrace, so people won't see any errors from this plugin
// when Bukkit Dev's servers are down,
// So people won't think the plugin is broken, while the actualy problem is
// much, much smaller. latestVersion will be null, though, which will prompt a
// warning in the log instead.
// e.printStackTrace();
return;

View File

@ -0,0 +1,12 @@
TIER.Leather=&2Leather Armored Elytra
TIER.Gold=&EGolden Armored Elytra
TIER.Chain=&8Chain Armored Elytra
TIER.Iron=&7Iron Armored Elytra
TIER.Diamond=&BDiamond Armored Elytra
MESSAGES.Lore=Elytra with %ARMOR_TIER% level protection
MESSAGES.UsageDenied=You do not have the required permissions to wear %ARMOR_TIER%!
MESSAGES.ElytraReceived=&2A(n) %ARMOR_TIER% has been bestowed upon you!
MESSAGES.UninstallMode=&cPlugin in uninstall mode! New Armored Elytras are not allowed!
MESSAGES.UnsupportedTier=&cNot a supported armor tier! Try one of these: leather, gold, chain, iron, diamond.
MESSAGES.NoGivePermission=&cYou do not have the required permission node to give %ARMOR_TIER%s.
MESSAGES.RepairNeeded=&cYou cannot equip this elytra! Please repair it in an anvil first.

View File

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