初始化项目

This commit is contained in:
yhy
2026-06-03 06:25:44 +08:00
commit 293a160856
65 changed files with 6417 additions and 0 deletions

View 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);
}
}
}