minecraft-source/src/net/minecraft/world/level/Explosion.java

303 lines
15 KiB
Java

package net.minecraft.world.level;
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
import net.minecraft.world.entity.item.PrimedTnt;
import net.minecraft.world.entity.item.ItemEntity;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import java.util.Iterator;
import net.minecraft.world.level.block.Block;
import com.mojang.datafixers.util.Pair;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.server.level.ServerLevel;
import java.util.Collections;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.sounds.SoundSource;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.block.state.BlockState;
import java.util.Set;
import net.minecraft.world.item.enchantment.ProtectionEnchantment;
import net.minecraft.world.entity.LivingEntity;
import com.google.common.collect.Sets;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.HitResult;
import net.minecraft.util.Mth;
import com.google.common.collect.Maps;
import com.google.common.collect.Lists;
import java.util.Collection;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.entity.player.Player;
import java.util.Map;
import net.minecraft.core.BlockPos;
import java.util.List;
import net.minecraft.world.damagesource.DamageSource;
import javax.annotation.Nullable;
import net.minecraft.world.entity.Entity;
import java.util.Random;
public class Explosion {
private final boolean fire;
private final BlockInteraction blockInteraction;
private final Random random;
private final Level level;
private final double x;
private final double y;
private final double z;
@Nullable
private final Entity source;
private final float radius;
private DamageSource damageSource;
private final List<BlockPos> toBlow;
private final Map<Player, Vec3> hitPlayers;
public Explosion(final Level bjt, @Nullable final Entity akn, final double double3, final double double4, final double double5, final float float6, final List<BlockPos> list) {
this(bjt, akn, double3, double4, double5, float6, false, BlockInteraction.DESTROY, list);
}
public Explosion(final Level bjt, @Nullable final Entity akn, final double double3, final double double4, final double double5, final float float6, final boolean boolean7, final BlockInteraction a, final List<BlockPos> list) {
this(bjt, akn, double3, double4, double5, float6, boolean7, a);
this.toBlow.addAll(list);
}
public Explosion(final Level bjt, @Nullable final Entity akn, final double double3, final double double4, final double double5, final float float6, final boolean boolean7, final BlockInteraction a) {
this.random = new Random();
this.toBlow = Lists.newArrayList();
this.hitPlayers = Maps.newHashMap();
this.level = bjt;
this.source = akn;
this.radius = float6;
this.x = double3;
this.y = double4;
this.z = double5;
this.fire = boolean7;
this.blockInteraction = a;
this.damageSource = DamageSource.explosion(this);
}
public static float getSeenPercent(final Vec3 cvi, final Entity akn) {
final AABB cvc3 = akn.getBoundingBox();
final double double4 = 1.0 / ((cvc3.maxX - cvc3.minX) * 2.0 + 1.0);
final double double5 = 1.0 / ((cvc3.maxY - cvc3.minY) * 2.0 + 1.0);
final double double6 = 1.0 / ((cvc3.maxZ - cvc3.minZ) * 2.0 + 1.0);
final double double7 = (1.0 - Math.floor(1.0 / double4) * double4) / 2.0;
final double double8 = (1.0 - Math.floor(1.0 / double6) * double6) / 2.0;
if (double4 < 0.0 || double5 < 0.0 || double6 < 0.0) {
return 0.0f;
}
int integer14 = 0;
int integer15 = 0;
for (float float16 = 0.0f; float16 <= 1.0f; float16 += (float)double4) {
for (float float17 = 0.0f; float17 <= 1.0f; float17 += (float)double5) {
for (float float18 = 0.0f; float18 <= 1.0f; float18 += (float)double6) {
final double double9 = Mth.lerp(float16, cvc3.minX, cvc3.maxX);
final double double10 = Mth.lerp(float17, cvc3.minY, cvc3.maxY);
final double double11 = Mth.lerp(float18, cvc3.minZ, cvc3.maxZ);
final Vec3 cvi2 = new Vec3(double9 + double7, double10, double11 + double8);
if (akn.level.clip(new ClipContext(cvi2, cvi, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, akn)).getType() == HitResult.Type.MISS) {
++integer14;
}
++integer15;
}
}
}
return integer14 / (float)integer15;
}
public void explode() {
final Set<BlockPos> set2 = Sets.newHashSet();
final int integer3 = 16;
for (int integer4 = 0; integer4 < 16; ++integer4) {
for (int integer5 = 0; integer5 < 16; ++integer5) {
for (int integer6 = 0; integer6 < 16; ++integer6) {
if (integer4 == 0 || integer4 == 15 || integer5 == 0 || integer5 == 15 || integer6 == 0 || integer6 == 15) {
double double7 = integer4 / 15.0f * 2.0f - 1.0f;
double double8 = integer5 / 15.0f * 2.0f - 1.0f;
double double9 = integer6 / 15.0f * 2.0f - 1.0f;
final double double10 = Math.sqrt(double7 * double7 + double8 * double8 + double9 * double9);
double7 /= double10;
double8 /= double10;
double9 /= double10;
float float15 = this.radius * (0.7f + this.level.random.nextFloat() * 0.6f);
double double11 = this.x;
double double12 = this.y;
double double13 = this.z;
final float float16 = 0.3f;
while (float15 > 0.0f) {
final BlockPos fk23 = new BlockPos(double11, double12, double13);
final BlockState byg24 = this.level.getBlockState(fk23);
final FluidState cog25 = this.level.getFluidState(fk23);
if (!byg24.isAir() || !cog25.isEmpty()) {
float float17 = Math.max(byg24.getBlock().getExplosionResistance(), cog25.getExplosionResistance());
if (this.source != null) {
float17 = this.source.getBlockExplosionResistance(this, this.level, fk23, byg24, cog25, float17);
}
float15 -= (float17 + 0.3f) * 0.3f;
}
if (float15 > 0.0f && (this.source == null || this.source.shouldBlockExplode(this, this.level, fk23, byg24, float15))) {
set2.add(fk23);
}
double11 += double7 * 0.30000001192092896;
double12 += double8 * 0.30000001192092896;
double13 += double9 * 0.30000001192092896;
float15 -= 0.22500001f;
}
}
}
}
}
this.toBlow.addAll(set2);
final float float18 = this.radius * 2.0f;
int integer5 = Mth.floor(this.x - float18 - 1.0);
int integer6 = Mth.floor(this.x + float18 + 1.0);
final int integer7 = Mth.floor(this.y - float18 - 1.0);
final int integer8 = Mth.floor(this.y + float18 + 1.0);
final int integer9 = Mth.floor(this.z - float18 - 1.0);
final int integer10 = Mth.floor(this.z + float18 + 1.0);
final List<Entity> list11 = this.level.getEntities(this.source, new AABB(integer5, integer7, integer9, integer6, integer8, integer10));
final Vec3 cvi12 = new Vec3(this.x, this.y, this.z);
for (int integer11 = 0; integer11 < list11.size(); ++integer11) {
final Entity akn14 = list11.get(integer11);
if (!akn14.ignoreExplosion()) {
final double double14 = Mth.sqrt(akn14.distanceToSqr(cvi12)) / float18;
if (double14 <= 1.0) {
double double15 = akn14.getX() - this.x;
double double16 = akn14.getEyeY() - this.y;
double double17 = akn14.getZ() - this.z;
final double double18 = Mth.sqrt(double15 * double15 + double16 * double16 + double17 * double17);
if (double18 != 0.0) {
double15 /= double18;
double16 /= double18;
double17 /= double18;
final double double19 = getSeenPercent(cvi12, akn14);
final double double20 = (1.0 - double14) * double19;
akn14.hurt(this.getDamageSource(), (float)(int)((double20 * double20 + double20) / 2.0 * 7.0 * float18 + 1.0));
double double21 = double20;
if (akn14 instanceof LivingEntity) {
double21 = ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity)akn14, double20);
}
akn14.setDeltaMovement(akn14.getDeltaMovement().add(double15 * double21, double16 * double21, double17 * double21));
if (akn14 instanceof Player) {
final Player ayg31 = (Player)akn14;
if (!ayg31.isSpectator() && (!ayg31.isCreative() || !ayg31.abilities.flying)) {
this.hitPlayers.put(ayg31, new Vec3(double15 * double20, double16 * double20, double17 * double20));
}
}
}
}
}
}
}
public void finalizeExplosion(final boolean boolean1) {
if (this.level.isClientSide) {
this.level.playLocalSound(this.x, this.y, this.z, SoundEvents.GENERIC_EXPLODE, SoundSource.BLOCKS, 4.0f, (1.0f + (this.level.random.nextFloat() - this.level.random.nextFloat()) * 0.2f) * 0.7f, false);
}
final boolean boolean2 = this.blockInteraction != BlockInteraction.NONE;
if (boolean1) {
if (this.radius < 2.0f || !boolean2) {
this.level.addParticle(ParticleTypes.EXPLOSION, this.x, this.y, this.z, 1.0, 0.0, 0.0);
}
else {
this.level.addParticle(ParticleTypes.EXPLOSION_EMITTER, this.x, this.y, this.z, 1.0, 0.0, 0.0);
}
}
if (boolean2) {
final ObjectArrayList<Pair<ItemStack, BlockPos>> objectArrayList4 = (ObjectArrayList<Pair<ItemStack, BlockPos>>)new ObjectArrayList();
Collections.shuffle(this.toBlow, this.level.random);
for (final BlockPos fk6 : this.toBlow) {
final BlockState byg7 = this.level.getBlockState(fk6);
final Block bpe8 = byg7.getBlock();
if (!byg7.isAir()) {
final BlockPos fk7 = fk6.immutable();
this.level.getProfiler().push("explosion_blocks");
if (bpe8.dropFromExplosion(this) && this.level instanceof ServerLevel) {
final BlockEntity bwi10 = bpe8.isEntityBlock() ? this.level.getBlockEntity(fk6) : null;
final LootContext.Builder a11 = new LootContext.Builder((ServerLevel)this.level).withRandom(this.level.random).<BlockPos>withParameter(LootContextParams.BLOCK_POS, fk6).<ItemStack>withParameter(LootContextParams.TOOL, ItemStack.EMPTY).<BlockEntity>withOptionalParameter(LootContextParams.BLOCK_ENTITY, bwi10).<Entity>withOptionalParameter(LootContextParams.THIS_ENTITY, this.source);
if (this.blockInteraction == BlockInteraction.DESTROY) {
a11.<Float>withParameter(LootContextParams.EXPLOSION_RADIUS, this.radius);
}
byg7.getDrops(a11).forEach(bek -> addBlockDrops(objectArrayList4, bek, fk7));
}
this.level.setBlock(fk6, Blocks.AIR.defaultBlockState(), 3);
bpe8.wasExploded(this.level, fk6, this);
this.level.getProfiler().pop();
}
}
for (final Pair<ItemStack, BlockPos> pair6 : objectArrayList4) {
Block.popResource(this.level, (BlockPos)pair6.getSecond(), (ItemStack)pair6.getFirst());
}
}
if (this.fire) {
for (final BlockPos fk8 : this.toBlow) {
if (this.random.nextInt(3) == 0 && this.level.getBlockState(fk8).isAir() && this.level.getBlockState(fk8.below()).isSolidRender(this.level, fk8.below())) {
this.level.setBlockAndUpdate(fk8, Blocks.FIRE.defaultBlockState());
}
}
}
}
private static void addBlockDrops(final ObjectArrayList<Pair<ItemStack, BlockPos>> objectArrayList, final ItemStack bek, final BlockPos fk) {
for (int integer4 = objectArrayList.size(), integer5 = 0; integer5 < integer4; ++integer5) {
final Pair<ItemStack, BlockPos> pair6 = (Pair<ItemStack, BlockPos>)objectArrayList.get(integer5);
final ItemStack bek2 = (ItemStack)pair6.getFirst();
if (ItemEntity.areMergable(bek2, bek)) {
final ItemStack bek3 = ItemEntity.merge(bek2, bek, 16);
objectArrayList.set(integer5, Pair.of((Object)bek3, pair6.getSecond()));
if (bek.isEmpty()) {
return;
}
}
}
objectArrayList.add(Pair.of((Object)bek, (Object)fk));
}
public DamageSource getDamageSource() {
return this.damageSource;
}
public void setDamageSource(final DamageSource ajw) {
this.damageSource = ajw;
}
public Map<Player, Vec3> getHitPlayers() {
return this.hitPlayers;
}
@Nullable
public LivingEntity getSourceMob() {
if (this.source == null) {
return null;
}
if (this.source instanceof PrimedTnt) {
return ((PrimedTnt)this.source).getOwner();
}
if (this.source instanceof LivingEntity) {
return (LivingEntity)this.source;
}
if (this.source instanceof AbstractHurtingProjectile) {
return ((AbstractHurtingProjectile)this.source).owner;
}
return null;
}
public void clearToBlow() {
this.toBlow.clear();
}
public List<BlockPos> getToBlow() {
return this.toBlow;
}
public enum BlockInteraction {
NONE,
BREAK,
DESTROY;
}
}