From c81fb8825b983730c2db80bdf8e1ad466c890e38 Mon Sep 17 00:00:00 2001 From: doctor4t <25477005+doctor4t@users.noreply.github.com> Date: Fri, 23 Apr 2021 20:00:10 +0200 Subject: [PATCH] This one's a banger --- README.md | 15 + build.gradle | 2 +- gradle.properties | 8 +- .../mixin/CreeperEntityMixin.java | 58 ++- .../mixin/HostileEntityMixin.java | 32 +- .../mixin/LivingEntityMixin.java | 29 ++ .../mixin/MobEntityMixin.java | 30 ++ .../mixin/ServerWorldMixin.java | 26 ++ .../world/CustomCreeperExplosion.java | 340 ++++++++++++++++++ .../{modid => reactivecreepers}/icon.png | Bin src/main/resources/fabric.mod.json | 2 +- .../resources/reactivecreepers.mixins.json | 5 +- 12 files changed, 512 insertions(+), 35 deletions(-) create mode 100644 README.md create mode 100644 src/main/java/ladysnake/reactivecreepers/mixin/LivingEntityMixin.java create mode 100644 src/main/java/ladysnake/reactivecreepers/mixin/MobEntityMixin.java create mode 100644 src/main/java/ladysnake/reactivecreepers/mixin/ServerWorldMixin.java create mode 100644 src/main/java/ladysnake/reactivecreepers/world/CustomCreeperExplosion.java rename src/main/resources/assets/{modid => reactivecreepers}/icon.png (100%) diff --git a/README.md b/README.md new file mode 100644 index 0000000..e3332b7 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +Features: +- Creepers explode when getting damaged by an explosion +- Creepers ignite when on fire +- Creepers get charged up when damaged by a charged creeper +- Creepers have 4 times the follow / target range +- Creepers spawn at any light level +- Creepers have a randomly reduced fuse time +- Creepers have a 10% chance to expel random flying blocks + - These blocks can have any blockstate in the game + - These blocks deal damage like anvils +- Creepers have a 10% chance to spawn 1 to 10 other creepers with random status effects when exploding +- Creepers don't take fall damage +- Creepers have a 10% chance to spawn charged +- Creepers are twice as fast +- Creeper explosion have a random knockback between normal and five times the Vanilla knockback \ No newline at end of file diff --git a/build.gradle b/build.gradle index f6220cc..c9c600d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '0.2.6-SNAPSHOT' + id 'fabric-loom' version '0.6-SNAPSHOT' id 'maven-publish' } diff --git a/gradle.properties b/gradle.properties index 0c328ec..1dae2b2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,12 +2,12 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties -minecraft_version=20w09a -yarn_mappings=20w09a+build.6 -loader_version=0.7.8+build.186 +minecraft_version=21w16a +yarn_mappings=21w16a+build.4 +loader_version=0.11.3 #Fabric api -fabric_version=0.4.33+build.301-1.16 +fabric_version=0.33.0+1.17 # Mod Properties mod_version = 1.0 diff --git a/src/main/java/ladysnake/reactivecreepers/mixin/CreeperEntityMixin.java b/src/main/java/ladysnake/reactivecreepers/mixin/CreeperEntityMixin.java index e0c8b16..26d8535 100644 --- a/src/main/java/ladysnake/reactivecreepers/mixin/CreeperEntityMixin.java +++ b/src/main/java/ladysnake/reactivecreepers/mixin/CreeperEntityMixin.java @@ -1,26 +1,42 @@ package ladysnake.reactivecreepers.mixin; +import net.fabricmc.fabric.mixin.object.builder.SpawnRestrictionAccessor; import net.minecraft.entity.EntityType; +import net.minecraft.entity.SpawnRestriction; +import net.minecraft.entity.attribute.DefaultAttributeContainer; +import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.mob.CreeperEntity; -import net.minecraft.entity.mob.MobEntityWithAi; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.mob.Monster; +import net.minecraft.util.registry.Registry; import net.minecraft.world.World; 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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(CreeperEntity.class) -public abstract class CreeperEntityMixin extends HostileEntityMixin { - @Shadow protected abstract void explode(); +public abstract class CreeperEntityMixin extends LivingEntityMixin implements Monster { + @Shadow + protected abstract void explode(); - @Shadow public abstract void setIgnited(); + @Shadow + public abstract void ignite(); - @Shadow private int fuseTime; + @Shadow + private int fuseTime; - @Shadow @Final private static TrackedData CHARGED; + @Shadow + @Final + private static TrackedData CHARGED; - protected CreeperEntityMixin(EntityType type, World world) { + protected CreeperEntityMixin(EntityType type, World world) { super(type, world); } @@ -31,18 +47,40 @@ protected float onDamage(DamageSource source, float amount) { this.getDataTracker().set(CHARGED, true); return 1F; } else { - this.fuseTime = 0; - this.setIgnited(); + this.ignite(); return 0.0F; } } + if (source.isFire() && !this.getDataTracker().get(CHARGED)) { - this.setIgnited(); + this.ignite(); + } + + if (source.isFromFalling()) { + return 0; } + return amount; } private boolean shouldCharge(DamageSource source) { return source.getAttacker() instanceof CreeperEntity && source.getAttacker().getDataTracker().get(CHARGED) && !this.getDataTracker().get(CHARGED); } + + // bigger follow range and faster speed + @Inject(method = "createCreeperAttributes", at = @At("RETURN"), cancellable = true) + private static void createCreeperAttributes(CallbackInfoReturnable cir) { + cir.setReturnValue(HostileEntity.createHostileAttributes().add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.5D).add(EntityAttributes.GENERIC_FOLLOW_RANGE, 35.0D)); + } + + @Inject(method = "ignite", at = @At("RETURN")) + public void ignite(CallbackInfo ci) { + this.fuseTime = this.random.nextInt(30); + } + + @Inject(method = "initDataTracker", at = @At("RETURN")) + protected void initDataTracker(CallbackInfo ci) { + this.dataTracker.set(CHARGED, random.nextInt(10) == 0); + } + } diff --git a/src/main/java/ladysnake/reactivecreepers/mixin/HostileEntityMixin.java b/src/main/java/ladysnake/reactivecreepers/mixin/HostileEntityMixin.java index 32a3738..b2d1e37 100644 --- a/src/main/java/ladysnake/reactivecreepers/mixin/HostileEntityMixin.java +++ b/src/main/java/ladysnake/reactivecreepers/mixin/HostileEntityMixin.java @@ -1,30 +1,26 @@ package ladysnake.reactivecreepers.mixin; import net.minecraft.entity.EntityType; -import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.SpawnReason; import net.minecraft.entity.mob.HostileEntity; -import net.minecraft.entity.mob.MobEntityWithAi; -import net.minecraft.entity.mob.Monster; -import net.minecraft.world.World; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.Difficulty; +import net.minecraft.world.ServerWorldAccess; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(HostileEntity.class) -public abstract class HostileEntityMixin extends MobEntityWithAi implements Monster { - protected HostileEntityMixin(EntityType type, World world) { - super(type, world); - } +import java.util.Random; - @ModifyVariable(at = @At(value = "HEAD"), method = "damage", argsOnly = true) - private float damage(float amount, DamageSource source) { - return this.onDamage(source, amount); - } +@Mixin(HostileEntity.class) +public class HostileEntityMixin { - @Unique - protected float onDamage(DamageSource source, float amount) { - return amount; + @Inject(method = "canSpawnInDark", at = @At("RETURN"), cancellable = true) + private static void canSpawnInDark(EntityType type, ServerWorldAccess world, SpawnReason spawnReason, BlockPos pos, Random random, CallbackInfoReturnable cir) { + if (world.getDifficulty() != Difficulty.PEACEFUL && type == EntityType.CREEPER) { + cir.setReturnValue(true); + } } } diff --git a/src/main/java/ladysnake/reactivecreepers/mixin/LivingEntityMixin.java b/src/main/java/ladysnake/reactivecreepers/mixin/LivingEntityMixin.java new file mode 100644 index 0000000..3a08857 --- /dev/null +++ b/src/main/java/ladysnake/reactivecreepers/mixin/LivingEntityMixin.java @@ -0,0 +1,29 @@ +package ladysnake.reactivecreepers.mixin; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(LivingEntity.class) +public abstract class LivingEntityMixin extends Entity { + public LivingEntityMixin(EntityType type, World world) { + super(type, world); + } + + @ModifyVariable(at = @At(value = "HEAD"), method = "damage", argsOnly = true) + private float damage(float amount, DamageSource source) { + return this.onDamage(source, amount); + } + + @Unique + protected float onDamage(DamageSource source, float amount) { + return amount; + } + +} diff --git a/src/main/java/ladysnake/reactivecreepers/mixin/MobEntityMixin.java b/src/main/java/ladysnake/reactivecreepers/mixin/MobEntityMixin.java new file mode 100644 index 0000000..def1205 --- /dev/null +++ b/src/main/java/ladysnake/reactivecreepers/mixin/MobEntityMixin.java @@ -0,0 +1,30 @@ +package ladysnake.reactivecreepers.mixin; + +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.SpawnReason; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.Difficulty; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Random; + +@Mixin(MobEntity.class) +public abstract class MobEntityMixin extends LivingEntity { + protected MobEntityMixin(EntityType entityType, World world) { + super(entityType, world); + } + + @Inject(method = "canMobSpawn", at = @At("HEAD"), cancellable = true) + private static void canMobSpawn(EntityType type, WorldAccess world, SpawnReason spawnReason, BlockPos pos, Random random, CallbackInfoReturnable cir) { + if (world.getDifficulty() != Difficulty.PEACEFUL && type == EntityType.CREEPER) { + cir.setReturnValue(true); + } + } +} diff --git a/src/main/java/ladysnake/reactivecreepers/mixin/ServerWorldMixin.java b/src/main/java/ladysnake/reactivecreepers/mixin/ServerWorldMixin.java new file mode 100644 index 0000000..4be6e8e --- /dev/null +++ b/src/main/java/ladysnake/reactivecreepers/mixin/ServerWorldMixin.java @@ -0,0 +1,26 @@ +package ladysnake.reactivecreepers.mixin; + +import ladysnake.reactivecreepers.world.CustomCreeperExplosion; +import net.minecraft.entity.Entity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.mob.CreeperEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.World; +import net.minecraft.world.explosion.Explosion; +import net.minecraft.world.explosion.ExplosionBehavior; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(ServerWorld.class) +public class ServerWorldMixin { + @ModifyVariable(method = "createExplosion(Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/damage/DamageSource;Lnet/minecraft/world/explosion/ExplosionBehavior;DDDFZLnet/minecraft/world/explosion/Explosion$DestructionType;)Lnet/minecraft/world/explosion/Explosion;", at = @At("STORE")) + private Explosion createExplosion(Explosion explosion, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionBehavior behavior, double x, double y, double z, float power, boolean createFire, Explosion.DestructionType destructionType) { + if (entity instanceof CreeperEntity) { + return new CustomCreeperExplosion((World) (Object) this, entity, damageSource, behavior, x, y, z, power, destructionType); + } else { + return explosion; + } + } +} diff --git a/src/main/java/ladysnake/reactivecreepers/world/CustomCreeperExplosion.java b/src/main/java/ladysnake/reactivecreepers/world/CustomCreeperExplosion.java new file mode 100644 index 0000000..6699590 --- /dev/null +++ b/src/main/java/ladysnake/reactivecreepers/world/CustomCreeperExplosion.java @@ -0,0 +1,340 @@ +package ladysnake.reactivecreepers.world; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.mojang.authlib.properties.Property; +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectListIterator; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.enchantment.ProtectionEnchantment; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.FallingBlockEntity; +import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.TntEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.mob.CreeperEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.fluid.FluidState; +import net.minecraft.item.ItemStack; +import net.minecraft.loot.context.LootContext; +import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.RaycastContext; +import net.minecraft.world.World; +import net.minecraft.world.explosion.EntityExplosionBehavior; +import net.minecraft.world.explosion.Explosion; +import net.minecraft.world.explosion.ExplosionBehavior; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Random; +import java.util.Set; + +public class CustomCreeperExplosion extends Explosion { + private static final ExplosionBehavior field_25818 = new ExplosionBehavior(); + private final Random random; + private final World world; + private final double x; + private final double y; + private final double z; + private final Entity entity; + private final float power; + private final DamageSource damageSource; + private final ExplosionBehavior behavior; + private final List affectedBlocks; + private final Map affectedPlayers; + private final boolean spawnBlocks; + private final boolean spawnCreepers; + + public CustomCreeperExplosion(World world, Entity entity, DamageSource damageSource, ExplosionBehavior explosionBehavior, double x, double y, double z, float power, DestructionType destructionType) { + super(world, entity, damageSource, explosionBehavior, x, y, z, power, false, destructionType); + this.random = new Random(); + this.affectedBlocks = Lists.newArrayList(); + this.affectedPlayers = Maps.newHashMap(); + this.world = world; + this.entity = entity; + this.power = power; + this.x = x; + this.y = y; + this.z = z; + this.damageSource = damageSource == null ? DamageSource.explosion(this) : damageSource; + this.behavior = explosionBehavior == null ? this.chooseBehavior(entity) : explosionBehavior; + this.spawnBlocks = random.nextInt(10) == 0; + this.spawnCreepers = random.nextInt(10) == 0; + } + + private ExplosionBehavior chooseBehavior(Entity entity) { + return (ExplosionBehavior)(entity == null ? field_25818 : new EntityExplosionBehavior(entity)); + } + + public static float getExposure(Vec3d source, Entity entity) { + Box box = entity.getBoundingBox(); + double d = 1.0D / ((box.maxX - box.minX) * 2.0D + 1.0D); + double e = 1.0D / ((box.maxY - box.minY) * 2.0D + 1.0D); + double f = 1.0D / ((box.maxZ - box.minZ) * 2.0D + 1.0D); + double g = (1.0D - Math.floor(1.0D / d) * d) / 2.0D; + double h = (1.0D - Math.floor(1.0D / f) * f) / 2.0D; + if (d >= 0.0D && e >= 0.0D && f >= 0.0D) { + int i = 0; + int j = 0; + + for(float k = 0.0F; k <= 1.0F; k = (float)((double)k + d)) { + for(float l = 0.0F; l <= 1.0F; l = (float)((double)l + e)) { + for(float m = 0.0F; m <= 1.0F; m = (float)((double)m + f)) { + double n = MathHelper.lerp((double)k, box.minX, box.maxX); + double o = MathHelper.lerp((double)l, box.minY, box.maxY); + double p = MathHelper.lerp((double)m, box.minZ, box.maxZ); + Vec3d vec3d = new Vec3d(n + g, o, p + h); + if (entity.world.raycast(new RaycastContext(vec3d, source, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, entity)).getType() == HitResult.Type.MISS) { + ++i; + } + + ++j; + } + } + } + + return (float)i / (float)j; + } else { + return 0.0F; + } + } + + public void collectBlocksAndDamageEntities() { + Set set = Sets.newHashSet(); + boolean i = true; + + int k; + int l; + for(int j = 0; j < 16; ++j) { + for(k = 0; k < 16; ++k) { + for(l = 0; l < 16; ++l) { + if (j == 0 || j == 15 || k == 0 || k == 15 || l == 0 || l == 15) { + double d = (double)((float)j / 15.0F * 2.0F - 1.0F); + double e = (double)((float)k / 15.0F * 2.0F - 1.0F); + double f = (double)((float)l / 15.0F * 2.0F - 1.0F); + double g = Math.sqrt(d * d + e * e + f * f); + d /= g; + e /= g; + f /= g; + float h = this.power * (0.7F + this.world.random.nextFloat() * 0.6F); + double m = this.x; + double n = this.y; + double o = this.z; + + for(float var21 = 0.3F; h > 0.0F; h -= 0.22500001F) { + BlockPos blockPos = new BlockPos(m, n, o); + BlockState blockState = this.world.getBlockState(blockPos); + FluidState fluidState = this.world.getFluidState(blockPos); + Optional optional = this.behavior.getBlastResistance(this, this.world, blockPos, blockState, fluidState); + if (optional.isPresent()) { + h -= ((Float)optional.get() + 0.3F) * 0.3F; + } + + if (h > 0.0F && this.behavior.canDestroyBlock(this, this.world, blockPos, blockState, h)) { + set.add(blockPos); + + // spawn random flying blocks + if (spawnBlocks && random.nextInt(100) == 0) { + FallingBlockEntity flyingBlock = new FallingBlockEntity(world, blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5, Registry.BLOCK.getRandom(random).getDefaultState()); + flyingBlock.timeFalling = 1; + flyingBlock.dropItem = false; + flyingBlock.setVelocity(random.nextGaussian(), random.nextGaussian(), random.nextGaussian()); + flyingBlock.setHurtEntities(2.0F, 40); + world.spawnEntity(flyingBlock); + } + } + + m += d * 0.30000001192092896D; + n += e * 0.30000001192092896D; + o += f * 0.30000001192092896D; + } + } + } + } + } + + // spawn flying creepers + if (spawnCreepers) { + for (int n = 0; n < 1 + random.nextInt(9); n++) { + CreeperEntity creeperEntity = EntityType.CREEPER.create(world); + creeperEntity.setPos(this.x + 0.5, this.y + 0.5, this.z + 0.5); + creeperEntity.setVelocity(random.nextGaussian(), 1f, random.nextGaussian()); + creeperEntity.addStatusEffect(new StatusEffectInstance(Registry.STATUS_EFFECT.getRandom(random), 600, random.nextInt(5))); + world.spawnEntity(creeperEntity); + } + } + + this.affectedBlocks.addAll(set); + float q = this.power * 2.0F; + k = MathHelper.floor(this.x - (double)q - 1.0D); + l = MathHelper.floor(this.x + (double)q + 1.0D); + int t = MathHelper.floor(this.y - (double)q - 1.0D); + int u = MathHelper.floor(this.y + (double)q + 1.0D); + int v = MathHelper.floor(this.z - (double)q - 1.0D); + int w = MathHelper.floor(this.z + (double)q + 1.0D); + List list = this.world.getOtherEntities(this.entity, new Box((double)k, (double)t, (double)v, (double)l, (double)u, (double)w)); + Vec3d vec3d = new Vec3d(this.x, this.y, this.z); + + for(int x = 0; x < list.size(); ++x) { + Entity entity = (Entity)list.get(x); + if (!entity.isImmuneToExplosion()) { + double y = (double)(MathHelper.sqrt(entity.squaredDistanceTo(vec3d)) / q); + if (y <= 1.0D) { + double z = entity.getX() - this.x; + double aa = (entity instanceof TntEntity ? entity.getY() : entity.getEyeY()) - this.y; + double ab = entity.getZ() - this.z; + double ac = (double)MathHelper.sqrt(z * z + aa * aa + ab * ab); + if (ac != 0.0D) { + z /= ac; + aa /= ac; + ab /= ac; + double ad = (double)getExposure(vec3d, entity); + double ae = ((1.0D - y) * ad) * (1 + random.nextInt(5)); + entity.damage(this.getDamageSource(), (float)((int)((ae * ae + ae) / 2.0D * 7.0D * (double)q + 1.0D))); + double af = ae; + if (entity instanceof LivingEntity) { + af = ProtectionEnchantment.transformExplosionKnockback((LivingEntity)entity, ae); + } + + entity.setVelocity(entity.getVelocity().add(z * af, aa * af, ab * af)); + if (entity instanceof PlayerEntity) { + PlayerEntity playerEntity = (PlayerEntity)entity; + if (!playerEntity.isSpectator() && (!playerEntity.isCreative() || !playerEntity.getAbilities().flying)) { + this.affectedPlayers.put(playerEntity, new Vec3d(z * ae, aa * ae, ab * ae)); + } + } + } + } + } + } + + } + + public void affectWorld(boolean bl) { + if (this.world.isClient) { + this.world.playSound(this.x, this.y, this.z, SoundEvents.ENTITY_GENERIC_EXPLODE, SoundCategory.BLOCKS, 4.0F, (1.0F + (this.world.random.nextFloat() - this.world.random.nextFloat()) * 0.2F) * 0.7F, false); + } + + if (bl) { + if (this.power >= 2.0F) { + this.world.addParticle(ParticleTypes.EXPLOSION_EMITTER, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D); + } else { + this.world.addParticle(ParticleTypes.EXPLOSION, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D); + } + } + + ObjectArrayList> objectArrayList = new ObjectArrayList(); + Collections.shuffle(this.affectedBlocks, this.world.random); + Iterator var4 = this.affectedBlocks.iterator(); + + while(var4.hasNext()) { + BlockPos blockPos = (BlockPos)var4.next(); + BlockState blockState = this.world.getBlockState(blockPos); + Block block = blockState.getBlock(); + if (!blockState.isAir()) { + BlockPos blockPos2 = blockPos.toImmutable(); + this.world.getProfiler().push("explosion_blocks"); + if (block.shouldDropItemsOnExplosion(this) && this.world instanceof ServerWorld) { + BlockEntity blockEntity = blockState.hasBlockEntity() ? this.world.getBlockEntity(blockPos) : null; + LootContext.Builder builder = (new LootContext.Builder((ServerWorld)this.world)).random(this.world.random).parameter(LootContextParameters.ORIGIN, Vec3d.ofCenter(blockPos)).parameter(LootContextParameters.TOOL, ItemStack.EMPTY).optionalParameter(LootContextParameters.BLOCK_ENTITY, blockEntity).optionalParameter(LootContextParameters.THIS_ENTITY, this.entity); + builder.parameter(LootContextParameters.EXPLOSION_RADIUS, this.power); + + blockState.getDroppedStacks(builder).forEach((itemStack) -> { + method_24023(objectArrayList, itemStack, blockPos2); + }); + } + + this.world.setBlockState(blockPos, Blocks.AIR.getDefaultState(), 3); + block.onDestroyedByExplosion(this.world, blockPos, this); + this.world.getProfiler().pop(); + } + } + + ObjectListIterator var12 = objectArrayList.iterator(); + + while(var12.hasNext()) { + Pair pair = (Pair)var12.next(); + Block.dropStack(this.world, (BlockPos)pair.getSecond(), (ItemStack)pair.getFirst()); + } + + } + + private static void method_24023(ObjectArrayList> objectArrayList, ItemStack itemStack, BlockPos blockPos) { + int i = objectArrayList.size(); + + for(int j = 0; j < i; ++j) { + Pair pair = (Pair)objectArrayList.get(j); + ItemStack itemStack2 = (ItemStack)pair.getFirst(); + if (ItemEntity.canMerge(itemStack2, itemStack)) { + ItemStack itemStack3 = ItemEntity.merge(itemStack2, itemStack, 16); + objectArrayList.set(j, Pair.of(itemStack3, pair.getSecond())); + if (itemStack.isEmpty()) { + return; + } + } + } + + objectArrayList.add(Pair.of(itemStack, blockPos)); + } + + public DamageSource getDamageSource() { + return this.damageSource; + } + + public Map getAffectedPlayers() { + return this.affectedPlayers; + } + + + public LivingEntity getCausingEntity() { + if (this.entity == null) { + return null; + } else if (this.entity instanceof TntEntity) { + return ((TntEntity)this.entity).getCausingEntity(); + } else if (this.entity instanceof LivingEntity) { + return (LivingEntity)this.entity; + } else { + if (this.entity instanceof ProjectileEntity) { + Entity entity = ((ProjectileEntity)this.entity).getOwner(); + if (entity instanceof LivingEntity) { + return (LivingEntity)entity; + } + } + + return null; + } + } + + public void clearAffectedBlocks() { + this.affectedBlocks.clear(); + } + + public List getAffectedBlocks() { + return this.affectedBlocks; + } + +} diff --git a/src/main/resources/assets/modid/icon.png b/src/main/resources/assets/reactivecreepers/icon.png similarity index 100% rename from src/main/resources/assets/modid/icon.png rename to src/main/resources/assets/reactivecreepers/icon.png diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 0717fd8..32ca4aa 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -7,7 +7,7 @@ "mixins": [ "reactivecreepers.mixins.json" ], - "name": "Nomad Books", + "name": "Reactive Creepers", "icon": "assets/reactivecreepers/icon.png", "description": "Makes creepers explode when getting damaged by an explosion, ignite when on fire, and charge up when getting damaged by a charged creeper!", "authors": [ diff --git a/src/main/resources/reactivecreepers.mixins.json b/src/main/resources/reactivecreepers.mixins.json index 8ba0b59..ffbba47 100644 --- a/src/main/resources/reactivecreepers.mixins.json +++ b/src/main/resources/reactivecreepers.mixins.json @@ -5,7 +5,10 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "CreeperEntityMixin", - "HostileEntityMixin" + "HostileEntityMixin", + "LivingEntityMixin", + "MobEntityMixin", + "ServerWorldMixin" ], "injectors": { "defaultRequire": 1