225 lines
8.6 KiB
Java
225 lines
8.6 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* org.jspecify.annotations.Nullable
|
|
*/
|
|
package net.minecraft.world.entity.vehicle;
|
|
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.tags.DamageTypeTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.projectile.AbstractArrow;
|
|
import net.minecraft.world.entity.projectile.Projectile;
|
|
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
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 net.minecraft.world.level.gamerules.GameRules;
|
|
import net.minecraft.world.level.material.FluidState;
|
|
import net.minecraft.world.level.storage.ValueInput;
|
|
import net.minecraft.world.level.storage.ValueOutput;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
public class MinecartTNT
|
|
extends AbstractMinecart {
|
|
private static final byte EVENT_PRIME = 10;
|
|
private static final String TAG_EXPLOSION_POWER = "explosion_power";
|
|
private static final String TAG_EXPLOSION_SPEED_FACTOR = "explosion_speed_factor";
|
|
private static final String TAG_FUSE = "fuse";
|
|
private static final float DEFAULT_EXPLOSION_POWER_BASE = 4.0f;
|
|
private static final float DEFAULT_EXPLOSION_SPEED_FACTOR = 1.0f;
|
|
private static final int NO_FUSE = -1;
|
|
private @Nullable DamageSource ignitionSource;
|
|
private int fuse = -1;
|
|
private float explosionPowerBase = 4.0f;
|
|
private float explosionSpeedFactor = 1.0f;
|
|
|
|
public MinecartTNT(EntityType<? extends MinecartTNT> type, Level level) {
|
|
super(type, level);
|
|
}
|
|
|
|
@Override
|
|
public BlockState getDefaultDisplayBlockState() {
|
|
return Blocks.TNT.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
double speedSqr;
|
|
super.tick();
|
|
if (this.fuse > 0) {
|
|
--this.fuse;
|
|
this.level().addParticle(ParticleTypes.SMOKE, this.getX(), this.getY() + 0.5, this.getZ(), 0.0, 0.0, 0.0);
|
|
} else if (this.fuse == 0) {
|
|
this.explode(this.ignitionSource, this.getDeltaMovement().horizontalDistanceSqr());
|
|
}
|
|
if (this.horizontalCollision && (speedSqr = this.getDeltaMovement().horizontalDistanceSqr()) >= (double)0.01f) {
|
|
this.explode(this.ignitionSource, speedSqr);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean hurtServer(ServerLevel level, DamageSource source, float damage) {
|
|
AbstractArrow projectile;
|
|
Entity sourceEntity = source.getDirectEntity();
|
|
if (sourceEntity instanceof AbstractArrow && (projectile = (AbstractArrow)sourceEntity).isOnFire()) {
|
|
DamageSource damageSource = this.damageSources().explosion(this, source.getEntity());
|
|
this.explode(damageSource, projectile.getDeltaMovement().lengthSqr());
|
|
}
|
|
return super.hurtServer(level, source, damage);
|
|
}
|
|
|
|
@Override
|
|
public void destroy(ServerLevel level, DamageSource source) {
|
|
double speedSqr = this.getDeltaMovement().horizontalDistanceSqr();
|
|
if (MinecartTNT.damageSourceIgnitesTnt(source) || speedSqr >= (double)0.01f) {
|
|
if (this.fuse < 0) {
|
|
this.primeFuse(source);
|
|
this.fuse = this.random.nextInt(20) + this.random.nextInt(20);
|
|
}
|
|
return;
|
|
}
|
|
this.destroy(level, this.getDropItem());
|
|
}
|
|
|
|
@Override
|
|
protected Item getDropItem() {
|
|
return Items.TNT_MINECART;
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getPickResult() {
|
|
return new ItemStack(Items.TNT_MINECART);
|
|
}
|
|
|
|
protected void explode(@Nullable DamageSource damageSource, double speedSqr) {
|
|
Level level = this.level();
|
|
if (level instanceof ServerLevel) {
|
|
ServerLevel level2 = (ServerLevel)level;
|
|
if (level2.getGameRules().get(GameRules.TNT_EXPLODES).booleanValue()) {
|
|
double speed = Math.min(Math.sqrt(speedSqr), 5.0);
|
|
level2.explode(this, damageSource, null, this.getX(), this.getY(), this.getZ(), (float)((double)this.explosionPowerBase + (double)this.explosionSpeedFactor * this.random.nextDouble() * 1.5 * speed), false, Level.ExplosionInteraction.TNT);
|
|
this.discard();
|
|
} else if (this.isPrimed()) {
|
|
this.discard();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean causeFallDamage(double fallDistance, float damageModifier, DamageSource damageSource) {
|
|
if (fallDistance >= 3.0) {
|
|
double power = fallDistance / 10.0;
|
|
this.explode(this.ignitionSource, power * power);
|
|
}
|
|
return super.causeFallDamage(fallDistance, damageModifier, damageSource);
|
|
}
|
|
|
|
@Override
|
|
public void activateMinecart(ServerLevel level, int xt, int yt, int zt, boolean state) {
|
|
if (state && this.fuse < 0) {
|
|
this.primeFuse(null);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void handleEntityEvent(byte id) {
|
|
if (id == 10) {
|
|
this.primeFuse(null);
|
|
} else {
|
|
super.handleEntityEvent(id);
|
|
}
|
|
}
|
|
|
|
public void primeFuse(@Nullable DamageSource source) {
|
|
ServerLevel serverLevel;
|
|
Level level = this.level();
|
|
if (level instanceof ServerLevel && !(serverLevel = (ServerLevel)level).getGameRules().get(GameRules.TNT_EXPLODES).booleanValue()) {
|
|
return;
|
|
}
|
|
this.fuse = 80;
|
|
if (!this.level().isClientSide()) {
|
|
if (source != null && this.ignitionSource == null) {
|
|
this.ignitionSource = this.damageSources().explosion(this, source.getEntity());
|
|
}
|
|
this.level().broadcastEntityEvent(this, (byte)10);
|
|
if (!this.isSilent()) {
|
|
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0f, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
public int getFuse() {
|
|
return this.fuse;
|
|
}
|
|
|
|
public boolean isPrimed() {
|
|
return this.fuse > -1;
|
|
}
|
|
|
|
@Override
|
|
public float getBlockExplosionResistance(Explosion explosion, BlockGetter level, BlockPos pos, BlockState block, FluidState fluid, float resistance) {
|
|
if (this.isPrimed() && (block.is(BlockTags.RAILS) || level.getBlockState(pos.above()).is(BlockTags.RAILS))) {
|
|
return 0.0f;
|
|
}
|
|
return super.getBlockExplosionResistance(explosion, level, pos, block, fluid, resistance);
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldBlockExplode(Explosion explosion, BlockGetter level, BlockPos pos, BlockState state, float power) {
|
|
if (this.isPrimed() && (state.is(BlockTags.RAILS) || level.getBlockState(pos.above()).is(BlockTags.RAILS))) {
|
|
return false;
|
|
}
|
|
return super.shouldBlockExplode(explosion, level, pos, state, power);
|
|
}
|
|
|
|
@Override
|
|
protected void readAdditionalSaveData(ValueInput input) {
|
|
super.readAdditionalSaveData(input);
|
|
this.fuse = input.getIntOr(TAG_FUSE, -1);
|
|
this.explosionPowerBase = Mth.clamp(input.getFloatOr(TAG_EXPLOSION_POWER, 4.0f), 0.0f, 128.0f);
|
|
this.explosionSpeedFactor = Mth.clamp(input.getFloatOr(TAG_EXPLOSION_SPEED_FACTOR, 1.0f), 0.0f, 128.0f);
|
|
}
|
|
|
|
@Override
|
|
protected void addAdditionalSaveData(ValueOutput output) {
|
|
super.addAdditionalSaveData(output);
|
|
output.putInt(TAG_FUSE, this.fuse);
|
|
if (this.explosionPowerBase != 4.0f) {
|
|
output.putFloat(TAG_EXPLOSION_POWER, this.explosionPowerBase);
|
|
}
|
|
if (this.explosionSpeedFactor != 1.0f) {
|
|
output.putFloat(TAG_EXPLOSION_SPEED_FACTOR, this.explosionSpeedFactor);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
boolean shouldSourceDestroy(DamageSource source) {
|
|
return MinecartTNT.damageSourceIgnitesTnt(source);
|
|
}
|
|
|
|
private static boolean damageSourceIgnitesTnt(DamageSource source) {
|
|
Entity entity = source.getDirectEntity();
|
|
if (entity instanceof Projectile) {
|
|
Projectile projectile = (Projectile)entity;
|
|
return projectile.isOnFire();
|
|
}
|
|
return source.is(DamageTypeTags.IS_FIRE) || source.is(DamageTypeTags.IS_EXPLOSION);
|
|
}
|
|
}
|
|
|