Skip to content

Commit

Permalink
Fixed #326
Browse files Browse the repository at this point in the history
  • Loading branch information
wdog5734 committed Oct 17, 2024
1 parent d8a1fcb commit 3055009
Showing 1 changed file with 39 additions and 135 deletions.
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);
}
}

0 comments on commit 3055009

Please sign in to comment.