/*
* ReActions, Minecraft bukkit plugin
* (c)2012-2017, fromgate, fromgate@gmail.com
* http://dev.bukkit.org/server-mods/reactions/
*
* This file is part of ReActions.
*
* ReActions 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.
*
* ReActions 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 ReActions. If not, see <http://www.gnorg/licenses/>.
*
*/
package me.fromgate.reactions.util;
import me.fromgate.reactions.util.message.M;
import org.bukkit.entity.Damageable;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class BukkitCompatibilityFix {
/*
* In latest version of Bukkit API getShooter() method returns Projectile source
* that not available in previous version of Bukkit API.
* This method is returns LivingEntity instead of ProjectileSource
*/
public static LivingEntity getShooter(Projectile projectile) {
if (projectile == null) return null;
try {
Method getShooter = projectile.getClass().getDeclaredMethod("getShooter");
Object shooterObject = getShooter.invoke(projectile);
if (shooterObject != null && shooterObject instanceof LivingEntity) return (LivingEntity) shooterObject;
} catch (Exception e) {
M.logOnce("getShooter", "Method \"getShooter\" is not declared in Projectile class");
}
return null;
}
public static void setItemInHand(Player player, ItemStack item) {
if (player == null) return;
PlayerInventory inv = player.getInventory();
Method setItem = null;
try {
setItem = PlayerInventory.class.getDeclaredMethod("setItemInMainHand", ItemStack.class);
} catch (NoSuchMethodException e) {
// nop
}
if (setItem == null) {
try {
setItem = PlayerInventory.class.getDeclaredMethod("setItemInHand", ItemStack.class);
} catch (Exception e) {
//nop
}
}
try {
setItem.invoke(inv, item);
} catch (Exception e) {
M.logOnce("setItemInHand", "Methods \"setItemInHand\" and \"setItemInMainHand\" are not declared in PlayerInventory class");
}
}
@SuppressWarnings("deprecation")
public static ItemStack getItemInHand(Player player) {
if (player == null) return null;
PlayerInventory inv = player.getInventory();
Method getItem = null;
try {
getItem = PlayerInventory.class.getDeclaredMethod("getItemInMainHand");
} catch (NoSuchMethodException e) {
// nop
}
if (getItem == null) {
try {
getItem = PlayerInventory.class.getDeclaredMethod("getItemInHand", ItemStack.class);
} catch (Exception e) {
//nop
}
}
try {
Object itemObj = getItem.invoke(inv);
if (itemObj != null && itemObj instanceof ItemStack) {
return (ItemStack) itemObj;
}
} catch (Exception e) {
M.logOnce("getItemInHand", "Methods \"getItemInHand\" and \"getItemInMainHand\" are not declared in PlayerInventory class (Old server?!)");
return player.getItemInHand();
}
return null;
}
public static void setItemInHand(LivingEntity entity, ItemStack item) {
if (entity == null) return;
EntityEquipment inv = entity.getEquipment();
Method setItem = null;
try {
setItem = EntityEquipment.class.getDeclaredMethod("setItemInMainHand", ItemStack.class);
} catch (NoSuchMethodException e) {
// nop
}
if (setItem == null) {
try {
setItem = EntityEquipment.class.getDeclaredMethod("setItemInHand", ItemStack.class);
} catch (Exception e) {
//nop
}
}
try {
setItem.invoke(inv, item);
} catch (Exception e) {
M.logOnce("EEsetItemInHand", "Methods \"setItemInHand\" and \"setItemInMainHand\" are not declared in EntityEquipment class");
}
}
public static ItemStack getItemInHand(LivingEntity entity) {
if (entity == null) return null;
EntityEquipment inv = entity.getEquipment();
Method getItem = null;
try {
getItem = EntityEquipment.class.getDeclaredMethod("getItemInMainHand");
} catch (NoSuchMethodException e) {
// nop
}
if (getItem == null) {
try {
getItem = EntityEquipment.class.getDeclaredMethod("getItemInHand", ItemStack.class);
} catch (Exception e) {
//nop
}
}
try {
Object itemObj = getItem.invoke(inv);
if (itemObj != null && itemObj instanceof ItemStack) return (ItemStack) itemObj;
} catch (Exception e) {
M.logOnce("EEgetItemInHand", "Methods \"getItemInHand\" and \"getItemInMainHand\" are not declared in EntityEquipment class");
}
return null;
}
public static void setItemInOffHand(Player player, ItemStack item) {
if (player == null) return;
PlayerInventory inv = player.getInventory();
Method setItem;
try {
setItem = PlayerInventory.class.getDeclaredMethod("setItemInOffHand", ItemStack.class);
setItem.invoke(inv, item);
} catch (Exception e) {
M.logOnce("setItemInOffHand", "Method \"setItemInOffHand\" is not declared in PlayerInventory class");
}
}
public static void setItemInOffHand(LivingEntity entity, ItemStack item) {
if (entity == null) return;
EntityEquipment inv = entity.getEquipment();
Method setItem;
try {
setItem = EntityEquipment.class.getDeclaredMethod("setItemInOffHand", ItemStack.class);
setItem.invoke(inv, item);
} catch (Exception e) {
M.logOnce("EEsetItemInOffHand", "Method \"setItemInOffHand\" is not declared in EntityEquipment class");
}
}
public static ItemStack getItemInOffHand(LivingEntity entity) {
if (entity == null) return null;
EntityEquipment inv = entity.getEquipment();
Method getItem;
try {
getItem = EntityEquipment.class.getDeclaredMethod("getItemInOffHand");
Object itemObj = getItem.invoke(inv);
if (itemObj != null && itemObj instanceof ItemStack) return (ItemStack) itemObj;
} catch (Exception e) {
M.logOnce("EEgetItemInOffHand", "Method \"getItemInOffHand\" is are not declared in EntityEquipment class");
}
return null;
}
public static ItemStack getItemInOffHand(Player player) {
if (player == null) return null;
PlayerInventory inv = player.getInventory();
Method getItem;
try {
getItem = PlayerInventory.class.getDeclaredMethod("getItemInOffHand");
Object itemObj = getItem.invoke(inv);
if (itemObj != null && itemObj instanceof ItemStack) return (ItemStack) itemObj;
} catch (Exception e) {
M.logOnce("getItemInOffHand", "Method \"getItemInOffHand\" is are not declared in PlayerInventory class");
}
return null;
}
/*
* Fix health (double/int) compatibility issue
* Works nice in 1.5.2
*/
public static double getEntityHealth(LivingEntity entity) {
return getDoubleMethod("getHealth", entity, Damageable.class);
}
/*
* Fix health (double/int) compatibility issue
* Works nice in 1.5.2
*/
public static double getEntityMaxHealth(LivingEntity entity) {
return getDoubleMethod("getMaxHealth", entity, Damageable.class);
}
/*
* Fix health (double/int) compatibility issue
* Works nice in 1.5.2
*/
public static void setEntityHealth(LivingEntity entity, double health) {
executeMethodObjectDouble("setHealth", entity, Damageable.class, health);
}
/*
* Fix health (double/int) compatibility issue
* Works nice in 1.5.2
*/
public static void setEntityMaxHealth(LivingEntity entity, double health) {
executeMethodObjectDouble("setMaxHealth", entity, Damageable.class, health);
}
/*
* Fix damage (double/int) compatibility issue
* Works nice in 1.5.2
*/
public static void damageEntity(LivingEntity entity, double damage) {
executeMethodObjectDouble("damage", entity, Damageable.class, damage);
}
/*
* Fix damage (double/int) compatibility issue
* Works nice in 1.5.2
*/
public static void setEventDamage(EntityDamageEvent event, double damage) {
executeMethodObjectDouble("setDamage", event, EntityDamageEvent.class, damage);
}
/*
* Fix damage (double/int) compatibility issue
* Works nice in 1.5.2
*/
public static double getEventDamage(EntityDamageEvent event) {
return getDoubleMethod("getDamage", event, EntityDamageEvent.class);
}
/*
* Fix damage (double/int) compatibility issue
* Works nice in 1.5.2
*/
public static void setItemPickupDelay(Item item, double pickupDelay) {
executeMethodObjectDouble("setPickupDelay", item, Item.class, pickupDelay);
}
/*
* Fix damage (double/int) compatibility issue
* Works nice in 1.5.2
*/
public static double getItemPickupDelay(Item item) {
return getDoubleMethod("getPickupDelay", item, Item.class);
}
/*
* Internal method, using reflections to access double or integer values
*/
private static double getDoubleMethod(String methodName, Object object, Class<?> clazz) {
if (object == null) return 0;
try {
Method method = clazz.getDeclaredMethod(methodName);
Object value = method.invoke(object);
double returnDouble = 0;
if (method.getReturnType().equals(double.class)) returnDouble = (Double) value;
else if (method.getReturnType().equals(int.class)) returnDouble = (double) (Integer) value;
return returnDouble;
} catch (Exception e) {
M.logOnce("BCF" + methodName, "Looks like this version of BukkitAPI totally incompatible with API 1.7.x. Method \"" + methodName + "\" is not declared in " + object.getClass().getCanonicalName());
e.printStackTrace();
}
return 0;
}
/*
* Internal method, using reflections to access double or integer values
*/
private static void executeMethodObjectDouble(String methodName, Object object, Class<?> clazz, double param) {
if (object == null) return;
boolean useInt = false;
Method method;
try {
method = clazz.getDeclaredMethod(methodName, double.class);
} catch (Exception e) {
try {
method = clazz.getDeclaredMethod(methodName, int.class);
useInt = true;
} catch (Exception e2) {
return;
}
}
if (method != null) {
try {
if (useInt) method.invoke(object, (int) param);
else method.invoke(object, (double) param);
} catch (Exception e) {
e.printStackTrace();
}
} else
M.logOnce("BCFix" + methodName, "Looks like this version of BukkitAPI totally incompatible with API 1.7.x. Method \"" + methodName + "\" is not declared in " + object.getClass().getCanonicalName() + " or not working properly");
}
/*
* Create EntityDamageByEntityEvent according to version of Bukkit
* Overrides damage (double/int) compatibility issue
* Works nice with 1.5.2
*/
public static EntityEvent createEntityDamageByEntityEvent(Entity damager, Entity entity, DamageCause damageCause, double damage) {
Class<?> EntityDamageByEntityEvent;
try {
EntityDamageByEntityEvent = Class.forName("org.bukkit.event.entity.EntityDamageByEntityEvent");
} catch (Exception e) {
e.printStackTrace();
return null;
}
Constructor<?> constructor;
boolean useInt = false;
try {
constructor = EntityDamageByEntityEvent.getConstructor(Entity.class, Entity.class, DamageCause.class, double.class);
} catch (Exception e) {
try {
constructor = EntityDamageByEntityEvent.getConstructor(Entity.class, Entity.class, DamageCause.class, int.class);
useInt = true;
} catch (Exception e1) {
M.logOnce("BCFixEntityDamageEvent", "Failed to determine constructor for EntityDamageByEntityEvent");
return null;
}
}
Object event;
try {
if (useInt) event = constructor.newInstance(damager, entity, DamageCause.ENTITY_ATTACK, (int) damage);
else event = constructor.newInstance(damager, entity, DamageCause.ENTITY_ATTACK, damage);
} catch (Exception e) {
M.logOnce("BCFixEntityDamageEvent2", "Failed to initiate EntityDamageByEntityEvent");
return null;
}
return (EntityEvent) event;
}
public static boolean isHandSlot(PlayerInteractEntityEvent event) {
try {
return event.getHand() == EquipmentSlot.HAND;
} catch (NoSuchMethodError ignored) {
}
return true;
}
}