初始化项目
This commit is contained in:
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
target/
|
||||||
|
out/
|
||||||
|
lib/
|
||||||
|
libs/
|
||||||
|
.vscode/
|
||||||
|
.codex/
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
*.db
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite3
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
604
README2.md
Normal file
604
README2.md
Normal file
@@ -0,0 +1,604 @@
|
|||||||
|
# 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、领取奖励、退出保存的冒烟测试。
|
||||||
77
pom.xml
Normal file
77
pom.xml
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.yaohun.main</groupId>
|
||||||
|
<artifactId>AuPet</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<parent.project.dir>${project.basedir}/..</parent.project.dir>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>papermc-repo</id>
|
||||||
|
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.papermc.paper</groupId>
|
||||||
|
<artifactId>paper-api</artifactId>
|
||||||
|
<version>1.21.8-R0.1-SNAPSHOT</version>
|
||||||
|
<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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
265
src/main/java/com/yaohun/petsystem/PetMain.java
Normal file
265
src/main/java/com/yaohun/petsystem/PetMain.java
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
122
src/main/java/com/yaohun/petsystem/api/PetExpAPI.java
Normal file
122
src/main/java/com/yaohun/petsystem/api/PetExpAPI.java
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
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]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.yaohun.petsystem.command;
|
||||||
|
|
||||||
|
public class PetCommand {
|
||||||
|
}
|
||||||
141
src/main/java/com/yaohun/petsystem/config/Config.java
Normal file
141
src/main/java/com/yaohun/petsystem/config/Config.java
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
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 + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
86
src/main/java/com/yaohun/petsystem/data/PetData.java
Normal file
86
src/main/java/com/yaohun/petsystem/data/PetData.java
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/main/java/com/yaohun/petsystem/data/PetSQL.java
Normal file
105
src/main/java/com/yaohun/petsystem/data/PetSQL.java
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
136
src/main/java/com/yaohun/petsystem/data/PlayerData.java
Normal file
136
src/main/java/com/yaohun/petsystem/data/PlayerData.java
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/main/java/com/yaohun/petsystem/data/SkillData.java
Normal file
60
src/main/java/com/yaohun/petsystem/data/SkillData.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/main/java/com/yaohun/petsystem/event/PetCallEvent.java
Normal file
47
src/main/java/com/yaohun/petsystem/event/PetCallEvent.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/main/java/com/yaohun/petsystem/gui/CarryGui.java
Normal file
89
src/main/java/com/yaohun/petsystem/gui/CarryGui.java
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
206
src/main/java/com/yaohun/petsystem/gui/FeedingGui.java
Normal file
206
src/main/java/com/yaohun/petsystem/gui/FeedingGui.java
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
185
src/main/java/com/yaohun/petsystem/gui/MainGui.java
Normal file
185
src/main/java/com/yaohun/petsystem/gui/MainGui.java
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
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();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/main/java/com/yaohun/petsystem/manage/PetManager.java
Normal file
71
src/main/java/com/yaohun/petsystem/manage/PetManager.java
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
253
src/main/java/com/yaohun/petsystem/manage/PlayerManager.java
Normal file
253
src/main/java/com/yaohun/petsystem/manage/PlayerManager.java
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
111
src/main/java/com/yaohun/petsystem/model/PetNbt.java
Normal file
111
src/main/java/com/yaohun/petsystem/model/PetNbt.java
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main/java/com/yaohun/petsystem/model/PetQuality.java
Normal file
49
src/main/java/com/yaohun/petsystem/model/PetQuality.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/main/java/com/yaohun/petsystem/util/MessageUtil.java
Normal file
78
src/main/java/com/yaohun/petsystem/util/MessageUtil.java
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
178
src/main/java/com/yaohun/petsystem/util/PetUtil.java
Normal file
178
src/main/java/com/yaohun/petsystem/util/PetUtil.java
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
202
src/main/java/com/yaohun/petsystem/util/wolf/CustomWolf.java
Normal file
202
src/main/java/com/yaohun/petsystem/util/wolf/CustomWolf.java
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
package com.yaohun.petsystem.util.wolf;
|
||||||
|
|
||||||
|
import com.yaohun.petsystem.model.PetNbt;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.animal.wolf.Wolf;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.attribute.Attribute;
|
||||||
|
import org.bukkit.attribute.AttributeInstance;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义的狼实体类,用于实现“跟随玩家”的宠物功能。
|
||||||
|
* 继承原版 NMS Wolf 实体,通过 tick() 方法控制移动与传送。
|
||||||
|
*/
|
||||||
|
public class CustomWolf extends Wolf {
|
||||||
|
|
||||||
|
private static final double STOP_DISTANCE_SQ = 9.0D;
|
||||||
|
private static final double TELEPORT_DISTANCE_SQ = 144.0D;
|
||||||
|
private static final double LOOK_DISTANCE_SQ = 256.0D;
|
||||||
|
private static final double FOLLOW_SPEED = 1.2D;
|
||||||
|
private static final double DEFAULT_MOVEMENT_SPEED = 0.4D;
|
||||||
|
private static final int PATH_RECALC_TICKS = 10;
|
||||||
|
|
||||||
|
private final UUID ownerUuid;
|
||||||
|
|
||||||
|
private int timeToRecalcPath = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法:初始化宠物实体
|
||||||
|
*
|
||||||
|
* @param world NMS 世界对象
|
||||||
|
* @param owner 宠物主人(Bukkit Player)
|
||||||
|
*/
|
||||||
|
public CustomWolf(Level world, Player owner) {
|
||||||
|
super(EntityType.WOLF, world);
|
||||||
|
this.ownerUuid = owner.getUniqueId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每 tick 执行的逻辑,控制宠物的移动与状态
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
|
Player owner = Bukkit.getPlayer(ownerUuid);
|
||||||
|
if (owner == null || !owner.isOnline()) {
|
||||||
|
this.discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (owner.isDead()) {
|
||||||
|
this.getNavigation().stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!owner.getWorld().equals(this.getBukkitEntity().getWorld())) {
|
||||||
|
this.getNavigation().stop();
|
||||||
|
teleportToOwnerLocation(owner);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
net.minecraft.world.entity.player.Player nmsOwner = ((CraftPlayer) owner).getHandle();
|
||||||
|
|
||||||
|
double distanceSq = this.distanceToSqr(nmsOwner);
|
||||||
|
|
||||||
|
if (distanceSq < STOP_DISTANCE_SQ) {
|
||||||
|
this.getNavigation().stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldTeleport = distanceSq > TELEPORT_DISTANCE_SQ;
|
||||||
|
|
||||||
|
if (!shouldTeleport && distanceSq <= LOOK_DISTANCE_SQ) {
|
||||||
|
this.getLookControl().setLookAt(nmsOwner, 10.0F, this.getMaxHeadXRot());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--this.timeToRecalcPath <= 0) {
|
||||||
|
this.timeToRecalcPath = PATH_RECALC_TICKS;
|
||||||
|
|
||||||
|
if (shouldTeleport) {
|
||||||
|
if (!tryTeleportNearOwner(nmsOwner)) {
|
||||||
|
this.getNavigation().moveTo(nmsOwner, FOLLOW_SPEED);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.getNavigation().moveTo(nmsOwner, FOLLOW_SPEED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当宠物距离主人太远时,尝试在主人周围随机传送
|
||||||
|
*
|
||||||
|
* @param nmsOwner 主人 NMS 实体
|
||||||
|
*/
|
||||||
|
private boolean tryTeleportNearOwner(Entity nmsOwner) {
|
||||||
|
Vec3 pos = nmsOwner.position();
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
int x = (int) Math.floor(pos.x) + (random.nextInt(7) - 3);
|
||||||
|
int y = (int) Math.floor(pos.y);
|
||||||
|
int z = (int) Math.floor(pos.z) + (random.nextInt(7) - 3);
|
||||||
|
|
||||||
|
Location location = new Location(getBukkitEntity().getWorld(), x + 0.5D, y, z + 0.5D);
|
||||||
|
if (isSafeTeleportLocation(location)) {
|
||||||
|
this.teleportTo(location.getX(), location.getY(), location.getZ());
|
||||||
|
this.getNavigation().stop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void teleportToOwnerLocation(Player owner) {
|
||||||
|
Location location = owner.getLocation();
|
||||||
|
if (isSafeTeleportLocation(location)) {
|
||||||
|
this.getBukkitEntity().teleport(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSafeTeleportLocation(Location location) {
|
||||||
|
Block feet = location.getBlock();
|
||||||
|
Block head = feet.getRelative(0, 1, 0);
|
||||||
|
Block ground = feet.getRelative(0, -1, 0);
|
||||||
|
if (!feet.isPassable() || !head.isPassable() || !ground.getType().isSolid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!location.getWorld().equals(getBukkitEntity().getWorld())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return this.level().noCollision(this, this.getBoundingBox().move(
|
||||||
|
location.getX() - this.getX(),
|
||||||
|
location.getY() - this.getY(),
|
||||||
|
location.getZ() - this.getZ()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重写受伤方法,防止主人伤害到自己的宠物
|
||||||
|
*
|
||||||
|
* @param source 伤害来源
|
||||||
|
* @param amount 伤害数值
|
||||||
|
* @return 是否成功造成伤害
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean hurtServer(ServerLevel level, DamageSource source, float amount) {
|
||||||
|
Entity entity = source.getEntity();
|
||||||
|
|
||||||
|
if (entity != null && entity.getUUID().equals(ownerUuid)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return super.hurtServer(level, source, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态方法:用于在 Bukkit 世界中生成并注册一只 CustomWolf
|
||||||
|
*
|
||||||
|
* @param owner 宠物主人
|
||||||
|
* @return 新生成的 CustomWolf 实例
|
||||||
|
*/
|
||||||
|
public static CustomWolf spawnCustomWolf(Player owner, PetNbt petNbt) {
|
||||||
|
CraftWorld world = (CraftWorld) owner.getWorld();
|
||||||
|
Level nmsWorld = world.getHandle();
|
||||||
|
|
||||||
|
CustomWolf wolf = new CustomWolf(nmsWorld, owner);
|
||||||
|
|
||||||
|
wolf.setSilent(true);
|
||||||
|
wolf.setOrderedToSit(false);
|
||||||
|
wolf.setPos(owner.getLocation().getX(), owner.getLocation().getY(), owner.getLocation().getZ());
|
||||||
|
|
||||||
|
LivingEntity livingEntity = wolf.getBukkitLivingEntity();
|
||||||
|
double maxHealth = Math.max(1.0D, petNbt.maxHealth);
|
||||||
|
double health = Math.max(1.0D, Math.min(petNbt.health, maxHealth));
|
||||||
|
double damage = Math.max(0.0D, petNbt.damage);
|
||||||
|
|
||||||
|
setAttribute(livingEntity, Attribute.MAX_HEALTH, maxHealth);
|
||||||
|
setAttribute(livingEntity, Attribute.MOVEMENT_SPEED, DEFAULT_MOVEMENT_SPEED);
|
||||||
|
setAttribute(livingEntity, Attribute.ATTACK_DAMAGE, damage);
|
||||||
|
livingEntity.setHealth(health);
|
||||||
|
|
||||||
|
nmsWorld.addFreshEntity(wolf);
|
||||||
|
|
||||||
|
return wolf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setAttribute(LivingEntity entity, Attribute attribute, double value) {
|
||||||
|
AttributeInstance instance = entity.getAttribute(attribute);
|
||||||
|
if (instance != null) {
|
||||||
|
instance.setBaseValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/main/resources/config.yml
Normal file
31
src/main/resources/config.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
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
|
||||||
0
src/main/resources/lang.yml
Normal file
0
src/main/resources/lang.yml
Normal file
6
src/main/resources/plugin.yml
Normal file
6
src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
name: AuPet
|
||||||
|
main: com.yaohun.petsystem.PetMain
|
||||||
|
version: 1.0.1
|
||||||
|
api-version: 1.21
|
||||||
|
commands:
|
||||||
|
apet:
|
||||||
265
src/src/main/java/com/yaohun/petsystem/PetMain.java
Normal file
265
src/src/main/java/com/yaohun/petsystem/PetMain.java
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
122
src/src/main/java/com/yaohun/petsystem/api/PetExpAPI.java
Normal file
122
src/src/main/java/com/yaohun/petsystem/api/PetExpAPI.java
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
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]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.yaohun.petsystem.command;
|
||||||
|
|
||||||
|
public class PetCommand {
|
||||||
|
}
|
||||||
141
src/src/main/java/com/yaohun/petsystem/config/Config.java
Normal file
141
src/src/main/java/com/yaohun/petsystem/config/Config.java
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
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 + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
86
src/src/main/java/com/yaohun/petsystem/data/PetData.java
Normal file
86
src/src/main/java/com/yaohun/petsystem/data/PetData.java
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/src/main/java/com/yaohun/petsystem/data/PetSQL.java
Normal file
105
src/src/main/java/com/yaohun/petsystem/data/PetSQL.java
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
136
src/src/main/java/com/yaohun/petsystem/data/PlayerData.java
Normal file
136
src/src/main/java/com/yaohun/petsystem/data/PlayerData.java
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/src/main/java/com/yaohun/petsystem/data/SkillData.java
Normal file
60
src/src/main/java/com/yaohun/petsystem/data/SkillData.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/src/main/java/com/yaohun/petsystem/gui/CarryGui.java
Normal file
89
src/src/main/java/com/yaohun/petsystem/gui/CarryGui.java
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
206
src/src/main/java/com/yaohun/petsystem/gui/FeedingGui.java
Normal file
206
src/src/main/java/com/yaohun/petsystem/gui/FeedingGui.java
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
185
src/src/main/java/com/yaohun/petsystem/gui/MainGui.java
Normal file
185
src/src/main/java/com/yaohun/petsystem/gui/MainGui.java
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
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();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
253
src/src/main/java/com/yaohun/petsystem/manage/PlayerManager.java
Normal file
253
src/src/main/java/com/yaohun/petsystem/manage/PlayerManager.java
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
111
src/src/main/java/com/yaohun/petsystem/model/PetNbt.java
Normal file
111
src/src/main/java/com/yaohun/petsystem/model/PetNbt.java
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/src/main/java/com/yaohun/petsystem/model/PetQuality.java
Normal file
49
src/src/main/java/com/yaohun/petsystem/model/PetQuality.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/src/main/java/com/yaohun/petsystem/util/MessageUtil.java
Normal file
78
src/src/main/java/com/yaohun/petsystem/util/MessageUtil.java
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
178
src/src/main/java/com/yaohun/petsystem/util/PetUtil.java
Normal file
178
src/src/main/java/com/yaohun/petsystem/util/PetUtil.java
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
202
src/src/main/java/com/yaohun/petsystem/util/wolf/CustomWolf.java
Normal file
202
src/src/main/java/com/yaohun/petsystem/util/wolf/CustomWolf.java
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
package com.yaohun.petsystem.util.wolf;
|
||||||
|
|
||||||
|
import com.yaohun.petsystem.model.PetNbt;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.animal.wolf.Wolf;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.attribute.Attribute;
|
||||||
|
import org.bukkit.attribute.AttributeInstance;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义的狼实体类,用于实现“跟随玩家”的宠物功能。
|
||||||
|
* 继承原版 NMS Wolf 实体,通过 tick() 方法控制移动与传送。
|
||||||
|
*/
|
||||||
|
public class CustomWolf extends Wolf {
|
||||||
|
|
||||||
|
private static final double STOP_DISTANCE_SQ = 9.0D;
|
||||||
|
private static final double TELEPORT_DISTANCE_SQ = 144.0D;
|
||||||
|
private static final double LOOK_DISTANCE_SQ = 256.0D;
|
||||||
|
private static final double FOLLOW_SPEED = 1.2D;
|
||||||
|
private static final double DEFAULT_MOVEMENT_SPEED = 0.4D;
|
||||||
|
private static final int PATH_RECALC_TICKS = 10;
|
||||||
|
|
||||||
|
private final UUID ownerUuid;
|
||||||
|
|
||||||
|
private int timeToRecalcPath = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法:初始化宠物实体
|
||||||
|
*
|
||||||
|
* @param world NMS 世界对象
|
||||||
|
* @param owner 宠物主人(Bukkit Player)
|
||||||
|
*/
|
||||||
|
public CustomWolf(Level world, Player owner) {
|
||||||
|
super(EntityType.WOLF, world);
|
||||||
|
this.ownerUuid = owner.getUniqueId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每 tick 执行的逻辑,控制宠物的移动与状态
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
|
Player owner = Bukkit.getPlayer(ownerUuid);
|
||||||
|
if (owner == null || !owner.isOnline()) {
|
||||||
|
this.discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (owner.isDead()) {
|
||||||
|
this.getNavigation().stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!owner.getWorld().equals(this.getBukkitEntity().getWorld())) {
|
||||||
|
this.getNavigation().stop();
|
||||||
|
teleportToOwnerLocation(owner);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
net.minecraft.world.entity.player.Player nmsOwner = ((CraftPlayer) owner).getHandle();
|
||||||
|
|
||||||
|
double distanceSq = this.distanceToSqr(nmsOwner);
|
||||||
|
|
||||||
|
if (distanceSq < STOP_DISTANCE_SQ) {
|
||||||
|
this.getNavigation().stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldTeleport = distanceSq > TELEPORT_DISTANCE_SQ;
|
||||||
|
|
||||||
|
if (!shouldTeleport && distanceSq <= LOOK_DISTANCE_SQ) {
|
||||||
|
this.getLookControl().setLookAt(nmsOwner, 10.0F, this.getMaxHeadXRot());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--this.timeToRecalcPath <= 0) {
|
||||||
|
this.timeToRecalcPath = PATH_RECALC_TICKS;
|
||||||
|
|
||||||
|
if (shouldTeleport) {
|
||||||
|
if (!tryTeleportNearOwner(nmsOwner)) {
|
||||||
|
this.getNavigation().moveTo(nmsOwner, FOLLOW_SPEED);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.getNavigation().moveTo(nmsOwner, FOLLOW_SPEED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当宠物距离主人太远时,尝试在主人周围随机传送
|
||||||
|
*
|
||||||
|
* @param nmsOwner 主人 NMS 实体
|
||||||
|
*/
|
||||||
|
private boolean tryTeleportNearOwner(Entity nmsOwner) {
|
||||||
|
Vec3 pos = nmsOwner.position();
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
int x = (int) Math.floor(pos.x) + (random.nextInt(7) - 3);
|
||||||
|
int y = (int) Math.floor(pos.y);
|
||||||
|
int z = (int) Math.floor(pos.z) + (random.nextInt(7) - 3);
|
||||||
|
|
||||||
|
Location location = new Location(getBukkitEntity().getWorld(), x + 0.5D, y, z + 0.5D);
|
||||||
|
if (isSafeTeleportLocation(location)) {
|
||||||
|
this.teleportTo(location.getX(), location.getY(), location.getZ());
|
||||||
|
this.getNavigation().stop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void teleportToOwnerLocation(Player owner) {
|
||||||
|
Location location = owner.getLocation();
|
||||||
|
if (isSafeTeleportLocation(location)) {
|
||||||
|
this.getBukkitEntity().teleport(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSafeTeleportLocation(Location location) {
|
||||||
|
Block feet = location.getBlock();
|
||||||
|
Block head = feet.getRelative(0, 1, 0);
|
||||||
|
Block ground = feet.getRelative(0, -1, 0);
|
||||||
|
if (!feet.isPassable() || !head.isPassable() || !ground.getType().isSolid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!location.getWorld().equals(getBukkitEntity().getWorld())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return this.level().noCollision(this, this.getBoundingBox().move(
|
||||||
|
location.getX() - this.getX(),
|
||||||
|
location.getY() - this.getY(),
|
||||||
|
location.getZ() - this.getZ()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重写受伤方法,防止主人伤害到自己的宠物
|
||||||
|
*
|
||||||
|
* @param source 伤害来源
|
||||||
|
* @param amount 伤害数值
|
||||||
|
* @return 是否成功造成伤害
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean hurtServer(ServerLevel level, DamageSource source, float amount) {
|
||||||
|
Entity entity = source.getEntity();
|
||||||
|
|
||||||
|
if (entity != null && entity.getUUID().equals(ownerUuid)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return super.hurtServer(level, source, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态方法:用于在 Bukkit 世界中生成并注册一只 CustomWolf
|
||||||
|
*
|
||||||
|
* @param owner 宠物主人
|
||||||
|
* @return 新生成的 CustomWolf 实例
|
||||||
|
*/
|
||||||
|
public static CustomWolf spawnCustomWolf(Player owner, PetNbt petNbt) {
|
||||||
|
CraftWorld world = (CraftWorld) owner.getWorld();
|
||||||
|
Level nmsWorld = world.getHandle();
|
||||||
|
|
||||||
|
CustomWolf wolf = new CustomWolf(nmsWorld, owner);
|
||||||
|
|
||||||
|
wolf.setSilent(true);
|
||||||
|
wolf.setOrderedToSit(false);
|
||||||
|
wolf.setPos(owner.getLocation().getX(), owner.getLocation().getY(), owner.getLocation().getZ());
|
||||||
|
|
||||||
|
LivingEntity livingEntity = wolf.getBukkitLivingEntity();
|
||||||
|
double maxHealth = Math.max(1.0D, petNbt.maxHealth);
|
||||||
|
double health = Math.max(1.0D, Math.min(petNbt.health, maxHealth));
|
||||||
|
double damage = Math.max(0.0D, petNbt.damage);
|
||||||
|
|
||||||
|
setAttribute(livingEntity, Attribute.MAX_HEALTH, maxHealth);
|
||||||
|
setAttribute(livingEntity, Attribute.MOVEMENT_SPEED, DEFAULT_MOVEMENT_SPEED);
|
||||||
|
setAttribute(livingEntity, Attribute.ATTACK_DAMAGE, damage);
|
||||||
|
livingEntity.setHealth(health);
|
||||||
|
|
||||||
|
nmsWorld.addFreshEntity(wolf);
|
||||||
|
|
||||||
|
return wolf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setAttribute(LivingEntity entity, Attribute attribute, double value) {
|
||||||
|
AttributeInstance instance = entity.getAttribute(attribute);
|
||||||
|
if (instance != null) {
|
||||||
|
instance.setBaseValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/src/main/resources/config.yml
Normal file
31
src/src/main/resources/config.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
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
|
||||||
0
src/src/main/resources/lang.yml
Normal file
0
src/src/main/resources/lang.yml
Normal file
6
src/src/main/resources/plugin.yml
Normal file
6
src/src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
name: AuPet
|
||||||
|
main: com.yaohun.petsystem.PetMain
|
||||||
|
version: 1.0.1
|
||||||
|
api-version: 1.21
|
||||||
|
commands:
|
||||||
|
apet:
|
||||||
Reference in New Issue
Block a user