/*******************************************************************************
* Copyright 2014 Tobias Welther
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package de.tobiyas.racesandclasses.util.bukkit.versioning.compatibility;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.bukkit.GameMode;
import org.bukkit.entity.Damageable;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import de.tobiyas.racesandclasses.RacesAndClasses;
import de.tobiyas.racesandclasses.eventprocessing.events.entitydamage.EntityHealEvent;
import de.tobiyas.racesandclasses.util.bukkit.versioning.CertainVersionChecker;
public class CompatibilityModifier {
public static class EntityDamage{
/**
* Returns a safe value of the damage from an {@link EntityDamageEvent}.
*
* @param event
* @return
*/
public static double safeGetDamage(EntityDamageEvent event){
if(CertainVersionChecker.isAbove1_6()){
return event.getDamage();
}else{
try{
Method method = EntityDamageEvent.class.getMethod("getDamage");
int value = (Integer) method.invoke(event);
return value;
}catch(Exception exp){
return 1;
}
}
}
/**
* Safely sets the damage to the {@link EntityDamageEvent}
*
* @param damage to set
* @param event to set in
*/
public static void safeSetDamage(double damage, EntityDamageEvent event){
if(CertainVersionChecker.isAbove1_6()){
event.setDamage(damage);
}else{
try{
Method method = EntityDamageEvent.class.getMethod("setDamage", int.class);
int intValue = (int) damage;
method.invoke(event, intValue);
}catch(Exception exp){
}
}
}
/**
* Creates an Entity Damage by entity event safely.
*
* @param entity
* @param cause
* @param damage
* @return
*/
@SuppressWarnings("deprecation")
public static EntityDamageEvent safeCreateEvent(Entity entity, DamageCause cause, double damage){
if(CertainVersionChecker.isAbove1_6()){
return new EntityDamageEvent(entity, cause, damage);
}else{
int roundedDamage = Math.round((float) damage);
return new EntityDamageEvent(entity, cause, roundedDamage);
}
}
}
public static class EntityDamageByEntity{
/**
* Creates an Entity Damage by entity event safely.
*
* @param entity
* @param cause
* @param damage
* @return
*/
@SuppressWarnings("deprecation")
public static EntityDamageByEntityEvent safeCreateEvent(Entity damager, Entity target, DamageCause cause, double damage){
if(CertainVersionChecker.isAbove1_6()){
return new EntityDamageByEntityEvent(damager, target, cause, damage);
}else{
try{
int roundedDamage = Math.round((float) damage);
return new EntityDamageByEntityEvent(damager, target, cause, roundedDamage);
}catch(Exception exp){
return null;
}
}
}
}
public static class BukkitPlayer{
/**
* Checks if the Player is fully healed.
*
* @param player to check
*
* @return true if the player has full Health, false otherwise.
*/
public static boolean isFullyHealed(Player player){
if(player == null) return false;
return Math.abs(safeGetMaxHealth(player) - safeGetHealth(player)) < 0.01;
}
/**
* Sets the max life of a Player safely to the correct value
*
* @param maxLife
* @param player
*/
public static void safeSetMaxHealth(double maxHealth, Player player){
if(maxHealth <= 0) return;
if(player == null) return;
if(safeGetHealth(player) < maxHealth){
safeSetHealth(maxHealth, player);
}
if(CertainVersionChecker.isAbove1_6()){
try{ player.setMaxHealth(maxHealth); }catch(Throwable exp){}
}else{
try{
Method method = Damageable.class.getMethod("setMaxHealth", int.class);
int intHealthValue = (int) maxHealth;
method.invoke(player, intHealthValue);
}catch(Exception exp){
}
}
}
/**
* Returns the Player's max health.
*
* @param player
*/
public static double safeGetMaxHealth(Player player){
if(player == null) return 0;
if(CertainVersionChecker.isAbove1_6()){
return player.getMaxHealth();
}else{
try{
Method method = Damageable.class.getMethod("getMaxHealth");
int maxHealth = (Integer) method.invoke(player);
return maxHealth;
}catch(Exception exp){
return 20;
}
}
}
/**
* Returns the Player's current health.
*
* @param player
*/
public static double safeGetHealth(Player player){
if(player == null) return 0;
if(CertainVersionChecker.isAbove1_6()){
return player.getHealth();
}else{
try{
Method method = Damageable.class.getMethod("getHealth");
int maxHealth = (Integer) method.invoke(player);
return maxHealth;
}catch(Exception exp){
return 20;
}
}
}
/**
* Sets the current health of a Player to the correct value
* <br>The health is set is MAX the max health of a Player.
*
* @param newHealth the health to set to
* @param player the player to set the health
*/
public static void safeSetHealth(double newHealth, Player player) {
if(player == null) return;
if(newHealth > safeGetMaxHealth(player)){
newHealth = safeGetMaxHealth(player);
}
if(CertainVersionChecker.isAbove1_6()){
try { player.setHealth(newHealth); }catch(Throwable exp){}
}else{
try{
Method method = Damageable.class.getMethod("setHealth", int.class);
int intNewHealth = (int) newHealth;
method.invoke(player, intNewHealth);
}catch(Exception exp){}
}
}
/**
* Damages a Player by a certain Value
*
* @param damage the damage to do
* @param player the player to damage
*/
public static void safeDamage(double damage, Player player) {
if(player == null) return;
//if in creative, there is no
if(player.getGameMode() == GameMode.CREATIVE) return;
double oldHealth = safeGetHealth(player);
double newHealth = oldHealth - damage;
safeSetHealth(newHealth, player);
}
/**
* Damages a Player by a certain Value.
* <br>This calls player.damage().
* <br>This triggers a Damage event.
*
* @param damage the damage to do
* @param player the player to damage
*/
public static void safeDamageWithEvent(double damage, Player player) {
if(player == null) return;
//if in creative, there is no
if(player.getGameMode() == GameMode.CREATIVE) return;
if(CertainVersionChecker.isAbove1_6()){
try { player.damage(damage); }catch(Throwable exp){}
}else{
try{
Method method = Damageable.class.getMethod("damage", int.class);
int intNewHealth = (int) damage;
method.invoke(player, intNewHealth);
}catch(Exception exp){}
}
}
/**
* Heals a Player by a certain Value
*
* @param healAmount the healing to do
* @param player the player to heal
*/
public static void safeHeal(double healAmount, Player player) {
if(player == null) return;
if(healAmount <= 0) return;
double oldHealth = safeGetHealth(player);
double newHealth = oldHealth + healAmount;
safeSetHealth(newHealth, player);
}
}
public static class EntityHeal{
/**
* Generates a EntityHealEvent regardless of MC version. (1.5 or 1.6)
*
* @param target entity
* @param amount of healing
* @param reason of healing
* @return the generated Event
*/
@SuppressWarnings("deprecation")
public static EntityHealEvent safeGenerate(Entity target, double amount, RegainReason reason){
if(target == null) return null;
if(CertainVersionChecker.isAbove1_6()){
return new EntityHealEvent(target, amount, reason);
}else{
int intAmount = (int) amount;
return new EntityHealEvent(target, intAmount, reason);
}
}
/**
* Sets the Amount to the corresponding value
*
* @param event
* @param amount
*/
public static void safeSetAmount(EntityHealEvent event, double amount){
if(event == null) return;
if(CertainVersionChecker.isAbove1_6()){
event.setAmount(amount);
}else{
try{
Method method = EntityRegainHealthEvent.class.getMethod("setAmount", int.class);
int intAmount = (int) amount;
method.invoke(event, intAmount);
}catch(Exception exp){}
}
}
/**
* Gets the amount safely of an {@link EntityHealEvent}
*
* @param event
* @return
*/
public static double safeGetAmount(EntityHealEvent event){
if(event == null) return 0;
if(CertainVersionChecker.isAbove1_6()){
return event.getAmount();
}else{
try{
Method method = EntityRegainHealthEvent.class.getMethod("getAmount");
return (Double) method.invoke(event);
}catch(Exception exp){
return 0;
}
}
}
}
public static class EntityRegainHealth{
/**
* Sets the Amount to the corresponding value
*
* @param event
* @param amount
*/
public static void safeSetAmount(EntityRegainHealthEvent event, double amount){
if(event == null) return;
if(CertainVersionChecker.isAbove1_6()){
event.setAmount(amount);
}else{
try{
Method method = EntityRegainHealthEvent.class.getMethod("setAmount", int.class);
int intAmount = (int) amount;
method.invoke(event, intAmount);
}catch(Exception exp){}
}
}
/**
* Gets the amount safely of an {@link EntityRegainHealthEvent}
*
* @param event
* @return
*/
public static double safeGetAmount(EntityRegainHealthEvent event){
if(event == null) return 0;
if(CertainVersionChecker.isAbove1_6()){
return event.getAmount();
}else{
try{
Method method = EntityRegainHealthEvent.class.getMethod("getAmount");
return (Double) method.invoke(event);
}catch(Exception exp){
return 0;
}
}
}
}
public static class LivingEntity{
/**
* Does damage to an entity safely to healthVersions.
*
* @param entity to damage
* @param value to do damage
*
* @deprecated try to use {@link #safeDamageEntityByEntity(org.bukkit.entity.LivingEntity, org.bukkit.entity.LivingEntity, double)}
*/
public static void safeDamageEntity(org.bukkit.entity.LivingEntity entity, double value){
if(entity == null) return;
if(CertainVersionChecker.isAbove1_6()){
entity.damage(value);
}else{
int damage = Math.round((float) value);
try{
Method method = org.bukkit.entity.LivingEntity.class.getMethod("damage", Integer.class);
method.invoke(entity, damage);
}catch(Exception exp){}//silent fail
}
}
/**
* Does damage to an entity safely to healthVersions.
*
* @param entity to damage.
* @param damager to use.
* @param value to do damage.
*/
public static void safeDamageEntityByEntity(org.bukkit.entity.LivingEntity entity,
org.bukkit.entity.LivingEntity damager, double value){
if(entity == null) return;
if(CertainVersionChecker.isAbove1_6()){
entity.damage(value, damager);
}else{
int damage = Math.round((float) value);
try{
Method method = org.bukkit.entity.LivingEntity.class.getMethod("damage", Integer.class, Entity.class);
method.invoke(entity, damage, damager);
}catch(Exception exp){}//silent fail
}
}
/**
* Does damage to an entity safely to healthVersions.
*
* @param entity to damage
* @param value to do damage
*/
public static void safeDamageEntityByEntity(org.bukkit.entity.LivingEntity entity,
org.bukkit.entity.LivingEntity damager, double value, DamageCause cause){
if(entity == null) return;
if(CertainVersionChecker.isAbove1_6()){
//This will be auto-removed later!
new DamageEventChangerClass(cause);
entity.damage(value, damager);
}else{
int damage = Math.round((float) value);
try{
Method method = org.bukkit.entity.LivingEntity.class.getMethod("damage", Integer.class, Entity.class);
method.invoke(entity, damage, damager);
}catch(Exception exp){}//silent fail
}
}
private static class DamageEventChangerClass implements Listener{
private final DamageCause cause;
private DamageEventChangerClass(DamageCause cause) {
this.cause = cause;
RacesAndClasses.getPlugin().registerEvents(this);
}
@EventHandler(priority=EventPriority.LOWEST)
public void damage(EntityDamageByEntityEvent event){
try{
Field field = EntityDamageEvent.class.getDeclaredField("cause");
field.setAccessible(true);
field.set(event, cause);
}catch(Throwable exp){ exp.printStackTrace(); }
HandlerList.unregisterAll(this);
}
}
/**
* Does damage to an entity safely to healthVersions.
*
* @param entity to damage
* @param value to do damage
*/
public static void safeHealEntity(org.bukkit.entity.LivingEntity entity, double value){
if(entity == null) return;
if(value < 0 )return;
double maxHealth = safeGetEntityMaxHealth(entity);
double newHealth = safeGetEntityHealth(entity) + value;
safeSetEntityHealth(entity, Math.min(maxHealth, newHealth));
}
/**
* Gets the Current Health of the Entity..
*
* @param entity to check
*/
public static double safeGetEntityHealth(org.bukkit.entity.LivingEntity entity){
if(entity == null) return 0;
if(CertainVersionChecker.isAbove1_6()){
return entity.getHealth();
}else{
try{
Method method = org.bukkit.entity.LivingEntity.class.getMethod("getHealth");
return (Double) method.invoke(entity);
}catch(Exception exp){ return 0; }//silent fail
}
}
/**
* Gets the Current Health of the Entity..
*
* @param entity to check
*/
public static double safeGetEntityMaxHealth(org.bukkit.entity.LivingEntity entity){
if(entity == null) return 0;
if(CertainVersionChecker.isAbove1_6()){
return entity.getMaxHealth();
}else{
try{
Method method = org.bukkit.entity.LivingEntity.class.getMethod("getMaxHealth");
return (Double) method.invoke(entity);
}catch(Exception exp){ return 0; }//silent fail
}
}
/**
* Gets the Current Health of the Entity..
*
* @param entity to check
*/
public static void safeSetEntityMaxHealth(org.bukkit.entity.LivingEntity entity, double value){
if(entity == null) return;
double maxHealth = safeGetEntityMaxHealth(entity);
if(CertainVersionChecker.isAbove1_6()){
entity.setMaxHealth(maxHealth);
}else{
try{
Method method = org.bukkit.entity.LivingEntity.class.getMethod("setHealth", Integer.class);
method.invoke(entity, (int) maxHealth);
}catch(Exception exp){}//silent fail
}
}
/**
* Gets the Current Health of the Entity..
*
* @param entity to check
*/
public static void safeSetEntityHealth(org.bukkit.entity.LivingEntity entity, double value){
if(entity == null) return;
if(value <= 0) return;
if(CertainVersionChecker.isAbove1_6()){
entity.setHealth(value);
}else{
try{
Method method = org.bukkit.entity.LivingEntity.class.getMethod("setHealth", Integer.class);
method.invoke(entity, (int) value);
}catch(Exception exp){}//silent fail
}
}
}
public static class Shooter{
/**
* Finds the shooter of an arrow if any present.
*
* @param arrow the arrow to get the shooter from.
* @return the found Living entity the arrow belongs to or NULL if not found.
*/
public static org.bukkit.entity.LivingEntity getShooter(Projectile projectile){
if(projectile == null) return null;
try{
return (org.bukkit.entity.LivingEntity)projectile.getShooter();
}catch(Throwable exp){
//lets do good old reflections on this.
}
try{
Method method = projectile.getClass().getMethod("getShooter");
return (org.bukkit.entity.LivingEntity) method.invoke(projectile, method);
}catch(Throwable exp){
//well we don't know how to get to the shooter.
}
//nothing worked...
return null;
}
}
}