All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.nukkit.entity.ai.executor.MeleeAttackExecutor Maven / Gradle / Ivy

There is a newer version: 1.20.40-r1
Show newest version
package cn.nukkit.entity.ai.executor;

import cn.nukkit.Player;
import cn.nukkit.Server;
import cn.nukkit.api.PowerNukkitXOnly;
import cn.nukkit.api.Since;
import cn.nukkit.entity.Entity;
import cn.nukkit.entity.EntityCanAttack;
import cn.nukkit.entity.EntityIntelligent;
import cn.nukkit.entity.EntityLiving;
import cn.nukkit.entity.ai.memory.MemoryType;
import cn.nukkit.event.entity.EntityDamageByEntityEvent;
import cn.nukkit.event.entity.EntityDamageEvent;
import cn.nukkit.inventory.EntityInventoryHolder;
import cn.nukkit.item.Item;
import cn.nukkit.item.enchantment.Enchantment;
import cn.nukkit.math.Vector3;
import cn.nukkit.network.protocol.EntityEventPacket;
import cn.nukkit.potion.Effect;

import java.util.EnumMap;
import java.util.Map;

/**
 * 通用近战攻击执行器.
 * 

* Universal melee attack actuator. */ @PowerNukkitXOnly @Since("1.6.0.0-PNX") public class MeleeAttackExecutor implements EntityControl, IBehaviorExecutor { protected MemoryType memory; protected float speed; protected int maxSenseRangeSquared; protected boolean clearDataWhenLose; protected int coolDown; protected int attackTick; protected Vector3 oldTarget; /** * 用来指定特定的攻击目标. *

* Used to specify a specific attack target. */ @Since("1.19.30-r1") protected Entity target; /** * 用来指定特定的视线目标 *

* Used to specify a specific look target. */ @Since("1.19.30-r1") protected Vector3 lookTarget; /** * 给予目标药水效果 *

* Give target potion effect */ @Since("1.19.63-r2") protected Effect[] effects; public MeleeAttackExecutor(MemoryType memory, float speed, int maxSenseRange, boolean clearDataWhenLose, int coolDown) { this(memory, speed, maxSenseRange, clearDataWhenLose, coolDown, new Effect[]{}); } /** * 近战攻击执行器 * * @param memory 用于读取攻击目标的记忆
Used to read the memory of the attack target * @param speed 移动向攻击目标的速度
The speed of movement towards the attacking target * @param maxSenseRange 最大获取攻击目标范围
The maximum range of attack targets * @param clearDataWhenLose 失去目标时清空记忆
Clear your memory when you lose your target * @param coolDown 攻击冷却时间(单位tick)
Attack cooldown (in tick) * @param effects 给予目标药水效果
Give the target potion effect */ public MeleeAttackExecutor(MemoryType memory, float speed, int maxSenseRange, boolean clearDataWhenLose, int coolDown, Effect... effects) { this.memory = memory; this.speed = speed; this.maxSenseRangeSquared = maxSenseRange * maxSenseRange; this.clearDataWhenLose = clearDataWhenLose; this.coolDown = coolDown; this.effects = effects; } @Override public boolean execute(EntityIntelligent entity) { attackTick++; if (entity.getBehaviorGroup().getMemoryStorage().isEmpty(memory)) return false; Entity newTarget = entity.getBehaviorGroup().getMemoryStorage().get(memory); //first is null if (this.target == null) { this.target = newTarget; } if (this.lookTarget == null) { this.lookTarget = target.clone(); } //some check if (!target.isAlive()) return false; else if (target instanceof Player player) { if (player.isCreative() || player.isSpectator() || !player.isOnline() || !entity.level.getName().equals(player.level.getName())) { return false; } } //update target and look target if (!this.target.getPosition().equals(newTarget.getPosition())) { target = newTarget; } if (!this.lookTarget.equals(newTarget.getLocation())) { lookTarget = newTarget.getLocation(); } //set some motion control if (!entity.isEnablePitch()) entity.setEnablePitch(true); if (entity.getMovementSpeed() != speed) entity.setMovementSpeed(speed); //set target and look target setRouteTarget(entity, this.target.clone()); setLookTarget(entity, this.lookTarget.clone()); var floor = target.floor(); if (oldTarget == null || !oldTarget.equals(floor)) entity.getBehaviorGroup().setForceUpdateRoute(true); oldTarget = floor; //attack logic if (entity.distanceSquared(target) <= 2.5 && attackTick > coolDown) { Item item = entity instanceof EntityInventoryHolder holder ? holder.getItemInHand() : Item.AIR_ITEM; float defaultDamage = 0; if (entity instanceof EntityCanAttack entityCanAttack) { defaultDamage = entityCanAttack.getDiffHandDamage(entity.getServer().getDifficulty()); } float itemDamage = item.getAttackDamage() + defaultDamage; Enchantment[] enchantments = item.getEnchantments(); if (item.applyEnchantments()) { for (Enchantment enchantment : enchantments) { itemDamage += enchantment.getDamageBonus(target); } } Map damage = new EnumMap<>(EntityDamageEvent.DamageModifier.class); damage.put(EntityDamageEvent.DamageModifier.BASE, itemDamage); float knockBack = 0.3f; if (item.applyEnchantments()) { Enchantment knockBackEnchantment = item.getEnchantment(Enchantment.ID_KNOCKBACK); if (knockBackEnchantment != null) { knockBack += knockBackEnchantment.getLevel() * 0.1f; } } EntityDamageByEntityEvent ev = new EntityDamageByEntityEvent(entity, target, EntityDamageEvent.DamageCause.ENTITY_ATTACK, damage, knockBack, item.applyEnchantments() ? enchantments : null); ev.setBreakShield(item.canBreakShield()); target.attack(ev); if (!ev.isCancelled()) { for (var e : effects) { target.addEffect(e); } playAttackAnimation(entity); attackTick = 0; } return target.getHealth() != 0; } return true; } @Override public void onStop(EntityIntelligent entity) { removeRouteTarget(entity); removeLookTarget(entity); //重置速度 entity.setMovementSpeed(EntityLiving.DEFAULT_SPEED); if (clearDataWhenLose) { entity.getBehaviorGroup().getMemoryStorage().clear(memory); } entity.setEnablePitch(false); this.target = null; this.lookTarget = null; } @Override public void onInterrupt(EntityIntelligent entity) { removeRouteTarget(entity); removeLookTarget(entity); //重置速度 entity.setMovementSpeed(EntityLiving.DEFAULT_SPEED); if (clearDataWhenLose) { entity.getBehaviorGroup().getMemoryStorage().clear(memory); } entity.setEnablePitch(false); this.target = null; this.lookTarget = null; } protected void playAttackAnimation(EntityIntelligent entity) { EntityEventPacket pk = new EntityEventPacket(); pk.eid = entity.getId(); pk.event = EntityEventPacket.ARM_SWING; Server.broadcastPacket(entity.getViewers().values(), pk); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy