Wither Config allows you to adjust the Wither's stats and behavior for a tailored boss experience.
at 1.0 136 lines 6.0 kB view raw
1package dev.redstudio.witherconfig.mixin; 2 3import dev.redstudio.witherconfig.config.WitherConfigConfig; 4import net.minecraft.block.state.IBlockState; 5import net.minecraft.entity.Entity; 6import net.minecraft.entity.boss.EntityWither; 7import net.minecraft.entity.monster.EntityMob; 8import net.minecraft.entity.player.EntityPlayer; 9import net.minecraft.util.math.BlockPos; 10import net.minecraft.util.math.MathHelper; 11import net.minecraft.world.World; 12import net.minecraftforge.event.ForgeEventFactory; 13import org.spongepowered.asm.mixin.Mixin; 14import org.spongepowered.asm.mixin.Shadow; 15import org.spongepowered.asm.mixin.Unique; 16import org.spongepowered.asm.mixin.injection.At; 17import org.spongepowered.asm.mixin.injection.Inject; 18import org.spongepowered.asm.mixin.injection.ModifyArg; 19import org.spongepowered.asm.mixin.injection.Redirect; 20import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 21 22/** 23 * @author Luna Lage (Desoroxxx) 24 * @since 1 25 */ 26@Mixin(EntityWither.class) 27public abstract class EntityWitherMixin extends EntityMob { 28 29 @Shadow public abstract int getWatchedTargetId(final int head); 30 31 @Shadow public abstract boolean isArmored(); 32 33 @Shadow private int blockBreakCounter; 34 35 private EntityWitherMixin(final World world) { 36 super(world); 37 } 38 39 @ModifyArg(method = "applyEntityAttributes", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/ai/attributes/IAttributeInstance;setBaseValue(D)V", ordinal = 0)) 40 private double changeMaxHealth(final double original) { 41 return WitherConfigConfig.common.maxHealth; 42 } 43 44 @ModifyArg(method = "applyEntityAttributes", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/ai/attributes/IAttributeInstance;setBaseValue(D)V", ordinal = 1)) 45 private double changeMovementSpeed(final double original) { 46 return WitherConfigConfig.common.movementSpeed; 47 } 48 49 @ModifyArg(method = "applyEntityAttributes", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/ai/attributes/IAttributeInstance;setBaseValue(D)V", ordinal = 2)) 50 private double changeFollowRange(final double original) { 51 return WitherConfigConfig.common.followRange; 52 } 53 54 @ModifyArg(method = "applyEntityAttributes", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/ai/attributes/IAttributeInstance;setBaseValue(D)V", ordinal = 3)) 55 private double changeArmor(final double original) { 56 return WitherConfigConfig.common.armor; 57 } 58 59 @ModifyArg(method = "ignite", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/boss/EntityWither;setInvulTime(I)V")) 60 private int changeSummonSequenceLength(final int original) { 61 return WitherConfigConfig.common.summonSequence.length; 62 } 63 64 @ModifyArg(method = "updateAITasks", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;newExplosion(Lnet/minecraft/entity/Entity;DDDFZZ)Lnet/minecraft/world/Explosion;")) 65 private float changeEndExplosionStrength(final float original) { 66 return WitherConfigConfig.common.summonSequence.endExplosionStrength; 67 } 68 69 @Redirect(method = "onLivingUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/boss/EntityWither;getWatchedTargetId(I)I", ordinal = 0)) 70 private int disableVanillaTargetFollowingLogic(final EntityWither instance, int head) { 71 return 0; 72 } 73 74 @Inject(method = "onLivingUpdate", at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;isRemote:Z", shift = At.Shift.AFTER)) 75 private void newTargetFollowingLogic(final CallbackInfo callbackInfo) { 76 if (world.isRemote || getWatchedTargetId(0) <= 0) 77 return; 78 79 final Entity target = world.getEntityByID(getWatchedTargetId(0)); 80 81 if (target == null) 82 return; 83 84 if (target instanceof EntityPlayer && WitherConfigConfig.common.breakBlocksWhenTargetingPlayer) 85 wither_Config$destroyBlocks(); 86 87 final double movementSpeed = WitherConfigConfig.common.movementSpeed; 88 89 if (posY < target.posY || !isArmored() && posY < target.posY + WitherConfigConfig.common.unarmoredFlyHeight) { 90 if (motionY < 0) 91 motionY = 0; 92 93 motionY += (0.5 - motionY) * movementSpeed; 94 } 95 96 final double deltaX = target.posX - posX; 97 final double deltaZ = target.posZ - posZ; 98 final double distanceToTarget = Math.sqrt(deltaX * deltaX + deltaZ * deltaZ); 99 100 if (distanceToTarget > WitherConfigConfig.common.followDistance) { 101 motionX += (deltaX / distanceToTarget * 0.5 - motionX) * movementSpeed; 102 motionZ += (deltaZ / distanceToTarget * 0.5 - motionZ) * movementSpeed; 103 } 104 } 105 106 @Unique 107 private void wither_Config$destroyBlocks() { 108 if (net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this)) { 109 final int x = MathHelper.floor(posX); 110 final int y = MathHelper.floor(posY); 111 final int z = MathHelper.floor(posZ); 112 113 boolean flag = false; 114 115 for (int xOffset = -1; xOffset <= 1; ++xOffset) { 116 for (int zOffset = -1; zOffset <= 1; ++zOffset) { 117 for (int yOffset = 0; yOffset <= 4; ++yOffset) { 118 final int currentX = x + xOffset; 119 final int currentY = y + yOffset; 120 final int currentZ = z + zOffset; 121 122 final BlockPos blockPos = new BlockPos(currentX, currentY, currentZ); 123 final IBlockState blockState = this.world.getBlockState(blockPos); 124 125 if (blockState.getBlock().canEntityDestroy(blockState, world, blockPos, this) && ForgeEventFactory.onEntityDestroyBlock(this, blockPos, blockState)) 126 flag = this.world.destroyBlock(blockPos, true) || flag; 127 } 128 } 129 } 130 131 if (flag) { 132 this.world.playEvent(null, 1022, new BlockPos(this), 0); 133 } 134 } 135 } 136}