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

87 Commits

Author SHA1 Message Date
renovate[bot] 3ebd583fad chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.6 2026-05-27 22:03:28 +00:00
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
94 changed files with 3874 additions and 2283 deletions
+3 -3
View File
@@ -14,9 +14,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v6
- name: "Set up JDK"
uses: actions/setup-java@v2
uses: actions/setup-java@v5
with:
java-version: '11'
distribution: 'adopt'
@@ -37,7 +37,7 @@ jobs:
cp -vrf asset/*.jar artifacts
- name: "Upload artifact"
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v7
with:
name: Artifact
path: artifacts
+2 -2
View File
@@ -11,9 +11,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v6
- name: "Set up JDK"
uses: actions/setup-java@v2
uses: actions/setup-java@v5
with:
java-version: '11'
distribution: 'adopt'
+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.
+99 -60
View File
@@ -1,123 +1,159 @@
```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)
开源的传送插件,包含数个功能,并根据用户需求持续更新添加新功能。
项目代码符合开发规范,适合新手开发者学习Bukkit,制作属于自己的插件。
本插件由 [璎珞服务器](https://www.yingluo.world/) 请求本人开发,经过授权后开源。
## 功能与优势
### 当前功能
- 多种存储格式,按需选择。
- 支持 YAML、JSON 与 MySQL/MariaDB 存储方式
- 支持直接调用 [EssentialsX](https://github.com/EssentialsX/Essentials) 数据,无缝切换
- 支持 YAML、JSON 与 MySQL/MariaDB 存储方式
- 支持直接调用 [EssentialsX](https://github.com/EssentialsX/Essentials) / CMI 数据,无缝切换
- 可点击的消息(如“点击同意”)
- 基于MineDown语法,可自定义配置
- 基于MineDown语法,可自定义配置
- 玩家间的传送请求
- 支持指定处理某位玩家的请求
- 设置家与回家 (可以理解为私人地标)
- 支持依照权限设定不同数量的作为VIP附加内容
- 支持指定处理某位玩家的请求
- 设置地标
- 支持依照权限设定不同数量的地标点作为VIP附加内容
- 设置家位置 (可以理解为私人地标)
- 支持依照权限设定不同数量的家作为VIP附加内容
- 回到死亡地点、上一传送地点
### 优势
- **轻量插件。** 适合小型服务器使用,配置简单方便。
- **规范开发。** 插件符合开发规范,适合新手开发者学习。
- **规范开发。** 插件架构符合开发规范,适合新手开发者学习。
- 自 [3.0.0]() 版本开始采用了 EasyPlugin 开发,可能与其他主流插件结构有些不同。
- **持续维护。** 新功能需求均可提交,大概率在后续开发中支持。
- 功能需求请 [提交Issues](https://github.com/CarmJos/MoeTeleport/issues/new?assignees=&labels=enhancement&template=feature_issues.md&title=) ,不要在帖子中提交!
- 功能需求请 [提交Issues](https://github.com/CarmJos/MoeTeleport/issues/new?assignees=&labels=enhancement&template=feature_issues.md&title=)
,不要在帖子中提交!
- 提交与 “传送” 相关联的请求才大概率会被更新支持。
## [依赖](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) 实现。
- 所有 messages.yml 均支持 MineDown 语法。
- 所有 messages.yml 均支持 MineDown 语法。
- **[推荐]** 变量部分基于 [PlaceholderAPI](https://www.spigotmc.org/resources/6245/) 实现。
详细依赖列表可见 [Dependencies](https://github.com/CarmJos/MoeTeleport/network/dependencies) 。
## [指令](src/main/resources/plugin.yml)
以下指令的主指令为 `/MoeTeleport``/mt`
本插件所有指令支持配置“简化指令”,如允许玩家直接输入 `/back` 执行 `/MoeTeleport back`,详见 [配置文件](#配置) 相关内容。
- 必须参数 `<参数>`
- 可选参数 `[参数]`
```text
# /MoeTeleport reload
# reload
@ 管理指令 (MoeTeleport.admin)
- 重载插件配置文件。
# /back
- 返回上一个传送地点
# back
- 回到之前的传送位置。
# /tpa <玩家>
- 请求传送到一个玩家身边。
# /tpaHere <玩家>
- 请求一个玩家传送到自己身边。
# /tpAccept [玩家]
- 同意一个请求,可以限定某个玩家。
# /tpDeny [玩家]
- 拒绝一个请求,可以限定某个玩家。
----- [ 传送相关指令 ] -----
# /home [name]
- 返回设定的家
- 不填name会返回第一个设置的家
# teleport to <目标玩家>
- 请求传送到目标玩家的位置。
# teleport here <玩家>
- 请求目标玩家传送到自己的位置。
# teleport accept [玩家]
- 同意一个传送请求(可具体指定玩家的请求)。
# teleport deny [玩家]
- 拒绝一个传送请求(可具体指定玩家的请求)。
----- [ 家相关指令 ] -----
# home to [家名]
- 传送到指定的家。
- 若不填写具体的家明则返回首个设置的家,
- 若存在名为“home”的家则优先返回“home”。
# /listHome
- 列出所有家的位置
# /setHome [name]
- 设置家 (不填name默认为home)
# /delHome <name>
- 删除家
# home list
- 列出所有的家位置。
# 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),详见源文件。
## 使用统计
### 玩家数据配置文件 (data/\<UUID\>.yml)
本插件采用 `YAML格式` 存储玩家数据。
```yaml
# 玩家的家位置记录
# 格式为 world;x;y;z;yaw;pitch
homes:
"name": "world;112.21;45;21.241245552;92.5512;-11"
```
[![bStats](https://bstats.org/signatures/bukkit/MoeTeleport.svg)](https://bstats.org/plugin/bukkit/MoeTeleport/14459)
## 支持与捐赠
若您觉得本插件做的不错,您可以捐赠支持我!
若您觉得本插件做的不错,您可以捐赠支持我,感谢您成为开源项目的支持者
感谢您成为开源项目的支持者!
由衷感谢以下支持本项目开发的朋友们:
- 本插件由 [**璎珞**服务器](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) 开源协议。
> ### 关于 GPL 协议
<details>
<summary>关于 GPL 协议</summary>
> GNU General Public Licence (GPL) 有可能是开源界最常用的许可模式。GPL 保证了所有开发者的权利,同时为使用者提供了足够的复制,分发,修改的权利:
>
> #### 可自由复制
@@ -127,8 +163,11 @@ homes:
> #### 可以用来盈利
> 你可以在分发软件的时候收费,但你必须在收费前向你的客户提供该软件的 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) 。*
</details>
Binary file not shown.
Binary file not shown.
+126 -63
View File
@@ -5,15 +5,20 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.jdk.version>8</project.jdk.version>
<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>
<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>
<groupId>cc.carm.plugin</groupId>
<artifactId>moeteleport</artifactId>
<version>3.0.0</version>
<version>4.0.3</version>
<name>MoeTeleport</name>
<description>喵喵传送,简单的传送、设置家的插件。</description>
@@ -21,12 +26,12 @@
<issueManagement>
<system>GitHub Issues</system>
<url>${project.url}/issues</url>
<url>https://github.com/CarmJos/MoeTeleport/issues</url>
</issueManagement>
<ciManagement>
<system>GitHub Actions</system>
<url>${project.url}/actions/workflows/maven.yml</url>
<url>https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml</url>
</ciManagement>
<developers>
@@ -39,13 +44,6 @@
</developers>
<repositories>
<repository>
<id>carm-repo</id>
<name>Carm's Repo</name>
<url>https://repo.carm.cc/repository/maven-public/</url>
</repository>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
@@ -82,58 +80,93 @@
</repository>
<repository>
<id>github</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/${project.name}</url>
<id>carm-repo</id>
<name>Carm's Repo</name>
<url>https://repo.carm.cc/repository/maven-public/</url>
</repository>
</repositories>
<distributionManagement>
<downloadUrl>${project.url}/releases</downloadUrl>
<downloadUrl>https://github.com/CarmJos/MoeTeleport/releases</downloadUrl>
<repository>
<id>github</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/${project.name}</url>
<url>https://maven.pkg.github.com/CarmJos/MoeTeleport</url>
</repository>
</distributionManagement>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.17-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.10.9</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.essentialsx</groupId>
<artifactId>EssentialsX</artifactId>
<version>2.19.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easysql-beecp</artifactId>
<version>0.3.8</version>
<artifactId>mineconfiguration-bukkit</artifactId>
<version>${deps.mineconfig.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>githubreleases4j</artifactId>
<version>1.3.1</version>
<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>
</dependency>
<dependency>
<groupId>com.Zrips</groupId>
<artifactId>CMI-API</artifactId>
<version>9.3.1.2</version>
<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>
@@ -141,13 +174,44 @@
<artifactId>minedown</artifactId>
<version>1.7.1-SNAPSHOT</version>
<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.0.0</version>
<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>
@@ -160,19 +224,18 @@
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>22.0.0</version>
<version>26.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<version>3.5.0</version>
<configuration>
<filesets>
<fileset>
@@ -195,10 +258,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<version>3.15.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>${project.jdk.version}</source>
<target>${project.jdk.version}</target>
<encoding>UTF-8</encoding>
<compilerArgument>-parameters</compilerArgument>
</configuration>
@@ -206,12 +269,12 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<version>3.5.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<version>3.4.0</version>
<executions>
<execution>
<phase>package</phase>
@@ -224,7 +287,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version>
<version>3.6.2</version>
<executions>
<execution>
<phase>package</phase>
@@ -234,7 +297,7 @@
</execution>
</executions>
<configuration>
<finalName>${project.name}-${project.version}</finalName>
<finalName>MoeTeleport-${project.version}</finalName>
<outputDirectory>${project.basedir}/asset/</outputDirectory>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
@@ -247,6 +310,10 @@
</filter>
</filters>
<relocations>
<relocation>
<pattern>cc.carm.lib</pattern>
<shadedPattern>cc.carm.plugin.moeteleport.lib</shadedPattern>
</relocation>
<relocation>
<pattern>de.themoep.minedown</pattern>
<shadedPattern>cc.carm.plugin.moeteleport.lib.minedown</shadedPattern>
@@ -255,25 +322,21 @@
<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>
<relocation>
<pattern>cc.carm.lib.easysql</pattern>
<shadedPattern>cc.carm.plugin.moeteleport.lib.easysql</shadedPattern>
</relocation>
<relocation>
<pattern>cc.carm.lib.githubreleases4j</pattern>
<shadedPattern>cc.carm.plugin.moeteleport.lib.github</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<version>3.5.6</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
+6
View File
@@ -0,0 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
}
+101 -120
View File
@@ -1,191 +1,172 @@
package cc.carm.plugin.moeteleport;
import cc.carm.plugin.moeteleport.command.BackCommand;
import cc.carm.plugin.moeteleport.command.MoeTeleportCommand;
import cc.carm.plugin.moeteleport.command.completer.HomeNameCompleter;
import cc.carm.plugin.moeteleport.command.completer.PlayerNameCompleter;
import cc.carm.plugin.moeteleport.command.completer.TpRequestCompleter;
import cc.carm.plugin.moeteleport.command.home.DelHomeCommand;
import cc.carm.plugin.moeteleport.command.home.GoHomeCommand;
import cc.carm.plugin.moeteleport.command.home.ListHomeCommand;
import cc.carm.plugin.moeteleport.command.home.SetHomeCommand;
import cc.carm.plugin.moeteleport.command.tpa.TpHandleCommand;
import cc.carm.plugin.moeteleport.command.tpa.TpaCommand;
import cc.carm.plugin.moeteleport.configuration.PluginConfig;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.easyplugin.EasyPlugin;
import cc.carm.lib.easyplugin.command.alias.AliasCommandManager;
import cc.carm.lib.easyplugin.updatechecker.GHUpdateChecker;
import cc.carm.lib.mineconfiguration.bukkit.MineConfiguration;
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.listener.TeleportListener;
import cc.carm.plugin.moeteleport.listener.UserListener;
import cc.carm.plugin.moeteleport.manager.ConfigManager;
import cc.carm.plugin.moeteleport.manager.RequestManager;
import cc.carm.plugin.moeteleport.manager.UserManager;
import cc.carm.plugin.moeteleport.manager.*;
import cc.carm.plugin.moeteleport.storage.DataStorage;
import cc.carm.plugin.moeteleport.storage.StorageMethod;
import cc.carm.plugin.moeteleport.util.ColorParser;
import cc.carm.plugin.moeteleport.util.JarResourceUtils;
import cc.carm.plugin.moeteleport.util.SchedulerUtils;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
import org.bukkit.command.TabCompleter;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.particle.utils.ReflectionUtils;
import java.util.Arrays;
public class Main extends JavaPlugin {
public class Main extends EasyPlugin {
private static Main instance;
private static SchedulerUtils scheduler;
private static DataStorage storage;
protected ConfigurationProvider<?> configProvider;
protected ConfigurationProvider<?> messageProvider;
private UserManager userManager;
private RequestManager requestManager;
protected DataStorage storage;
protected WarpManager warpManager;
protected UserManager userManager;
protected RequestManager requestManager;
protected TeleportManager teleportManager;
protected AliasCommandManager commandManager;
public Main() {
instance = this;
}
@Override
public void onEnable() {
instance = this;
scheduler = new SchedulerUtils(this);
outputInfo();
protected void load() {
log(getName() + " " + getDescription().getVersion() + " &7开始加载...");
long startTime = System.currentTimeMillis();
log("加载插件配置文件...");
this.configProvider = MineConfiguration.from(this, "config.yml");
this.configProvider.initialize(PluginConfig.class);
log("加载配置文件...");
ConfigManager.initConfig();
this.messageProvider = MineConfiguration.from(this, "messages.yml");
this.messageProvider.initialize(PluginMessages.class);
}
@Override
protected boolean initialize() {
log("初始化存储方式...");
StorageMethod storageMethod = StorageMethod.read(PluginConfig.STORAGE_METHOD.get());
log(" 正在使用 " + storageMethod.name() + " 进行数据存储");
StorageMethod storageMethod = StorageMethod.read(PluginConfig.STORAGE.METHOD.get());
storage = storageMethod.createStorage();
if (!storage.initialize()) {
error("初始化存储失败,请检查配置文件。");
storage.shutdown();
try {
log(" 正在使用 " + storageMethod.name() + " 进行数据存储");
storage = storageMethod.createStorage();
storage.initialize();
} catch (Exception ex) {
severe("初始化存储失败,请检查配置文件。");
setEnabled(false);
return; // 初始化失败,不再继续加载
return false; // 初始化失败,不再继续加载
}
log("加载地标管理器...");
warpManager = new WarpManager();
log("加载用户管理器...");
this.userManager = new UserManager();
if (Bukkit.getOnlinePlayers().size() > 0) {
log(" 加载现有用户数据...");
getUserManager().loadAll();
this.userManager.loadAll();
}
log("加载请求管理器...");
this.requestManager = new RequestManager(this);
log("加载传送管理器...");
this.teleportManager = new TeleportManager(this);
log("注册监听器...");
regListener(new UserListener());
registerListener(new UserListener());
registerListener(new TeleportListener());
log("注册指令...");
registerCommand("MoeTeleport", new MoeTeleportCommand());
registerCommand("MoeTeleport", new MainCommands(this));
registerCommand("back", new BackCommand());
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();
}
}
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());
if (PluginConfig.METRICS.get()) {
if (PluginConfig.METRICS.getNotNull()) {
log("启用统计数据...");
Metrics metrics = new Metrics(this, 14459);
metrics.addCustomChart(new SimplePie("storage_method", storageMethod::name));
}
log("加载完成 ,共耗时 " + (System.currentTimeMillis() - startTime) + " ms 。");
if (PluginConfig.CHECK_UPDATE.getNotNull()) {
log("开始检查更新...");
getScheduler().runAsync(GHUpdateChecker.runner(this));
} else {
log("已禁用检查更新,跳过。");
}
log("初始化粒子库...");
ReflectionUtils.setPlugin(this);
return true;
}
@Override
public void onDisable() {
outputInfo();
log(getName() + " " + getDescription().getVersion() + " 开始卸载...");
long startTime = System.currentTimeMillis();
protected void shutdown() {
if (PluginConfig.COMMAND.ENABLE.getNotNull() && this.commandManager != null) {
log("清空简化指令...");
this.commandManager.unregisterAll();
}
log("关闭所有请求...");
getRequestManager().shutdown();
this.requestManager.shutdown();
this.teleportManager.shutdown();
log("保存用户数据...");
getUserManager().unloadAll(true);
this.userManager.unloadAll(true);
log("保存地标数据...");
this.warpManager.saveWarps();
log("终止存储源...");
this.storage.shutdown();
log("卸载监听器...");
Bukkit.getServicesManager().unregisterAll(this);
log("卸载完成 ,共耗时 " + (System.currentTimeMillis() - startTime) + " ms 。");
}
/**
* 注册监听器
*
* @param listener 监听器
*/
public static void regListener(Listener listener) {
Bukkit.getPluginManager().registerEvents(listener, getInstance());
@Override
public boolean isDebugging() {
return PluginConfig.DEBUG.getNotNull();
}
public void outputInfo() {
String[] pluginInfo = JarResourceUtils.readResource(this.getResource("PLUGIN_INFO"));
if (pluginInfo != null) {
Arrays.stream(pluginInfo).forEach(Main::log);
}
public static void info(String... messages) {
getInstance().log(messages);
}
public static void log(String message) {
Bukkit.getConsoleSender().sendMessage(ColorParser.parse("[" + getInstance().getName() + "] " + message));
public static void severe(String... messages) {
getInstance().error(messages);
}
public static void error(String message) {
log("&4[ERROR] &r" + message);
}
public static void debug(String message) {
if (PluginConfig.DEBUG.get()) {
log("&e[DEBUG] &r" + message);
}
public static void debugging(String... messages) {
getInstance().debug(messages);
}
public static Main getInstance() {
return instance;
}
public static SchedulerUtils getScheduler() {
return scheduler;
public ConfigurationProvider<?> getConfigProvider() {
return configProvider;
}
public static void registerCommand(String commandName,
@NotNull CommandExecutor executor) {
registerCommand(commandName, executor, null);
public ConfigurationProvider<?> getMessageProvider() {
return messageProvider;
}
public static void registerCommand(String commandName,
@NotNull CommandExecutor executor,
@Nullable TabCompleter tabCompleter) {
PluginCommand command = Bukkit.getPluginCommand(commandName);
if (command == null) return;
command.setExecutor(executor);
if (tabCompleter != null) command.setTabCompleter(tabCompleter);
}
public static DataStorage getStorage() {
return storage;
}
public static UserManager getUserManager() {
return Main.getInstance().userManager;
}
public static RequestManager getRequestManager() {
return Main.getInstance().requestManager;
}
}
@@ -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.length == 1 && 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,44 +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";
if (homeName.length() > 30) {
// 限定家的名字长度
PluginMessages.Home.NAME_TOO_LONG.sendWithPlaceholders(sender);
return true;
}
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,49 +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;
}
if (player == target) {
// fix #5 - 玩家给自己发送传送请求
PluginMessages.SELF_REQUEST.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.bukkit.Bukkit;
@@ -1,45 +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 ConfigValue<Boolean> DEBUG = new ConfigValue<>(
"debug", Boolean.class, false
);
public static final ConfigValue<Boolean> METRICS = new ConfigValue<>(
"metrics", Boolean.class, true
);
public static final ConfigValue<Boolean> CHECK_UPDATE = new ConfigValue<>(
"check-update", Boolean.class, true
);
public static final ConfigValue<String> STORAGE_METHOD = new ConfigValue<>(
"storage.method", String.class, "YAML"
);
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,59 +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 SELF_REQUEST = new ConfigMessageList("self-request");
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 NAME_TOO_LONG = new ConfigMessageList("name-too-long");
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,8 +1,8 @@
package cc.carm.plugin.moeteleport.listener;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginConfig;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -14,22 +14,22 @@ public class UserListener implements Listener {
@EventHandler
public void onJoin(PlayerJoinEvent event) {
Main.getUserManager().loadData(event.getPlayer().getUniqueId());
MoeTeleport.getUserManager().loadData(event.getPlayer().getUniqueId());
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
Main.getRequestManager().cancelAllRequests(player);
Main.getUserManager().unloadData(player.getUniqueId());
MoeTeleport.getRequestManager().cancelAllRequests(player);
MoeTeleport.getUserManager().unloadData(player.getUniqueId());
}
@EventHandler
public void onDeath(PlayerDeathEvent event) {
if (PluginConfig.DEATH_GO_BACK.get()) {
if (PluginConfig.BACK.DEATH.getNotNull()) {
Player player = event.getEntity();
Main.getUserManager().getData(player).setLastLocation(player.getLocation());
PluginMessages.DEATH_BACK.send(player);
MoeTeleport.getUserManager().getData(player).setLastLocation(player.getLocation());
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;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginConfig;
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 cc.carm.plugin.moeteleport.MoeTeleport;
import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
import cc.carm.plugin.moeteleport.teleport.TeleportRequest;
import org.bukkit.entity.Player;
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.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class RequestManager {
public BukkitRunnable checkRunnable;
protected final Map<UUID, TeleportRequest> requests = new ConcurrentHashMap<>();
protected BukkitRunnable runnable;
public RequestManager(Main main) {
this.checkRunnable = new BukkitRunnable() {
this.runnable = new BukkitRunnable() {
@Override
public void run() {
checkRequests();
tickRequests();
}
};
this.checkRunnable.runTaskTimerAsynchronously(main, 100L, 20L);
this.runnable.runTaskTimerAsynchronously(main, 100L, 20L);
}
public void shutdown() {
if (!this.checkRunnable.isCancelled()) {
this.checkRunnable.cancel();
if (!this.runnable.isCancelled()) {
this.runnable.cancel();
}
}
public void checkRequests() {
Main.getUserManager().getUserDataMap().values()
.forEach(data -> data.getReceivedRequests().entrySet().stream()
.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()))
);
@Unmodifiable
public Map<UUID, TeleportRequest> getRequests() {
return Collections.unmodifiableMap(requests);
}
public void sendRequest(Player sender, Player receiver, TeleportRequest.RequestType type) {
int expireTime = PluginConfig.EXPIRE_TIME.get();
public @Nullable TeleportRequest getRequest(UUID senderUUID) {
return requests.get(senderUUID);
}
PluginMessages.Request.SENT.sendWithPlaceholders(sender,
new String[]{"%(player)", "%(expire)"},
new Object[]{receiver.getName(), expireTime}
);
@Unmodifiable
public @NotNull Map<UUID, TeleportRequest> getUserReceivedRequests(@NotNull UUID receiverUUID) {
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) {
case TPA: {
PluginMessages.TPA.sendWithPlaceholders(receiver,
new String[]{"%(player)", "%(expire)"},
new Object[]{sender.getName(), expireTime}
);
case TPA_TO: {
PluginMessages.REQUESTS.RECEIVED_TP_HERE.send(receiver, sender.getName(), expireTime);
break;
}
case TPA_HERE: {
PluginMessages.TPA_HERE.sendWithPlaceholders(receiver,
new String[]{"%(player)", "%(expire)"},
new Object[]{sender.getName(), expireTime}
);
PluginMessages.REQUESTS.RECEIVED_TP_TO.send(receiver, sender.getName(), expireTime);
break;
}
}
TeleportRequest request = new TeleportRequest(sender, receiver, type);
Main.getUserManager().getData(receiver).getReceivedRequests().put(sender.getUniqueId(), request);
Main.getUserManager().getData(sender).getSentRequests().add(receiver.getUniqueId());
requests.put(sender.getUniqueId(), new TeleportRequest(type, sender, receiver));
}
public void acceptRequest(TeleportRequest request) {
PluginMessages.ACCEPTED.sendWithPlaceholders(request.getSender(),
new String[]{"%(player)"},
new Object[]{request.getReceiver().getName()}
);
PluginMessages.TP_ACCEPT.sendWithPlaceholders(request.getReceiver(),
new String[]{"%(player)"},
new Object[]{request.getSender().getName()}
);
TeleportManager.teleport(request.getTeleportPlayer(), request.getTeleportLocation(), true);
PluginMessages.REQUESTS.WAS_ACCEPTED.send(request.getSender(), request.getReceiver().getName());
PluginMessages.REQUESTS.ACCEPTED.send(request.getReceiver(), request.getSender().getName());
removeRequests(request);
MoeTeleport.getTeleportManager().queueTeleport(request.createQueue(
Duration.of(PluginConfig.TELEPORTATION.WAIT_TIME.getNotNull(), ChronoUnit.SECONDS)
));
}
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);
}
public void denyRequest(TeleportRequest request) {
PluginMessages.DENIED.sendWithPlaceholders(request.getSender(),
new String[]{"%(player)"},
new Object[]{request.getReceiver().getName()}
);
PluginMessages.TP_DENY.sendWithPlaceholders(request.getReceiver(),
new String[]{"%(player)"},
new Object[]{request.getSender().getName()}
);
PluginMessages.REQUESTS.WAS_DENIED.send(request.getSender(), request.getReceiver().getName());
PluginMessages.REQUESTS.DENIED.send(request.getReceiver(), request.getSender().getName());
removeRequests(request);
}
public void removeRequests(TeleportRequest request) {
Main.getUserManager().getData(request.getSender())
.getSentRequests()
.remove(request.getReceiver().getUniqueId());
Main.getUserManager().getData(request.getReceiver())
.getReceivedRequests()
.remove(request.getSender().getUniqueId());
this.requests.remove(request.getSender().getUniqueId());
}
public void cancelAllRequests(Player player) {
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()
.peek(receiverUUID -> PluginMessages.Request.OFFLINE.sendWithPlaceholders(
Bukkit.getPlayer(receiverUUID),
new String[]{"%(player)"}, new Object[]{player.getName()}
)).map(receiverUUID -> Main.getUserManager().getData(receiverUUID))
.filter(Objects::nonNull).map(UserData::getReceivedRequests)
.forEach(senders -> senders.remove(playerUUID));
TeleportRequest sent = requests.remove(playerUUID);
if (sent != null) {
PluginMessages.REQUESTS.OFFLINE.send(sent.getReceiver(), player.getName());
}
data.getSentRequests().clear();
data.getReceivedRequests().clear();
for (TeleportRequest received : getUserReceivedRequests(playerUUID).values()) {
PluginMessages.REQUESTS.OFFLINE.send(received.getSender(), player.getName());
removeRequests(received);
}
}
}
@@ -1,60 +1,151 @@
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.PluginMessages;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.conf.PluginConfig;
import cc.carm.plugin.moeteleport.conf.PluginMessages;
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.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.Material;
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 static void teleport(Player player, DataLocation targetLocation, boolean onlySafety) {
Location location = targetLocation.getBukkitLocation();
if (location == null) {
PluginMessages.NOT_AVAILABLE.sendWithPlaceholders(player,
new String[]{"%(location)"},
new Object[]{targetLocation.toFlatString()}
);
} else {
teleport(player, location, onlySafety);
}
}
protected final Map<UUID, TeleportQueue> teleportQueue = new ConcurrentHashMap<>();
protected BukkitRunnable runnable;
public static void teleport(Player player, Location targetLocation, boolean onlySafety) {
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);
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) {
PluginMessages.TELEPORT.NOT_AVAILABLE.send(player, queue.getTarget().getText());
PluginConfig.TELEPORTATION.SOUND.FAILED.playTo(player);
} else {
PluginMessages.NOT_AVAILABLE.sendWithPlaceholders(player,
new String[]{"%(location)"},
new Object[]{new DataLocation(targetLocation).toFlatString()}
);
PluginMessages.TELEPORT.TELEPORTED.send(player, queue.getTarget().getText());
PluginConfig.TELEPORTATION.TITLE.TELEPORTED.send(player, queue.getTarget().getText());
Main.getInstance().getScheduler().run(() -> {
player.teleport(location);
PluginConfig.TELEPORTATION.SOUND.TELEPORTED.playTo(player);
});
if (PluginConfig.TELEPORTATION.EFFECTS.getNotNull()) {
new ParticleBuilder(ParticleEffect.ITEM_CRACK, location)
.setParticleData(new ItemTexture(new ItemStack(Material.ENDER_EYE)))
.setAmount(1).setOffsetY(1F).display();
}
}
}
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());
}
}
@@ -1,17 +1,22 @@
package cc.carm.plugin.moeteleport.manager;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginConfig;
import cc.carm.plugin.moeteleport.model.UserData;
import cc.carm.plugin.moeteleport.MoeTeleport;
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.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
public class UserManager {
@@ -22,27 +27,39 @@ public class UserManager {
this.userDataMap = new HashMap<>();
}
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
public UserData readData(UUID userUUID) {
try {
long start = System.currentTimeMillis();
DataStorage storage = Main.getStorage();
Main.debug("正通过 " + storage.getClass().getSimpleName() + " 读取 " + userUUID + " 的用户数据...(" + System.currentTimeMillis() + ")");
DataStorage storage = MoeTeleport.getStorage();
Main.debugging("正通过 " + storage.getClass().getSimpleName() + " 读取 " + userUUID + " 的用户数据...(" + System.currentTimeMillis() + ")");
UserData data = storage.loadData(userUUID);
if (data == null) {
Main.debug("当前还不存在玩家 " + userUUID + " 的数据,视作新档。");
Main.debugging("当前还不存在玩家 " + userUUID + " 的数据,视作新档。");
return new UserData(userUUID);
}
Main.debug("通过 " + storage.getClass().getSimpleName() + "读取 " + userUUID + " 的用户数据完成,"
Main.debugging("通过 " + storage.getClass().getSimpleName() + "读取 " + userUUID + " 的用户数据完成,"
+ "耗时 " + (System.currentTimeMillis() - start) + "ms。");
return data;
} catch (Exception e) {
Main.error("无法正常读取玩家数据,玩家操作将不会被保存,请检查数据配置!");
Main.error("Could not load user's data, please check the data configuration!");
Main.severe("无法正常读取玩家数据,玩家操作将不会被保存,请检查数据配置!");
Main.severe("Could not load user's data, please check the data configuration!");
e.printStackTrace();
return new UserData(userUUID);
}
@@ -51,17 +68,17 @@ public class UserManager {
public void saveData(UserData data) {
try {
long start = System.currentTimeMillis();
DataStorage storage = Main.getStorage();
DataStorage storage = MoeTeleport.getStorage();
Main.debug("正通过 " + storage.getClass().getSimpleName() + " 保存 " + data.getUserUUID() + " 的用户数据...(" + System.currentTimeMillis() + ")");
Main.debugging("正通过 " + storage.getClass().getSimpleName() + " 保存 " + data.getUserUUID() + " 的用户数据...(" + System.currentTimeMillis() + ")");
storage.saveUserData(data);
Main.debug("通过 " + storage.getClass().getSimpleName() + " 保存 " + data.getUserUUID() + " 的用户数据完成," +
Main.debugging("通过 " + storage.getClass().getSimpleName() + " 保存 " + data.getUserUUID() + " 的用户数据完成," +
"耗时 " + (System.currentTimeMillis() - start) + "ms。");
} catch (Exception e) {
Main.error("无法正常保存玩家数据,请检查数据配置!");
Main.error("Could not save user's data, please check the data configuration!");
Main.severe("无法正常保存玩家数据,请检查数据配置!");
Main.severe("Could not save user's data, please check the data configuration!");
e.printStackTrace();
}
}
@@ -107,33 +124,42 @@ public class UserManager {
return getUserDataMap().get(player.getUniqueId());
}
public int getMaxHome(Player player) {
Map<Integer, String> permissions = PluginConfig.PERMISSIONS.get();
int current = PluginConfig.DEFAULT_HOME.get();
public long countUserWarps(UUID userUUID) {
return MoeTeleport.getWarpManager().listWarps().values().stream()
.map(WarpInfo::getOwner).filter(Objects::nonNull)
.filter(ownerUUID -> ownerUUID.equals(userUUID))
.count();
}
for (Map.Entry<Integer, String> entry : permissions.entrySet()) {
if (entry.getKey() > current && player.hasPermission(entry.getValue())) {
current = entry.getKey();
}
}
return current;
public int getMaxHome(Player player) {
return getMaxValue(player, PluginConfig.HOMES.PERMISSIONS.getNotNull(), PluginConfig.HOMES.DEFAULTS.getNotNull());
}
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(Main.getStorage());
task.run(MoeTeleport.getStorage());
} catch (Exception exception) {
Main.error("无法正常更改玩家数据,请检查数据配置!");
Main.error("Could not edit user's data, please check the data configuration!");
Main.severe("无法正常更改玩家数据,请检查数据配置!");
Main.severe("Could not edit user's data, please check the data configuration!");
exception.printStackTrace();
}
}
public void editDataAsync(@NotNull DataTaskRunner task) {
Main.getScheduler().runAsync(() -> editData(task));
Main.getInstance().getScheduler().runAsync(() -> editData(task));
}
public HashMap<UUID, UserData> getUserDataMap() {
@NotNull
@Unmodifiable
public Map<UUID, UserData> listUserData() {
return ImmutableMap.copyOf(getUserDataMap());
}
protected @NotNull HashMap<UUID, UserData> getUserDataMap() {
return userDataMap;
}
@@ -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
}
}
@@ -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;
}
}
@@ -1,6 +1,7 @@
package cc.carm.plugin.moeteleport.storage;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.model.WarpInfo;
import org.bukkit.Location;
import org.jetbrains.annotations.Nullable;
@@ -25,5 +26,17 @@ public class DataSerializer {
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;
}
}
@@ -1,11 +1,12 @@
package cc.carm.plugin.moeteleport.storage;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.conf.location.DataLocation;
import cc.carm.plugin.moeteleport.manager.UserManager;
import cc.carm.plugin.moeteleport.model.UserData;
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 {
@@ -13,9 +14,9 @@ public interface DataStorage {
/**
* 在插件加载存储源时执行。
*
* @return 是否初始化成功
* @throws Exception 当出现任何错误时抛出
*/
boolean initialize();
void initialize() throws Exception;
/**
* 在插件被卸载时执行。
@@ -44,6 +45,22 @@ public interface DataStorage {
*/
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);
}
/**
* 为某用户设定一个家的位置。
*
@@ -1,54 +1,35 @@
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.EssentialXStorage;
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 cc.carm.plugin.moeteleport.storage.custom.CustomStorage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Supplier;
public enum StorageMethod {
CUSTOM(0, new String[]{}, CustomStorage::new),
YAML(1, new String[]{"yml"}, YAMLStorage::new),
JSON(2, new String[]{}, JSONStorage::new),
MYSQL(3, new String[]{"my-sql", "mariadb", "sql", "database"}, MySQLStorage::new),
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"}, EssentialXStorage::new);
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 Supplier<@NotNull DataStorage> storageSupplier;
private @NotNull Class<? extends DataStorage> storageClazz;
StorageMethod(int id, String[] alias, @NotNull Supplier<@NotNull DataStorage> storageSupplier) {
StorageMethod(int id, String[] alias, @NotNull Class<? extends DataStorage> storageClazz) {
this.id = id;
this.alias = alias;
this.storageSupplier = storageSupplier;
}
public int getID() {
return id;
}
public String[] getAlias() {
return alias;
}
public @NotNull Supplier<@NotNull DataStorage> getStorageSupplier() {
return storageSupplier;
}
public void setStorageSupplier(@NotNull Supplier<@NotNull DataStorage> storageSupplier) {
this.storageSupplier = storageSupplier;
}
public @NotNull DataStorage createStorage() {
return getStorageSupplier().get();
this.storageClazz = storageClazz;
}
public static @NotNull StorageMethod read(String s) {
@@ -63,7 +44,6 @@ public enum StorageMethod {
}
}
public static @Nullable StorageMethod readByName(String name) {
return Arrays.stream(values()).filter(value -> value.name().equalsIgnoreCase(name)).findFirst().orElse(null);
}
@@ -74,8 +54,27 @@ public enum StorageMethod {
.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();
}
}
@@ -1,24 +1,20 @@
package cc.carm.plugin.moeteleport.model;
package cc.carm.plugin.moeteleport.storage;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
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.*;
import java.util.concurrent.ConcurrentHashMap;
public class UserData {
protected final @NotNull UUID userUUID;
private final LinkedHashMap<String, DataLocation> homeLocations;
public boolean enableAutoSelect = false;
private @Nullable Location lastLocation;
private final LinkedHashMap<String, DataLocation> homeLocations;
private final HashSet<UUID/*receiverUUID*/> sentRequests = new HashSet<>(); // 记录发出的请求
private final ConcurrentHashMap<UUID/*senderUUID*/, TeleportRequest> receivedRequests = new ConcurrentHashMap<>(); // 记录收到的传送请求
public UserData(@NotNull UUID userUUID) {
this(userUUID, null, new LinkedHashMap<>());
@@ -43,13 +39,13 @@ public class UserData {
public void setHomeLocation(String homeName, Location location) {
delHomeLocation(homeName);
getHomeLocations().put(homeName, new DataLocation(location));
Main.getUserManager().editData((storage) -> storage.setHome(userUUID, 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());
Main.getUserManager().editData((storage) -> storage.delHome(userUUID, homeName));
MoeTeleport.getUserManager().editData((storage) -> storage.delHome(userUUID, homeName));
}
public Map.Entry<String, DataLocation> getHomeLocation(@Nullable String homeName) {
@@ -75,14 +71,6 @@ public class UserData {
this.lastLocation = lastLocation;
}
public HashSet<UUID> getSentRequests() {
return sentRequests;
}
public ConcurrentHashMap<UUID, TeleportRequest> getReceivedRequests() {
return receivedRequests;
}
public boolean isEnableAutoSelect() {
return enableAutoSelect;
}
@@ -1,23 +1,26 @@
package cc.carm.plugin.moeteleport.storage.custom;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.model.UserData;
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 boolean initialize() {
Main.error("您选择使用自定义存储,但并没有应用成功。");
Main.error("You are using CustomStorage, but not overwrite the methods.");
return false;
public void initialize() throws UnsupportedOperationException {
Main.severe("您选择使用自定义存储,但并没有应用成功。");
Main.severe("You are using CustomStorage, but not overwrite the methods.");
throw new UnsupportedOperationException("您选择使用自定义存储,但并没有应用成功。");
}
@Override
@@ -28,14 +31,34 @@ public class CustomStorage implements DataStorage {
@Override
@TestOnly
public @Nullable UserData loadData(@NotNull UUID uuid) {
return null;
public @Nullable UserData loadData(@NotNull UUID uuid) throws UnsupportedOperationException {
throw new UnsupportedOperationException("您选择使用自定义存储,但并没有应用成功。");
}
@Override
@TestOnly
public void saveUserData(@NotNull UserData data) {
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
@@ -1,37 +0,0 @@
package cc.carm.plugin.moeteleport.storage.database;
import cc.carm.plugin.moeteleport.configuration.values.ConfigValue;
public class DBConfiguration {
protected static final ConfigValue<String> DRIVER_NAME = new ConfigValue<>(
"storage.mysql.driver", String.class,
"com.mysql.cj.jdbc.Driver"
);
protected static final ConfigValue<String> HOST = new ConfigValue<>(
"storage.mysql.host", String.class,
"127.0.0.1"
);
protected static final ConfigValue<Integer> PORT = new ConfigValue<>(
"storage.mysql.port", Integer.class,
3306
);
protected static final ConfigValue<String> DATABASE = new ConfigValue<>(
"storage.mysql.database", String.class,
"minecraft"
);
protected static final ConfigValue<String> USERNAME = new ConfigValue<>(
"storage.mysql.username", String.class,
"root"
);
protected static final ConfigValue<String> PASSWORD = new ConfigValue<>(
"storage.mysql.password", String.class,
"password"
);
}
@@ -1,52 +0,0 @@
package cc.carm.plugin.moeteleport.storage.database;
import cc.carm.plugin.moeteleport.configuration.values.ConfigValue;
public class DBTables {
protected static class UserLastLocations {
protected static final ConfigValue<String> TABLE_NAME = new ConfigValue<>(
"storage.mysql.tables.last-location", String.class,
"mt_user_last_locations"
);
protected static final String[] TABLE_COLUMNS = new String[]{
"`uuid` VARCHAR(36) NOT NULL PRIMARY KEY", // 用户的UUID
"`world` VARCHAR(128) NOT NULL",// 最后地址的所在世界
"`x` DOUBLE NOT NULL",// 最后地址的X坐标
"`y` DOUBLE NOT NULL",// 最后地址的Y坐标
"`z` DOUBLE NOT NULL",// 最后地址的Z坐标
"`yaw` DOUBLE NOT NULL",// 最后地址的Yaw角度
"`pitch` DOUBLE NOT NULL",// 最后地址的Pitch角度
"`update` DATETIME NOT NULL " +
"DEFAULT CURRENT_TIMESTAMP " +
"ON UPDATE CURRENT_TIMESTAMP "
};
}
protected static class UserHomes {
protected static final ConfigValue<String> TABLE_NAME = new ConfigValue<>(
"storage.mysql.tables.home", String.class,
"mt_user_homes"
);
protected static final String[] TABLE_COLUMNS = new String[]{
"`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '背包ID'",
"`uuid` VARCHAR(36) NOT NULL", // 用户的UUID
"`name` VARCHAR(32) NOT NULL",
"`world` VARCHAR(128) NOT NULL",
"`x` DOUBLE NOT NULL",
"`y` DOUBLE NOT NULL",
"`z` DOUBLE NOT NULL",
"`yaw` DOUBLE NOT NULL",
"`pitch` DOUBLE NOT NULL",
"INDEX `user`(`uuid`)",
"UNIQUE KEY `home`(`uuid`,`name`)"
};
}
}
@@ -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);
}
}
@@ -2,66 +2,74 @@ 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.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.model.UserData;
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 boolean initialize() {
public void initialize() throws Exception {
Main.info("加载数据库配置...");
Main.getInstance().getConfigProvider().initialize(DatabaseConfig.class);
try {
Main.log(" 尝试连接到数据库...");
String url = String.format("jdbc:mysql://%s:%s/%s?useSSL=false",
DBConfiguration.HOST.get(), DBConfiguration.PORT.get(), DBConfiguration.DATABASE.get()
);
Main.info(" 尝试连接到数据库...");
this.sqlManager = EasySQL.createManager(
DBConfiguration.DRIVER_NAME.get(), url,
DBConfiguration.USERNAME.get(), DBConfiguration.PASSWORD.get()
DatabaseConfig.DRIVER_NAME.getNotNull(), DatabaseConfig.buildJDBC(),
DatabaseConfig.USERNAME.getNotNull(), DatabaseConfig.PASSWORD.getNotNull()
);
this.sqlManager.setDebugMode(() -> Main.getInstance().isDebugging());
} catch (Exception exception) {
Main.error("无法连接到数据库,请检查配置文件");
exception.printStackTrace();
return false;
throw new Exception("无法连接到数据库,请检查配置文件", exception);
}
try {
Main.log(" 创建插件所需表...");
getSQLManager().createTable(DBTables.UserLastLocations.TABLE_NAME.get())
.setColumns(DBTables.UserLastLocations.TABLE_COLUMNS)
.build().execute();
getSQLManager().createTable(DBTables.UserHomes.TABLE_NAME.get())
.setColumns(DBTables.UserHomes.TABLE_COLUMNS)
.build().execute();
Main.info(" 创建插件所需表...");
for (DatabaseTables value : DatabaseTables.values()) {
value.create(this.sqlManager);
}
} catch (SQLException exception) {
Main.error("无法创建插件所需的表,请检查数据库权限。");
exception.printStackTrace();
return false;
throw new Exception("无法创建插件所需的表,请检查数据库权限。", exception);
}
return true;
Main.info(" 加载地标数据...");
try {
this.warpsMap = loadWarps();
} catch (Exception e) {
throw new Exception("无法加载地标数据,请检查数据库权限和相关表。", e);
}
}
@Override
public void shutdown() {
Main.log(" 关闭数据库连接...");
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);
@@ -73,7 +81,7 @@ public class MySQLStorage implements DataStorage {
public void saveUserData(@NotNull UserData data) throws Exception {
Location location = data.getLastLocation();
if (location != null && location.getWorld() != null) {
getSQLManager().createReplace(DBTables.UserLastLocations.TABLE_NAME.get())
DatabaseTables.LAST_LOCATION.createReplace()
.setColumnNames("uuid", "world", "x", "y", "z", "yaw", "pitch")
.setParams(
data.getUserUUID(), location.getWorld().getName(),
@@ -81,14 +89,24 @@ public class MySQLStorage implements DataStorage {
location.getYaw(), location.getPitch()
).execute();
} else {
getSQLManager().createDelete(DBTables.UserLastLocations.TABLE_NAME.get())
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 getSQLManager().createQuery().inTable(DBTables.UserHomes.TABLE_NAME.get())
return DatabaseTables.HOMES.createQuery()
.addCondition("uuid", uuid).build()
.executeFunction((query) -> {
LinkedHashMap<String, DataLocation> homes = new LinkedHashMap<>();
@@ -97,39 +115,42 @@ public class MySQLStorage implements DataStorage {
while (resultSet.next()) {
String name = resultSet.getString("name");
if (name == null) continue;
homes.put(name, new DataLocation(
resultSet.getString("world"),
resultSet.getDouble("x"),
resultSet.getDouble("y"),
resultSet.getDouble("z"),
resultSet.getFloat("yaw"),
resultSet.getFloat("pitch")
));
homes.put(name, readLocation(resultSet));
}
return homes;
}, new LinkedHashMap<>());
}
private @Nullable DataLocation loadLastLocation(@NotNull UUID uuid) throws Exception {
return getSQLManager().createQuery().inTable(DBTables.UserLastLocations.TABLE_NAME.get())
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 new DataLocation(
resultSet.getString("world"),
resultSet.getDouble("x"),
resultSet.getDouble("y"),
resultSet.getDouble("z"),
resultSet.getFloat("yaw"),
resultSet.getFloat("pitch")
);
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 {
getSQLManager().createReplace(DBTables.UserHomes.TABLE_NAME.get())
DatabaseTables.HOMES.createReplace()
.setColumnNames("uuid", "name", "world", "x", "y", "z", "yaw", "pitch")
.setParams(
uuid, homeName, location.getWorldName(),
@@ -141,15 +162,46 @@ public class MySQLStorage implements DataStorage {
@Override
public boolean delHome(@NotNull UUID uuid, @NotNull String homeName) throws Exception {
return getSQLManager().createDelete(DBTables.UserHomes.TABLE_NAME.get())
return DatabaseTables.HOMES.createDelete()
.addCondition("uuid", uuid)
.addCondition("name", homeName)
.setLimit(1)
.build().executeFunction((i) -> i > 0, false);
}
public SQLManager getSQLManager() {
return sqlManager;
@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);
}
}
}
@@ -1,7 +1,8 @@
package cc.carm.plugin.moeteleport.storage.extension;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.model.UserData;
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;
@@ -10,28 +11,63 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class EssentialXStorage extends PluginBasedStorage {
public class EssentialStorage extends PluginBasedStorage {
public EssentialXStorage() {
public EssentialStorage() {
super("Essentials");
}
private Essentials essentials;
@Override
public boolean initialize() {
return super.initialize() && (this.essentials = (Essentials) getDependPlugin()) != null;
}
@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;
return (Essentials) getDependPlugin();
}
public static class EssentialUserData extends UserData {
@@ -71,13 +107,13 @@ public class EssentialXStorage extends PluginBasedStorage {
}
@Override
public void setLastLocation(@Nullable Location lastLocation) {
getEssUser().setLastLocation(lastLocation);
public @Nullable Location getLastLocation() {
return getEssUser().getLastLocation();
}
@Override
public @Nullable Location getLastLocation() {
return getEssUser().getLastLocation();
public void setLastLocation(@Nullable Location lastLocation) {
getEssUser().setLastLocation(lastLocation);
}
@@ -1,8 +1,10 @@
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.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.model.UserData;
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;
@@ -15,7 +17,9 @@ 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 {
@@ -23,11 +27,19 @@ 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.debug("当前文件夾内不存在玩家 " + uuid + " 的数据,视作新档。");
Main.debugging("当前文件夾内不存在玩家 " + uuid + " 的数据,视作新档。");
return null;
}
@@ -68,4 +80,63 @@ public class JSONStorage extends FileBasedStorage {
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;
}
}
@@ -1,21 +1,46 @@
package cc.carm.plugin.moeteleport.storage.file;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.model.UserData;
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()) {
@@ -23,7 +48,7 @@ public class YAMLStorage extends FileBasedStorage {
}
File userDataFile = new File(getDataFolder(), uuid + ".yml");
if (!userDataFile.exists()) {
Main.debug("当前文件夾内不存在玩家 " + uuid + " 的数据,视作新档。");
Main.debugging("当前文件夾内不存在玩家 " + uuid + " 的数据,视作新档。");
return null;
}
@@ -59,4 +84,50 @@ public class YAMLStorage extends FileBasedStorage {
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;
}
}
@@ -1,8 +1,10 @@
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.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.configuration.values.ConfigValue;
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;
@@ -12,23 +14,31 @@ import java.util.UUID;
public abstract class FileBasedStorage implements DataStorage {
private static final ConfigValue<String> FILE_PATH = new ConfigValue<>(
"storage.file-path", String.class, "data"
);
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 boolean initialize() {
try {
this.dataFolder = new File(Main.getInstance().getDataFolder(), FILE_PATH.get());
if (!dataFolder.exists()) {
return dataFolder.mkdir();
} else {
return dataFolder.isDirectory();
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("无法创建数据文件夹!");
}
} catch (Exception ex) {
return false;
} else if (!dataFolder.isDirectory()) {
throw new Exception("数据文件夹路径对应的不是一个文件夹!");
}
}
@@ -49,6 +59,17 @@ public abstract class FileBasedStorage implements DataStorage {
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;
}
@@ -1,12 +1,14 @@
package cc.carm.plugin.moeteleport.storage.impl;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import cc.carm.plugin.moeteleport.model.UserData;
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 {
@@ -18,8 +20,10 @@ public abstract class PluginBasedStorage implements DataStorage {
}
@Override
public boolean initialize() {
return dependPlugin != null;
public void initialize() throws NullPointerException {
if (dependPlugin == null) {
throw new NullPointerException("该存储类型依赖的插件不存在,请检查配置文件");
}
}
public Plugin getDependPlugin() {
@@ -36,6 +40,11 @@ public abstract class PluginBasedStorage implements DataStorage {
// 一般都由其他插件自行保存,不需要实现。
}
@Override
public void saveWarps(@NotNull Map<String, WarpInfo> warps) {
// 一般都由其他插件自行保存,不需要实现。
}
@Override
public void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation homeLocation) {
// 一般都由其他插件自行保存,不需要实现。
@@ -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;
}
}
@@ -1,105 +0,0 @@
package cc.carm.plugin.moeteleport.util;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@SuppressWarnings("ResultOfMethodCallIgnored")
public class JarResourceUtils {
public static final char JAR_SEPARATOR = '/';
public static @Nullable String[] readResource(@Nullable InputStream resourceStream) {
if (resourceStream == null) return null;
try (Scanner scanner = new Scanner(resourceStream, "UTF-8")) {
List<String> contents = new ArrayList<>();
while (scanner.hasNextLine()) {
contents.add(scanner.nextLine());
}
return contents.toArray(new String[0]);
} catch (Exception e) {
return null;
}
}
public static void copyFolderFromJar(String folderName, File destFolder, CopyOption option)
throws IOException {
copyFolderFromJar(folderName, destFolder, option, null);
}
public static void copyFolderFromJar(String folderName, File destFolder,
CopyOption option, PathTrimmer trimmer) throws IOException {
if (!destFolder.exists())
destFolder.mkdirs();
byte[] buffer = new byte[1024];
File fullPath;
String path = JarResourceUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath();
if (trimmer != null)
path = trimmer.trim(path);
try {
if (!path.startsWith("file"))
path = "file://" + path;
fullPath = new File(new URI(path));
} catch (URISyntaxException e) {
e.printStackTrace();
return;
}
ZipInputStream zis = new ZipInputStream(new FileInputStream(fullPath));
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
if (!entry.getName().startsWith(folderName + JAR_SEPARATOR))
continue;
String fileName = entry.getName();
if (fileName.charAt(fileName.length() - 1) == JAR_SEPARATOR) {
File file = new File(destFolder + File.separator + fileName);
if (file.isFile()) {
file.delete();
}
file.mkdirs();
continue;
}
File file = new File(destFolder + File.separator + fileName);
if (option == CopyOption.COPY_IF_NOT_EXIST && file.exists())
continue;
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
if (!file.exists())
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
zis.closeEntry();
zis.close();
}
public enum CopyOption {
COPY_IF_NOT_EXIST, REPLACE_IF_EXIST
}
@FunctionalInterface
public interface PathTrimmer {
String trim(String original);
}
}
@@ -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;
}
}
@@ -1,250 +0,0 @@
package cc.carm.plugin.moeteleport.util;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Callable;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
public class SchedulerUtils {
private final JavaPlugin plugin;
public SchedulerUtils(JavaPlugin plugin) {
this.plugin = plugin;
}
private JavaPlugin getPlugin() {
return this.plugin;
}
public void run(Runnable runnable) {
Bukkit.getScheduler().runTask(this.getPlugin(), runnable);
}
public void runAsync(Runnable runnable) {
Bukkit.getScheduler().runTaskAsynchronously(this.getPlugin(), runnable);
}
public void runLater(long delay, Runnable runnable) {
Bukkit.getScheduler().runTaskLater(this.getPlugin(), runnable, delay);
}
public void runLaterAsync(long delay, Runnable runnable) {
Bukkit.getScheduler().runTaskLaterAsynchronously(this.getPlugin(), runnable, delay);
}
public void runAtInterval(long interval, Runnable... tasks) {
this.runAtInterval(0L, interval, tasks);
}
public void runAtInterval(long delay, long interval, Runnable... tasks) {
(new BukkitRunnable() {
private int index;
public void run() {
if (this.index >= tasks.length) {
this.cancel();
} else {
tasks[this.index].run();
++this.index;
}
}
}).runTaskTimer(this.getPlugin(), delay, interval);
}
public void runAtIntervalAsync(long interval, Runnable... tasks) {
this.runAtIntervalAsync(0L, interval, tasks);
}
public void runAtIntervalAsync(long delay, long interval, Runnable... tasks) {
(new BukkitRunnable() {
private int index;
public void run() {
if (this.index >= tasks.length) {
this.cancel();
} else {
tasks[this.index].run();
++this.index;
}
}
}).runTaskTimerAsynchronously(this.getPlugin(), delay, interval);
}
public void repeat(int repetitions, long interval, Runnable task, Runnable onComplete) {
(new BukkitRunnable() {
private int index;
public void run() {
++this.index;
if (this.index >= repetitions) {
this.cancel();
if (onComplete != null) {
onComplete.run();
}
} else {
task.run();
}
}
}).runTaskTimer(this.getPlugin(), 0L, interval);
}
public void repeatAsync(int repetitions, long interval, Runnable task, Runnable onComplete) {
(new BukkitRunnable() {
private int index;
public void run() {
++this.index;
if (this.index >= repetitions) {
this.cancel();
if (onComplete != null) {
onComplete.run();
}
} else {
task.run();
}
}
}).runTaskTimerAsynchronously(this.getPlugin(), 0L, interval);
}
public void repeatWhile(long interval, Callable<Boolean> predicate, Runnable task, Runnable onComplete) {
(new BukkitRunnable() {
public void run() {
try {
if (!(Boolean)predicate.call()) {
this.cancel();
if (onComplete == null) {
return;
}
onComplete.run();
return;
}
task.run();
} catch (Exception var2) {
var2.printStackTrace();
}
}
}).runTaskTimer(this.getPlugin(), 0L, interval);
}
public void repeatWhileAsync(long interval, Callable<Boolean> predicate, Runnable task, Runnable onComplete) {
(new BukkitRunnable() {
public void run() {
try {
if (!(Boolean)predicate.call()) {
this.cancel();
if (onComplete == null) {
return;
}
onComplete.run();
return;
}
task.run();
} catch (Exception var2) {
var2.printStackTrace();
}
}
}).runTaskTimerAsynchronously(this.getPlugin(), 0L, interval);
}
public class TaskBuilder {
private final Queue<SchedulerUtils.Task> taskList = new LinkedList<>();
public TaskBuilder() {
}
public SchedulerUtils.TaskBuilder append(SchedulerUtils.TaskBuilder builder) {
this.taskList.addAll(builder.taskList);
return this;
}
public SchedulerUtils.TaskBuilder appendDelay(long delay) {
this.taskList.add((onComplete) -> SchedulerUtils.this.runLater(delay, onComplete));
return this;
}
public SchedulerUtils.TaskBuilder appendTask(Runnable task) {
this.taskList.add((onComplete) -> {
task.run();
onComplete.run();
});
return this;
}
public SchedulerUtils.TaskBuilder appendTask(SchedulerUtils.Task task) {
this.taskList.add(task);
return this;
}
public SchedulerUtils.TaskBuilder appendDelayedTask(long delay, Runnable task) {
this.taskList.add((onComplete) -> SchedulerUtils.this.runLater(delay, () -> {
task.run();
onComplete.run();
}));
return this;
}
public SchedulerUtils.TaskBuilder appendTasks(long delay, long interval, Runnable... tasks) {
this.taskList.add((onComplete) -> {
Runnable[] all = Arrays.copyOf(tasks, tasks.length + 1);
all[all.length - 1] = onComplete;
SchedulerUtils.this.runAtInterval(delay, interval, all);
});
return this;
}
public SchedulerUtils.TaskBuilder appendRepeatingTask(int repetitions, long interval, Runnable task) {
this.taskList.add((onComplete) -> SchedulerUtils.this.repeat(repetitions, interval, task, onComplete));
return this;
}
public SchedulerUtils.TaskBuilder appendConditionalRepeatingTask(long interval, Callable<Boolean> predicate, Runnable task) {
this.taskList.add((onComplete) -> SchedulerUtils.this.repeatWhile(interval, predicate, task, onComplete));
return this;
}
public SchedulerUtils.TaskBuilder waitFor(Callable<Boolean> predicate) {
this.taskList.add((onComplete) -> (new BukkitRunnable() {
public void run() {
try {
if (!(Boolean)predicate.call()) {
return;
}
this.cancel();
onComplete.run();
} catch (Exception var2) {
var2.printStackTrace();
}
}
}).runTaskTimer(SchedulerUtils.this.getPlugin(), 0L, 1L));
return this;
}
public void runTasks() {
this.startNext();
}
private void startNext() {
SchedulerUtils.Task task = this.taskList.poll();
if (task != null) {
task.start(this::startNext);
}
}
}
public interface Task {
void start(Runnable onComplete);
}
}
+3 -2
View File
@@ -2,5 +2,6 @@
&d| |___ ___&5|_ _|___| |___ ___ ___ ___| |_
&d| | | | . | -_|&5 | | | -_| | -_| . | . | _| _|
&d|_|_|_|___|___|&5 |_| |___|_|___| _|___|_| |_|
&d &5 |_|
&f 查看更多信息请访问项目主页&d https://github.com/CarmJos/MoeTeleport
&8# &dMoe&5Teleport &5 |_|
&f 当前版本 &d${project.version} &f查看更多信息请访问项目主页
&8 -> &d https://github.com/CarmJos/MoeTeleport
-61
View File
@@ -1,61 +0,0 @@
# ${project.name} - ${project.description}
# 项目地址: ${project.url}
# 下载地址: ${project.distributionManagement.downloadUrl}
version: ${project.version}
debug: false
# 统计数据设定
# 该选项用于帮助开发者统计插件版本与使用情况,且绝不会影响性能与使用体验。
# 当然,您也可以选择在这里关闭,或在plugins/bStats下的配置文件中关闭。
metrics: true
# 检查更新设定
# 该选项用于插件判断是否要检查更新,若您不希望插件检查更新并提示您,可以选择关闭。
# 检查更新为异步操作,绝不会影响性能与使用体验。
check-update: true
# 存储相关配置
# 注意:存储配置不会通过重载指令生效,如有修改请重新启动服务器。
storage:
# 存储方式,可选 [ yaml | json | mysql | Essential(须安装ess插件) ]
method: yaml
# 选择 yaml/json 存储方式时的存储路径
# 默认为相对路径,相对于插件生成的配置文件夹下的路径
# 支持绝对路径,如 “/var/data/ud/"(linux) 或 "D:\data\ud\"(windows)
# 使用绝对路径时请注意权限问题
file-path: data
# 选择 database 存储方式时的数据库配置
mysql:
# 数据库驱动路径
driver: "com.mysql.cj.jdbc.Driver"
# 数据库连接配置
host: "127.0.0.1"
port: 3306
database: "minecraft"
username: "username"
password: "password"
# 插件相关表的名称
tables:
last-location: "mt_last_locations"
home: "mt_homes"
# 默认玩家可设置多少家
defaultHome: 1
permissions:
10: "MoeTeleport.home.vip" # 最多可以设置10个家
# 传送请求过期时间
expireTime: 30
# 返回死亡点
# 开启后将允许玩家输入 /back 返回死亡地点。
death-back: true
# 危险的方块类型,将判断目的地脚下的方块的类型是否在这个列表中
dangerous-blocks:
- LAVA
- AIR
-74
View File
@@ -1,74 +0,0 @@
no-last-location:
- "&f您当前没有进行传送,无法返回上个地点。"
death-back:
- "&f您可以输入 &5/back &f或 [&d&l点击这里](show_text=点击返回到死亡地点 run_command=/back) &f返回您的死亡地点。"
not-online:
- "&f目标玩家并不在线,无法发送请求。"
self-request:
- "&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设置一个吧!"
name-too-long:
- "&f您所输入的家的名字太长,家的名称不应当超过 &d30 &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覆盖之前的家传送点。"
+20 -33
View File
@@ -10,46 +10,33 @@ api-version: 1.13
softdepend:
- PlaceholderAPI
- Essentials
- CMI
permissions:
"MoeTeleport":
description: "插件的主权限节点"
default: false
"MoeTeleport.admin":
description: "插件的管理员权限节点"
default: op
"MoeTeleport.teleport":
description: "使用传送请求相关指令的权限。"
default: true
"MoeTeleport.home":
description: "使用家相关指令的权限。"
default: true
"MoeTeleport.warp":
description: "使用传送请求相关指令的权限。"
default: true
"MoeTeleport.back":
description: "使用返回相关指令的权限。"
default: true
commands:
"MoeTeleport":
description: "插件的主命令,用于重载插件或查看插件信息。"
permission: "MoeTeleport.admin"
usage: "/MoeTeleport reload"
"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: "删除家的传送点。"
usage: "您可以输入 /MoeTeleport help 查看插件的相关帮助。"
aliases:
- mt