完善并添加README.md

This commit is contained in:
yhy
2026-06-03 07:09:32 +08:00
parent 293a160856
commit 7cd89e59fd
47 changed files with 750 additions and 3726 deletions

View File

@@ -16,6 +16,7 @@ import com.yaohun.petsystem.manage.PetManager;
import com.yaohun.petsystem.manage.PlayerManager;
import com.yaohun.petsystem.model.PetNbt;
import com.yaohun.petsystem.util.MessageUtil;
import com.yaohun.petsystem.util.InventoryUtil;
import com.yaohun.petsystem.util.PetUtil;
import de.tr7zw.nbtapi.NBTItem;
import io.lumine.mythic.bukkit.MythicBukkit;
@@ -65,7 +66,9 @@ public class PetMain extends JavaPlugin {
@Override
public void onDisable() {
getPlayerManager().closeSaveAllData();
if (getPlayerManager() != null) {
getPlayerManager().closeSaveAllData();
}
}
@Override
@@ -203,6 +206,10 @@ public class PetMain extends JavaPlugin {
return true;
}
PetNbt petNbt = PetExpAPI.addExp(playerName, stack, exp);
if (petNbt == null) {
sender.sendMessage(prefix + "执行失败,未找到宠物配置.");
return true;
}
ItemStack petStack = PetUtil.refreshPetStackData(petNbt);
player.getInventory().setItemInMainHand(petNbt.saveIoItem(petStack));
sender.sendMessage(prefix + "给予 §6手持灵宠 §a经验: §d+" + exp);
@@ -234,7 +241,7 @@ public class PetMain extends JavaPlugin {
}
PetNbt petNbt = new PetNbt(petData);
ItemStack petStack = PetUtil.getPetStackDefault(petNbt);
player.getInventory().addItem(petNbt.saveIoItem(petStack));
InventoryUtil.giveOrDrop(player, petNbt.saveIoItem(petStack));
DemonAPI.sendMessage(sender, "玩家: §e" + playerName + " §a宠物: §6" + petKey + " §r[背包]");
return true;
}
@@ -262,4 +269,4 @@ public class PetMain extends JavaPlugin {
return playerManager;
}
}
}

View File

