minecraft-src/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java
2025-07-04 03:45:38 +03:00

183 lines
5.3 KiB
Java

package net.minecraft.world.entity.projectile;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.SynchedEntityData.Builder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ClipContext.Block;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.HitResult.Type;
import org.jetbrains.annotations.Nullable;
public abstract class AbstractHurtingProjectile extends Projectile {
public static final double INITAL_ACCELERATION_POWER = 0.1;
public static final double DEFLECTION_SCALE = 0.5;
public double accelerationPower = 0.1;
protected AbstractHurtingProjectile(EntityType<? extends AbstractHurtingProjectile> entityType, Level level) {
super(entityType, level);
}
protected AbstractHurtingProjectile(EntityType<? extends AbstractHurtingProjectile> entityType, double x, double y, double z, Level level) {
this(entityType, level);
this.setPos(x, y, z);
}
public AbstractHurtingProjectile(EntityType<? extends AbstractHurtingProjectile> entityType, double x, double y, double z, Vec3 movement, Level level) {
this(entityType, level);
this.snapTo(x, y, z, this.getYRot(), this.getXRot());
this.reapplyPosition();
this.assignDirectionalMovement(movement, this.accelerationPower);
}
public AbstractHurtingProjectile(EntityType<? extends AbstractHurtingProjectile> entityType, LivingEntity owner, Vec3 movement, Level level) {
this(entityType, owner.getX(), owner.getY(), owner.getZ(), movement, level);
this.setOwner(owner);
this.setRot(owner.getYRot(), owner.getXRot());
}
@Override
protected void defineSynchedData(Builder builder) {
}
@Override
public boolean shouldRenderAtSqrDistance(double distance) {
double d = this.getBoundingBox().getSize() * 4.0;
if (Double.isNaN(d)) {
d = 4.0;
}
d *= 64.0;
return distance < d * d;
}
protected Block getClipType() {
return Block.COLLIDER;
}
@Override
public void tick() {
Entity entity = this.getOwner();
this.applyInertia();
if (this.level().isClientSide || (entity == null || !entity.isRemoved()) && this.level().hasChunkAt(this.blockPosition())) {
HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity, this.getClipType());
Vec3 vec3;
if (hitResult.getType() != Type.MISS) {
vec3 = hitResult.getLocation();
} else {
vec3 = this.position().add(this.getDeltaMovement());
}
ProjectileUtil.rotateTowardsMovement(this, 0.2F);
this.setPos(vec3);
this.applyEffectsFromBlocks();
super.tick();
if (this.shouldBurn()) {
this.igniteForSeconds(1.0F);
}
if (hitResult.getType() != Type.MISS && this.isAlive()) {
this.hitTargetOrDeflectSelf(hitResult);
}
this.createParticleTrail();
} else {
this.discard();
}
}
private void applyInertia() {
Vec3 vec3 = this.getDeltaMovement();
Vec3 vec32 = this.position();
float g;
if (this.isInWater()) {
for (int i = 0; i < 4; i++) {
float f = 0.25F;
this.level().addParticle(ParticleTypes.BUBBLE, vec32.x - vec3.x * 0.25, vec32.y - vec3.y * 0.25, vec32.z - vec3.z * 0.25, vec3.x, vec3.y, vec3.z);
}
g = this.getLiquidInertia();
} else {
g = this.getInertia();
}
this.setDeltaMovement(vec3.add(vec3.normalize().scale(this.accelerationPower)).scale(g));
}
private void createParticleTrail() {
ParticleOptions particleOptions = this.getTrailParticle();
Vec3 vec3 = this.position();
if (particleOptions != null) {
this.level().addParticle(particleOptions, vec3.x, vec3.y + 0.5, vec3.z, 0.0, 0.0, 0.0);
}
}
@Override
public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) {
return false;
}
@Override
protected boolean canHitEntity(Entity target) {
return super.canHitEntity(target) && !target.noPhysics;
}
protected boolean shouldBurn() {
return true;
}
@Nullable
protected ParticleOptions getTrailParticle() {
return ParticleTypes.SMOKE;
}
/**
* Return the motion factor for this projectile. The factor is multiplied by the original motion.
*/
protected float getInertia() {
return 0.95F;
}
protected float getLiquidInertia() {
return 0.8F;
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putDouble("acceleration_power", this.accelerationPower);
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
this.accelerationPower = tag.getDoubleOr("acceleration_power", 0.1);
}
@Override
public float getLightLevelDependentMagicValue() {
return 1.0F;
}
private void assignDirectionalMovement(Vec3 movement, double accelerationPower) {
this.setDeltaMovement(movement.normalize().scale(accelerationPower));
this.hasImpulse = true;
}
@Override
protected void onDeflection(@Nullable Entity entity, boolean deflectedByPlayer) {
super.onDeflection(entity, deflectedByPlayer);
if (deflectedByPlayer) {
this.accelerationPower = 0.1;
} else {
this.accelerationPower *= 0.5;
}
}
}