初始化项目
This commit is contained in:
202
src/main/java/com/yaohun/petsystem/util/wolf/CustomWolf.java
Normal file
202
src/main/java/com/yaohun/petsystem/util/wolf/CustomWolf.java
Normal file
@@ -0,0 +1,202 @@
|
||||
package com.yaohun.petsystem.util.wolf;
|
||||
|
||||
import com.yaohun.petsystem.model.PetNbt;
|
||||
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.animal.wolf.Wolf;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.attribute.AttributeInstance;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 自定义的狼实体类,用于实现“跟随玩家”的宠物功能。
|
||||
* 继承原版 NMS Wolf 实体,通过 tick() 方法控制移动与传送。
|
||||
*/
|
||||
public class CustomWolf extends Wolf {
|
||||
|
||||
private static final double STOP_DISTANCE_SQ = 9.0D;
|
||||
private static final double TELEPORT_DISTANCE_SQ = 144.0D;
|
||||
private static final double LOOK_DISTANCE_SQ = 256.0D;
|
||||
private static final double FOLLOW_SPEED = 1.2D;
|
||||
private static final double DEFAULT_MOVEMENT_SPEED = 0.4D;
|
||||
private static final int PATH_RECALC_TICKS = 10;
|
||||
|
||||
private final UUID ownerUuid;
|
||||
|
||||
private int timeToRecalcPath = 0;
|
||||
|
||||
/**
|
||||
* 构造方法:初始化宠物实体
|
||||
*
|
||||
* @param world NMS 世界对象
|
||||
* @param owner 宠物主人(Bukkit Player)
|
||||
*/
|
||||
public CustomWolf(Level world, Player owner) {
|
||||
super(EntityType.WOLF, world);
|
||||
this.ownerUuid = owner.getUniqueId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 每 tick 执行的逻辑,控制宠物的移动与状态
|
||||
*/
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
Player owner = Bukkit.getPlayer(ownerUuid);
|
||||
if (owner == null || !owner.isOnline()) {
|
||||
this.discard();
|
||||
return;
|
||||
}
|
||||
if (owner.isDead()) {
|
||||
this.getNavigation().stop();
|
||||
return;
|
||||
}
|
||||
if (!owner.getWorld().equals(this.getBukkitEntity().getWorld())) {
|
||||
this.getNavigation().stop();
|
||||
teleportToOwnerLocation(owner);
|
||||
return;
|
||||
}
|
||||
|
||||
net.minecraft.world.entity.player.Player nmsOwner = ((CraftPlayer) owner).getHandle();
|
||||
|
||||
double distanceSq = this.distanceToSqr(nmsOwner);
|
||||
|
||||
if (distanceSq < STOP_DISTANCE_SQ) {
|
||||
this.getNavigation().stop();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean shouldTeleport = distanceSq > TELEPORT_DISTANCE_SQ;
|
||||
|
||||
if (!shouldTeleport && distanceSq <= LOOK_DISTANCE_SQ) {
|
||||
this.getLookControl().setLookAt(nmsOwner, 10.0F, this.getMaxHeadXRot());
|
||||
}
|
||||
|
||||
if (--this.timeToRecalcPath <= 0) {
|
||||
this.timeToRecalcPath = PATH_RECALC_TICKS;
|
||||
|
||||
if (shouldTeleport) {
|
||||
if (!tryTeleportNearOwner(nmsOwner)) {
|
||||
this.getNavigation().moveTo(nmsOwner, FOLLOW_SPEED);
|
||||
}
|
||||
} else {
|
||||
this.getNavigation().moveTo(nmsOwner, FOLLOW_SPEED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当宠物距离主人太远时,尝试在主人周围随机传送
|
||||
*
|
||||
* @param nmsOwner 主人 NMS 实体
|
||||
*/
|
||||
private boolean tryTeleportNearOwner(Entity nmsOwner) {
|
||||
Vec3 pos = nmsOwner.position();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int x = (int) Math.floor(pos.x) + (random.nextInt(7) - 3);
|
||||
int y = (int) Math.floor(pos.y);
|
||||
int z = (int) Math.floor(pos.z) + (random.nextInt(7) - 3);
|
||||
|
||||
Location location = new Location(getBukkitEntity().getWorld(), x + 0.5D, y, z + 0.5D);
|
||||
if (isSafeTeleportLocation(location)) {
|
||||
this.teleportTo(location.getX(), location.getY(), location.getZ());
|
||||
this.getNavigation().stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void teleportToOwnerLocation(Player owner) {
|
||||
Location location = owner.getLocation();
|
||||
if (isSafeTeleportLocation(location)) {
|
||||
this.getBukkitEntity().teleport(location);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSafeTeleportLocation(Location location) {
|
||||
Block feet = location.getBlock();
|
||||
Block head = feet.getRelative(0, 1, 0);
|
||||
Block ground = feet.getRelative(0, -1, 0);
|
||||
if (!feet.isPassable() || !head.isPassable() || !ground.getType().isSolid()) {
|
||||
return false;
|
||||
}
|
||||
if (!location.getWorld().equals(getBukkitEntity().getWorld())) {
|
||||
return true;
|
||||
}
|
||||
return this.level().noCollision(this, this.getBoundingBox().move(
|
||||
location.getX() - this.getX(),
|
||||
location.getY() - this.getY(),
|
||||
location.getZ() - this.getZ()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写受伤方法,防止主人伤害到自己的宠物
|
||||
*
|
||||
* @param source 伤害来源
|
||||
* @param amount 伤害数值
|
||||
* @return 是否成功造成伤害
|
||||
*/
|
||||
@Override
|
||||
public boolean hurtServer(ServerLevel level, DamageSource source, float amount) {
|
||||
Entity entity = source.getEntity();
|
||||
|
||||
if (entity != null && entity.getUUID().equals(ownerUuid)) {
|
||||
return false;
|
||||
}
|
||||
return super.hurtServer(level, source, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态方法:用于在 Bukkit 世界中生成并注册一只 CustomWolf
|
||||
*
|
||||
* @param owner 宠物主人
|
||||
* @return 新生成的 CustomWolf 实例
|
||||
*/
|
||||
public static CustomWolf spawnCustomWolf(Player owner, PetNbt petNbt) {
|
||||
CraftWorld world = (CraftWorld) owner.getWorld();
|
||||
Level nmsWorld = world.getHandle();
|
||||
|
||||
CustomWolf wolf = new CustomWolf(nmsWorld, owner);
|
||||
|
||||
wolf.setSilent(true);
|
||||
wolf.setOrderedToSit(false);
|
||||
wolf.setPos(owner.getLocation().getX(), owner.getLocation().getY(), owner.getLocation().getZ());
|
||||
|
||||
LivingEntity livingEntity = wolf.getBukkitLivingEntity();
|
||||
double maxHealth = Math.max(1.0D, petNbt.maxHealth);
|
||||
double health = Math.max(1.0D, Math.min(petNbt.health, maxHealth));
|
||||
double damage = Math.max(0.0D, petNbt.damage);
|
||||
|
||||
setAttribute(livingEntity, Attribute.MAX_HEALTH, maxHealth);
|
||||
setAttribute(livingEntity, Attribute.MOVEMENT_SPEED, DEFAULT_MOVEMENT_SPEED);
|
||||
setAttribute(livingEntity, Attribute.ATTACK_DAMAGE, damage);
|
||||
livingEntity.setHealth(health);
|
||||
|
||||
nmsWorld.addFreshEntity(wolf);
|
||||
|
||||
return wolf;
|
||||
}
|
||||
|
||||
private static void setAttribute(LivingEntity entity, Attribute attribute, double value) {
|
||||
AttributeInstance instance = entity.getAttribute(attribute);
|
||||
if (instance != null) {
|
||||
instance.setBaseValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user