@@ -29,49 +29,24 @@ public class PetExpAPI {
return;
}
int petLevel = petNbt.level;
if (petLevel >= petData.getMaxLevel()) {
int levelCap = getLevelCap(petData, petNbt.evolution);
if (petLevel >= levelCap) {
return;
}
// 进化阶段判断
int evolution = petNbt.evolution;
if (evolution == 1) {
if (petLevel >= 20) {
return;
}
} else if (evolution == 2) {
if (petLevel >= 40) {
return;
}
} else if (evolution == 3) {
if (petLevel >= 60) {
return;
}
} else if (evolution == 4) {
if (petLevel >= 70) {
return;
}
} else if (evolution == 5) {
if (petLevel >= 75) {
return;
}
}
int needExp = LevelExpManager.getNeedExpValue(petLevel);
petNbt.setTotalExp(petNbt.totalExp + addExp);
int nowExp = petNbt.exp;
addExp = nowExp + addExp;
while (addExp >= needExp) {
if (petLevel < 0) {
break;
}
while (needExp > 0 && petLevel < levelCap && addExp >= needExp) {
addExp -= needExp;
petLevel++;
needExp = LevelExpManager.getNeedExpValue(petLevel);
bcmupLevelEvant(playerName, petLevel);
playerData.refreshPetStack();
}
petNbt.setExp(addExp);
petNbt.setLevel(petLevel);
playerData.refreshPetStack();
playerData.savePlayerData();
}
@@ -86,7 +61,8 @@ public class PetExpAPI {
PetNbt petNbt = new PetNbt();
petNbt.loadNbtData(nbtItem);
int petLevel = petNbt.level;
if (petLevel >= petData.getMaxLevel()) {
int levelCap = getLevelCap(petData, petNbt.evolution);
if (petLevel >= levelCap) {
return petNbt;
}
int needExp = LevelExpManager.getNeedExpValue(petLevel);
@@ -94,10 +70,7 @@ public class PetExpAPI {
int nowExp = petNbt.exp;
addExp = nowExp + addExp;
while (addExp >= needExp) {
if (petLevel < 0) {
break;
}
while (needExp > 0 && petLevel < levelCap && addExp >= needExp) {
addExp -= needExp;
petLevel++;
needExp = LevelExpManager.getNeedExpValue(petLevel);
@@ -108,6 +81,22 @@ public class PetExpAPI {
return petNbt;
}
private static int getLevelCap(PetData petData, int evolution) {
int maxLevel = petData.getMaxLevel();
int evolutionLimit = switch (evolution) {
case 1 -> 20;
case 2 -> 40;
case 3 -> 60;
case 4 -> 70;
case 5 -> 75;
default -> maxLevel;
};
if (maxLevel <= 0) {
return evolutionLimit;
}
return Math.min(maxLevel, evolutionLimit);
}
public static void bcmupLevelEvant(String playerName, int level) {
boolean butt = false;
if (level == 10 || level == 20 || level == 30 || level == 40 || level == 50 ||
@@ -119,4 +108,4 @@ public class PetExpAPI {
// Bukkit.broadcastMessage("§f[§c§l公告§f] §a玩家§e"+playName+"§a本月器师手礼达到了 §7[§e§lLv."+level+"§7]");
}
}
}
}

View File

@@ -44,14 +44,21 @@ public class Config {
}
private static void loadQualityShowMap(FileConfiguration config) {
qualityShowMap.clear();
qualityShowMap.put(0, "§f普通");
ConfigurationSection section = config.getConfigurationSection("QualityShow");
if (section == null) {
Bukkit.getConsoleSender().sendMessage("- 资质稀有度: §f" + qualityShowMap.size() + "");
return;
}
for (String levelKey : section.getKeys(false)) {
int level = Integer.parseInt(levelKey);
String show = section.getString(levelKey).replace("&", "§");
qualityShowMap.put(level, show);
try {
int level = Integer.parseInt(levelKey);
String show = section.getString(levelKey, "§f普通").replace("&", "§");
qualityShowMap.put(level, show);
} catch (NumberFormatException e) {
Bukkit.getConsoleSender().sendMessage("§c[宠物系统] 资质显示配置无效: " + levelKey);
}
}
Bukkit.getConsoleSender().sendMessage("- 资质稀有度: §f" + qualityShowMap.size() + "");
}
@@ -62,8 +69,8 @@ public class Config {
try {
material = Material.valueOf(stackType.toUpperCase());
} catch (IllegalArgumentException e) {
Bukkit.getConsoleSender().sendMessage("- 宠物模板载入: §c失败");
return;
material = Material.DIAMOND;
Bukkit.getConsoleSender().sendMessage("- 宠物模板载入: §c材质无效已使用默认材质");
}
String stackName = config.getString("Pet_Stack_Template.name", "§f宠物");
List<String> stringList = config.getStringList("Pet_Stack_Template.lore");
@@ -80,6 +87,9 @@ public class Config {
}
public static ItemStack getPetStackTemplate() {
if (petStackTemplate == null) {
petStackTemplate = new ItemStack(Material.DIAMOND);
}
return petStackTemplate.clone();
}
@@ -119,7 +129,7 @@ public class Config {
public static String getQualityShow(int value) {
Map.Entry<Integer, String> entry = qualityShowMap.floorEntry(value);
return entry != null ? entry.getValue() : qualityShowMap.get(0);
return entry != null ? entry.getValue() : "§f普通";
}
public static String getHealthChar(int percent) {
@@ -138,4 +148,4 @@ public class Config {
return "§f<image:default:level_tag_" + level + ">";
}
}
}

View File

@@ -5,6 +5,7 @@ import com.yaohun.petsystem.config.Config;
import com.yaohun.petsystem.data.PlayerData;
import com.yaohun.petsystem.gui.holder.CarryGuiHolder;
import com.yaohun.petsystem.manage.PlayerManager;
import com.yaohun.petsystem.util.InventoryUtil;
import com.yaohun.petsystem.util.MessageUtil;
import de.tr7zw.nbtapi.NBTItem;
import me.Demon.DemonPlugin.DemonAPI;
@@ -54,7 +55,7 @@ public class CarryGui implements Listener {
playerManager.removePetCall(playerName);
playerData.refreshPetStack();
ItemStack petStack = playerData.getPetStack();
player.getInventory().addItem(petStack);
InventoryUtil.giveOrDrop(player, petStack);
playerData.setPetStack(DemonAPI.getErrItems());
playerData.savePlayerData();
inv.setItem(PET_SLOT, Config.getItemStack("carry_gui"));
@@ -78,7 +79,7 @@ public class CarryGui implements Listener {
playerManager.removePetCall(playerName);
playerData.refreshPetStack();
ItemStack petStack = playerData.getPetStack();
player.getInventory().addItem(petStack);
InventoryUtil.giveOrDrop(player, petStack);
playerData.setPetStack(DemonAPI.getErrItems());
playerData.savePlayerData();
MessageUtil.sendMessageKey(player, "pet_stack_carry_takeOut", Sound.ENTITY_PLAYER_LEVELUP);

View File

@@ -8,6 +8,7 @@ import com.yaohun.petsystem.gui.holder.FeedingGuiHolder;
import com.yaohun.petsystem.manage.LevelExpManager;
import com.yaohun.petsystem.manage.PlayerManager;
import com.yaohun.petsystem.model.PetNbt;
import com.yaohun.petsystem.util.InventoryUtil;
import com.yaohun.petsystem.util.MessageUtil;
import com.yaohun.petsystem.util.PetUtil;
import de.tr7zw.nbtapi.NBTItem;
@@ -96,7 +97,7 @@ public class FeedingGui implements Listener {
// 判断槽位内是否已存在物品
ItemStack foodStack = getFooedStack(inv);
if (foodStack != null) {
player.getInventory().addItem(foodStack);
InventoryUtil.giveOrDrop(player, foodStack);
}
e.setCurrentItem(null);
inv.setItem(FOOD_SLOT, clickStack);
@@ -110,7 +111,7 @@ public class FeedingGui implements Listener {
// 判断槽位内是否已存在物品
ItemStack foodStack = getFooedStack(inv);
if (foodStack != null) {
player.getInventory().addItem(foodStack);
InventoryUtil.giveOrDrop(player, foodStack);
inv.setItem(FOOD_SLOT, DemonAPI.getPaperAirItems());
}
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
@@ -199,8 +200,8 @@ public class FeedingGui implements Listener {
ItemStack stack = getFooedStack(inv);
if (stack != null) {
inv.setItem(FOOD_SLOT, DemonAPI.getPaperAirItems());
player.getInventory().addItem(stack);
InventoryUtil.giveOrDrop(player, stack);
}
}
}
}
}

View File

@@ -9,6 +9,7 @@ import com.yaohun.petsystem.gui.holder.MainGuiHolder;
import com.yaohun.petsystem.listener.RePetNameListener;
import com.yaohun.petsystem.manage.PlayerManager;
import com.yaohun.petsystem.model.PetNbt;
import com.yaohun.petsystem.util.InventoryUtil;
import com.yaohun.petsystem.util.MessageUtil;
import com.yaohun.petsystem.util.PetUtil;
import me.Demon.DemonPlugin.DemonAPI;
@@ -150,7 +151,7 @@ public class MainGui implements Listener {
playerManager.removePetCall(playerName);
playerData.refreshPetStack();
ItemStack petStack = playerData.getPetStack();
player.getInventory().addItem(petStack);
InventoryUtil.giveOrDrop(player, petStack);
playerData.setPetStack(DemonAPI.getErrItems());
playerData.savePlayerData();
player.closeInventory();
@@ -182,4 +183,4 @@ public class MainGui implements Listener {
}
}
}
}
}

View File

@@ -38,6 +38,10 @@ public class PlayerListener implements Listener {
if (petUUID == null) {
return;
}
if (petUUID.equals(e.getEntity().getUniqueId())) {
e.setCancelled(true);
return;
}
Entity entity = Bukkit.getEntity(petUUID);
if (entity instanceof Wolf wolf) {
wolf.setTarget(target);
@@ -74,6 +78,6 @@ public class PlayerListener implements Listener {
Player player = e.getPlayer();
String playerName = player.getName();
PlayerManager playerManager = PetMain.getPlayerManager();
playerManager.removePetCall(playerName);
playerManager.closeSaveData(playerName);
}
}

View File

@@ -5,38 +5,39 @@ import com.yaohun.petsystem.config.Config;
import com.yaohun.petsystem.data.PlayerData;
import com.yaohun.petsystem.manage.PlayerManager;
import com.yaohun.petsystem.util.MessageUtil;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.UUID;
public class RePetNameListener implements Listener {
private static List<UUID> reNameList = new ArrayList<>();
private static final Set<UUID> reNameList = Collections.newSetFromMap(new ConcurrentHashMap<>());
public static void addReNameUUID(UUID uuid) {
if (!reNameList.contains(uuid)) {
reNameList.add(uuid);
}
reNameList.add(uuid);
}
@EventHandler
public void onChat(AsyncPlayerChatEvent e) {
Player player = e.getPlayer();
UUID uuid = player.getUniqueId();
if (reNameList.isEmpty()) {
return;
}
if (!reNameList.contains(uuid)) {
if (!reNameList.remove(uuid)) {
return;
}
e.setCancelled(true);
reNameList.remove(uuid);
String reName = e.getMessage();
Bukkit.getScheduler().runTask(PetMain.inst(), () -> handleRename(player, reName));
}
private void handleRename(Player player, String reName) {
String playerName = player.getName();
PlayerManager playerManager = PetMain.getPlayerManager();
PlayerData playerData = playerManager.getPlayerData(playerName);
@@ -44,7 +45,6 @@ public class RePetNameListener implements Listener {
MessageUtil.sendMessageKey(player, "pet_rename_no_pets", Sound.ENTITY_VILLAGER_NO);
return;
}
String reName = e.getMessage();
if (reName.isEmpty()) {
MessageUtil.sendMessageKey(player, "pet_rename_empty", Sound.ENTITY_VILLAGER_NO);
return;
@@ -59,4 +59,4 @@ public class RePetNameListener implements Listener {
String message = Config.getLanguage("pet_rename_success");
MessageUtil.sendMessage(player, message.replace("{petName}", newName), Sound.ENTITY_PLAYER_LEVELUP);
}
}
}

View File

@@ -2,6 +2,7 @@ package com.yaohun.petsystem.manage;
import com.yaohun.petsystem.PetMain;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -13,17 +14,43 @@ public class LevelExpManager {
private static HashMap<Integer, Integer> needExpMap = new HashMap<>();
public static void reloadLevelManager(PetMain plugin) {
needExpMap.clear();
ConfigurationSection section = plugin.getConfig().getConfigurationSection("NeedExpSettings");
if (section != null) {
loadNeedExpSection(section);
} else {
loadLegacyNeedExpFile(plugin);
}
Bukkit.getConsoleSender().sendMessage("§7- 等级经验配置: §f" + needExpMap.size() + "");
}
private static void loadNeedExpSection(ConfigurationSection section) {
for (String levelKey : section.getKeys(false)) {
try {
int level = Integer.parseInt(levelKey);
int needExp = section.getInt(levelKey);
needExpMap.put(level, needExp);
} catch (NumberFormatException e) {
Bukkit.getConsoleSender().sendMessage("§c[宠物系统] 等级经验配置无效: " + levelKey);
}
}
}
private static void loadLegacyNeedExpFile(PetMain plugin) {
File file = new File(plugin.getDataFolder() + "/Settings", "needExp.yml");
if (file.getParentFile().exists()) {
file.getParentFile().mkdirs();
if (!file.exists()) {
return;
}
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
for (String levelKey : config.getKeys(false)) {
int level = Integer.parseInt(levelKey);
int needExp = config.getInt(levelKey);
needExpMap.put(level, needExp);
try {
int level = Integer.parseInt(levelKey);
int needExp = config.getInt(levelKey);
needExpMap.put(level, needExp);
} catch (NumberFormatException e) {
Bukkit.getConsoleSender().sendMessage("§c[宠物系统] 旧等级经验配置无效: " + levelKey);
}
}
Bukkit.getConsoleSender().sendMessage("§7- 等级经验配置: §f" + needExpMap.size() + "");
}
public static int getNeedExpValue(int level) {
@@ -32,4 +59,4 @@ public class LevelExpManager {
}
return 1000000;
}
}
}

View File

@@ -6,6 +6,7 @@ import com.yaohun.petsystem.data.PetData;
import com.yaohun.petsystem.data.PetSQL;
import com.yaohun.petsystem.data.PlayerData;
import com.yaohun.petsystem.event.PetCallEvent;
import com.yaohun.petsystem.util.InventoryUtil;
import com.yaohun.petsystem.util.MessageUtil;
import com.yaohun.petsystem.util.model.BetterModelUtil;
import com.yaohun.petsystem.util.wolf.CustomWolf;
@@ -43,10 +44,10 @@ public class PlayerManager {
}
public void closeSaveData(String playerName) {
PlayerData playerData = getPlayerData(playerName);
playerData.savePlayerData();
playerDataMap.remove(playerName);
PlayerData playerData = playerDataMap.remove(playerName);
if (playerData != null) {
playerData.savePlayerData();
}
removePetCall(playerName);
}
@@ -244,7 +245,7 @@ public class PlayerManager {
if (!nbtItem.hasKey("petKey")) {
Bukkit.getConsoleSender().sendMessage("[日志 - 宠物] 未检测到宠物petKey的Nbt标识.");
}
player.getInventory().addItem(petStack);
InventoryUtil.giveOrDrop(player, petStack);
playerData.setPetStack(DemonAPI.getErrItems());
playerData.savePlayerData();
MessageUtil.sendMessageKey(player, "pet_stack_carry_takeOut", Sound.ENTITY_PLAYER_LEVELUP);

View File

@@ -0,0 +1,24 @@
package com.yaohun.petsystem.util;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
public class InventoryUtil {
public static void giveOrDrop(Player player, ItemStack itemStack) {
if (player == null || itemStack == null) {
return;
}
HashMap<Integer, ItemStack> leftoverMap = player.getInventory().addItem(itemStack);
if (leftoverMap.isEmpty()) {
return;
}
for (ItemStack leftover : leftoverMap.values()) {
player.getWorld().dropItemNaturally(player.getLocation(), leftover);
}
MessageUtil.sendMessage(player, "§e背包空间不足剩余物品已掉落在当前位置。", Sound.ENTITY_ITEM_PICKUP);
}
}

View File

@@ -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) {