1
mirror of https://github.com/CarmJos/MoeTeleport.git synced 2026-06-05 00:28:16 +08:00

116 Commits

Author SHA1 Message Date
renovate[bot] 6019410f0c chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.5 2026-03-10 08:06:00 +08:00
renovate[bot] 03346ecfcd chore(deps): update dependency org.bstats:bstats-bukkit to v3.2.1 2026-03-10 08:05:53 +08:00
renovate[bot] 1720572f4d chore(deps): update actions/upload-artifact action to v7 2026-03-10 08:05:44 +08:00
renovate[bot] 81d0b8869d chore(deps): update dependency org.apache.maven.plugins:maven-shade-plugin to v3.6.2 2026-03-10 08:05:35 +08:00
renovate[bot] d620109904 chore(deps): update actions/upload-artifact action to v6 2026-02-21 00:57:39 +08:00
renovate[bot] d11e5a44b8 chore(deps): update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.15.0 2026-02-21 00:57:33 +08:00
renovate[bot] d404e36805 fix(deps): update dependency me.clip:placeholderapi to v2.12.2 2026-02-21 00:57:27 +08:00
renovate[bot] 0d9f34c135 fix(deps): update dependency org.jetbrains:annotations to v26.1.0 2026-02-21 00:57:21 +08:00
renovate[bot] 1b6bd72570 chore(deps): update actions/upload-artifact action to v5 2025-12-01 09:32:26 +08:00
renovate[bot] e148747a0b fix(deps): update dependency me.clip:placeholderapi to v2.11.7 2025-12-01 09:32:20 +08:00
renovate[bot] 2d55ac35f8 fix(deps): update dependency org.spigotmc:spigot-api to v1.19-r0.1-20220725.090125-47 2025-12-01 09:32:14 +08:00
renovate[bot] d826abdecc chore(deps): update dependency org.apache.maven.plugins:maven-jar-plugin to v3.5.0 2025-12-01 09:32:07 +08:00
renovate[bot] b63e130b15 chore(deps): update actions/checkout action to v6 2025-12-01 09:32:00 +08:00
renovate[bot] 8f8d5c7016 chore(deps): update dependency org.apache.maven.plugins:maven-source-plugin to v3.4.0 2025-12-01 09:31:53 +08:00
renovate[bot] 813dbd8b83 chore(deps): update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.14.1 2025-09-24 09:19:31 +08:00
renovate[bot] 0db564c027 chore(deps): update dependency org.apache.maven.plugins:maven-shade-plugin to v3.6.1 2025-09-14 16:56:47 +08:00
renovate[bot] b50d2f216d chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.4 2025-09-14 16:56:41 +08:00
renovate[bot] 8d0cb0365a fix(deps): update dependency org.jetbrains:annotations to v26.0.2-1 2025-09-12 08:52:20 +08:00
renovate[bot] 0a3b1c0017 chore(deps): update dependency cc.carm.lib:mineconfiguration-bukkit to v3.1.3 2025-08-21 23:44:22 +08:00
renovate[bot] c8b2e03efe chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.3 2025-08-21 23:44:13 +08:00
renovate[bot] e917d2a5b3 chore(deps): update deps.easyplugin.version to v1.5.14 2025-08-21 23:44:06 +08:00
renovate[bot] c6fec42aa4 fix(deps): update dependency net.essentialsx:essentialsx to v2.21.2 2025-08-21 23:44:00 +08:00
renovate[bot] 73489054a1 chore(deps): update dependency org.apache.maven.plugins:maven-clean-plugin to v3.5.0 2025-08-21 23:43:52 +08:00
renovate[bot] 6344dfe2d9 fix(deps): update dependency com.comphenix.protocol:protocollib to v5 2025-08-21 23:43:45 +08:00
renovate[bot] 3d7bb0292a chore(deps): update actions/checkout action to v5 2025-08-21 23:43:40 +08:00
renovate[bot] 52d806f5d4 chore(deps): update actions/setup-java action to v5 2025-08-21 23:43:33 +08:00
renovate[bot] 3f2713389b chore(deps): update dependency cc.carm.lib:mineconfiguration-bukkit to v3.1.1 2025-04-18 10:56:06 +08:00
renovate[bot] 97781fc1aa fix(deps): update dependency net.essentialsx:essentialsx to v2.21.0 2025-04-18 10:56:01 +08:00
renovate[bot] 74d083f51f chore(deps): update dependency org.apache.maven.plugins:maven-clean-plugin to v3.4.1 2025-03-12 04:38:20 +08:00
renovate[bot] a073ebf34c chore(deps): update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.14.0 2025-03-12 04:38:17 +08:00
renovate[bot] 1a8fb8459e chore(deps): update dependency cc.carm.lib:mineconfiguration-bukkit to v3 2025-03-12 04:38:13 +08:00
renovate[bot] db53b416c7 fix(deps): update dependency org.jetbrains:annotations to v26.0.2 2025-02-06 16:37:03 +08:00
renovate[bot] ef56193d7f fix(deps): update dependency org.jetbrains:annotations to v26 2025-01-18 02:24:27 +08:00
renovate[bot] 103b4bb734 chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3 2025-01-18 02:22:50 +08:00
renovate[bot] c4adadf24f chore(deps): update dependency org.apache.maven.plugins:maven-clean-plugin to v3 2025-01-18 02:22:47 +08:00
renovate[bot] 61c7e4e7da chore(deps): update actions/upload-artifact action to v4 2025-01-18 02:22:44 +08:00
renovate[bot] 17d8e6847b chore(deps): update actions/setup-java action to v4 2025-01-18 02:22:41 +08:00
renovate[bot] eaff4d066c chore(deps): update actions/checkout action to v4 2025-01-18 02:22:38 +08:00
renovate[bot] 3cc6485d3d fix(deps): update dependency org.jetbrains:annotations to v23.1.0 2025-01-18 02:22:35 +08:00
renovate[bot] 665fa3f53d fix(deps): update dependency net.essentialsx:essentialsx to v2.20.1 2025-01-18 02:22:31 +08:00
renovate[bot] c481db7827 chore(deps): update dependency org.bstats:bstats-bukkit to v3.1.0 2025-01-18 02:21:54 +08:00
renovate[bot] 08a308c88d chore(deps): update dependency org.apache.maven.plugins:maven-source-plugin to v3.3.1 2025-01-18 02:21:51 +08:00
renovate[bot] 6b0c9e2a2c chore(deps): update dependency org.apache.maven.plugins:maven-jar-plugin to v3.4.2 2025-01-18 02:21:36 +08:00
renovate[bot] a01746348e chore(deps): update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.13.0 2025-01-18 02:21:33 +08:00
renovate[bot] 104e9ae4ce chore(deps): update dependency org.apache.maven.plugins:maven-clean-plugin to v2.6.1 2025-01-18 02:21:30 +08:00
renovate[bot] 979417cc2a chore(deps): update dependency cc.carm.lib:mineconfiguration-bukkit to v2.9.3 2025-01-18 02:21:27 +08:00
renovate[bot] dba6eb9af5 chore(deps): update deps.easyplugin.version to v1.5.12 2025-01-18 02:21:23 +08:00
renovate[bot] 743cca2238 chore(deps): update dependency xyz.xenondevs:particle to v1.8.4 2025-01-18 02:21:20 +08:00
renovate[bot] eb9f5bd4ad chore(deps): update dependency org.apache.maven.plugins:maven-shade-plugin to v3.6.0 2025-01-18 02:10:09 +08:00
renovate[bot] 7515e7e271 fix(deps): update dependency me.clip:placeholderapi to v2.11.6 2025-01-18 01:06:59 +08:00
renovate[bot] 3f0a47d5cd chore(deps): update dependency cc.carm.lib:easysql-beecp to v0.4.7 2025-01-18 00:10:22 +08:00
renovate[bot] d896be6f98 chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v2.22.2 2025-01-18 00:10:10 +08:00
renovate[bot] 392e16c165 Add renovate.json 2025-01-18 00:01:06 +08:00
carm f4e3dabb29 fix(cancel): 修复取消传送功能异常的问题 (#13) 2023-04-03 17:10:07 +08:00
carm 4393cc9ce2 feat(command): 为各个指令的功能添加单独权限,修复接受指令错误的问题 2023-03-17 22:36:14 +08:00
carm 8c1a4530c0 feat(deps): 适配上游依赖库更新。 2023-03-17 18:05:23 +08:00
carm 21e3fc1674 fix(papi): 消息文件不在强制要求依赖PlaceholderAPI 2023-03-17 18:02:20 +08:00
carm b35ac8e4c4 feat(rename): 支持地标点与家传送点的重命名功能 2023-02-19 04:56:28 +08:00
carm 0d1fdccb79 feat(rename): 支持地标点与家传送点的重命名功能 2023-02-19 04:52:24 +08:00
carm f728d1f7e6 docs(en): 提供英文版本的介绍,并发布于SpigotMC 2023-02-16 21:05:21 +08:00
Maverical cb76e86b80 docs(en): Supply the English version of README documentation (#12) 2023-02-16 00:08:25 +08:00
carm b23997f7a7 feat(effect): 支持简单的传送粒子效果 2023-02-14 23:15:12 +08:00
carm bc14c39d68 feat(effect): 支持简单的传送粒子效果 2023-02-14 23:06:02 +08:00
carm eaa83a89d1 feat(delay): 支持延迟进行玩家传送。#8 2023-02-14 01:34:35 +08:00
carm 9008ebbdfe docs(badge): 添加标签 2023-02-12 04:41:18 +08:00
carm 54a9f8688c docs(badge): 添加标签 2023-02-12 04:39:31 +08:00
carm 5abf09cf22 docs(badge): 添加标签 2023-02-12 04:38:59 +08:00
carm d391364b96 docs(donate): 移除支付二维码 2023-02-12 04:32:30 +08:00
carm c8901ac457 docs(cmd): 添加新指令介绍 2023-02-12 04:31:09 +08:00
carm 5659d6d9d5 docs(cmd): 添加新指令介绍 2023-02-12 04:30:56 +08:00
carm df0541d4dd feat(cmd): 优化指令实现方式,补全指令相关介绍。 2023-02-12 04:20:15 +08:00
carm 7d59c921f0 feat(update): 更新插件依赖版本,适配新功能 2023-02-10 20:15:03 +08:00
carm 8eb0021196 feat(update): 更新插件依赖版本,适配新功能 2023-02-07 23:16:50 +08:00
carm 4f232d35c4 fix(click): 修复消息文件中点击指令异常的问题 2023-01-31 19:59:45 +08:00
carm f2bfdf4635 fix(cmd): 修复点击指令异常的问题。 2023-01-31 19:59:11 +08:00
carm 3a016fb560 Merge remote-tracking branch 'origin/master' 2022-04-03 20:54:52 +08:00
carm 7cf0b9ed01 [3.1.1] 版本修复
- `[R]` 重写存储源初始化方法。
- `[F]` 修复服务器在未安装 Essentials 时出现无法加载插件的问题。
2022-04-03 20:54:38 +08:00
carm 5f6a44d96f Update README.md 2022-03-08 22:54:38 +08:00
carm d24278b81c Update README.md 2022-03-08 22:54:15 +08:00
carm d1ff8a12d4 添加使用统计图 2022-03-08 06:22:45 +08:00
carm 3c07da0e3f 修改措辞 2022-03-05 10:25:28 +08:00
carm 61d97c2df4 修正打包位置错误 2022-03-02 20:34:57 +08:00
carm 514f757fe8 修正打包位置错误 2022-03-02 20:34:49 +08:00
carm 33c2f9de78 修正一个命名错误 2022-02-27 23:16:19 +08:00
carm e9d4e3f9bc Merge remote-tracking branch 'origin/master' 2022-02-26 00:56:07 +08:00
carm 4c5e9a09be [3.1.0] 版本更新
- [A] 添加 #7 所提到的地标点相关功能,支持玩家自设地标点并作出限制。
- [U] 修改项目结构,开始采用EasyPlugin结构。
- [U] 更换消息配置文件读取格式与读取方式。
- [A] 为 setHome 覆盖旧位置添加一条独立的消息,避免手误使旧地址丢失。
- [A] 离线也将会保存玩家最后地址,避免出现死亡后掉线失去最后地址的问题。
2022-02-26 00:54:15 +08:00
carm e1c913dc00 Create FUNDING.yml 2022-02-25 06:45:18 +08:00
carm 4afcf85d65 Update README.md 2022-02-25 06:09:50 +08:00
carm c31bf8df65 Update README.md 2022-02-25 06:09:06 +08:00
carm fa958f8507 [no ci] 移除对于“mysql”存储方式的推荐标签 2022-02-25 06:05:27 +08:00
carm df7acc369f 修改空格行数 2022-02-25 05:57:43 +08:00
carm 120e8491d2 修改jdbc的URL 2022-02-25 05:49:56 +08:00
carm 90a1da8629 delHome添加limit限定 2022-02-25 05:46:56 +08:00
carm e81055e3f2 修复数据库保存传参错误的问题 2022-02-25 05:46:25 +08:00
carm f3c5ff6eb6 修改数据库配置读取方式,使其更简单明了 2022-02-25 05:43:47 +08:00
carm e186e5ea0a 修复报错空lastLocation的问题 2022-02-25 05:37:41 +08:00
carm 623fc36c20 修复报错空lastLocation的问题 2022-02-25 05:33:53 +08:00
carm 0f112280be 启动与卸载时输出插件信息 2022-02-25 05:25:09 +08:00
carm a2ae3f83f4 启动与卸载时输出插件信息 2022-02-25 05:22:28 +08:00
carm c350bb2037 启动与卸载时输出插件信息 2022-02-25 05:22:20 +08:00
carm 67a8b60670 指定API-VERSION 2022-02-25 05:17:16 +08:00
carm 848d3aaa33 支持 #6 中提到的 Essential 存储 2022-02-25 05:10:16 +08:00
carm 061b41b1a3 Merge remote-tracking branch 'origin/master' 2022-02-25 04:40:55 +08:00
carm 7bfef559d4 [3.0.0] 版本更新
- [F] 修复玩家给自己发送传送请求的问题。
- [A] 添加 插件更新 提示,允许自定义开关。
- [A] 添加 插件统计,允许自定义开关。
- [A] 实现 #6 提到的多数据源支持,目前支持 YAML、JSON与MySQL,并提供CUSTOM数据源允许开发者重写。
- [A] 对于家的名字长度做出限制,为 30 个字符。
- [U] 对于判断用户最多设置家数量的权限,不再添加“MoeTeleport”开头。
2022-02-25 04:40:45 +08:00
carm 947799e8b2 [2.1.0] 版本更新
- [F] 修复玩家给自己发送传送请求的问题。
- [A] 添加 插件更新 提示,允许自定义开关。
- [A] 添加 插件统计,允许自定义开关。
- [A] 实现 #6 提到的多数据源支持,目前支持 YAML、JSON与MySQL,并提供CUSTOM数据源允许开发者重写。
- [A] 对于家的名字长度做出限制,为 30 个字符。
- [U] 对于判断用户最多设置家数量的权限,不再添加“MoeTeleport”开头。
2022-02-25 04:38:58 +08:00
carm 5424c389ce [2.1.0] 版本更新
- [F] 修复玩家给自己发送传送请求的问题。
- [A] 添加 插件更新 提示,允许自定义开关。
- [A] 添加 插件统计,允许自定义开关。
- [A] 实现 #6 提到的多数据源支持,目前支持 YAML、JSON与MySQL,并提供CUSTOM数据源允许开发者重写。
- [A] 对于家的名字长度做出限制,为 30 个字符。
- [U] 对于判断用户最多设置家数量的权限,不再添加“MoeTeleport”开头。
2022-02-25 04:38:46 +08:00
carm 740670e19a 添加clean配置 2022-02-24 16:07:47 +08:00
carm a66a30abc4 [2.0.2] 版本修复
- [F] 修复玩家可以给自己发送传送请求的问题
2022-02-24 16:00:42 +08:00
carm 948b4f1915 [F] 修复玩家可以给自己发送传送请求的问题 2022-02-24 16:00:24 +08:00
carm b5f6794a85 Update feature_issues.md 2022-02-24 15:54:35 +08:00
carm ee31e501c8 Update bugs_report.md 2022-02-24 15:54:04 +08:00
carm e6ada9ed47 Update README.md 2022-02-24 06:36:36 +08:00
carm 9dea97bc79 Merge pull request #4 from Msyial/master
Add a clickable text for back command
2022-02-20 07:37:09 +08:00
Z1SHU 7ac6f4ebb7 Update messages.yml 2022-02-20 07:35:38 +08:00
carm 0bd002d606 移除 asset 的上传 2022-02-19 16:06:41 +08:00
carm 8bc2f0dba5 [2.0.1] 版本更新
- [F] 修复MoeTeleport指令错误的问题。
2022-02-18 20:59:02 +08:00
96 changed files with 4736 additions and 1721 deletions
+2
View File
@@ -0,0 +1,2 @@
custom: ['https://donate.carm.cc']
+7 -5
View File
@@ -8,23 +8,25 @@ assignees: ''
--- ---
**问题简述** **问题简述**
用简短的话语描述一下大概问题。 <!--用简短的话语描述一下大概问题。-->
**问题来源** **问题来源**
<!--
描述一下通过哪些操作才发现的问题,如: 描述一下通过哪些操作才发现的问题,如:
1. 打开 '...' 1. 打开 '...'
2. 点击了 '....' 2. 点击了 '....'
3. 出现了报错 '....' 3. 出现了报错 '....'
-->
**预期结果**(可选) **预期结果**(可选)
如果问题不发生,应该是什么情况 <!--如果问题不发生,应该是什么情况-->
**问题截图/问题报错** **问题截图/问题报错**
如果有报错或输出,请提供截图。 <!--如果有报错或输出,请提供截图。-->
**操作环境** **操作环境**
请在后台输入 `version` 并复制相关输出。 <!--请在后台输入 `version` 并复制相关输出。-->
**其他补充** **其他补充**
如有其他补充,可以在这里描述。 <!--如有其他补充,可以在这里描述。-->
+4 -4
View File
@@ -8,13 +8,13 @@ assignees: ''
--- ---
**功能简述** **功能简述**
简单的描述一下你想要的功能 <!--简单的描述一下你想要的功能-->
**需求来源** **需求来源**
简单的描述一下为什么需要这个功能。 <!--简单的描述一下为什么需要这个功能。-->
**功能参考**(可选) **功能参考**(可选)
如果有相关功能的参考,如文本、截图,请提供给我们。 <!--如果有相关功能的参考,如文本、截图,请提供给我们。-->
**附加内容** **附加内容**
如果有什么小细节需要重点注意,请在这里告诉我们。 <!--如果有什么小细节需要重点注意,请在这里告诉我们。-->
+3 -3
View File
@@ -14,9 +14,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v6
- name: "Set up JDK" - name: "Set up JDK"
uses: actions/setup-java@v2 uses: actions/setup-java@v5
with: with:
java-version: '11' java-version: '11'
distribution: 'adopt' distribution: 'adopt'
@@ -37,7 +37,7 @@ jobs:
cp -vrf asset/*.jar artifacts cp -vrf asset/*.jar artifacts
- name: "Upload artifact" - name: "Upload artifact"
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v7
with: with:
name: Artifact name: Artifact
path: artifacts path: artifacts
+2 -2
View File
@@ -11,9 +11,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v6
- name: "Set up JDK" - name: "Set up JDK"
uses: actions/setup-java@v2 uses: actions/setup-java@v5
with: with:
java-version: '11' java-version: '11'
distribution: 'adopt' distribution: 'adopt'
+1
View File
@@ -2,3 +2,4 @@
/target/ /target/
./*.iml ./*.iml
*.iml *.iml
asset/
+155
View File
@@ -0,0 +1,155 @@
```text
__ ___ ______ __ __
/ |/ /__ __/_ __/__ / /__ ___ ___ ____/ /_
/ /|_/ / _ \/ -_) / / -_) / -_) _ \/ _ \/ __/ __/
/_/ /_/\___/\__/_/ \__/_/\__/ .__/\___/_/ \__/
/_/
```
README LANGUAGES [ [中文](README.md) | [**English**](README-EN.md) ]
# MoeTeleport
[![CodeFactor](https://www.codefactor.io/repository/github/CarmJos/MoeTeleport/badge?s=b76fec1f64726b5f19989aace6adb5f85fdab840)](https://www.codefactor.io/repository/github/CarmJos/MoeTeleport)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/MoeTeleport)
[![Download](https://img.shields.io/github/downloads/CarmJos/MoeTeleport/total)](https://github.com/CarmJos/MoeTeleport/releases)
[![Java CI with Maven](https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml)
![Support](https://img.shields.io/badge/Minecraft-Java%201.13--Latest-blue)
![](https://visitor-badge.glitch.me/badge?page_id=moeteleport.readme)
MoeTeleport is an open source delivery plugin that contains several features and will be always updated to add new features based on users' requirements.
The project code conforms to the development specifications and is suitable for new developers to learn Bukkit and make their own plugins.
## Functions and advantages
### Current functions
- Multiple storage formats, select on demand.
- Support YAML, JSON and MySQL/MariaDB storage
- Support direct call [EssentialsX] (https://github.com/EssentialsX/Essentials)/CMI data, Seamless switching
- Clickable messages (such as "Click-Agree")
- Based on the MineDown syntax, Customizable configuration
- Teleport requests between players
- Support to specify handling a player's request
- Set warp locations
- Support to set a different number of warp locations as VIP add-on content based on permissions
- Set home locations (understood as private warps)
- Support setting different number of homes according to permissions as VIP add-on content
- Return to the place of death and the last location
### Advantages
- ** Lightweight plugin. ** Suitable for small servers, simple and convenient configuration.
- ** Specification development. ** Plugin architecture conforms to development specifications, suitable for new developers to learn.
- EasyPlugin has been used since [3.0.0]() and may be somewhat different from other mainstream plugin structures.
- ** Continuous maintenance. ** All new functional requirements can be submitted, which is likely to be supported in the subsequent development.
- Functional requirements please [submit Issues] (HTTP: / / https://github.com/CarmJos/MoeTeleport/issues/new?assignees=&labels=enhancement&template=feature issues.md&title=), do not submit in the post!
- Submitting requests associated with "teleport" will most likely be updated and supported.
## [Dependencies](https://github.com/CarmJos/MoeTeleport/network/dependencies)
- **[Necessary]** The plugin is based on [Spigot-API](https://hub.spigotmc.org/stash/projects/SPIGOT) 、[BukkitAPI](http://bukkit.org/).
- **[Included]** Message format is based on [MineDown](https://github.com/Phoenix616/MineDown).
- All messages.yml support MineDown syntax。
- **[Recommended]** The variable part is based on [PlaceholderAPI](https://www.spigotmc.org/resources/6245/).
Read this if you need more details. [Dependencies](https://github.com/CarmJos/MoeTeleport/network/dependencies).
## [Commands](src/main/resources/plugin.yml)
The main command is `/MoeTeleport` or `/mt`.
All commands in this plugin support configuration of "simplified commands",
such as allowing the player to directly input '/back' and execute '/MoeTeleport back', see [configuration](#Config) related content.
- Required parameter '< Parameter >'
- Optional parameter '[parameter]'
```text
# reload
@ Admin command (MoeTeleport.admin)
- Reload the plugin configuration file.
# back
- Return to the last location.
----- [Teleport commands] -----
# teleport to <target player>
- Request to teleport to target player's location.
# teleport here <target player>
- Request the target player to teleport to their location.
# teleport accept [target player]
- Grant a teleport request (player requests can be specified).
# teleport deny [target player].
- Reject a teleport request (player requests can be specified).
----- [Home commands] -----
# home to [home name]
- Send to the specified home.
- If you do not fill in the specific home, return to the first set of home.
- If there is a home named "home", return to "home" preferentially.
# home list
- List all the home names.
# home set [home name]
- Set a home location.
- If you do not specify the name of home, the default value is "home".
# home delete [home name]
-Delete a home location
----- [Warp commands] -----
# warp to <warp name>
- Teleport to the specified location.
# warp list
- List all current warp locations.
# warp set <warp name>
- Set a warp location.
- If the warp already exists and you are the owner (or the server administrator) of the warp,
- the old warp point will be overwritten.
# warp delete <Warp name>
- Delete one of your own warps
```
## Config
### Plugin configuration file ([config.yml]())
Read source file for more details.
### Message configuration file ([messages.yml]())
Support [MineDown syntax](https://wiki.phoenix616.dev/library:minedown:syntax)
Read source file for more details.
## Usage statistics
[![bStats](https://bstats.org/signatures/bukkit/MoeTeleport.svg)](https://bstats.org/plugin/bukkit/MoeTeleport/14459)
## Support and donate
If you find this plugin helps, you can donate to support me. Thank you for being a supporter of this open source project!
Sincere thanks to the following friends who support the development of this project:
- This plugin is entrusted by [**璎珞 **](https://www.yingluo.world/) server , authorized already.
- Thank you to [**XingMC**(MagicMC server developer)](https://www.mcbbs.net/?4816320) for funding the subsequent development of this plugin.
Many thanks to Jetbrains for kindly providing a license for me to work on this and other open-source projects.
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/UserPrefix)
## Open source agreement
The source code of this project uses [GNU General Public License v3.0](https://opensource.org/licenses/GPL-3.0) License.
+114 -51
View File
@@ -1,23 +1,56 @@
```text ```text
__ __ _______ _ _ __ ___ ______ __ __
| \/ | |__ __| | | | | / |/ /__ __/_ __/__ / /__ ___ ___ ____/ /_
| \ / | ___ ___| | ___| | ___ _ __ ___ _ __| |_ / /|_/ / _ \/ -_) / / -_) / -_) _ \/ _ \/ __/ __/
| |\/| |/ _ \ / _ \ |/ _ \ |/ _ \ '_ \ / _ \| '__| __| /_/ /_/\___/\__/_/ \__/_/\__/ .__/\___/_/ \__/
| | | | (_) | __/ | __/ | __/ |_) | (_) | | | |_ /_/
|_| |_|\___/ \___|_|\___|_|\___| .__/ \___/|_| \__|
| |
|_|
``` ```
README LANGUAGES [ [**中文**](README.md) | [English](README-EN.md) ]
# MoeTeleport 喵喵传送 # MoeTeleport 喵喵传送
简单的传送请求插件,支持设置家与返回上一个地点。 [![CodeFactor](https://www.codefactor.io/repository/github/CarmJos/MoeTeleport/badge?s=b76fec1f64726b5f19989aace6adb5f85fdab840)](https://www.codefactor.io/repository/github/CarmJos/MoeTeleport)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/MoeTeleport)
[![Download](https://img.shields.io/github/downloads/CarmJos/MoeTeleport/total)](https://github.com/CarmJos/MoeTeleport/releases)
[![Java CI with Maven](https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml)
![Support](https://img.shields.io/badge/Minecraft-Java%201.13--Latest-blue)
![](https://visitor-badge.glitch.me/badge?page_id=moeteleport.readme)
本插件由 [璎珞服务器](https://www.yingluo.world/) 请求本人开发,经过授权后开源 开源的传送插件,包含数个功能,并根据用户需求持续更新添加新功能
项目代码符合开发规范,适合新手开发者学习Bukkit,制作属于自己的插件。
## 功能与优势
### 当前功能
- 多种存储格式,按需选择。
- 支持 YAML、JSON 与 MySQL/MariaDB 存储方式
- 支持直接调用 [EssentialsX](https://github.com/EssentialsX/Essentials) / CMI 数据,无缝切换
- 可点击的消息(如“点击同意”)
- 基于MineDown语法,可自定义配置
- 玩家间的传送请求
- 支持指定处理某位玩家的请求
- 设置地标点
- 支持依照权限设定不同数量的地标点作为VIP附加内容
- 设置家位置 (可以理解为私人地标)
- 支持依照权限设定不同数量的家作为VIP附加内容
- 回到死亡地点、上一传送地点
### 优势
- **轻量插件。** 适合小型服务器使用,配置简单方便。
- **规范开发。** 插件架构符合开发规范,适合新手开发者学习。
- 自 [3.0.0]() 版本开始采用了 EasyPlugin 开发,可能与其他主流插件结构有些不同。
- **持续维护。** 新功能需求均可提交,大概率在后续开发中支持。
- 功能需求请 [提交Issues](https://github.com/CarmJos/MoeTeleport/issues/new?assignees=&labels=enhancement&template=feature_issues.md&title=)
,不要在帖子中提交!
- 提交与 “传送” 相关联的请求才大概率会被更新支持。
## [依赖](https://github.com/CarmJos/MoeTeleport/network/dependencies) ## [依赖](https://github.com/CarmJos/MoeTeleport/network/dependencies)
- **[必须]** 插件本体基于 [Spigot-API](https://hub.spigotmc.org/stash/projects/SPIGOT) 、[BukkitAPI](http://bukkit.org/) 实现。 - **[必须]** 插件本体基于 [Spigot-API](https://hub.spigotmc.org/stash/projects/SPIGOT) 、[BukkitAPI](http://bukkit.org/)
实现。
- **[自带]** 消息格式基于 [MineDown](https://github.com/Phoenix616/MineDown) 实现。 - **[自带]** 消息格式基于 [MineDown](https://github.com/Phoenix616/MineDown) 实现。
- 所有 messages.yml 均支持 MineDown 语法。 - 所有 messages.yml 均支持 MineDown 语法。
- **[推荐]** 变量部分基于 [PlaceholderAPI](https://www.spigotmc.org/resources/6245/) 实现。 - **[推荐]** 变量部分基于 [PlaceholderAPI](https://www.spigotmc.org/resources/6245/) 实现。
@@ -26,74 +59,101 @@
## [指令](src/main/resources/plugin.yml) ## [指令](src/main/resources/plugin.yml)
以下指令的主指令为 `/MoeTeleport``/mt`
本插件所有指令支持配置“简化指令”,如允许玩家直接输入 `/back` 执行 `/MoeTeleport back`,详见 [配置文件](#配置) 相关内容。
- 必须参数 `<参数>` - 必须参数 `<参数>`
- 可选参数 `[参数]` - 可选参数 `[参数]`
```text ```text
# /MoeTeleport reload # reload
@ 管理指令 (MoeTeleport.admin) @ 管理指令 (MoeTeleport.admin)
- 重载插件配置文件。 - 重载插件配置文件。
# /back # back
- 返回上一个传送地点 - 回到之前的传送位置。
# /tpa <玩家> ----- [ 传送相关指令 ] -----
- 请求传送到一个玩家身边。
# /tpaHere <玩家>
- 请求一个玩家传送到自己身边。
# /tpAccept [玩家]
- 同意一个请求,可以限定某个玩家。
# /tpDeny [玩家]
- 拒绝一个请求,可以限定某个玩家。
# /home [name] # teleport to <目标玩家>
- 返回设定的家 - 请求传送到目标玩家的位置。
- 不填name会返回第一个设置的家
# teleport here <玩家>
- 请求目标玩家传送到自己的位置。
# teleport accept [玩家]
- 同意一个传送请求(可具体指定玩家的请求)。
# teleport deny [玩家]
- 拒绝一个传送请求(可具体指定玩家的请求)。
----- [ 家相关指令 ] -----
# home to [家名]
- 传送到指定的家。
- 若不填写具体的家明则返回首个设置的家,
- 若存在名为“home”的家则优先返回“home”。 - 若存在名为“home”的家则优先返回“home”。
# /listHome
- 列出所有家的位置 # home list
# /setHome [name] - 列出所有的家位置。
- 设置家 (不填name默认为home)
# /delHome <name> # home set [家名]
- 删除家 - 设定一个家的位置。
- 若不填写家的名称则默认为“home”。
# home delete [家名]
- 删除一个家的位置。
----- [ 地标相关指令 ] -----
# warp to <地标名>
- 传送到指定的地标点。
# warp list
- 列出当前所有的地标点。
# warp set <地标名>
- 设定一个地标点。
- 若地标点已存在,且您是地标点的设立者(或是服务器管理员),
- 则会覆盖原有的地标点位置。
# warp delete <地标名>
- 删除一个自己设立的地标点。
``` ```
## 配置 ## 配置
### 插件配置文件 ([config.yml](src/main/resources/config.yml)) ### 插件配置文件 ([config.yml]())
详见源文件。 详见源文件。
### 消息配置文件 ([messages.yml](src/main/resources/messages.yml)) ### 消息配置文件 ([messages.yml]())
支持 [MineDown 语法](https://wiki.phoenix616.dev/library:minedown:syntax),详见源文件。 支持 [MineDown 语法](https://wiki.phoenix616.dev/library:minedown:syntax),详见源文件。
## 使用统计
[![bStats](https://bstats.org/signatures/bukkit/MoeTeleport.svg)](https://bstats.org/plugin/bukkit/MoeTeleport/14459)
### 玩家数据配置文件 (data/\<UUID\>.yml)
本插件采用 `YAML格式` 存储玩家数据。
```yaml
# 玩家的家位置记录
# 格式为 world;x;y;z;yaw;pitch
homes:
"name": "world;112.21;45;21.241245552;92.5512;-11"
```
## 支持与捐赠 ## 支持与捐赠
若您觉得本插件做的不错,您可以捐赠支持我! 若您觉得本插件做的不错,您可以捐赠支持我,感谢您成为开源项目的支持者
感谢您成为开源项目的支持者! 由衷感谢以下支持本项目开发的朋友们:
- 本插件由 [**璎珞**服务器](https://www.yingluo.world/) 委托本人开发,经过授权后开源。
- 感谢 [**XingMC**(MagicMC服务器开发者)](https://www.mcbbs.net/?4816320) 为本插件提供后续开发的资金赞助。
<img height=25% width=25% src="https://raw.githubusercontent.com/CarmJos/CarmJos/main/img/donate-code.jpg" alt=""/> Many thanks to Jetbrains for kindly providing a license for me to work on this and other open-source projects.
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/UserPrefix)
## 开源协议 ## 开源协议
本项目源码采用 [GNU General Public License v3.0](https://opensource.org/licenses/GPL-3.0) 开源协议。 本项目源码采用 [GNU General Public License v3.0](https://opensource.org/licenses/GPL-3.0) 开源协议。
> ### 关于 GPL 协议 <details>
<summary>关于 GPL 协议</summary>
> GNU General Public Licence (GPL) 有可能是开源界最常用的许可模式。GPL 保证了所有开发者的权利,同时为使用者提供了足够的复制,分发,修改的权利: > GNU General Public Licence (GPL) 有可能是开源界最常用的许可模式。GPL 保证了所有开发者的权利,同时为使用者提供了足够的复制,分发,修改的权利:
> >
> #### 可自由复制 > #### 可自由复制
@@ -103,8 +163,11 @@ homes:
> #### 可以用来盈利 > #### 可以用来盈利
> 你可以在分发软件的时候收费,但你必须在收费前向你的客户提供该软件的 GNU GPL 许可协议,以便让他们知道,他们可以从别的渠道免费得到这份软件,以及你收费的理由。 > 你可以在分发软件的时候收费,但你必须在收费前向你的客户提供该软件的 GNU GPL 许可协议,以便让他们知道,他们可以从别的渠道免费得到这份软件,以及你收费的理由。
> #### 可自由修改 > #### 可自由修改
> 如果你想添加或删除某个功能,没问题,如果你想在别的项目中使用部分代码,也没问题,唯一的要求是,使用了这段代码的项目也必须使用 GPL 协议。 > 如果你想添加或删除某个功能,没问题,如果你想在别的项目中使用部分代码,也没问题,唯一的要求是,使用了这段代码的项目也必须使用
> GPL 协议。
> >
> 需要注意的是,分发的时候,需要明确提供源代码和二进制文件,另外,用于某些程序的某些协议有一些问题和限制,你可以看一下 @PierreJoye 写的 Practical Guide to GPL Compliance 一文。使用 GPL 协议,你必须在源代码代码中包含相应信息,以及协议本身。 > 需要注意的是,分发的时候,需要明确提供源代码和二进制文件,另外,用于某些程序的某些协议有一些问题和限制,你可以看一下
> @PierreJoye 写的 Practical Guide to GPL Compliance 一文。使用 GPL 协议,你必须在源代码代码中包含相应信息,以及协议本身。
> >
> *以上文字来自 [五种开源协议GPL,LGPL,BSD,MIT,Apache](https://www.oschina.net/question/54100_9455) 。* > *以上文字来自 [五种开源协议GPL,LGPL,BSD,MIT,Apache](https://www.oschina.net/question/54100_9455) 。*
</details>
Binary file not shown.
Binary file not shown.
+172 -35
View File
@@ -5,15 +5,20 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
<maven.compiler.source>8</maven.compiler.source> <project.jdk.version>8</project.jdk.version>
<maven.compiler.target>8</maven.compiler.target> <maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<deps.easyplugin.version>1.5.14</deps.easyplugin.version>
<deps.easysql.version>0.4.7</deps.easysql.version>
<deps.mineconfig.version>3.1.3</deps.mineconfig.version>
</properties> </properties>
<groupId>cc.carm.plugin</groupId> <groupId>cc.carm.plugin</groupId>
<artifactId>moeteleport</artifactId> <artifactId>moeteleport</artifactId>
<version>2.0.0</version> <version>4.0.3</version>
<name>MoeTeleport</name> <name>MoeTeleport</name>
<description>喵喵传送,简单的传送、设置家的插件。</description> <description>喵喵传送,简单的传送、设置家的插件。</description>
@@ -21,12 +26,12 @@
<issueManagement> <issueManagement>
<system>GitHub Issues</system> <system>GitHub Issues</system>
<url>${project.url}/issues</url> <url>https://github.com/CarmJos/MoeTeleport/issues</url>
</issueManagement> </issueManagement>
<ciManagement> <ciManagement>
<system>GitHub Actions</system> <system>GitHub Actions</system>
<url>${project.url}/actions/workflows/maven.yml</url> <url>https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml</url>
</ciManagement> </ciManagement>
<developers> <developers>
@@ -39,13 +44,6 @@
</developers> </developers>
<repositories> <repositories>
<repository>
<id>carm-repo</id>
<name>Carm's Repo</name>
<url>https://repo.carm.cc/repository/maven-public/</url>
</repository>
<repository> <repository>
<id>spigot-repo</id> <id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
@@ -77,35 +75,98 @@
</repository> </repository>
<repository> <repository>
<id>github</id> <id>essentials-repo</id>
<name>GitHub Packages</name> <url>https://repo.essentialsx.net/releases/</url>
<url>https://maven.pkg.github.com/CarmJos/${project.name}</url>
</repository> </repository>
<repository>
<id>carm-repo</id>
<name>Carm's Repo</name>
<url>https://repo.carm.cc/repository/maven-public/</url>
</repository>
</repositories> </repositories>
<distributionManagement> <distributionManagement>
<downloadUrl>${project.url}/releases</downloadUrl> <downloadUrl>https://github.com/CarmJos/MoeTeleport/releases</downloadUrl>
<repository> <repository>
<id>github</id> <id>github</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/${project.name}</url> <url>https://maven.pkg.github.com/CarmJos/MoeTeleport</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>spigot-api</artifactId> <artifactId>mineconfiguration-bukkit</artifactId>
<version>1.17-R0.1-SNAPSHOT</version> <version>${deps.mineconfig.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyplugin-main</artifactId>
<version>${deps.easyplugin.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyplugin-command</artifactId>
<version>${deps.easyplugin.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyplugin-command-alias</artifactId>
<version>${deps.easyplugin.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyplugin-githubchecker</artifactId>
<version>${deps.easyplugin.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.essentialsx</groupId>
<artifactId>EssentialsX</artifactId>
<version>2.21.2</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.clip</groupId> <groupId>com.Zrips</groupId>
<artifactId>placeholderapi</artifactId> <artifactId>CMI-API</artifactId>
<version>2.10.9</version> <version>9.3.1.2</version>
<scope>provided</scope> <scope>system</scope>
<systemPath>${project.basedir}/lib/CMI-API9.3.1.2.jar</systemPath>
</dependency>
<dependency>
<groupId>com.Zrips</groupId>
<artifactId>CMILib</artifactId>
<version>1.2.4.5</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/CMILib1.2.4.5.jar</systemPath>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easysql-beecp</artifactId>
<version>${deps.easysql.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
@@ -113,6 +174,44 @@
<artifactId>minedown</artifactId> <artifactId>minedown</artifactId>
<version>1.7.1-SNAPSHOT</version> <version>1.7.1-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>xyz.xenondevs</groupId>
<artifactId>particle</artifactId>
<version>1.8.4</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.19-R0.1-20220725.090125-47</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>5.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.2.1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.12.2</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
@@ -125,22 +224,44 @@
<dependency> <dependency>
<groupId>org.jetbrains</groupId> <groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId> <artifactId>annotations</artifactId>
<version>22.0.0</version> <version>26.1.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-clean-plugin</artifactId>
<version>3.8.1</version> <version>3.5.0</version>
<configuration> <configuration>
<source>1.8</source> <filesets>
<target>1.8</target> <fileset>
<directory>${project.basedir}/asset/</directory>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>**/*</include>
</includes>
</fileset>
<fileset>
<directory>${project.basedir}/api-docs/</directory>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>**/*</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
<configuration>
<source>${project.jdk.version}</source>
<target>${project.jdk.version}</target>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<compilerArgument>-parameters</compilerArgument> <compilerArgument>-parameters</compilerArgument>
</configuration> </configuration>
@@ -148,12 +269,12 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version> <version>3.5.0</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version> <version>3.4.0</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@@ -166,7 +287,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version> <version>3.6.2</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@@ -176,7 +297,7 @@
</execution> </execution>
</executions> </executions>
<configuration> <configuration>
<finalName>${project.name}-${project.version}</finalName> <finalName>MoeTeleport-${project.version}</finalName>
<outputDirectory>${project.basedir}/asset/</outputDirectory> <outputDirectory>${project.basedir}/asset/</outputDirectory>
<createDependencyReducedPom>false</createDependencyReducedPom> <createDependencyReducedPom>false</createDependencyReducedPom>
<filters> <filters>
@@ -189,17 +310,33 @@
</filter> </filter>
</filters> </filters>
<relocations> <relocations>
<relocation>
<pattern>cc.carm.lib</pattern>
<shadedPattern>cc.carm.plugin.moeteleport.lib</shadedPattern>
</relocation>
<relocation> <relocation>
<pattern>de.themoep.minedown</pattern> <pattern>de.themoep.minedown</pattern>
<shadedPattern>cc.carm.plugin.moeteleport.lib.minedown</shadedPattern> <shadedPattern>cc.carm.plugin.moeteleport.lib.minedown</shadedPattern>
</relocation> </relocation>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>cc.carm.plugin.moeteleport.lib.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>xyz.xenondevs.particle</pattern>
<shadedPattern>cc.carm.plugin.moeteleport.lib.praticle</shadedPattern>
</relocation>
<relocation>
<pattern>org.json</pattern>
<shadedPattern>cc.carm.plugin.moeteleport.lib.json</shadedPattern>
</relocation>
</relocations> </relocations>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version> <version>3.5.5</version>
<configuration> <configuration>
<useSystemClassLoader>false</useSystemClassLoader> <useSystemClassLoader>false</useSystemClassLoader>
</configuration> </configuration>
+6
View File
@@ -0,0 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
}
+147 -124
View File
@@ -1,149 +1,172 @@
package cc.carm.plugin.moeteleport; package cc.carm.plugin.moeteleport;
import cc.carm.plugin.moeteleport.command.BackCommand; import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.plugin.moeteleport.command.MoeTeleportCommand; import cc.carm.lib.easyplugin.EasyPlugin;
import cc.carm.plugin.moeteleport.command.completer.HomeNameCompleter; import cc.carm.lib.easyplugin.command.alias.AliasCommandManager;
import cc.carm.plugin.moeteleport.command.completer.PlayerNameCompleter; import cc.carm.lib.easyplugin.updatechecker.GHUpdateChecker;
import cc.carm.plugin.moeteleport.command.completer.TpRequestCompleter; import cc.carm.lib.mineconfiguration.bukkit.MineConfiguration;
import cc.carm.plugin.moeteleport.command.home.DelHomeCommand; import cc.carm.plugin.moeteleport.command.MainCommands;
import cc.carm.plugin.moeteleport.command.home.GoHomeCommand; import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.command.home.ListHomeCommand; import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.command.home.SetHomeCommand; import cc.carm.plugin.moeteleport.listener.TeleportListener;
import cc.carm.plugin.moeteleport.command.tpa.TpHandleCommand;
import cc.carm.plugin.moeteleport.command.tpa.TpaCommand;
import cc.carm.plugin.moeteleport.listener.UserListener; import cc.carm.plugin.moeteleport.listener.UserListener;
import cc.carm.plugin.moeteleport.manager.ConfigManager; import cc.carm.plugin.moeteleport.manager.*;
import cc.carm.plugin.moeteleport.manager.RequestManager; import cc.carm.plugin.moeteleport.storage.DataStorage;
import cc.carm.plugin.moeteleport.manager.UserManager; import cc.carm.plugin.moeteleport.storage.StorageMethod;
import cc.carm.plugin.moeteleport.model.UserData; import org.bstats.bukkit.Metrics;
import cc.carm.plugin.moeteleport.util.ColorParser; import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import xyz.xenondevs.particle.utils.ReflectionUtils;
public class Main extends JavaPlugin { public class Main extends EasyPlugin {
public static boolean debugMode = true;
private static Main instance; private static Main instance;
private UserManager userManager;
private RequestManager requestManager;
/** protected ConfigurationProvider<?> configProvider;
* 注册监听器 protected ConfigurationProvider<?> messageProvider;
*
* @param listener 监听器 protected DataStorage storage;
*/ protected WarpManager warpManager;
public static void regListener(Listener listener) { protected UserManager userManager;
Bukkit.getPluginManager().registerEvents(listener, getInstance()); protected RequestManager requestManager;
protected TeleportManager teleportManager;
protected AliasCommandManager commandManager;
public Main() {
instance = this;
} }
public static void log(String message) { @Override
Bukkit.getConsoleSender().sendMessage(ColorParser.parse("[" + getInstance().getName() + "] " + message)); protected void load() {
log("加载插件配置文件...");
this.configProvider = MineConfiguration.from(this, "config.yml");
this.configProvider.initialize(PluginConfig.class);
this.messageProvider = MineConfiguration.from(this, "messages.yml");
this.messageProvider.initialize(PluginMessages.class);
} }
public static void error(String message) { @Override
log("&4[ERROR] &r" + message); protected boolean initialize() {
log("初始化存储方式...");
StorageMethod storageMethod = StorageMethod.read(PluginConfig.STORAGE.METHOD.get());
try {
log(" 正在使用 " + storageMethod.name() + " 进行数据存储");
storage = storageMethod.createStorage();
storage.initialize();
} catch (Exception ex) {
severe("初始化存储失败,请检查配置文件。");
setEnabled(false);
return false; // 初始化失败,不再继续加载
} }
public static void debug(String message) { log("加载地标管理器...");
if (debugMode) { warpManager = new WarpManager();
log("&b[DEBUG] &r" + message);
log("加载用户管理器...");
this.userManager = new UserManager();
if (Bukkit.getOnlinePlayers().size() > 0) {
log(" 加载现有用户数据...");
this.userManager.loadAll();
} }
log("加载请求管理器...");
this.requestManager = new RequestManager(this);
log("加载传送管理器...");
this.teleportManager = new TeleportManager(this);
log("注册监听器...");
registerListener(new UserListener());
registerListener(new TeleportListener());
log("注册指令...");
registerCommand("MoeTeleport", new MainCommands(this));
if (PluginConfig.COMMAND.ENABLE.getNotNull()) {
log("注册简化指令映射...");
try {
this.commandManager = new AliasCommandManager(this);
PluginConfig.COMMAND.ALIAS.getNotNull().forEach(commandManager::register);
} catch (Exception e) {
log("注册简化指令失败: " + e.getMessage());
e.printStackTrace();
}
}
if (PluginConfig.METRICS.getNotNull()) {
log("启用统计数据...");
Metrics metrics = new Metrics(this, 14459);
metrics.addCustomChart(new SimplePie("storage_method", storageMethod::name));
}
if (PluginConfig.CHECK_UPDATE.getNotNull()) {
log("开始检查更新...");
getScheduler().runAsync(GHUpdateChecker.runner(this));
} else {
log("已禁用检查更新,跳过。");
}
log("初始化粒子库...");
ReflectionUtils.setPlugin(this);
return true;
}
@Override
protected void shutdown() {
if (PluginConfig.COMMAND.ENABLE.getNotNull() && this.commandManager != null) {
log("清空简化指令...");
this.commandManager.unregisterAll();
}
log("关闭所有请求...");
this.requestManager.shutdown();
this.teleportManager.shutdown();
log("保存用户数据...");
this.userManager.unloadAll(true);
log("保存地标数据...");
this.warpManager.saveWarps();
log("终止存储源...");
this.storage.shutdown();
log("卸载监听器...");
Bukkit.getServicesManager().unregisterAll(this);
}
@Override
public boolean isDebugging() {
return PluginConfig.DEBUG.getNotNull();
}
public static void info(String... messages) {
getInstance().log(messages);
}
public static void severe(String... messages) {
getInstance().error(messages);
}
public static void debugging(String... messages) {
getInstance().debug(messages);
} }
public static Main getInstance() { public static Main getInstance() {
return instance; return instance;
} }
public static void registerCommand(String commandName, public ConfigurationProvider<?> getConfigProvider() {
@NotNull CommandExecutor executor) { return configProvider;
registerCommand(commandName, executor, null);
} }
public static void registerCommand(String commandName, public ConfigurationProvider<?> getMessageProvider() {
@NotNull CommandExecutor executor, return messageProvider;
@Nullable TabCompleter tabCompleter) {
PluginCommand command = Bukkit.getPluginCommand(commandName);
if (command == null) return;
command.setExecutor(executor);
if (tabCompleter != null) command.setTabCompleter(tabCompleter);
} }
public static UserManager getUserManager() {
return Main.getInstance().userManager;
}
public static RequestManager getRequestManager() {
return Main.getInstance().requestManager;
}
@Override
public void onEnable() {
instance = this;
log(getName() + " " + getDescription().getVersion() + " &7开始加载...");
long startTime = System.currentTimeMillis();
log("加载配置文件...");
ConfigManager.initConfig();
log("加载用户管理器...");
this.userManager = new UserManager(this);
if (Bukkit.getOnlinePlayers().size() > 0) {
log(" 加载现有用户数据...");
for (Player player : Bukkit.getOnlinePlayers()) {
UserData data = Main.getUserManager().loadData(player.getUniqueId());
Main.getUserManager().getUserDataMap().put(player.getUniqueId(), data);
}
}
log("加载请求管理器...");
this.requestManager = new RequestManager(this);
log("注册监听器...");
regListener(new UserListener());
log("注册指令...");
registerCommand("MoeTeleport", new MoeTeleportCommand());
registerCommand("back", new BackCommand());
registerCommand("home", new GoHomeCommand(), new HomeNameCompleter());
registerCommand("delHome", new DelHomeCommand(), new HomeNameCompleter());
registerCommand("setHome", new SetHomeCommand());
registerCommand("listHome", new ListHomeCommand());
registerCommand("tpa", new TpaCommand(), new PlayerNameCompleter());
registerCommand("tpaHere", new TpaCommand(), new PlayerNameCompleter());
registerCommand("tpAccept", new TpHandleCommand(), new TpRequestCompleter());
registerCommand("tpDeny", new TpHandleCommand(), new TpRequestCompleter());
log("加载完成 ,共耗时 " + (System.currentTimeMillis() - startTime) + " ms 。");
}
@Override
public void onDisable() {
log(getName() + " " + getDescription().getVersion() + " 开始卸载...");
long startTime = System.currentTimeMillis();
log("关闭所有请求...");
getRequestManager().shutdown();
log("保存用户数据...");
getUserManager().getUserDataMap().values().forEach(UserData::save);
getUserManager().getUserDataMap().clear();
log("卸载监听器...");
Bukkit.getServicesManager().unregisterAll(this);
log("卸载完成 ,共耗时 " + (System.currentTimeMillis() - startTime) + " ms 。");
}
} }
@@ -0,0 +1,41 @@
package cc.carm.plugin.moeteleport;
import cc.carm.plugin.moeteleport.manager.RequestManager;
import cc.carm.plugin.moeteleport.manager.TeleportManager;
import cc.carm.plugin.moeteleport.manager.UserManager;
import cc.carm.plugin.moeteleport.manager.WarpManager;
import cc.carm.plugin.moeteleport.storage.DataStorage;
import cc.carm.plugin.moeteleport.storage.StorageMethod;
public class MoeTeleport {
public static DataStorage getStorage() {
return Main.getInstance().storage;
}
public static WarpManager getWarpManager() {
return Main.getInstance().warpManager;
}
public static UserManager getUserManager() {
return Main.getInstance().userManager;
}
public static RequestManager getRequestManager() {
return Main.getInstance().requestManager;
}
public static TeleportManager getTeleportManager() {
return Main.getInstance().teleportManager;
}
public void setStorage(DataStorage storage) {
Main.getInstance().storage = storage;
}
public void registerCustomStorage(Class<? extends DataStorage> storageClazz) {
StorageMethod.CUSTOM.setStorageClazz(storageClazz);
}
}
@@ -1,28 +0,0 @@
package cc.carm.plugin.moeteleport.command;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.manager.TeleportManager;
import cc.carm.plugin.moeteleport.model.UserData;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class BackCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
UserData data = Main.getUserManager().getData(player);
if (data.getLastLocation() == null) {
PluginMessages.NO_LAST_LOCATION.send(player);
return true;
}
TeleportManager.teleport(player, data.getLastLocation(), false);
return true;
}
}
@@ -0,0 +1,35 @@
package cc.carm.plugin.moeteleport.command;
import cc.carm.lib.easyplugin.command.CommandHandler;
import cc.carm.plugin.moeteleport.command.sub.*;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public class MainCommands extends CommandHandler {
public MainCommands(@NotNull JavaPlugin plugin) {
super(plugin);
registerHandler(new TeleportCommands(plugin, this, "teleport", "tp"));
registerHandler(new WarpCommands(plugin, this, "warp", "warps"));
registerHandler(new HomeCommands(plugin, this, "home", "homes"));
registerSubCommand(new BackCommand(this, "back"));
registerSubCommand(new ReloadCommand(this, "reload"));
}
@Override
public Void noArgs(CommandSender sender) {
PluginMessages.USAGE.COMMAND.send(sender);
return null;
}
@Override
public Void noPermission(CommandSender sender) {
PluginMessages.NO_PERMISSION.send(sender);
return null;
}
}
@@ -1,23 +0,0 @@
package cc.carm.plugin.moeteleport.command;
import cc.carm.plugin.moeteleport.manager.ConfigManager;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class MoeTeleportCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command,
@NotNull String s, @NotNull String[] args) {
if (args[0].equalsIgnoreCase("reload")) {
commandSender.sendMessage("Reloading config...");
ConfigManager.reload();
commandSender.sendMessage("Config reloaded.");
return true;
}
return false;
}
}
@@ -0,0 +1,40 @@
package cc.carm.plugin.moeteleport.command.base;
import cc.carm.lib.easyplugin.command.SubCommand;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.HomeCommands;
import cc.carm.plugin.moeteleport.storage.UserData;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public abstract class HomeSubCommand extends SubCommand<HomeCommands> {
public HomeSubCommand(@NotNull HomeCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
public @NotNull UserData getData(Player player) {
return MoeTeleport.getUserManager().getData(player);
}
public @Nullable UserData getData(UUID player) {
return MoeTeleport.getUserManager().getData(player);
}
public @NotNull List<String> listHomes(CommandSender sender, String input) {
if (!(sender instanceof Player)) return Collections.emptyList();
return MoeTeleport.getUserManager().getData((Player) sender)
.getHomeLocations().keySet().stream()
.filter(s -> StringUtil.startsWithIgnoreCase(s, input))
.limit(10).collect(Collectors.toList());
}
}
@@ -0,0 +1,45 @@
package cc.carm.plugin.moeteleport.command.base;
import cc.carm.lib.easyplugin.command.SubCommand;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.TeleportCommands;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.teleport.TeleportRequest;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.stream.Collectors;
public abstract class TeleportSubCommand extends SubCommand<TeleportCommands> {
public TeleportSubCommand(@NotNull TeleportCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
public @NotNull UserData getData(Player player) {
return MoeTeleport.getUserManager().getData(player);
}
public @Nullable UserData getData(UUID player) {
return MoeTeleport.getUserManager().getData(player);
}
public @NotNull List<String> listRequests(CommandSender sender, String input) {
if (!(sender instanceof Player)) return Collections.emptyList();
return getReceivedRequests((Player) sender).keySet().stream()
.map(Bukkit::getPlayer).filter(Objects::nonNull).map(HumanEntity::getName)
.filter(s -> StringUtil.startsWithIgnoreCase(s, input))
.limit(10).collect(Collectors.toList());
}
public @NotNull Map<UUID, TeleportRequest> getReceivedRequests(Player player) {
return MoeTeleport.getRequestManager().getUserReceivedRequests(player.getUniqueId());
}
}
@@ -0,0 +1,53 @@
package cc.carm.plugin.moeteleport.command.base;
import cc.carm.lib.easyplugin.command.SubCommand;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.WarpCommands;
import cc.carm.plugin.moeteleport.manager.WarpManager;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public abstract class WarpSubCommand extends SubCommand<WarpCommands> {
public WarpSubCommand(@NotNull WarpCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
public WarpManager getManager() {
return MoeTeleport.getWarpManager();
}
@NotNull
@Unmodifiable
public Map<String, WarpInfo> listWarps() {
return getManager().listWarps();
}
public WarpInfo getWarp(@NotNull String name) {
return getManager().getWarp(name);
}
public List<String> listWarpNames(CommandSender sender, String input, boolean limitOwner) {
if (limitOwner && sender instanceof Player) {
Player player = (Player) sender;
return listWarps().entrySet().stream()
.filter(entry -> entry.getValue().getOwner() != null)
.filter(entry -> entry.getValue().getOwner().equals(player.getUniqueId()))
.map(Map.Entry::getKey)
.filter(s -> StringUtil.startsWithIgnoreCase(s, input))
.limit(10).collect(Collectors.toList());
} else {
return listWarps().keySet().stream()
.filter(s -> StringUtil.startsWithIgnoreCase(s, input))
.limit(10).collect(Collectors.toList());
}
}
}
@@ -1,30 +0,0 @@
package cc.carm.plugin.moeteleport.command.completer;
import cc.carm.plugin.moeteleport.Main;
import com.google.common.collect.ImmutableList;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.stream.Collectors;
public class HomeNameCompleter implements TabCompleter {
@Nullable
@Override
public java.util.List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (!(sender instanceof Player)) return ImmutableList.of();
if (args.length == 1) {
return Main.getUserManager().getData((Player) sender).getHomeLocations().keySet().stream()
.filter(s -> StringUtil.startsWithIgnoreCase(s, args[0]))
.limit(10).collect(Collectors.toList());
} else {
return ImmutableList.of();
}
}
}
@@ -1,47 +0,0 @@
package cc.carm.plugin.moeteleport.command.completer;
import com.google.common.collect.ImmutableList;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.HumanEntity;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class PlayerNameCompleter implements TabCompleter {
List<Integer> indexes;
public PlayerNameCompleter() {
this(1);
}
public PlayerNameCompleter(Integer index) {
this(new Integer[]{index});
}
public PlayerNameCompleter(Integer[] indexes) {
this.indexes = Arrays.asList(indexes);
}
@Nullable
@Override
public java.util.List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length >= 1 && indexes.contains(args.length)) {
return Bukkit.getOnlinePlayers().stream()
.map(HumanEntity::getName)
.filter(s -> StringUtil.startsWithIgnoreCase(s, args[args.length - 1]))
.limit(10).collect(Collectors.toList());
} else {
return ImmutableList.of();
}
}
}
@@ -1,53 +0,0 @@
package cc.carm.plugin.moeteleport.command.completer;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.model.UserData;
import com.google.common.collect.ImmutableList;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class TpRequestCompleter implements TabCompleter {
List<Integer> indexes;
public TpRequestCompleter() {
this(1);
}
public TpRequestCompleter(Integer index) {
this(new Integer[]{index});
}
public TpRequestCompleter(Integer[] indexes) {
this.indexes = Arrays.asList(indexes);
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (!(sender instanceof Player)) return ImmutableList.of();
if (args.length >= 1 && indexes.contains(args.length)) {
UserData data = Main.getUserManager().getData((Player) sender);
return data.getReceivedRequests().keySet().stream()
.map(Bukkit::getPlayer).filter(Objects::nonNull).map(HumanEntity::getName)
.filter(s -> StringUtil.startsWithIgnoreCase(s, args[args.length - 1]))
.limit(10).collect(Collectors.toList());
} else {
return ImmutableList.of();
}
}
}
@@ -1,39 +0,0 @@
package cc.carm.plugin.moeteleport.command.home;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.model.UserData;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class DelHomeCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player)) return false;
if (args.length < 1) return false;
Player player = (Player) sender;
UserData data = Main.getUserManager().getData(player);
String homeName = args[0];
Map.Entry<String, DataLocation> locationInfo = data.getHomeLocation(homeName);
if (locationInfo == null) {
PluginMessages.Home.NOT_FOUND.sendWithPlaceholders(player);
} else {
PluginMessages.Home.REMOVED.sendWithPlaceholders(player,
new String[]{"%(name)", "%(location)"},
new Object[]{locationInfo.getKey(), locationInfo.getValue().toFlatString()});
data.delHomeLocation(homeName);
}
return true;
}
}
@@ -1,35 +0,0 @@
package cc.carm.plugin.moeteleport.command.home;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.manager.TeleportManager;
import cc.carm.plugin.moeteleport.model.UserData;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class GoHomeCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
UserData data = Main.getUserManager().getData(player);
String homeName = args.length >= 1 ? args[0] : null;
Map.Entry<String, DataLocation> locationInfo = data.getHomeLocation(homeName);
if (locationInfo == null) {
PluginMessages.Home.NOT_FOUND.sendWithPlaceholders(player);
} else {
TeleportManager.teleport(player, locationInfo.getValue(), false);
}
return true;
}
}
@@ -1,29 +0,0 @@
package cc.carm.plugin.moeteleport.command.home;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.model.UserData;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ListHomeCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
UserData data = Main.getUserManager().getData(player);
PluginMessages.Home.HEADER.sendWithPlaceholders(player);
data.getHomeLocations().forEach((name, loc) -> PluginMessages.Home.LIST_OBJECT
.sendWithPlaceholders(player,
new String[]{"%(id)", "%(location)"},
new Object[]{name, loc.toFlatString()}
));
return true;
}
}
@@ -1,38 +0,0 @@
package cc.carm.plugin.moeteleport.command.home;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.model.UserData;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class SetHomeCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
UserData data = Main.getUserManager().getData(player);
String homeName = args.length >= 1 ? args[0] : "home";
int maxHome = Main.getUserManager().getMaxHome(player);
if (data.getHomeLocations().size() >= maxHome && data.getHomeLocation(homeName) == null) {
PluginMessages.Home.OVER_LIMIT.sendWithPlaceholders(sender,
new String[]{"%(max)"}, new Object[]{maxHome}
);
return true;
}
data.setHomeLocation(homeName, player.getLocation());
PluginMessages.Home.SET.sendWithPlaceholders(player,
new String[]{"%(name)"}, new Object[]{homeName}
);
return true;
}
}
@@ -0,0 +1,47 @@
package cc.carm.plugin.moeteleport.command.sub;
import cc.carm.lib.easyplugin.command.SubCommand;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.MainCommands;
import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.storage.UserData;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public class BackCommand extends SubCommand<MainCommands> {
public BackCommand(@NotNull MainCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
if (!PluginConfig.BACK.ENABLE.getNotNull()) {
PluginMessages.NOT_ENABLED.send(sender);
return null;
}
Player player = (Player) sender;
UserData data = MoeTeleport.getUserManager().getData(player);
if (data.getLastLocation() == null) {
PluginMessages.BACK.NO_LAST_LOCATION.send(player);
return null;
}
MoeTeleport.getTeleportManager().queueTeleport(player, data.getLastLocation());
return null;
}
@Override
public boolean hasPermission(CommandSender sender) {
return sender.hasPermission("MoeTeleport.back");
}
}
@@ -0,0 +1,56 @@
package cc.carm.plugin.moeteleport.command.sub;
import cc.carm.lib.easyplugin.command.CommandHandler;
import cc.carm.plugin.moeteleport.command.MainCommands;
import cc.carm.plugin.moeteleport.command.sub.home.*;
import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public class HomeCommands extends CommandHandler {
protected final @NotNull MainCommands main;
public HomeCommands(@NotNull JavaPlugin plugin, @NotNull MainCommands main,
@NotNull String cmd, @NotNull String... aliases) {
super(plugin, cmd, aliases);
this.main = main;
registerSubCommand(new HomeTeleportCommand(this, "to", "teleport", "tp"));
registerSubCommand(new HomeListCommand(this, "list", "ls"));
registerSubCommand(new HomeCreateCommand(this, "set", "create"));
registerSubCommand(new HomeDeleteCommand(this, "delete", "remove", "del"));
registerSubCommand(new HomeRenameCommand(this, "rename", "rn"));
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (!PluginConfig.HOMES.ENABLE.getNotNull()) {
PluginMessages.NOT_ENABLED.send(sender);
return true;
}
return super.onCommand(sender, command, label, args);
}
@Override
public Void noArgs(CommandSender sender) {
PluginMessages.USAGE.HOMES.send(sender);
return null;
}
@Override
public Void noPermission(CommandSender sender) {
return main.noPermission(sender);
}
@Override
public boolean hasPermission(CommandSender sender) {
return sender.hasPermission("MoeTeleport.home");
}
}
@@ -0,0 +1,41 @@
package cc.carm.plugin.moeteleport.command.sub;
import cc.carm.lib.easyplugin.command.SubCommand;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.command.MainCommands;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public class ReloadCommand extends SubCommand<MainCommands> {
public ReloadCommand(@NotNull MainCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) {
PluginMessages.RELOAD.START.send(sender);
long s1 = System.currentTimeMillis();
try {
Main.getInstance().getConfigProvider().reload();
Main.getInstance().getMessageProvider().reload();
PluginMessages.RELOAD.COMPLETE.send(sender, System.currentTimeMillis() - s1);
} catch (Exception ex) {
PluginMessages.RELOAD.ERROR.send(sender);
ex.printStackTrace();
}
return null;
}
@Override
public boolean hasPermission(CommandSender sender) {
return sender.hasPermission("MoeTeleport.admin");
}
}
@@ -0,0 +1,46 @@
package cc.carm.plugin.moeteleport.command.sub;
import cc.carm.lib.easyplugin.command.CommandHandler;
import cc.carm.plugin.moeteleport.command.MainCommands;
import cc.carm.plugin.moeteleport.command.sub.teleport.TeleportCancelCommand;
import cc.carm.plugin.moeteleport.command.sub.teleport.TeleportHandleCommand;
import cc.carm.plugin.moeteleport.command.sub.teleport.TeleportRequestCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.teleport.TeleportRequest;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public class TeleportCommands extends CommandHandler {
protected final @NotNull MainCommands main;
public TeleportCommands(@NotNull JavaPlugin plugin, @NotNull MainCommands main,
@NotNull String cmd, @NotNull String... aliases) {
super(plugin, cmd, aliases);
this.main = main;
registerSubCommand(new TeleportRequestCommand(this, TeleportRequest.Type.TPA_TO, "to"));
registerSubCommand(new TeleportRequestCommand(this, TeleportRequest.Type.TPA_HERE, "here"));
registerSubCommand(new TeleportHandleCommand(this, true, "accept", "agree"));
registerSubCommand(new TeleportHandleCommand(this, false, "deny", "refuse"));
registerSubCommand(new TeleportCancelCommand(this, "cancel"));
}
@Override
public Void noArgs(CommandSender sender) {
PluginMessages.USAGE.TELEPORT.send(sender);
return null;
}
@Override
public Void noPermission(CommandSender sender) {
return main.noPermission(sender);
}
@Override
public boolean hasPermission(CommandSender sender) {
return sender.hasPermission("MoeTeleport.teleport");
}
}
@@ -0,0 +1,58 @@
package cc.carm.plugin.moeteleport.command.sub;
import cc.carm.lib.easyplugin.command.CommandHandler;
import cc.carm.plugin.moeteleport.command.MainCommands;
import cc.carm.plugin.moeteleport.command.sub.warp.*;
import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public class WarpCommands extends CommandHandler {
protected final @NotNull MainCommands main;
public WarpCommands(@NotNull JavaPlugin plugin, @NotNull MainCommands main,
@NotNull String cmd, @NotNull String... aliases) {
super(plugin, cmd, aliases);
this.main = main;
registerSubCommand(new WarpTeleportCommand(this, "to", "teleport", "tp"));
registerSubCommand(new WarpListCommand(this, "list", "ls"));
registerSubCommand(new WarpInfoCommand(this, "info", "i"));
registerSubCommand(new WarpCreateCommand(this, "set", "create"));
registerSubCommand(new WarpDeleteCommand(this, "delete", "remove", "del"));
registerSubCommand(new WarpRenameCommand(this, "rename", "rn"));
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (!PluginConfig.WARPS.ENABLE.getNotNull()) {
PluginMessages.NOT_ENABLED.send(sender);
return true;
}
return super.onCommand(sender, command, label, args);
}
@Override
public Void noArgs(CommandSender sender) {
PluginMessages.USAGE.WARPS.send(sender);
return null;
}
@Override
public Void noPermission(CommandSender sender) {
return main.noPermission(sender);
}
@Override
public boolean hasPermission(CommandSender sender) {
return sender.hasPermission("MoeTeleport.warp");
}
}
@@ -0,0 +1,65 @@
package cc.carm.plugin.moeteleport.command.sub.home;
import cc.carm.lib.easyplugin.command.SimpleCompleter;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.HomeCommands;
import cc.carm.plugin.moeteleport.command.base.HomeSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.storage.UserData;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class HomeCreateCommand extends HomeSubCommand {
public HomeCreateCommand(@NotNull HomeCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
Player player = (Player) sender;
UserData data = getData(player);
String homeName = args.length >= 1 ? args[0] : "home";
if (homeName.length() > 32) { // 超过家的名字长度限定
PluginMessages.HOME.NAME_TOO_LONG.send(sender);
return null;
}
Map.Entry<String, DataLocation> lastHomeLocation = data.getHomeLocation(homeName);
int maxHome = MoeTeleport.getUserManager().getMaxHome(player);
if (data.getHomeLocations().size() >= maxHome && lastHomeLocation == null) {
PluginMessages.HOME.OVER_LIMIT.send(sender, maxHome);
return null;
}
data.setHomeLocation(homeName, player.getLocation());
if (lastHomeLocation != null) {
PluginMessages.HOME.OVERRIDE.send(sender, homeName, lastHomeLocation.getValue().toFlatString());
} else {
PluginMessages.HOME.SET.send(player, homeName);
}
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return SimpleCompleter.text(args[args.length - 1], "home", sender.getName());
} else return Collections.emptyList();
}
}
@@ -0,0 +1,54 @@
package cc.carm.plugin.moeteleport.command.sub.home;
import cc.carm.plugin.moeteleport.command.sub.HomeCommands;
import cc.carm.plugin.moeteleport.command.base.HomeSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.storage.UserData;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class HomeDeleteCommand extends HomeSubCommand {
public HomeDeleteCommand(@NotNull HomeCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
if (args.length < 1) return getParent().noArgs(sender);
Player player = (Player) sender;
UserData data = getData(player);
String homeName = args[0];
Map.Entry<String, DataLocation> locationInfo = data.getHomeLocation(homeName);
if (locationInfo == null) {
PluginMessages.HOME.NOT_FOUND.send(player);
} else {
PluginMessages.HOME.REMOVED.send(player, locationInfo.getKey(), locationInfo.getValue().toFlatString());
data.delHomeLocation(homeName);
}
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return listHomes(sender, args[args.length - 1]);
} else return Collections.emptyList();
}
}
@@ -0,0 +1,37 @@
package cc.carm.plugin.moeteleport.command.sub.home;
import cc.carm.plugin.moeteleport.command.sub.HomeCommands;
import cc.carm.plugin.moeteleport.command.base.HomeSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.storage.UserData;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public class HomeListCommand extends HomeSubCommand {
public HomeListCommand(@NotNull HomeCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
Player player = (Player) sender;
UserData data = getData(player);
if (data.getHomeLocations().isEmpty()) {
PluginMessages.HOME.EMPTY.send(sender);
return null;
}
PluginMessages.HOME.LIST.HEADER.send(player);
data.getHomeLocations().forEach((name, loc) -> PluginMessages.HOME.LIST.OBJECT.send(player, name, loc.toFlatString()));
return null;
}
}
@@ -0,0 +1,71 @@
package cc.carm.plugin.moeteleport.command.sub.home;
import cc.carm.plugin.moeteleport.command.sub.HomeCommands;
import cc.carm.plugin.moeteleport.command.base.HomeSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.storage.UserData;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class HomeRenameCommand extends HomeSubCommand {
public HomeRenameCommand(@NotNull HomeCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
if (args.length < 2) return getParent().noArgs(sender);
String homeName = args[0];
String newName = args[1];
if (homeName.equals(newName)) return getParent().noArgs(sender);
if (newName.length() > 32) { // 超过家的名字长度限定
PluginMessages.HOME.NAME_TOO_LONG.send(sender);
return null;
}
Player player = (Player) sender;
UserData data = getData(player);
Map.Entry<String, DataLocation> locationInfo = data.getHomeLocation(homeName);
if (locationInfo == null) {
PluginMessages.HOME.NOT_FOUND.send(player);
return null;
}
Map.Entry<String, DataLocation> newInfo = data.getHomeLocation(newName);
if (newInfo != null) {
PluginMessages.HOME.ALREADY_EXITS.send(player);
return null;
}
PluginMessages.HOME.RENAMED.send(player, newName, locationInfo.getKey());
data.setHomeLocation(newName, locationInfo.getValue().getBukkitLocation());
data.delHomeLocation(homeName);
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return listHomes(sender, args[args.length - 1]);
} else return Collections.emptyList();
}
}
@@ -0,0 +1,52 @@
package cc.carm.plugin.moeteleport.command.sub.home;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.HomeCommands;
import cc.carm.plugin.moeteleport.command.base.HomeSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.storage.UserData;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class HomeTeleportCommand extends HomeSubCommand {
public HomeTeleportCommand(@NotNull HomeCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
Player player = (Player) sender;
UserData data = getData(player);
String homeName = args.length >= 1 ? args[0] : null;
Map.Entry<String, DataLocation> locationInfo = data.getHomeLocation(homeName);
if (locationInfo == null) {
PluginMessages.HOME.NOT_FOUND.send(player);
} else {
MoeTeleport.getTeleportManager().queueTeleport(player, locationInfo.getValue());
}
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return listHomes(sender, args[args.length - 1]);
} else return Collections.emptyList();
}
}
@@ -0,0 +1,48 @@
package cc.carm.plugin.moeteleport.command.sub.teleport;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.TeleportCommands;
import cc.carm.plugin.moeteleport.command.base.TeleportSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.teleport.TeleportRequest;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class TeleportCancelCommand extends TeleportSubCommand {
public TeleportCancelCommand(@NotNull TeleportCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
Player player = (Player) sender;
TeleportRequest request = MoeTeleport.getRequestManager().getRequest(player.getUniqueId());
if (request == null) {
PluginMessages.REQUESTS.EMPTY_REQUESTS.send(player);
return null;
}
MoeTeleport.getRequestManager().cancelRequest(request);
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return listRequests(sender, args[args.length - 1]);
} else return Collections.emptyList();
}
}
@@ -0,0 +1,85 @@
package cc.carm.plugin.moeteleport.command.sub.teleport;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.TeleportCommands;
import cc.carm.plugin.moeteleport.command.base.TeleportSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.teleport.TeleportRequest;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class TeleportHandleCommand extends TeleportSubCommand {
protected final boolean accept;
public TeleportHandleCommand(@NotNull TeleportCommands parent, boolean accept, String name, String... aliases) {
super(parent, name, aliases);
this.accept = accept;
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
Player player = (Player) sender;
UserData data = MoeTeleport.getUserManager().getData(player);
Map<UUID, TeleportRequest> receivedRequests = getReceivedRequests(player);
if (receivedRequests.isEmpty()) {
PluginMessages.REQUESTS.EMPTY_REQUESTS.send(player);
return null;
}
String targetName = args.length > 0 ? args[0] : null;
data.setEnableAutoSelect(false);
if (targetName != null) {
Player target = Bukkit.getPlayer(targetName);
TeleportRequest request = target == null ? null : receivedRequests.get(target.getUniqueId());
if (request == null) {
PluginMessages.REQUESTS.NO_REQUEST_FROM.send(player, target == null ? targetName : target.getName());
} else {
handle(request); // 交给Manager处理
}
} else {
if (receivedRequests.size() == 1 || data.isEnableAutoSelect()) {
receivedRequests.values().stream()
.min(Comparator.comparingLong(TeleportRequest::getActiveMillis))
.ifPresent(this::handle);
} else {
PluginMessages.REQUESTS.MULTI.send(player,
receivedRequests.size(),
"moeteleport teleport " + (accept ? "tpAccept" : "tpDeny").toLowerCase()
);
data.setEnableAutoSelect(true);
}
}
return null;
}
private void handle(TeleportRequest request) {
if (accept) {
MoeTeleport.getRequestManager().acceptRequest(request);
} else {
MoeTeleport.getRequestManager().denyRequest(request);
}
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return listRequests(sender, args[args.length - 1]);
} else return Collections.emptyList();
}
}
@@ -0,0 +1,20 @@
package cc.carm.plugin.moeteleport.command.sub.teleport;
import cc.carm.plugin.moeteleport.command.sub.TeleportCommands;
import cc.carm.plugin.moeteleport.command.base.TeleportSubCommand;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public class TeleportRandomCommand extends TeleportSubCommand {
public TeleportRandomCommand(@NotNull TeleportCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
return null;
}
}
@@ -0,0 +1,73 @@
package cc.carm.plugin.moeteleport.command.sub.teleport;
import cc.carm.lib.easyplugin.command.SimpleCompleter;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.TeleportCommands;
import cc.carm.plugin.moeteleport.command.base.TeleportSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.teleport.TeleportRequest;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class TeleportRequestCommand extends TeleportSubCommand {
private final @NotNull TeleportRequest.Type type;
public TeleportRequestCommand(@NotNull TeleportCommands parent,
@NotNull TeleportRequest.Type type,
String name, String... aliases) {
super(parent, name, aliases);
this.type = type;
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
if (args.length < 1) return getParent().noArgs(sender);
Player player = (Player) sender;
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
PluginMessages.NOT_ONLINE.send(player);
return null;
}
if (player == target) {
// fix #5 - 玩家给自己发送传送请求
PluginMessages.REQUESTS.SELF.send(player);
return null;
}
TeleportRequest sent = MoeTeleport.getRequestManager().getRequest(player.getUniqueId());
if (sent != null) {
PluginMessages.REQUESTS.DUPLICATE.send(sender, target.getName(), sent.getRemainSeconds());
return null;
}
MoeTeleport.getRequestManager().sendRequest(player, target, type);
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return SimpleCompleter.objects(
args[args.length - 1], 15,
Bukkit.getOnlinePlayers().stream()
.map(Player::getName)
.filter(s -> !s.equalsIgnoreCase(sender.getName()))
);
} else return Collections.emptyList();
}
}
@@ -0,0 +1,71 @@
package cc.carm.plugin.moeteleport.command.sub.warp;
import cc.carm.lib.easyplugin.command.SimpleCompleter;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.WarpCommands;
import cc.carm.plugin.moeteleport.command.base.WarpSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class WarpCreateCommand extends WarpSubCommand {
public WarpCreateCommand(@NotNull WarpCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
Player player = (Player) sender;
String warpName = args.length >= 1 ? args[0] : player.getName();
if (warpName.length() > 16) { // 超过地标的名字长度限定
PluginMessages.WARP.NAME_TOO_LONG.send(sender);
return null;
}
WarpInfo info = getWarp(warpName);
if (!player.isOp() && !player.hasPermission("MoeTeleport.admin")) {
if (info != null && (info.getOwner() == null || !info.getOwner().equals(player.getUniqueId()))) {
PluginMessages.WARP.NOT_OWNER.send(sender, warpName);
return null;
}
int maxWarp = MoeTeleport.getUserManager().getMaxWarps(player);
long currentUsed = MoeTeleport.getUserManager().countUserWarps(player.getUniqueId());
if (currentUsed >= maxWarp && info == null) {
PluginMessages.WARP.OVER_LIMIT.send(sender, maxWarp);
return null;
}
}
getManager().setWarpAsync(warpName, player.getUniqueId(), player.getLocation());
if (info != null) {
PluginMessages.WARP.OVERRIDE.send(sender, warpName, info.getLocation().toFlatString());
} else {
PluginMessages.WARP.SET.send(sender, warpName);
}
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return SimpleCompleter.text(args[args.length - 1], sender.getName());
} else return Collections.emptyList();
}
}
@@ -0,0 +1,55 @@
package cc.carm.plugin.moeteleport.command.sub.warp;
import cc.carm.plugin.moeteleport.command.sub.WarpCommands;
import cc.carm.plugin.moeteleport.command.base.WarpSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class WarpDeleteCommand extends WarpSubCommand {
public WarpDeleteCommand(@NotNull WarpCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
if (args.length < 1) return getParent().noArgs(sender);
String warpName = args[0];
WarpInfo info = getWarp(warpName);
if (info == null) {
PluginMessages.WARP.NOT_FOUND.send(sender, warpName);
return null;
}
if (sender instanceof Player && !sender.isOp()
&& !sender.hasPermission("MoeTeleport.admin")) {
Player player = (Player) sender;
if (info.getOwner() == null || !info.getOwner().equals(player.getUniqueId())) {
PluginMessages.WARP.NOT_OWNER.send(sender);
return null;
}
}
getManager().delWarpAsync(warpName);
PluginMessages.WARP.REMOVED.send(sender, warpName, info.getLocation().toFlatString());
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return listWarpNames(sender, args[args.length - 1], true);
} else return Collections.emptyList();
}
}
@@ -0,0 +1,47 @@
package cc.carm.plugin.moeteleport.command.sub.warp;
import cc.carm.plugin.moeteleport.command.sub.WarpCommands;
import cc.carm.plugin.moeteleport.command.base.WarpSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class WarpInfoCommand extends WarpSubCommand {
public WarpInfoCommand(@NotNull WarpCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) {
String warpName = args[0];
WarpInfo info = getWarp(warpName);
if (info == null) {
PluginMessages.WARP.NOT_FOUND.send(sender, warpName);
return null;
}
String ownerName = info.getOwnerName();
if (ownerName != null) {
PluginMessages.WARP.INFO_FULL.send(sender, warpName, ownerName, info.getLocation().toFlatString());
} else {
PluginMessages.WARP.INFO_LOCATION.send(sender, warpName, info.getLocation().toFlatString());
}
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return listWarpNames(sender, args[args.length - 1], false);
} else return Collections.emptyList();
}
}
@@ -0,0 +1,68 @@
package cc.carm.plugin.moeteleport.command.sub.warp;
import cc.carm.lib.easyplugin.command.SimpleCompleter;
import cc.carm.plugin.moeteleport.command.sub.WarpCommands;
import cc.carm.plugin.moeteleport.command.base.WarpSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.IntStream;
public class WarpListCommand extends WarpSubCommand {
public WarpListCommand(@NotNull WarpCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) {
ArrayList<WarpInfo> warps = new ArrayList<>(listWarps().values());
if (warps.isEmpty()) {
PluginMessages.WARP.EMPTY.send(sender);
return null;
}
String pageString = args.length > 0 ? args[0] : null;
int page = 1;
if (pageString != null) {
try {
page = Integer.parseInt(pageString);
} catch (Exception ignored) {
}
}
int maxPage = (int) Math.ceil(warps.size() / 10.0);
int currentPage = Math.min(page, maxPage);
int startIndex = Math.max(0, (currentPage - 1) * 10);
int endIndex = Math.min(warps.size(), startIndex + 9);
PluginMessages.WARP.LIST.HEADER.send(sender, currentPage, maxPage);
for (int i = startIndex; i < endIndex; i++) {
WarpInfo info = warps.get(i);
String ownerName = info.getOwnerName();
if (ownerName == null) {
PluginMessages.WARP.LIST.OBJECT_NO_OWNER.send(sender, info.getName(), info.getLocation().toFlatString());
} else {
PluginMessages.WARP.LIST.OBJECT.send(sender, info.getName(), ownerName, info.getLocation().toFlatString());
}
}
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
int maxPage = (int) Math.ceil(listWarps().size() / 10.0);
return SimpleCompleter.objects(args[args.length - 1], IntStream.rangeClosed(1, maxPage).boxed());
} else return Collections.emptyList();
}
}
@@ -0,0 +1,71 @@
package cc.carm.plugin.moeteleport.command.sub.warp;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.command.sub.WarpCommands;
import cc.carm.plugin.moeteleport.command.base.WarpSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class WarpRenameCommand extends WarpSubCommand {
public WarpRenameCommand(@NotNull WarpCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
if (args.length < 2) return getParent().noArgs(sender);
String oldName = args[0];
String newName = args[1];
if (oldName.equals(newName)) return getParent().noArgs(sender);
if (newName.length() > 16) { // 超过地标的名字长度限定
PluginMessages.WARP.NAME_TOO_LONG.send(sender);
return null;
}
Player player = (Player) sender;
WarpInfo info = getWarp(oldName);
if (info == null) {
PluginMessages.WARP.NOT_FOUND.send(player);
return null;
}
WarpInfo newInfo = getWarp(oldName);
if (newInfo != null) {
PluginMessages.WARP.ALREADY_EXITS.send(player);
return null;
}
PluginMessages.WARP.RENAMED.send(player, newName, info.getLocation());
Main.getInstance().getScheduler().runAsync(() -> {
getManager().setWarp(newName, player.getUniqueId(), info.getLocation());
getManager().delWarp(oldName);
});
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return listWarpNames(sender, args[args.length - 1], true);
} else return Collections.emptyList();
}
}
@@ -0,0 +1,50 @@
package cc.carm.plugin.moeteleport.command.sub.warp;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.command.sub.WarpCommands;
import cc.carm.plugin.moeteleport.command.base.WarpSubCommand;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class WarpTeleportCommand extends WarpSubCommand {
public WarpTeleportCommand(@NotNull WarpCommands parent, String name, String... aliases) {
super(parent, name, aliases);
}
@Override
public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) {
if (!(sender instanceof Player)) {
PluginMessages.NOT_PLAYER.send(sender);
return null;
}
if (args.length < 1) return getParent().noArgs(sender);
Player player = (Player) sender;
WarpInfo info = getWarp(args[0]);
if (info == null) {
PluginMessages.WARP.NOT_FOUND.send(player, args[0]);
return null;
}
MoeTeleport.getTeleportManager().queueTeleport(player, info.getLocation());
return null;
}
@Override
public List<String> tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) {
if (args.length == 1) {
return listWarpNames(sender, args[args.length - 1], false);
} else return Collections.emptyList();
}
}
@@ -1,65 +0,0 @@
package cc.carm.plugin.moeteleport.command.tpa;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.model.TeleportRequest;
import cc.carm.plugin.moeteleport.model.UserData;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
public class TpHandleCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
UserData data = Main.getUserManager().getData(player);
if (data.getReceivedRequests().isEmpty()) {
PluginMessages.Request.NOT_FOUND.sendWithPlaceholders(player);
return true;
}
String targetName = args.length > 0 ? args[0] : null;
boolean accept = command.getName().equalsIgnoreCase("tpAccept");
data.setEnableAutoSelect(false);
if (targetName != null) {
Player target = Bukkit.getPlayer(targetName);
if (target == null || !data.getReceivedRequests().containsKey(target.getUniqueId())) {
PluginMessages.Request.NOT_FOUND_PLAYER.sendWithPlaceholders(player,
new String[]{"%(player)"},
new Object[]{target == null ? targetName : target.getName()}
);
} else {
handle(data.getReceivedRequests().get(target.getUniqueId()), accept); // 交给Manager处理
}
} else {
if (data.getReceivedRequests().size() == 1 || data.isEnableAutoSelect()) {
data.getReceivedRequests().values().stream()
.min(Comparator.comparingLong(TeleportRequest::getActiveTime))
.ifPresent(request -> handle(request, accept));
} else {
PluginMessages.Request.MULTI.sendWithPlaceholders(player,
new String[]{"%(num)", "%(command)"},
new Object[]{data.getReceivedRequests().size(), command.getName()}
);
data.setEnableAutoSelect(true);
}
}
return true;
}
private void handle(TeleportRequest request, boolean accept) {
if (accept) {
Main.getRequestManager().acceptRequest(request);
} else {
Main.getRequestManager().denyRequest(request);
}
}
}
@@ -1,43 +0,0 @@
package cc.carm.plugin.moeteleport.command.tpa;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.model.TeleportRequest;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class TpaCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player) || args.length < 1) return false;
Player player = (Player) sender;
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
PluginMessages.NOT_ONLINE.sendWithPlaceholders(player);
return true;
}
TeleportRequest request = Main.getUserManager().getData(target).getReceivedRequests().get(player.getUniqueId());
if (request != null) {
PluginMessages.Request.DUPLICATE.sendWithPlaceholders(sender,
new String[]{"%(player)", "%(expire)"},
new Object[]{target.getName(), request.getRemainSeconds()}
);
return true;
}
if (command.getName().equalsIgnoreCase("tpa")) {
Main.getRequestManager().sendRequest(player, target, TeleportRequest.RequestType.TPA);
} else {
Main.getRequestManager().sendRequest(player, target, TeleportRequest.RequestType.TPA_HERE);
}
return true;
}
}
@@ -0,0 +1,203 @@
package cc.carm.plugin.moeteleport.conf;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.util.MapFactory;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredMap;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredSound;
import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredTitle;
public class PluginConfig extends ConfigurationRoot {
public static final ConfigValue<Boolean> DEBUG = ConfiguredValue.of(Boolean.class, false);
@HeaderComment({
"统计数据设定",
"该选项用于帮助开发者统计插件版本与使用情况,且绝不会影响性能与使用体验。",
"当然,您也可以选择在这里关闭,或在plugins/bStats下的配置文件中关闭。"
})
public static final ConfigValue<Boolean> METRICS = ConfiguredValue.of(Boolean.class, true);
@HeaderComment({
"检查更新设定",
"该选项用于插件判断是否要检查更新,若您不希望插件检查更新并提示您,可以选择关闭。",
"检查更新为异步操作,绝不会影响性能与使用体验。"
})
public static final ConfigValue<Boolean> CHECK_UPDATE = ConfiguredValue.of(Boolean.class, true);
@HeaderComment("简化插件指令设定")
public static final class COMMAND extends ConfigurationRoot {
@HeaderComment({"是否启用简化指令"})
public static final ConfigValue<Boolean> ENABLE = ConfiguredValue.of(Boolean.class, true);
@HeaderComment({
"简化指令表,配置以方便玩家使用。",
"格式: 简短指令: 本插件子指令(不含前缀)",
"如 [back: back] 代表 玩家可以输入/back 代替 /MoeTeleport back",
"注意:简短指令不应当包含空格,且不可与其他插件指令重复,否则将会被覆盖。",
})
public static final ConfiguredMap<String, String> ALIAS = ConfiguredMap.builder(String.class, String.class)
.fromString().defaults((map) -> {
map.put("back", "back");
map.put("tpa", "teleport to");
map.put("tpaHere", "teleport here");
map.put("tpAccept", "teleport accept");
map.put("tpDeny", "teleport deny");
map.put("tpCancel", "teleport cancel");
map.put("home", "home to");
map.put("setHome", "home set");
map.put("delHome", "home delete");
map.put("listHomes", "home list");
map.put("listHome", "home list");
map.put("renameHome", "home rename");
map.put("warp", "warp to");
map.put("setWarp", "warp set");
map.put("delWarp", "warp delete");
map.put("warpInfo", "warp info");
map.put("listWarps", "warp list");
map.put("listWarp", "warp list");
map.put("renameWarp", "warp rename");
}).build();
}
@HeaderComment({"存储相关配置", "注意:存储配置不会通过重载指令生效,如有修改请重新启动服务器。"})
public static final class STORAGE extends ConfigurationRoot {
@HeaderComment("存储方式,可选 [ yaml | json | mysql | Essential(须安装ess插件) | CMI(须安装CMI插件) | custom(自定义,须重写功能) ]")
public static final ConfigValue<String> METHOD = ConfiguredValue.of(String.class, "YAML");
}
@HeaderComment("传送的相关配置")
public static final class TELEPORTATION extends ConfigurationRoot {
/* Will be supported again in the future
@HeaderComment("危险的方块类型,将判断目的地脚下的方块的类型是否在这个列表中")
public static final ConfiguredList<String> DANGEROUS_TYPES = ConfiguredList.builder(String.class)
.fromString()
.defaults("LAVA", "AIR")
.build();
*/
@HeaderComment("传送的引导时间,单位为秒")
public static final ConfigValue<Integer> WAIT_TIME = ConfiguredValue.of(Integer.class, 3);
@HeaderComment("打断传送引导的方式")
public static final class INTERRUPT extends ConfigurationRoot {
@HeaderComment("在传送引导时是否会因为移动打断传送")
public static final ConfigValue<Boolean> MOVE = ConfiguredValue.of(Boolean.class, true);
@HeaderComment("在传送引导时是否会因为攻击/被攻击打断传送")
public static final ConfigValue<Boolean> ATTACK = ConfiguredValue.of(Boolean.class, true);
@HeaderComment("在传送引导时是否会因为下蹲打断传送")
public static final ConfigValue<Boolean> SNAKE = ConfiguredValue.of(Boolean.class, false);
}
@HeaderComment("传送过程中的标题")
public static final class TITLE extends ConfigurationRoot {
public static final ConfiguredTitle CHANNELING = PluginMessages.title().defaults(
"&d&l将在 %(time) 秒后传送",
"&7传送过程中请不要移动"
).params("time", "target").fadeIn(0).stay(25).fadeOut(0).build();
public static final ConfiguredTitle TELEPORTED = PluginMessages.title().defaults(
"&d&l传送完成",
"&7已将您传送到 %(target)"
).params("target").fadeIn(0).stay(20).fadeOut(10).build();
}
@HeaderComment("传送引导过程中的音效")
public static final class SOUND extends ConfigurationRoot {
public static final ConfiguredSound CHANNELING = ConfiguredSound.of("UI_BUTTON_CLICK", 0.5f, 1.0f);
public static final ConfiguredSound TELEPORTED = ConfiguredSound.of("ENTITY_ENDERMAN_TELEPORT", 0.5f, 1.0f);
public static final ConfiguredSound FAILED = ConfiguredSound.of("ENTITY_VILLAGER_NO", 0.5f, 1.0f);
public static final ConfiguredSound INTERRUPTED = ConfiguredSound.of("BLOCK_NOTE_BLOCK_BASEDRUM", 1f, 1.0f);
}
@HeaderComment("传送引导特效")
public static final ConfigValue<Boolean> EFFECTS = ConfiguredValue.of(Boolean.class, true);
}
@HeaderComment("传送请求的相关配置")
public static final class REQUEST extends ConfigurationRoot {
@HeaderComment("请求的过期时间,单位为秒")
public static final ConfigValue<Integer> EXPIRE_TIME = ConfiguredValue.of(Integer.class, 30);
public static final class SOUND extends ConfigurationRoot {
public static final ConfiguredSound SENT = ConfiguredSound.of("UI_BUTTON_CLICK", 0.5f, 1.0f);
public static final ConfiguredSound RECEIVED = ConfiguredSound.of("ENTITY_EXPERIENCE_ORB_PICKUP", 0.5f, 1.0f);
public static final ConfiguredSound CANCELLED = ConfiguredSound.of("ENTITY_VILLAGER_NO", 0.5f, 1.0f);
}
}
@HeaderComment("返回上一传送点的相关配置")
public static final class BACK extends ConfigurationRoot {
@HeaderComment("是否启用返回上一传送点功能")
public static final ConfigValue<Boolean> ENABLE = ConfiguredValue.of(Boolean.class, false);
@HeaderComment({"返回死亡点", "开启后将允许玩家输入 /back 返回死亡地点。"})
public static final ConfigValue<Boolean> DEATH = ConfiguredValue.of(Boolean.class, true);
}
@HeaderComment("“家”功能相关配置")
public static final class HOMES extends ConfigurationRoot {
@HeaderComment("是否启用家功能")
public static final ConfigValue<Boolean> ENABLE = ConfiguredValue.of(Boolean.class, false);
@HeaderComment("普通玩家可设置多少家")
public static final ConfigValue<Integer> DEFAULTS = ConfiguredValue.of(Integer.class, 2);
@HeaderComment("设定权限对应的可设置家的数量。 (数量: 权限)")
public static final ConfiguredMap<Integer, String> PERMISSIONS = ConfiguredMap
.builder(Integer.class, String.class)
.fromString()
.parseKey(Integer::parseInt).serializeKey(Object::toString)
.defaults(MapFactory.linkedMap(10, "MoeTeleport.vip").build())
.build();
}
@HeaderComment("“地标”功能相关配置")
public static final class WARPS extends ConfigurationRoot {
@HeaderComment("是否启用地标功能")
public static final ConfigValue<Boolean> ENABLE = ConfiguredValue.of(Boolean.class, false);
@HeaderComment("普通玩家可设置多少地标")
public static final ConfigValue<Integer> DEFAULTS = ConfiguredValue.of(Integer.class, 0);
@HeaderComment("设定权限对应的可设置地标的数量。 (数量: 权限)")
public static final ConfiguredMap<Integer, String> PERMISSIONS = ConfiguredMap
.builder(Integer.class, String.class)
.fromString()
.parseKey(Integer::parseInt).serializeKey(Object::toString)
.defaults(MapFactory.linkedMap(2, "MoeTeleport.vip").build())
.build();
}
}
@@ -0,0 +1,386 @@
package cc.carm.plugin.moeteleport.conf;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.easyplugin.utils.ColorParser;
import cc.carm.lib.easyplugin.utils.MessageUtils;
import cc.carm.lib.mineconfiguration.bukkit.builder.message.CraftMessageListBuilder;
import cc.carm.lib.mineconfiguration.bukkit.builder.message.CraftMessageValueBuilder;
import cc.carm.lib.mineconfiguration.bukkit.builder.title.TitleConfigBuilder;
import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredMessage;
import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredMessageList;
import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredTitle;
import de.themoep.minedown.MineDown;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.function.BiFunction;
@HeaderComment({
"MoeTeleport 传送插件的消息配置文件",
"如特定的消息不需要任何提示,可直接留下单行空内容消息。",
"支持 支持 &+颜色代码(原版颜色)、§(#XXXXXX)(RGB颜色) 与 &<#XXXXXX>(前后标注RGB颜色渐变)。",
" "
})
public class PluginMessages extends ConfigurationRoot {
public static @NotNull CraftMessageListBuilder<BaseComponent[]> list() {
return ConfiguredMessageList.create(getParser())
.whenSend((sender, message) -> message.forEach(m -> sender.spigot().sendMessage(m)));
}
public static @NotNull CraftMessageValueBuilder<BaseComponent[]> value() {
return ConfiguredMessage.create(getParser())
.whenSend((sender, message) -> sender.spigot().sendMessage(message));
}
public static @NotNull TitleConfigBuilder title() {
return ConfiguredTitle.create().whenSend((player, in, stay, out, line1, line2) -> player.sendTitle(line1, line2, in, stay, out));
}
public static @NotNull BiFunction<CommandSender, String, BaseComponent[]> getParser() {
return (sender, message) -> MineDown.parse(ColorParser.parse(MessageUtils.setPlaceholders(sender, message)));
}
public static final ConfiguredMessageList<BaseComponent[]> NO_PERMISSION = list().defaults(
"&c&l抱歉!&f但您没有足够的权限使用该指令。"
).build();
public static final ConfiguredMessageList<BaseComponent[]> NOT_ONLINE = list().defaults(
"&f目标玩家并不在线,无法发送请求。"
).build();
public static final ConfiguredMessageList<BaseComponent[]> NOT_PLAYER = list().defaults(
"&f该指令请以玩家身份执行。"
).build();
public static final ConfiguredMessageList<BaseComponent[]> NOT_ENABLED = list().defaults(
"&f该功能在次服务器中并未被启用。"
).build();
public static class USAGE extends ConfigurationRoot {
public static final ConfiguredMessageList<BaseComponent[]> COMMAND = list().defaults(
"&5&l喵喵传送 &f指令帮助",
"&8#&f teleport help",
"&8-&7 查看传送请求相关帮助。",
"&8#&f warp help",
"&8-&7 查看地标点相关帮助。",
"&8#&f home Help",
"&8-&7 查看家传送点的相关帮助。",
"&8#&f back",
"&8-&7 回到之前的传送位置。"
).build();
public static final ConfiguredMessageList<BaseComponent[]> TELEPORT = list().defaults(
"&5&l喵喵传送 &f传送指令帮助",
"&8#&f teleport to &d<目标玩家>",
"&8-&7 请求传送到目标玩家的位置。",
"&8#&f teleport here &d<目标玩家>",
"&8-&7 请求目标玩家传送到自己的位置。",
"&8#&f teleport accept &d[玩家]",
"&8-&7 同意一个传送请求(可具体指定玩家的请求)。",
"&8#&f teleport deny &d[玩家]",
"&8-&7 拒绝一个传送请求(可具体指定玩家的请求)。",
"&8#&f teleport cancel",
"&8-&7 取消已经发出的传送请求。"
).build();
public static final ConfiguredMessageList<BaseComponent[]> WARPS = list().defaults(
"&5&l喵喵传送 &f地标指令帮助",
"&8#&f warp list",
"&8-&7 列出当前所有的地标点。",
"&8#&f warp to &d<地标名>",
"&8-&7 传送到指定的地标点。",
"&8#&f warp set &d[地标名]",
"&8-&7 设定一个地标点。",
"&8-&7&o 若地标点已存在,且您是地标点的设立者,",
"&8-&7&o 则会覆盖原有的地标点位置。",
"&8#&f warp delete &d[地标名]",
"&8-&7 删除一个自己设立的地标点。",
"&8#&f warp rename &d<原地标名> &d<新地标名>",
"&8-&7 重命名一个自己设立的地标点。"
).build();
public static final ConfiguredMessageList<BaseComponent[]> HOMES = list().defaults(
"&5&l喵喵传送 &f家指令帮助",
"&8#&f home list",
"&8-&7 列出所有的家位置。",
"&8#&f home to &d[家名]",
"&8-&7 传送到指定的家。",
"&8-&7&o 若不填写具体的名称则返回首个设置的家,",
"&8-&7&o 若存在名为“home”的家则优先返回“home”。",
"&8#&f home set &d[家名]",
"&8-&7 设定一个家的位置。",
"&8-&7&o 若不填写家的名称则默认为“home”",
"&8#&f home delete &d[家名]",
"&8-&7 删除一个家的位置。",
"&8#&f home rename &d<原家名> &d<新家名>",
"&8-&7 重命名一个家传送点的名称。"
).build();
}
public static class RELOAD extends ConfigurationRoot {
public static final ConfiguredMessageList<BaseComponent[]> START = list().defaults(
"&f正在重载配置文件..."
).build();
public static final ConfiguredMessageList<BaseComponent[]> ERROR = list().defaults(
"&f配置文件&c重载失败!&f详细原因详见后台输出。"
).build();
public static final ConfiguredMessageList<BaseComponent[]> COMPLETE = list().defaults(
"&f配置文件重载完成,共耗时 &d%(time)&fms 。"
).params("time").build();
}
public static class BACK extends ConfigurationRoot {
public static final ConfiguredMessageList<BaseComponent[]> NO_LAST_LOCATION = list().defaults(
"&f您当前没有进行任何传送,无法返回上个地点。"
).build();
public static final ConfiguredMessageList<BaseComponent[]> DEATH_MESSAGE = list().defaults(
"&f您可以输入 &5/back &f或 [&d&l点击这里](show_text=点击返回到死亡地点 run_command=/moeteleport back) &f返回您的死亡地点。"
).build();
}
public static class TELEPORT extends ConfigurationRoot {
public static final ConfiguredMessageList<BaseComponent[]> TELEPORTED = list().defaults(
"&f正在将您传送到 &d%(target) &f..."
).params("target").build();
public static final ConfiguredMessageList<BaseComponent[]> NOT_SAFE = list().defaults(
"&f目标地点 &d%(location) &f可能并不安全,因此传送被暂缓执行。",
"&7如您确认传送到目标位置,请再次输入接受指令以执行本次传送。"
).params("location").build();
public static final ConfiguredMessageList<BaseComponent[]> NOT_AVAILABLE = list().defaults(
"&f目标地点丢失,暂时无法前往,传送被取消。"
).build();
public static final ConfiguredMessageList<BaseComponent[]> INTERRUPTED = list().defaults(
"&c&l传送中断!&f传送过程中请不要移动。"
).build();
}
public static class REQUESTS extends ConfigurationRoot {
public static final ConfiguredMessageList<BaseComponent[]> SELF = list().defaults("&f您不能向自己发送请求。").build();
public static final ConfiguredMessageList<BaseComponent[]> OFFLINE = list().defaults(
"&d%(player) &f离线,相关请求已自动取消。"
).params("player").build();
public static final ConfiguredMessageList<BaseComponent[]> MULTI = list().defaults(
"&f您当前有&d%(num)条请求&f待处理,请输入 &5/%(command) <玩家名> &f决定回应谁的请求。",
"&f您也可以再次输入 &5/%(command) &f快速回应最近的一条请求。"
).params("num", "command").build();
public static final ConfiguredMessageList<BaseComponent[]> EMPTY_REQUESTS = list()
.defaults("&f您当前没有任何待处理的传送请求。")
.build();
public static final ConfiguredMessageList<BaseComponent[]> NO_REQUEST_FROM = list().defaults(
"&f您当前没有收到来自 &d%(player) &f的传送请求。"
).params("player").build();
public static final ConfiguredMessageList<BaseComponent[]> SENT = list().defaults(
"&f成功向玩家 &d%(player) &f发送传送请求,对方有 &5%(expire)秒 &f的时间回应该请求。"
).params("player", "expire").build();
public static final ConfiguredMessageList<BaseComponent[]> DUPLICATE = list().defaults(
"&f您已经向 &d%(player) &f发送过传送请求,对方仍有 &5%(expire)秒 &f的时间回应该请求。",
"&f如您想要取消该请求,请输入 [&e&l[点击取消]](show_text=点击同意请求 run_command=/moeteleport teleport cancel %(player)) &f或输入 &5/tpCancel &f取消该请求。"
).params("player", "expire").build();
public static final ConfiguredMessageList<BaseComponent[]> RECEIVED_TP_HERE = list().defaults(
"&d%(player) &f请求传送到您身边,您有 &5%(expire)秒 &f的时间回应。",
" [&a&l[点击同意]](show_text=点击同意请求 run_command=/moeteleport teleport accept %(player)) &f或输入 &5/tpAccept &f同意该请求。",
" [&c&l[点击拒绝]](show_text=点击拒绝请求 run_command=/moeteleport teleport deny %(player)) &f或输入 &5/tpDeny &f拒绝该请求。"
).params("player", "expire").build();
public static final ConfiguredMessageList<BaseComponent[]> RECEIVED_TP_TO = list().defaults(
"&d%(player) &f请求传送您到Ta身边,您有 &5%(expire)秒 &f的时间回应。",
" [&a&l[点击同意]](show_text=点击同意请求 run_command=/moeteleport teleport accept %(player)) &f或输入 &5/tpAccept &f同意该请求。",
" [&c&l[点击拒绝]](show_text=点击拒绝请求 run_command=/moeteleport teleport deny %(player)) &f或输入 &5/tpDeny &f拒绝该请求。"
).params("player", "expire").build();
public static final ConfiguredMessageList<BaseComponent[]> ACCEPTED = list().defaults(
"&f您同意了 &d%(player) &f的传送请求。"
).params("player").build();
public static final ConfiguredMessageList<BaseComponent[]> DENIED = list().defaults(
"&f您&d拒绝&f了 &d%(player) &f的传送请求。"
).params("player").build();
public static final ConfiguredMessageList<BaseComponent[]> WAS_ACCEPTED = list().defaults(
"&d%(player) &f同意了您的传送请求。"
).params("player").build();
public static final ConfiguredMessageList<BaseComponent[]> WAS_DENIED = list().defaults(
"&d%(player) &f拒绝了您的传送请求。"
).params("player").build();
public static final ConfiguredMessageList<BaseComponent[]> SENT_TIMEOUT = list().defaults(
"&f发往 &d%(player) &f的传送请求已超时。"
).params("player").build();
public static final ConfiguredMessageList<BaseComponent[]> RECEIVED_TIMEOUT = list().defaults(
"&f来自 &d%(player) &f的传送请求已超时。"
).params("player").build();
public static final ConfiguredMessageList<BaseComponent[]> SENT_CANCELLED = list().defaults(
"&f发往 &d%(player) &f的传送请求已取消。"
).params("player").build();
public static final ConfiguredMessageList<BaseComponent[]> RECEIVED_CANCELLED = list().defaults(
"&f来自 &d%(player) &f的传送请求已被取消。"
).params("player").build();
}
public static class HOME extends ConfigurationRoot {
public static final ConfiguredMessageList<BaseComponent[]> EMPTY = list().defaults(
"&f您还没有设置任何家的位置,快设置一个吧!"
).build();
public static final ConfiguredMessageList<BaseComponent[]> NAME_TOO_LONG = list()
.defaults("&f您所输入的家的名字太长,家的名称不应当超过 &d32 &f个字符。")
.build();
public static final ConfiguredMessageList<BaseComponent[]> OVER_LIMIT = list().defaults(
"&f您最多只能设置 &d%(max) &f个家传送点!",
"&7可以输入 &5/delHome <家名称> &7删除之前的家传送点,",
"&7或输入 &5/setHome <家名称> &7覆盖之前的家传送点。"
).params("max").build();
public static final ConfiguredMessageList<BaseComponent[]> ALREADY_EXITS = list()
.defaults("&f您已存在名为 &d%(name) &f的家传送点,换个名字叭~")
.params("name")
.build();
public static final ConfiguredMessageList<BaseComponent[]> NOT_FOUND = list()
.defaults("&f您还没有设置这个家,请先输入 &5/setHome <家名称> &f设置一个吧!")
.build();
public static final ConfiguredMessageList<BaseComponent[]> SET = list().defaults(
"&f成功设定名为 &d%(name) &f的家传送点。"
).params("name").build();
public static final ConfiguredMessageList<BaseComponent[]> OVERRIDE = list().defaults(
"&f成功覆盖名为 &d%(name) &f的家传送点。",
"&8原先位置为 &5%(location) &8。"
).params("name", "location").build();
public static final ConfiguredMessageList<BaseComponent[]> REMOVED = list().defaults(
"&f成功移除名为 &d%(name) &f的家传送点。",
"&8原先位置为 &5%(location) &8。"
).params("name", "location").build();
public static final ConfiguredMessageList<BaseComponent[]> RENAMED = list().defaults(
"&f成功以 &d%(newName) 重命名原先的家传送点 &d&o%(oldName) &f。"
).params("newName", "oldName").build();
public static class LIST extends ConfigurationRoot {
public static final ConfiguredMessageList<BaseComponent[]> HEADER = list().defaults(
"&f您当前设定的所有家:"
).build();
public static final ConfiguredMessageList<BaseComponent[]> OBJECT = list().defaults(
"&8# &f%(id) &d%(location) [&7✈](show_text=点击返回家 %(id) run_command=/moeteleport home to %(id))"
).params("id", "location").build();
}
}
public static class WARP extends ConfigurationRoot {
public static final ConfiguredMessageList<BaseComponent[]> EMPTY = list().defaults(
"&f当前服务器暂无任何地标点,快设置一个吧!"
).build();
public static final ConfiguredMessageList<BaseComponent[]> NOT_OWNER = list().defaults(
"&f您不是地标 &d%(name) &f的创建者,无法进行此操作。"
).params("name").build();
public static final ConfiguredMessageList<BaseComponent[]> NOT_FOUND = list()
.defaults("&f目前暂不存在ID为 %(id) 的地标点。")
.params("id")
.build();
public static final ConfiguredMessageList<BaseComponent[]> NAME_TOO_LONG = list()
.defaults("&f您所输入的家的名字太长,地标的名称不应当超过 &d16 &f个字符。")
.build();
public static final ConfiguredMessageList<BaseComponent[]> OVER_LIMIT = list().defaults(
"&f您最多只能设置 &d%(max) &f个地标传送点!",
"&7可以输入 &5/delWarp <地标名称> &7删除之前的地标传送点,",
"&7或输入 &5/setWarp <地标名称> &7覆盖之前的地标传送点。"
).params("max").build();
public static final ConfiguredMessageList<BaseComponent[]> INFO_LOCATION = list().defaults(
"&f地标点 &d%(name) &f所在位置为 &5%(location) &f。[&7✈](show_text=点击前往&d %(name) run_command=/moeteleport warp to %(name))"
).params("name", "location").build();
public static final ConfiguredMessageList<BaseComponent[]> INFO_FULL = list().defaults(
"&f地标点 &d%(name) &f由 &5%(owner) &f创建,所在位置为 &d%(location) &f。[&7✈](show_text=点击前往&d %(name) run_command=/moeteleport warp to %(name))"
).params("name", "owner", "location").build();
public static final ConfiguredMessageList<BaseComponent[]> SET = list().defaults(
"&f成功设定名为 &d%(name) &f的地标传送点。"
).params("name").build();
public static final ConfiguredMessageList<BaseComponent[]> OVERRIDE = list().defaults(
"&f成功覆盖名为 &d%(name) &f的地标传送点。",
"&8原先位置为 &5%(location) &8。"
).params("name", "location").build();
public static final ConfiguredMessageList<BaseComponent[]> REMOVED = list().defaults(
"&f成功移除名为 &d%(name) &f的地标传送点。",
"&8原先位置为 &5%(location) &8。"
).params("name", "location").build();
public static final ConfiguredMessageList<BaseComponent[]> ALREADY_EXITS = list()
.defaults("&f已存在名为 &d%(name) &f的地标点,换个名字叭~")
.params("name")
.build();
public static final ConfiguredMessageList<BaseComponent[]> RENAMED = list().defaults(
"&f成功以 &d%(newName) 重命名原先的地标点 &d&o%(oldName) &f。"
).params("newName", "oldName").build();
public static class LIST extends ConfigurationRoot {
public static final ConfiguredMessageList<BaseComponent[]> HEADER = list().defaults(
"&f当前地标列表 &7(第&f%(current)&8/%(max)&7页)"
).params("current", "max").build();
public static final ConfiguredMessageList<BaseComponent[]> OBJECT = list().defaults(
"&8# &f%(id) &7[由%(owner)创建]",
"&8- &d%(location) [&7✈](show_text=点击前往&d %(id) run_command=/moeteleport warp to %(id))"
).params("id", "owner", "location").build();
public static final ConfiguredMessageList<BaseComponent[]> OBJECT_NO_OWNER = list().defaults(
"&8# &f%(id)",
"&8- &d%(location) [&7✈](show_text=点击前往&d %(id) run_command=/moeteleport warp to %(id))"
).params("id", "location").build();
}
}
}
@@ -1,4 +1,4 @@
package cc.carm.plugin.moeteleport.configuration.location; package cc.carm.plugin.moeteleport.conf.location;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -1,29 +0,0 @@
package cc.carm.plugin.moeteleport.configuration;
import cc.carm.plugin.moeteleport.configuration.values.ConfigValue;
import cc.carm.plugin.moeteleport.configuration.values.ConfigValueList;
import cc.carm.plugin.moeteleport.configuration.values.ConfigValueMap;
public class PluginConfig {
public static final ConfigValueMap<Integer, String> PERMISSIONS = new ConfigValueMap<>(
"permissions", Integer::parseInt, String.class
);
public static final ConfigValueList<String> DANGEROUS_TYPES = new ConfigValueList<>(
"dangerous-blocks", String.class, new String[]{"LAVA"}
);
public static final ConfigValue<Integer> EXPIRE_TIME = new ConfigValue<>(
"expireTime", Integer.class, 30
);
public static final ConfigValue<Integer> DEFAULT_HOME = new ConfigValue<>(
"defaultHome", Integer.class, 1
);
public static final ConfigValue<Boolean> DEATH_GO_BACK = new ConfigValue<>(
"death-back", Boolean.class, true
);
}
@@ -1,57 +0,0 @@
package cc.carm.plugin.moeteleport.configuration;
import cc.carm.plugin.moeteleport.configuration.message.ConfigMessage;
import cc.carm.plugin.moeteleport.configuration.message.ConfigMessageList;
public class PluginMessages {
public static final ConfigMessageList NO_LAST_LOCATION = new ConfigMessageList("no-last-location");
public static final ConfigMessageList NOT_ONLINE = new ConfigMessageList("not-online");
public static final ConfigMessageList TPA = new ConfigMessageList("tpa");
public static final ConfigMessageList TPA_HERE = new ConfigMessageList("tpahere");
public static final ConfigMessageList TP_ACCEPT = new ConfigMessageList("tpaccept");
public static final ConfigMessageList TP_DENY = new ConfigMessageList("tpdeny");
public static final ConfigMessageList ACCEPTED = new ConfigMessageList("accepted");
public static final ConfigMessageList DENIED = new ConfigMessageList("denied");
public static final ConfigMessageList TELEPORTING = new ConfigMessageList("teleporting");
public static final ConfigMessageList DANGEROUS = new ConfigMessageList("dangerous");
public static final ConfigMessageList DANGEROUS_HERE = new ConfigMessageList("dangerous-here");
public static final ConfigMessageList NOT_AVAILABLE = new ConfigMessageList("notAvailable");
public static final ConfigMessageList DEATH_BACK = new ConfigMessageList("death-back");
public static class Request {
public static final ConfigMessageList DUPLICATE = new ConfigMessageList("request-duplicate");
public static final ConfigMessageList OFFLINE = new ConfigMessageList("offline");
public static final ConfigMessageList SENT = new ConfigMessageList("request-sent");
public static final ConfigMessageList MULTI = new ConfigMessageList("multi-requests");
public static final ConfigMessageList SENT_TIMEOUT = new ConfigMessageList("request-sent-timeout");
public static final ConfigMessageList RECEIVED_TIMEOUT = new ConfigMessageList("request-received-timeout");
public static final ConfigMessageList NOT_FOUND = new ConfigMessageList("no-request");
public static final ConfigMessageList NOT_FOUND_PLAYER = new ConfigMessageList("no-request-player");
}
public static class Home {
public static final ConfigMessageList HEADER = new ConfigMessageList("home-list-header");
public static final ConfigMessage LIST_OBJECT = new ConfigMessage("home-list-object");
public static final ConfigMessageList OVER_LIMIT = new ConfigMessageList("home-over-limit");
public static final ConfigMessageList NOT_FOUND = new ConfigMessageList("home-not-found");
public static final ConfigMessageList SET = new ConfigMessageList("home-set");
public static final ConfigMessageList REMOVED = new ConfigMessageList("home-removed");
}
}
@@ -1,64 +0,0 @@
package cc.carm.plugin.moeteleport.configuration.file;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.IOException;
public class FileConfig {
private final JavaPlugin plugin;
private final String fileName;
private File file;
private FileConfiguration config;
public FileConfig(final JavaPlugin plugin) {
this(plugin, "config.yml");
}
public FileConfig(final JavaPlugin plugin, final String name) {
this.plugin = plugin;
this.fileName = name;
initFile();
}
private void initFile() {
this.file = new File(plugin.getDataFolder(), fileName);
if (!this.file.exists()) {
if (!this.file.getParentFile().exists()) {
boolean success = this.file.getParentFile().mkdirs();
}
plugin.saveResource(fileName, true);
}
this.config = YamlConfiguration.loadConfiguration(this.file);
}
public File getFile() {
return file;
}
public FileConfiguration getConfig() {
return config;
}
public void save() {
try {
getConfig().save(getFile());
} catch (IOException e) {
e.printStackTrace();
}
}
public void reload() {
if (getFile().exists()) {
this.config = YamlConfiguration.loadConfiguration(getFile());
} else {
initFile();
}
}
}
@@ -1,32 +0,0 @@
package cc.carm.plugin.moeteleport.configuration.message;
import cc.carm.plugin.moeteleport.configuration.values.ConfigValue;
import cc.carm.plugin.moeteleport.manager.ConfigManager;
import cc.carm.plugin.moeteleport.util.MessageUtil;
import org.bukkit.command.CommandSender;
import java.util.Collections;
public class ConfigMessage extends ConfigValue<String> {
public ConfigMessage(String configSection) {
this(configSection, null);
}
public ConfigMessage(String configSection, String defaultValue) {
super(ConfigManager.getMessageConfig(), configSection, String.class, defaultValue);
}
public void send(CommandSender sender) {
MessageUtil.send(sender, get());
}
public void sendWithPlaceholders(CommandSender sender) {
MessageUtil.sendWithPlaceholders(sender, get());
}
public void sendWithPlaceholders(CommandSender sender, String[] params, Object[] values) {
MessageUtil.sendWithPlaceholders(sender, Collections.singletonList(get()), params, values);
}
}
@@ -1,30 +0,0 @@
package cc.carm.plugin.moeteleport.configuration.message;
import cc.carm.plugin.moeteleport.configuration.values.ConfigValueList;
import cc.carm.plugin.moeteleport.manager.ConfigManager;
import cc.carm.plugin.moeteleport.util.MessageUtil;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.Nullable;
public class ConfigMessageList extends ConfigValueList<String> {
public ConfigMessageList(String configSection) {
super(ConfigManager.getMessageConfig(), configSection, String.class);
}
public ConfigMessageList(String configSection, String[] defaultValue) {
super(ConfigManager.getMessageConfig(), configSection, String.class, defaultValue);
}
public void send(@Nullable CommandSender sender) {
MessageUtil.send(sender, get());
}
public void sendWithPlaceholders(@Nullable CommandSender sender) {
MessageUtil.sendWithPlaceholders(sender, get());
}
public void sendWithPlaceholders(@Nullable CommandSender sender, String[] params, Object[] values) {
MessageUtil.sendWithPlaceholders(sender, get(), params, values);
}
}
@@ -1,58 +0,0 @@
package cc.carm.plugin.moeteleport.configuration.values;
import cc.carm.plugin.moeteleport.configuration.file.FileConfig;
import cc.carm.plugin.moeteleport.manager.ConfigManager;
import org.bukkit.configuration.file.FileConfiguration;
public class ConfigValue<V> {
FileConfig source;
String configSection;
Class<V> clazz;
V defaultValue;
public ConfigValue(String configSection, Class<V> clazz) {
this(configSection, clazz, null);
}
public ConfigValue(String configSection, Class<V> clazz, V defaultValue) {
this(ConfigManager.getPluginConfig(), configSection, clazz, defaultValue);
}
public ConfigValue(FileConfig source, String configSection, Class<V> clazz, V defaultValue) {
this.source = source;
this.configSection = configSection;
this.clazz = clazz;
this.defaultValue = defaultValue;
}
public FileConfiguration getConfiguration() {
return this.source.getConfig();
}
public V get() {
if (getConfiguration().contains(this.configSection)) {
Object val = getConfiguration().get(this.configSection, this.defaultValue);
return this.clazz.isInstance(val) ? this.clazz.cast(val) : this.defaultValue;
} else {
// 如果没有默认值,就把配置写进去,便于配置
return setDefault();
}
}
public void set(V value) {
getConfiguration().set(this.configSection, value);
this.save();
}
public void save() {
this.source.save();
}
public V setDefault() {
set(this.defaultValue);
return this.defaultValue;
}
}
@@ -1,71 +0,0 @@
package cc.carm.plugin.moeteleport.configuration.values;
import cc.carm.plugin.moeteleport.configuration.file.FileConfig;
import cc.carm.plugin.moeteleport.manager.ConfigManager;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ConfigValueList<V> {
FileConfig source;
String configSection;
Class<V> clazz;
V[] defaultValue;
public ConfigValueList(String configSection, Class<V> clazz) {
this(ConfigManager.getPluginConfig(), configSection, clazz);
}
public ConfigValueList(String configSection, Class<V> clazz, V[] defaultValue) {
this(ConfigManager.getPluginConfig(), configSection, clazz, defaultValue);
}
public ConfigValueList(FileConfig configuration, String configSection, Class<V> clazz) {
this(configuration, configSection, clazz, null);
}
public ConfigValueList(FileConfig configuration, String configSection, Class<V> clazz, V[] defaultValue) {
this.source = configuration;
this.configSection = configSection;
this.clazz = clazz;
this.defaultValue = defaultValue;
}
public FileConfiguration getConfiguration() {
return this.source.getConfig();
}
public ArrayList<V> get() {
List<?> list = getConfiguration().getList(this.configSection);
if (list == null) {
if (defaultValue != null) {
return new ArrayList<>(Arrays.asList(defaultValue));
} else {
return new ArrayList<>();
}
} else {
ArrayList<V> result = new ArrayList<>();
for (Object object : list) {
if (this.clazz.isInstance(object)) {
result.add(this.clazz.cast(object));
}
}
return result;
}
}
public void set(ArrayList<V> value) {
getConfiguration().set(this.configSection, value);
this.save();
}
public void save() {
this.source.save();
}
}
@@ -1,79 +0,0 @@
package cc.carm.plugin.moeteleport.configuration.values;
import cc.carm.plugin.moeteleport.configuration.file.FileConfig;
import cc.carm.plugin.moeteleport.manager.ConfigManager;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
public class ConfigValueMap<K, V> {
@NotNull FileConfig source;
@NotNull String configSection;
@NotNull Function<String, K> keyCast;
@NotNull Class<V> valueClazz;
@Nullable LinkedHashMap<K, V> valueCache;
public ConfigValueMap(@NotNull String configSection, @NotNull Function<String, K> keyCast,
@NotNull Class<V> valueClazz) {
this(ConfigManager.getPluginConfig(), configSection, keyCast, valueClazz);
}
public ConfigValueMap(@NotNull FileConfig configuration, @NotNull String configSection,
@NotNull Function<String, K> keyCast, @NotNull Class<V> valueClazz) {
this.source = configuration;
this.configSection = configSection;
this.keyCast = keyCast;
this.valueClazz = valueClazz;
}
public @NotNull FileConfiguration getConfiguration() {
return this.source.getConfig();
}
public void clearCache() {
this.valueCache = null;
}
@NotNull
public Map<K, V> get() {
if (valueCache != null) return valueCache;
ConfigurationSection section = getConfiguration().getConfigurationSection(this.configSection);
if (section == null) return new LinkedHashMap<>();
Set<String> keys = section.getKeys(false);
if (keys.isEmpty()) return new LinkedHashMap<>();
else {
LinkedHashMap<K, V> result = new LinkedHashMap<>();
for (String key : keys) {
K finalKey = keyCast.apply(key);
Object val = section.get(key);
V finalValue = this.valueClazz.isInstance(val) ? this.valueClazz.cast(val) : null;
if (finalKey != null && finalValue != null) {
result.put(finalKey, finalValue);
}
}
this.valueCache = result;
return result;
}
}
public void set(LinkedHashMap<K, V> valuesMap) {
this.valueCache = valuesMap;
getConfiguration().createSection(this.configSection, valuesMap);
this.save();
}
public void save() {
this.source.save();
}
}
@@ -0,0 +1,56 @@
package cc.carm.plugin.moeteleport.listener;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.teleport.TeleportQueue;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerToggleSneakEvent;
public class TeleportListener implements Listener {
@EventHandler
public void onMove(PlayerMoveEvent event) {
if (!PluginConfig.TELEPORTATION.INTERRUPT.MOVE.getNotNull()) return;
Location from = event.getFrom();
Location to = event.getTo();
if (to == null) return;
if (from.getBlockX() == to.getBlockX()
&& from.getBlockY() == to.getBlockY()
&& from.getBlockZ() == to.getBlockZ()) {
return;
}
TeleportQueue queue = MoeTeleport.getTeleportManager().getQueue(event.getPlayer());
if (queue == null) return;
MoeTeleport.getTeleportManager().interruptQueue(queue);
}
@EventHandler
public void onDamage(EntityDamageByEntityEvent event) {
if (!PluginConfig.TELEPORTATION.INTERRUPT.ATTACK.getNotNull()) return;
if (!(event.getEntity() instanceof Player)) return;
TeleportQueue queue = MoeTeleport.getTeleportManager().getQueue((Player) event.getEntity());
if (queue == null) return;
MoeTeleport.getTeleportManager().interruptQueue(queue);
}
@EventHandler
public void onSnake(PlayerToggleSneakEvent event) {
if (!PluginConfig.TELEPORTATION.INTERRUPT.SNAKE.getNotNull()) return;
TeleportQueue queue = MoeTeleport.getTeleportManager().getQueue(event.getPlayer());
if (queue == null) return;
MoeTeleport.getTeleportManager().interruptQueue(queue);
}
}
@@ -1,9 +1,8 @@
package cc.carm.plugin.moeteleport.listener; package cc.carm.plugin.moeteleport.listener;
import cc.carm.plugin.moeteleport.Main; import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.configuration.PluginConfig; import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.configuration.PluginMessages; import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.model.UserData;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@@ -11,31 +10,26 @@ import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import java.util.UUID;
public class UserListener implements Listener { public class UserListener implements Listener {
@EventHandler @EventHandler
public void onJoin(PlayerJoinEvent event) { public void onJoin(PlayerJoinEvent event) {
UUID uuid = event.getPlayer().getUniqueId(); MoeTeleport.getUserManager().loadData(event.getPlayer().getUniqueId());
UserData data = Main.getUserManager().loadData(uuid);
Main.getUserManager().getUserDataMap().put(uuid, data);
} }
@EventHandler @EventHandler
public void onQuit(PlayerQuitEvent event) { public void onQuit(PlayerQuitEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
Main.getRequestManager().cancelAllRequests(player); MoeTeleport.getRequestManager().cancelAllRequests(player);
Main.getUserManager().getData(player).save(); //保存 MoeTeleport.getUserManager().unloadData(player.getUniqueId());
Main.getUserManager().getUserDataMap().remove(player.getUniqueId());
} }
@EventHandler @EventHandler
public void onDeath(PlayerDeathEvent event) { public void onDeath(PlayerDeathEvent event) {
if (PluginConfig.DEATH_GO_BACK.get()) { if (PluginConfig.BACK.DEATH.getNotNull()) {
Player player = event.getEntity(); Player player = event.getEntity();
Main.getUserManager().getData(player).setLastLocation(player.getLocation()); MoeTeleport.getUserManager().getData(player).setLastLocation(player.getLocation());
PluginMessages.DEATH_BACK.send(player); PluginMessages.BACK.DEATH_MESSAGE.send(player);
} }
} }
@@ -1,37 +0,0 @@
package cc.carm.plugin.moeteleport.manager;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginConfig;
import cc.carm.plugin.moeteleport.configuration.file.FileConfig;
public class ConfigManager {
private static FileConfig config;
private static FileConfig messageConfig;
public static void initConfig() {
ConfigManager.config = new FileConfig(Main.getInstance(), "config.yml");
ConfigManager.messageConfig = new FileConfig(Main.getInstance(), "messages.yml");
}
public static FileConfig getPluginConfig() {
return config;
}
public static FileConfig getMessageConfig() {
return messageConfig;
}
public static void reload() {
getPluginConfig().reload();
getMessageConfig().reload();
PluginConfig.PERMISSIONS.clearCache();
}
public static void saveConfig() {
getPluginConfig().save();
getMessageConfig().save();
}
}
@@ -1,140 +1,138 @@
package cc.carm.plugin.moeteleport.manager; package cc.carm.plugin.moeteleport.manager;
import cc.carm.plugin.moeteleport.Main; import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginConfig; import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.configuration.PluginMessages; import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.model.TeleportRequest; import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.model.UserData; import cc.carm.plugin.moeteleport.teleport.TeleportRequest;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Objects; import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class RequestManager { public class RequestManager {
public BukkitRunnable checkRunnable; protected final Map<UUID, TeleportRequest> requests = new ConcurrentHashMap<>();
protected BukkitRunnable runnable;
public RequestManager(Main main) { public RequestManager(Main main) {
this.checkRunnable = new BukkitRunnable() { this.runnable = new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
checkRequests(); tickRequests();
} }
}; };
this.checkRunnable.runTaskTimerAsynchronously(main, 100L, 20L); this.runnable.runTaskTimerAsynchronously(main, 100L, 20L);
} }
public void shutdown() { public void shutdown() {
if (!this.checkRunnable.isCancelled()) { if (!this.runnable.isCancelled()) {
this.checkRunnable.cancel(); this.runnable.cancel();
} }
} }
public void checkRequests() { @Unmodifiable
Main.getUserManager().getUserDataMap().values() public Map<UUID, TeleportRequest> getRequests() {
.forEach(data -> data.getReceivedRequests().entrySet().stream() return Collections.unmodifiableMap(requests);
.filter(entry -> entry.getValue().isExpired())
.peek(entry -> PluginMessages.Request.SENT_TIMEOUT.sendWithPlaceholders(
entry.getValue().getSender(), new String[]{"%(player)"},
new Object[]{entry.getValue().getReceiver().getName()}))
.peek(entry -> PluginMessages.Request.RECEIVED_TIMEOUT.sendWithPlaceholders(
entry.getValue().getReceiver(), new String[]{"%(player)"},
new Object[]{entry.getValue().getSender().getName()}))
.peek(entry -> Main.getUserManager()
.getData(entry.getValue().getSender()).getSentRequests()
.remove(entry.getKey()))
.forEach(entry -> data.getReceivedRequests().remove(entry.getKey()))
);
} }
public void sendRequest(Player sender, Player receiver, TeleportRequest.RequestType type) { public @Nullable TeleportRequest getRequest(UUID senderUUID) {
int expireTime = PluginConfig.EXPIRE_TIME.get(); return requests.get(senderUUID);
}
PluginMessages.Request.SENT.sendWithPlaceholders(sender, @Unmodifiable
new String[]{"%(player)", "%(expire)"}, public @NotNull Map<UUID, TeleportRequest> getUserReceivedRequests(@NotNull UUID receiverUUID) {
new Object[]{receiver.getName(), expireTime} return requests.values().stream()
); .filter(request -> request.getReceiver().getUniqueId().equals(receiverUUID))
.collect(Collectors.toMap(request -> request.getSender().getUniqueId(), request -> request));
}
public void tickRequests() {
Iterator<Map.Entry<UUID, TeleportRequest>> requestIterator = requests.entrySet().iterator();
while (requestIterator.hasNext()) {
Map.Entry<UUID, TeleportRequest> entry = requestIterator.next();
TeleportRequest request = entry.getValue();
if (!request.isExpired()) continue;
requestIterator.remove(); // 移除过期的请求
// 发送提示
PluginMessages.REQUESTS.SENT_TIMEOUT.send(request.getSender(), request.getReceiver().getName());
PluginMessages.REQUESTS.RECEIVED_TIMEOUT.send(request.getReceiver(), request.getSender().getName());
}
}
public void sendRequest(Player sender, Player receiver, TeleportRequest.Type type) {
int expireTime = PluginConfig.REQUEST.EXPIRE_TIME.getNotNull();
PluginConfig.REQUEST.SOUND.SENT.playTo(sender);
PluginConfig.REQUEST.SOUND.RECEIVED.playTo(receiver);
PluginMessages.REQUESTS.SENT.send(sender, receiver.getName(), expireTime);
switch (type) { switch (type) {
case TPA: { case TPA_TO: {
PluginMessages.TPA.sendWithPlaceholders(receiver, PluginMessages.REQUESTS.RECEIVED_TP_HERE.send(receiver, sender.getName(), expireTime);
new String[]{"%(player)", "%(expire)"},
new Object[]{sender.getName(), expireTime}
);
break; break;
} }
case TPA_HERE: { case TPA_HERE: {
PluginMessages.TPA_HERE.sendWithPlaceholders(receiver, PluginMessages.REQUESTS.RECEIVED_TP_TO.send(receiver, sender.getName(), expireTime);
new String[]{"%(player)", "%(expire)"},
new Object[]{sender.getName(), expireTime}
);
break; break;
} }
} }
TeleportRequest request = new TeleportRequest(sender, receiver, type); requests.put(sender.getUniqueId(), new TeleportRequest(type, sender, receiver));
Main.getUserManager().getData(receiver).getReceivedRequests().put(sender.getUniqueId(), request);
Main.getUserManager().getData(sender).getSentRequests().add(receiver.getUniqueId());
} }
public void acceptRequest(TeleportRequest request) { public void acceptRequest(TeleportRequest request) {
PluginMessages.ACCEPTED.sendWithPlaceholders(request.getSender(), PluginMessages.REQUESTS.WAS_ACCEPTED.send(request.getSender(), request.getReceiver().getName());
new String[]{"%(player)"}, PluginMessages.REQUESTS.ACCEPTED.send(request.getReceiver(), request.getSender().getName());
new Object[]{request.getReceiver().getName()}
); removeRequests(request);
PluginMessages.TP_ACCEPT.sendWithPlaceholders(request.getReceiver(), MoeTeleport.getTeleportManager().queueTeleport(request.createQueue(
new String[]{"%(player)"}, Duration.of(PluginConfig.TELEPORTATION.WAIT_TIME.getNotNull(), ChronoUnit.SECONDS)
new Object[]{request.getSender().getName()} ));
); }
TeleportManager.teleport(request.getTeleportPlayer(), request.getTeleportLocation(), true);
public void cancelRequest(TeleportRequest request) {
PluginMessages.REQUESTS.SENT_CANCELLED.send(request.getSender(), request.getReceiver().getName());
PluginMessages.REQUESTS.RECEIVED_CANCELLED.send(request.getReceiver(), request.getSender().getName());
PluginConfig.REQUEST.SOUND.CANCELLED.playTo(request.getSender());
PluginConfig.REQUEST.SOUND.CANCELLED.playTo(request.getReceiver());
removeRequests(request); removeRequests(request);
} }
public void denyRequest(TeleportRequest request) { public void denyRequest(TeleportRequest request) {
PluginMessages.DENIED.sendWithPlaceholders(request.getSender(), PluginMessages.REQUESTS.WAS_DENIED.send(request.getSender(), request.getReceiver().getName());
new String[]{"%(player)"}, PluginMessages.REQUESTS.DENIED.send(request.getReceiver(), request.getSender().getName());
new Object[]{request.getReceiver().getName()}
);
PluginMessages.TP_DENY.sendWithPlaceholders(request.getReceiver(),
new String[]{"%(player)"},
new Object[]{request.getSender().getName()}
);
removeRequests(request); removeRequests(request);
} }
public void removeRequests(TeleportRequest request) { public void removeRequests(TeleportRequest request) {
Main.getUserManager().getData(request.getSender()) this.requests.remove(request.getSender().getUniqueId());
.getSentRequests()
.remove(request.getReceiver().getUniqueId());
Main.getUserManager().getData(request.getReceiver())
.getReceivedRequests()
.remove(request.getSender().getUniqueId());
} }
public void cancelAllRequests(Player player) { public void cancelAllRequests(Player player) {
UUID playerUUID = player.getUniqueId(); UUID playerUUID = player.getUniqueId();
UserData data = Main.getUserManager().getData(player);
data.getReceivedRequests().keySet().stream()
.peek(senderUUID -> PluginMessages.Request.OFFLINE.sendWithPlaceholders(
Bukkit.getPlayer(senderUUID),
new String[]{"%(player)"}, new Object[]{player.getName()}
)).map(senderUUID -> Main.getUserManager().getData(senderUUID))
.filter(Objects::nonNull).map(UserData::getSentRequests)
.forEach(receivers -> receivers.remove(playerUUID));
data.getSentRequests().stream() TeleportRequest sent = requests.remove(playerUUID);
.peek(receiverUUID -> PluginMessages.Request.OFFLINE.sendWithPlaceholders( if (sent != null) {
Bukkit.getPlayer(receiverUUID), PluginMessages.REQUESTS.OFFLINE.send(sent.getReceiver(), player.getName());
new String[]{"%(player)"}, new Object[]{player.getName()} }
)).map(receiverUUID -> Main.getUserManager().getData(receiverUUID))
.filter(Objects::nonNull).map(UserData::getReceivedRequests)
.forEach(senders -> senders.remove(playerUUID));
data.getSentRequests().clear(); for (TeleportRequest received : getUserReceivedRequests(playerUUID).values()) {
data.getReceivedRequests().clear(); PluginMessages.REQUESTS.OFFLINE.send(received.getSender(), player.getName());
removeRequests(received);
}
} }
} }
@@ -1,60 +1,151 @@
package cc.carm.plugin.moeteleport.manager; package cc.carm.plugin.moeteleport.manager;
import cc.carm.plugin.moeteleport.Main; import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginConfig; import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.configuration.PluginMessages; import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation; import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.teleport.TeleportQueue;
import cc.carm.plugin.moeteleport.teleport.TeleportRequest;
import cc.carm.plugin.moeteleport.teleport.target.TeleportLocationTarget;
import cc.carm.plugin.moeteleport.teleport.target.TeleportTarget;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.particle.ParticleBuilder;
import xyz.xenondevs.particle.ParticleEffect;
import xyz.xenondevs.particle.data.texture.ItemTexture;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class TeleportManager { public class TeleportManager {
public static void teleport(Player player, DataLocation targetLocation, boolean onlySafety) { protected final Map<UUID, TeleportQueue> teleportQueue = new ConcurrentHashMap<>();
Location location = targetLocation.getBukkitLocation(); protected BukkitRunnable runnable;
public TeleportManager(Main main) {
this.runnable = new BukkitRunnable() {
@Override
public void run() {
tickQueue();
}
};
this.runnable.runTaskTimerAsynchronously(main, 20L, 20L);
}
public void shutdown() {
if (!this.runnable.isCancelled()) {
this.runnable.cancel();
}
}
public void tickQueue() {
boolean enableEffect = PluginConfig.TELEPORTATION.EFFECTS.getNotNull();
Iterator<Map.Entry<UUID, TeleportQueue>> queueIterator = teleportQueue.entrySet().iterator();
while (queueIterator.hasNext()) {
Map.Entry<UUID, TeleportQueue> entry = queueIterator.next();
TeleportQueue queue = entry.getValue();
if (!queue.checkTime()) {
PluginConfig.TELEPORTATION.SOUND.CHANNELING.playTo(queue.getPlayer());
PluginConfig.TELEPORTATION.TITLE.CHANNELING.send(
queue.getPlayer(),
queue.getRemainSeconds() + 1, queue.getTarget().getText()
);
if (enableEffect) {
new ParticleBuilder(ParticleEffect.PORTAL, queue.getPlayer().getLocation())
.setAmount(100).setOffsetY(1F).display();
}
continue;
}
queueIterator.remove();
executeTeleport(queue);
}
}
public void interruptQueue(TeleportQueue queue) {
teleportQueue.remove(queue.getPlayer().getUniqueId());
PluginMessages.TELEPORT.INTERRUPTED.send(queue.getPlayer());
PluginConfig.TELEPORTATION.SOUND.INTERRUPTED.playTo(queue.getPlayer());
}
public TeleportQueue getQueue(UUID uuid) {
return teleportQueue.get(uuid);
}
public TeleportQueue getQueue(Player player) {
return getQueue(player.getUniqueId());
}
public boolean isChanneling(UUID uuid) {
return teleportQueue.containsKey(uuid);
}
public boolean isChanneling(Player player) {
return isChanneling(player.getUniqueId());
}
public @Nullable Duration getDelayDuration() {
return Duration.of(PluginConfig.TELEPORTATION.WAIT_TIME.getNotNull(), ChronoUnit.SECONDS);
}
public void queueTeleport(@Nullable TeleportQueue queue) {
if (queue == null) return;
if (queue.checkTime()) { // 直接满足传送条件
executeTeleport(queue);
return;
}
teleportQueue.put(queue.getPlayer().getUniqueId(), queue);
}
public void queueTeleport(TeleportRequest request) {
queueTeleport(request.createQueue(getDelayDuration()));
}
public void queueTeleport(Player player, TeleportTarget target) {
queueTeleport(new TeleportQueue(player, target, getDelayDuration()));
}
public void queueTeleport(Player player, DataLocation target) {
queueTeleport(player, new TeleportLocationTarget(target));
}
public void queueTeleport(Player player, Location target) {
queueTeleport(player, new TeleportLocationTarget(target));
}
protected void executeTeleport(TeleportQueue queue) {
Player player = queue.getPlayer();
queue.getUser().setLastLocation(player.getLocation());
Location location = queue.getTarget().prepare();
if (location == null) { if (location == null) {
PluginMessages.NOT_AVAILABLE.sendWithPlaceholders(player, PluginMessages.TELEPORT.NOT_AVAILABLE.send(player, queue.getTarget().getText());
new String[]{"%(location)"}, PluginConfig.TELEPORTATION.SOUND.FAILED.playTo(player);
new Object[]{targetLocation.toFlatString()}
);
} else { } else {
teleport(player, location, onlySafety); PluginMessages.TELEPORT.TELEPORTED.send(player, queue.getTarget().getText());
} PluginConfig.TELEPORTATION.TITLE.TELEPORTED.send(player, queue.getTarget().getText());
} Main.getInstance().getScheduler().run(() -> {
player.teleport(location);
public static void teleport(Player player, Location targetLocation, boolean onlySafety) { PluginConfig.TELEPORTATION.SOUND.TELEPORTED.playTo(player);
if (targetLocation.isWorldLoaded()) { });
if (!onlySafety || TeleportManager.isSafeLocation(targetLocation)) {
Main.getUserManager().getData(player).setLastLocation(player.getLocation());
player.teleport(targetLocation);
PluginMessages.TELEPORTING.sendWithPlaceholders(player,
new String[]{"%(location)"},
new Object[]{new DataLocation(targetLocation).toFlatString()}
);
} else {
PluginMessages.DANGEROUS.send(player);
}
} else {
PluginMessages.NOT_AVAILABLE.sendWithPlaceholders(player,
new String[]{"%(location)"},
new Object[]{new DataLocation(targetLocation).toFlatString()}
);
}
}
public static boolean isSafeLocation(Location location) {
Block leg = location.getBlock();
if (!leg.getType().isAir()) {
return false; // not transparent (will suffocate)
}
Block head = leg.getRelative(BlockFace.UP);
if (!head.getType().isAir()) {
return false; // not transparent (will suffocate)
}
Block ground = leg.getRelative(BlockFace.DOWN);
return !PluginConfig.DANGEROUS_TYPES.get().contains(ground.getType().name());
}
if (PluginConfig.TELEPORTATION.EFFECTS.getNotNull()) {
new ParticleBuilder(ParticleEffect.ITEM_CRACK, location)
.setParticleData(new ItemTexture(new ItemStack(Material.ENDER_EYE)))
.setAmount(1).setOffsetY(1F).display();
}
}
}
} }
@@ -1,33 +1,117 @@
package cc.carm.plugin.moeteleport.manager; package cc.carm.plugin.moeteleport.manager;
import cc.carm.plugin.moeteleport.Main; import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginConfig; import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.model.UserData; import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import cc.carm.plugin.moeteleport.storage.DataStorage;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.util.DataTaskRunner;
import com.google.common.collect.ImmutableMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public class UserManager { public class UserManager {
private final File dataFolder; private final HashMap<UUID, UserData> userDataMap;
private final HashMap<UUID, UserData> userDataMap = new HashMap<>(); public UserManager() {
this.userDataMap = new HashMap<>();
public UserManager(Main main) {
this.dataFolder = new File(main.getDataFolder() + "/data");
if (!dataFolder.isDirectory() || !dataFolder.exists()) {
boolean success = dataFolder.mkdir();
} }
private static int getMaxValue(Player player, Map<Integer, String> permissions, int defaultValue) {
int current = defaultValue;
for (Map.Entry<Integer, String> entry : permissions.entrySet()) {
if (entry.getKey() > current && player.hasPermission(entry.getValue())) {
current = entry.getKey();
}
}
return current;
} }
@NotNull @NotNull
public UserData loadData(UUID userUUID) { public UserData readData(UUID userUUID) {
return new UserData(getDataFolder(), userUUID); try {
long start = System.currentTimeMillis();
DataStorage storage = MoeTeleport.getStorage();
Main.debugging("正通过 " + storage.getClass().getSimpleName() + " 读取 " + userUUID + " 的用户数据...(" + System.currentTimeMillis() + ")");
UserData data = storage.loadData(userUUID);
if (data == null) {
Main.debugging("当前还不存在玩家 " + userUUID + " 的数据,视作新档。");
return new UserData(userUUID);
}
Main.debugging("通过 " + storage.getClass().getSimpleName() + "读取 " + userUUID + " 的用户数据完成,"
+ "耗时 " + (System.currentTimeMillis() - start) + "ms。");
return data;
} catch (Exception e) {
Main.severe("无法正常读取玩家数据,玩家操作将不会被保存,请检查数据配置!");
Main.severe("Could not load user's data, please check the data configuration!");
e.printStackTrace();
return new UserData(userUUID);
}
}
public void saveData(UserData data) {
try {
long start = System.currentTimeMillis();
DataStorage storage = MoeTeleport.getStorage();
Main.debugging("正通过 " + storage.getClass().getSimpleName() + " 保存 " + data.getUserUUID() + " 的用户数据...(" + System.currentTimeMillis() + ")");
storage.saveUserData(data);
Main.debugging("通过 " + storage.getClass().getSimpleName() + " 保存 " + data.getUserUUID() + " 的用户数据完成," +
"耗时 " + (System.currentTimeMillis() - start) + "ms。");
} catch (Exception e) {
Main.severe("无法正常保存玩家数据,请检查数据配置!");
Main.severe("Could not save user's data, please check the data configuration!");
e.printStackTrace();
}
}
public void loadData(UUID userUUID) {
getUserDataMap().put(userUUID, readData(userUUID));
}
public void unloadData(UUID userUUID) {
unloadData(userUUID, true);
}
public void unloadData(UUID userUUID, boolean save) {
UserData data = getData(userUUID);
if (data == null) return;
if (save) saveData(data);
getUserDataMap().remove(userUUID);
}
public void loadAll() {
for (Player player : Bukkit.getOnlinePlayers()) {
if (getUserDataMap().containsKey(player.getUniqueId())) continue;
loadData(player.getUniqueId());
}
}
public void saveAll() {
getUserDataMap().values().forEach(this::saveData);
}
public void unloadAll(boolean save) {
if (save) saveAll();
getUserDataMap().clear();
} }
@Nullable @Nullable
@@ -40,25 +124,43 @@ public class UserManager {
return getUserDataMap().get(player.getUniqueId()); return getUserDataMap().get(player.getUniqueId());
} }
public long countUserWarps(UUID userUUID) {
return MoeTeleport.getWarpManager().listWarps().values().stream()
.map(WarpInfo::getOwner).filter(Objects::nonNull)
.filter(ownerUUID -> ownerUUID.equals(userUUID))
.count();
}
public int getMaxHome(Player player) { public int getMaxHome(Player player) {
Map<Integer, String> permissions = PluginConfig.PERMISSIONS.get(); return getMaxValue(player, PluginConfig.HOMES.PERMISSIONS.getNotNull(), PluginConfig.HOMES.DEFAULTS.getNotNull());
int current = PluginConfig.DEFAULT_HOME.get();
for (Map.Entry<Integer, String> entry : permissions.entrySet()) {
if (entry.getKey() > current && player.hasPermission(
Main.getInstance().getName() + "." + entry.getValue()
)) {
current = entry.getKey();
}
}
return current;
} }
public HashMap<UUID, UserData> getUserDataMap() { public int getMaxWarps(Player player) {
return getMaxValue(player, PluginConfig.WARPS.PERMISSIONS.getNotNull(), PluginConfig.WARPS.DEFAULTS.getNotNull());
}
public void editData(@NotNull DataTaskRunner task) {
try {
task.run(MoeTeleport.getStorage());
} catch (Exception exception) {
Main.severe("无法正常更改玩家数据,请检查数据配置!");
Main.severe("Could not edit user's data, please check the data configuration!");
exception.printStackTrace();
}
}
public void editDataAsync(@NotNull DataTaskRunner task) {
Main.getInstance().getScheduler().runAsync(() -> editData(task));
}
@NotNull
@Unmodifiable
public Map<UUID, UserData> listUserData() {
return ImmutableMap.copyOf(getUserDataMap());
}
protected @NotNull HashMap<UUID, UserData> getUserDataMap() {
return userDataMap; return userDataMap;
} }
public File getDataFolder() {
return dataFolder;
}
} }
@@ -0,0 +1,86 @@
package cc.carm.plugin.moeteleport.manager;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import com.google.common.collect.ImmutableMap;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Map;
import java.util.UUID;
public class WarpManager {
public void saveWarps() {
try {
MoeTeleport.getStorage().saveWarps();
} catch (Exception exception) {
Main.severe("保存地标数据失败,请检查配置文件。");
exception.printStackTrace();
}
}
public void setWarp(@NotNull String name, @Nullable UUID owner, @NotNull Location location) {
setWarp(name, owner, new DataLocation(location));
}
public void setWarp(@NotNull String name, @Nullable UUID owner, @NotNull DataLocation location) {
try {
MoeTeleport.getStorage().setWarp(name, new WarpInfo(name,owner, location));
} catch (Exception exception) {
Main.severe("保存地标数据 " + name + " 失败,请检查配置文件。");
exception.printStackTrace();
}
}
public void setWarpAsync(@NotNull String name, @Nullable UUID owner, @NotNull Location location) {
Main.getInstance().getScheduler().runAsync(() -> setWarp(name, owner, location));
}
public void setWarpAsync(@NotNull String name, @Nullable UUID owner, @NotNull DataLocation location) {
Main.getInstance().getScheduler().runAsync(() -> setWarp(name, owner, location));
}
public void delWarp(@NotNull String name) {
try {
MoeTeleport.getStorage().delWarp(name);
} catch (Exception exception) {
Main.severe("删除地标数据 " + name + " 失败,请检查配置文件。");
exception.printStackTrace();
}
}
public void delWarpAsync(@NotNull String name) {
Main.getInstance().getScheduler().runAsync(() -> delWarp(name));
}
public WarpInfo getWarp(@NotNull String name) {
return listWarps().entrySet().stream()
.filter(entry -> entry.getKey().equalsIgnoreCase(name))
.map(Map.Entry::getValue)
.findFirst().orElse(null);
}
public boolean hasWarp(@NotNull String name) {
return MoeTeleport.getStorage().hasWarp(name);
}
@NotNull
@Unmodifiable
public Map<String, WarpInfo> listWarps() {
return ImmutableMap.copyOf(getWarpsMap());
}
@NotNull
protected Map<String, WarpInfo> getWarpsMap() {
return MoeTeleport.getStorage().getWarps();
}
}
@@ -1,71 +0,0 @@
package cc.carm.plugin.moeteleport.model;
import cc.carm.plugin.moeteleport.configuration.PluginConfig;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class TeleportRequest {
final @NotNull Player sender;
final @NotNull Player receiver;
final @NotNull RequestType type;
final long createTime;
public TeleportRequest(@NotNull Player sender,
@NotNull Player receiver,
@NotNull RequestType type) {
this.sender = sender;
this.receiver = receiver;
this.type = type;
this.createTime = System.currentTimeMillis();
}
public @NotNull Player getSender() {
return sender;
}
public @NotNull Player getReceiver() {
return receiver;
}
public @NotNull Player getTeleportPlayer() {
return getType() == RequestType.TPA ? getSender() : getReceiver();
}
public @NotNull Location getTeleportLocation() {
return getType() == RequestType.TPA_HERE ? getSender().getLocation() : getReceiver().getLocation();
}
public @NotNull RequestType getType() {
return type;
}
public long getCreateTime() {
return createTime;
}
public long getActiveTime() {
return System.currentTimeMillis() - getCreateTime();
}
public long getRemainTime() {
return PluginConfig.EXPIRE_TIME.get() * 1000 - getActiveTime();
}
public long getRemainSeconds() {
return getRemainTime() / 1000;
}
public boolean isExpired() {
return getActiveTime() > PluginConfig.EXPIRE_TIME.get() * 1000;
}
public enum RequestType {
TPA,
TPA_HERE
}
}
@@ -1,132 +0,0 @@
package cc.carm.plugin.moeteleport.model;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class UserData {
private final @NotNull File dataFile;
private final @NotNull FileConfiguration dataConfig;
private final HashSet<UUID/*receiverUUID*/> sentRequests = new HashSet<>(); // 记录发出的请求
private final ConcurrentHashMap<UUID/*senderUUID*/, TeleportRequest> receivedRequests = new ConcurrentHashMap<>(); // 记录收到的传送请求
public boolean enableAutoSelect = false;
private @Nullable Location lastLocation;
private LinkedHashMap<String, DataLocation> homeLocations;
public UserData(@NotNull File dataFolder, @NotNull UUID uuid) {
this(new File(dataFolder, uuid + ".yml"));
}
public UserData(@NotNull File file) {
if (!file.exists()) {
try {
boolean success = file.createNewFile();
} catch (IOException e) {
Main.error("在加载用户 " + file.getName() + " 的数据时出现异常。");
Main.error(e.getLocalizedMessage());
}
}
this.dataFile = file;
this.dataConfig = YamlConfiguration.loadConfiguration(dataFile);
loadHomeData();
}
public void loadHomeData() {
LinkedHashMap<String, DataLocation> data = new LinkedHashMap<>();
Optional.ofNullable(getDataConfig().getConfigurationSection("homes"))
.ifPresent(section -> section.getKeys(false).forEach(homeName -> {
DataLocation location = DataLocation.deserializeText(section.getString(homeName));
if (location != null) data.put(homeName, location);
}));
this.homeLocations = data;
}
public LinkedHashMap<String, DataLocation> getHomeLocations() {
return homeLocations;
}
public void setHomeLocation(String homeName, Location location) {
delHomeLocation(homeName);
getHomeLocations().put(homeName, new DataLocation(location));
}
public void delHomeLocation(String homeName) {
Map.Entry<String, DataLocation> lastLocation = getHomeLocation(homeName);
if (lastLocation != null) getHomeLocations().remove(lastLocation.getKey());
}
public Map.Entry<String, DataLocation> getHomeLocation(@Nullable String homeName) {
LinkedHashMap<String, DataLocation> homes = getHomeLocations();
if (homeName == null) {
if (homes.containsKey("home")) {
return new AbstractMap.SimpleEntry<>("home", homes.get("home"));
} else {
return homes.entrySet().stream().findFirst().orElse(null);
}
} else {
return homes.entrySet().stream()
.filter(entry -> entry.getKey().equalsIgnoreCase(homeName))
.findFirst().orElse(null);
}
}
public @Nullable Location getLastLocation() {
return lastLocation;
}
public void setLastLocation(@Nullable Location lastLocation) {
this.lastLocation = lastLocation;
}
public HashSet<UUID> getSentRequests() {
return sentRequests;
}
public ConcurrentHashMap<UUID, TeleportRequest> getReceivedRequests() {
return receivedRequests;
}
public boolean isEnableAutoSelect() {
return enableAutoSelect;
}
public void setEnableAutoSelect(boolean enableAutoSelect) {
this.enableAutoSelect = enableAutoSelect;
}
public @NotNull File getDataFile() {
return dataFile;
}
public @NotNull FileConfiguration getDataConfig() {
return dataConfig;
}
public LinkedHashMap<String, String> saveToMap() {
LinkedHashMap<String, DataLocation> homeLocations = getHomeLocations();
LinkedHashMap<String, String> data = new LinkedHashMap<>();
if (homeLocations.isEmpty()) return data;
homeLocations.forEach((name, loc) -> data.put(name, loc.serializeToText()));
return data;
}
public void save() {
try {
getDataConfig().createSection("homes", saveToMap());
getDataConfig().save(getDataFile());
} catch (Exception ex) {
Main.error("在保存 " + getDataFile().getName() + " 时出现异常。");
Main.error(ex.getLocalizedMessage());
}
}
}
@@ -0,0 +1,47 @@
package cc.carm.plugin.moeteleport.model;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class WarpInfo {
private final @NotNull String name;
private final @Nullable UUID owner;
private final @NotNull DataLocation location;
public WarpInfo(@NotNull String name, @Nullable UUID owner, @NotNull DataLocation location) {
this.name = name;
this.owner = owner;
this.location = location;
}
public @NotNull String getName() {
return name;
}
public @Nullable UUID getOwner() {
return owner;
}
public @Nullable String getOwnerName() {
if (getOwner() != null) {
OfflinePlayer offline = Bukkit.getOfflinePlayer(getOwner());
if (offline.getName() != null) {
return offline.getName();
}
}
return null;
}
public @NotNull DataLocation getLocation() {
return location;
}
}
@@ -0,0 +1,42 @@
package cc.carm.plugin.moeteleport.storage;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.bukkit.Location;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
public class DataSerializer {
public static Map<String, String> serializeLocationsMap(LinkedHashMap<String, DataLocation> data) {
LinkedHashMap<String, String> after = new LinkedHashMap<>();
if (data == null || data.isEmpty()) return after;
data.forEach((name, loc) -> after.put(name, loc.serializeToText()));
return after;
}
public static @Nullable String serializeLocation(@Nullable DataLocation loc) {
return Optional.ofNullable(loc).map(DataLocation::serializeToText).orElse(null);
}
public static @Nullable String serializeLocation(@Nullable Location loc) {
return serializeLocation(Optional.ofNullable(loc).map(DataLocation::new).orElse(null));
}
public static Map<String, Object> serializeWarpMap(WarpInfo info) {
LinkedHashMap<String, Object> after = new LinkedHashMap<>();
if (info.getOwner() != null) after.put("owner", info.getOwner().toString());
after.put("world", info.getLocation().getWorldName());
after.put("x", info.getLocation().getX());
after.put("y", info.getLocation().getY());
after.put("z", info.getLocation().getZ());
after.put("yaw", info.getLocation().getYaw());
after.put("pitch", info.getLocation().getPitch());
return after;
}
}
@@ -0,0 +1,85 @@
package cc.carm.plugin.moeteleport.storage;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.manager.UserManager;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.UUID;
public interface DataStorage {
/**
* 在插件加载存储源时执行。
*
* @throws Exception 当出现任何错误时抛出
*/
void initialize() throws Exception;
/**
* 在插件被卸载时执行。
*/
void shutdown();
/**
* 用于加载用户数据的方法。<b>该方法将会被异步运行!</b>
* <br>该方法一般无需自行执行,见 {@link UserManager#loadData(UUID)}
* <br>
* <br>若不存在该用户的数据,请返回 null 。
* <br>若加载出现任何错误,请抛出异常。
*
* @param uuid 用户UUID
* @throws Exception 当出现任何错误时抛出
*/
@Nullable
UserData loadData(@NotNull UUID uuid) throws Exception;
/**
* 用于保存用户数据的方法。 <b>该方法将会被异步运行!</b>
* <br>该方法一般无需自行执行,见 {@link UserManager#saveData(UserData)}
*
* @param data 用户数据
* @throws Exception 当出现任何错误时抛出
*/
void saveUserData(@NotNull UserData data) throws Exception;
Map<String, WarpInfo> getWarps();
default void saveWarps() throws Exception {
saveWarps(getWarps());
}
void saveWarps(@NotNull Map<String, WarpInfo> warps) throws Exception;
void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) throws Exception;
boolean delWarp(@NotNull String name) throws Exception;
default boolean hasWarp(@NotNull String name) {
return getWarps().containsKey(name);
}
/**
* 为某用户设定一个家的位置。
*
* @param uuid 用户UUID
* @param homeName 家的名称
* @param homeLocation 家的位置
* @throws Exception 当出现任何错误时抛出
*/
void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation homeLocation) throws Exception;
/**
* 为某用户移除一个家的位置。
*
* @param uuid 用户UUID
* @param homeName 家的名称
* @return 是否有一个家被移除
* @throws Exception 当出现任何错误时抛出
*/
boolean delHome(@NotNull UUID uuid, @NotNull String homeName) throws Exception;
}
@@ -0,0 +1,80 @@
package cc.carm.plugin.moeteleport.storage;
import cc.carm.plugin.moeteleport.storage.custom.CustomStorage;
import cc.carm.plugin.moeteleport.storage.database.MySQLStorage;
import cc.carm.plugin.moeteleport.storage.extension.CMIStorage;
import cc.carm.plugin.moeteleport.storage.extension.EssentialStorage;
import cc.carm.plugin.moeteleport.storage.file.JSONStorage;
import cc.carm.plugin.moeteleport.storage.file.YAMLStorage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Optional;
public enum StorageMethod {
CUSTOM(0, new String[]{}, CustomStorage.class),
YAML(1, new String[]{"yml"}, YAMLStorage.class),
JSON(2, new String[]{}, JSONStorage.class),
MYSQL(3, new String[]{"my-sql", "mariadb", "sql", "database"}, MySQLStorage.class),
ESSENTIALS(11, new String[]{"essential", "ess", "EssentialsX", "essX"}, EssentialStorage.class),
CMI(12, new String[]{}, CMIStorage.class);
private final int id;
private final String[] alias;
private @NotNull Class<? extends DataStorage> storageClazz;
StorageMethod(int id, String[] alias, @NotNull Class<? extends DataStorage> storageClazz) {
this.id = id;
this.alias = alias;
this.storageClazz = storageClazz;
}
public static @NotNull StorageMethod read(String s) {
StorageMethod byName = readByName(s);
if (byName != null) return byName;
StorageMethod byAlias = readByAlias(s);
if (byAlias != null) return byAlias;
try {
return Optional.ofNullable(readByID(Integer.parseInt(s))).orElse(YAML);
} catch (Exception ex) {
return YAML;
}
}
public static @Nullable StorageMethod readByName(String name) {
return Arrays.stream(values()).filter(value -> value.name().equalsIgnoreCase(name)).findFirst().orElse(null);
}
public static @Nullable StorageMethod readByAlias(String name) {
return Arrays.stream(values())
.filter(value -> Arrays.stream(value.getAlias()).anyMatch(alias -> alias.equalsIgnoreCase(name)))
.findFirst().orElse(null);
}
public static @Nullable StorageMethod readByID(int id) {
return Arrays.stream(values()).filter(value -> value.getID() == id).findFirst().orElse(null);
}
public int getID() {
return id;
}
public String[] getAlias() {
return alias;
}
public @NotNull Class<? extends DataStorage> getStorageClazz() {
return storageClazz;
}
public void setStorageClazz(@NotNull Class<? extends DataStorage> storageClazz) {
this.storageClazz = storageClazz;
}
public @NotNull DataStorage createStorage() throws Exception {
return getStorageClazz().newInstance();
}
}
@@ -0,0 +1,82 @@
package cc.carm.plugin.moeteleport.storage;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class UserData {
protected final @NotNull UUID userUUID;
private final LinkedHashMap<String, DataLocation> homeLocations;
public boolean enableAutoSelect = false;
private @Nullable Location lastLocation;
public UserData(@NotNull UUID userUUID) {
this(userUUID, null, new LinkedHashMap<>());
}
public UserData(@NotNull UUID userUUID,
@Nullable DataLocation lastLocation,
@NotNull LinkedHashMap<String, DataLocation> homeLocations) {
this.userUUID = userUUID;
this.lastLocation = Optional.ofNullable(lastLocation).map(DataLocation::getBukkitLocation).orElse(null);
this.homeLocations = homeLocations;
}
public @NotNull UUID getUserUUID() {
return userUUID;
}
public LinkedHashMap<String, DataLocation> getHomeLocations() {
return homeLocations;
}
public void setHomeLocation(String homeName, Location location) {
delHomeLocation(homeName);
getHomeLocations().put(homeName, new DataLocation(location));
MoeTeleport.getUserManager().editData((storage) -> storage.setHome(userUUID, homeName, new DataLocation(location)));
}
public void delHomeLocation(String homeName) {
Map.Entry<String, DataLocation> lastLocation = getHomeLocation(homeName);
if (lastLocation != null) getHomeLocations().remove(lastLocation.getKey());
MoeTeleport.getUserManager().editData((storage) -> storage.delHome(userUUID, homeName));
}
public Map.Entry<String, DataLocation> getHomeLocation(@Nullable String homeName) {
LinkedHashMap<String, DataLocation> homes = getHomeLocations();
if (homeName == null) {
if (homes.containsKey("home")) {
return new AbstractMap.SimpleEntry<>("home", homes.get("home"));
} else {
return homes.entrySet().stream().findFirst().orElse(null);
}
} else {
return homes.entrySet().stream()
.filter(entry -> entry.getKey().equalsIgnoreCase(homeName))
.findFirst().orElse(null);
}
}
public @Nullable Location getLastLocation() {
return lastLocation;
}
public void setLastLocation(@Nullable Location lastLocation) {
this.lastLocation = lastLocation;
}
public boolean isEnableAutoSelect() {
return enableAutoSelect;
}
public void setEnableAutoSelect(boolean enableAutoSelect) {
this.enableAutoSelect = enableAutoSelect;
}
}
@@ -0,0 +1,73 @@
package cc.carm.plugin.moeteleport.storage.custom;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import cc.carm.plugin.moeteleport.storage.DataStorage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class CustomStorage implements DataStorage {
@Override
@TestOnly
public void initialize() throws UnsupportedOperationException {
Main.severe("您选择使用自定义存储,但并没有应用成功。");
Main.severe("You are using CustomStorage, but not overwrite the methods.");
throw new UnsupportedOperationException("您选择使用自定义存储,但并没有应用成功。");
}
@Override
@TestOnly
public void shutdown() {
}
@Override
@TestOnly
public @Nullable UserData loadData(@NotNull UUID uuid) throws UnsupportedOperationException {
throw new UnsupportedOperationException("您选择使用自定义存储,但并没有应用成功。");
}
@Override
@TestOnly
public void saveUserData(@NotNull UserData data) throws UnsupportedOperationException {
throw new UnsupportedOperationException("您选择使用自定义存储,但并没有应用成功。");
}
@Override
public Map<String, WarpInfo> getWarps() {
return new HashMap<>();
}
@Override
public void saveWarps(@NotNull Map<String, WarpInfo> warps) {
}
@Override
public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) {
}
@Override
public boolean delWarp(@NotNull String name) {
return true;
}
@Override
public void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation homeLocation) throws Exception {
}
@Override
public boolean delHome(@NotNull UUID uuid, @NotNull String homeName) {
return true;
}
}
@@ -0,0 +1,41 @@
package cc.carm.plugin.moeteleport.storage.database;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
@HeaderComment("选择 database (如mysql) 存储方式时的数据库配置")
@ConfigPath("storage.database")
public class DatabaseConfig extends ConfigurationRoot {
@ConfigPath("driver")
protected static final ConfigValue<String> DRIVER_NAME = ConfiguredValue.of(
String.class, "com.mysql.jdbc.Driver"
);
protected static final ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
protected static final ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
protected static final ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
protected static final ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
protected static final ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
protected static final ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
@HeaderComment("插件相关表的名称")
public static final class TABLES extends ConfigurationRoot {
public static final ConfigValue<String> LAST_LOCATION = ConfiguredValue.of(String.class, "mt_last_locations");
public static final ConfigValue<String> HOMES = ConfiguredValue.of(String.class, "mt_homes");
public static final ConfigValue<String> WARPS = ConfiguredValue.of(String.class, "mt_warps");
}
protected static String buildJDBC() {
return String.format("jdbc:mysql://%s:%s/%s%s",
HOST.getNotNull(), PORT.getNotNull(), DATABASE.getNotNull(), EXTRA.getNotNull()
);
}
}
@@ -0,0 +1,96 @@
package cc.carm.plugin.moeteleport.storage.database;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.SQLTable;
import cc.carm.lib.easysql.api.builder.TableCreateBuilder;
import cc.carm.lib.easysql.api.enums.IndexType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.sql.SQLException;
import java.util.function.Consumer;
public enum DatabaseTables implements SQLTable {
LAST_LOCATION(DatabaseConfig.TABLES.LAST_LOCATION, (table) -> {
table.addColumn("uuid", "CHAR(36) NOT NULL PRIMARY KEY"); // 用户的UUID
// 坐标世界与位置
table.addColumn("world", "VARCHAR(128) NOT NULL");
table.addColumn("x", "DOUBLE NOT NULL");
table.addColumn("y", "DOUBLE NOT NULL");
table.addColumn("z", "DOUBLE NOT NULL");
table.addColumn("yaw", "DOUBLE NOT NULL");
table.addColumn("pitch", "DOUBLE NOT NULL");
table.addColumn("update",
"DATETIME NOT NULL " +
"DEFAULT CURRENT_TIMESTAMP " +
"ON UPDATE CURRENT_TIMESTAMP"
);
}),
HOMES(DatabaseConfig.TABLES.HOMES, (table) -> {
table.addAutoIncrementColumn("id", true, true);
table.addColumn("uuid", "CHAR(36) NOT NULL");
table.addColumn("name", "VARCHAR(32) NOT NULL");
// 坐标世界与位置
table.addColumn("world", "VARCHAR(128) NOT NULL");
table.addColumn("x", "DOUBLE NOT NULL");
table.addColumn("y", "DOUBLE NOT NULL");
table.addColumn("z", "DOUBLE NOT NULL");
table.addColumn("yaw", "DOUBLE NOT NULL");
table.addColumn("pitch", "DOUBLE NOT NULL");
table.setIndex(IndexType.INDEX, "idx_homes_user", "uuid");
table.setIndex(IndexType.UNIQUE_KEY, "uk_homes", "uuid", "name");
}),
WRAPS(DatabaseConfig.TABLES.WARPS, (table) -> {
table.addAutoIncrementColumn("id", true, true);
table.addColumn("name", "VARCHAR(32) NOT NULL");
table.addColumn("owner", "CHAR(36) NOT NULL");
// 坐标世界与位置
table.addColumn("world", "VARCHAR(128) NOT NULL");
table.addColumn("x", "DOUBLE NOT NULL");
table.addColumn("y", "DOUBLE NOT NULL");
table.addColumn("z", "DOUBLE NOT NULL");
table.addColumn("yaw", "DOUBLE NOT NULL");
table.addColumn("pitch", "DOUBLE NOT NULL");
table.setIndex(IndexType.UNIQUE_KEY, "uk_wraps", "name");
});
private final Consumer<TableCreateBuilder> builder;
private final ConfigValue<String> name;
private @Nullable SQLManager manager;
DatabaseTables(ConfigValue<String> name,
Consumer<TableCreateBuilder> builder) {
this.name = name;
this.builder = builder;
}
@Override
public @Nullable SQLManager getSQLManager() {
return this.manager;
}
@Override
public @NotNull String getTableName() {
return this.name.getNotNull();
}
@Override
public boolean create(SQLManager sqlManager) throws SQLException {
if (this.manager == null) this.manager = sqlManager;
TableCreateBuilder tableBuilder = sqlManager.createTable(getTableName());
if (builder != null) builder.accept(tableBuilder);
return tableBuilder.build().executeFunction(l -> l > 0, false);
}
}
@@ -0,0 +1,208 @@
package cc.carm.plugin.moeteleport.storage.database;
import cc.carm.lib.easysql.EasySQL;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.util.UUIDUtil;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import cc.carm.plugin.moeteleport.storage.DataStorage;
import cc.carm.plugin.moeteleport.storage.UserData;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class MySQLStorage implements DataStorage {
SQLManager sqlManager;
Map<String, WarpInfo> warpsMap = new HashMap<>();
@Override
public void initialize() throws Exception {
Main.info("加载数据库配置...");
Main.getInstance().getConfigProvider().initialize(DatabaseConfig.class);
try {
Main.info(" 尝试连接到数据库...");
this.sqlManager = EasySQL.createManager(
DatabaseConfig.DRIVER_NAME.getNotNull(), DatabaseConfig.buildJDBC(),
DatabaseConfig.USERNAME.getNotNull(), DatabaseConfig.PASSWORD.getNotNull()
);
this.sqlManager.setDebugMode(() -> Main.getInstance().isDebugging());
} catch (Exception exception) {
throw new Exception("无法连接到数据库,请检查配置文件", exception);
}
try {
Main.info(" 创建插件所需表...");
for (DatabaseTables value : DatabaseTables.values()) {
value.create(this.sqlManager);
}
} catch (SQLException exception) {
throw new Exception("无法创建插件所需的表,请检查数据库权限。", exception);
}
Main.info(" 加载地标数据...");
try {
this.warpsMap = loadWarps();
} catch (Exception e) {
throw new Exception("无法加载地标数据,请检查数据库权限和相关表。", e);
}
}
@Override
public void shutdown() {
Main.info(" 关闭数据库连接...");
EasySQL.shutdownManager(getSQLManager());
this.sqlManager = null;
}
public SQLManager getSQLManager() {
return sqlManager;
}
@Override
public @Nullable UserData loadData(@NotNull UUID uuid) throws Exception {
LinkedHashMap<String, DataLocation> homes = loadHomes(uuid);
DataLocation lastLocation = loadLastLocation(uuid);
return new UserData(uuid, lastLocation, homes);
}
@Override
public void saveUserData(@NotNull UserData data) throws Exception {
Location location = data.getLastLocation();
if (location != null && location.getWorld() != null) {
DatabaseTables.LAST_LOCATION.createReplace()
.setColumnNames("uuid", "world", "x", "y", "z", "yaw", "pitch")
.setParams(
data.getUserUUID(), location.getWorld().getName(),
location.getX(), location.getY(), location.getZ(),
location.getYaw(), location.getPitch()
).execute();
} else {
DatabaseTables.LAST_LOCATION.createDelete()
.addCondition("uuid", data.getUserUUID()).setLimit(1)
.build().execute();
}
}
@Override
public Map<String, WarpInfo> getWarps() {
return this.warpsMap;
}
@Override
public void saveWarps(@NotNull Map<String, WarpInfo> warps) {
// 单独保存,不需要统一存储
}
private @NotNull LinkedHashMap<String, DataLocation> loadHomes(@NotNull UUID uuid) throws Exception {
return DatabaseTables.HOMES.createQuery()
.addCondition("uuid", uuid).build()
.executeFunction((query) -> {
LinkedHashMap<String, DataLocation> homes = new LinkedHashMap<>();
ResultSet resultSet = query.getResultSet();
if (resultSet == null) return homes;
while (resultSet.next()) {
String name = resultSet.getString("name");
if (name == null) continue;
homes.put(name, readLocation(resultSet));
}
return homes;
}, new LinkedHashMap<>());
}
private @Nullable DataLocation loadLastLocation(@NotNull UUID uuid) throws Exception {
return DatabaseTables.LAST_LOCATION.createQuery()
.addCondition("uuid", uuid).setLimit(1).build()
.executeFunction((query) -> {
ResultSet resultSet = query.getResultSet();
if (resultSet == null || !resultSet.next()) return null;
return readLocation(resultSet);
});
}
private @NotNull Map<String, WarpInfo> loadWarps() throws Exception {
return DatabaseTables.WRAPS.createQuery()
.orderBy("id", true).build().executeFunction((query) -> {
LinkedHashMap<String, WarpInfo> warps = new LinkedHashMap<>();
ResultSet resultSet = query.getResultSet();
if (resultSet == null) return warps;
while (resultSet.next()) {
String uuidString = resultSet.getString("owner");
UUID uuid = uuidString == null ? null : UUIDUtil.toUUID(uuidString);
String name = resultSet.getString("name");
DataLocation location = readLocation(resultSet);
warps.put(name, new WarpInfo(name, uuid, location));
}
return warps;
}, new LinkedHashMap<>());
}
@Override
public void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation location) throws Exception {
DatabaseTables.HOMES.createReplace()
.setColumnNames("uuid", "name", "world", "x", "y", "z", "yaw", "pitch")
.setParams(
uuid, homeName, location.getWorldName(),
location.getX(), location.getY(), location.getZ(),
location.getYaw(), location.getPitch()
).execute();
}
@Override
public boolean delHome(@NotNull UUID uuid, @NotNull String homeName) throws Exception {
return DatabaseTables.HOMES.createDelete()
.addCondition("uuid", uuid)
.addCondition("name", homeName)
.setLimit(1)
.build().executeFunction((i) -> i > 0, false);
}
@Override
public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) throws Exception {
this.warpsMap.put(name, warpInfo);
DataLocation location = warpInfo.getLocation();
DatabaseTables.WRAPS.createReplace()
.setColumnNames("name", "owner", "world", "x", "y", "z", "yaw", "pitch")
.setParams(
name, warpInfo.getOwner(), location.getWorldName(),
location.getX(), location.getY(), location.getZ(),
location.getYaw(), location.getPitch()
).execute();
}
@Override
public boolean delWarp(@NotNull String name) throws Exception {
String actualName = this.warpsMap.keySet().stream().filter(s -> s.equalsIgnoreCase(name)).findFirst().orElse(null);
if (actualName == null) return false;
this.warpsMap.remove(actualName);
return DatabaseTables.WRAPS.createDelete()
.addCondition("name", actualName).setLimit(1)
.build().executeFunction((i) -> i > 0, false);
}
protected DataLocation readLocation(ResultSet result) throws SQLException {
return new DataLocation(
result.getString("world"),
result.getDouble("x"),
result.getDouble("y"),
result.getDouble("z"),
result.getFloat("yaw"),
result.getFloat("pitch")
);
}
}
@@ -0,0 +1,124 @@
package cc.carm.plugin.moeteleport.storage.extension;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.storage.impl.PluginBasedStorage;
import com.Zrips.CMI.CMI;
import com.Zrips.CMI.Containers.CMIUser;
import com.Zrips.CMI.Modules.Homes.CmiHome;
import com.Zrips.CMI.Modules.Warps.CmiWarp;
import com.Zrips.CMI.Modules.Warps.WarpManager;
import net.Zrips.CMILib.Container.CMILocation;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class CMIStorage extends PluginBasedStorage {
public CMIStorage() {
super("CMI");
}
@Override
public @Nullable UserData loadData(@NotNull UUID uuid) {
return new CMIUserData(uuid);
}
@Override
public Map<String, WarpInfo> getWarps() {
Map<String, WarpInfo> warps = new LinkedHashMap<>();
cmi().getWarps().forEach((name, warp) -> warps.put(name, new WarpInfo(name, warp.getCreator(), convert(warp.getLoc()))));
return warps;
}
@Override
public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) throws Exception {
CmiWarp warp = new CmiWarp(name);
warp.setLoc(convert(warpInfo.getLocation()));
warp.setCreator(warpInfo.getOwner());
cmi().addWarp(warp);
}
@Override
public boolean delWarp(@NotNull String name) throws Exception {
CmiWarp warp = cmi().getWarp(name);
if (warp == null) return false;
cmi().remove(warp);
return true;
}
@Override
public boolean hasWarp(@NotNull String name) {
return cmi().getWarp(name) != null;
}
protected WarpManager cmi() {
return CMI.getInstance().getWarpManager();
}
public static DataLocation convert(CMILocation loc) {
return new DataLocation(loc.getWorldName(), loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
}
public static CMILocation convert(DataLocation loc) {
return new CMILocation(loc.getWorldName(), loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
}
public static class CMIUserData extends UserData {
CMIUser cmiUser;
public CMIUserData(@NotNull UUID userUUID) {
super(userUUID);
this.cmiUser = CMI.getInstance().getPlayerManager().getUser(userUUID);
}
public CMIUser getCMIUser() {
return cmiUser;
}
@Override
public LinkedHashMap<String, DataLocation> getHomeLocations() {
LinkedHashMap<String, DataLocation> homes = new LinkedHashMap<>();
getCMIUser().getHomes().forEach((name, home) -> {
homes.put(name, convert(home.getLoc()));
});
return homes;
}
@Override
public void setHomeLocation(String homeName, Location location) {
getCMIUser().addHome(new CmiHome(homeName, new CMILocation(location)), true);
}
@Override
public void delHomeLocation(String homeName) {
try {
getCMIUser().removeHome(homeName);
} catch (Exception ignored) {
}
}
@Override
public @Nullable Location getLastLocation() {
return getCMIUser().getLastTeleportLocation();
}
@Override
public void setLastLocation(@Nullable Location lastLocation) {
getCMIUser().setLastTeleportLocation(lastLocation);
}
}
}
@@ -0,0 +1,122 @@
package cc.carm.plugin.moeteleport.storage.extension;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import cc.carm.plugin.moeteleport.storage.impl.PluginBasedStorage;
import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.User;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class EssentialStorage extends PluginBasedStorage {
public EssentialStorage() {
super("Essentials");
}
@Override
public @Nullable UserData loadData(@NotNull UUID uuid) {
return new EssentialUserData(uuid, getEssentials());
}
@Override
public Map<String, WarpInfo> getWarps() {
Map<String, WarpInfo> warps = new LinkedHashMap<>();
for (String warpName : getEssentials().getWarps().getList()) {
try {
Location warpLocation = getEssentials().getWarps().getWarp(warpName);
UUID owner = getEssentials().getWarps().getLastOwner(warpName);
warps.put(warpName, new WarpInfo(warpName, owner, new DataLocation(warpLocation)));
} catch (Exception ignore) {
}
}
return warps;
}
@Override
public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) throws Exception {
User user = getEssentials().getUser(warpInfo.getOwner());
Location location = warpInfo.getLocation().getBukkitLocation();
if (location == null) return;
if (user == null) {
getEssentials().getWarps().setWarp(name, location);
} else {
getEssentials().getWarps().setWarp(user, name, warpInfo.getLocation().getBukkitLocation());
}
}
@Override
public boolean delWarp(@NotNull String name) throws Exception {
boolean has = hasWarp(name);
getEssentials().getWarps().removeWarp(name);
return has;
}
@Override
public boolean hasWarp(@NotNull String name) {
return getEssentials().getWarps().isWarp(name);
}
public Essentials getEssentials() {
return (Essentials) getDependPlugin();
}
public static class EssentialUserData extends UserData {
User essentialsUser;
public EssentialUserData(@NotNull UUID userUUID, Essentials essentials) {
super(userUUID);
this.essentialsUser = essentials.getUser(userUUID);
}
public User getEssUser() {
return essentialsUser;
}
@Override
public LinkedHashMap<String, DataLocation> getHomeLocations() {
LinkedHashMap<String, DataLocation> homes = new LinkedHashMap<>();
getEssUser().getHomes().forEach(homeName -> {
Location homeLocation = getEssUser().getHome(homeName);
if (homeLocation != null) homes.put(homeName, new DataLocation(homeLocation));
});
return homes;
}
@Override
public void setHomeLocation(String homeName, Location location) {
getEssUser().setHome(homeName, location);
}
@Override
public void delHomeLocation(String homeName) {
try {
getEssUser().delHome(homeName);
} catch (Exception ignored) {
}
}
@Override
public @Nullable Location getLastLocation() {
return getEssUser().getLastLocation();
}
@Override
public void setLastLocation(@Nullable Location lastLocation) {
getEssUser().setLastLocation(lastLocation);
}
}
}
@@ -0,0 +1,142 @@
package cc.carm.plugin.moeteleport.storage.file;
import cc.carm.lib.easysql.api.util.UUIDUtil;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import cc.carm.plugin.moeteleport.storage.DataSerializer;
import cc.carm.plugin.moeteleport.storage.impl.FileBasedStorage;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class JSONStorage extends FileBasedStorage {
protected static final Gson GSON = new Gson();
protected static final JsonParser PARSER = new JsonParser();
Map<String, WarpInfo> warpsMap = new HashMap<>();
@Override
public void initialize() throws Exception {
super.initialize();
this.warpsMap = loadWarps();
}
@Override
public @Nullable UserData loadData(@NotNull UUID uuid) throws Exception {
File userDataFile = new File(getDataFolder(), uuid + ".json");
if (!userDataFile.exists()) {
Main.debugging("当前文件夾内不存在玩家 " + uuid + " 的数据,视作新档。");
return null;
}
JsonElement dataElement = PARSER.parse(new FileReader(userDataFile));
if (!dataElement.isJsonObject()) throw new NullPointerException(userDataFile.getName());
JsonObject dataObject = dataElement.getAsJsonObject();
DataLocation lastLocation = null;
if (dataObject.has("lastLocation")) {
lastLocation = DataLocation.deserializeText(dataObject.get("lastLocation").getAsString());
}
LinkedHashMap<String, DataLocation> homeData = new LinkedHashMap<>();
if (dataObject.has("homes")) {
JsonObject homesObject = dataObject.getAsJsonObject("homes");
if (homesObject != null) {
homesObject.entrySet().forEach(entry -> {
DataLocation location = DataLocation.deserializeText(entry.getValue().getAsString());
if (location != null) homeData.put(entry.getKey(), location);
});
}
}
return new UserData(uuid, lastLocation, homeData);
}
@Override
public void saveUserData(@NotNull UserData data) throws Exception {
JsonObject dataObject = new JsonObject();
if (data.getLastLocation() != null) {
dataObject.addProperty("lastLocation", DataSerializer.serializeLocation(data.getLastLocation()));
}
dataObject.add("homes", GSON.toJsonTree(DataSerializer.serializeLocationsMap(data.getHomeLocations())));
FileWriter writer = new FileWriter(new File(getDataFolder(), data.getUserUUID() + ".json"));
writer.write(GSON.toJson(dataObject));
writer.flush();
writer.close();
}
private @NotNull Map<String, WarpInfo> loadWarps() throws Exception {
File warpDataFile = new File(getDataFolder(), "warps.json");
if (!warpDataFile.exists()) return new LinkedHashMap<>();
JsonElement dataElement = PARSER.parse(new FileReader(warpDataFile));
if (!dataElement.isJsonObject()) throw new NullPointerException(warpDataFile.getName());
JsonObject dataObject = dataElement.getAsJsonObject();
LinkedHashMap<String, WarpInfo> warps = new LinkedHashMap<>();
dataObject.entrySet().forEach(entry -> {
String warpName = entry.getKey();
if (entry.getValue().isJsonObject()) {
try {
JsonObject warpObject = entry.getValue().getAsJsonObject();
UUID owner = warpObject.has("owner") ? UUIDUtil.toUUID(warpObject.get("owner").getAsString()) : null;
DataLocation location = new DataLocation(
warpObject.get("world").getAsString(),
warpObject.get("x").getAsDouble(),
warpObject.get("y").getAsDouble(),
warpObject.get("z").getAsDouble(),
warpObject.get("yaw").getAsFloat(),
warpObject.get("pitch").getAsFloat()
);
warps.put(warpName, new WarpInfo(warpName, owner, location));
} catch (Exception ignore) {
}
}
});
return warps;
}
@Override
public void saveWarps(@NotNull Map<String, WarpInfo> warps) throws Exception {
JsonObject dataObject = new JsonObject();
warps.forEach((name, info) -> dataObject.add(name, GSON.toJsonTree(DataSerializer.serializeWarpMap(info))));
FileWriter writer = new FileWriter(new File(getDataFolder(), "warps.json"));
writer.write(GSON.toJson(dataObject));
writer.flush();
writer.close();
}
@Override
public Map<String, WarpInfo> getWarps() {
return warpsMap;
}
@Override
public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) {
this.warpsMap.put(name, warpInfo);
}
@Override
public boolean delWarp(@NotNull String name) {
return this.warpsMap.remove(name) != null;
}
}
@@ -0,0 +1,133 @@
package cc.carm.plugin.moeteleport.storage.file;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import cc.carm.plugin.moeteleport.storage.DataSerializer;
import cc.carm.plugin.moeteleport.storage.impl.FileBasedStorage;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public class YAMLStorage extends FileBasedStorage {
Map<String, WarpInfo> warpsMap;
File warpsDataFile;
FileConfiguration warpsConfiguration;
@Override
public void initialize() throws Exception {
super.initialize();
this.warpsDataFile = new File(getDataFolder(), "warps.yml");
if (!this.warpsDataFile.exists() && !warpsDataFile.createNewFile()) {
throw new Exception("无法创建 warps.yml 文件。");
}
this.warpsConfiguration = YamlConfiguration.loadConfiguration(warpsDataFile);
this.warpsMap = loadWarps();
}
@Override
public void saveWarps(@NotNull Map<String, WarpInfo> warps) throws Exception {
this.warpsConfiguration.save(this.warpsDataFile);
}
@Override
public @Nullable UserData loadData(@NotNull UUID uuid) {
if (getDataFolder() == null || !getDataFolder().exists() || !getDataFolder().isDirectory()) {
throw new NullPointerException("Storage data folder is not initialized.");
}
File userDataFile = new File(getDataFolder(), uuid + ".yml");
if (!userDataFile.exists()) {
Main.debugging("当前文件夾内不存在玩家 " + uuid + " 的数据,视作新档。");
return null;
}
YamlConfiguration userConfiguration = YamlConfiguration.loadConfiguration(userDataFile);
DataLocation lastLocation = Optional
.ofNullable(userConfiguration.getString("lastLocation"))
.map(DataLocation::deserializeText)
.orElse(null);
LinkedHashMap<String, DataLocation> homeData = new LinkedHashMap<>();
Optional.ofNullable(userConfiguration.getConfigurationSection("homes")).ifPresent(
section -> section.getKeys(false).forEach(homeName -> {
DataLocation location = DataLocation.deserializeText(section.getString(homeName));
if (location != null) homeData.put(homeName, location);
}));
return new UserData(uuid, lastLocation, homeData);
}
@Override
public void saveUserData(@NotNull UserData data) throws Exception {
if (getDataFolder() == null || !getDataFolder().exists() || !getDataFolder().isDirectory()) {
throw new NullPointerException("Storage data folder is not initialized.");
}
YamlConfiguration userConfiguration = new YamlConfiguration();
if (data.getLastLocation() != null) {
userConfiguration.set("lastLocation", DataSerializer.serializeLocation(data.getLastLocation()));
}
userConfiguration.createSection("homes", DataSerializer.serializeLocationsMap(data.getHomeLocations()));
userConfiguration.save(new File(getDataFolder(), data.getUserUUID() + ".yml"));
}
private @NotNull Map<String, WarpInfo> loadWarps() {
LinkedHashMap<String, WarpInfo> warps = new LinkedHashMap<>();
ConfigurationSection warpsSection = this.warpsConfiguration.getConfigurationSection("warps");
if (warpsSection == null) return warps;
for (String warpName : warpsSection.getKeys(false)) {
ConfigurationSection warpInfoSection = warpsSection.getConfigurationSection(warpName);
if (warpInfoSection == null) continue;
try {
String ownerString = warpInfoSection.getString("owner");
UUID owner = ownerString == null ? null : UUID.fromString(ownerString);
DataLocation location = new DataLocation(
warpInfoSection.getString("world"),
warpInfoSection.getDouble("x"),
warpInfoSection.getDouble("y"),
warpInfoSection.getDouble("z"),
warpInfoSection.getLong("yaw"),
warpInfoSection.getLong("pitch")
);
warps.put(warpName, new WarpInfo(warpName, owner, location));
} catch (Exception ignore) {
}
}
return warps;
}
@Override
public Map<String, WarpInfo> getWarps() {
return warpsMap;
}
@Override
public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) {
this.warpsMap.put(name, warpInfo);
this.warpsConfiguration.createSection("warps." + name, DataSerializer.serializeWarpMap(warpInfo));
}
@Override
public boolean delWarp(@NotNull String name) {
this.warpsConfiguration.set("warps." + name, null);
return this.warpsMap.remove(name) != null;
}
}
@@ -0,0 +1,77 @@
package cc.carm.plugin.moeteleport.storage.impl;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import cc.carm.plugin.moeteleport.storage.DataStorage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.UUID;
public abstract class FileBasedStorage implements DataStorage {
protected static final ConfigValue<String> FILE_PATH = ConfiguredValue.builder(String.class)
.fromString().defaults("data")
.headerComments(
"选择 yaml/json 存储方式时的存储路径",
"默认为相对路径,相对于插件生成的配置文件夹下的路径",
"支持绝对路径,如 “/var/data/moe-teleport/\"(linux) 或 \"D:\\data\\moe-teleport\\\"(windows)",
"使用绝对路径时请注意权限问题"
).build();
protected @Nullable File dataFolder;
@Override
public void initialize() throws Exception {
FILE_PATH.initialize(
Main.getInstance().getConfigProvider(), true,
"storage.file", null, null
);
this.dataFolder = new File(Main.getInstance().getDataFolder(), FILE_PATH.getNotNull());
if (!dataFolder.exists()) {
if (!dataFolder.mkdir()) {
throw new Exception("无法创建数据文件夹!");
}
} else if (!dataFolder.isDirectory()) {
throw new Exception("数据文件夹路径对应的不是一个文件夹!");
}
}
@Override
public void shutdown() {
// 似乎没什么需要做的?
dataFolder = null;
}
@Override
public void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation homeLocation) throws Exception {
// saveData 方法即保存所有数据,不需要针对单个数据进行变更。
}
@Override
public boolean delHome(@NotNull UUID uuid, @NotNull String homeName) {
// saveData 方法即保存所有数据,不需要针对单个数据进行变更。
return true;
}
@Override
public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) {
// saveWarp 方法即保存所有数据,不需要针对单个数据进行变更。
}
@Override
public boolean delWarp(@NotNull String name) {
// saveWarp 方法即保存所有数据,不需要针对单个数据进行变更。
return true;
}
public @Nullable File getDataFolder() {
return dataFolder;
}
}
@@ -0,0 +1,59 @@
package cc.carm.plugin.moeteleport.storage.impl;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import cc.carm.plugin.moeteleport.storage.DataStorage;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.UUID;
public abstract class PluginBasedStorage implements DataStorage {
protected Plugin dependPlugin;
public PluginBasedStorage(String dependPluginName) {
this.dependPlugin = Bukkit.getPluginManager().getPlugin(dependPluginName);
}
@Override
public void initialize() throws NullPointerException {
if (dependPlugin == null) {
throw new NullPointerException("该存储类型依赖的插件不存在,请检查配置文件");
}
}
public Plugin getDependPlugin() {
return dependPlugin;
}
@Override
public void shutdown() {
// 一般啥也不需要我们做
}
@Override
public void saveUserData(@NotNull UserData data) {
// 一般都由其他插件自行保存,不需要实现。
}
@Override
public void saveWarps(@NotNull Map<String, WarpInfo> warps) {
// 一般都由其他插件自行保存,不需要实现。
}
@Override
public void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation homeLocation) {
// 一般都由其他插件自行保存,不需要实现。
}
@Override
public boolean delHome(@NotNull UUID uuid, @NotNull String homeName) {
// 一般都由其他插件自行保存,不需要实现。
return true;
}
}
@@ -0,0 +1,55 @@
package cc.carm.plugin.moeteleport.teleport;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.teleport.target.TeleportTarget;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.Duration;
public class TeleportQueue {
private final @NotNull Player player;
private final @NotNull TeleportTarget target;
private final long createMillis;
private final long executeMillis;
public TeleportQueue(@NotNull Player player, @NotNull TeleportTarget target, @Nullable Duration delay) {
this.player = player;
this.target = target;
this.createMillis = System.currentTimeMillis();
this.executeMillis = delay == null ? 0 : System.currentTimeMillis() + delay.toMillis();
}
public @NotNull Player getPlayer() {
return player;
}
public @NotNull UserData getUser() {
return MoeTeleport.getUserManager().getData(getPlayer());
}
public @NotNull TeleportTarget getTarget() {
return target;
}
public long getCreateMillis() {
return createMillis;
}
public long getExecuteMillis() {
return executeMillis;
}
public long getRemainSeconds() {
return (executeMillis - System.currentTimeMillis()) / 1000;
}
public boolean checkTime() {
return System.currentTimeMillis() >= executeMillis;
}
}
@@ -0,0 +1,89 @@
package cc.carm.plugin.moeteleport.teleport;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.storage.UserData;
import cc.carm.plugin.moeteleport.teleport.target.TeleportPlayerTarget;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.Duration;
public class TeleportRequest {
public enum Type {TPA_TO, TPA_HERE}
private final @NotNull Type type;
private final @NotNull Player sender;
private final @NotNull Player receiver;
private final long createMillis;
public TeleportRequest(@NotNull Type type, @NotNull Player sender, @NotNull Player receiver) {
this.type = type;
this.sender = sender;
this.receiver = receiver;
this.createMillis = System.currentTimeMillis();
}
public @NotNull Type getRequestType() {
return type;
}
public @NotNull Player getReceiver() {
return receiver;
}
public @NotNull UserData getReceiverUser() {
return MoeTeleport.getUserManager().getData(getReceiver());
}
public @NotNull Player getSender() {
return sender;
}
public @NotNull UserData getSenderUser() {
return MoeTeleport.getUserManager().getData(getSender());
}
public long getCreateMillis() {
return createMillis;
}
public long getActiveMillis() {
return System.currentTimeMillis() - getCreateMillis();
}
public long getRemainMillis() {
return PluginConfig.REQUEST.EXPIRE_TIME.getNotNull() * 1000 - getActiveMillis();
}
public long getRemainSeconds() {
return getRemainMillis() / 1000;
}
public boolean isExpired() {
return getActiveMillis() > PluginConfig.REQUEST.EXPIRE_TIME.getNotNull() * 1000;
}
public @Nullable TeleportQueue createQueue(@Nullable Duration delay) {
Player player;
TeleportPlayerTarget destination;
if (type == Type.TPA_TO) {
destination = new TeleportPlayerTarget(receiver);
player = sender;
} else if (type == Type.TPA_HERE) {
destination = new TeleportPlayerTarget(sender);
player = receiver;
} else {
return null;
}
return new TeleportQueue(player, destination, delay);
}
}
@@ -0,0 +1,39 @@
package cc.carm.plugin.moeteleport.teleport.target;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class TeleportLocationTarget implements TeleportTarget {
private final @NotNull DataLocation location;
public TeleportLocationTarget(@NotNull DataLocation location) {
this.location = location;
}
public TeleportLocationTarget(@NotNull Location location) {
this(new DataLocation(location));
}
public @NotNull DataLocation getDataLocation() {
return location;
}
public @Nullable Location getLocation() {
return getDataLocation().getBukkitLocation();
}
@Override
public Location prepare() {
Location loc = getLocation();
if (loc == null || !loc.isWorldLoaded()) return null;
return loc;
}
@Override
public String getText() {
return getDataLocation().toFlatString();
}
}
@@ -0,0 +1,25 @@
package cc.carm.plugin.moeteleport.teleport.target;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class TeleportPlayerTarget implements TeleportTarget {
protected final @NotNull Player target;
public TeleportPlayerTarget(@NotNull Player target) {
this.target = target;
}
@Override
public Location prepare() {
return target.isOnline() ? target.getLocation() : null;
}
@Override
public String getText() {
return target.getName();
}
}
@@ -0,0 +1,43 @@
package cc.carm.plugin.moeteleport.teleport.target;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.jetbrains.annotations.Nullable;
public interface TeleportTarget {
/**
* 准备可传送的目的地
*
* @return 准备传送目的地
*/
@Nullable Location prepare();
/**
* @return 目标的文字介绍
*/
String getText();
/**
* 检查一个位置是否安全
*
* @param location 位置
* @return 是否安全
*/
@Deprecated
static boolean checkLocation(Location location) {
Block leg = location.getBlock();
if (!leg.getType().isAir()) {
return false; // not transparent (will suffocate)
}
Block head = leg.getRelative(BlockFace.UP);
if (!head.getType().isAir()) {
return false; // not transparent (will suffocate)
}
Block ground = leg.getRelative(BlockFace.DOWN);
// return !PluginConfig.TELEPORTATION.DANGEROUS_TYPES.getNotNull().contains(ground.getType().name());
return !ground.isPassable();
}
}
@@ -1,31 +0,0 @@
package cc.carm.plugin.moeteleport.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ColorParser {
public static String parse(String text) {
return parseColor(parseHexColor(text));
}
public static String parseColor(final String text) {
return text.replaceAll("&", "§").replace("§§", "&");
}
public static String parseHexColor(String text) {
Pattern pattern = Pattern.compile("&\\((&?#[0-9a-fA-F]{6})\\)");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
String hexColor = text.substring(matcher.start() + 2, matcher.end() - 1);
hexColor = hexColor.replace("&", "");
StringBuilder bukkitColorCode = new StringBuilder('§' + "x");
for (int i = 1; i < hexColor.length(); i++) {
bukkitColorCode.append('§').append(hexColor.charAt(i));
}
text = text.replaceAll("&\\(" + hexColor + "\\)", bukkitColorCode.toString().toLowerCase());
matcher.reset(text);
}
return text;
}
}
@@ -0,0 +1,8 @@
package cc.carm.plugin.moeteleport.util;
import cc.carm.plugin.moeteleport.storage.DataStorage;
@FunctionalInterface
public interface DataTaskRunner {
void run(DataStorage storage) throws Exception;
}
@@ -1,77 +0,0 @@
package cc.carm.plugin.moeteleport.util;
import de.themoep.minedown.MineDown;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class MessageUtil {
public static boolean hasPlaceholderAPI() {
return Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null;
}
public static void send(@Nullable CommandSender sender, List<String> messages) {
if (messages == null || messages.isEmpty() || sender == null) return;
for (String s : messages) {
sender.spigot().sendMessage(MineDown.parse(s));
}
}
public static void send(@Nullable CommandSender sender, String... messages) {
send(sender, Arrays.asList(messages));
}
public static void sendWithPlaceholders(CommandSender sender, String... messages) {
sendWithPlaceholders(sender, Arrays.asList(messages));
}
public static void sendWithPlaceholders(@Nullable CommandSender sender, List<String> messages) {
if (messages == null || messages.isEmpty() || sender == null) return;
if (hasPlaceholderAPI() && sender instanceof Player) {
send(sender, PlaceholderAPI.setPlaceholders((Player) sender, messages));
} else {
send(sender, messages);
}
}
public static void sendWithPlaceholders(@Nullable CommandSender sender, List<String> messages, String param, Object value) {
sendWithPlaceholders(sender, messages, new String[]{param}, new Object[]{value});
}
public static void sendWithPlaceholders(@Nullable CommandSender sender, List<String> messages, String[] params, Object[] values) {
sendWithPlaceholders(sender, setCustomParams(messages, params, values));
}
public static List<String> setCustomParams(List<String> messages, String param, Object value) {
return setCustomParams(messages, new String[]{param}, new Object[]{value});
}
public static List<String> setCustomParams(List<String> messages, String[] params, Object[] values) {
if (params.length != values.length) return messages;
HashMap<String, Object> paramsMap = new HashMap<>();
for (int i = 0; i < params.length; i++) {
paramsMap.put(params[i], values[i]);
}
return setCustomParams(messages, paramsMap);
}
public static List<String> setCustomParams(List<String> messages, HashMap<String, Object> params) {
List<String> list = new ArrayList<>();
for (String message : messages) {
String afterMessage = message;
for (Map.Entry<String, Object> entry : params.entrySet()) {
afterMessage = afterMessage.replace(entry.getKey(), entry.getValue().toString());
}
list.add(afterMessage);
}
return list;
}
}
+7
View File
@@ -0,0 +1,7 @@
&d _____ &5 _____ _ _
&d| |___ ___&5|_ _|___| |___ ___ ___ ___| |_
&d| | | | . | -_|&5 | | | -_| | -_| . | . | _| _|
&d|_|_|_|___|___|&5 |_| |___|_|___| _|___|_| |_|
&8# &dMoe&5Teleport &5 |_|
&f 当前版本 &d${project.version} &f查看更多信息请访问项目主页
&8 -> &d https://github.com/CarmJos/MoeTeleport
-20
View File
@@ -1,20 +0,0 @@
version: ${project.version}
defaultHome: 1
permissions:
# 以下命令全部为 MoeTeleport 的子节点
# 如 "home.vip" 的权限全拼就是 "MoeTeleport.home.vip"
10: "home.vip" # 最多可以设置10个家
# 传送请求过期时间
expireTime: 30
# 返回死亡点
# 开启后将允许玩家输入 /back 返回死亡地点。
death-back: true
# 危险的方块类型,将判断目的地脚下的方块的类型是否在这个列表中
dangerous-blocks:
- LAVA
- AIR
-68
View File
@@ -1,68 +0,0 @@
no-last-location:
- "&f您当前没有进行传送,无法返回上个地点。"
death-back:
- "&f您可以输入 &5/back &f返回您的死亡地点。"
not-online:
- "&f目标玩家并不在线,无法发送请求。"
tpa:
- "&d%(player) &f请求传送到您身边,您有 &5%(expire)秒 &f的时间回应。"
- "[&a&l[同意]](show_text=点击同意请求 run_command=/tpAccept %(player)) &f输入 &5/tpAccept &f同意该请求。"
- "[&c&l[拒绝]](show_text=点击拒绝请求 run_command=/tpDeny %(player)) &f输入 &5/tpDeny &f拒绝该请求。"
tpahere:
- "&d%(player) &f请求传送您到Ta身边,您有 &5%(expire)秒 &f的时间回应。"
- "[&a&l[同意]](show_text=点击同意请求 run_command=/tpAccept %(player)) &f输入 &5/tpAccept &f同意该请求。"
- "[&c&l[拒绝]](show_text=点击拒绝请求 run_command=/tpDeny %(player)) &f输入 &5/tpDeny &f拒绝该请求。"
tpaccept:
- "&f您同意了 &d%(player) &f的传送请求。"
tpdeny:
- "&f您&d拒绝&f了 &d%(player) &f的传送请求。"
accepted:
- "&d%(player) &f同意了您的传送请求。"
denied:
- "&d%(player) &f拒绝了您的传送请求。"
offline:
- "&d%(player) &f离线,相关请求已自动取消。"
request-duplicate:
- "&f您已经向 &d%(player) &f发送过传送请求,对方仍有 &5%(expire)秒 &f的时间回应该请求。"
request-sent:
- "&f成功向玩家 &d%(player) &f发送传送请求,对方有 &5%(expire)秒 &f的时间回应该请求。"
no-request:
- "&f您当前没有任何待处理的传送请求。"
no-request-player:
- "&f您当前没有收到来自 &d%(player) &f的传送请求。"
multi-requests:
- "&f您当前有&d%(num)条请求&f待处理,请输入 &5/%(command) <玩家名> &f决定回应谁的请求。"
- "&f您也可以再次输入 &5/%(command) &f快速回应最近的一条请求。"
request-sent-timeout:
- "&f发往 &d%(player) &f的传送请求已超时。"
request-received-timeout:
- "&f来自 &d%(player) &f的传送请求已超时。"
teleporting:
- "&f正在传送到 &d%(location) &f..."
dangerous:
- "&f目标地点不安全,传送被取消。"
dangerous-here:
- "&f当前地点不安全,传送被取消。"
notAvailable:
- "&f目标地点暂时无法前往,传送被取消。"
home-list-header:
- "&f您当前设定的所有家:"
home-list-object: "&8# &f%(id) &d%(location) [&7✈](show_text=点击返回家 %(id) run_command=/home %(id))"
home-not-found:
- "&f您还没有设置这个家,请先输入 &5/setHome <家名称> &f设置一个吧!"
home-set:
- "&f成功设定名为 &d%(name) &f的家传送点。"
home-removed:
- "&f成功移除名为 &d%(name) &f的家传送点。"
- "&7原先位置为 &f%(location) &7。"
home-over-limit:
- "&f您最多只能设置 &d%(max) &f个家传送点!"
- "&7可以输入 &5/delHome <家名称> &7删除之前的家传送点,"
- "&7或输入 &5/setHome <家名称> &7覆盖之前的家传送点。"
+24 -34
View File
@@ -1,52 +1,42 @@
main: cc.carm.plugin.moeteleport.Main main: cc.carm.plugin.moeteleport.Main
name: ${project.name} name: MoeTeleport
version: ${project.version} version: ${project.version}
author: CarmJos author: CarmJos
website: ${project.url} website: ${project.url}
description: ${project.description} description: ${project.description}
api-version: 1.13
softdepend: softdepend:
- PlaceholderAPI - PlaceholderAPI
- Essentials
- CMI
permissions: permissions:
"MoeTeleport":
description: "插件的主权限节点"
default: false
"MoeTeleport.admin": "MoeTeleport.admin":
description: "插件的管理员权限节点" description: "插件的管理员权限节点"
default: op default: op
"MoeTeleport.teleport":
description: "使用传送请求相关指令的权限。"
default: true
"MoeTeleport.home":
description: "使用家相关指令的权限。"
default: true
"MoeTeleport.warp":
description: "使用传送请求相关指令的权限。"
default: true
"MoeTeleport.back":
description: "使用返回相关指令的权限。"
default: true
commands: commands:
"MoeTeleport": "MoeTeleport":
description: "插件的主命令,用于重载插件或查看插件信息。" description: "插件的主命令,用于重载插件或查看插件信息。"
permission: "MoeTeleport.admin" usage: "您可以输入 /MoeTeleport help 查看插件的相关帮助。"
usage: "/MoeTeleport reload" aliases:
- mt
"back":
description: 返回传送前的上一个地点。
"tpa":
usage: "/tpa <玩家> "
description: 请求传送到一个玩家身边。
"tpaHere":
usage: "/tpaHere <玩家>"
description: 请求一个玩家传送到自己身边。
"tpAccept":
usage: "/tpAccept [玩家]"
description: 同意一个请求,可以限定某个玩家。
"tpDeny":
usage: "/tpDeny [玩家]"
description: 拒绝一个请求,可以限定某个玩家。
"home":
usage: "/home [名称] "
description: "返回家所在位置。"
"listHome":
description: "列出所有家的位置。"
"setHome":
usage: "/setHome [名称] "
description: "设置家的传送点 (不填名称默认为home)"
"delHome":
usage: "/delHome <名称> "
description: "删除家的传送点。"