package com.atsuishio.superbwarfare.entity.vehicle; import com.atsuishio.superbwarfare.entity.DroneEntity; import com.atsuishio.superbwarfare.entity.TargetEntity; import com.atsuishio.superbwarfare.entity.projectile.FlareDecoyEntity; import com.atsuishio.superbwarfare.entity.projectile.LaserEntity; import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModSounds; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.util.Mth; import net.minecraft.world.entity.AreaEffectCloud; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MoverType; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.level.Level; import net.minecraft.world.level.entity.EntityTypeTest; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import org.joml.Math; import org.joml.Vector3f; public class MobileVehicleEntity extends EnergyVehicleEntity { public static final EntityDataAccessor POWER = SynchedEntityData.defineId(MobileVehicleEntity.class, EntityDataSerializers.FLOAT); public boolean leftInputDown; public boolean rightInputDown; public boolean forwardInputDown; public boolean backInputDown; public boolean upInputDown; public boolean downInputDown; public boolean decoyInputDown; public double lastTickSpeed; public double lastTickVerticalSpeed; public int collisionCoolDown; public MobileVehicleEntity(EntityType pEntityType, Level pLevel) { super(pEntityType, pLevel); } @Override public void playerTouch(Player pPlayer) { if (pPlayer.isCrouching() && !this.level().isClientSide) { double entitySize = pPlayer.getBbWidth() * pPlayer.getBbHeight(); double thisSize = this.getBbWidth() * this.getBbHeight(); double f = Math.min(entitySize / thisSize, 2); double f1 = Math.min(thisSize / entitySize, 4); this.setDeltaMovement(this.getDeltaMovement().add(new Vec3(pPlayer.position().vectorTo(this.position()).toVector3f()).scale(0.15 * f * pPlayer.getDeltaMovement().length()))); pPlayer.setDeltaMovement(pPlayer.getDeltaMovement().add(new Vec3(this.position().vectorTo(pPlayer.position()).toVector3f()).scale(0.1 * f1 * pPlayer.getDeltaMovement().length()))); } } @Override public void baseTick() { lastTickSpeed = new Vec3(this.getDeltaMovement().x, this.getDeltaMovement().y + 0.06, this.getDeltaMovement().z).length(); lastTickVerticalSpeed = this.getDeltaMovement().y + 0.06; if (collisionCoolDown > 0) { collisionCoolDown--; } super.baseTick(); crushEntities(this.getDeltaMovement()); this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.06, 0.0)); this.move(MoverType.SELF, this.getDeltaMovement()); this.refreshDimensions(); } @Override public void move(@NotNull MoverType movementType, @NotNull Vec3 movement) { super.move(movementType, movement); if (lastTickSpeed < 0.3 || collisionCoolDown > 0) return; if ((verticalCollision)) { if (this instanceof IHelicopterEntity) { this.hurt(ModDamageTypes.causeVehicleStrikeDamage(this.level().registryAccess(), this, this.getFirstPassenger() == null ? this : this.getFirstPassenger()), (float) (100 * ((lastTickSpeed - 0.3) * (lastTickSpeed - 0.3)))); this.bounceVertical(Direction.getNearest(this.getDeltaMovement().x(), this.getDeltaMovement().y(), this.getDeltaMovement().z()).getOpposite()); } else if (Mth.abs((float) lastTickVerticalSpeed) > 0.6) { this.hurt(ModDamageTypes.causeVehicleStrikeDamage(this.level().registryAccess(), this, this.getFirstPassenger() == null ? this : this.getFirstPassenger()), (float) (240 * ((Mth.abs((float) lastTickVerticalSpeed) - 0.6) * (lastTickSpeed - 0.4) * (lastTickSpeed - 0.4)))); if (!this.level().isClientSide) { this.level().playSound(null, this, ModSounds.VEHICLE_STRIKE.get(), this.getSoundSource(), 1, 1); } this.bounceVertical(Direction.getNearest(this.getDeltaMovement().x(), this.getDeltaMovement().y(), this.getDeltaMovement().z()).getOpposite()); } } if (this.horizontalCollision) { this.hurt(ModDamageTypes.causeVehicleStrikeDamage(this.level().registryAccess(), this, this.getFirstPassenger() == null ? this : this.getFirstPassenger()), (float) (180 * ((lastTickSpeed - 0.4) * (lastTickSpeed - 0.4)))); this.bounceHorizontal(Direction.getNearest(this.getDeltaMovement().x(), this.getDeltaMovement().y(), this.getDeltaMovement().z()).getOpposite()); if (!this.level().isClientSide) { this.level().playSound(null, this, ModSounds.VEHICLE_STRIKE.get(), this.getSoundSource(), 1, 1); } collisionCoolDown = 4; crash = true; } } public void bounceHorizontal(Direction direction) { switch (direction.getAxis()) { case X: this.setDeltaMovement(this.getDeltaMovement().multiply(-0.8, 0.99, 0.99)); break; case Z: this.setDeltaMovement(this.getDeltaMovement().multiply(0.99, 0.99, -0.8)); break; } } public void bounceVertical(Direction direction) { if (!this.level().isClientSide) { this.level().playSound(null, this, ModSounds.VEHICLE_STRIKE.get(), this.getSoundSource(), 1, 1); } collisionCoolDown = 4; crash = true; if (direction.getAxis() == Direction.Axis.Y) { this.setDeltaMovement(this.getDeltaMovement().multiply(0.9, -0.8, 0.9)); } } /** * 撞击实体并造成伤害 * @param velocity 动量 */ public void crushEntities(Vec3 velocity) { if (this instanceof DroneEntity) return; if (velocity.horizontalDistance() < 0.1) return; if (isRemoved()) return; var frontBox = getBoundingBox().move(velocity.scale(0.5)); var velAdd = velocity.add(0, 0, 0).scale(0.9); var entities = level().getEntities(EntityTypeTest.forClass(Entity.class), frontBox, entity -> entity != this && entity != getFirstPassenger() && entity.getVehicle() == null) .stream().filter(entity -> entity.isAlive() && !(entity instanceof ItemEntity || entity instanceof Projectile || entity instanceof ProjectileEntity || entity instanceof LaserEntity || entity instanceof FlareDecoyEntity || entity instanceof AreaEffectCloud) && !(entity instanceof Player player && (player.isSpectator() || player.isCreative()))) .toList(); for (var entity : entities) { double entitySize = entity.getBbWidth() * entity.getBbHeight(); double thisSize = this.getBbWidth() * this.getBbHeight(); double f = Math.min(entitySize / thisSize, 2); double f1 = Math.min(thisSize / entitySize, 4); if (velocity.length() > 0.3) { if (!this.level().isClientSide) { this.level().playSound(null, this, ModSounds.VEHICLE_STRIKE.get(), this.getSoundSource(), 1, 1); } if (!(entity instanceof TargetEntity)) { this.push(-f * velAdd.x, -f * velAdd.y, -f * velAdd.z); } entity.push(f1 * velAdd.x, f1 * velAdd.y, f1 * velAdd.z); entity.hurt(ModDamageTypes.causeVehicleStrikeDamage(this.level().registryAccess(), this, this.getFirstPassenger() == null ? this : this.getFirstPassenger()), (float) (thisSize * 20 * ((velocity.length() - 0.3) * (velocity.length() - 0.3)))); if (entities instanceof VehicleEntity) { this.hurt(ModDamageTypes.causeVehicleStrikeDamage(this.level().registryAccess(), entity, entity.getFirstPassenger() == null ? entity : entity.getFirstPassenger()), (float) (entitySize * 10 * ((velocity.length() - 0.3) * (velocity.length() - 0.3)))); } } else { entity.push(0.3 * f1 * velAdd.x, 0.3 * f1 * velAdd.y, 0.3 * f1 * velAdd.z); } } } public Vector3f getForwardDirection() { return new Vector3f( Mth.sin(-getYRot() * ((float) java.lang.Math.PI / 180)), 0.0f, Mth.cos(getYRot() * ((float) java.lang.Math.PI / 180)) ).normalize(); } public Vector3f getRightDirection() { return new Vector3f( Mth.cos(-getYRot() * ((float) java.lang.Math.PI / 180)), 0.0f, Mth.sin(getYRot() * ((float) java.lang.Math.PI / 180)) ).normalize(); } public SoundEvent getEngineSound() { return SoundEvents.EMPTY; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(POWER, 0f); } @Override protected void readAdditionalSaveData(CompoundTag compound) { super.readAdditionalSaveData(compound); this.entityData.set(POWER, compound.getFloat("Power")); } @Override public void addAdditionalSaveData(CompoundTag compound) { super.addAdditionalSaveData(compound); compound.putFloat("Power", this.entityData.get(POWER)); } }