Clean up code, fix bugs, use Maven
- Switched to Maven for project compilation. - Added config options to globally bypass permissions for crafting and/or wearing of all tiers. - Now using Consumer for stuff that previously used the ugly is1_9 boolean. - Switched to using ArmorEquipEvent for checking if players are allowed to wear something. It's much cleaner and includes some previously omitted equip events (such as from a dispenser). - Code cleanup. - Fixed issue where unbreakable armored elytras would still "break". - Added MENDING enchantment to the default set of enchantments again. - Using Maven shade for bStats and removed the old Metrics class.
This commit is contained in:
parent
080b6c6dab
commit
e906ddfdb3
160
pom.xml
160
pom.xml
@ -1,21 +1,27 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>nl.pim16aap2</groupId>
|
||||
<artifactId>ArmoredElytra</artifactId>
|
||||
<version>2.4.8-SNAPSHOT</version>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>nl.pim16aap2</groupId>
|
||||
<artifactId>ArmoredElytra</artifactId>
|
||||
<version>2.4.10</version>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>bstats-repo</id>
|
||||
<url>http://repo.bstats.org/content/repositories/releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>CodeMC</id>
|
||||
<url>https://repo.codemc.org/repository/maven-public</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
@ -23,24 +29,108 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!--bStats -->
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bukkit</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.tr7zw</groupId>
|
||||
<artifactId>Item-NBT-API</artifactId>
|
||||
<version>master-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<!--bStats -->
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bukkit</artifactId>
|
||||
<version>1.5</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>com.github.Arnuh</groupId>
|
||||
<artifactId>ArmorEquipEvent</artifactId>
|
||||
<version>39fadc1393</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.name}</finalName>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src</directory>
|
||||
<excludes>
|
||||
<exclude>**/*.java</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>plugin.yml</include>
|
||||
<include>config.yml</include>
|
||||
<include>en_US.txt</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<configuration>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>nl.pim16aap2.armoredElytra</shadedPattern>
|
||||
</relocation>
|
||||
<!--<relocation>
|
||||
<pattern>com.codingforcookies</pattern>
|
||||
<shadedPattern>nl.pim16aap2.armoredElytra</shadedPattern>
|
||||
</relocation>-->
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>deploy-artifact</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<ant antfile="${basedir}/mover.xml">
|
||||
<target name="copyAll" />
|
||||
</ant>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
@ -3,6 +3,7 @@ package nl.pim16aap2.armoredElytra;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -19,9 +20,13 @@ import nl.pim16aap2.armoredElytra.nbtEditor.NBTEditor;
|
||||
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;
|
||||
|
||||
// TODO: Use this for NBT stuff: https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/
|
||||
// TODO: Figure out if the config really does read the list of enchantments accurately. A bug report with a customized config seemed to load the default settings...
|
||||
// TODO: Verify enchantments on startup. Remove them from the list if they're invalid.
|
||||
// TODO: Don't delete the config file. Look at BigDoors.
|
||||
|
||||
public class ArmoredElytra extends JavaPlugin implements Listener
|
||||
{
|
||||
private NBTEditor nbtEditor;
|
||||
@ -151,6 +156,16 @@ public class ArmoredElytra extends JavaPlugin implements Listener
|
||||
elytraLore = (Objects.equals(elytraLore, new String("NONE")) ? null : elytraLore );
|
||||
}
|
||||
|
||||
public boolean playerHasCraftPerm(Player player, ArmorTier armorTier)
|
||||
{
|
||||
return getConfigLoader().bypassCraftPerm() || player.hasPermission("armoredelytra.craft." + ArmorTier.getName(armorTier));
|
||||
}
|
||||
|
||||
public boolean playerHasWearPerm(Player player, ArmorTier armorTier)
|
||||
{
|
||||
return getConfigLoader().bypassWearPerm() || player.hasPermission("armoredelytra.wear." + ArmorTier.getName(armorTier));
|
||||
}
|
||||
|
||||
// Returns true if this is the latest version of this plugin.
|
||||
public boolean isUpToDate()
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ import nl.pim16aap2.armoredElytra.util.ArmorTier;
|
||||
public class CommandHandler implements CommandExecutor
|
||||
{
|
||||
private final ArmoredElytra plugin;
|
||||
private final NBTEditor nbtEditor;
|
||||
private final NBTEditor nbtEditor;
|
||||
|
||||
public CommandHandler(ArmoredElytra plugin, NBTEditor nbtEditor)
|
||||
{
|
||||
|
@ -1,10 +1,13 @@
|
||||
package nl.pim16aap2.armoredElytra.handlers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -13,14 +16,16 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.inventory.PrepareAnvilEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.AnvilInventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.codingforcookies.armorequip.ArmorEquipEvent;
|
||||
import com.codingforcookies.armorequip.ArmorListener;
|
||||
import com.codingforcookies.armorequip.ArmorType;
|
||||
import com.codingforcookies.armorequip.DispenserArmorListener;
|
||||
|
||||
import nl.pim16aap2.armoredElytra.ArmoredElytra;
|
||||
import nl.pim16aap2.armoredElytra.nbtEditor.NBTEditor;
|
||||
@ -32,48 +37,74 @@ import nl.pim16aap2.armoredElytra.util.XMaterial;
|
||||
|
||||
public class EventHandlers implements Listener
|
||||
{
|
||||
private final NBTEditor nbtEditor;
|
||||
private final ArmoredElytra plugin;
|
||||
private final boolean is1_9;
|
||||
private final NBTEditor nbtEditor;
|
||||
private final ArmoredElytra plugin;
|
||||
|
||||
private final Consumer<AnvilInventory> cleanAnvilInventory;
|
||||
private final Consumer<Player> moveChestplateToInventory;
|
||||
|
||||
public EventHandlers(ArmoredElytra plugin, NBTEditor nbtEditor, boolean is1_9)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
this.plugin = plugin;
|
||||
this.nbtEditor = nbtEditor;
|
||||
this.is1_9 = is1_9;
|
||||
}
|
||||
|
||||
// Remove item from player's chestplate slot and puts it in their normal inventory.
|
||||
private void unenquipChestPlayer(Player p)
|
||||
{
|
||||
if (is1_9)
|
||||
p.getInventory().getChestplate().setType(XMaterial.AIR.parseMaterial());
|
||||
else
|
||||
{
|
||||
p.getInventory().addItem(p.getInventory().getChestplate());
|
||||
p.getInventory().getChestplate().setAmount(0);
|
||||
p.updateInventory();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the anvil's inventory (destroy all the items in all 3 slots (second slot is not emptied, when repairing you can safely give multiple items)).
|
||||
private void cleanAnvil(AnvilInventory anvilInventory)
|
||||
{
|
||||
initializeArmorEquipEvent();
|
||||
if (is1_9)
|
||||
{
|
||||
ItemStack air = new ItemStack(XMaterial.AIR.parseMaterial(), 1);
|
||||
anvilInventory.setItem(0, air);
|
||||
anvilInventory.setItem(1, air);
|
||||
anvilInventory.setItem(2, air);
|
||||
cleanAnvilInventory = this::cleanAnvilOld;
|
||||
moveChestplateToInventory = this::moveChestplateToInventoryOld;
|
||||
}
|
||||
else
|
||||
{
|
||||
anvilInventory.getItem(0).setAmount(0);
|
||||
anvilInventory.getItem(1).setAmount(anvilInventory.getItem(1).getAmount() - 1);
|
||||
anvilInventory.getItem(2).setAmount(0);
|
||||
cleanAnvilInventory = this::cleanAnvilNew;
|
||||
moveChestplateToInventory = this::moveChestplateToInventoryNew;
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeArmorEquipEvent()
|
||||
{
|
||||
Bukkit.getPluginManager().registerEvents(new ArmorListener(new ArrayList<String>()), plugin);
|
||||
try
|
||||
{
|
||||
// Older versions did not have this event. So try to load it if possible, but
|
||||
// don't worry
|
||||
// about it not working.
|
||||
Class.forName("org.bukkit.event.block.BlockDispenseArmorEvent");
|
||||
plugin.getServer().getPluginManager().registerEvents(new DispenserArmorListener(), plugin);
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void moveChestplateToInventoryOld(Player player)
|
||||
{
|
||||
player.getInventory().getChestplate().setType(XMaterial.AIR.parseMaterial());
|
||||
}
|
||||
|
||||
private void moveChestplateToInventoryNew(Player player)
|
||||
{
|
||||
player.getInventory().addItem(player.getInventory().getChestplate());
|
||||
player.getInventory().getChestplate().setAmount(0);
|
||||
player.updateInventory();
|
||||
}
|
||||
|
||||
// Clean 1.9 inventories.
|
||||
private void cleanAnvilOld(AnvilInventory anvilInventory)
|
||||
{
|
||||
ItemStack air = new ItemStack(XMaterial.AIR.parseMaterial(), 1);
|
||||
anvilInventory.setItem(0, air);
|
||||
anvilInventory.setItem(1, air);
|
||||
anvilInventory.setItem(2, air);
|
||||
}
|
||||
|
||||
// Clean >=1.10 inventories.
|
||||
private void cleanAnvilNew(AnvilInventory anvilInventory)
|
||||
{
|
||||
anvilInventory.getItem(0).setAmount(0);
|
||||
anvilInventory.getItem(1).setAmount(anvilInventory.getItem(1).getAmount() - 1);
|
||||
anvilInventory.getItem(2).setAmount(0);
|
||||
}
|
||||
|
||||
// Check if the enchantment is allowed on elytras.
|
||||
private boolean isAllowedEnchantment(Enchantment enchant)
|
||||
{
|
||||
@ -85,18 +116,20 @@ public class EventHandlers implements Listener
|
||||
}
|
||||
|
||||
// Combine 2 maps of enchantments (and remove any invalid ones).
|
||||
private Map<Enchantment, Integer> combineEnchantments(Map<Enchantment, Integer> enchantments0, Map<Enchantment, Integer> enchantments1)
|
||||
private Map<Enchantment, Integer> combineEnchantments(Map<Enchantment, Integer> enchantments0,
|
||||
Map<Enchantment, Integer> enchantments1)
|
||||
{
|
||||
enchantments0 = fixEnchantments(enchantments0);
|
||||
Map<Enchantment, Integer> combined = new HashMap<>(fixEnchantments(enchantments0));
|
||||
|
||||
// If the second set of enchantments is null, the combined enchantments are just the first enchantments.
|
||||
// If the second set of enchantments is null, the combined enchantments are just
|
||||
// the first enchantments.
|
||||
if (enchantments1 == null)
|
||||
return combined;
|
||||
|
||||
enchantments1 = fixEnchantments(enchantments1);
|
||||
enchantments1 = fixEnchantments(enchantments1);
|
||||
// Loop through the enchantments of item1.
|
||||
for (Map.Entry<Enchantment, Integer > entry : enchantments1.entrySet())
|
||||
for (Map.Entry<Enchantment, Integer> entry : enchantments1.entrySet())
|
||||
{
|
||||
Integer enchantLevel = enchantments0.get(entry.getKey());
|
||||
if (enchantLevel != null)
|
||||
@ -123,11 +156,13 @@ public class EventHandlers implements Listener
|
||||
int protVal0 = Util.getProtectionEnchantmentsVal(enchantments0);
|
||||
int protVal1 = Util.getProtectionEnchantmentsVal(enchantments1);
|
||||
|
||||
// If they have different protection enchantments, keep enchantment1's enchantments
|
||||
// And remove the protection enchantment from enchantments0. Yes, this system only works
|
||||
// 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)
|
||||
switch (protVal0)
|
||||
{
|
||||
case 1:
|
||||
combined.remove(Enchantment.PROTECTION_ENVIRONMENTAL);
|
||||
@ -154,7 +189,7 @@ public class EventHandlers implements Listener
|
||||
{
|
||||
// Get the multiplier for the repair items.
|
||||
double mult = 0.01;
|
||||
if ( repairItem.getType().equals(Material.LEATHER))
|
||||
if (repairItem.getType().equals(Material.LEATHER))
|
||||
mult *= (100.0f / plugin.getConfigLoader().LEATHER_TO_FULL());
|
||||
|
||||
else if (repairItem.getType().equals(Material.GOLD_INGOT))
|
||||
@ -191,18 +226,16 @@ public class EventHandlers implements Listener
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Valid inputs:
|
||||
* - Elytra (armored or not) + chestplate -> Create Armored Elytra
|
||||
* - Elytra (armored) + enchanted book -> Enchant
|
||||
* - Elytra (armored) + its repair item -> Repair
|
||||
* - Elytra (armored) + other elytra (armored) -> Combine (Enchant + Repair)
|
||||
* ! Elytra (armored, !leather) + leather -> Block
|
||||
*
|
||||
* Ignoring:
|
||||
* - Elytra (not armored) + !chestplate -> None
|
||||
* - * + * -> None
|
||||
*/
|
||||
// Valid inputs:
|
||||
// - Elytra (armored or not) + chestplate -> Create Armored Elytra
|
||||
// - Elytra (armored) + enchanted book -> Enchant
|
||||
// - Elytra (armored) + its repair item -> Repair
|
||||
// - Elytra (armored) + other elytra (armored) -> Combine (Enchant + Repair)
|
||||
// ! Elytra (armored, !leather) + leather -> Block
|
||||
//
|
||||
// Ignoring:
|
||||
// - Elytra (not armored) + !chestplate -> None
|
||||
// - * + * -> None
|
||||
private Action isValidInput(ItemStack itemOne, ItemStack itemTwo)
|
||||
{
|
||||
if (itemOne == null || itemTwo == null)
|
||||
@ -212,8 +245,8 @@ public class EventHandlers implements Listener
|
||||
if (itemTwo.getType() == Material.ELYTRA && itemOne.getType() != Material.ELYTRA)
|
||||
{
|
||||
ItemStack tmp = itemOne;
|
||||
itemOne = itemTwo;
|
||||
itemTwo = tmp;
|
||||
itemOne = itemTwo;
|
||||
itemTwo = tmp;
|
||||
}
|
||||
|
||||
if (itemOne.getType() != Material.ELYTRA)
|
||||
@ -237,7 +270,8 @@ public class EventHandlers implements Listener
|
||||
if (ArmorTier.getRepairItem(tier) == matTwo)
|
||||
return Action.REPAIR;
|
||||
|
||||
// If the armored elytra is to be combined with another armored elytra of the same tier...
|
||||
// If the armored elytra is to be combined with another armored elytra of the
|
||||
// same tier...
|
||||
if (nbtEditor.getArmorTier(itemTwo) == tier)
|
||||
return Action.COMBINE;
|
||||
|
||||
@ -254,9 +288,9 @@ public class EventHandlers implements Listener
|
||||
@EventHandler
|
||||
private void onAnvilInventoryOpen(PrepareAnvilEvent event)
|
||||
{
|
||||
Player player = (Player) event.getView().getPlayer();
|
||||
ItemStack itemA = event.getInventory().getItem(0);
|
||||
ItemStack itemB = event.getInventory().getItem(1);
|
||||
Player player = (Player) event.getView().getPlayer();
|
||||
ItemStack itemA = event.getInventory().getItem(0);
|
||||
ItemStack itemB = event.getInventory().getItem(1);
|
||||
ItemStack result = null;
|
||||
|
||||
if (itemA != null && itemB != null)
|
||||
@ -264,42 +298,43 @@ public class EventHandlers implements Listener
|
||||
if (itemB.getType() == Material.ELYTRA && itemA.getType() != Material.ELYTRA)
|
||||
{
|
||||
result = itemA;
|
||||
itemA = itemB;
|
||||
itemB = result;
|
||||
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;
|
||||
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);
|
||||
enchantments = fixEnchantments(enchantments);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case REPAIR:
|
||||
newTier = curTier;
|
||||
durability = repairItem(itemA.getDurability(), itemB);
|
||||
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());
|
||||
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 = Util.armorToTier(itemB.getType());
|
||||
durability = 0;
|
||||
enchantments = combineEnchantments(enchantments, itemB.getEnchantments());
|
||||
newTier = Util.armorToTier(itemB.getType());
|
||||
durability = 0;
|
||||
enchantments = combineEnchantments(enchantments, itemB.getEnchantments());
|
||||
break;
|
||||
case ENCHANT:
|
||||
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) itemB.getItemMeta();
|
||||
newTier = curTier;
|
||||
durability = itemA.getDurability();
|
||||
newTier = curTier;
|
||||
durability = itemA.getDurability();
|
||||
// If there aren't any illegal enchantments on the book, continue as normal.
|
||||
// Otherwise... Block.
|
||||
if (verifyEnchantments(meta.getStoredEnchants()) != meta.getStoredEnchants().size())
|
||||
@ -316,7 +351,7 @@ public class EventHandlers implements Listener
|
||||
return;
|
||||
}
|
||||
|
||||
if (Util.playerHasCraftPerm(player, newTier))
|
||||
if (plugin.playerHasCraftPerm(player, newTier))
|
||||
{
|
||||
result = new ItemStack(Material.ELYTRA, 1);
|
||||
if (enchantments != null)
|
||||
@ -329,8 +364,10 @@ public class EventHandlers implements Listener
|
||||
}
|
||||
|
||||
// Check if either itemA or itemB is unoccupied.
|
||||
if ((itemA == null || itemB == null) && nbtEditor.getArmorTier(event.getInventory().getItem(2)) != ArmorTier.NONE)
|
||||
// If Item2 is occupied despite itemA or itemB not being occupied. (only for armored elytra)/
|
||||
if ((itemA == null || itemB == null) &&
|
||||
nbtEditor.getArmorTier(event.getInventory().getItem(2)) != ArmorTier.NONE)
|
||||
// If Item2 is occupied despite itemA or itemB not being occupied. (only for
|
||||
// armored elytra)/
|
||||
event.setResult(null);
|
||||
player.updateInventory();
|
||||
}
|
||||
@ -357,22 +394,28 @@ public class EventHandlers implements Listener
|
||||
}
|
||||
catch (ClassCastException exception)
|
||||
{
|
||||
// Print warning to console and exit onInventoryClick event (no support for custom inventories as they are usually used for GUI's).
|
||||
plugin.debugMsg(Level.WARNING, "Could not cast inventory to anvilInventory for player " + player.getName() + "! Armored Elytras cannot be crafted!");
|
||||
// Print warning to console and exit onInventoryClick event (no support for
|
||||
// custom inventories as they are usually used for GUI's).
|
||||
plugin.debugMsg(Level.WARNING, "Could not cast inventory to anvilInventory for player " + player.getName()
|
||||
+ "! Armored Elytras cannot be crafted!");
|
||||
return;
|
||||
}
|
||||
|
||||
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 (armortier != ArmorTier.NONE && Util.playerHasCraftPerm(player, armortier))
|
||||
if (armortier != ArmorTier.NONE && plugin.playerHasCraftPerm(player, armortier))
|
||||
{
|
||||
// Create a new armored elytra and give that one to the player instead of the result.
|
||||
// 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.
|
||||
ItemStack result = nbtEditor.addArmorNBTTags(anvilInventory.getItem(2), armortier, plugin.getConfigLoader().unbreakable());
|
||||
// Create a new armored elytra and give that one to the player instead of the
|
||||
// result.
|
||||
// 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.
|
||||
ItemStack result = nbtEditor.addArmorNBTTags(anvilInventory.getItem(2), armortier,
|
||||
plugin.getConfigLoader().unbreakable());
|
||||
// Give the result to the player and clear the anvil's inventory.
|
||||
if (e.isShiftClick())
|
||||
{
|
||||
@ -384,98 +427,34 @@ public class EventHandlers implements Listener
|
||||
else
|
||||
player.setItemOnCursor(result);
|
||||
// Clean the anvil's inventory after transferring the items.
|
||||
cleanAnvil(anvilInventory);
|
||||
cleanAnvilInventory.accept(anvilInventory);
|
||||
player.updateInventory();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the player has the correct permission and that the item is not broken.
|
||||
// Make sure the player has the correct permission and that the item is not
|
||||
// broken.
|
||||
private AllowedToWearEnum isAllowedToWear(ItemStack elytra, Player player, ArmorTier armorTier)
|
||||
{
|
||||
if (armorTier.equals(ArmorTier.NONE))
|
||||
return AllowedToWearEnum.ALLOWED;
|
||||
if (Util.isBroken(elytra))
|
||||
return AllowedToWearEnum.BROKEN;
|
||||
if (!Util.playerHasWearPerm(player, armorTier))
|
||||
if (!plugin.playerHasWearPerm(player, armorTier))
|
||||
return AllowedToWearEnum.NOPERMISSION;
|
||||
return AllowedToWearEnum.ALLOWED;
|
||||
}
|
||||
|
||||
// Check if the player tries to equip armor by richt clicking it.
|
||||
@EventHandler
|
||||
public void onRightClick(PlayerInteractEvent event)
|
||||
{
|
||||
if (!event.getAction().equals(org.bukkit.event.block.Action.RIGHT_CLICK_AIR) &&
|
||||
!event.getAction().equals(org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK))
|
||||
return;
|
||||
|
||||
ItemStack item = event.getItem();
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (item.getType() == Material.ELYTRA)
|
||||
{
|
||||
ArmorTier armorTier = nbtEditor.getArmorTier(item);
|
||||
if (nbtEditor.getArmorTier(item) == ArmorTier.NONE)
|
||||
return;
|
||||
AllowedToWearEnum allowed = isAllowedToWear(item, player, armorTier);
|
||||
if (allowed == AllowedToWearEnum.BROKEN)
|
||||
{
|
||||
plugin.messagePlayer(player, plugin.getMyMessages().getString("MESSAGES.RepairNeeded"));
|
||||
event.setCancelled(true);
|
||||
player.updateInventory();
|
||||
}
|
||||
else if (allowed == AllowedToWearEnum.NOPERMISSION)
|
||||
{
|
||||
plugin.usageDeniedMessage(player, armorTier);
|
||||
event.setCancelled(true);
|
||||
player.updateInventory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Player closes their inventory. Also checks for whether they are allowed to wear the armored elytra they are wearing.
|
||||
// This is done again here because there are ways to bypass permission check when equipping.
|
||||
@EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent e)
|
||||
{
|
||||
verifyArmorInChestSlot((Player) e.getPlayer());
|
||||
}
|
||||
|
||||
// Check if the player is allowed to wear the armored elytra based on their permissions.
|
||||
private void verifyArmorInChestSlot(Player player)
|
||||
{
|
||||
ItemStack chestplate = player.getInventory().getChestplate();
|
||||
// If the player equips a new chestplate.
|
||||
if (player.getInventory().getChestplate() == null)
|
||||
return;
|
||||
|
||||
ArmorTier armorTier = nbtEditor.getArmorTier(chestplate);
|
||||
// If that chestplate is an (armored) elytra.
|
||||
if (armorTier == ArmorTier.NONE)
|
||||
return;
|
||||
|
||||
AllowedToWearEnum allowed = isAllowedToWear(chestplate, player, armorTier);
|
||||
if (allowed == AllowedToWearEnum.BROKEN)
|
||||
{
|
||||
plugin.messagePlayer(player, plugin.getMyMessages().getString("MESSAGES.RepairNeeded"));
|
||||
unenquipChestPlayer(player);
|
||||
}
|
||||
else if (allowed == AllowedToWearEnum.NOPERMISSION)
|
||||
{
|
||||
plugin.usageDeniedMessage(player, armorTier);
|
||||
unenquipChestPlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
// Because the armored elytra doesn't actually give any armor, the damage
|
||||
// received by players wearing an armored elytra is calculated here.
|
||||
// Handle armored elytra durability loss.
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onPlayerDamage(EntityDamageEvent e)
|
||||
{
|
||||
if(!(e.getEntity() instanceof Player))
|
||||
if (!(e.getEntity() instanceof Player))
|
||||
return;
|
||||
|
||||
if (plugin.getConfigLoader().unbreakable())
|
||||
return;
|
||||
|
||||
Player p = (Player) e.getEntity();
|
||||
@ -495,21 +474,24 @@ public class EventHandlers implements Listener
|
||||
if (cause != DamageCause.DROWNING && cause != DamageCause.STARVATION && cause != DamageCause.SUFFOCATION &&
|
||||
cause != DamageCause.SUICIDE && cause != DamageCause.FLY_INTO_WALL && cause != DamageCause.POISON)
|
||||
{
|
||||
int durability = p.getInventory().getChestplate().getDurability();
|
||||
int durability = p.getInventory().getChestplate().getDurability();
|
||||
int maxDurability = p.getInventory().getChestplate().getType().getMaxDurability();
|
||||
int newDurability = durability + ((int) (e.getDamage() / 4) > 1 ? (int) (e.getDamage() / 4) : 1);
|
||||
|
||||
// If the elytra has the durability enchantment, we calculate the durability loss ourselves.
|
||||
// If the elytra has the durability enchantment, we calculate the durability
|
||||
// loss ourselves.
|
||||
if (p.getInventory().getChestplate().containsEnchantment(Enchantment.DURABILITY))
|
||||
{
|
||||
// Get a random int between 0 and 100 to use in deciding if the durability enchantment will take effect.
|
||||
Random r = new Random();
|
||||
int randomInt = r.nextInt(101);
|
||||
int enchantLevel = p.getInventory().getChestplate().getEnchantmentLevel(Enchantment.DURABILITY);
|
||||
// Get a random int between 0 and 100 to use in deciding if the durability
|
||||
// enchantment will take effect.
|
||||
Random r = new Random();
|
||||
int randomInt = r.nextInt(101);
|
||||
int enchantLevel = p.getInventory().getChestplate().getEnchantmentLevel(Enchantment.DURABILITY);
|
||||
int durabilityDelta = (100 / (enchantLevel + 1)) < randomInt ? 0 : 1;
|
||||
// If the durability equals/exceeds maxDurability, it's broken (0 = full item durability).
|
||||
// If the durability equals/exceeds maxDurability, it's broken (0 = full item
|
||||
// durability).
|
||||
if (durability >= maxDurability)
|
||||
unenquipChestPlayer(p);
|
||||
moveChestplateToInventory.accept(p);
|
||||
else
|
||||
newDurability = durability + durabilityDelta;
|
||||
}
|
||||
@ -517,28 +499,37 @@ public class EventHandlers implements Listener
|
||||
if (newDurability >= maxDurability)
|
||||
{
|
||||
newDurability = maxDurability;
|
||||
unenquipChestPlayer(p);
|
||||
moveChestplateToInventory.accept(p);
|
||||
}
|
||||
elytra.setDurability((short) (newDurability));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the player is trying to equip a broken elytra (and prevent that).
|
||||
@EventHandler
|
||||
public void playerEquipsArmor(InventoryClickEvent e)
|
||||
public void onEquip(ArmorEquipEvent e)
|
||||
{
|
||||
if (!(e.getWhoClicked() instanceof Player))
|
||||
if (!e.getType().equals(ArmorType.CHESTPLATE) ||
|
||||
!e.getNewArmorPiece().getType().equals(Material.ELYTRA) ||
|
||||
e.getNewArmorPiece() == null)
|
||||
return;
|
||||
|
||||
Player player = (Player) e.getWhoClicked();
|
||||
new BukkitRunnable()
|
||||
ArmorTier armorTier = nbtEditor.getArmorTier(e.getNewArmorPiece());
|
||||
AllowedToWearEnum allowed = isAllowedToWear(e.getNewArmorPiece(), e.getPlayer(), armorTier);
|
||||
switch(allowed)
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
verifyArmorInChestSlot(player);
|
||||
}
|
||||
}.runTaskLater(plugin, 1);
|
||||
case ALLOWED:
|
||||
break;
|
||||
case BROKEN:
|
||||
plugin.messagePlayer(e.getPlayer(), plugin.getMyMessages().getString("MESSAGES.RepairNeeded"));
|
||||
e.setCancelled(true);
|
||||
break;
|
||||
case NOPERMISSION:
|
||||
plugin.usageDeniedMessage(e.getPlayer(), armorTier);
|
||||
e.setCancelled(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,6 @@ public class GetArmorValueNew implements GetArmorValue
|
||||
plugin.myLogger(Level.INFO, "Failed to obtain armor value from NBT!");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ public class GetArmorValueOld implements GetArmorValue
|
||||
String stringAtPos = nbtString.substring(pos, pos + 1);
|
||||
return Integer.parseInt(stringAtPos);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ public class NBTEditor
|
||||
Object nmsStack = asNMSCopy.invoke(null, item);
|
||||
Object compound = ((boolean) hasTag.invoke(nmsStack) ? getTag.invoke(nmsStack) : NBTTagCompound.newInstance());
|
||||
Object modifiers = NBTTagList.newInstance();
|
||||
Object armor = NBTTagCompound.newInstance();
|
||||
Object armor = NBTTagCompound.newInstance(); // I should be able to simply add custom tags here!
|
||||
setTag.invoke (armor, "AttributeName", NBTTagStringCtor.newInstance("generic.armor"));
|
||||
setTag.invoke (armor, "Name", NBTTagStringCtor.newInstance("generic.armor"));
|
||||
setTag.invoke (armor, "Amount", NBTTagIntCtor.newInstance(armorProtection));
|
||||
|
@ -30,6 +30,8 @@ public class ConfigLoader
|
||||
private boolean noFlightDurability;
|
||||
private List<String> allowedEnchantments;
|
||||
private boolean allowMultipleProtectionEnchantments;
|
||||
public boolean bypassWearPerm;
|
||||
public boolean bypassCraftPerm;
|
||||
|
||||
private ArrayList<ConfigOption<?>> configOptionsList;
|
||||
private ArmoredElytra plugin;
|
||||
@ -87,7 +89,7 @@ public class ConfigLoader
|
||||
"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.",
|
||||
"a lot of resources, so you can just leave the plugin enabled and ignore it.",
|
||||
"Please do not forget to MAKE A BACKUP before enabling this option!"
|
||||
};
|
||||
String[] languageFileComment =
|
||||
@ -102,11 +104,16 @@ public class ConfigLoader
|
||||
"elytra that has the protection enchantment with an enchanted book that has the blast protection enchantment",
|
||||
"would result in removal of the protection enchantment and addition of the blast protection enchantment."
|
||||
};
|
||||
String[] permissionsComment =
|
||||
{
|
||||
"Globally bypass permissions for wearing and/or crafting amored elytras. Useful if permissions are unavailable."
|
||||
};
|
||||
|
||||
|
||||
// Set default list of allowed enchantments.
|
||||
allowedEnchantments = new ArrayList<>(Arrays.asList("DURABILITY", "PROTECTION_FIRE", "PROTECTION_EXPLOSIONS",
|
||||
"PROTECTION_PROJECTILE", "PROTECTION_ENVIRONMENTAL", "THORNS",
|
||||
"BINDING_CURSE", "VANISHING_CURSE"));
|
||||
"BINDING_CURSE", "VANISHING_CURSE", "MENDING"));
|
||||
|
||||
FileConfiguration config = plugin.getConfig();
|
||||
|
||||
@ -123,6 +130,8 @@ public class ConfigLoader
|
||||
enableDebug = addNewConfigOption(config, "enableDebug", false, debugComment);
|
||||
uninstallMode = addNewConfigOption(config, "uninstallMode", false, uninstallComment);
|
||||
languageFile = addNewConfigOption(config, "languageFile", "en_US", languageFileComment);
|
||||
bypassWearPerm = addNewConfigOption(config, "bypassWearPermissions", true, permissionsComment);
|
||||
bypassCraftPerm = addNewConfigOption(config, "bypassCraftPermissions", true, null);
|
||||
|
||||
writeConfig();
|
||||
}
|
||||
@ -239,4 +248,14 @@ public class ConfigLoader
|
||||
{
|
||||
return allowedEnchantments;
|
||||
}
|
||||
|
||||
public boolean bypassWearPerm()
|
||||
{
|
||||
return bypassWearPerm;
|
||||
}
|
||||
|
||||
public boolean bypassCraftPerm()
|
||||
{
|
||||
return bypassCraftPerm;
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,11 @@ public class Messages
|
||||
|
||||
// Load the default en_US from the resources.
|
||||
plugin.saveResource("en_US.txt", true);
|
||||
defaultFile.setWritable(false);
|
||||
if (!defaultFile.setWritable(false))
|
||||
{
|
||||
plugin.myLogger(Level.WARNING, "Could not set default language file to read-only!");
|
||||
plugin.myLogger(Level.WARNING, "This is not a big problem. Just remember not to edit the file!");
|
||||
}
|
||||
}
|
||||
|
||||
// Read locale file.
|
||||
@ -58,7 +62,7 @@ public class Messages
|
||||
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[] newLineSplitter = value.split("\\\\n");
|
||||
|
||||
String values = newLineSplitter[0];
|
||||
|
||||
@ -83,22 +87,11 @@ public class Messages
|
||||
// Get a string from a key. Returns "null" if null.
|
||||
public String getString(String key)
|
||||
{
|
||||
String value = null;
|
||||
value = messageMap.get(key);
|
||||
if (value == null)
|
||||
{
|
||||
value = "ArmoredElytra: Translation not found! Contact server admin!";
|
||||
plugin.myLogger(Level.WARNING, "Failed to get translation for key " + key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
String value = messageMap.get(key);
|
||||
if (value != null)
|
||||
return value;
|
||||
|
||||
public String getStringReverse(String value)
|
||||
{
|
||||
return messageMap.entrySet().stream()
|
||||
.filter(e -> e.getValue().equals(value))
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
plugin.myLogger(Level.WARNING, "Failed to get the translation for key " + key);
|
||||
return "Translation for key \"" + key + "\" not found! Contact server admin!";
|
||||
}
|
||||
}
|
||||
|
@ -1,425 +0,0 @@
|
||||
package nl.pim16aap2.armoredElytra.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
* bStats collects some data for plugin authors.
|
||||
*
|
||||
* Check out https://bStats.org/ to learn more about bStats!
|
||||
*/
|
||||
public class Metrics
|
||||
{
|
||||
|
||||
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' });
|
||||
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))
|
||||
{
|
||||
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The version of this bStats class
|
||||
public static final int B_STATS_VERSION = 1;
|
||||
|
||||
// The url to which the data is sent
|
||||
private static final String URL = "https://bStats.org/submitData/bukkit";
|
||||
|
||||
// Should failed requests be logged?
|
||||
private static boolean logFailedRequests;
|
||||
|
||||
// The uuid of the server
|
||||
private static String serverUUID;
|
||||
|
||||
// The plugin
|
||||
private final JavaPlugin plugin;
|
||||
|
||||
// A list with all custom charts
|
||||
private final List<CustomChart> charts = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param plugin The plugin which stats should be submitted.
|
||||
*/
|
||||
public Metrics(JavaPlugin plugin)
|
||||
{
|
||||
if (plugin == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Plugin cannot be null!");
|
||||
}
|
||||
this.plugin = plugin;
|
||||
|
||||
// Get the config file
|
||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||
|
||||
// Check if the config file exists
|
||||
if (!config.isSet("serverUuid"))
|
||||
{
|
||||
|
||||
// Add default values
|
||||
config.addDefault("enabled", true);
|
||||
// Every server gets it's unique random id.
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||
// Should failed request be logged?
|
||||
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.save(configFile);
|
||||
}
|
||||
catch (IOException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
// Load the data
|
||||
serverUUID = config.getString("serverUuid");
|
||||
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
|
||||
{
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
found = true; // We aren't the first
|
||||
break;
|
||||
}
|
||||
catch (NoSuchFieldException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
// Register our service
|
||||
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal);
|
||||
if (!found)
|
||||
{
|
||||
// We are the first!
|
||||
startSubmitting();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the Scheduler which submits our data every 30 minutes.
|
||||
*/
|
||||
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()
|
||||
{
|
||||
@Override
|
||||
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()
|
||||
{
|
||||
@Override
|
||||
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!
|
||||
// WARNING: Just don't do it!
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin specific data. This method is called using Reflection.
|
||||
*
|
||||
* @return The plugin specific data.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public JSONObject getPluginData()
|
||||
{
|
||||
JSONObject data = new JSONObject();
|
||||
|
||||
String pluginName = plugin.getDescription().getName();
|
||||
String pluginVersion = plugin.getDescription().getVersion();
|
||||
|
||||
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)
|
||||
{
|
||||
// Add the data of the custom charts
|
||||
JSONObject chart = customChart.getRequestJsonObject();
|
||||
if (chart == null)
|
||||
{ // If the chart is null, we skip it
|
||||
continue;
|
||||
}
|
||||
customCharts.add(chart);
|
||||
}
|
||||
data.put("customCharts", customCharts);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server specific data.
|
||||
*
|
||||
* @return The server specific data.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private JSONObject getServerData()
|
||||
{
|
||||
// Minecraft specific data
|
||||
int playerAmount;
|
||||
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;
|
||||
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 = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
|
||||
}
|
||||
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
|
||||
String bukkitVersion = org.bukkit.Bukkit.getVersion();
|
||||
bukkitVersion = bukkitVersion.substring(bukkitVersion.indexOf("MC: ") + 4, bukkitVersion.length() - 1);
|
||||
|
||||
// OS/Java specific data
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
String osName = System.getProperty("os.name");
|
||||
String osArch = System.getProperty("os.arch");
|
||||
String osVersion = System.getProperty("os.version");
|
||||
int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
JSONObject data = new JSONObject();
|
||||
|
||||
data.put("serverUUID", serverUUID);
|
||||
|
||||
data.put("playerAmount", playerAmount);
|
||||
data.put("onlineMode", onlineMode);
|
||||
data.put("bukkitVersion", bukkitVersion);
|
||||
|
||||
data.put("javaVersion", javaVersion);
|
||||
data.put("osName", osName);
|
||||
data.put("osArch", osArch);
|
||||
data.put("osVersion", osVersion);
|
||||
data.put("coreCount", coreCount);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the data and sends it afterwards.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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
|
||||
{
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
data.put("plugins", pluginData);
|
||||
|
||||
// Create a new thread for the connection to the bStats server
|
||||
new Thread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Send the data
|
||||
sendData(data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Something went wrong! :(
|
||||
if (logFailedRequests)
|
||||
{
|
||||
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the data to the bStats server.
|
||||
*
|
||||
* @param data The data to send.
|
||||
* @throws Exception If the request failed.
|
||||
*/
|
||||
private static void sendData(JSONObject data) throws Exception
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Data cannot be null!");
|
||||
}
|
||||
if (Bukkit.isPrimaryThread())
|
||||
{
|
||||
throw new IllegalAccessException("This method must not be called from the main thread!");
|
||||
}
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
|
||||
|
||||
// Compress the data to save bandwidth
|
||||
byte[] compressedData = compress(data.toString());
|
||||
|
||||
// Add headers
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
|
||||
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
|
||||
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
|
||||
|
||||
// Send data
|
||||
connection.setDoOutput(true);
|
||||
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
|
||||
outputStream.write(compressedData);
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
connection.getInputStream().close(); // We don't care about the response - Just send our data :)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given String.
|
||||
*
|
||||
* @param str The string to gzip.
|
||||
* @return The gzipped String.
|
||||
* @throws IOException If the compression failed.
|
||||
*/
|
||||
private static byte[] compress(final String str) throws IOException
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
|
||||
gzip.write(str.getBytes("UTF-8"));
|
||||
gzip.close();
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom chart.
|
||||
*/
|
||||
public static abstract class CustomChart
|
||||
{
|
||||
|
||||
// The id of the chart
|
||||
final String chartId;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
*/
|
||||
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()
|
||||
{
|
||||
JSONObject chart = new JSONObject();
|
||||
chart.put("chartId", chartId);
|
||||
try
|
||||
{
|
||||
JSONObject data = getChartData();
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ import java.util.Map;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class Util
|
||||
@ -92,14 +91,4 @@ public class Util
|
||||
ret += 16;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static boolean playerHasCraftPerm(Player player, ArmorTier armorTier)
|
||||
{
|
||||
return player.hasPermission("armoredelytra.craft." + ArmorTier.getName(armorTier));
|
||||
}
|
||||
|
||||
public static boolean playerHasWearPerm(Player player, ArmorTier armorTier)
|
||||
{
|
||||
return player.hasPermission("armoredelytra.wear." + ArmorTier.getName(armorTier));
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
name: ArmoredElytra
|
||||
main: nl.pim16aap2.armoredElytra.ArmoredElytra
|
||||
version: 2.4.8
|
||||
version: ${project.version}
|
||||
author: pim16aap2
|
||||
commands:
|
||||
ArmoredElytra:
|
||||
|
Loading…
x
Reference in New Issue
Block a user