/** Copyright (C) <2015> <coolAlias> This file is part of coolAlias' Zelda Sword Skills Minecraft Mod; as such, 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 <http://www.gnu.org/licenses/>. */ package zeldaswordskills.entity; import java.lang.reflect.Field; import java.lang.reflect.Method; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraftforge.fml.relauncher.ReflectionHelper; import zeldaswordskills.ZSSMain; public class DirtyEntityAccessor { /** Accessible reference to {@code EntityLivingBase#damageEntity} */ private static Method damageEntity; /** Accessible reference to {@code EntityLivingBase#applyPotionDamageCalculations */ private static Method applyPotionDamageCalculations; /** Accessible reference to {@code Entity#setSize */ private static Method setSize; /** Accessible reference to {@code EntityLiving#experienceValue */ private static Field experienceValue; /** Damages the target for the amount of damage using the vanilla method; posts LivingHurtEvent */ public static void damageEntity(EntityLivingBase target, DamageSource source, float amount) { if (damageEntity == null) { damageEntity = ReflectionHelper.findMethod(EntityLivingBase.class, target, new String[]{"func_70665_d","damageEntity"}, DamageSource.class, float.class); } try { damageEntity.invoke(target, source, amount); } catch (Exception e) { e.printStackTrace(); } } /** * Returns the amount of damage the entity will receive after armor and potions are taken into account */ public static float getModifiedDamage(EntityLivingBase entity, DamageSource source, float amount) { if (applyPotionDamageCalculations == null) { applyPotionDamageCalculations = ReflectionHelper.findMethod(EntityLivingBase.class, entity, new String[]{"func_70672_c","applyPotionDamageCalculations"}, DamageSource.class, float.class); } // Don't want to actually damage the entity's armor at this point, so // reproduce parts of EntityLivingBase#applyArmorCalculations here: if (!source.isUnblockable()) { int armor = 25 - entity.getTotalArmorValue(); amount = (amount * (float) armor) / 25.0F; } try { applyPotionDamageCalculations.invoke(entity, source, amount); } catch (Exception e) { e.printStackTrace(); } return Math.max(amount - entity.getAbsorptionAmount(), 0.0F); } /** Sets or adds to the amount of xp the entity will drop when killed */ public static void setLivingXp(EntityLiving entity, int xp, boolean add) { if (experienceValue == null) { experienceValue = ReflectionHelper.findField(EntityLiving.class, "field_70728_aV", "experienceValue"); } try { int value = experienceValue.getInt(entity); experienceValue.set(entity, (add ? value + xp : xp)); } catch (Exception e) { e.printStackTrace(); } } /** * Sets an entity's size; stores original size in entity's extended data * @param width stored as "origWidth" * @param height stored as "origHeight" */ public static void setSize(Entity entity, float width, float height) { if (setSize == null) { setSize = ReflectionHelper.findMethod(Entity.class, entity, new String[]{"func_70105_a","setSize"}, float.class, float.class); } NBTTagCompound compound = entity.getEntityData(); compound.setFloat("origWidth", entity.width); compound.setFloat("origHeight", entity.height); try { setSize.invoke(entity, width, height); } catch (Exception e) { e.printStackTrace(); } if (entity instanceof EntityPlayer) { ((EntityPlayer) entity).eyeHeight = 0.85F * height; } } /** * Restores entity to original size; must have first called {@link #setSize(Entity, float, float) setSize} */ public static void restoreOriginalSize(Entity entity) { NBTTagCompound compound = entity.getEntityData(); if (compound.hasKey("origWidth") && compound.hasKey("origHeight")) { if (setSize == null) { setSize = ReflectionHelper.findMethod(Entity.class, entity, new String[]{"func_70105_a","setSize"}, float.class, float.class); } try { setSize.invoke(entity, compound.getFloat("origWidth"), compound.getFloat("origHeight")); } catch (Exception e) { e.printStackTrace(); } if (entity instanceof EntityPlayer) { ((EntityPlayer) entity).eyeHeight = ((EntityPlayer) entity).getDefaultEyeHeight(); } } else { ZSSMain.logger.warn("Attempted to restore original size without any available data"); } } }