完善并添加README.md
This commit is contained in:
508
README.md
Normal file
508
README.md
Normal file
@@ -0,0 +1,508 @@
|
||||
# AuPet 灵宠系统
|
||||
|
||||
AuPet 是一个面向 Minecraft Paper 1.21 系列服务端的灵宠插件。
|
||||
|
||||
插件围绕“宠物物品 + 玩家携带数据 + 宠物召唤实体 + GUI 管理”构建,适合用于服务器宠物养成、宠物技能展示、宠物出战和宠物经验成长玩法。
|
||||
|
||||
核心功能:
|
||||
|
||||
- 玩家通过 GUI 查看当前携带的灵宠、等级、经验、血量和资质
|
||||
- 支持将手持宠物物品携带到玩家数据中
|
||||
- 支持从玩家数据中取出宠物物品
|
||||
- 支持召唤和召回宠物实体
|
||||
- 支持 BetterModel 模型展示
|
||||
- 支持 MythicMobs 技能触发
|
||||
- 支持宠物喂养、经验增加和进化阶段控制
|
||||
- 支持宠物改名
|
||||
- 支持 MySQL 持久化玩家宠物数据
|
||||
- 提供宠物召唤事件,方便其他插件监听
|
||||
|
||||
简单理解:
|
||||
|
||||
```yml
|
||||
AuPet = 灵宠物品管理 + 宠物数据持久化 + 宠物 GUI + 宠物召唤 + 技能触发
|
||||
玩家 = 携带、召唤、喂养、改名和培养宠物
|
||||
管理员 = 配置宠物类型、模型、技能、等级经验和 GUI 展示
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 运行环境
|
||||
|
||||
## 服务端版本
|
||||
|
||||
```yml
|
||||
Minecraft: 1.21.x
|
||||
推荐服务端: Paper
|
||||
Java: 21
|
||||
```
|
||||
|
||||
当前构建配置使用:
|
||||
|
||||
```yml
|
||||
Paper API: 1.21.8-R0.1-SNAPSHOT
|
||||
plugin.yml api-version: 1.21
|
||||
```
|
||||
|
||||
## 前置依赖
|
||||
|
||||
插件代码依赖以下组件:
|
||||
|
||||
```yml
|
||||
DemonAPI
|
||||
CraftDataManager
|
||||
NBTAPI
|
||||
MythicMobs
|
||||
BetterModel
|
||||
```
|
||||
|
||||
服务器启动前应确认这些插件或依赖已正确安装,并且版本与构建配置兼容。
|
||||
|
||||
------
|
||||
|
||||
# 安装方式
|
||||
|
||||
## 第一步:构建插件
|
||||
|
||||
在项目根目录执行:
|
||||
|
||||
```bash
|
||||
mvn -q -DskipTests package
|
||||
```
|
||||
|
||||
构建成功后会生成:
|
||||
|
||||
```yml
|
||||
target/AuPet-1.0-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
## 第二步:放入服务器
|
||||
|
||||
将插件 jar 放入服务器插件目录:
|
||||
|
||||
```yml
|
||||
plugins/AuPet.jar
|
||||
```
|
||||
|
||||
同时放入前置依赖插件。
|
||||
|
||||
## 第三步:启动服务器
|
||||
|
||||
首次启动后会生成插件配置目录。
|
||||
|
||||
控制台应能看到宠物系统参数、等级经验配置和宠物类型加载日志。
|
||||
|
||||
------
|
||||
|
||||
# 目录结构
|
||||
|
||||
## 插件默认资源
|
||||
|
||||
```yml
|
||||
config.yml
|
||||
lang.yml
|
||||
plugin.yml
|
||||
```
|
||||
|
||||
## 插件数据目录
|
||||
|
||||
宠物类型配置读取自:
|
||||
|
||||
```yml
|
||||
plugins/AuPet/PetData/
|
||||
```
|
||||
|
||||
玩家携带宠物数据保存到 MySQL 表:
|
||||
|
||||
```yml
|
||||
aupets_data
|
||||
```
|
||||
|
||||
表字段:
|
||||
|
||||
```yml
|
||||
PLAYERNAME: 玩家名
|
||||
PETSTACK: 序列化后的宠物 ItemStack
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 玩家命令
|
||||
|
||||
## 打开主界面
|
||||
|
||||
```yml
|
||||
/apet
|
||||
/apet open
|
||||
```
|
||||
|
||||
玩家未携带宠物时会打开携带界面;已携带宠物时会打开宠物主界面。
|
||||
|
||||
## 携带或取出宠物
|
||||
|
||||
```yml
|
||||
/apet carry
|
||||
```
|
||||
|
||||
当玩家未携带宠物时:
|
||||
|
||||
- 需要手持带有 `petKey` NBT 的宠物物品
|
||||
- 执行后会将手持宠物写入玩家数据
|
||||
- 手持栏会被清空
|
||||
|
||||
当玩家已携带宠物时:
|
||||
|
||||
- 会收回已召唤宠物
|
||||
- 刷新宠物物品数据
|
||||
- 将宠物物品返还给玩家
|
||||
|
||||
如果玩家背包已满,剩余物品会掉落在玩家当前位置。
|
||||
|
||||
## 召唤或召回宠物
|
||||
|
||||
```yml
|
||||
/apet call
|
||||
```
|
||||
|
||||
当宠物未出战时会召唤宠物;当宠物已出战时会召回宠物。
|
||||
|
||||
召唤时会:
|
||||
|
||||
- 生成狼实体作为宠物基础实体
|
||||
- 应用宠物血量、攻击、移动速度属性
|
||||
- 加载 BetterModel 模型
|
||||
- 触发配置的出生技能
|
||||
- 触发 `PetCallEvent`
|
||||
|
||||
------
|
||||
|
||||
# 管理员命令
|
||||
|
||||
管理员命令需要:
|
||||
|
||||
```yml
|
||||
admin.use
|
||||
```
|
||||
|
||||
## 查看帮助
|
||||
|
||||
```yml
|
||||
/apet
|
||||
```
|
||||
|
||||
## 重载配置
|
||||
|
||||
```yml
|
||||
/apet reload
|
||||
```
|
||||
|
||||
重载内容:
|
||||
|
||||
- 语言文件
|
||||
- 默认配置
|
||||
- 等级经验配置
|
||||
- 宠物模板
|
||||
- GUI 物品配置
|
||||
- 品质显示配置
|
||||
- 宠物类型配置
|
||||
|
||||
## 给予宠物
|
||||
|
||||
```yml
|
||||
/apet give 宠物Key 玩家名
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```yml
|
||||
/apet give cat Steve
|
||||
```
|
||||
|
||||
插件会读取 `PetData` 中对应宠物配置,生成默认宠物物品并发放给目标玩家。
|
||||
|
||||
## 增加宠物经验
|
||||
|
||||
```yml
|
||||
/apet addexp 经验 玩家名
|
||||
```
|
||||
|
||||
给玩家当前携带的宠物增加经验。
|
||||
|
||||
## 增加手持宠物经验
|
||||
|
||||
```yml
|
||||
/apet addexp 经验 玩家名 true
|
||||
```
|
||||
|
||||
给目标玩家手持的宠物物品增加经验。
|
||||
|
||||
------
|
||||
|
||||
# 宠物配置
|
||||
|
||||
宠物配置文件位于:
|
||||
|
||||
```yml
|
||||
plugins/AuPet/PetData/宠物Key.yml
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```yml
|
||||
PetName: "§a森林灵宠"
|
||||
MaxLevel: 30
|
||||
ModelId: forest_pet
|
||||
CustomIconModelId: 10001
|
||||
AccessChannels:
|
||||
- "活动获取"
|
||||
- "商城购买"
|
||||
SummonSkill: "pet_spawn_effect"
|
||||
DeathSkill: "default"
|
||||
Skills:
|
||||
bite:
|
||||
mmSkill: "pet_bite"
|
||||
needLevel: 1
|
||||
trigger: "onAttack"
|
||||
coolDown: 5000
|
||||
item:
|
||||
name: "&a撕咬"
|
||||
lore:
|
||||
- "&7触发条件: 攻击时"
|
||||
- "&7冷却: 5秒"
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
```yml
|
||||
PetName: 宠物显示名
|
||||
MaxLevel: 宠物最大等级
|
||||
ModelId: BetterModel 模型 ID
|
||||
CustomIconModelId: 宠物物品 CustomModelData
|
||||
AccessChannels: 获取渠道展示
|
||||
SummonSkill: 召唤时触发的 MythicMobs 技能,default 表示不触发
|
||||
DeathSkill: 死亡技能预留字段
|
||||
Skills: 宠物技能列表
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 技能触发器
|
||||
|
||||
当前代码支持:
|
||||
|
||||
```yml
|
||||
onAttack: 玩家攻击实体时触发
|
||||
onDamaged: 玩家受到伤害时触发
|
||||
onSpawn: 宠物召唤后触发 SummonSkill
|
||||
```
|
||||
|
||||
技能由 MythicMobs 执行。
|
||||
|
||||
技能冷却使用玩家 UUID 和技能名作为冷却键。
|
||||
|
||||
------
|
||||
|
||||
# 等级经验配置
|
||||
|
||||
默认配置节点:
|
||||
|
||||
```yml
|
||||
NeedExpSettings:
|
||||
1: 10000
|
||||
2: 10000
|
||||
3: 10000
|
||||
30: -1
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
```yml
|
||||
正数: 当前等级升到下一级所需经验
|
||||
-1: 终止等级,不再继续升级
|
||||
```
|
||||
|
||||
宠物还会受到进化阶段限制:
|
||||
|
||||
```yml
|
||||
进化 1: 最高 20 级
|
||||
进化 2: 最高 40 级
|
||||
进化 3: 最高 60 级
|
||||
进化 4: 最高 70 级
|
||||
进化 5: 最高 75 级
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# GUI 功能
|
||||
|
||||
## 主界面
|
||||
|
||||
主界面展示:
|
||||
|
||||
- 宠物物品
|
||||
- 宠物技能
|
||||
- 宠物资质
|
||||
- 召唤或召回按钮
|
||||
- 喂养入口
|
||||
- 改名入口
|
||||
|
||||
## 携带界面
|
||||
|
||||
用于携带或取出宠物。
|
||||
|
||||
玩家可以通过点击背包中的宠物物品,将其写入当前携带数据。
|
||||
|
||||
## 喂养界面
|
||||
|
||||
支持放入带有以下 NBT 的道具:
|
||||
|
||||
```yml
|
||||
petAppleExp: 增加经验
|
||||
petAppleUp: 进化阶段要求等级
|
||||
```
|
||||
|
||||
关闭界面时,如果喂养槽仍有物品,会自动返还玩家。
|
||||
|
||||
背包满时,剩余物会掉落到玩家当前位置。
|
||||
|
||||
------
|
||||
|
||||
# 数据保存机制
|
||||
|
||||
玩家数据以序列化 ItemStack 形式保存到 MySQL。
|
||||
|
||||
主要保存时机:
|
||||
|
||||
- 携带宠物
|
||||
- 取出宠物
|
||||
- 喂养加经验
|
||||
- 宠物改名
|
||||
- 玩家退出
|
||||
- 插件关闭
|
||||
|
||||
注意:
|
||||
|
||||
```yml
|
||||
当前数据库读写仍是同步模型。
|
||||
在线人数较多或数据库延迟较高时,建议后续改造为异步加载和保存队列。
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# API 与事件
|
||||
|
||||
## 宠物经验 API
|
||||
|
||||
其他代码可以调用:
|
||||
|
||||
```java
|
||||
PetExpAPI.addExp(player, 1000);
|
||||
```
|
||||
|
||||
也可以对手持宠物物品增加经验:
|
||||
|
||||
```java
|
||||
PetNbt petNbt = PetExpAPI.addExp(playerName, itemStack, 1000);
|
||||
```
|
||||
|
||||
## 宠物召唤事件
|
||||
|
||||
宠物召唤成功后会触发:
|
||||
|
||||
```java
|
||||
PetCallEvent
|
||||
```
|
||||
|
||||
可读取:
|
||||
|
||||
```java
|
||||
event.getOwner();
|
||||
event.getCutomName();
|
||||
event.getEntityUuid();
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 构建验证
|
||||
|
||||
本地验证命令:
|
||||
|
||||
```bash
|
||||
mvn -q test
|
||||
mvn -q -DskipTests package
|
||||
```
|
||||
|
||||
当前验证结果:
|
||||
|
||||
```yml
|
||||
mvn test: 通过
|
||||
mvn package: 通过
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 常见问题
|
||||
|
||||
## 插件启动时报缺少类
|
||||
|
||||
检查前置依赖是否安装:
|
||||
|
||||
```yml
|
||||
DemonAPI
|
||||
CraftDataManager
|
||||
NBTAPI
|
||||
MythicMobs
|
||||
BetterModel
|
||||
```
|
||||
|
||||
同时检查这些依赖的版本是否与构建配置兼容。
|
||||
|
||||
## 执行 /apet give 找不到宠物
|
||||
|
||||
检查:
|
||||
|
||||
```yml
|
||||
plugins/AuPet/PetData/宠物Key.yml 是否存在
|
||||
文件名是否与命令中的宠物Key一致
|
||||
配置是否能被 YAML 正常读取
|
||||
```
|
||||
|
||||
## 召唤宠物失败
|
||||
|
||||
检查:
|
||||
|
||||
```yml
|
||||
BetterModel 中是否存在对应 ModelId
|
||||
宠物血量是否大于 0
|
||||
MythicMobs 技能名是否正确
|
||||
```
|
||||
|
||||
## 宠物无法升级
|
||||
|
||||
检查:
|
||||
|
||||
```yml
|
||||
NeedExpSettings 当前等级是否为 -1
|
||||
宠物是否已达到 MaxLevel
|
||||
宠物是否已达到当前进化阶段上限
|
||||
```
|
||||
|
||||
## GUI 按钮显示异常
|
||||
|
||||
检查:
|
||||
|
||||
```yml
|
||||
config.yml 中 GuiItemData 是否完整
|
||||
lang.yml 中语言键是否完整
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 维护建议
|
||||
|
||||
- 发布前同步检查 `plugin.yml` 版本号。
|
||||
- 修改宠物配置后执行 `/apet reload`。
|
||||
- 新增宠物前先在测试服验证 BetterModel 模型和 MythicMobs 技能。
|
||||
- 不建议在高峰期进行大量玩家数据迁移。
|
||||
- 后续优先补充数据库异步队列和 MockBukkit 测试。
|
||||
- 每次更新后至少完成一次登录、携带宠物、打开 GUI、召唤宠物、喂养、退出保存的冒烟测试。
|
||||
604
README2.md
604
README2.md
@@ -1,604 +0,0 @@
|
||||
# 1.AuOnlineReward 是什么?
|
||||
|
||||
AuOnlineReward 是一个 Minecraft 1.12.2 Bukkit / Spigot 在线奖励插件。
|
||||
|
||||
它用于根据玩家在线时间发放阶段奖励,并根据阶段奖励领取次数解锁累积奖励。
|
||||
|
||||
核心功能:
|
||||
|
||||
- 玩家通过 GUI 查看在线信息和奖励状态
|
||||
- 支持每日在线阶段奖励
|
||||
- 支持累积领取次数奖励
|
||||
- 支持每日在线数据刷新
|
||||
- 支持月度在线数据刷新
|
||||
- 支持配置奖励物品和奖励命令
|
||||
- 支持通过 API 获取玩家在线时间
|
||||
- 支持奖励领取事件,方便其他插件监听
|
||||
|
||||
简单理解:
|
||||
|
||||
```yml
|
||||
AuOnlineReward = 在线时长统计 + 在线奖励 GUI + 奖励命令执行
|
||||
玩家 = 在线积累时间并领取奖励
|
||||
管理员 = 配置奖励物品、奖励条件和发奖命令
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 2.运行环境
|
||||
|
||||
## 服务端版本
|
||||
|
||||
```yml
|
||||
Minecraft: 1.12.2
|
||||
服务端: Bukkit / Spigot / Paper
|
||||
Java: 8
|
||||
```
|
||||
|
||||
## 前置插件
|
||||
|
||||
AuOnlineReward 依赖 DemonAPI。
|
||||
|
||||
`plugin.yml` 中已经声明:
|
||||
|
||||
```yml
|
||||
depend:
|
||||
- DemonAPI
|
||||
```
|
||||
|
||||
服务器启动前必须确保 DemonAPI 已放入插件目录。
|
||||
|
||||
------
|
||||
|
||||
# 3.安装方式
|
||||
|
||||
## 第一步:放入插件
|
||||
|
||||
将插件 jar 放入服务器插件目录:
|
||||
|
||||
```yml
|
||||
plugins/AuOnlineReward.jar
|
||||
```
|
||||
|
||||
同时放入前置插件:
|
||||
|
||||
```yml
|
||||
plugins/DemonAPI.jar
|
||||
```
|
||||
|
||||
## 第二步:启动服务器
|
||||
|
||||
首次启动后会生成插件配置文件。
|
||||
|
||||
## 第三步:检查加载
|
||||
|
||||
控制台应能看到插件正常启用,没有缺少 DemonAPI 的报错。
|
||||
|
||||
------
|
||||
|
||||
# 4.目录结构
|
||||
|
||||
## 插件配置目录
|
||||
|
||||
默认配置和语言文件位于:
|
||||
|
||||
```yml
|
||||
plugins/AuOnlineReward/config.yml
|
||||
plugins/AuOnlineReward/language.yml
|
||||
```
|
||||
|
||||
## 玩家数据目录
|
||||
|
||||
玩家在线数据会保存到:
|
||||
|
||||
```yml
|
||||
plugins/AuData/AuOnlineReward/玩家名.yml
|
||||
```
|
||||
|
||||
玩家数据示例:
|
||||
|
||||
```yml
|
||||
OnlineData:
|
||||
todayOnline: 0
|
||||
totalOnline: 0
|
||||
monthOnline: 0
|
||||
totalSign: 0
|
||||
signAmount: 0
|
||||
currentReward: MinuteReward_30
|
||||
collectionTime: 1717200000000
|
||||
offlineTime: 1717200000000
|
||||
receivedList: []
|
||||
permanentReceived: []
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
```yml
|
||||
todayOnline: 今日在线秒数
|
||||
totalOnline: 累积在线秒数
|
||||
monthOnline: 本月在线秒数
|
||||
totalSign: 总计领取阶段奖励次数
|
||||
signAmount: 当前轮累积领取阶段奖励次数
|
||||
currentReward: 当前可领取的阶段奖励
|
||||
collectionTime: 上次阶段奖励领取时间
|
||||
offlineTime: 上次离线时间
|
||||
receivedList: 今日已领取阶段奖励
|
||||
permanentReceived: 当前轮已领取累积奖励
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 5.玩家命令
|
||||
|
||||
## 打开在线奖励界面
|
||||
|
||||
```yml
|
||||
/auonline open
|
||||
```
|
||||
|
||||
玩家执行后会打开在线福利 GUI。
|
||||
|
||||
GUI 中会显示:
|
||||
|
||||
- 累积在线时间
|
||||
- 本月在线时间
|
||||
- 今日在线时间
|
||||
- 总计领取奖励次数
|
||||
- 阶段奖励状态
|
||||
- 累积奖励状态
|
||||
|
||||
注意:
|
||||
|
||||
```yml
|
||||
每日 00:10 前无法打开 GUI
|
||||
这是为了避免跨日数据刷新期间领取状态异常
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 6.管理员命令
|
||||
|
||||
管理员命令需要 OP 权限。
|
||||
|
||||
## 查看命令帮助
|
||||
|
||||
```yml
|
||||
/auonline
|
||||
```
|
||||
|
||||
## 重载配置
|
||||
|
||||
```yml
|
||||
/auonline reload
|
||||
```
|
||||
|
||||
重载内容:
|
||||
|
||||
- 奖励配置
|
||||
- 语言配置
|
||||
- GUI 标题
|
||||
- 奖励显示文本
|
||||
|
||||
## 刷新所有玩家每日数据
|
||||
|
||||
```yml
|
||||
/auonline dayrefresh
|
||||
```
|
||||
|
||||
作用:
|
||||
|
||||
- 清空今日在线时间
|
||||
- 重置当前阶段奖励
|
||||
- 重置今日阶段奖励领取记录
|
||||
- 重新载入在线玩家数据
|
||||
|
||||
## 刷新指定玩家每日数据
|
||||
|
||||
```yml
|
||||
/auonline dayrefresh 玩家名
|
||||
```
|
||||
|
||||
只刷新指定玩家的每日在线奖励数据。
|
||||
|
||||
## 查看玩家数据
|
||||
|
||||
```yml
|
||||
/auonline info 玩家名
|
||||
/auonline look 玩家名
|
||||
```
|
||||
|
||||
不填写玩家名时,默认查看执行者自己的数据。
|
||||
|
||||
## 查看今日在线排行
|
||||
|
||||
```yml
|
||||
/auonline topDay
|
||||
/auonline top
|
||||
```
|
||||
|
||||
显示当前已缓存玩家的今日在线排行。
|
||||
|
||||
------
|
||||
|
||||
# 7.奖励类型
|
||||
|
||||
AuOnlineReward 当前包含两类奖励。
|
||||
|
||||
## 阶段奖励
|
||||
|
||||
配置节点通常以 `MinuteReward_` 开头。
|
||||
|
||||
示例:
|
||||
|
||||
```yml
|
||||
RewardData:
|
||||
MinuteReward_30:
|
||||
slot: 10
|
||||
needOnline: 1800
|
||||
needOnlineTime: 1800
|
||||
itemStack:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: IRON_INGOT
|
||||
commands:
|
||||
- eco give %player% 500
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
```yml
|
||||
slot: GUI 中的格子位置
|
||||
needOnline: 距离上次阶段奖励领取需要等待的秒数
|
||||
needOnlineTime: 今日在线秒数要求
|
||||
itemStack: GUI 中展示的奖励物品
|
||||
commands: 领取后执行的命令
|
||||
```
|
||||
|
||||
阶段奖励领取成功后:
|
||||
|
||||
- 增加当前轮阶段领取次数
|
||||
- 增加总计阶段领取次数
|
||||
- 写入今日已领取记录
|
||||
- 切换到下一个阶段奖励
|
||||
- 执行奖励命令
|
||||
- 保存玩家数据
|
||||
|
||||
## 累积奖励
|
||||
|
||||
配置节点通常以 `SignReward_` 开头。
|
||||
|
||||
示例:
|
||||
|
||||
```yml
|
||||
RewardData:
|
||||
SignReward_15:
|
||||
slot: 29
|
||||
needOnline: 25
|
||||
itemStack:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: CHEST
|
||||
commands:
|
||||
- eco give %player% 10000
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
```yml
|
||||
slot: GUI 中的格子位置
|
||||
needOnline: 需要累计领取多少次阶段奖励
|
||||
itemStack: GUI 中展示的奖励物品
|
||||
commands: 领取后执行的命令
|
||||
```
|
||||
|
||||
累积奖励领取成功后会写入 `permanentReceived`。
|
||||
|
||||
当领取 `SignReward_Max` 后:
|
||||
|
||||
```yml
|
||||
signAmount 会重置为 0
|
||||
permanentReceived 会清空
|
||||
进入下一轮累积奖励
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 8.奖励命令怎么写?
|
||||
|
||||
奖励命令写在 `commands` 列表中。
|
||||
|
||||
示例:
|
||||
|
||||
```yml
|
||||
commands:
|
||||
- eco give %player% 500
|
||||
- points give %player% 10
|
||||
- bcm &a玩家 &e%player% &a领取了在线奖励
|
||||
```
|
||||
|
||||
支持占位符:
|
||||
|
||||
```yml
|
||||
%player% 玩家名
|
||||
%itemName% 奖励物品显示名
|
||||
```
|
||||
|
||||
如果命令包含 `msg:`,会向玩家发送消息,而不是由控制台执行命令。
|
||||
|
||||
示例:
|
||||
|
||||
```yml
|
||||
commands:
|
||||
- "msg:&a你领取了在线奖励"
|
||||
```
|
||||
|
||||
颜色代码支持:
|
||||
|
||||
```yml
|
||||
&a &b &c &e &f
|
||||
```
|
||||
|
||||
插件执行时会转换为 Minecraft 颜色符号。
|
||||
|
||||
------
|
||||
|
||||
# 9.语言文件怎么写?
|
||||
|
||||
语言文件为:
|
||||
|
||||
```yml
|
||||
plugins/AuOnlineReward/language.yml
|
||||
```
|
||||
|
||||
主要节点:
|
||||
|
||||
```yml
|
||||
Online-Gui:
|
||||
Title: "§r日常福利 - 累积在线豪礼相赠"
|
||||
Received: "§a§l★ §7领取状态: §a已领取"
|
||||
Not-Started: "§c§l★ §7领取状态: §c未开始"
|
||||
Pending: "§b§l★ §7领取状态: §b待领取"
|
||||
Total-Online: "§7累积在线: §a%time%"
|
||||
Monthly-Online: "§7本月在线: §a%time%"
|
||||
Daily-Online: "§7今日在线: §a%time%"
|
||||
Total-Rewards: "§7总计领取奖励: §a%amount%次"
|
||||
Message:
|
||||
Reward-Progress: "你还需要获取§e[%amount%次]§a阶段奖励才能领取奖励。"
|
||||
Wait-Time: "您还需要等待§e[%time%秒]§a才能领取该奖励。"
|
||||
Daily-Requirement: "你需要今日在线§e[%time%秒]§a才能领取该奖励。"
|
||||
Already-Claimed: "你已经领取过这个累积奖励。"
|
||||
Not-Available: "这个阶段奖励尚未开启,暂时无法领取。"
|
||||
```
|
||||
|
||||
修改语言文件后执行:
|
||||
|
||||
```yml
|
||||
/auonline reload
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 10.在线时间刷新机制
|
||||
|
||||
## 在线计时
|
||||
|
||||
插件会定时统计在线玩家的在线时长。
|
||||
|
||||
统计字段:
|
||||
|
||||
```yml
|
||||
todayOnline: 今日在线
|
||||
monthOnline: 本月在线
|
||||
totalOnline: 累积在线
|
||||
```
|
||||
|
||||
玩家退出时会补算最后一段在线时间,并保存玩家数据。
|
||||
|
||||
## 每日刷新
|
||||
|
||||
每日刷新会处理:
|
||||
|
||||
```yml
|
||||
todayOnline = 0
|
||||
currentReward = MinuteReward_30
|
||||
receivedList = []
|
||||
collectionTime = 当前时间
|
||||
```
|
||||
|
||||
## 月度刷新
|
||||
|
||||
月度刷新会处理:
|
||||
|
||||
```yml
|
||||
monthOnline = 0
|
||||
```
|
||||
|
||||
## 刷新性能说明
|
||||
|
||||
批量刷新玩家文件时,插件会将 YAML 文件读写放到异步任务中执行。
|
||||
|
||||
刷新完成后,再回到主线程重新载入在线玩家。
|
||||
|
||||
这样可以降低大量玩家数据文件刷新时对主线程的影响。
|
||||
|
||||
------
|
||||
|
||||
# 11.API 调用
|
||||
|
||||
其他插件可以通过 `OnlineAPI` 获取玩家在线时间。
|
||||
|
||||
## 获取今日在线分钟数
|
||||
|
||||
```java
|
||||
int minutes = OnlineAPI.getTime(playerName);
|
||||
```
|
||||
|
||||
## 获取本月在线分钟数
|
||||
|
||||
```java
|
||||
int minutes = OnlineAPI.getTimeMonth(playerName);
|
||||
```
|
||||
|
||||
## 获取累积在线分钟数
|
||||
|
||||
```java
|
||||
int minutes = OnlineAPI.getTimeTotal(playerName);
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
```yml
|
||||
API 返回单位是分钟
|
||||
底层玩家数据保存单位是秒
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 12.事件监听
|
||||
|
||||
玩家成功领取奖励后会触发:
|
||||
|
||||
```java
|
||||
OnlineRewardEvent
|
||||
```
|
||||
|
||||
监听示例:
|
||||
|
||||
```java
|
||||
@EventHandler
|
||||
public void onOnlineReward(OnlineRewardEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
String playerName = event.getPlayerName();
|
||||
String rewardKey = event.getOnlineData().getRewardKey();
|
||||
}
|
||||
```
|
||||
|
||||
事件可用于:
|
||||
|
||||
- 记录领奖日志
|
||||
- 触发额外奖励
|
||||
- 接入活动系统
|
||||
- 接入统计系统
|
||||
|
||||
------
|
||||
|
||||
# 13.配置示例
|
||||
|
||||
## 阶段奖励示例
|
||||
|
||||
```yml
|
||||
RewardData:
|
||||
MinuteReward_30:
|
||||
slot: 10
|
||||
needOnline: 1800
|
||||
needOnlineTime: 1800
|
||||
itemStack:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: IRON_INGOT
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: §6§l阶段奖励 I
|
||||
lore:
|
||||
- §7还差 §c%time% §7才能领取
|
||||
- §e金币 §e*500
|
||||
commands:
|
||||
- eco give %player% 500
|
||||
```
|
||||
|
||||
## 累积奖励示例
|
||||
|
||||
```yml
|
||||
RewardData:
|
||||
SignReward_15:
|
||||
slot: 29
|
||||
needOnline: 25
|
||||
itemStack:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: CHEST
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: TILE_ENTITY
|
||||
display-name: §6§l累积打卡奖励 I
|
||||
lore:
|
||||
- §7还需领取 §c%amounut% §7阶段奖励
|
||||
- §e金币 §e*10000
|
||||
commands:
|
||||
- eco give %player% 10000
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
```yml
|
||||
阶段奖励 lore 中需要包含 %time%
|
||||
累积奖励 lore 中需要包含 %amounut%
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 14.常见问题
|
||||
|
||||
## 执行 /auonline open 没反应
|
||||
|
||||
检查:
|
||||
|
||||
```yml
|
||||
是否在每日 00:10 之前
|
||||
DemonAPI 是否正常加载
|
||||
language.yml 中 Title 是否存在
|
||||
config.yml 中 RewardData 是否存在
|
||||
```
|
||||
|
||||
## 奖励无法领取
|
||||
|
||||
检查:
|
||||
|
||||
```yml
|
||||
今日在线秒数是否达到 needOnlineTime
|
||||
距离上次领取是否达到 needOnline
|
||||
currentReward 是否等于当前点击的阶段奖励
|
||||
该奖励是否已经在 receivedList 中
|
||||
```
|
||||
|
||||
## 累积奖励无法领取
|
||||
|
||||
检查:
|
||||
|
||||
```yml
|
||||
signAmount 是否达到 needOnline
|
||||
该奖励是否已经在 permanentReceived 中
|
||||
```
|
||||
|
||||
## 修改配置后没有变化
|
||||
|
||||
执行:
|
||||
|
||||
```yml
|
||||
/auonline reload
|
||||
```
|
||||
|
||||
如果删除了奖励节点,重载后旧奖励缓存会被清理。
|
||||
|
||||
## 玩家数据异常
|
||||
|
||||
可以刷新指定玩家每日数据:
|
||||
|
||||
```yml
|
||||
/auonline dayrefresh 玩家名
|
||||
```
|
||||
|
||||
也可以检查玩家数据文件:
|
||||
|
||||
```yml
|
||||
plugins/AuData/AuOnlineReward/玩家名.yml
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
# 15.维护建议
|
||||
|
||||
- 修改奖励配置前,先备份 `config.yml`。
|
||||
- 大量玩家数据刷新建议避开服务器高峰期。
|
||||
- 奖励命令应先在测试服验证,避免命令拼写错误导致奖励无法发放。
|
||||
- 不建议把高耗时命令放入奖励命令列表。
|
||||
- 修改语言或奖励配置后,使用 `/auonline reload` 重载。
|
||||
- 发布新版本时,应同步检查 `plugin.yml` 的版本号。
|
||||
- 每次更新后建议至少完成一次登录、打开 GUI、领取奖励、退出保存的冒烟测试。
|
||||
51
pom.xml
51
pom.xml
@@ -21,6 +21,10 @@
|
||||
<id>papermc-repo</id>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>public-survive</id>
|
||||
<url>https://repo.aurora-pixels.com/repository/public-survive/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
||||
@@ -32,46 +36,29 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>local</groupId>
|
||||
<artifactId>demon-api</artifactId>
|
||||
<version>local</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${parent.project.dir}/lib/DemonAPI.jar</systemPath>
|
||||
<groupId>de.tr7zw.nbtapi.plugin</groupId>
|
||||
<artifactId>NBTAPI</artifactId>
|
||||
<version>2.15.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>local</groupId>
|
||||
<artifactId>nbt-api</artifactId>
|
||||
<version>local</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${parent.project.dir}/lib/item-nbt-api-plugin-2.15.1.jar</systemPath>
|
||||
<groupId>me.Demon.DemonPlugin</groupId>
|
||||
<artifactId>DemonAPI</artifactId>
|
||||
<version>2.1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>local</groupId>
|
||||
<artifactId>mythicmobs</artifactId>
|
||||
<version>local</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${parent.project.dir}/lib/MythicMobs-5.9.1.jar</systemPath>
|
||||
<groupId>io.lumine.mythic.bukkit</groupId>
|
||||
<artifactId>MythicMobs</artifactId>
|
||||
<version>5.9.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>local</groupId>
|
||||
<artifactId>bettermodel</artifactId>
|
||||
<version>local</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${parent.project.dir}/lib/BetterModel-2.2.0-paper.jar</systemPath>
|
||||
<groupId>kr.toxicity.model.paper</groupId>
|
||||
<artifactId>BetterModel</artifactId>
|
||||
<version>2.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>local</groupId>
|
||||
<artifactId>craft-data-manager</artifactId>
|
||||
<version>local</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${parent.project.dir}/lib/CraftDataManager.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>local</groupId>
|
||||
<artifactId>paper-1.21.8-mapped-server</artifactId>
|
||||
<version>1.21.8</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${parent.project.dir}/.gradle/caches/paperweight/taskCache/mappedServerJar.jar</systemPath>
|
||||
<groupId>com.tianyu.datamanager</groupId>
|
||||
<artifactId>CraftDataManager</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,7 +200,7 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
24
src/main/java/com/yaohun/petsystem/util/InventoryUtil.java
Normal file
24
src/main/java/com/yaohun/petsystem/util/InventoryUtil.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
name: AuPet
|
||||
main: com.yaohun.petsystem.PetMain
|
||||
version: 1.0.1
|
||||
version: 1.0.2
|
||||
api-version: 1.21
|
||||
softdepend:
|
||||
- DemonAPI
|
||||
- NBTAPI
|
||||
- MythicMobs
|
||||
- BetterModel
|
||||
- CraftDataManager
|
||||
commands:
|
||||
apet:
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
package com.yaohun.petsystem;
|
||||
|
||||
import com.yaohun.petsystem.api.PetExpAPI;
|
||||
import com.yaohun.petsystem.config.Config;
|
||||
import com.yaohun.petsystem.data.PetData;
|
||||
import com.yaohun.petsystem.data.PetSQL;
|
||||
import com.yaohun.petsystem.data.PlayerData;
|
||||
import com.yaohun.petsystem.data.SkillData;
|
||||
import com.yaohun.petsystem.gui.CarryGui;
|
||||
import com.yaohun.petsystem.gui.FeedingGui;
|
||||
import com.yaohun.petsystem.gui.MainGui;
|
||||
import com.yaohun.petsystem.listener.PetSkillsListener;
|
||||
import com.yaohun.petsystem.listener.PlayerListener;
|
||||
import com.yaohun.petsystem.listener.RePetNameListener;
|
||||
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.PetUtil;
|
||||
import de.tr7zw.nbtapi.NBTItem;
|
||||
import io.lumine.mythic.bukkit.MythicBukkit;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import me.Demon.DemonPlugin.Util.CDTimeAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PetMain extends JavaPlugin {
|
||||
|
||||
private static PetMain instance;
|
||||
private static PlayerManager playerManager;
|
||||
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
saveDefaultConfig();
|
||||
|
||||
PetSQL.init();
|
||||
|
||||
MessageUtil.init(this);
|
||||
Config.reloadConfig(this);
|
||||
PetManager.reloadPetManager();
|
||||
playerManager = new PlayerManager();
|
||||
|
||||
getServer().getPluginManager().registerEvents(new MainGui(), this);
|
||||
getServer().getPluginManager().registerEvents(new FeedingGui(), this);
|
||||
getServer().getPluginManager().registerEvents(new CarryGui(), this);
|
||||
|
||||
getServer().getPluginManager().registerEvents(new PlayerListener(), this);
|
||||
getServer().getPluginManager().registerEvents(new RePetNameListener(), this);
|
||||
|
||||
getServer().getPluginManager().registerEvents(new PetSkillsListener(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getPlayerManager().closeSaveAllData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!sender.hasPermission("admin.use")) {
|
||||
if(args.length == 0){
|
||||
if (sender instanceof Player player) {
|
||||
MainGui.openGui(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
String prefix = "§f[§c灵宠§f] §a";
|
||||
if (args.length == 0) {
|
||||
sender.sendMessage("§r");
|
||||
sender.sendMessage("§e==----- ======= §6宠物系统 §e======= -----==");
|
||||
sender.sendMessage("§2/" + label + " call §f- §2召唤宠物");
|
||||
sender.sendMessage("§2/" + label + " carry §f- §2携带手持宠物");
|
||||
if (sender.isOp()) {
|
||||
sender.sendMessage("§2/" + label + " addExp §e[经验] §b<玩家> §7true §f- §2给予玩家宠物");
|
||||
sender.sendMessage("§2/" + label + " give §e[宠物] §b<玩家> §f- §2给予玩家宠物");
|
||||
sender.sendMessage("§2/" + label + " reload §f- §2重载配置文件");
|
||||
}
|
||||
sender.sendMessage("§e==----- ======= §6宠物系统 §e======= -----==");
|
||||
sender.sendMessage("§r");
|
||||
return true;
|
||||
}
|
||||
if ("reload".equalsIgnoreCase(args[0])) {
|
||||
MessageUtil.init(this);
|
||||
Config.reloadConfig(this);
|
||||
PetManager.reloadPetManager();
|
||||
sender.sendMessage(prefix + "配置文件已重载完成.");
|
||||
return true;
|
||||
}
|
||||
if ("open".equalsIgnoreCase(args[0])) {
|
||||
if (sender instanceof Player player) {
|
||||
MainGui.openGui(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ("test".equalsIgnoreCase(args[0])) {
|
||||
if (sender instanceof Player player) {
|
||||
// 判断玩家是否携带宠物
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
// 获取宠物相关数据
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
if(playerData.isPetStackNull()){
|
||||
return true;
|
||||
}
|
||||
PetData petData = playerData.getPetNbt().petData;
|
||||
LinkedHashMap<String , SkillData> skillDataMap = petData.getSkillDataMap();
|
||||
for(SkillData skillData : skillDataMap.values()){
|
||||
String cdKey = "skill_"+skillData.getSkillName();
|
||||
if ("onAttack".equalsIgnoreCase(skillData.getTrigger())) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
if(!CDTimeAPI.isCD(uuid,cdKey)) {
|
||||
long cooldown = skillData.getCoolDown();
|
||||
CDTimeAPI.setPlayerCD(uuid, cdKey, cooldown);
|
||||
String mmSkill = skillData.getMmSkill();
|
||||
// 执行技能
|
||||
MythicBukkit.inst().getAPIHelper().castSkill(
|
||||
player,
|
||||
mmSkill,
|
||||
player.getLocation()
|
||||
);
|
||||
player.sendMessage("[调试 - 宠物技能] 触发条件: onAttack 触发技能: "+mmSkill);
|
||||
break;
|
||||
} else {
|
||||
sender.sendMessage("# 拦截 冷却中...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ("carry".equalsIgnoreCase(args[0])) {
|
||||
String playerName = sender.getName();
|
||||
if (args.length >= 2) {
|
||||
playerName = args[1];
|
||||
}
|
||||
Player player = Bukkit.getPlayer(playerName);
|
||||
if (player == null || !player.isOnline()) {
|
||||
sender.sendMessage(prefix + "玩家 " + playerName + " 不在线.");
|
||||
return true;
|
||||
}
|
||||
getPlayerManager().carryPetStackData(player);
|
||||
return true;
|
||||
}
|
||||
if ("call".equalsIgnoreCase(args[0])) {
|
||||
String playerName = sender.getName();
|
||||
if (args.length >= 2) {
|
||||
playerName = args[1];
|
||||
}
|
||||
Player player = Bukkit.getPlayer(playerName);
|
||||
if (player == null || !player.isOnline()) {
|
||||
sender.sendMessage(prefix + "玩家 " + playerName + " 不在线.");
|
||||
return true;
|
||||
}
|
||||
if (playerManager.isPetCallExit(playerName)) {
|
||||
playerManager.removePetCall(playerName);
|
||||
sender.sendMessage(prefix + "已收回 §6" + playerName + " §a的宠物.");
|
||||
} else {
|
||||
playerManager.callPet(player);
|
||||
sender.sendMessage(prefix + "已召唤 §6" + playerName + " §a的宠物.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ("addexp".equalsIgnoreCase(args[0])) {
|
||||
if (args.length == 1) {
|
||||
sender.sendMessage(prefix + "缺少数值参数.");
|
||||
return true;
|
||||
}
|
||||
int exp = Integer.parseInt(args[1]);
|
||||
// 获取玩家数据
|
||||
String playerName = sender.getName();
|
||||
if (args.length >= 3) {
|
||||
playerName = args[2];
|
||||
}
|
||||
Player player = Bukkit.getPlayer(playerName);
|
||||
if (player == null || !player.isOnline()) {
|
||||
sender.sendMessage(prefix + "玩家 " + playerName + " 不在线.");
|
||||
return true;
|
||||
}
|
||||
if (args.length >= 4) {
|
||||
ItemStack stack = player.getInventory().getItemInMainHand();
|
||||
if (DemonAPI.itemIsNull(stack) || DemonAPI.itemIsLore(stack)) {
|
||||
sender.sendMessage(prefix + "执行失败,你需要将灵宠拿在手中.");
|
||||
return true;
|
||||
}
|
||||
NBTItem nbtItem = new NBTItem(stack);
|
||||
if (!nbtItem.hasKey("petKey")) {
|
||||
sender.sendMessage(prefix + "执行失败,你需要将灵宠拿在手中.");
|
||||
return true;
|
||||
}
|
||||
PetNbt petNbt = PetExpAPI.addExp(playerName, stack, exp);
|
||||
ItemStack petStack = PetUtil.refreshPetStackData(petNbt);
|
||||
player.getInventory().setItemInMainHand(petNbt.saveIoItem(petStack));
|
||||
sender.sendMessage(prefix + "给予 §6手持灵宠 §a经验: §d+" + exp);
|
||||
} else {
|
||||
PetExpAPI.addExp(player, exp);
|
||||
sender.sendMessage(prefix + "给予 §6" + playerName + " §a的灵宠经验: §d+" + exp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ("give".equalsIgnoreCase(args[0])) {
|
||||
if (args.length == 1) {
|
||||
sender.sendMessage(prefix + "缺少宠物参数.");
|
||||
return true;
|
||||
}
|
||||
String petKey = args[1];
|
||||
PetData petData = PetManager.getPetData(petKey);
|
||||
if (petData == null) {
|
||||
sender.sendMessage(prefix + "未找到 " + petKey + " 的相关配置.");
|
||||
return true;
|
||||
}
|
||||
String playerName = sender.getName();
|
||||
if (args.length >= 3) {
|
||||
playerName = args[2];
|
||||
}
|
||||
Player player = Bukkit.getPlayer(playerName);
|
||||
if (player == null) {
|
||||
sender.sendMessage(prefix + "未找到玩家 " + playerName);
|
||||
return true;
|
||||
}
|
||||
PetNbt petNbt = new PetNbt(petData);
|
||||
ItemStack petStack = PetUtil.getPetStackDefault(petNbt);
|
||||
player.getInventory().addItem(petNbt.saveIoItem(petStack));
|
||||
DemonAPI.sendMessage(sender, "玩家: §e" + playerName + " §a宠物: §6" + petKey + " §r[背包]");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (sender.isOp()) {
|
||||
if (args.length == 2 && "give".equalsIgnoreCase(args[0])) {
|
||||
return PetManager.getPetDataMap().keySet().stream()
|
||||
.filter(s -> s.toLowerCase().startsWith(args[1].toLowerCase()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
// 如果不符合上述条件,则返回空列表
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static PetMain inst() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static PlayerManager getPlayerManager() {
|
||||
return playerManager;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package com.yaohun.petsystem.api;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.data.PetData;
|
||||
import com.yaohun.petsystem.data.PlayerData;
|
||||
import com.yaohun.petsystem.manage.LevelExpManager;
|
||||
import com.yaohun.petsystem.manage.PetManager;
|
||||
import com.yaohun.petsystem.manage.PlayerManager;
|
||||
import com.yaohun.petsystem.model.PetNbt;
|
||||
import de.tr7zw.nbtapi.NBTItem;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PetExpAPI {
|
||||
|
||||
public static void addExp(Player player, int addExp) {
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
if (playerData.isPetStackNull()) {
|
||||
System.out.println("[日志 - 灵宠] 玩家 " + playerName + " 尚未携带宠物.");
|
||||
return;
|
||||
}
|
||||
PetNbt petNbt = playerData.getPetNbt();
|
||||
String petKey = petNbt.petData.getFileName();
|
||||
PetData petData = PetManager.getPetData(petKey);
|
||||
if (petData == null) {
|
||||
System.out.println("[日志 - 灵宠] 未添加 " + petKey + " 的宠物配置.");
|
||||
return;
|
||||
}
|
||||
int petLevel = petNbt.level;
|
||||
if (petLevel >= petData.getMaxLevel()) {
|
||||
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;
|
||||
}
|
||||
addExp -= needExp;
|
||||
petLevel++;
|
||||
needExp = LevelExpManager.getNeedExpValue(petLevel);
|
||||
bcmupLevelEvant(playerName, petLevel);
|
||||
playerData.refreshPetStack();
|
||||
}
|
||||
petNbt.setExp(addExp);
|
||||
petNbt.setLevel(petLevel);
|
||||
playerData.savePlayerData();
|
||||
}
|
||||
|
||||
public static PetNbt addExp(String playerName, ItemStack stack, int addExp) {
|
||||
NBTItem nbtItem = new NBTItem(stack);
|
||||
String petKey = nbtItem.getString("petKey");
|
||||
PetData petData = PetManager.getPetData(petKey);
|
||||
if (petData == null) {
|
||||
System.out.println("[日志 - 灵宠] 未添加 " + petKey + " 的宠物配置.");
|
||||
return null;
|
||||
}
|
||||
PetNbt petNbt = new PetNbt();
|
||||
petNbt.loadNbtData(nbtItem);
|
||||
int petLevel = petNbt.level;
|
||||
if (petLevel >= petData.getMaxLevel()) {
|
||||
return petNbt;
|
||||
}
|
||||
int needExp = LevelExpManager.getNeedExpValue(petLevel);
|
||||
petNbt.setTotalExp(petNbt.totalExp + addExp);
|
||||
|
||||
int nowExp = petNbt.exp;
|
||||
addExp = nowExp + addExp;
|
||||
while (addExp >= needExp) {
|
||||
if (petLevel < 0) {
|
||||
break;
|
||||
}
|
||||
addExp -= needExp;
|
||||
petLevel++;
|
||||
needExp = LevelExpManager.getNeedExpValue(petLevel);
|
||||
bcmupLevelEvant(playerName, petLevel);
|
||||
}
|
||||
petNbt.setExp(addExp);
|
||||
petNbt.setLevel(petLevel);
|
||||
return petNbt;
|
||||
}
|
||||
|
||||
public static void bcmupLevelEvant(String playerName, int level) {
|
||||
boolean butt = false;
|
||||
if (level == 10 || level == 20 || level == 30 || level == 40 || level == 50 ||
|
||||
level == 60 || level == 70 || level == 80 || level == 90 || level == 100
|
||||
|| level == 105 || level == 110 || level == 115 || level == 120 || level == 125) {
|
||||
butt = true;
|
||||
}
|
||||
if (butt) {
|
||||
// Bukkit.broadcastMessage("§f[§c§l公告§f] §a玩家§e"+playName+"§a本月器师手礼达到了 §7[§e§lLv."+level+"§7]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package com.yaohun.petsystem.command;
|
||||
|
||||
public class PetCommand {
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
package com.yaohun.petsystem.config;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.manage.LevelExpManager;
|
||||
import com.yaohun.petsystem.util.MessageUtil;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import me.Demon.DemonPlugin.Util.ColorUtil;
|
||||
import me.Demon.DemonPlugin.data.GuiItemData;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Config {
|
||||
|
||||
private static ItemStack petStackTemplate;
|
||||
private static NavigableMap<Integer, String> qualityShowMap = new TreeMap<>();
|
||||
private static HashMap<String, GuiItemData> guiItemDataMap = new HashMap<>();
|
||||
|
||||
public static void reloadConfig(PetMain plugin) {
|
||||
plugin.reloadConfig();
|
||||
plugin.saveConfig();
|
||||
FileConfiguration config = plugin.getConfig();
|
||||
Bukkit.getConsoleSender().sendMessage("§6[宠物系统] §7参数设定:");
|
||||
LevelExpManager.reloadLevelManager(plugin);
|
||||
loadPetStackTemplate(config);
|
||||
loadGuiItemData(config);
|
||||
loadQualityShowMap(config);
|
||||
}
|
||||
|
||||
private static void loadGuiItemData(FileConfiguration config) {
|
||||
guiItemDataMap.clear();
|
||||
ConfigurationSection section = config.getConfigurationSection("GuiItemData");
|
||||
if (section == null) {
|
||||
return;
|
||||
}
|
||||
for (String itemKey : section.getKeys(false)) {
|
||||
guiItemDataMap.put(itemKey, new GuiItemData(itemKey, section));
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadQualityShowMap(FileConfiguration config) {
|
||||
ConfigurationSection section = config.getConfigurationSection("QualityShow");
|
||||
if (section == null) {
|
||||
return;
|
||||
}
|
||||
for (String levelKey : section.getKeys(false)) {
|
||||
int level = Integer.parseInt(levelKey);
|
||||
String show = section.getString(levelKey).replace("&", "§");
|
||||
qualityShowMap.put(level, show);
|
||||
}
|
||||
Bukkit.getConsoleSender().sendMessage("- 资质稀有度: §f" + qualityShowMap.size() + "个");
|
||||
}
|
||||
|
||||
private static void loadPetStackTemplate(FileConfiguration config) {
|
||||
String stackType = config.getString("Pet_Stack_Template.type", "DIAMOND");
|
||||
Material material;
|
||||
try {
|
||||
material = Material.valueOf(stackType.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
Bukkit.getConsoleSender().sendMessage("- 宠物模板载入: §c失败");
|
||||
return;
|
||||
}
|
||||
String stackName = config.getString("Pet_Stack_Template.name", "§f宠物");
|
||||
List<String> stringList = config.getStringList("Pet_Stack_Template.lore");
|
||||
List<String> stackLore = ColorUtil.listcolor(stringList);
|
||||
ItemStack itemStack = new ItemStack(material);
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
meta.setDisplayName(stackName);
|
||||
meta.setLore(stackLore);
|
||||
itemStack.setItemMeta(meta);
|
||||
petStackTemplate = itemStack;
|
||||
|
||||
String itemName = DemonAPI.getItemName(itemStack.clone());
|
||||
Bukkit.getConsoleSender().sendMessage("- 宠物模板载入: §f" + itemName);
|
||||
}
|
||||
|
||||
public static ItemStack getPetStackTemplate() {
|
||||
return petStackTemplate.clone();
|
||||
}
|
||||
|
||||
public static String getLanguage(String key) {
|
||||
HashMap<String, String> hashMap = MessageUtil.getLanguageMap();
|
||||
if (hashMap.containsKey(key)) {
|
||||
return hashMap.get(key);
|
||||
}
|
||||
return "缺少参数.§7" + key;
|
||||
}
|
||||
|
||||
public static ItemStack getItemStack(String itemKey) {
|
||||
if (guiItemDataMap.containsKey(itemKey)) {
|
||||
ItemStack itemStack = guiItemDataMap.get(itemKey).getItemStack().clone();
|
||||
if (itemStack.hasItemMeta()) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta.hasLore()) {
|
||||
List<String> originalLore = meta.getLore();
|
||||
if (originalLore != null) {
|
||||
// 创建新的lore列表进行处理
|
||||
List<String> newLore = new ArrayList<>();
|
||||
for (String line : originalLore) {
|
||||
// 应用颜色转换或其他处理逻辑
|
||||
newLore.add(DemonAPI.convertHexColor(line));
|
||||
}
|
||||
// 设置处理后的新lore
|
||||
meta.setLore(newLore);
|
||||
itemStack.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
return itemStack;
|
||||
}
|
||||
return DemonAPI.getErrItems();
|
||||
}
|
||||
|
||||
|
||||
public static String getQualityShow(int value) {
|
||||
Map.Entry<Integer, String> entry = qualityShowMap.floorEntry(value);
|
||||
return entry != null ? entry.getValue() : qualityShowMap.get(0);
|
||||
}
|
||||
|
||||
public static String getHealthChar(int percent) {
|
||||
// 限制范围 [0,100]
|
||||
percent = Math.max(0, Math.min(100, percent));
|
||||
// 取整到最近的 10 倍数,例如 87 → 80,93 → 90
|
||||
int step = (percent / 10) * 10;
|
||||
// 处理 100 特殊情况
|
||||
if (percent == 100) {
|
||||
step = 100;
|
||||
}
|
||||
return "§f<image:default:hp_" + step + ">";
|
||||
}
|
||||
|
||||
public static String getLevelChar(int level) {
|
||||
return "§f<image:default:level_tag_" + level + ">";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package com.yaohun.petsystem.data;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class PetData {
|
||||
private String fileName;
|
||||
private String petName;
|
||||
private int customIconModelId;
|
||||
private int maxLevel;
|
||||
private String modelId;
|
||||
private List<String> accessChannelsList;
|
||||
private String summonSkill;
|
||||
private String deathSkill;
|
||||
private LinkedHashMap<String, SkillData> skillDataMap = new LinkedHashMap<>();
|
||||
|
||||
public PetData(String fileName, FileConfiguration config) {
|
||||
this.fileName = fileName;
|
||||
this.petName = config.getString("PetName");
|
||||
this.maxLevel = config.getInt("MaxLevel");
|
||||
this.modelId = config.getString("ModelId");
|
||||
this.customIconModelId = config.getInt("CustomIconModelId");
|
||||
this.accessChannelsList = config.getStringList("AccessChannels");
|
||||
this.summonSkill = config.getString("SummonSkill", "default");
|
||||
this.deathSkill = config.getString("DeathSkill", "default");
|
||||
loadSkillData(config);
|
||||
}
|
||||
|
||||
private void loadSkillData(FileConfiguration config) {
|
||||
ConfigurationSection section = config.getConfigurationSection("Skills");
|
||||
if (section == null) {
|
||||
return;
|
||||
}
|
||||
for (String key : section.getKeys(false)) {
|
||||
SkillData skillData = new SkillData(key, section);
|
||||
skillDataMap.put(key, skillData);
|
||||
}
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public String getPetName() {
|
||||
return petName;
|
||||
}
|
||||
|
||||
public int getMaxLevel() {
|
||||
return maxLevel;
|
||||
}
|
||||
|
||||
public String getModelId() {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
public int getCustomIconModelId() {
|
||||
return customIconModelId;
|
||||
}
|
||||
|
||||
public List<String> getAccessChannelsList() {
|
||||
return accessChannelsList;
|
||||
}
|
||||
|
||||
public String getSummonSkill() {
|
||||
return summonSkill;
|
||||
}
|
||||
|
||||
public String getDeathSkill() {
|
||||
return deathSkill;
|
||||
}
|
||||
|
||||
public LinkedHashMap<String, SkillData> getSkillDataMap() {
|
||||
return skillDataMap;
|
||||
}
|
||||
|
||||
public SkillData getSkillData(String skillName) {
|
||||
if (skillDataMap.containsKey(skillName)) {
|
||||
return skillDataMap.get(skillName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.yaohun.petsystem.data;
|
||||
|
||||
import com.tianyu.datamanager.DataAPI;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
public class PetSQL {
|
||||
|
||||
private static HikariDataSource dataSource;
|
||||
private static String host;
|
||||
private static String port;
|
||||
private static String database;
|
||||
private static String tables;
|
||||
private static String username;
|
||||
private static String password;
|
||||
|
||||
// 初始化数据库连接和表结构
|
||||
public static void init() {
|
||||
host = DataAPI.getMysql().getHost();
|
||||
port = DataAPI.getMysql().getPort();
|
||||
database = DataAPI.getMysql().getDatabase();
|
||||
tables = "aupets_data";
|
||||
username = DataAPI.getMysql().getUser();
|
||||
password = DataAPI.getMysql().getPassword();
|
||||
|
||||
setupDataSource(); // 初始化连接池
|
||||
initTable(); // 确保表结构已经创建
|
||||
}
|
||||
|
||||
// 配置并初始化 HikariCP 连接池
|
||||
private static void setupDataSource() {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
|
||||
config.setJdbcUrl("jdbc:mysql://" + host + ":" + port + "/" + database + "?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false");
|
||||
config.setUsername(username);
|
||||
config.setPassword(password);
|
||||
config.setMaximumPoolSize(3);
|
||||
config.setMinimumIdle(1);
|
||||
config.setIdleTimeout(300000L);
|
||||
config.setMaxLifetime(0L);
|
||||
dataSource = new HikariDataSource(config);
|
||||
}
|
||||
|
||||
// 初始化表结构(如果表不存在)
|
||||
private static void initTable() {
|
||||
String createTableSQL = "CREATE TABLE IF NOT EXISTS " + tables + " (" +
|
||||
"PLAYERNAME VARCHAR(255) NOT NULL, " +
|
||||
"PETSTACK TEXT NOT NULL, " +
|
||||
"PRIMARY KEY (PLAYERNAME))";
|
||||
try (Connection conn = getConnection(); Statement stmt = conn.createStatement()) {
|
||||
stmt.execute(createTableSQL);
|
||||
} catch (SQLException e) {
|
||||
Bukkit.getLogger().severe("初始化表结构失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 获取玩家宠物信息
|
||||
public static String getPetStack(String playerName) {
|
||||
String query = "SELECT PETSTACK FROM " + tables + " WHERE PLAYERNAME = ? LIMIT 1";
|
||||
try (Connection conn = getConnection();
|
||||
PreparedStatement ps = conn.prepareStatement(query)) {
|
||||
ps.setString(1, playerName);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
return rs.getString("PETSTACK");
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
Bukkit.getLogger().severe("获取字符串值失败: " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// 保存数据
|
||||
public static void saveData(String playerName, String petStack) {
|
||||
String sql = "INSERT INTO " + tables + " (PLAYERNAME, PETSTACK) " +
|
||||
"VALUES (?, ?) " + "ON DUPLICATE KEY UPDATE PETSTACK = VALUES(PETSTACK)";
|
||||
try (Connection conn = getConnection();
|
||||
PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||
ps.setString(1, playerName);
|
||||
ps.setString(2, petStack);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
Bukkit.getLogger().severe("保存宠物数据失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 获取数据库连接
|
||||
private static Connection getConnection() throws SQLException {
|
||||
return dataSource.getConnection();
|
||||
}
|
||||
|
||||
// 关闭连接池
|
||||
public static void closeConnection() {
|
||||
if (dataSource != null && !dataSource.isClosed()) {
|
||||
dataSource.close();
|
||||
Bukkit.getConsoleSender().sendMessage("数据库连接已成功关闭。#1");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
package com.yaohun.petsystem.data;
|
||||
|
||||
import com.yaohun.petsystem.model.PetNbt;
|
||||
import com.yaohun.petsystem.util.PetUtil;
|
||||
import de.tr7zw.nbtapi.NBTItem;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
import org.bukkit.util.io.BukkitObjectOutputStream;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
public class PlayerData {
|
||||
|
||||
private String playerName;
|
||||
private ItemStack petStack;
|
||||
private PetNbt petNbt;
|
||||
|
||||
public PlayerData(String playerName) {
|
||||
this.playerName = playerName;
|
||||
this.petStack = deserializeItemStack(PetSQL.getPetStack(playerName));
|
||||
if (isPetStackNull()) {
|
||||
return;
|
||||
}
|
||||
PetNbt petNbt = new PetNbt();
|
||||
NBTItem nbtItem = new NBTItem(petStack);
|
||||
petNbt.loadNbtData(nbtItem);
|
||||
this.petNbt = petNbt;
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
||||
public PetNbt getPetNbt() {
|
||||
return petNbt;
|
||||
}
|
||||
|
||||
public ItemStack getPetStack() {
|
||||
return petStack;
|
||||
}
|
||||
|
||||
public void rePetNameStack(String newName) {
|
||||
ItemStack stack = petStack.clone();
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
meta.displayName(Component.text(newName)
|
||||
.color(NamedTextColor.GREEN)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
stack.setItemMeta(meta);
|
||||
setPetStack(stack);
|
||||
}
|
||||
|
||||
public void setPetStack(ItemStack petStack) {
|
||||
this.petStack = petStack;
|
||||
if (isPetStackNull()) {
|
||||
return;
|
||||
}
|
||||
PetNbt petNbt = new PetNbt();
|
||||
NBTItem nbtItem = new NBTItem(petStack);
|
||||
petNbt.loadNbtData(nbtItem);
|
||||
this.petNbt = petNbt;
|
||||
}
|
||||
|
||||
public void refreshPetStack() {
|
||||
ItemStack itemStack = PetUtil.getPetStackDefault(petNbt);
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
meta.displayName(Component.text(petStack.getItemMeta().getDisplayName())
|
||||
.color(NamedTextColor.GREEN)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
petStack = petNbt.saveIoItem(itemStack);
|
||||
}
|
||||
|
||||
public void savePlayerData() {
|
||||
if (DemonAPI.itemIsNull(petStack)) {
|
||||
PetSQL.saveData(playerName, serializeItemStack(DemonAPI.getErrItems()));
|
||||
} else {
|
||||
PetSQL.saveData(playerName, serializeItemStack(petStack));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPetStackNull() {
|
||||
return petStack == null || petStack.getType().equals(Material.BARRIER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 ItemStack 序列化为 Base64 字符串
|
||||
*
|
||||
* @param itemStack 要序列化的 ItemStack
|
||||
* @return 序列化后的 Base64 字符串
|
||||
*/
|
||||
private String serializeItemStack(ItemStack itemStack) {
|
||||
if (itemStack == null) {
|
||||
return "";
|
||||
}
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream)) {
|
||||
dataOutput.writeObject(itemStack);
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
} catch (IOException e) {
|
||||
Bukkit.getLogger().warning("[日志 - 灵宠] 序列化 ItemStack 时出错: " + e.getMessage());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Base64 字符串反序列化为 ItemStack
|
||||
*
|
||||
* @param data Base64 字符串
|
||||
* @return 反序列化后的 ItemStack
|
||||
*/
|
||||
private ItemStack deserializeItemStack(String data) {
|
||||
if (data == null || data.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
byte[] decodedData = Base64.getDecoder().decode(data);
|
||||
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(decodedData);
|
||||
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream)) {
|
||||
return (ItemStack) dataInput.readObject();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Bukkit.getLogger().warning("[日志 - 灵宠] 反序列化 ItemStack 时出错: " + e.getMessage());
|
||||
return DemonAPI.getErrItems();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.yaohun.petsystem.data;
|
||||
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SkillData {
|
||||
|
||||
private String skillName; // 技能名
|
||||
private String mmSkill; // MM技能
|
||||
private int needLevel; // 触发要求等级
|
||||
private String trigger; // 触发器
|
||||
private long coolDown; // 冷却时间
|
||||
private String itemName;
|
||||
private List<String> itemLore = new ArrayList<>();
|
||||
|
||||
public SkillData(String skillName, ConfigurationSection section) {
|
||||
this.skillName = skillName;
|
||||
this.mmSkill = section.getString(skillName + ".mmSkill");
|
||||
this.needLevel = section.getInt(skillName + ".needLevel");
|
||||
this.trigger = section.getString(skillName + ".trigger");
|
||||
this.coolDown = section.getLong(skillName + ".coolDown");
|
||||
this.itemName = DemonAPI.convertHexColor(section.getString(skillName + ".item.name", "技能 I"));
|
||||
List<String> itemlore = section.getStringList(skillName + ".item.lore");
|
||||
// Bukkit.getConsoleSender().sendMessage("[调试] name: "+skillName+" itemlore = "+itemlore);
|
||||
for (String line : itemlore) {
|
||||
this.itemLore.add(DemonAPI.convertHexColor(line));
|
||||
}
|
||||
}
|
||||
|
||||
public String getSkillName() {
|
||||
return skillName;
|
||||
}
|
||||
|
||||
public String getMmSkill() {
|
||||
return mmSkill;
|
||||
}
|
||||
|
||||
public int getNeedLevel() {
|
||||
return needLevel;
|
||||
}
|
||||
|
||||
public String getTrigger() {
|
||||
return trigger;
|
||||
}
|
||||
|
||||
public long getCoolDown() {
|
||||
return coolDown;
|
||||
}
|
||||
|
||||
public String getItemName() {
|
||||
return itemName;
|
||||
}
|
||||
|
||||
public List<String> getItemLore() {
|
||||
return itemLore;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.yaohun.petsystem.event;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PetCallEvent extends Event {
|
||||
|
||||
private final Player owner;
|
||||
private final String cutomName;
|
||||
private final UUID entityUuid;
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
public PetCallEvent(Player owner, String cutomName, UUID entityUuid) {
|
||||
this.owner = owner;
|
||||
this.cutomName = cutomName;
|
||||
this.entityUuid = entityUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public Player getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public String getCutomName() {
|
||||
return cutomName;
|
||||
}
|
||||
|
||||
public UUID getEntityUuid() {
|
||||
return entityUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventName() {
|
||||
return super.getEventName();
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package com.yaohun.petsystem.gui;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
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.MessageUtil;
|
||||
import de.tr7zw.nbtapi.NBTItem;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class CarryGui implements Listener {
|
||||
|
||||
private static final int PET_SLOT = 4;
|
||||
|
||||
public static void openGui(Player player) {
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
Inventory inv = Bukkit.createInventory(new CarryGuiHolder(), 9, Config.getLanguage("carry_gui_title"));
|
||||
if (playerData.isPetStackNull()) {
|
||||
inv.setItem(PET_SLOT, Config.getItemStack("carry_gui"));
|
||||
} else {
|
||||
inv.setItem(PET_SLOT, playerData.getPetStack());
|
||||
}
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onClick(InventoryClickEvent e) {
|
||||
int rawSlot = e.getRawSlot();
|
||||
Player player = (Player) e.getWhoClicked();
|
||||
Inventory inv = e.getInventory();
|
||||
if ((e.getInventory().getHolder() instanceof CarryGuiHolder)) {
|
||||
e.setCancelled(true);
|
||||
ItemStack stack = e.getCurrentItem();
|
||||
if (DemonAPI.itemIsNull(stack)) {
|
||||
return;
|
||||
}
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
if (rawSlot == PET_SLOT) {
|
||||
if (!playerData.isPetStackNull()) {
|
||||
playerManager.removePetCall(playerName);
|
||||
playerData.refreshPetStack();
|
||||
ItemStack petStack = playerData.getPetStack();
|
||||
player.getInventory().addItem(petStack);
|
||||
playerData.setPetStack(DemonAPI.getErrItems());
|
||||
playerData.savePlayerData();
|
||||
inv.setItem(PET_SLOT, Config.getItemStack("carry_gui"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (playerData.isPetStackNull()) {
|
||||
NBTItem nbtItem = new NBTItem(stack);
|
||||
if (!nbtItem.hasKey("petKey")) {
|
||||
MessageUtil.sendMessageKey(player, "hand_not_pet_stack", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
e.setCurrentItem(new ItemStack(Material.AIR));
|
||||
playerData.setPetStack(stack);
|
||||
playerData.savePlayerData();
|
||||
String itemName = DemonAPI.getItemName(stack);
|
||||
String message = Config.getLanguage("pet_stack_carry_success");
|
||||
MessageUtil.sendMessage(player, message.replace("{petName}", itemName), Sound.ENTITY_PLAYER_LEVELUP);
|
||||
MainGui.openGui(player);
|
||||
} else {
|
||||
playerManager.removePetCall(playerName);
|
||||
playerData.refreshPetStack();
|
||||
ItemStack petStack = playerData.getPetStack();
|
||||
player.getInventory().addItem(petStack);
|
||||
playerData.setPetStack(DemonAPI.getErrItems());
|
||||
playerData.savePlayerData();
|
||||
MessageUtil.sendMessageKey(player, "pet_stack_carry_takeOut", Sound.ENTITY_PLAYER_LEVELUP);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
package com.yaohun.petsystem.gui;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.api.PetExpAPI;
|
||||
import com.yaohun.petsystem.config.Config;
|
||||
import com.yaohun.petsystem.data.PlayerData;
|
||||
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.MessageUtil;
|
||||
import com.yaohun.petsystem.util.PetUtil;
|
||||
import de.tr7zw.nbtapi.NBTItem;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
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.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FeedingGui implements Listener {
|
||||
|
||||
private final static int FOOD_SLOT = 15;
|
||||
|
||||
public static void openGui(Player player) {
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
if (playerData.isPetStackNull()) {
|
||||
MessageUtil.sendMessageKey(player, "gui_no_pets_brought", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
String invTitle = Config.getLanguage("main_gui_title");
|
||||
if (playerManager.isPetCallExit(playerName)) {
|
||||
invTitle = Config.getLanguage("main_gui_title") + Config.getLanguage("call_gui_title");
|
||||
}
|
||||
Inventory inv = Bukkit.createInventory(new FeedingGuiHolder(), 36, invTitle + Config.getLanguage("feeding_gui_title"));
|
||||
// 关闭界面
|
||||
inv.setItem(1, Config.getItemStack("close"));
|
||||
//食物槽
|
||||
inv.setItem(FOOD_SLOT, DemonAPI.getPaperAirItems());
|
||||
checkFoodGuiPetState(inv, playerData);
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
private static void checkFoodGuiPetState(Inventory inv, PlayerData playerData) {
|
||||
inv.setItem(23, getFoodButt(playerData.getPetNbt()));
|
||||
inv.setItem(24, getFoodButt(playerData.getPetNbt()));
|
||||
inv.setItem(25, getFoodButt(playerData.getPetNbt()));
|
||||
inv.setItem(11, PetUtil.getPetGuiStack(playerData, "chongwu_feed"));
|
||||
}
|
||||
|
||||
private static ItemStack getFoodButt(PetNbt petNbt) {
|
||||
ItemStack stack = Config.getItemStack("weishibutton");
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
List<String> lore = meta.getLore();
|
||||
lore.replaceAll(s -> DemonAPI.convertHexColor(s
|
||||
.replace("{petlevel}", String.valueOf(petNbt.level))
|
||||
.replace("{exp}", String.valueOf(petNbt.exp))
|
||||
.replace("{maxExp}", String.valueOf(LevelExpManager.getNeedExpValue(petNbt.level)))));
|
||||
meta.setLore(lore);
|
||||
stack.setItemMeta(meta);
|
||||
return stack;
|
||||
}
|
||||
|
||||
private ItemStack getFooedStack(Inventory inv) {
|
||||
ItemStack foodStack = inv.getItem(FOOD_SLOT);
|
||||
if (DemonAPI.itemIsNull(foodStack) || DemonAPI.itemIsLore(foodStack)) {
|
||||
return null;
|
||||
}
|
||||
return foodStack;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onClick(InventoryClickEvent e) {
|
||||
int rawSlot = e.getRawSlot();
|
||||
Player player = (Player) e.getWhoClicked();
|
||||
String playerName = player.getName();
|
||||
Inventory inv = e.getInventory();
|
||||
if ((e.getInventory().getHolder() instanceof FeedingGuiHolder)) {
|
||||
e.setCancelled(true);
|
||||
if (rawSlot > 35) {
|
||||
ItemStack clickStack = e.getCurrentItem();
|
||||
if (DemonAPI.itemIsNull(clickStack) || DemonAPI.itemIsLore(clickStack)) {
|
||||
return;
|
||||
}
|
||||
NBTItem nbtItem = new NBTItem(clickStack);
|
||||
if (nbtItem.hasKey("petAppleExp") || nbtItem.hasKey("petAppleUp")) {
|
||||
// 判断槽位内是否已存在物品
|
||||
ItemStack foodStack = getFooedStack(inv);
|
||||
if (foodStack != null) {
|
||||
player.getInventory().addItem(foodStack);
|
||||
}
|
||||
e.setCurrentItem(null);
|
||||
inv.setItem(FOOD_SLOT, clickStack);
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
|
||||
} else {
|
||||
MessageUtil.sendMessageKey(player, "pet_feed_not_apple", Sound.ENTITY_VILLAGER_NO);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (rawSlot == FOOD_SLOT) {
|
||||
// 判断槽位内是否已存在物品
|
||||
ItemStack foodStack = getFooedStack(inv);
|
||||
if (foodStack != null) {
|
||||
player.getInventory().addItem(foodStack);
|
||||
inv.setItem(FOOD_SLOT, DemonAPI.getPaperAirItems());
|
||||
}
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
|
||||
}
|
||||
if (rawSlot == 1) {
|
||||
MainGui.openGui(player);
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
|
||||
}
|
||||
if (rawSlot == 23 || rawSlot == 24 || rawSlot == 25) {
|
||||
// 获取实物槽位中的物品
|
||||
ItemStack foodStack = inv.getItem(FOOD_SLOT);
|
||||
if (DemonAPI.itemIsNull(foodStack) || DemonAPI.itemIsLore(foodStack)) {
|
||||
return;
|
||||
}
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
|
||||
String itemName = DemonAPI.getItemName(foodStack);
|
||||
NBTItem nbtItem = new NBTItem(foodStack);
|
||||
if (nbtItem.hasKey("petAppleExp")) {
|
||||
// 扣除果实
|
||||
if (foodStack.getAmount() == 1) {
|
||||
inv.setItem(FOOD_SLOT, DemonAPI.getPaperAirItems());
|
||||
} else {
|
||||
foodStack.setAmount(foodStack.getAmount() - 1);
|
||||
}
|
||||
// 获取增加经验
|
||||
int addExp = Integer.parseInt(nbtItem.getString("petAppleExp"));
|
||||
PetExpAPI.addExp(player, addExp);
|
||||
String message = Config.getLanguage("pet_feed_exp_success");
|
||||
message = message.replace("{itemName}", itemName);
|
||||
message = message.replace("{exp}", String.valueOf(addExp));
|
||||
MessageUtil.sendMessage(player, message, Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
|
||||
// 刷新宠物经验
|
||||
checkFoodGuiPetState(inv, playerData);
|
||||
playerData.refreshPetStack();
|
||||
} else if (nbtItem.hasKey("petAppleUp")) {
|
||||
PetNbt petNbt = playerData.getPetNbt();
|
||||
// 获取进化阶段
|
||||
int needLevel = Integer.parseInt(nbtItem.getString("petAppleUp"));
|
||||
if (needLevel == 20) {
|
||||
feedEvolutionEvent(player, needLevel, petNbt, 1, 2, itemName);
|
||||
} else if (needLevel == 40) {
|
||||
feedEvolutionEvent(player, needLevel, petNbt, 2, 3, itemName);
|
||||
} else if (needLevel == 60) {
|
||||
feedEvolutionEvent(player, needLevel, petNbt, 3, 4, itemName);
|
||||
} else if (needLevel == 70) {
|
||||
feedEvolutionEvent(player, needLevel, petNbt, 4, 5, itemName);
|
||||
} else if (needLevel == 75) {
|
||||
feedEvolutionEvent(player, needLevel, petNbt, 5, 6, itemName);
|
||||
}
|
||||
} else {
|
||||
MessageUtil.sendMessageKey(player, "pet_feed_not_apple", Sound.ENTITY_VILLAGER_NO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void feedEvolutionEvent(Player player, int appleLevel, PetNbt petNbt, int needEvolution, int nextEvolution, String itemName) {
|
||||
int evolution = petNbt.evolution;
|
||||
int petLevel = petNbt.level;
|
||||
if (evolution == nextEvolution) {
|
||||
MessageUtil.sendMessageKey(player, "pet_feed_evolution_already", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
if (evolution == needEvolution) {
|
||||
// 判断宠物等级是否满足要求
|
||||
if (petLevel < appleLevel) {
|
||||
String message = Config.getLanguage("pet_feed_evolution_need_level");
|
||||
MessageUtil.sendMessage(player, message.replace("{level}", Config.getLevelChar(appleLevel)), Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
petNbt.setEvolution(nextEvolution);
|
||||
String message = Config.getLanguage("pet_feed_evolution_success");
|
||||
MessageUtil.sendMessage(player, message.replace("{itemName}", itemName), Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
|
||||
} else {
|
||||
MessageUtil.sendMessageKey(player, "pet_feed_evolution_request", Sound.ENTITY_VILLAGER_NO);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onClose(InventoryCloseEvent e) {
|
||||
Inventory inv = e.getInventory();
|
||||
if ((e.getInventory().getHolder() instanceof FeedingGuiHolder)) {
|
||||
Player player = (Player) e.getPlayer();
|
||||
ItemStack stack = getFooedStack(inv);
|
||||
if (stack != null) {
|
||||
inv.setItem(FOOD_SLOT, DemonAPI.getPaperAirItems());
|
||||
player.getInventory().addItem(stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
package com.yaohun.petsystem.gui;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.config.Config;
|
||||
import com.yaohun.petsystem.data.PetData;
|
||||
import com.yaohun.petsystem.data.PlayerData;
|
||||
import com.yaohun.petsystem.data.SkillData;
|
||||
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.MessageUtil;
|
||||
import com.yaohun.petsystem.util.PetUtil;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MainGui implements Listener {
|
||||
|
||||
public static void openGui(Player player) {
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
if (playerData.isPetStackNull()) {
|
||||
CarryGui.openGui(player);
|
||||
// MessageUtil.sendMessageKey(player, "gui_no_pets_brought", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
String invTitle = Config.getLanguage("main_gui_title");
|
||||
String buttonKey = "zhaohuan";
|
||||
if (playerManager.isPetCallExit(playerName)) {
|
||||
invTitle = Config.getLanguage("main_gui_title") + Config.getLanguage("call_gui_title");
|
||||
buttonKey = "zhaohui";
|
||||
}
|
||||
Inventory inv = Bukkit.createInventory(new MainGuiHolder(), 36, invTitle);
|
||||
// 关闭界面
|
||||
inv.setItem(0, Config.getItemStack("close"));
|
||||
// 宠物图鉴
|
||||
inv.setItem(1, Config.getItemStack("pettujian"));
|
||||
// 宠物物品显示
|
||||
inv.setItem(11, PetUtil.getPetGuiStack(playerData, "chongwu"));
|
||||
// 宠物技能显示
|
||||
PetData petData = playerData.getPetNbt().petData;
|
||||
int slot = 13;
|
||||
for (SkillData skillData : petData.getSkillDataMap().values()) {
|
||||
inv.setItem(slot, getSkillGoldenApple(skillData));
|
||||
slot++;
|
||||
}
|
||||
// 宠物召唤按钮
|
||||
ItemStack zhaohuanStack = Config.getItemStack(buttonKey);
|
||||
inv.setItem(29, zhaohuanStack);
|
||||
inv.setItem(30, zhaohuanStack);
|
||||
// 宠物喂养按钮
|
||||
inv.setItem(31, Config.getItemStack("weiyang"));
|
||||
// 宠物工作按钮
|
||||
inv.setItem(32, Config.getItemStack("gongzuo"));
|
||||
inv.setItem(33, Config.getItemStack("gongzuo"));
|
||||
// 宠物品质数据查询
|
||||
inv.setItem(22, getQualificationStack(playerData, "fangs"));
|
||||
inv.setItem(23, getQualificationStack(playerData, "survive"));
|
||||
inv.setItem(24, getQualificationStack(playerData, "efficiency"));
|
||||
// 仓库、Wiki按钮
|
||||
inv.setItem(7, Config.getItemStack("cangku"));
|
||||
inv.setItem(8, Config.getItemStack("wiki"));
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
private static ItemStack getSkillGoldenApple(SkillData skillData) {
|
||||
ItemStack stack = new ItemStack(Material.GOLDEN_APPLE);
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
meta.displayName(Component.text(skillData.getItemName())
|
||||
.color(NamedTextColor.GREEN)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
meta.setLore(skillData.getItemLore());
|
||||
stack.setItemMeta(meta);
|
||||
return stack;
|
||||
}
|
||||
|
||||
private static ItemStack getQualificationStack(PlayerData playerData, String type) {
|
||||
PetNbt petNbt = playerData.getPetNbt();
|
||||
int value = 0;
|
||||
if ("fangs".equalsIgnoreCase(type)) {
|
||||
value = petNbt.quality.getFangs();
|
||||
} else if ("survive".equalsIgnoreCase(type)) {
|
||||
value = petNbt.quality.getSurvive();
|
||||
} else if ("efficiency".equalsIgnoreCase(type)) {
|
||||
value = petNbt.quality.getEfficiency();
|
||||
}
|
||||
ItemStack stack = Config.getItemStack(type);
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
List<String> lore = meta.getLore();
|
||||
for (int i = 0; i < lore.size(); i++) {
|
||||
String line = lore.get(i);
|
||||
if (line.contains("{qualityShow}")) {
|
||||
lore.set(i, DemonAPI.convertHexColor(line).replace("{qualityShow}", Config.getQualityShow(value)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
meta.setLore(lore);
|
||||
stack.setItemMeta(meta);
|
||||
return stack;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onClick(InventoryClickEvent e) {
|
||||
int rawSlot = e.getRawSlot();
|
||||
Player player = (Player) e.getWhoClicked();
|
||||
if ((e.getInventory().getHolder() instanceof MainGuiHolder)) {
|
||||
e.setCancelled(true);
|
||||
// 关闭界面按钮
|
||||
if (rawSlot == 0) {
|
||||
player.closeInventory();
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
|
||||
}
|
||||
if (rawSlot == 1) {
|
||||
player.closeInventory();
|
||||
// 打开宠物图鉴操作
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
|
||||
}
|
||||
// Wiki按钮
|
||||
if (rawSlot == 8) {
|
||||
player.closeInventory();
|
||||
MessageUtil.sendMessageKey(player, "gui_wiki_message", Sound.UI_BUTTON_CLICK);
|
||||
}
|
||||
// 仓库按钮
|
||||
if (rawSlot == 7) {
|
||||
player.closeInventory();
|
||||
// 打开便捷仓库操作
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
|
||||
}
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
if (rawSlot == 11) {
|
||||
if (e.isShiftClick()) {
|
||||
String playerName = player.getName();
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
if (!playerData.isPetStackNull()) {
|
||||
playerManager.removePetCall(playerName);
|
||||
playerData.refreshPetStack();
|
||||
ItemStack petStack = playerData.getPetStack();
|
||||
player.getInventory().addItem(petStack);
|
||||
playerData.setPetStack(DemonAPI.getErrItems());
|
||||
playerData.savePlayerData();
|
||||
player.closeInventory();
|
||||
Bukkit.getScheduler().runTaskLater(PetMain.inst(), player::updateInventory, 2L);
|
||||
MessageUtil.sendMessageKey(player, "pet_stack_carry_takeOut", Sound.ENTITY_PLAYER_LEVELUP);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (e.isLeftClick()) {
|
||||
player.closeInventory();
|
||||
RePetNameListener.addReNameUUID(player.getUniqueId());
|
||||
MessageUtil.sendMessageKey(player, "pet_rename_add", Sound.UI_BUTTON_CLICK);
|
||||
}
|
||||
}
|
||||
// 召唤宠物操作按钮
|
||||
if (rawSlot == 29 || rawSlot == 30) {
|
||||
player.closeInventory();
|
||||
playerManager.callPet(player);
|
||||
}
|
||||
// 打开投喂宠物界面
|
||||
if (rawSlot == 31) {
|
||||
FeedingGui.openGui(player);
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
|
||||
}
|
||||
// 打开打工系统
|
||||
if (rawSlot == 32 || rawSlot == 33) {
|
||||
player.closeInventory();
|
||||
MessageUtil.sendMessageKey(player, "imperfect_function", Sound.ENTITY_VILLAGER_NO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.yaohun.petsystem.gui.holder;
|
||||
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
|
||||
public class CarryGuiHolder implements InventoryHolder {
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.yaohun.petsystem.gui.holder;
|
||||
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
|
||||
public class FeedingGuiHolder implements InventoryHolder {
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.yaohun.petsystem.gui.holder;
|
||||
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
|
||||
public class MainGuiHolder implements InventoryHolder {
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package com.yaohun.petsystem.listener;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.data.PetData;
|
||||
import com.yaohun.petsystem.data.PlayerData;
|
||||
import com.yaohun.petsystem.data.SkillData;
|
||||
import com.yaohun.petsystem.manage.PlayerManager;
|
||||
import io.lumine.mythic.bukkit.MythicBukkit;
|
||||
import me.Demon.DemonPlugin.Util.CDTimeAPI;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PetSkillsListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onDamager(EntityDamageByEntityEvent e){
|
||||
if(e.getDamager() instanceof Player player){
|
||||
// 判断玩家是否携带宠物
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
// 获取宠物相关数据
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
if(playerData.isPetStackNull()){
|
||||
return;
|
||||
}
|
||||
PetData petData = playerData.getPetNbt().petData;
|
||||
int petLevel = playerData.getPetNbt().level;
|
||||
LinkedHashMap<String , SkillData> skillDataMap = petData.getSkillDataMap();
|
||||
for(SkillData skillData : skillDataMap.values()){
|
||||
if(petLevel >= skillData.getNeedLevel()) {
|
||||
String cdKey = "skill_"+skillData.getSkillName();
|
||||
if ("onAttack".equalsIgnoreCase(skillData.getTrigger())) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
if(!CDTimeAPI.isCD(uuid,cdKey)) {
|
||||
long cooldown = skillData.getCoolDown();
|
||||
CDTimeAPI.setPlayerCD(uuid, cdKey, cooldown);
|
||||
String mmSkill = skillData.getMmSkill();
|
||||
// 执行技能
|
||||
MythicBukkit.inst().getAPIHelper().castSkill(
|
||||
player,
|
||||
mmSkill,
|
||||
player.getLocation()
|
||||
);
|
||||
player.sendMessage("[调试 - 宠物技能] 触发条件: onAttack 触发技能: "+skillData.getSkillName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(e.getEntity() instanceof Player player){
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
if(playerData.isPetStackNull()){
|
||||
return;
|
||||
}
|
||||
PetData petData = playerData.getPetNbt().petData;
|
||||
int petLevel = playerData.getPetNbt().level;
|
||||
LinkedHashMap<String , SkillData> skillDataMap = petData.getSkillDataMap();
|
||||
for(SkillData skillData : skillDataMap.values()){
|
||||
if(petLevel >= skillData.getNeedLevel()) {
|
||||
String cdKey = "skill_"+skillData.getSkillName();
|
||||
if ("onDamaged".equalsIgnoreCase(skillData.getTrigger())) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
if(!CDTimeAPI.isCD(uuid,cdKey)) {
|
||||
long cooldown = skillData.getCoolDown();
|
||||
CDTimeAPI.setPlayerCD(uuid, cdKey, cooldown);
|
||||
String mmSkill = skillData.getMmSkill();
|
||||
// 执行技能
|
||||
MythicBukkit.inst().getAPIHelper().castSkill(player, mmSkill, player.getLocation());
|
||||
player.sendMessage("[调试 - 宠物技能] 触发条件: onDamaged 触发技能: "+skillData.getSkillName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*public boolean runSkills(SkillCaster caster, SkillTrigger cause, AbstractLocation origin, AbstractEntity trigger, Consumer<SkillMetadata> transformer) {
|
||||
return new TriggeredSkill(cause, caster, origin, trigger, this.artifact.getMechanics(cause), true, meta -> {
|
||||
transformer.getVariables().putString("equip-slot", this.equippedSlot);
|
||||
transformer.getVariables().putObject("equip-item", this.itemStack);
|
||||
if (r5 != null) {
|
||||
r5.accept(transformer);
|
||||
}
|
||||
}, new Pair[0]).getCancelled();
|
||||
}*/
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package com.yaohun.petsystem.listener;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.data.PlayerData;
|
||||
import com.yaohun.petsystem.manage.PlayerManager;
|
||||
import com.yaohun.petsystem.model.PetNbt;
|
||||
import com.yaohun.petsystem.util.PetUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Wolf;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onDamage(EntityDamageByEntityEvent e) {
|
||||
if (e.getEntity() instanceof Player) {
|
||||
return;
|
||||
}
|
||||
if (!(e.getEntity() instanceof LivingEntity target)) {
|
||||
return;
|
||||
}
|
||||
if (e.getDamager() instanceof Player player) {
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
if (!playerManager.isPetCallExit(playerName)) {
|
||||
return;
|
||||
}
|
||||
UUID petUUID = playerManager.getPetUUID(playerName);
|
||||
if (petUUID == null) {
|
||||
return;
|
||||
}
|
||||
Entity entity = Bukkit.getEntity(petUUID);
|
||||
if (entity instanceof Wolf wolf) {
|
||||
wolf.setTarget(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查伤害 狼造成的伤害
|
||||
@EventHandler
|
||||
public void onDamageCheck(EntityDamageByEntityEvent e) {
|
||||
if (e.getDamager() instanceof Wolf wolf) {
|
||||
PlayerData playerData = PetUtil.updatePetNameTag(wolf);
|
||||
if (playerData != null) {
|
||||
double health = wolf.getHealth();
|
||||
PetNbt petNbt = playerData.getPetNbt();
|
||||
petNbt.setHealth((int) health);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDeath(EntityDeathEvent e) {
|
||||
String ownerName = PetMain.getPlayerManager().getPetOwnerName(e.getEntity().getUniqueId());
|
||||
if (ownerName == null) {
|
||||
return;
|
||||
}
|
||||
PlayerData playerData = PetMain.getPlayerManager().getPlayerData(ownerName);
|
||||
playerData.getPetNbt().setHealth(0);
|
||||
PetMain.getPlayerManager().removePetCall(ownerName);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent e){
|
||||
Player player = e.getPlayer();
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
playerManager.removePetCall(playerName);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.yaohun.petsystem.listener;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
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.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.UUID;
|
||||
|
||||
public class RePetNameListener implements Listener {
|
||||
|
||||
private static List<UUID> reNameList = new ArrayList<>();
|
||||
|
||||
public static void addReNameUUID(UUID uuid) {
|
||||
if (!reNameList.contains(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)) {
|
||||
return;
|
||||
}
|
||||
e.setCancelled(true);
|
||||
reNameList.remove(uuid);
|
||||
String playerName = player.getName();
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
if (playerData.isPetStackNull()) {
|
||||
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;
|
||||
}
|
||||
if (reName.length() < 3) {
|
||||
MessageUtil.sendMessageKey(player, "pet_rename_length", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
String newName = reName.replace("&", "§");
|
||||
playerData.rePetNameStack(newName);
|
||||
playerData.savePlayerData();
|
||||
String message = Config.getLanguage("pet_rename_success");
|
||||
MessageUtil.sendMessage(player, message.replace("{petName}", newName), Sound.ENTITY_PLAYER_LEVELUP);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.yaohun.petsystem.manage;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class LevelExpManager {
|
||||
|
||||
private static HashMap<Integer, Integer> needExpMap = new HashMap<>();
|
||||
|
||||
public static void reloadLevelManager(PetMain plugin) {
|
||||
File file = new File(plugin.getDataFolder() + "/Settings", "needExp.yml");
|
||||
if (file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
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);
|
||||
}
|
||||
Bukkit.getConsoleSender().sendMessage("§7- 等级经验配置: §f" + needExpMap.size() + "条");
|
||||
}
|
||||
|
||||
public static int getNeedExpValue(int level) {
|
||||
if (needExpMap.containsKey(level)) {
|
||||
return needExpMap.get(level);
|
||||
}
|
||||
return 1000000;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.yaohun.petsystem.manage;
|
||||
|
||||
import kr.toxicity.model.api.tracker.Tracker;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PetCallSession {
|
||||
|
||||
private final UUID ownerUuid;
|
||||
private final UUID entityUuid;
|
||||
private final Tracker tracker;
|
||||
|
||||
public PetCallSession(UUID ownerUuid, UUID entityUuid, Tracker tracker) {
|
||||
this.ownerUuid = ownerUuid;
|
||||
this.entityUuid = entityUuid;
|
||||
this.tracker = tracker;
|
||||
}
|
||||
|
||||
public UUID getOwnerUuid() {
|
||||
return ownerUuid;
|
||||
}
|
||||
|
||||
public UUID getEntityUuid() {
|
||||
return entityUuid;
|
||||
}
|
||||
|
||||
public Entity getEntity() {
|
||||
return Bukkit.getEntity(entityUuid);
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
Entity entity = getEntity();
|
||||
return entity != null && !entity.isDead();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (tracker != null && !tracker.isClosed()) {
|
||||
tracker.despawn();
|
||||
tracker.close();
|
||||
}
|
||||
Entity entity = getEntity();
|
||||
if (entity != null && !entity.isDead()) {
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.yaohun.petsystem.manage;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.data.PetData;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class PetManager {
|
||||
|
||||
private static HashMap<String, PetData> petDataMap = new HashMap<>();
|
||||
|
||||
public static void reloadPetManager() {
|
||||
petDataMap.clear();
|
||||
Bukkit.getConsoleSender().sendMessage("§6[宠物系统] §7宠物类型:");
|
||||
String folderPath = PetMain.inst().getDataFolder().getPath() + "/PetData";
|
||||
File folder = new File(folderPath);
|
||||
if (!folder.exists() || !folder.isDirectory()) {
|
||||
System.out.println("[日志 - 灵宠] 未检测到任何宠物配置: " + folderPath);
|
||||
return;
|
||||
}
|
||||
List<File> ymlFiles = new ArrayList<>();
|
||||
DemonAPI.collectYmlFiles(folder, ymlFiles);
|
||||
if (ymlFiles.isEmpty()) {
|
||||
System.out.println("[日志 - 灵宠] 未检测到任何宠物配置: " + folderPath);
|
||||
return;
|
||||
}
|
||||
for (File file : ymlFiles) {
|
||||
String fileName = file.getName().replace(".yml", "");
|
||||
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||
PetData petData = new PetData(fileName, config);
|
||||
petDataMap.put(fileName, petData);
|
||||
Bukkit.getConsoleSender().sendMessage("- 宠物: §f" + petData.getPetName() + " §7MaxLevel: §f" + petData.getMaxLevel());
|
||||
}
|
||||
}
|
||||
|
||||
public static HashMap<String, PetData> getPetDataMap() {
|
||||
return petDataMap;
|
||||
}
|
||||
|
||||
public static PetData getItemNameToPetData(String itemName) {
|
||||
for (PetData petData : petDataMap.values()) {
|
||||
if (petData.getPetName().contains(itemName)) {
|
||||
return petData;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PetData getPetData(String petKey) {
|
||||
if (petDataMap.containsKey(petKey)) {
|
||||
return petDataMap.get(petKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取宠物获取渠道
|
||||
public static List<String> getPetAccessChannels(String petKey) {
|
||||
PetData petData = PetManager.getPetData(petKey);
|
||||
if (petData == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return petData.getAccessChannelsList();
|
||||
}
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
package com.yaohun.petsystem.manage;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.config.Config;
|
||||
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.MessageUtil;
|
||||
import com.yaohun.petsystem.util.model.BetterModelUtil;
|
||||
import com.yaohun.petsystem.util.wolf.CustomWolf;
|
||||
import de.tr7zw.nbtapi.NBTItem;
|
||||
import io.lumine.mythic.bukkit.MythicBukkit;
|
||||
import kr.toxicity.model.api.tracker.Tracker;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import me.Demon.DemonPlugin.Util.CDTimeAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerManager {
|
||||
|
||||
private HashMap<String, PlayerData> playerDataMap = new HashMap<>();
|
||||
private HashMap<String, PetCallSession> petCallMap = new HashMap<>();
|
||||
// private HashMap<UUID, ModeledEntity> petEntityModelMap = new HashMap<>();
|
||||
|
||||
public PlayerData getPlayerData(String name) {
|
||||
if (!playerDataMap.containsKey(name)) {
|
||||
playerDataMap.put(name, new PlayerData(name));
|
||||
}
|
||||
return playerDataMap.get(name);
|
||||
}
|
||||
|
||||
public void saveAllData() {
|
||||
for (PlayerData playerData : playerDataMap.values()) {
|
||||
playerData.savePlayerData();
|
||||
}
|
||||
}
|
||||
|
||||
public void closeSaveData(String playerName) {
|
||||
PlayerData playerData = getPlayerData(playerName);
|
||||
playerData.savePlayerData();
|
||||
playerDataMap.remove(playerName);
|
||||
|
||||
removePetCall(playerName);
|
||||
}
|
||||
|
||||
public void closeSaveAllData() {
|
||||
for (PlayerData playerData : playerDataMap.values()) {
|
||||
playerData.savePlayerData();
|
||||
}
|
||||
playerDataMap.clear();
|
||||
for (PetCallSession session : petCallMap.values()) {
|
||||
session.close();
|
||||
}
|
||||
PetSQL.closeConnection();
|
||||
petCallMap.clear();
|
||||
}
|
||||
|
||||
public void setPetCall(String name, UUID ownerUuid, UUID entityUuid, Tracker tracker) {
|
||||
petCallMap.put(name, new PetCallSession(ownerUuid, entityUuid, tracker));
|
||||
}
|
||||
|
||||
public void removePetCall(String name) {
|
||||
PetCallSession session = petCallMap.remove(name);
|
||||
if (session != null) {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPetCallExit(String name) {
|
||||
PetCallSession session = petCallMap.get(name);
|
||||
if (session == null) {
|
||||
return false;
|
||||
}
|
||||
if (!session.isAlive()) {
|
||||
petCallMap.remove(name);
|
||||
session.close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getPetOwnerName(UUID entityUuid) {
|
||||
for (String name : petCallMap.keySet()) {
|
||||
PetCallSession session = petCallMap.get(name);
|
||||
if (session.getEntityUuid().equals(entityUuid)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public UUID getPetUUID(String name) {
|
||||
if (isPetCallExit(name)) {
|
||||
return petCallMap.get(name).getEntityUuid();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
public ModeledEntity getPetEntityModel(UUID entityUuid) {
|
||||
for (ModeledEntity entity : petEntityModelMap.values()) {
|
||||
if (entity.getBase().getUUID().equals(entityUuid)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setPetEntityModelMap(UUID entityUUID, ModeledEntity entityModel) {
|
||||
petEntityModelMap.put(entityUUID, entityModel);
|
||||
}*/
|
||||
|
||||
public void callPet(Player player) {
|
||||
String carryCdKey = "callPetStackCD";
|
||||
UUID uuid = player.getUniqueId();
|
||||
if (CDTimeAPI.isCD(uuid, carryCdKey)) {
|
||||
MessageUtil.sendMessageKey(player, "system_coolingDown", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
CDTimeAPI.setPlayerCD(uuid, carryCdKey, 1000 * 5);
|
||||
String playerName = player.getName();
|
||||
PlayerData playerData = getPlayerData(playerName);
|
||||
if (playerData == null) {
|
||||
return;
|
||||
}
|
||||
if (playerData.isPetStackNull()) {
|
||||
MessageUtil.sendMessageKey(player, "no_summons_pets_brought", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
// 判断玩家是否已经召唤宠物
|
||||
if (isPetCallExit(playerName)) {
|
||||
removePetCall(playerName);
|
||||
MessageUtil.sendMessageKey(player, "pet_summons_recovers", Sound.UI_BUTTON_CLICK);
|
||||
return;
|
||||
}
|
||||
int health = playerData.getPetNbt().health;
|
||||
if (health < 1) {
|
||||
MessageUtil.sendMessageKey(player, "no_summons_pets_health", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
String petStackName = DemonAPI.getItemName(playerData.getPetStack());
|
||||
CustomWolf wolf = CustomWolf.spawnCustomWolf(player, playerData.getPetNbt());
|
||||
PetData petData = playerData.getPetNbt().petData;
|
||||
String modelID = petData.getModelId();
|
||||
Tracker tracker = BetterModelUtil.spawnModel(player, wolf.getBukkitEntity(), modelID);
|
||||
if (tracker == null) {
|
||||
wolf.getBukkitEntity().remove();
|
||||
MessageUtil.sendMessage(player, "§c宠物模型载入失败,召唤已取消。", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
setPetCall(playerName, player.getUniqueId(), wolf.getUUID(), tracker);
|
||||
/*ActiveModel model = ModelEngineAPI.createActiveModel(modelID);
|
||||
if (model != null) {
|
||||
ModeledEntity modeledEntity = ModelEngineAPI.createModeledEntity(wolf.getBukkitEntity());
|
||||
setPetEntityModelMap(wolf.getUUID(), modeledEntity);
|
||||
modeledEntity.addModel(model, true);
|
||||
modeledEntity.setBaseEntityVisible(false);
|
||||
model.setHitboxVisible(true);
|
||||
model.setShadowVisible(true);
|
||||
String text = Config.getLanguage("pet_name_tag")
|
||||
.replace("{name}", playerName)
|
||||
.replace("{petName}", petStackName);
|
||||
|
||||
wolf.setCustomName(Component.literal(text));
|
||||
wolf.setCustomNameVisible(true);
|
||||
|
||||
NameTag tag = PetUtil.getNameBone(modeledEntity, "name");
|
||||
if (tag != null) {
|
||||
tag.setString(text);
|
||||
tag.setVisible(true);
|
||||
}
|
||||
int petLevel = playerData.getPetNbt().level;
|
||||
double healthNow = wolf.getHealth();
|
||||
double healthMax = wolf.getMaxHealth();
|
||||
// 计算获得血量百分比
|
||||
int percent = (int) Math.round((healthNow / healthMax) * 100.0);
|
||||
String levelText = Config.getLanguage("pet_level_tag")
|
||||
.replace("{level}", Config.getLevelChar(petLevel))
|
||||
.replace("{health}", Config.getHealthChar(percent));
|
||||
NameTag levelTag = PetUtil.getNameBone(modeledEntity, "level");
|
||||
if (levelTag != null) {
|
||||
levelTag.setString(levelText);
|
||||
levelTag.setVisible(true);
|
||||
}
|
||||
Bukkit.getConsoleSender().sendMessage("[日志 - 宠物] 模型资源 " + modelID + " 载入成功!");
|
||||
} else {
|
||||
Bukkit.getConsoleSender().sendMessage("[日志 - 宠物] 模型资源 " + modelID + " 载入失败!");
|
||||
}*/
|
||||
String summonSkill = petData.getSummonSkill();
|
||||
if (!"default".equalsIgnoreCase(summonSkill)) {
|
||||
Bukkit.getScheduler().runTaskLater(PetMain.inst(), () -> {
|
||||
if (wolf.isRemoved() || wolf.getBukkitLivingEntity().isDead()) {
|
||||
return;
|
||||
}
|
||||
MythicBukkit.inst().getAPIHelper().castSkill(wolf.getBukkitLivingEntity(), summonSkill, wolf.getBukkitLivingEntity().getLocation());
|
||||
player.sendMessage("[调试 - 宠物技能] 触发条件: onSpawn 触发技能: "+summonSkill);
|
||||
}, 2L);
|
||||
}
|
||||
// 设置宠物召唤状态
|
||||
MessageUtil.sendMessageKey(player, "pet_summons_success", Sound.UI_BUTTON_CLICK);
|
||||
// 发布事件
|
||||
PetCallEvent event = new PetCallEvent(player, wolf.getBukkitEntity().getCustomName(), wolf.getUUID());
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
public void carryPetStackData(Player player) {
|
||||
String carryCdKey = "carryPetStackCD";
|
||||
UUID uuid = player.getUniqueId();
|
||||
if (CDTimeAPI.isCD(uuid, carryCdKey)) {
|
||||
MessageUtil.sendMessageKey(player, "system_coolingDown", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
CDTimeAPI.setPlayerCD(uuid, carryCdKey, 1000 * 5);
|
||||
String playerName = player.getName();
|
||||
PlayerData playerData = getPlayerData(playerName);
|
||||
if (playerData.isPetStackNull()) {
|
||||
ItemStack stack = player.getInventory().getItemInMainHand();
|
||||
if (DemonAPI.itemIsNull(stack)) {
|
||||
MessageUtil.sendMessageKey(player, "error_empty_hand", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
NBTItem nbtItem = new NBTItem(stack);
|
||||
if (!nbtItem.hasKey("petKey")) {
|
||||
MessageUtil.sendMessageKey(player, "hand_not_pet_stack", Sound.ENTITY_VILLAGER_NO);
|
||||
return;
|
||||
}
|
||||
player.getInventory().setItemInMainHand(null);
|
||||
playerData.setPetStack(stack);
|
||||
playerData.savePlayerData();
|
||||
String itemName = DemonAPI.getItemName(stack);
|
||||
String message = Config.getLanguage("pet_stack_carry_success");
|
||||
MessageUtil.sendMessage(player, message.replace("{petName}", itemName), Sound.ENTITY_PLAYER_LEVELUP);
|
||||
} else {
|
||||
removePetCall(playerName);
|
||||
playerData.refreshPetStack();
|
||||
ItemStack petStack = playerData.getPetStack();
|
||||
NBTItem nbtItem = new NBTItem(petStack);
|
||||
if (!nbtItem.hasKey("petKey")) {
|
||||
Bukkit.getConsoleSender().sendMessage("[日志 - 宠物] 未检测到宠物petKey的Nbt标识.");
|
||||
}
|
||||
player.getInventory().addItem(petStack);
|
||||
playerData.setPetStack(DemonAPI.getErrItems());
|
||||
playerData.savePlayerData();
|
||||
MessageUtil.sendMessageKey(player, "pet_stack_carry_takeOut", Sound.ENTITY_PLAYER_LEVELUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package com.yaohun.petsystem.model;
|
||||
|
||||
import com.yaohun.petsystem.data.PetData;
|
||||
import com.yaohun.petsystem.manage.LevelExpManager;
|
||||
import com.yaohun.petsystem.manage.PetManager;
|
||||
import de.tr7zw.nbtapi.NBTItem;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PetNbt {
|
||||
|
||||
private String petKey;
|
||||
public PetData petData;
|
||||
public int level;
|
||||
public int exp;
|
||||
public int maxExp;
|
||||
public int totalExp;
|
||||
public int damage;
|
||||
public int health;
|
||||
public int maxHealth;
|
||||
public int evolution;
|
||||
public PetQuality quality;
|
||||
|
||||
public PetNbt(PetData petData) {
|
||||
this.petKey = petData.getFileName();
|
||||
this.petData = petData;
|
||||
this.level = 1;
|
||||
this.maxExp = LevelExpManager.getNeedExpValue(level);
|
||||
this.exp = 0;
|
||||
this.totalExp = 0;
|
||||
this.damage = 7;
|
||||
this.health = 20;
|
||||
this.maxHealth = 20;
|
||||
this.evolution = 1;
|
||||
this.quality = PetQuality.random();
|
||||
}
|
||||
|
||||
public PetNbt() {
|
||||
}
|
||||
|
||||
public void loadNbtData(NBTItem nbtItem) {
|
||||
petKey = nbtItem.getString("petKey");
|
||||
petData = PetManager.getPetData(petKey);
|
||||
level = nbtItem.getInteger("level");
|
||||
exp = nbtItem.getInteger("exp");
|
||||
totalExp = nbtItem.getInteger("totalExp");
|
||||
maxExp = LevelExpManager.getNeedExpValue(level);
|
||||
damage = nbtItem.getInteger("damage");
|
||||
health = nbtItem.getInteger("health");
|
||||
maxHealth = nbtItem.getInteger("maxHealth");
|
||||
evolution = nbtItem.getInteger("evolution");
|
||||
int qualityFangs = nbtItem.getInteger("quality_fangs");
|
||||
int qualitySurvive = nbtItem.getInteger("quality_survive");
|
||||
int qualityEfficiency = nbtItem.getInteger("quality_efficiency");
|
||||
quality = new PetQuality(qualityFangs, qualitySurvive, qualityEfficiency);
|
||||
}
|
||||
|
||||
public ItemStack saveIoItem(ItemStack stack) {
|
||||
NBTItem nbtItem = new NBTItem(stack);
|
||||
nbtItem.setString("petKey", petKey);
|
||||
nbtItem.setInteger("level", level);
|
||||
nbtItem.setInteger("exp", exp);
|
||||
nbtItem.setInteger("totalExp", totalExp);
|
||||
nbtItem.setInteger("maxExp", LevelExpManager.getNeedExpValue(level));
|
||||
nbtItem.setInteger("damage", damage);
|
||||
nbtItem.setInteger("health", health);
|
||||
nbtItem.setInteger("maxHealth", maxHealth);
|
||||
nbtItem.setInteger("evolution", evolution);
|
||||
nbtItem.setInteger("quality_fangs", quality.getFangs());
|
||||
nbtItem.setInteger("quality_survive", quality.getSurvive());
|
||||
nbtItem.setInteger("quality_efficiency", quality.getEfficiency());
|
||||
return nbtItem.getItem();
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public void setExp(int exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public void setTotalExp(int totalExp) {
|
||||
this.totalExp = totalExp;
|
||||
}
|
||||
|
||||
public void setDamage(int damage) {
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
public void setHealth(int health) {
|
||||
this.health = health;
|
||||
}
|
||||
|
||||
public void setMaxHealth(int maxHealth) {
|
||||
this.maxHealth = maxHealth;
|
||||
}
|
||||
|
||||
public void setEvolution(int evolution) {
|
||||
this.evolution = evolution;
|
||||
}
|
||||
|
||||
public void setQuality(String qualityType, int value) {
|
||||
if ("quality_fangs".equals(qualityType)) {
|
||||
this.quality.setFangs(value);
|
||||
} else if ("quality_survive".equals(qualityType)) {
|
||||
this.quality.setSurvive(value);
|
||||
} else if ("quality_efficiency".equals(qualityType)) {
|
||||
this.quality.setEfficiency(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.yaohun.petsystem.model;
|
||||
|
||||
import me.Demon.DemonPlugin.Util.RandomUtil;
|
||||
|
||||
public class PetQuality {
|
||||
|
||||
private int fangs;
|
||||
|
||||
private int survive;
|
||||
|
||||
private int efficiency;
|
||||
|
||||
public PetQuality(int fangs, int survive, int efficiency) {
|
||||
this.fangs = fangs;
|
||||
this.survive = survive;
|
||||
this.efficiency = efficiency;
|
||||
}
|
||||
|
||||
public static PetQuality random() {
|
||||
int fangs = RandomUtil.getRandomInt(1, 100);
|
||||
int survive = RandomUtil.getRandomInt(1, 100);
|
||||
int efficiency = RandomUtil.getRandomInt(1, 100);
|
||||
return new PetQuality(fangs, survive, efficiency);
|
||||
}
|
||||
|
||||
public int getFangs() {
|
||||
return fangs;
|
||||
}
|
||||
|
||||
public void setFangs(int fangs) {
|
||||
this.fangs = fangs;
|
||||
}
|
||||
|
||||
public int getSurvive() {
|
||||
return survive;
|
||||
}
|
||||
|
||||
public void setSurvive(int survive) {
|
||||
this.survive = survive;
|
||||
}
|
||||
|
||||
public int getEfficiency() {
|
||||
return efficiency;
|
||||
}
|
||||
|
||||
public void setEfficiency(int efficiency) {
|
||||
this.efficiency = efficiency;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.yaohun.petsystem.util;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.config.Config;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MessageUtil {
|
||||
|
||||
private static HashMap<String, String> languageMap = new HashMap<>();
|
||||
|
||||
public static HashMap<String, String> getLanguageMap() {
|
||||
return languageMap;
|
||||
}
|
||||
|
||||
public static void init(PetMain plugin) {
|
||||
File file = new File(plugin.getDataFolder(), "lang.yml");
|
||||
if (!file.exists()) {
|
||||
plugin.saveResource("lang.yml", false);
|
||||
}
|
||||
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||
for (String key : config.getKeys(false)) {
|
||||
ConfigurationSection section = config.getConfigurationSection(key);
|
||||
for (String key2 : section.getKeys(false)) {
|
||||
String message = section.getString(key2).replace("&", "§");
|
||||
languageMap.put(key2, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendMessageKey(CommandSender sender, String key, Sound sound) {
|
||||
String message = Config.getLanguage(key);
|
||||
sender.sendMessage(convertHexColor(message));
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
player.playSound(player.getLocation(), sound, 0.8f, 1.2f);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendMessage(CommandSender sender, String message, Sound sound) {
|
||||
message = convertHexColor(message);
|
||||
sender.sendMessage(message);
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
player.playSound(player.getLocation(), sound, 0.8f, 1.2f);
|
||||
}
|
||||
}
|
||||
|
||||
public static String convertHexColor(String text) {
|
||||
if (text == null) return "";
|
||||
|
||||
// 匹配形如 #FFFFFF 的十六进制颜色代码
|
||||
Pattern pattern = Pattern.compile("#[A-Fa-f0-9]{6}");
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
// 去掉#
|
||||
while (matcher.find()) {
|
||||
String hex = matcher.group().substring(1);
|
||||
StringBuilder colorBuilder = new StringBuilder("§x");
|
||||
for (char c : hex.toCharArray()) {
|
||||
colorBuilder.append('§').append(c);
|
||||
}
|
||||
matcher.appendReplacement(buffer, colorBuilder.toString());
|
||||
}
|
||||
matcher.appendTail(buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
package com.yaohun.petsystem.util;
|
||||
|
||||
import com.yaohun.petsystem.PetMain;
|
||||
import com.yaohun.petsystem.config.Config;
|
||||
import com.yaohun.petsystem.data.PlayerData;
|
||||
import com.yaohun.petsystem.manage.LevelExpManager;
|
||||
import com.yaohun.petsystem.manage.PlayerManager;
|
||||
import com.yaohun.petsystem.model.PetNbt;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.bukkit.entity.Wolf;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PetUtil {
|
||||
|
||||
public static ItemStack refreshPetStackData(PetNbt petNbt) {
|
||||
return getPetStackDefault(petNbt);
|
||||
}
|
||||
|
||||
public static ItemStack getPetStackDefault(PetNbt petNbt) {
|
||||
// 获取相关默认参数
|
||||
String petName = petNbt.petData.getPetName();
|
||||
ItemStack stack = Config.getPetStackTemplate();
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
// 获取当前显示名
|
||||
String templateName = "{name}";
|
||||
if (meta.hasDisplayName()) {
|
||||
Component comp = meta.displayName();
|
||||
if (comp != null) {
|
||||
// 将组件转换为普通字符串
|
||||
templateName = PlainTextComponentSerializer.plainText().serialize(comp);
|
||||
}
|
||||
}
|
||||
// 替换占位符
|
||||
String replaced = templateName.replace("{name}", petName);
|
||||
// 正确方式:直接用 Adventure Component 设置显示名
|
||||
// 设置新的显示名(新版 Adventure API)
|
||||
meta.displayName(Component.text(replaced)
|
||||
.color(NamedTextColor.GREEN)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
List<Component> newLore = new ArrayList<>();
|
||||
List<String> rawLore = meta.getLore();
|
||||
if (rawLore == null) {
|
||||
rawLore = new ArrayList<>();
|
||||
}
|
||||
|
||||
for (String line : rawLore) {
|
||||
String string = line
|
||||
.replace("{name}", petName)
|
||||
.replace("{fangs}", String.valueOf(petNbt.quality.getFangs()))
|
||||
.replace("{survive}", String.valueOf(petNbt.quality.getSurvive()))
|
||||
.replace("{efficiency}", String.valueOf(petNbt.quality.getEfficiency()))
|
||||
.replace("{level}", String.valueOf(petNbt.level))
|
||||
.replace("{exp}", String.valueOf(petNbt.exp))
|
||||
.replace("{maxExp}", String.valueOf(LevelExpManager.getNeedExpValue(petNbt.level)))
|
||||
.replace("{damage}", String.valueOf(petNbt.damage))
|
||||
.replace("{health}", String.valueOf(petNbt.health))
|
||||
.replace("{maxHealth}", String.valueOf(petNbt.maxHealth));
|
||||
newLore.add(Component.text(MessageUtil.convertHexColor(string)).decoration(TextDecoration.ITALIC, false));
|
||||
}
|
||||
meta.lore(newLore);
|
||||
meta.setCustomModelData(petNbt.petData.getCustomIconModelId());
|
||||
stack.setItemMeta(meta);
|
||||
return stack;
|
||||
}
|
||||
|
||||
public static ItemStack getPetGuiStack(PlayerData playerData, String guiStackID) {
|
||||
// 1.获取玩家数据
|
||||
PetNbt petNbt = playerData.getPetNbt();
|
||||
ItemStack petStack = playerData.getPetStack();
|
||||
|
||||
ItemStack stack = Config.getItemStack(guiStackID);
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
// 设置新的显示名(新版 Adventure API)
|
||||
meta.displayName(Component.text(petStack.getItemMeta().getDisplayName())
|
||||
.color(NamedTextColor.GREEN)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
List<Component> newLore = new ArrayList<>();
|
||||
List<String> rawLore = meta.getLore();
|
||||
if (rawLore == null) {
|
||||
rawLore = new ArrayList<>();
|
||||
}
|
||||
|
||||
String statsName = "休息中";
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
if (playerManager.isPetCallExit(playerData.getPlayerName())) {
|
||||
statsName = "出战中";
|
||||
}
|
||||
for (String line : rawLore) {
|
||||
String string = line
|
||||
.replace("{stats}", statsName)
|
||||
.replace("{fangs}", String.valueOf(petNbt.quality.getFangs()))
|
||||
.replace("{survive}", String.valueOf(petNbt.quality.getSurvive()))
|
||||
.replace("{efficiency}", String.valueOf(petNbt.quality.getEfficiency()))
|
||||
.replace("{level}", String.valueOf(petNbt.level))
|
||||
.replace("{exp}", String.valueOf(petNbt.exp))
|
||||
.replace("{maxExp}", String.valueOf(LevelExpManager.getNeedExpValue(petNbt.level)))
|
||||
.replace("{damage}", String.valueOf(petNbt.damage))
|
||||
.replace("{health}", String.valueOf(petNbt.health))
|
||||
.replace("{maxHealth}", String.valueOf(petNbt.maxHealth));
|
||||
newLore.add(Component.text(MessageUtil.convertHexColor(string)).decoration(TextDecoration.ITALIC, false));
|
||||
}
|
||||
meta.lore(newLore);
|
||||
meta.setCustomModelData(petNbt.petData.getCustomIconModelId());
|
||||
stack.setItemMeta(meta);
|
||||
return stack;
|
||||
}
|
||||
|
||||
/*public static NameTag getNameBone(ModeledEntity model, String stringType) {
|
||||
if (model == null) {
|
||||
return null;
|
||||
}
|
||||
if (model.getModels().size() == 0) {
|
||||
return null;
|
||||
}
|
||||
Optional<ActiveModel> opt = model.getModels().values().stream().findFirst();
|
||||
ActiveModel activeModel = null;
|
||||
if (opt.isPresent()) {
|
||||
activeModel = opt.get();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
ModelBone bone = activeModel.getBone(stringType)
|
||||
.stream()
|
||||
.filter(modelBone -> modelBone.getBoneBehavior(BoneBehaviorTypes.NAMETAG).orElse(null) != null)
|
||||
.findFirst().orElse(null);
|
||||
if (bone == null) {
|
||||
return null;
|
||||
}
|
||||
NameTag nameTag = bone.getBoneBehavior(BoneBehaviorTypes.NAMETAG).orElse(null);
|
||||
return nameTag;
|
||||
}*/
|
||||
public static PlayerData updatePetNameTag(Wolf wolf) {
|
||||
PlayerManager playerManager = PetMain.getPlayerManager();
|
||||
if (wolf == null || wolf.isDead()) {
|
||||
return null;
|
||||
}
|
||||
UUID petUuid = wolf.getUniqueId();
|
||||
String ownerName = playerManager.getPetOwnerName(petUuid);
|
||||
if (ownerName == null) {
|
||||
return null;
|
||||
}
|
||||
PlayerData playerData = playerManager.getPlayerData(ownerName);
|
||||
// 判断玩家是否召唤宠物
|
||||
if (playerManager.isPetCallExit(ownerName)) {
|
||||
/*// 获取宠物的的模型文件
|
||||
ModeledEntity modeledEntity = playerManager.getPetEntityModel(petUuid);
|
||||
if (modeledEntity == null) {
|
||||
return null;
|
||||
}
|
||||
int petLevel = playerData.getPetNbt().level;
|
||||
double healthNow = wolf.getHealth();
|
||||
double healthMax = wolf.getMaxHealth();
|
||||
// 计算获得血量百分比
|
||||
int percent = (int) Math.round((healthNow / healthMax) * 100.0);
|
||||
String levelText = Config.getLanguage("pet_level_tag")
|
||||
.replace("{level}", Config.getLevelChar(petLevel))
|
||||
.replace("{health}", Config.getHealthChar(percent));
|
||||
NameTag levelTag = PetUtil.getNameBone(modeledEntity, "level");
|
||||
if (levelTag != null) {
|
||||
levelTag.setString(levelText);
|
||||
levelTag.setVisible(true);
|
||||
}*/
|
||||
return playerData;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.yaohun.petsystem.util.model;
|
||||
|
||||
import kr.toxicity.model.api.BetterModel;
|
||||
import kr.toxicity.model.api.bukkit.platform.BukkitAdapter;
|
||||
import kr.toxicity.model.api.data.renderer.ModelRenderer;
|
||||
import kr.toxicity.model.api.tracker.EntityTracker;
|
||||
import kr.toxicity.model.api.tracker.Tracker;
|
||||
import kr.toxicity.model.api.tracker.TrackerModifier;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BetterModelUtil {
|
||||
|
||||
public static Tracker spawnModel(Player owner, Entity entity, String modelId) {
|
||||
if (entity == null || entity.isDead()) {
|
||||
Bukkit.getLogger().warning("宠物模型载入失败: 实体不存在");
|
||||
return null;
|
||||
}
|
||||
if (modelId == null || modelId.isBlank()) {
|
||||
Bukkit.getLogger().warning("宠物模型载入失败: 模型ID为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
ModelRenderer renderer = BetterModel.modelOrNull(modelId);
|
||||
if (renderer == null) {
|
||||
Bukkit.getLogger().warning("宠物模型不存在: " + modelId);
|
||||
return null;
|
||||
}
|
||||
|
||||
EntityTracker tracker = renderer.create(
|
||||
BukkitAdapter.adapt(entity),
|
||||
getPetTrackerModifier(),
|
||||
BetterModelUtil::refreshModelTracker
|
||||
);
|
||||
|
||||
refreshModelTracker(tracker);
|
||||
spawnVisiblePlayers(tracker, entity);
|
||||
Bukkit.getLogger().info("宠物模型载入成功: 玩家=" + owner.getName() + ", 模型=" + modelId + ", 实体=" + entity.getUniqueId());
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
||||
public static void spawnVisiblePlayers(Tracker tracker, Entity entity) {
|
||||
if (tracker == null || tracker.isClosed() || entity == null) {
|
||||
return;
|
||||
}
|
||||
for (Player viewer : Bukkit.getOnlinePlayers()) {
|
||||
if (!viewer.isOnline()) {
|
||||
continue;
|
||||
}
|
||||
if (!viewer.getWorld().equals(entity.getWorld())) {
|
||||
continue;
|
||||
}
|
||||
if (tracker instanceof EntityTracker entityTracker) {
|
||||
entityTracker.registry().spawnIfNotSpawned(BukkitAdapter.adapt(viewer));
|
||||
} else {
|
||||
tracker.show(BukkitAdapter.adapt(viewer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void refreshModelTracker(Tracker tracker) {
|
||||
if (tracker == null || tracker.isClosed()) {
|
||||
return;
|
||||
}
|
||||
if (tracker instanceof EntityTracker entityTracker) {
|
||||
entityTracker.updateBaseEntity();
|
||||
entityTracker.refresh();
|
||||
}
|
||||
tracker.forceUpdate(true);
|
||||
}
|
||||
|
||||
private static TrackerModifier getPetTrackerModifier() {
|
||||
return TrackerModifier.DEFAULT.toBuilder()
|
||||
.sightTrace(false)
|
||||
.damageAnimation(false)
|
||||
.damageTint(false)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
NeedExpSettings:
|
||||
1: 10000
|
||||
2: 10000
|
||||
3: 10000
|
||||
4: 10000
|
||||
5: 10000
|
||||
6: 10000
|
||||
7: 10000
|
||||
8: 10000
|
||||
9: 10000
|
||||
10: 10000
|
||||
11: 10000
|
||||
12: 10000
|
||||
13: 10000
|
||||
14: 10000
|
||||
15: 10000
|
||||
16: 10000
|
||||
17: 10000
|
||||
18: 10000
|
||||
19: 10000
|
||||
20: 10000
|
||||
21: 10000
|
||||
22: 10000
|
||||
23: 10000
|
||||
24: 10000
|
||||
25: 10000
|
||||
26: 10000
|
||||
27: 10000
|
||||
28: 10000
|
||||
29: 10000
|
||||
30: -1
|
||||
@@ -1,6 +0,0 @@
|
||||
name: AuPet
|
||||
main: com.yaohun.petsystem.PetMain
|
||||
version: 1.0.1
|
||||
api-version: 1.21
|
||||
commands:
|
||||
apet:
|
||||
Reference in New Issue
Block a user