diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Hpj11Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Hpj11Entity.java index 455c06b86..fcd7c8b83 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Hpj11Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Hpj11Entity.java @@ -7,6 +7,7 @@ import com.atsuishio.superbwarfare.entity.TargetEntity; import com.atsuishio.superbwarfare.entity.projectile.GunGrenadeEntity; import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; import com.atsuishio.superbwarfare.entity.projectile.SmallCannonShellEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.AutoAimable; import com.atsuishio.superbwarfare.entity.vehicle.base.CannonEntity; import com.atsuishio.superbwarfare.entity.vehicle.base.ContainerMobileVehicleEntity; import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; @@ -61,7 +62,8 @@ import java.util.stream.StreamSupport; import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter; -public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEntity, CannonEntity, OwnableEntity { +public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEntity, CannonEntity, OwnableEntity, AutoAimable { + public static final EntityDataAccessor ANIM_TIME = SynchedEntityData.defineId(Hpj11Entity.class, EntityDataSerializers.INT); public static final EntityDataAccessor GUN_ROTATE = SynchedEntityData.defineId(Hpj11Entity.class, EntityDataSerializers.FLOAT); public static final EntityDataAccessor ACTIVE = SynchedEntityData.defineId(Hpj11Entity.class, EntityDataSerializers.BOOLEAN); @@ -263,7 +265,7 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti Vec3 barrelRootPos = new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); if (entityData.get(TARGET_UUID).equals("none") && tickCount % 2 == 0) { - Entity naerestEntity = seekNearLivingEntity(barrelRootPos, -32.5, 90, 3, 160, 0.3); + Entity naerestEntity = seekNearLivingEntity(this, barrelRootPos, -32.5, 90, 3, 160, 0.3); if (naerestEntity != null) { entityData.set(TARGET_UUID, naerestEntity.getStringUUID()); this.consumeEnergy(VehicleConfig.HPJ11_SEEK_COST.get()); @@ -314,7 +316,7 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti this.setYRot(this.getYRot() + Mth.clamp(0.9f * diffY, -20f, 20f)); if (target.distanceTo(this) <= 144 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 10) { - if (checkNoClip(target, barrelRootPos) && entityData.get(AMMO) > 0) { + if (checkNoClip(this, target, barrelRootPos) && entityData.get(AMMO) > 0) { vehicleShoot(player, 0); findEntityOnPath(barrelRootPos, targetVec); } else { @@ -364,7 +366,7 @@ public class Hpj11Entity extends ContainerMobileVehicleEntity implements GeoEnti Entity target = StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false) .filter(e -> { if (e == entity && e instanceof Projectile && !(e instanceof ProjectileEntity || e instanceof SmallCannonShellEntity)) { - return checkNoClip(e, pos); + return checkNoClip(this, e, pos); } return false; }).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null); diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/LaserTowerEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/LaserTowerEntity.java index 5b364b805..f16e0be44 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/LaserTowerEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/LaserTowerEntity.java @@ -2,6 +2,7 @@ package com.atsuishio.superbwarfare.entity.vehicle; import com.atsuishio.superbwarfare.config.server.VehicleConfig; import com.atsuishio.superbwarfare.entity.TargetEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.AutoAimable; import com.atsuishio.superbwarfare.entity.vehicle.base.EnergyVehicleEntity; import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; import com.atsuishio.superbwarfare.init.*; @@ -47,7 +48,7 @@ import java.util.UUID; import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter; -public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity, OwnableEntity { +public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity, OwnableEntity, AutoAimable { public static final EntityDataAccessor COOL_DOWN = SynchedEntityData.defineId(LaserTowerEntity.class, EntityDataSerializers.INT); public static final EntityDataAccessor TARGET_UUID = SynchedEntityData.defineId(LaserTowerEntity.class, EntityDataSerializers.STRING); @@ -241,7 +242,7 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity, Vec3 barrelRootPos = new Vec3(this.getX(), this.getY() + 1.390625f, this.getZ()); if (entityData.get(TARGET_UUID).equals("none") && tickCount % 5 == 0) { - Entity naerestEntity = seekNearLivingEntity(barrelRootPos,-40, 90,1,72, 0.01); + Entity naerestEntity = seekNearLivingEntity(this, barrelRootPos, -40, 90, 1, 72, 0.01); if (naerestEntity != null) { entityData.set(TARGET_UUID, naerestEntity.getStringUUID()); } @@ -291,7 +292,7 @@ public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity, changeTargetTimer++; } - if (this.entityData.get(COOL_DOWN) == 0 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 1 && checkNoClip(target, barrelRootPos)) { + if (this.entityData.get(COOL_DOWN) == 0 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 1 && checkNoClip(this, target, barrelRootPos)) { this.entityData.set(COOL_DOWN, VehicleConfig.LASER_TOWER_COOLDOWN.get()); if (level() instanceof ServerLevel serverLevel) { diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/AutoAimable.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/AutoAimable.java new file mode 100644 index 000000000..3f4b24d0c --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/AutoAimable.java @@ -0,0 +1,66 @@ +package com.atsuishio.superbwarfare.entity.vehicle.base; + +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.VectorTool; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.monster.Enemy; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +import java.util.Comparator; +import java.util.stream.StreamSupport; + +import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter; + +public interface AutoAimable { + + // 防御类载具实体搜寻周围实体 + default Entity seekNearLivingEntity(Entity attacker, Vec3 pos, double minAngle, double maxAngle, double minRange, double seekRange, double size) { + return StreamSupport.stream(EntityFindUtil.getEntities(attacker.level()).getAll().spliterator(), false) + .filter(e -> { + // TODO 自定义目标列表 + if (e.distanceTo(attacker) > minRange + && e.distanceTo(attacker) <= seekRange + && canAim(pos, e, minAngle, maxAngle) + && !(e instanceof Player player && (player.isSpectator() || player.isCreative())) + && ((e instanceof LivingEntity living && living instanceof Enemy && living.getHealth() > 0) || e == seekThreateningEntity(attacker, size, pos) || basicEnemyFilter(e)) + && smokeFilter(e)) { + return checkNoClip(attacker, e, pos); + } + return false; + }).min(Comparator.comparingDouble(e -> e.distanceTo(attacker))).orElse(null); + } + + // 判断具有威胁的弹射物 + default Entity seekThreateningEntity(Entity attacker, double size, Vec3 pos) { + return StreamSupport.stream(EntityFindUtil.getEntities(attacker.level()).getAll().spliterator(), false) + .filter(e -> { + if (!e.onGround() && e instanceof Projectile projectile && (e.getBbWidth() >= size || e.getBbHeight() >= size) && + VectorTool.calculateAngle(e.getDeltaMovement().normalize(), e.position().vectorTo(attacker.position()).normalize()) < 30) { + return checkNoClip(attacker, e, pos) && basicEnemyProjectileFilter(projectile); + } + return false; + }).min(Comparator.comparingDouble(e -> e.distanceTo(attacker))).orElse(null); + } + + // 判断载具和目标之间有无障碍物 + default boolean checkNoClip(Entity attacker, Entity target, Vec3 pos) { + return attacker.level().clip(new ClipContext(pos, target.getEyePosition(), + ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, attacker)).getType() != HitResult.Type.BLOCK; + } + + boolean basicEnemyFilter(Entity pEntity); + + boolean basicEnemyProjectileFilter(Projectile projectile); + + static boolean canAim(Vec3 pos, Entity target, double minAngle, double maxAngle) { + Vec3 targetPos = new Vec3(target.getX(), target.getY() + target.getBbHeight() / 2, target.getZ()); + Vec3 toVec = pos.vectorTo(targetPos).normalize(); + double targetAngle = VehicleEntity.getXRotFromVector(toVec); + return minAngle < targetAngle && targetAngle < maxAngle; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java index 3a4a7abf0..a86538693 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java @@ -42,19 +42,15 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.entity.*; -import net.minecraft.world.entity.monster.Enemy; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.AbstractArrow; -import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.entity.projectile.ThrownPotion; import net.minecraft.world.entity.vehicle.DismountHelper; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.OnlyIn; @@ -67,17 +63,15 @@ import org.joml.Matrix4f; import org.joml.Vector4f; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.function.Function; -import java.util.stream.StreamSupport; import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; -import static com.atsuishio.superbwarfare.tools.SeekTool.smokeFilter; public abstract class VehicleEntity extends Entity { + public static final EntityDataAccessor HEALTH = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.FLOAT); public static final EntityDataAccessor LAST_ATTACKER_UUID = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.STRING); public static final EntityDataAccessor LAST_DRIVER_UUID = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.STRING); @@ -976,55 +970,6 @@ public abstract class VehicleEntity extends Entity { return getEyePosition(); } - //防御类载具实体搜寻周围实体 - public Entity seekNearLivingEntity(Vec3 pos, double minAngle, double maxAngle, double minRange, double seekRange, double size) { - return StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false) - .filter(e -> { - // TODO 自定义目标列表 - if (e.distanceTo(this) > minRange - && e.distanceTo(this) <= seekRange - && canAim(pos, e, minAngle, maxAngle) - && !(e instanceof Player player && (player.isSpectator() || player.isCreative())) - && ((e instanceof LivingEntity living && living instanceof Enemy && living.getHealth() > 0) || e == seekThreateningEntity(size, pos) || basicEnemyFilter(e)) - && smokeFilter(e)) { - return checkNoClip(e, pos); - } - return false; - }).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null); - } - - //判断具有威胁的弹射物 - public Entity seekThreateningEntity(double size, Vec3 pos) { - return StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false) - .filter(e -> { - if (!e.onGround() && e instanceof Projectile projectile && (e.getBbWidth() >= size || e.getBbHeight() >= size) && VectorTool.calculateAngle(e.getDeltaMovement().normalize(), e.position().vectorTo(this.position()).normalize()) < 30) { - return checkNoClip(e, pos) && basicEnemyProjectileFilter(projectile); - } - return false; - }).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null); - } - - //判断载具和目标之间有无障碍物 - public boolean checkNoClip(Entity target, Vec3 pos) { - return level().clip(new ClipContext(pos, target.getEyePosition(), - ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() != HitResult.Type.BLOCK; - } - - public boolean basicEnemyFilter(Entity pEntity) { - return false; - } - - public boolean basicEnemyProjectileFilter(Projectile projectile) { - return false; - } - - public static boolean canAim(Vec3 pos, Entity target, double minAngle, double maxAngle) { - Vec3 targetPos = new Vec3(target.getX(), target.getY() + target.getBbHeight() / 2, target.getZ()); - Vec3 toVec = pos.vectorTo(targetPos).normalize(); - double targetAngle = VehicleEntity.getXRotFromVector(toVec); - return minAngle < targetAngle && targetAngle < maxAngle; - } - @OnlyIn(Dist.CLIENT) public void renderFirstPersonOverlay(GuiGraphics guiGraphics, Font font, Player player, int screenWidth, int screenHeight, float scale) { if (!(this instanceof WeaponVehicleEntity weaponVehicle)) return;