diff --git a/config.yml b/config.yml
index ac928e8..d573702 100644
--- a/config.yml
+++ b/config.yml
@@ -1,6 +1,14 @@
# Only drop heads when killed directly by a player
player-kills-only: true
+# Whether to drop heads if killed by projectile weapon from a player
+# Only checked if player-kills-only is true
+drop-for-ranged-kills: false
+
+# Whether to drop heads for any death cause if last-damager is a player
+# Only checked if player-kills-only is true
+drop-for-indirect-kills: false
+
# Only drop player heads (you can also do this in "default chances" file
# by making all mobs except players have a 0% chance of dropping a head)
player-heads-only: false
@@ -8,30 +16,35 @@ player-heads-only: false
# Whether to keep entity heads synced with the latest vanilla textures
refresh-textures: true
+# Whether to reset the item name for a head when refreshing its texture
+refresh-item-names: false
+
# When a player changes their skin, should old heads be updated to the
# new texture? Note: to refresh, heads must be mined or dropped
update-on-skin-change: false
# Enable the mechanic where any mob killed by a charged creeper explosion
# will drop its head with 100% probability * the spawn-cause modifier
-# This setting will override "player-kills-only" (but not "player-heads-only")
+# This setting overrides "player-kills-only" (but not "player-heads-only")
charged-creeper-drops: true
# A Minecraft easter egg is that mobs named 'Dinnerbone' or 'Grumm' are
# upside down.. If you want their heads to share this trait, set to true
grumm-heads: true
-# Percent increase in drop chance per looting level
-looting-bonus: 0.4
-
-# Uses non-linear (taylor series modifiers) when calculating drop chance
-use-taylor-modifiers: true
+# Uses non-linear function when calculating drop chance looting modifier.
+# If set to 'false', each looting level will add 1% to the drop chance.
+use-taylor-modifiers: false
# Only drop heads if the killer used an axe
must-use-axe: false
# Enable plugin Updater (checks for new versions with new head textures)
-update-plugin: true
+# Note: Disabled by default because some servers have reported errors
+update-plugin: false
+
+# Run in debug mode (prints extra information to console)
+debug-messages: true
# (Optional) Whitelist of tools a player must be using for heads to drop
# If "must-use-axe" is enabled, this list will be ignored
@@ -43,6 +56,7 @@ must-use:
# (Optional) Let certain tools have a higher chance of beheading
# The number is the percent increase in drop chance when using that tool
+# Eg: 3 = 3x chance, 0.8 = 80% chance increase, etc.
specific-tool-modifiers:
GOLD_AXE: 3
DIAMOND_AXE: 1
diff --git a/head-drop-rates.txt b/head-drop-rates.txt
index 013fa6b..f051b85 100644
--- a/head-drop-rates.txt
+++ b/head-drop-rates.txt
@@ -1,21 +1,21 @@
PLAYER: 0.15
UNKNOWN: 0.0001
BAT: 0.01
-BLAZE: 0.02
+BLAZE: 0.009
CAT: 0.008
CAVE_SPIDER: 0.001
CHICKEN: 0.001
COD: 0.009
-COW: 0.004
+COW: 0.003
CREEPER: 0.04 : NoLooting
DOLPHIN: 0.01
DONKEY: 0.007
-DROWNED: 0.008
+DROWNED: 0.005
ELDER_GUARDIAN: 0.05
ENDER_DRAGON: 0.5
ENDERMAN: 0.005
ENDERMITE: 0.01
-EVOKER: 0.15
+EVOKER: 0.008
GHAST: 0.006
GIANT: 0.05
GUARDIAN: 0.004
@@ -34,7 +34,7 @@ PARROT: 0.008
PHANTOM: 0.009
PIG: 0.004
PIG_ZOMBIE: 0.002
-PILLAGER: 0.01
+PILLAGER: 0.008
POLAR_BEAR: 0.008
PUFFERFISH: 0.012
RABBIT: 0.003
@@ -47,7 +47,7 @@ SKELETON: 0.007
SKELETON_HORSE: 0.01
SLIME: 0.006
SNOWMAN: 0.008
-SPIDER: 0.007
+SPIDER: 0.006
SQUID: 0.005
STRAY: 0.009
TROPICAL_FISH: 0.02
@@ -55,13 +55,13 @@ TURTLE: 0.007
TRADER_LLAMA: 0.012
VEX: 0.007
VILLAGER: 0.007
-VINDICATOR: 0.01
+VINDICATOR: 0.008
WANDERING_TRADER: 0.017
WITCH: 0.004
WITHER: 0.05
WITHER_SKELETON: 0.025 # Vanilla default
WOLF: 0.007
-ZOMBIE: 0.007
+ZOMBIE: 0.006
ZOMBIE_HORSE: 0.007
ZOMBIE_VILLAGER: 0.008
diff --git a/head-textures.txt b/head-textures.txt
index b8934f8..95549fb 100644
--- a/head-textures.txt
+++ b/head-textures.txt
@@ -157,7 +157,7 @@ TROPICAL_FISH|CLOWNFISH: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJ
TROPICAL_FISH|COTTON_CANDY_BETTA: xxx
TROPICAL_FISH|DOTTYBACK: xxx
TROPICAL_FISH|EMPEROR_RED_SNAPPER: xxx
-TROPICAL_FISH|RED_EMPEROR: EMPEROR_RED_SNAPPER
+TROPICAL_FISH|RED_EMPEROR: xxx
TROPICAL_FISH|GOATFISH: xxx
TROPICAL_FISH|MOORISH_IDOL: xxx
TROPICAL_FISH|ORNATE_BUTTERFLYFISH: xxx
diff --git a/plugin.yml b/plugin.yml
index 22980c6..c7d2f06 100644
--- a/plugin.yml
+++ b/plugin.yml
@@ -1,7 +1,7 @@
name: DropHeads
main: net.evmodder.DropHeads.DropHeads
author: EvModder/EvilWitchdoctor
-version: 3.2.8 #8=stable 1.14 release
+version: 3.2.10 #10=item renaming,wither drop rate fix
api-version: 1.13
commands:
@@ -9,28 +9,28 @@ commands:
description: Get a player or mob head
usage: /gethead [name]
aliases: [gethead,dhspawn,spawn-head,head,phspawn,skull]
- permission: evp.dropheads.spawn
+ permission: dropheads.spawn
permission-message: You do not have permission to do this.
debug_all_heads:
description: Place all heads into the world around the player
usage: /debug_all_heads
- permission: evp.dropheads.debug
+ permission: dropheads.debug
permission-message: You do not have permission to do this.
permissions:
- evp.dropheads.alwaysbehead:
+ dropheads.alwaysbehead:
description: This player will get heads 100% of the time
default: false
- evp.dropheads.canbehead:
+ dropheads.canbehead:
description: This player will be able to get heads
default: true
- evp.dropheads.spawn:
+ dropheads.spawn:
description: Permission to spawn heads with a command
default: op
- evp.dropheads.debug:
+ dropheads.debug:
description: Permission to spawn all the heads in a big cube
default: false
\ No newline at end of file
diff --git a/src/net/evmodder/DropHeads/DropHeads.java b/src/net/evmodder/DropHeads/DropHeads.java
index b18807d..72784bd 100644
--- a/src/net/evmodder/DropHeads/DropHeads.java
+++ b/src/net/evmodder/DropHeads/DropHeads.java
@@ -1,3 +1,21 @@
+/*
+ * DropHeds - a Bukkit plugin for naturally dropping mob heads
+ *
+ * Copyright (C) 2017 - 2019 Nathan / EvModder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
package net.evmodder.DropHeads;
import net.evmodder.DropHeads.commands.*;
@@ -18,7 +36,10 @@ public final class DropHeads extends EvPlugin{
api = new HeadAPI();
getServer().getPluginManager().registerEvents(new EntitySpawnListener(), this);
getServer().getPluginManager().registerEvents(new EntityDeathListener(), this);
- if(config.getBoolean("refresh-textures", true)){
+ if(config.getBoolean("drop-for-indirect-kills", false)){
+ getServer().getPluginManager().registerEvents(new EntityDamageListener(), this);
+ }
+ if(config.getBoolean("refresh-textures", false)){
getServer().getPluginManager().registerEvents(new ItemDropListener(), this);
getServer().getPluginManager().registerEvents(new BlockBreakListener(), this);
}
diff --git a/src/net/evmodder/DropHeads/TextureKeyLookup.java b/src/net/evmodder/DropHeads/TextureKeyLookup.java
index 37b012b..3e70b91 100644
--- a/src/net/evmodder/DropHeads/TextureKeyLookup.java
+++ b/src/net/evmodder/DropHeads/TextureKeyLookup.java
@@ -122,7 +122,8 @@ static String getTextureKey(LivingEntity entity){
if(entity.getCustomName() != null && entity.getCustomName().equals("jeb_")) return "SHEEP|JEB";
else return "SHEEP|"+((Sheep)entity).getColor().name();
case SHULKER:
- return "SHULKER|"+((Shulker)entity).getColor().name();
+ DyeColor color = ((Shulker)entity).getColor();
+ return color == null ? "SHULKER" : "SHULKER|"+color.name();
case TROPICAL_FISH:
TropicalFish f = (TropicalFish)entity;
return "TROPICAL_FISH|"+f.getBodyColor()+"|"+f.getPatternColor()+"|"+f.getPattern();
diff --git a/src/net/evmodder/DropHeads/listeners/EntityDamageListener.java b/src/net/evmodder/DropHeads/listeners/EntityDamageListener.java
new file mode 100644
index 0000000..f1bb889
--- /dev/null
+++ b/src/net/evmodder/DropHeads/listeners/EntityDamageListener.java
@@ -0,0 +1,29 @@
+package net.evmodder.DropHeads.listeners;
+
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Projectile;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.metadata.FixedMetadataValue;
+import net.evmodder.DropHeads.DropHeads;
+
+public class EntityDamageListener implements Listener{
+ final DropHeads pl;
+ final boolean allowProjectileKills;
+
+ // Only enabled if drop-for-indirect-kills is TRUE
+ public EntityDamageListener(){
+ pl = DropHeads.getPlugin();
+ allowProjectileKills = pl.getConfig().getBoolean("drop-for-ranged-kills", false);
+ }
+ @EventHandler(priority = EventPriority.HIGH)
+ public void entityDamageEvent(EntityDamageByEntityEvent evt){
+ if(evt.isCancelled()) return;
+ if(evt.getDamager() instanceof Player || (allowProjectileKills && evt.getDamager() instanceof Projectile
+ && ((Projectile)evt.getDamager()).getShooter() instanceof Player)){
+ evt.getEntity().setMetadata("PlayerDamage", new FixedMetadataValue(pl, System.currentTimeMillis()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/net/evmodder/DropHeads/listeners/EntityDeathListener.java b/src/net/evmodder/DropHeads/listeners/EntityDeathListener.java
index c219083..a6a06d6 100644
--- a/src/net/evmodder/DropHeads/listeners/EntityDeathListener.java
+++ b/src/net/evmodder/DropHeads/listeners/EntityDeathListener.java
@@ -3,9 +3,8 @@
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
+import java.util.Iterator;
import java.util.Random;
-import java.util.Set;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.enchantments.Enchantment;
@@ -14,6 +13,7 @@
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
+import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
@@ -21,27 +21,33 @@
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import net.evmodder.DropHeads.DropHeads;
+import net.evmodder.EvLib.EvUtils;
import net.evmodder.EvLib.FileIO;
public class EntityDeathListener implements Listener{
final DropHeads pl;
- final boolean playerKillsOnly, playerHeadsOnly, useTaylorModifiers, chargedCreepers;
- final Set mustUseTools = new HashSet();
- final Set noLootingEffectMobs = new HashSet();
- final Map mobChances = new HashMap();
- final Map toolBonuses = new HashMap();
- final double lootingBonus; double DEFAULT_CHANCE;
+ final boolean playerKillsOnly, allowIndirectKills, allowProjectileKills;
+ final boolean playerHeadsOnly, useTaylorModifiers, CHARGED_CREEPER_DROPS;
+ final HashSet mustUseTools;
+ final HashSet noLootingEffectMobs;
+ final HashMap mobChances;
+ final HashMap toolBonuses;
+ double DEFAULT_CHANCE;
final Random rand;
+ final boolean DEBUG_MODE;
public EntityDeathListener(){
pl = DropHeads.getPlugin();
playerKillsOnly = pl.getConfig().getBoolean("player-kills-only", true);
+ allowIndirectKills = pl.getConfig().getBoolean("drop-for-indirect-kills", false);
+ allowProjectileKills = pl.getConfig().getBoolean("drop-for-ranged-kills", false);
playerHeadsOnly = pl.getConfig().getBoolean("player-heads-only", false);
useTaylorModifiers = pl.getConfig().getBoolean("use-taylor-modifiers", true);
- chargedCreepers = pl.getConfig().getBoolean("charged-creeper-drops", true);
- lootingBonus = pl.getConfig().getDouble("looting-bonus", 0.4);
+ CHARGED_CREEPER_DROPS = pl.getConfig().getBoolean("charged-creeper-drops", true);
+ DEBUG_MODE = pl.getConfig().getBoolean("debug-messages", true);
rand = new Random();
+ mustUseTools = new HashSet();
if(pl.getConfig().getBoolean("must-use-axe")){
mustUseTools.add(Material.DIAMOND_AXE);
mustUseTools.add(Material.IRON_AXE);
@@ -56,95 +62,114 @@ else for(String toolName : pl.getConfig().getStringList("must-use")){
else pl.getLogger().warning("Unknown Tool \""+toolName+"\"!");
}
+ toolBonuses = new HashMap();
ConfigurationSection specificModifiers = pl.getConfig().getConfigurationSection("specific-tool-modifiers");
if(specificModifiers != null) for(String toolName : specificModifiers.getKeys(false)){
Material mat = Material.getMaterial(toolName.toUpperCase());
- if(mat != null) toolBonuses.put(mat, (float) specificModifiers.getDouble(toolName));
+ if(mat != null) toolBonuses.put(mat, specificModifiers.getDouble(toolName));
}
//Load individual mobs' drop chances
InputStream defaultChances = pl.getClass().getResourceAsStream("/head-drop-rates.txt");
String chances = FileIO.loadFile("head-drop-rates.txt", defaultChances);
+ mobChances = new HashMap();
+ noLootingEffectMobs = new HashSet();
for(String line : chances.split("\n")){
String[] parts = line.replace(" ", "").replace("\t", "").toUpperCase().split(":");
- if(parts.length > 1){
- try{
- if(parts[0].equals("UNKNOWN")){
- DEFAULT_CHANCE = Float.parseFloat(parts[1]);
- continue;
- }
- EntityType eType = EntityType.valueOf(parts[0]);
- float dropChance = Float.parseFloat(parts[1]);
- mobChances.put(eType, dropChance);
- if(parts.length > 2 && parts[2].equals("NOLOOTING")) noLootingEffectMobs.add(eType);
- // Commented out to allow >1 because Spawn-Reason modifiers are added after this
- /*if(dropChance > 1F){
- pl.getLogger().severe("Invalid value: "+parts[1]);
- pl.getLogger().severe("Drop chance must be between 0 and 1");
- mobChances.put(eType, Math.min(dropChance/10F, 1F));
- }*/
- }
- catch(NumberFormatException ex){pl.getLogger().severe("Invalid value: "+parts[1]);}
- catch(IllegalArgumentException ex){
- pl.getLogger().severe("Unknown entity type: "+parts[0]);
+ if(parts.length < 2) continue;
+ try{
+ if(parts[0].equals("UNKNOWN")){
+ DEFAULT_CHANCE = Float.parseFloat(parts[1]);
+ continue;
}
+ EntityType eType = EntityType.valueOf(parts[0]);
+ double dropChance = Double.parseDouble(parts[1]);
+ mobChances.put(eType, dropChance);
+ if(parts.length > 2 && parts[2].equals("NOLOOTING")) noLootingEffectMobs.add(eType);
+ // Commented out to allow >1 because Spawn-Reason modifiers are added after this
+ /*if(dropChance > 1F){
+ pl.getLogger().severe("Invalid value: "+parts[1]);
+ pl.getLogger().severe("Drop chance must be between 0 and 1");
+ mobChances.put(eType, Math.min(dropChance/10F, 1F));
+ }*/
+ }
+ catch(NumberFormatException ex){pl.getLogger().severe("Invalid value: "+parts[1]);}
+ catch(IllegalArgumentException ex){
+ pl.getLogger().severe("Unknown entity type: "+parts[0]);
}
}
}
+ static long timeSinceLastPlayerDamage(Entity entity){
+ long lastDamage = entity.hasMetadata("PlayerDamage") ? entity.getMetadata("PlayerDamage").get(0).asLong() : 0;
+ return System.currentTimeMillis() - lastDamage;
+ }
+ static double getSpawnCauseModifier(Entity e){
+ return e.hasMetadata("SpawnReason") ? e.getMetadata("SpawnReason").get(0).asDouble() : 1D;
+ }
+
@EventHandler
public void entityDeathEvent(EntityDeathEvent evt){
- double rawDropChance, dropChance;
- double lootBonus = 0D, toolBonus = 0D;
- double spawnCauseModifier = evt.getEntity().hasMetadata("SpawnReason") ?
- evt.getEntity().getMetadata("SpawnReason").get(0).asDouble() : 1D;
-
- if(playerHeadsOnly && evt.getEntity() instanceof Player == false) return;
-
+ LivingEntity victim = evt.getEntity();
+ if(playerHeadsOnly && victim instanceof Player == false) return;
Entity killer = null;
- EntityDamageEvent lastDamage = evt.getEntity().getLastDamageCause();
+ boolean killedByChargedCreeper = false, alwaysBeheadPerm = false;
+ double lootingBonus = 0D, weaponBonus = 0D;
+ EntityDamageEvent lastDamage = victim.getLastDamageCause();
if(lastDamage != null && lastDamage instanceof EntityDamageByEntityEvent){
killer = ((EntityDamageByEntityEvent)lastDamage).getDamager();
-
- if(chargedCreepers && killer instanceof Creeper && ((Creeper)killer).isPowered()) dropChance = 1D;
- else if(playerKillsOnly && killer instanceof Player == false) return;
- else if(!killer.hasPermission("evp.dropheads.canbehead")) return;
- else{
- ItemStack heldItem = null;
- if(killer instanceof LivingEntity){
- heldItem = ((LivingEntity)killer).getEquipment().getItemInMainHand();
- if(heldItem != null){
- lootBonus = heldItem.getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS)*lootingBonus;
- if(toolBonuses.containsKey(heldItem.getType())) toolBonus = toolBonuses.get(heldItem.getType());
- }
+ if(killer instanceof Creeper && ((Creeper)killer).isPowered()) killedByChargedCreeper = true;
+ //"else if" - Overrides "player-kills-only" - intentional design
+ else if(playerKillsOnly && killer instanceof Player == false){
+ if(allowProjectileKills && killer instanceof Projectile
+ && ((Projectile)killer).getShooter() instanceof Player);
+ else if(allowIndirectKills && timeSinceLastPlayerDamage(victim) < 60*1000);
+ else return;
+ }
+ if(!killer.hasPermission("dropheads.canbehead")) return;
+ alwaysBeheadPerm = killer.hasPermission("dropheads.alwaysbehead");
+
+ ItemStack itemInHand = null;
+ if(killer instanceof LivingEntity){
+ itemInHand = ((LivingEntity)killer).getEquipment().getItemInMainHand();
+ if(itemInHand != null && !noLootingEffectMobs.contains(victim.getType())){
+ lootingBonus = itemInHand.getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS)*0.01D;
+ weaponBonus = toolBonuses.getOrDefault(itemInHand.getType(), 0D);
}
- if(!mustUseTools.isEmpty() && (heldItem == null || !mustUseTools.contains(heldItem.getType()))) return;
-
- if(killer.hasPermission("evp.dropheads.alwaysbehead")) dropChance = spawnCauseModifier = 1D;
- else dropChance = mobChances.containsKey(evt.getEntityType()) ? mobChances.get(evt.getEntityType()) : 0D;
}
+ if(!mustUseTools.isEmpty() && (itemInHand == null || !mustUseTools.contains(itemInHand.getType()))) return;
}
- else if(playerKillsOnly) return;
- else dropChance = mobChances.containsKey(evt.getEntityType())
- ? mobChances.get(evt.getEntityType()) : DEFAULT_CHANCE;
- rawDropChance = (dropChance *= spawnCauseModifier);
+ double rawDropChance = mobChances.getOrDefault(victim.getType(), DEFAULT_CHANCE);
+ double spawnCauseMod = getSpawnCauseModifier(victim);
+ double dropChanceWithSpawnMod =
+ ((CHARGED_CREEPER_DROPS && killedByChargedCreeper) || alwaysBeheadPerm) ? 1D :
+ Math.min(rawDropChance*spawnCauseMod, 1D);
+ double dropChance = dropChanceWithSpawnMod;
if(useTaylorModifiers){
- toolBonus = Math.pow(2D, toolBonus*dropChance)-1D;
- lootBonus = Math.pow(2D, lootBonus*dropChance)-1D;
- dropChance += (lootBonus == 0D ? 0D : (lootBonus*(1D-dropChance))/(lootBonus+1D));//apply modifiers
- dropChance += (toolBonus == 0D ? 0D : (toolBonus*(1D-dropChance))/(toolBonus+1D));
+ lootingBonus = Math.pow(2D, 40*lootingBonus*dropChance)-1D;
+ if(lootingBonus > 0D) dropChance += (lootingBonus*(1D-dropChance))/(lootingBonus+1D);//apply modifiers
}
- else dropChance += lootBonus*dropChance + toolBonus*dropChance;
+ else dropChance += lootingBonus*dropChance;
+ dropChance += weaponBonus*dropChance;
+ dropChance = Math.min(dropChance, 1D);
- if(rand.nextDouble() < dropChance){
- evt.getEntity().getWorld().dropItem(evt.getEntity().getLocation(), pl.getAPI().getHead(evt.getEntity()));
+ //Remove vanilla head drops (TODO: test this)
+ Iterator it = evt.getDrops().iterator();
+ while(it.hasNext()) if(EvUtils.isHead(it.next().getType())) it.remove();
- pl.getLogger().info("Head dropped!\nDrop chance before tool modifiers: "+rawDropChance+
- "\nDrop chance after tool modifiers: "+dropChance+
- "\nMob killed: "+evt.getEntityType().name());
+ if(rand.nextDouble() < dropChance){
+ victim.getWorld().dropItem(victim.getLocation(), pl.getAPI().getHead(victim));
+ if(DEBUG_MODE){
+ pl.getLogger().info("Dropped Head: "+victim.getType().name()
+ +"\nRaw chance: "+rawDropChance
+ +", SpawnReason Modifier: "+spawnCauseMod
+ +", Looting Bonus: "+lootingBonus+", Weapon Bonus: "+weaponBonus
+ +", Charged Creeper: "+killedByChargedCreeper+", Always-Behead Perm: "+alwaysBeheadPerm
+ +", Final drop chance: "+dropChance);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/net/evmodder/DropHeads/listeners/EntitySpawnListener.java b/src/net/evmodder/DropHeads/listeners/EntitySpawnListener.java
index e766927..06e4a2c 100644
--- a/src/net/evmodder/DropHeads/listeners/EntitySpawnListener.java
+++ b/src/net/evmodder/DropHeads/listeners/EntitySpawnListener.java
@@ -46,4 +46,4 @@ public void entitySpawnEvent(CreatureSpawnEvent evt){
}
}
}
-}
+}
\ No newline at end of file
diff --git a/src/net/evmodder/DropHeads/listeners/ItemDropListener.java b/src/net/evmodder/DropHeads/listeners/ItemDropListener.java
index e894aaa..294d5c7 100644
--- a/src/net/evmodder/DropHeads/listeners/ItemDropListener.java
+++ b/src/net/evmodder/DropHeads/listeners/ItemDropListener.java
@@ -3,6 +3,8 @@
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.ItemSpawnEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import com.mojang.authlib.GameProfile;
import net.evmodder.DropHeads.DropHeads;
@@ -10,15 +12,27 @@
import net.evmodder.EvLib.EvUtils;
public class ItemDropListener implements Listener{
+ final boolean FORCE_RENAME;
+ public ItemDropListener(){
+ FORCE_RENAME = DropHeads.getPlugin().getConfig().getBoolean("refresh-item-names", false);
+ }
+
@EventHandler
public void onBarf(ItemSpawnEvent evt){
if(evt.isCancelled() || !EvUtils.isPlayerHead(evt.getEntity().getItemStack().getType())
|| !evt.getEntity().getItemStack().hasItemMeta()) return;
SkullMeta meta = (SkullMeta) evt.getEntity().getItemStack().getItemMeta();
+ String name = !FORCE_RENAME && meta.hasDisplayName() ? meta.getDisplayName() : null;
GameProfile profile = HeadUtils.getGameProfile(meta);
if(profile != null){
- evt.getEntity().setItemStack(DropHeads.getPlugin().getAPI().getHead(profile));
+ ItemStack refreshedItem = DropHeads.getPlugin().getAPI().getHead(profile);
+ if(name != null){
+ ItemMeta newMeta = refreshedItem.getItemMeta();
+ newMeta.setDisplayName(name);
+ refreshedItem.setItemMeta(newMeta);
+ }
+ evt.getEntity().setItemStack(refreshedItem);
}
}
}
\ No newline at end of file