-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
39 additions
and
135 deletions.
There are no files selected for viewing
174 changes: 39 additions & 135 deletions
174
...ver/src/main/java/com/mohistmc/banner/mixin/world/entity/boss/wither/MixinWitherBoss.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,165 +1,69 @@ | ||
package com.mohistmc.banner.mixin.world.entity.boss.wither; | ||
|
||
import java.util.List; | ||
import io.izzel.arclight.mixin.Decorate; | ||
import io.izzel.arclight.mixin.DecorationOps; | ||
import net.minecraft.core.BlockPos; | ||
import net.minecraft.server.level.ServerBossEvent; | ||
import net.minecraft.util.Mth; | ||
import net.minecraft.world.Difficulty; | ||
import net.minecraft.world.entity.Entity; | ||
import net.minecraft.world.entity.EntityType; | ||
import net.minecraft.world.entity.LivingEntity; | ||
import net.minecraft.world.entity.ai.targeting.TargetingConditions; | ||
import net.minecraft.world.entity.boss.wither.WitherBoss; | ||
import net.minecraft.world.entity.monster.Monster; | ||
import net.minecraft.world.level.GameRules; | ||
import net.minecraft.world.level.Explosion; | ||
import net.minecraft.world.level.Level; | ||
import net.minecraft.world.level.block.Blocks; | ||
import net.minecraft.world.level.block.state.BlockState; | ||
import org.bukkit.Bukkit; | ||
import org.bukkit.craftbukkit.v1_20_R1.event.CraftEventFactory; | ||
import org.bukkit.event.entity.EntityRegainHealthEvent; | ||
import org.bukkit.event.entity.EntityTargetEvent; | ||
import org.bukkit.event.entity.ExplosionPrimeEvent; | ||
import org.spongepowered.asm.mixin.Final; | ||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.Overwrite; | ||
import org.spongepowered.asm.mixin.Shadow; | ||
import org.spongepowered.asm.mixin.injection.At; | ||
import org.spongepowered.asm.mixin.injection.Inject; | ||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | ||
|
||
@Mixin(WitherBoss.class) | ||
public abstract class MixinWitherBoss extends Monster { | ||
|
||
|
||
// @formatter:off | ||
@Shadow public abstract int getInvulnerableTicks(); | ||
@Shadow public abstract void setInvulnerableTicks(int time); | ||
@Shadow @Final private int[] nextHeadUpdate; | ||
@Shadow @Final private int[] idleHeadUpdates; | ||
@Shadow protected abstract void performRangedAttack(int head, double x, double y, double z, boolean invulnerable); | ||
@Shadow public abstract int getAlternativeTarget(int head); | ||
@Shadow public abstract void setAlternativeTarget(int targetOffset, int newId); | ||
@Shadow protected abstract void performRangedAttack(int head, LivingEntity target); | ||
@Shadow @Final private static TargetingConditions TARGETING_CONDITIONS; | ||
@Shadow private int destroyBlocksTick; | ||
@Shadow @Final public ServerBossEvent bossEvent; | ||
@Shadow public static boolean canDestroy(BlockState state) {return false;} | ||
// @formatter:on | ||
|
||
protected MixinWitherBoss(EntityType<? extends Monster> entityType, Level level) { | ||
super(entityType, level); | ||
} | ||
|
||
/** | ||
* @author wdog5 | ||
* @reason | ||
*/ | ||
@Overwrite | ||
protected void customServerAiStep() { | ||
if (this.getInvulnerableTicks() > 0) { | ||
int k1 = this.getInvulnerableTicks() - 1; | ||
this.bossEvent.setProgress(1.0F - (float) k1 / 220.0F); | ||
if (k1 <= 0) { | ||
ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 7.0F, false); | ||
Bukkit.getPluginManager().callEvent(event); | ||
if (!event.isCancelled()) { | ||
this.level().explode((WitherBoss) (Object) this, this.getX(), this.getEyeY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); | ||
} | ||
if (!this.isSilent()) { | ||
this.level().globalLevelEvent(1023, this.blockPosition(), 0); | ||
} | ||
} | ||
|
||
this.setInvulnerableTicks(k1); | ||
if (this.tickCount % 10 == 0) { | ||
pushHealReason(EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); | ||
this.heal(10.0F); | ||
} | ||
|
||
} else { | ||
super.customServerAiStep(); | ||
|
||
for (int i = 1; i < 3; ++i) { | ||
if (this.tickCount >= this.nextHeadUpdate[i - 1]) { | ||
this.nextHeadUpdate[i - 1] = this.tickCount + 10 + this.random.nextInt(10); | ||
if (this.level().getDifficulty() == Difficulty.NORMAL || this.level().getDifficulty() == Difficulty.HARD) { | ||
int i3 = i - 1; | ||
int j3 = this.idleHeadUpdates[i - 1]; | ||
this.idleHeadUpdates[i3] = this.idleHeadUpdates[i - 1] + 1; | ||
if (j3 > 15) { | ||
double d0 = Mth.nextDouble(this.random, this.getX() - 10.0D, this.getX() + 10.0D); | ||
double d1 = Mth.nextDouble(this.random, this.getY() - 5.0D, this.getY() + 5.0D); | ||
double d2 = Mth.nextDouble(this.random, this.getZ() - 10.0D, this.getZ() + 10.0D); | ||
this.performRangedAttack(i + 1, d0, d1, d2, true); | ||
this.idleHeadUpdates[i - 1] = 0; | ||
} | ||
} | ||
@Decorate(method = "customServerAiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;explode(Lnet/minecraft/world/entity/Entity;DDDFZLnet/minecraft/world/level/Level$ExplosionInteraction;)Lnet/minecraft/world/level/Explosion;")) | ||
private Explosion banner$fireExplosionPrimeEvent(Level instance, Entity source, double x, double y, double z, float radius, boolean fire, Level.ExplosionInteraction explosionInteraction) throws Throwable { | ||
ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 7.0F, false); | ||
instance.getCraftServer().getPluginManager().callEvent(event); | ||
|
||
int l1 = this.getAlternativeTarget(i); | ||
if (l1 > 0) { | ||
LivingEntity livingentity = (LivingEntity) this.level().getEntity(l1); | ||
if (livingentity != null && this.canAttack(livingentity) && !(this.distanceToSqr(livingentity) > 900.0D) && this.hasLineOfSight(livingentity)) { | ||
this.performRangedAttack(i + 1, livingentity); | ||
this.nextHeadUpdate[i - 1] = this.tickCount + 40 + this.random.nextInt(20); | ||
this.idleHeadUpdates[i - 1] = 0; | ||
} else { | ||
if (CraftEventFactory.callEntityTargetLivingEvent((WitherBoss) (Object) this, livingentity, EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) | ||
continue; | ||
this.setAlternativeTarget(i, 0); | ||
} | ||
} else { | ||
List<LivingEntity> list = this.level().getNearbyEntities(LivingEntity.class, TARGETING_CONDITIONS, (WitherBoss) (Object) this, this.getBoundingBox().inflate(20.0D, 8.0D, 20.0D)); | ||
if (!list.isEmpty()) { | ||
LivingEntity livingentity1 = list.get(this.random.nextInt(list.size())); | ||
if (CraftEventFactory.callEntityTargetLivingEvent((WitherBoss) (Object) this, livingentity1, EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) | ||
continue; | ||
this.setAlternativeTarget(i, livingentity1.getId()); | ||
} | ||
} | ||
} | ||
} | ||
if (!event.isCancelled()) { | ||
return (Explosion) DecorationOps.callsite().invoke(instance, source, x, y, z, event.getRadius(), event.getFire(), explosionInteraction); | ||
} | ||
// CraftBukkit end | ||
return null; | ||
} | ||
|
||
if (this.getTarget() != null) { | ||
this.setAlternativeTarget(0, this.getTarget().getId()); | ||
} else { | ||
this.setAlternativeTarget(0, 0); | ||
@Decorate(method = "customServerAiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/boss/wither/WitherBoss;setAlternativeTarget(II)V")) | ||
private void banner$targetLivingEvent(WitherBoss instance, int i, int entityId) throws Throwable { | ||
if (i > 0 && entityId != 0) { | ||
if (CraftEventFactory.callEntityTargetLivingEvent((WitherBoss) (Object) this, (LivingEntity) this.level().getEntity(entityId), EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) { | ||
return; | ||
} | ||
} | ||
DecorationOps.callsite().invoke(instance, i, entityId); | ||
} | ||
|
||
if (this.destroyBlocksTick > 0) { | ||
--this.destroyBlocksTick; | ||
if (this.destroyBlocksTick == 0 && this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { | ||
int j1 = Mth.floor(this.getY()); | ||
int i2 = Mth.floor(this.getX()); | ||
int j2 = Mth.floor(this.getZ()); | ||
boolean flag = false; | ||
|
||
for (int j = -1; j <= 1; ++j) { | ||
for (int k2 = -1; k2 <= 1; ++k2) { | ||
for (int k = 0; k <= 3; ++k) { | ||
int l2 = i2 + j; | ||
int l = j1 + k; | ||
int i1 = j2 + k2; | ||
BlockPos blockpos = new BlockPos(l2, l, i1); | ||
BlockState blockstate = this.level().getBlockState(blockpos); | ||
if (canDestroy(blockstate)) { | ||
if (!CraftEventFactory.callEntityChangeBlockEvent((WitherBoss) (Object) this, blockpos, Blocks.AIR.defaultBlockState())) { | ||
continue; | ||
} | ||
flag = this.level().destroyBlock(blockpos, true, (WitherBoss) (Object) this) || flag; | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (flag) { | ||
this.level().levelEvent(null, 1022, this.blockPosition(), 0); | ||
} | ||
} | ||
} | ||
@Decorate(method = "customServerAiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;destroyBlock(Lnet/minecraft/core/BlockPos;ZLnet/minecraft/world/entity/Entity;)Z")) | ||
private boolean banner$damageBlock(Level instance, BlockPos blockPos, boolean b, Entity entity) throws Throwable { | ||
if (!CraftEventFactory.callEntityChangeBlockEvent((WitherBoss) (Object) this, blockPos, Blocks.AIR.defaultBlockState())) { | ||
return false; | ||
} | ||
return (boolean) DecorationOps.callsite().invoke(instance, blockPos, b, entity); | ||
} | ||
|
||
if (this.tickCount % 20 == 0) { | ||
pushHealReason(EntityRegainHealthEvent.RegainReason.REGEN); | ||
this.heal(1.0F); | ||
} | ||
@Inject(method = "customServerAiStep", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/world/entity/boss/wither/WitherBoss;heal(F)V")) | ||
private void banner$healReason(CallbackInfo ci) { | ||
pushHealReason(EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); | ||
} | ||
|
||
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); | ||
} | ||
@Inject(method = "customServerAiStep", at = @At(value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/world/entity/boss/wither/WitherBoss;heal(F)V")) | ||
private void banner$healReason0(CallbackInfo ci) { | ||
pushHealReason(EntityRegainHealthEvent.RegainReason.REGEN); | ||
} | ||
} |