完善并添加README.md
This commit is contained in:
@@ -1,130 +1,110 @@
|
||||
package com.yaohun.petsystem.util.wolf;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
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 org.bukkit.entity.Wolf;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 自定义的狼实体类,用于实现“跟随玩家”的宠物功能。
|
||||
* 继承原版 NMS Wolf 实体,通过 tick() 方法控制移动与传送。
|
||||
*/
|
||||
public class CustomWolf extends Wolf {
|
||||
public class CustomWolf {
|
||||
|
||||
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 static final long FOLLOW_INTERVAL_TICKS = 10L;
|
||||
|
||||
private final UUID ownerUuid;
|
||||
private final Wolf wolf;
|
||||
|
||||
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();
|
||||
private CustomWolf(UUID ownerUuid, Wolf wolf) {
|
||||
this.ownerUuid = ownerUuid;
|
||||
this.wolf = wolf;
|
||||
startFollowTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* 每 tick 执行的逻辑,控制宠物的移动与状态
|
||||
*/
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
public Wolf getBukkitEntity() {
|
||||
return wolf;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
public LivingEntity getBukkitLivingEntity() {
|
||||
return wolf;
|
||||
}
|
||||
|
||||
net.minecraft.world.entity.player.Player nmsOwner = ((CraftPlayer) owner).getHandle();
|
||||
public UUID getUUID() {
|
||||
return wolf.getUniqueId();
|
||||
}
|
||||
|
||||
double distanceSq = this.distanceToSqr(nmsOwner);
|
||||
public boolean isRemoved() {
|
||||
return !wolf.isValid();
|
||||
}
|
||||
|
||||
if (distanceSq < STOP_DISTANCE_SQ) {
|
||||
this.getNavigation().stop();
|
||||
return;
|
||||
}
|
||||
public static CustomWolf spawnCustomWolf(Player owner, PetNbt petNbt) {
|
||||
Wolf wolf = owner.getWorld().spawn(owner.getLocation(), Wolf.class, entity -> {
|
||||
entity.setSilent(true);
|
||||
entity.setTamed(true);
|
||||
entity.setOwner(owner);
|
||||
entity.setSitting(false);
|
||||
entity.setRemoveWhenFarAway(false);
|
||||
|
||||
boolean shouldTeleport = distanceSq > TELEPORT_DISTANCE_SQ;
|
||||
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);
|
||||
|
||||
if (!shouldTeleport && distanceSq <= LOOK_DISTANCE_SQ) {
|
||||
this.getLookControl().setLookAt(nmsOwner, 10.0F, this.getMaxHeadXRot());
|
||||
}
|
||||
setAttribute(entity, Attribute.MAX_HEALTH, maxHealth);
|
||||
setAttribute(entity, Attribute.MOVEMENT_SPEED, DEFAULT_MOVEMENT_SPEED);
|
||||
setAttribute(entity, Attribute.ATTACK_DAMAGE, damage);
|
||||
entity.setHealth(health);
|
||||
});
|
||||
return new CustomWolf(owner.getUniqueId(), wolf);
|
||||
}
|
||||
|
||||
if (--this.timeToRecalcPath <= 0) {
|
||||
this.timeToRecalcPath = PATH_RECALC_TICKS;
|
||||
|
||||
if (shouldTeleport) {
|
||||
if (!tryTeleportNearOwner(nmsOwner)) {
|
||||
this.getNavigation().moveTo(nmsOwner, FOLLOW_SPEED);
|
||||
private void startFollowTask() {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!wolf.isValid() || wolf.isDead()) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
Player owner = Bukkit.getPlayer(ownerUuid);
|
||||
if (owner == null || !owner.isOnline()) {
|
||||
wolf.remove();
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
if (owner.isDead()) {
|
||||
wolf.setTarget(null);
|
||||
return;
|
||||
}
|
||||
if (!owner.getWorld().equals(wolf.getWorld())) {
|
||||
teleportToOwner(owner);
|
||||
return;
|
||||
}
|
||||
double distanceSq = wolf.getLocation().distanceSquared(owner.getLocation());
|
||||
if (distanceSq < STOP_DISTANCE_SQ) {
|
||||
wolf.setTarget(null);
|
||||
return;
|
||||
}
|
||||
if (distanceSq > TELEPORT_DISTANCE_SQ) {
|
||||
teleportToOwner(owner);
|
||||
}
|
||||
} else {
|
||||
this.getNavigation().moveTo(nmsOwner, FOLLOW_SPEED);
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(PetMain.inst(), FOLLOW_INTERVAL_TICKS, FOLLOW_INTERVAL_TICKS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当宠物距离主人太远时,尝试在主人周围随机传送
|
||||
*
|
||||
* @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) {
|
||||
private void teleportToOwner(Player owner) {
|
||||
Location location = owner.getLocation();
|
||||
if (isSafeTeleportLocation(location)) {
|
||||
this.getBukkitEntity().teleport(location);
|
||||
wolf.teleport(location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,65 +112,7 @@ public class CustomWolf extends Wolf {
|
||||
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;
|
||||
return feet.isPassable() && head.isPassable() && ground.getType().isSolid();
|
||||
}
|
||||
|
||||
private static void setAttribute(LivingEntity entity, Attribute attribute, double value) {
|
||||
|
||||
Reference in New Issue
Block a user