95 行
3.3 KiB
Java
95 行
3.3 KiB
Java
package autodig.client.service;
|
||
|
||
import autodig.client.config.DigConfig;
|
||
import net.minecraft.client.MinecraftClient;
|
||
import net.minecraft.entity.Entity;
|
||
import net.minecraft.entity.LivingEntity;
|
||
import net.minecraft.entity.mob.Monster;
|
||
import net.minecraft.util.math.Box;
|
||
import net.minecraft.util.math.Vec3d;
|
||
|
||
/**
|
||
* 杀戮光环服务。
|
||
*
|
||
* <p>在开关开启时,自动攻击以玩家为中心、指定半径内最近的敌对生物
|
||
* ({@link Monster})。攻击前会转向目标方向;"安全模式"开启时,
|
||
* 玩家生命过低则停止攻击、保命优先。</p>
|
||
*/
|
||
public final class KillAura {
|
||
|
||
/** 攻击节流:每 N tick 才允许挥一刀,避免疯狂连点 */
|
||
private int attackCooldownTicks;
|
||
|
||
/**
|
||
* 每帧调用。执行杀戮光环逻辑(开关关闭时直接返回)。
|
||
*
|
||
* @param config 挖矿配置
|
||
*/
|
||
public void tick(DigConfig config) {
|
||
MinecraftClient client = MinecraftClient.getInstance();
|
||
if (client.player == null || client.world == null || client.interactionManager == null) {
|
||
return;
|
||
}
|
||
if (!config.killAura) {
|
||
return;
|
||
}
|
||
net.minecraft.entity.player.PlayerEntity player = client.player;
|
||
if (player.isDead()) {
|
||
return;
|
||
}
|
||
// 安全模式:血线过低不出击
|
||
if (config.killAuraSafe) {
|
||
double health = player.getHealth() / Math.max(player.getMaxHealth(), 1.0) * 100.0;
|
||
if (health < config.healthFleeThreshold) {
|
||
return;
|
||
}
|
||
}
|
||
// 挥刀节流
|
||
if (this.attackCooldownTicks > 0) {
|
||
this.attackCooldownTicks--;
|
||
return;
|
||
}
|
||
// 攻击冷却未转好则等待
|
||
if (player.getAttackCooldownProgress(0.5f) < 1.0f) {
|
||
return;
|
||
}
|
||
Entity target = this.findNearestHostile(client, player, config.killRange);
|
||
if (target == null) {
|
||
return;
|
||
}
|
||
// 转向目标
|
||
this.faceEntity(player, target);
|
||
client.interactionManager.attackEntity(player, target);
|
||
this.attackCooldownTicks = 4; // 约 4 tick 一刀
|
||
}
|
||
|
||
/** 在玩家周围范围内找最近的敌对生物。 */
|
||
private Entity findNearestHostile(MinecraftClient client, LivingEntity player, double range) {
|
||
range = Math.max(2.0, range);
|
||
Box box = player.getBoundingBox().expand(range);
|
||
Entity best = null;
|
||
double bestDist = Double.MAX_VALUE;
|
||
for (Entity e : client.world.getEntitiesByClass(Entity.class, box, e -> e instanceof Monster && e.isAlive())) {
|
||
double d = e.squaredDistanceTo(player);
|
||
if (d < bestDist) {
|
||
bestDist = d;
|
||
best = e;
|
||
}
|
||
}
|
||
return best;
|
||
}
|
||
|
||
/** 让玩家面朝向实体。 */
|
||
private void faceEntity(LivingEntity player, Entity target) {
|
||
Vec3d p = player.getEyePos();
|
||
Vec3d t = target.getEyePos();
|
||
double dx = t.x - p.x;
|
||
double dy = t.y - p.y;
|
||
double dz = t.z - p.z;
|
||
double d = Math.sqrt(dx * dx + dz * dz);
|
||
float yaw = (float) (Math.toDegrees(Math.atan2(dz, dx)) - 90.0);
|
||
float pitch = (float) (-Math.toDegrees(Math.atan2(dy, Math.max(d, 0.0001))));
|
||
player.setYaw(yaw);
|
||
player.setPitch(pitch);
|
||
}
|
||
} |