├── .documentation ├── README.md ├── javadoc │ └── JAVADOC-README.md └── repository │ └── REPO-README.md ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bugs_report.md │ └── feature_issues.md └── workflows │ ├── deploy.yml │ └── maven.yml ├── .gitignore ├── LICENSE ├── README.md ├── base ├── color │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── cc │ │ │ └── carm │ │ │ └── lib │ │ │ └── easyplugin │ │ │ └── utils │ │ │ └── ColorParser.java │ │ └── test │ │ └── java │ │ └── ColorParseTest.java ├── command-alias │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── cc │ │ └── carm │ │ └── lib │ │ └── easyplugin │ │ └── command │ │ └── alias │ │ ├── AliasCommand.java │ │ └── AliasCommandManager.java ├── command │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── cc │ │ └── carm │ │ └── lib │ │ └── easyplugin │ │ └── command │ │ ├── CommandHandler.java │ │ ├── NamedExecutor.java │ │ ├── SimpleCompleter.java │ │ └── SubCommand.java ├── gui │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── cc │ │ │ └── carm │ │ │ └── lib │ │ │ └── easyplugin │ │ │ └── gui │ │ │ ├── GUI.java │ │ │ ├── GUIItem.java │ │ │ ├── GUIListener.java │ │ │ ├── GUIType.java │ │ │ ├── configuration │ │ │ ├── GUIActionConfiguration.java │ │ │ ├── GUIActionType.java │ │ │ ├── GUIConfiguration.java │ │ │ └── GUIItemConfiguration.java │ │ │ └── paged │ │ │ ├── AutoPagedGUI.java │ │ │ ├── CommonPagedGUI.java │ │ │ └── PagedGUI.java │ │ └── test │ │ └── java │ │ ├── ActionReadTest.java │ │ └── PageTest.java ├── main │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── cc │ │ └── carm │ │ └── lib │ │ └── easyplugin │ │ ├── EasyPlugin.java │ │ ├── i18n │ │ └── EasyPluginMessageProvider.java │ │ └── utils │ │ ├── ItemStackFactory.java │ │ ├── MessageUtils.java │ │ └── SchedulerUtils.java ├── messages │ └── pom.xml ├── storage │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── cc │ │ └── carm │ │ └── lib │ │ └── easyplugin │ │ └── storage │ │ ├── DataStorage.java │ │ ├── StorageType.java │ │ ├── file │ │ ├── FileBasedStorage.java │ │ ├── FolderBasedStorage.java │ │ └── YAMLBasedStorage.java │ │ └── plugin │ │ └── PluginBasedStorage.java ├── user │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── cc │ │ └── carm │ │ └── lib │ │ └── easyplugin │ │ └── user │ │ ├── AbstractUserData.java │ │ ├── UserData.java │ │ ├── UserDataManager.java │ │ └── UserDataRegistry.java └── utils │ ├── pom.xml │ └── src │ └── main │ └── java │ └── cc │ └── carm │ └── lib │ └── easyplugin │ └── utils │ ├── EasyCooldown.java │ └── JarResourceUtils.java ├── collection ├── all │ └── pom.xml ├── bom │ └── pom.xml └── common │ └── pom.xml ├── extension ├── gh-checker │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── cc │ │ │ └── carm │ │ │ └── lib │ │ │ └── easyplugin │ │ │ └── updatechecker │ │ │ └── GHUpdateChecker.java │ │ └── test │ │ └── java │ │ └── cc │ │ └── carm │ │ └── lib │ │ └── easyplugin │ │ └── updatechecker │ │ └── RegexTest.java ├── papi │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── cc │ │ │ └── carm │ │ │ └── lib │ │ │ └── easyplugin │ │ │ └── papi │ │ │ ├── EasyPlaceholder.java │ │ │ ├── expansion │ │ │ ├── EasyExpansion.java │ │ │ ├── SectionExpansion.java │ │ │ └── SubExpansion.java │ │ │ └── handler │ │ │ └── PlaceholderHandler.java │ │ └── test │ │ └── java │ │ └── cc │ │ └── carm │ │ └── tests │ │ └── easyplugin │ │ └── papi │ │ ├── DemoPlaceholder.java │ │ └── PlaceholderTest.java └── vault │ ├── pom.xml │ └── src │ └── main │ └── java │ └── cc │ └── carm │ └── lib │ └── easyplugin │ └── vault │ └── EasyVault.java ├── pom.xml └── renovate.json /.documentation/README.md: -------------------------------------------------------------------------------- 1 | # 欢迎使用 EasyPlugin ! 2 | 3 | 这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~ -------------------------------------------------------------------------------- /.documentation/javadoc/JAVADOC-README.md: -------------------------------------------------------------------------------- 1 | # EasyPlugin Javadoc 2 | 3 | 基于 [Github Pages](https://pages.github.com/) 搭建,请访问 [JavaDoc](https://carmjos.github.io/EasyPlugin) 。 4 | 5 | ## 如何实现? 6 | 7 | 若您也想通过 [Github Actions](https://docs.github.com/en/actions/learn-github-actions) 8 | 自动部署项目的Javadoc到 [Github Pages](https://pages.github.com/) , 9 | 可以参考我的文章 [《自动部署Javadoc到Github Pages》](https://pages.carm.cc/doc/javadoc-in-github.html) 。 -------------------------------------------------------------------------------- /.documentation/repository/REPO-README.md: -------------------------------------------------------------------------------- 1 | # EasyPlugin Repository 2 | 3 | 采用github的repo分支进行依赖,随项目发布而自动更新。 4 | 5 | 其他依赖方式见主页介绍。 6 | 7 | ## 依赖方式 8 | 9 | ### Maven 10 | 11 | ```xml 12 | 13 | 14 | EasyPlugin 15 | GitHub Branch Repository 16 | https://github.com/CarmJos/EasyPlugin/blob/repo/ 17 | 18 | 19 | ``` 20 | 21 | ### Gradle 22 | 23 | ```groovy 24 | repositories { 25 | maven { url 'https://github.com/CarmJos/EasyPlugin/blob/repo/' } 26 | } 27 | ``` -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | #github: [ CarmJos ] 2 | custom: [ 'https://donate.carm.cc' ] -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bugs_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 问题提交 3 | about: 描述问题并提交,帮助我们对其进行检查与修复。 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### **问题简述** 11 | 12 | 用简短的话语描述一下大概问题。 13 | 14 | ### **问题来源** 15 | 16 | 描述一下通过哪些操作才发现的问题,如: 17 | 18 | 1. 使用了 ... 19 | 2. 输入了 ... 20 | 3. 出现了报错 ... 21 | 22 | ### **预期结果**(可选) 23 | 24 | 如果问题不发生,应该是什么情况 25 | 26 | ### **问题截图/问题报错** 27 | 28 | 如果有报错或输出,请提供截图。 29 | 30 | ### **操作环境** 31 | 32 | - 系统环境: `Windows 10` / `Ubuntu` / `...` 33 | - Java版本: `JDK11` / `OPENJDK8` / `JRE8` / `...` 34 | - 服务端版本: 请在后台输入 `version` 并复制相关输出。 35 | 36 | ### **其他补充** 37 | 38 | 如有其他补充,可以在这里描述。 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_issues.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 功能需求 3 | about: 希望我们提供更多的功能。 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### **功能简述** 11 | 12 | 简单的描述一下你想要的功能 13 | 14 | ### **需求来源** 15 | 16 | 简单的描述一下为什么需要这个功能。 17 | 18 | ### **功能参考**(可选) 19 | 20 | 如果有相关功能的参考,如文本、截图,请提供给我们。 21 | 22 | ### **附加内容** 23 | 24 | 如果有什么小细节需要重点注意,请在这里告诉我们。 25 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Deploy & Publish 5 | 6 | on: 7 | # 支持手动触发构建 8 | workflow_dispatch: 9 | release: 10 | # 创建release的时候触发 11 | types: [ published ] 12 | 13 | jobs: 14 | packages-deploy: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: "Set up JDK" 19 | uses: actions/setup-java@v4 20 | with: 21 | java-version: '8' 22 | distribution: 'adopt' 23 | cache: maven 24 | server-id: github 25 | server-username: MAVEN_USERNAME 26 | server-password: MAVEN_TOKEN 27 | 28 | - name: "Maven Deploy" 29 | run: mvn -B -Pgithub deploy --file pom.xml -DskipTests -Dgpg.skip 30 | env: 31 | MAVEN_USERNAME: ${{ github.repository_owner }} 32 | MAVEN_TOKEN: ${{secrets.GITHUB_TOKEN}} 33 | 34 | 35 | github-deploy: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | - name: "Set up JDK" 40 | uses: actions/setup-java@v4 41 | with: 42 | java-version: '8' 43 | distribution: 'adopt' 44 | cache: maven 45 | - name: "Maven Deploy" 46 | run: mvn -B -Plocal deploy --file pom.xml -DskipTests -Dgpg.skip 47 | 48 | - name: "Copy artifacts" 49 | run: | 50 | rm -rf deploy 51 | mkdir -vp deploy 52 | cp -vrf $HOME/local-deploy/* deploy/ 53 | cp -vrf .documentation/repository/REPO-README.md deploy/README.md 54 | 55 | - name: "Generate Javadoc" 56 | run: mvn -B javadoc:aggregate --file pom.xml -DskipTests 57 | 58 | - name: "Copy Javadoc" 59 | run: | 60 | rm -rf docs 61 | mkdir -vp docs 62 | cp -vrf target/reports/apidocs/* docs/ 63 | cp -vrf .documentation/javadoc/JAVADOC-README.md docs/README.md 64 | 65 | - name: "Generate Javadoc sitemap" 66 | id: sitemap 67 | uses: cicirello/generate-sitemap@v1 68 | with: 69 | base-url-path: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }} 70 | path-to-root: docs 71 | 72 | - name: "Output Javadoc stats" 73 | run: | 74 | echo "sitemap-path = ${{ steps.sitemap.outputs.sitemap-path }}" 75 | echo "url-count = ${{ steps.sitemap.outputs.url-count }}" 76 | echo "excluded-count = ${{ steps.sitemap.outputs.excluded-count }}" 77 | ls -l docs 78 | 79 | - name: "Configure Git" 80 | env: 81 | DEPLOY_PRI: ${{secrets.DEPLOY_PRI}} 82 | run: | 83 | sudo timedatectl set-timezone "Asia/Shanghai" 84 | mkdir -p ~/.ssh/ 85 | echo "$DEPLOY_PRI" > ~/.ssh/id_rsa 86 | chmod 600 ~/.ssh/id_rsa 87 | ssh-keyscan github.com >> ~/.ssh/known_hosts 88 | git config --global user.name '${{ github.repository_owner }}' 89 | git config --global user.email '${{ github.repository_owner }}@users.noreply.github.com' 90 | 91 | - name: "Commit&Push repository files" 92 | run: | 93 | cd deploy 94 | git init 95 | git remote add origin git@github.com:${{ github.repository_owner }}/${{ github.event.repository.name }}.git 96 | git checkout -b repo 97 | git add -A 98 | git commit -m "Maven project deployment." 99 | git push origin HEAD:repo --force 100 | 101 | - name: "Commit&Push API documentation" 102 | run: | 103 | cd docs 104 | git init 105 | git remote add origin git@github.com:${{ github.repository_owner }}/${{ github.event.repository.name }}.git 106 | git checkout -b gh-pages 107 | git add -A 108 | git commit -m "API Document generated." 109 | git push origin HEAD:gh-pages --force 110 | 111 | central-deploy: 112 | name: "Deploy Project (Central)" 113 | runs-on: ubuntu-latest 114 | steps: 115 | - uses: actions/checkout@v4 116 | - name: "Set up JDK" 117 | uses: actions/setup-java@v4 118 | with: 119 | java-version: '8' 120 | distribution: 'adopt' 121 | cache: maven 122 | server-id: central 123 | server-username: MAVEN_USERNAME 124 | server-password: MAVEN_PASSWORD 125 | gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import 126 | gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase 127 | 128 | - name: "Central Deploy" 129 | run: mvn -B -Pcentral deploy --file pom.xml -DskipTests 130 | env: 131 | MAVEN_USERNAME: ${{ secrets.OSSRH_USER }} 132 | MAVEN_PASSWORD: ${{ secrets.OSSRH_PASS }} 133 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} 134 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Build & Tests 5 | 6 | on: 7 | # 支持手动触发构建 8 | workflow_dispatch: 9 | push: 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: "Set up JDK" 19 | uses: actions/setup-java@v4 20 | with: 21 | cache: maven 22 | java-version: '8' 23 | distribution: 'adopt' 24 | server-id: github 25 | server-username: MAVEN_USERNAME 26 | server-password: MAVEN_TOKEN 27 | - name: "Package" 28 | run: mvn -B package --file pom.xml -Dmaven.javadoc.skip=true -Dgpg.skip 29 | env: 30 | MAVEN_USERNAME: ${{ github.repository_owner }} 31 | MAVEN_TOKEN: ${{secrets.GITHUB_TOKEN}} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /target/ 3 | /*/target/ 4 | **.iml -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Carm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ```text 2 | ______ ____ __ _ 3 | / ____/___ ________ __ / __ \/ /_ ______ _(_)___ 4 | / __/ / __ `/ ___/ / / / / /_/ / / / / / __ `/ / __ \ 5 | / /___/ /_/ (__ ) /_/ / / ____/ / /_/ / /_/ / / / / / 6 | /_____/\__,_/____/\__, / /_/ /_/\__,_/\__, /_/_/ /_/ 7 | /____/ /____/ 8 | ``` 9 | 10 | # EasyPlugin 11 | 12 | [![version](https://img.shields.io/github/v/release/CarmJos/EasyPlugin)](https://github.com/CarmJos/EasyPlugin/releases) 13 | [![License](https://img.shields.io/github/license/CarmJos/EasyPlugin)](https://opensource.org/licenses/MIT) 14 | [![workflow](https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml) 15 | [![CodeFactor](https://www.codefactor.io/repository/github/carmjos/EasyPlugin/badge)](https://www.codefactor.io/repository/github/carmjos/EasyPlugin) 16 | ![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyPlugin) 17 | ![](https://visitor-badge.glitch.me/badge?page_id=EasyPlugin.readme) 18 | 19 | 轻松(做)插件,旨在于方便快捷的使用Bukkit实现MC中的一些功能。 20 | 21 | ## 优势 22 | 23 | - 轻便独立的功能模块,按需使用,避免大量打包! 24 | - 详细的Javadoc与使用文档,轻松上手,方便使用! 25 | - 持续的更新与优化,需求不止,更新不止! 26 | - 如需新功能支持,请通过 [Issues](https://github.com/CarmJos/EasyPlugin/issues) 提交功能需求。 27 | 28 | ## 内容 29 | 30 | 项目初创不久,加 * 的仍在开发更新中...欢迎各路大佬帮助提供本项目的开发文档~ 31 | 32 | ### 集合部分 (`/collection`) 33 | 34 | - All [`easyplugin-all`](collection/all) 35 | - Common [`easyplugin-common`](collection/common) 36 | 37 | ### 主要部分 (`/base`) 38 | 39 | - Color [`easyplugin-color`](base/color) 40 | - 颜色工具类模块,提供功能全面的MC颜色解析转换工具。 41 | - 支持 `&+颜色代码`(原版颜色)、`§(#XXXXXX)`(RGB颜色) 与 `&<#XXXXXX>`(前后标注RGB颜色渐变)。 42 | - Utils [`easyplugin-utils`](base/utils) 43 | - 通用工具类模块,该模块中的内容支持在Bungee、Bukkit使用。 44 | - 本模块提供 45 | - `ColorParser` 支持RGB颜色与RGB渐变色的颜色解析器。 46 | - `EasyCooldown` 快速创造一个冷却时间的管理器。 47 | - `JarResourceUtils` 快速读取Jar包内容的工具类。 48 | - Main [`easyplugin-main`](base/main) 49 | - 主要接口模块,提供了方便的插件入口类与相关工具类。 50 | - Command [`easyplugin-command`](base/command) 51 | - 指令接口模块,便于快速进行子指令的实现,并提供单独的TabComplete方法。 52 | - 随本项目提供了 `SimpleCompleter` 类,用于快速创建补全的内容列表。 53 | - GUI [`easyplugin-gui`](base/main) 54 | - 简单便捷的箱子GUI接口,可以快速实现GUI中不同图标的点击功能。 55 | - 随本项目提供了 `AutoPagedGUI` 等翻页GUI抽象类。 56 | - Storage [`easyplugin-storage`](base/storage) 57 | - 抽象存储管理器,便于实现不同的存储类型。 58 | - 随本项目提供了 `FileBasedStorage`、`FolderBasedStorage` 等常用存储抽象方法。 59 | - Messages [`easyplugin-message`](base/messages) 60 | - 随本项目提供了基于 MineConfiguration 实现的 `EasyMessages` 类。 61 | - 支持多种消息配置,包括文本消息、ActionBar消息、Title消息、声音、粒子效果播放等。 62 | - 支持消息间的延迟发送。 63 | 64 | ### 独立项目部分 65 | 66 | > 以下项目均已独立出单独项目,如需使用,**强烈建议自行引用对应的项目**,以支持完整的Javadoc并获取源码内容! 67 | 68 | - _Listener_ -> [**EasyListener**](https://github.com/CarmJos/EasyListener) 69 | - _Configuration_ -> [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) 70 | - _Database_ -> [**EasySQL**](https://github.com/CarmJos/EasySQL) 71 | 72 | ### 附属部分 (`/extension`) 73 | 74 | - [PlaceholderAPI](https://www.spigotmc.org/resources/6245/) [`easyplugin-placeholderapi`](extension/papi) 75 | - PlaceholderAPI 扩展模块,提供了方便的 PlaceholderAPI 变量注册方法。 76 | - [Vault](https://github.com/MilkBowl/VaultAPI)* [`easyplugin-vault`](extension/vault) 77 | 78 | ## 开发 79 | 80 | 详细开发介绍请 [点击这里](.documentation/README.md) , JavaDoc(最新Release) 81 | 请 [点击这里](https://carmjos.github.io/EasyPlugin) 。 82 | 83 | ### 示例代码 84 | 85 | 您可以 [点击这里](https://github.com/CarmJos/UltraDepository) 86 | 查看实例项目演示,更多演示详见 [开发介绍](.documentation/README.md) 。 87 | 88 | ### 依赖方式 89 | 90 |
91 | 展开查看 Maven 依赖方式 92 | 93 | ```xml 94 | 95 | 96 | 97 | 98 | 99 | 100 | EasyPlugin 101 | GitHub Packages 102 | https://raw.githubusercontent.com/CarmJos/EasyPlugin/repo/ 103 | 104 | 105 | 106 | 107 | carm-repo 108 | Carm's Repo 109 | https://repo.carm.cc/repository/maven-public/ 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | cc.carm.lib 118 | easyplugin-all 119 | [LATEST RELEASE] 120 | compile 121 | 122 | 123 | 124 | 125 | cc.carm.lib 126 | easyplugin-common 127 | [LATEST RELEASE] 128 | compile 129 | 130 | 131 | 132 | 133 | cc.carm.lib 134 | easyplugin-main 135 | [LATEST RELEASE] 136 | compile 137 | 138 | 139 | 140 | 141 | 142 | 143 | ``` 144 | 145 |
146 | 147 |
148 | 展开查看 Gradle 依赖方式 149 | 150 | ```groovy 151 | repositories { 152 | // 采用github依赖库,安全稳定,但需要配置 (推荐) 153 | maven { url 'https://raw.githubusercontent.com/CarmJos/EasyPlugin/repo/' } 154 | 155 | // 采用我的私人依赖库,简单方便,但可能因为变故而无法使用 156 | maven { url 'https://repo.carm.cc/repository/maven-public/' } 157 | } 158 | 159 | dependencies { 160 | 161 | //大全集版本,包含项目内所有模块 162 | api "cc.carm.lib:easyplugin-all:[LATEST RELEASE]" 163 | 164 | //常用接口集,包含除附属插件模块外的所有模块 165 | api "cc.carm.lib:easyplugin-common:[LATEST RELEASE]" 166 | 167 | //插件主要接口模块,包含方便的插件入口类与相关工具类 168 | api "cc.carm.lib:easyplugin-main:[LATEST RELEASE]" 169 | 170 | // 其他模块自行选择,详见 “内容” 171 | 172 | } 173 | ``` 174 | 175 |
176 | 177 | ## 支持与捐赠 178 | 179 | 若您觉得本插件做的不错,您可以通过捐赠支持我! 180 | 181 | 感谢您对开源项目的支持! 182 | 183 | 184 | 185 | ## 开源协议 186 | 187 | 本项目源码采用 [The MIT License](https://opensource.org/licenses/MIT) 开源协议。 188 |
189 | 关于 MIT 协议 190 | 191 | > MIT 协议可能是几大开源协议中最宽松的一个,核心条款是: 192 | > 193 | > 该软件及其相关文档对所有人免费,可以任意处置,包括使用,复制,修改,合并,发表,分发,再授权,或者销售。唯一的限制是,软件中必须包含上述版 194 | > 权和许可提示。 195 | > 196 | > 这意味着: 197 | > - 你可以自由使用,复制,修改,可以用于自己的项目。 198 | > - 可以免费分发或用来盈利。 199 | > - 唯一的限制是必须包含许可声明。 200 | > 201 | > MIT 协议是所有开源许可中最宽松的一个,除了必须包含许可声明外,再无任何限制。 202 | > 203 | > *以上文字来自 [五种开源协议GPL,LGPL,BSD,MIT,Apache](https://www.oschina.net/question/54100_9455) 。* 204 |
-------------------------------------------------------------------------------- /base/color/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | cc.carm.lib 8 | easyplugin-parent 9 | 1.5.13 10 | ../../pom.xml 11 | 12 | 13 | ${project.jdk.version} 14 | ${project.jdk.version} 15 | UTF-8 16 | UTF-8 17 | 18 | easyplugin-color 19 | 20 | EasyPlugin-Color 21 | 轻松插件颜色模块,支持简单便捷的颜色解析器,包括基本颜色、RGB颜色与RGB渐变颜色。 22 | https://github.com/CarmJos/EasyPlugin 23 | 24 | 25 | 26 | CarmJos 27 | Carm Jos 28 | carm@carm.cc 29 | https://www.carm.cc 30 | 31 | 32 | 33 | 34 | 35 | The MIT License 36 | https://opensource.org/licenses/MIT 37 | 38 | 39 | 40 | 41 | GitHub Issues 42 | https://github.com/CarmJos/EasyPlugin/issues 43 | 44 | 45 | 46 | GitHub Actions 47 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 48 | 49 | 50 | 51 | 52 | 53 | org.apache.maven.plugins 54 | maven-javadoc-plugin 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /base/color/src/main/java/cc/carm/lib/easyplugin/utils/ColorParser.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import java.awt.*; 7 | import java.util.List; 8 | import java.util.*; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | import java.util.stream.Collectors; 12 | import java.util.stream.IntStream; 13 | 14 | /** 15 | * 颜色解析器。 16 | *
普通颜色 格式 {@code &+颜色代码 },如 {@literal &c} 、{@literal &a} 17 | *
RGB颜色(版本需要≥1.14) 格式 {@code &(#XXXXXX) },如 {@literal &(#aaaaaa)} 18 | *
渐变RBG颜色(版本需要≥1.14) 格式 {@code &<#XXXXXX>FOOBAR&<#XXXXXX> } 19 | *

注意:当使用渐变RGB颜色时,普通颜色代码与RGB颜色代码将失效。 20 | */ 21 | public class ColorParser { 22 | 23 | public static final Pattern HEX_PATTERN = Pattern.compile("&\\(&?#([\\da-fA-F]{6})\\)"); 24 | public static final Pattern GRADIENT_PATTERN = Pattern.compile("&<&?#([\\da-fA-F]{6})>"); 25 | public static final Pattern COLOR_PATTERN = Pattern.compile("([&§][0-9a-fA-FrRxX])+"); // 会影响颜色的代码 26 | public static final Pattern FORMAT_PATTERN = Pattern.compile("([&§][0-9a-fA-Fk-oK-OrRxX])+"); // MC可用的格式化代码 27 | 28 | /** 29 | * 清除一条消息中的全部颜色代码 (包括RGB颜色代码与渐变颜色代码) 30 | * 31 | * @param text 源消息内容 32 | * @return 清理颜色后的消息 33 | */ 34 | public static @NotNull String clear(@NotNull String text) { 35 | text = HEX_PATTERN.matcher(text).replaceAll(""); 36 | text = GRADIENT_PATTERN.matcher(text).replaceAll(""); 37 | text = FORMAT_PATTERN.matcher(text).replaceAll(""); 38 | return text; 39 | } 40 | 41 | /** 42 | * 对一条消息进行颜色解析,包括普通颜色代码、RGB颜色代码与RBG渐变代码。 43 | * 44 | * @param text 源消息内容 45 | * @return 解析后的消息 46 | */ 47 | public static @NotNull String parse(@NotNull String text) { 48 | return parseBaseColor(parseGradientColor(parseHexColor(text))); 49 | } 50 | 51 | /** 52 | * 对多条消息进行颜色解析,包括普通颜色代码、RGB颜色代码与RBG渐变代码。 53 | * 54 | * @param texts 源消息内容 55 | * @return 解析后的消息 56 | */ 57 | public static @NotNull String[] parse(@NotNull String... texts) { 58 | return parse(Arrays.asList(texts)).toArray(new String[0]); 59 | } 60 | 61 | /** 62 | * 对多条消息进行颜色解析,包括普通颜色代码、RGB颜色代码与RBG渐变代码。 63 | * 64 | * @param texts 源消息内容 65 | * @return 解析后的消息 66 | */ 67 | public static @NotNull List parse(@NotNull Collection texts) { 68 | return texts.stream().map(ColorParser::parse).collect(Collectors.toList()); 69 | } 70 | 71 | /** 72 | * 解析消息中的基本颜色代码格式 {@code &+颜色代码 },如 {@literal &c} 、{@literal &a} 73 | * 74 | * @param text 消息内容 75 | * @return RGB处理后的消息 76 | * @see net.md_5.bungee.api.ChatColor 77 | */ 78 | public static String parseBaseColor(final String text) { 79 | return text.replaceAll("&", "§").replace("§§", "&"); 80 | } 81 | 82 | /** 83 | * 解析消息中的RGB颜色代码(版本需要≥1.14) 格式 {@code &(#XXXXXX) },如 {@literal &(#aaaaaa)} 84 | * 85 | * @param text 消息内容 86 | * @return RGB处理后的消息 87 | */ 88 | public static String parseHexColor(String text) { 89 | Matcher matcher = HEX_PATTERN.matcher(text); 90 | while (matcher.find()) { 91 | text = matcher.replaceFirst(buildHexColor(matcher.group(1)).toLowerCase()); 92 | matcher.reset(text); 93 | } 94 | return text; 95 | } 96 | 97 | /** 98 | * 对一条消息进行RGB渐变处理(版本需要≥1.14),格式 {@code &<#XXXXXX>FOOBAR&<#XXXXXX> }。 99 | * 100 | * @param text 消息内容 101 | * @return RGB渐变处理后的消息 102 | */ 103 | public static @NotNull String parseGradientColor(@NotNull String text) { 104 | List colors = new ArrayList<>(); 105 | 106 | Matcher matcher = ColorParser.GRADIENT_PATTERN.matcher(text); 107 | while (matcher.find()) colors.add(matcher.group(1)); 108 | 109 | if (colors.isEmpty()) return text; // 无渐变颜色,直接跳出 110 | 111 | String[] parts = ColorParser.GRADIENT_PATTERN.split(text); 112 | StringBuilder builder = new StringBuilder(); 113 | for (int i = 0; i < parts.length; i++) { 114 | String startHex = i - 1 >= 0 && colors.size() > i - 1 ? colors.get(i - 1) : null; // 本条消息的起始颜色 115 | String endHex = colors.size() > i ? colors.get(i) : null; // 本条消息的结束颜色 116 | builder.append(gradientText(parts[i], startHex, endHex)); 117 | } 118 | 119 | return builder.toString(); 120 | } 121 | 122 | public static @NotNull String gradientText(@NotNull String text, 123 | @Nullable Color startColor, @Nullable Color endColor) { 124 | Objects.requireNonNull(text, "Text to be gradient should not be null!"); 125 | if (startColor == null || endColor == null || text.isEmpty()) { 126 | // 起始颜色有任一为空,则不进行渐变上色。 127 | // 若有起始颜色,则代表其跟在某个渐变之后,应当添加"&r"阻断前面的渐变。 128 | return (startColor != null ? "&r" : "") + text; 129 | } 130 | 131 | // 用于记录消息中特殊格式的位置 132 | // 在渐变中,允许使用格式字符与颜色字符来改变其中某个字的颜色/格式,以支持更多形式内容。 133 | LinkedHashMap extraFormats = new LinkedHashMap<>(); 134 | Matcher matcher = ColorParser.FORMAT_PATTERN.matcher(text); 135 | while (matcher.find()) { 136 | extraFormats.put(matcher.start(), matcher.group()); 137 | text = matcher.replaceFirst(""); 138 | matcher.reset(text); 139 | } 140 | 141 | if (text.length() == 1) { 142 | // 当只有一个实际字符时,无需进行渐变计算,直接返回 中间颜色+起始格式(如果有)+消息 即可。 143 | return colorText(text, extraFormats.get(0), buildHexColor(mediumHex(startColor, endColor))); 144 | } 145 | 146 | String[] characters = text.split(""); 147 | int step = characters.length; // 变换次数 148 | 149 | // 决定每种颜色变换的方向 150 | int rDirection = startColor.getRed() < endColor.getRed() ? 1 : -1; 151 | int gDirection = startColor.getGreen() < endColor.getGreen() ? 1 : -1; 152 | int bDirection = startColor.getBlue() < endColor.getBlue() ? 1 : -1; 153 | 154 | // 决定每种颜色每次变换的度 155 | int rStep = Math.abs(startColor.getRed() - endColor.getRed()) / (step - 1); 156 | int gStep = Math.abs(startColor.getGreen() - endColor.getGreen()) / (step - 1); 157 | int bStep = Math.abs(startColor.getBlue() - endColor.getBlue()) / (step - 1); 158 | 159 | String[] hexes = IntStream.range(0, step).mapToObj(i -> colorToHex( 160 | startColor.getRed() + rStep * i * rDirection, 161 | startColor.getGreen() + gStep * i * gDirection, 162 | startColor.getBlue() + bStep * i * bDirection 163 | )).toArray(String[]::new); 164 | 165 | StringBuilder sb = new StringBuilder(); 166 | String extra = null; 167 | for (int i = 0; i < characters.length; i++) { 168 | extra = buildExtraFormat(extra, extraFormats.get(i)); 169 | String s = colorText(characters[i], extra, buildHexColor(hexes[i])); 170 | sb.append(s); 171 | } 172 | return sb.toString(); 173 | } 174 | 175 | protected static String gradientText(@NotNull String text, @Nullable String startHex, @Nullable String endHex) { 176 | return gradientText(text, 177 | startHex == null ? null : Color.decode("0x" + startHex), 178 | endHex == null ? null : Color.decode("0x" + endHex) 179 | ); 180 | } 181 | 182 | private static String mediumHex(@NotNull Color start, @NotNull Color end) { 183 | return colorToHex( 184 | Math.abs(start.getRed() - end.getRed()) / 2, 185 | Math.abs(start.getGreen() - end.getGreen()) / 2, 186 | Math.abs(start.getBlue() - end.getBlue()) / 2 187 | ); 188 | } 189 | 190 | private static String colorText(String message, @Nullable String format, @Nullable String color) { 191 | if (format != null && COLOR_PATTERN.matcher(format).find()) { 192 | // format中存在影响颜色的内容,则当前消息的颜色会被覆盖。 193 | // 为了减少最终消息的长度,故直接返回键入的FORMAT和对应消息的内容。 194 | return format + message; 195 | } 196 | return (color == null ? "" : color) + (format == null ? "" : parseBaseColor(format)) + message; 197 | } 198 | 199 | protected static String colorToHex(Color color) { 200 | return colorToHex(color.getRed(), color.getGreen(), color.getBlue()); 201 | } 202 | 203 | protected static String colorToHex(int r, int g, int b) { 204 | // 将R、G、B转换为16进制(若非2位则补0)输出 205 | return String.format("%02X%02X%02X", r, g, b); 206 | } 207 | 208 | protected static String buildHexColor(String hexCode) { 209 | return Arrays.stream(hexCode.split("")).map(s -> '§' + s) 210 | .collect(Collectors.joining("", '§' + "x", "")); 211 | } 212 | 213 | protected static String buildExtraFormat(String current, String extra) { 214 | if (extra != null) current = (current == null ? "" : current) + extra; 215 | return isResetCode(current) ? null : current; 216 | } 217 | 218 | protected static boolean isResetCode(String input) { 219 | return input != null && (input.toLowerCase().endsWith("&r") || input.toLowerCase().endsWith("§r")); 220 | } 221 | 222 | } -------------------------------------------------------------------------------- /base/color/src/test/java/ColorParseTest.java: -------------------------------------------------------------------------------- 1 | import cc.carm.lib.easyplugin.utils.ColorParser; 2 | import org.junit.Test; 3 | 4 | import java.util.LinkedHashMap; 5 | import java.util.regex.Matcher; 6 | 7 | import static cc.carm.lib.easyplugin.utils.ColorParser.*; 8 | 9 | public class ColorParseTest { 10 | 11 | 12 | @Test 13 | public void test() { 14 | System.out.println(" "); 15 | System.out.println(parseGradientColor("&<#AAAAAA>我真的&<#BBBBBB>爱死&<#111111>你&<#FFFFFF>!")); 16 | 17 | // 测试穿插 18 | System.out.println(parse("&<#AAAAAA>&l&m我真的&o尊的&r真的&<#BBBBBB>&o爱死&<#111111>你&<#FFFFFF>了&r!")); 19 | System.out.println(parse("&<#AAAAAA>&l我&r真&(#666666)的&<#BBBBBB>&o爱死&<#111111>你&<#FFFFFF>了&r!")); 20 | System.out.println(parse("&r正常的颜色理应&c&l不受影响&r。")); 21 | 22 | System.out.println(clear("&f&l测试&<#AAAAAA>清理颜色代码&<#111111> &&这样应该&(#666666)不被影响 &f。")); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /base/command-alias/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | cc.carm.lib 8 | easyplugin-parent 9 | 1.5.13 10 | ../../pom.xml 11 | 12 | 13 | ${project.jdk.version} 14 | ${project.jdk.version} 15 | UTF-8 16 | UTF-8 17 | 18 | easyplugin-command-alias 19 | jar 20 | 21 | EasyPlugin-Command-Alias 22 | 轻松插件指令别名映射模块,支持将插件内复杂的子指令简化为一个单独的指令,方便玩家使用。 23 | https://github.com/CarmJos/EasyPlugin 24 | 25 | 26 | 27 | CarmJos 28 | Carm Jos 29 | carm@carm.cc 30 | https://www.carm.cc 31 | 32 | 33 | 34 | 35 | 36 | The MIT License 37 | https://opensource.org/licenses/MIT 38 | 39 | 40 | 41 | 42 | GitHub Issues 43 | https://github.com/CarmJos/EasyPlugin/issues 44 | 45 | 46 | 47 | GitHub Actions 48 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-javadoc-plugin 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /base/command-alias/src/main/java/cc/carm/lib/easyplugin/command/alias/AliasCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.command.alias; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.command.Command; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.command.SimpleCommandMap; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Optional; 13 | 14 | public class AliasCommand extends Command { 15 | 16 | protected final AliasCommandManager aliasCommandManager; 17 | protected final String targetCommand; 18 | 19 | public AliasCommand(String name, AliasCommandManager aliasCommandManager, String targetCommand) { 20 | super(name); 21 | this.aliasCommandManager = aliasCommandManager; 22 | this.targetCommand = targetCommand; 23 | } 24 | 25 | protected SimpleCommandMap getCommandMap() { 26 | return this.aliasCommandManager.getCommandMap(); 27 | } 28 | 29 | protected String buildCommand(String[] args) { 30 | return this.targetCommand + " " + String.join(" ", args); 31 | } 32 | 33 | @Override 34 | public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { 35 | return getCommandMap().dispatch(sender, buildCommand(args)); 36 | } 37 | 38 | @NotNull 39 | @Override 40 | public List tabComplete(@NotNull CommandSender sender, @NotNull String alias, 41 | @NotNull String[] args, @Nullable Location location) throws IllegalArgumentException { 42 | return Optional.ofNullable(getCommandMap().tabComplete(sender, buildCommand(args))).orElse(Collections.emptyList()); 43 | } 44 | 45 | @NotNull 46 | @Override 47 | public List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException { 48 | return tabComplete(sender, alias, args, null); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /base/command-alias/src/main/java/cc/carm/lib/easyplugin/command/alias/AliasCommandManager.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.command.alias; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.command.Command; 5 | import org.bukkit.command.SimpleCommandMap; 6 | import org.bukkit.plugin.SimplePluginManager; 7 | import org.bukkit.plugin.java.JavaPlugin; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import java.lang.reflect.Field; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * 指令简化别名(简化映射)管理器 16 | *
支持将插件内复杂的子指令简化为一个单独的指令,方便玩家使用。 17 | */ 18 | public class AliasCommandManager { 19 | 20 | protected final @NotNull JavaPlugin plugin; 21 | protected final @NotNull String prefix; 22 | 23 | protected final @NotNull SimpleCommandMap commandMap; 24 | protected final @NotNull Field knownCommandsFiled; 25 | 26 | protected final @NotNull Map registeredCommands = new HashMap<>(); 27 | 28 | public AliasCommandManager(@NotNull JavaPlugin plugin) throws Exception { 29 | this(plugin, plugin.getName()); 30 | } 31 | 32 | public AliasCommandManager(@NotNull JavaPlugin plugin, @NotNull String prefix) throws Exception { 33 | this.plugin = plugin; 34 | this.prefix = prefix.trim(); 35 | 36 | SimplePluginManager manager = (SimplePluginManager) Bukkit.getPluginManager(); 37 | Field commandMapField = SimplePluginManager.class.getDeclaredField("commandMap"); 38 | commandMapField.setAccessible(true); 39 | this.commandMap = (SimpleCommandMap) commandMapField.get(manager); 40 | 41 | this.knownCommandsFiled = SimpleCommandMap.class.getDeclaredField("knownCommands"); 42 | this.knownCommandsFiled.setAccessible(true); 43 | } 44 | 45 | @SuppressWarnings("unchecked") 46 | protected Map getKnownCommands() { 47 | try { 48 | return (Map) knownCommandsFiled.get(commandMap); 49 | } catch (IllegalAccessException e) { 50 | e.printStackTrace(); 51 | } 52 | return new HashMap<>(); 53 | } 54 | 55 | protected @NotNull SimpleCommandMap getCommandMap() { 56 | return commandMap; 57 | } 58 | 59 | public String getCommandPrefix() { 60 | return this.prefix; 61 | } 62 | 63 | public void register(@NotNull String alias, @NotNull String subCommand) { 64 | AliasCommand current = this.registeredCommands.get(alias); 65 | if (current != null) current.unregister(getCommandMap()); 66 | 67 | AliasCommand cmd = new AliasCommand(alias, this, getCommandPrefix() + " " + subCommand); 68 | this.registeredCommands.put(alias, cmd); 69 | getCommandMap().register(plugin.getName(), cmd); 70 | } 71 | 72 | public void unregister(@NotNull String alias) { 73 | AliasCommand current = this.registeredCommands.remove(alias); 74 | if (current != null) { 75 | getKnownCommands().remove(alias); 76 | current.unregister(getCommandMap()); 77 | } 78 | } 79 | 80 | public void unregisterAll() { 81 | registeredCommands.forEach((k, v) -> { 82 | getKnownCommands().remove(k); 83 | v.unregister(getCommandMap()); 84 | }); 85 | registeredCommands.clear(); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /base/command/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | ${project.jdk.version} 14 | ${project.jdk.version} 15 | UTF-8 16 | UTF-8 17 | 18 | easyplugin-command 19 | jar 20 | 21 | EasyPlugin-Command 22 | 轻松插件指令接口模块,方便快捷的编写子指令。 23 | https://github.com/CarmJos/EasyPlugin 24 | 25 | 26 | 27 | CarmJos 28 | Carm Jos 29 | carm@carm.cc 30 | https://www.carm.cc 31 | 32 | 33 | 34 | 35 | 36 | The MIT License 37 | https://opensource.org/licenses/MIT 38 | 39 | 40 | 41 | 42 | GitHub Issues 43 | https://github.com/CarmJos/EasyPlugin/issues 44 | 45 | 46 | 47 | GitHub Actions 48 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-javadoc-plugin 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /base/command/src/main/java/cc/carm/lib/easyplugin/command/CommandHandler.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.command; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandSender; 5 | import org.bukkit.command.TabExecutor; 6 | import org.bukkit.plugin.java.JavaPlugin; 7 | import org.bukkit.util.StringUtil; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.util.*; 12 | import java.util.stream.Collectors; 13 | 14 | @SuppressWarnings("UnusedReturnValue") 15 | public abstract class CommandHandler implements TabExecutor, NamedExecutor { 16 | 17 | protected final @NotNull JavaPlugin plugin; 18 | protected final @NotNull String cmd; 19 | protected final @NotNull List aliases; 20 | 21 | protected final @NotNull Map> registeredCommands = new HashMap<>(); 22 | protected final @NotNull Map registeredHandlers = new HashMap<>(); 23 | 24 | protected final @NotNull Map aliasesMap = new HashMap<>(); 25 | 26 | public CommandHandler(@NotNull JavaPlugin plugin) { 27 | this(plugin, plugin.getName()); 28 | } 29 | 30 | public CommandHandler(@NotNull JavaPlugin plugin, @NotNull String cmd) { 31 | this(plugin, cmd, new String[0]); 32 | } 33 | 34 | public CommandHandler(@NotNull JavaPlugin plugin, @NotNull String cmd, @NotNull String... aliases) { 35 | this.plugin = plugin; 36 | this.cmd = cmd; 37 | this.aliases = Arrays.asList(aliases); 38 | } 39 | 40 | public abstract Void noArgs(CommandSender sender); 41 | 42 | public Void unknownCommand(CommandSender sender, String[] args) { 43 | return noArgs(sender); 44 | } 45 | 46 | public abstract Void noPermission(CommandSender sender); 47 | 48 | public Void onException(CommandSender sender, SubCommand cmd, Exception ex) { 49 | sender.sendMessage("Error occurred when executing " + cmd.getIdentifier() + ": " + ex.getLocalizedMessage()); 50 | ex.printStackTrace(); 51 | return null; 52 | } 53 | 54 | @Override 55 | public @NotNull List getAliases() { 56 | return aliases; 57 | } 58 | 59 | @Override 60 | public @NotNull String getIdentifier() { 61 | return this.cmd; 62 | } 63 | 64 | public void registerSubCommand(SubCommand command) { 65 | String name = command.getIdentifier().toLowerCase(); 66 | this.registeredCommands.put(name, command); 67 | command.getAliases().forEach(alias -> this.aliasesMap.put(alias.toLowerCase(), name)); 68 | } 69 | 70 | public void registerHandler(CommandHandler handler) { 71 | String name = handler.getIdentifier().toLowerCase(); 72 | this.registeredHandlers.put(name, handler); 73 | handler.getAliases().forEach(alias -> this.aliasesMap.put(alias.toLowerCase(), name)); 74 | } 75 | 76 | @Override 77 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 78 | if (!this.hasPermission(sender)) { 79 | noPermission(sender); 80 | return true; 81 | } 82 | 83 | if (args.length == 0) { 84 | this.noArgs(sender); 85 | return true; 86 | } 87 | 88 | String input = args[0].toLowerCase(); 89 | 90 | CommandHandler handler = getHandler(input); 91 | if (handler != null) { 92 | if (!handler.hasPermission(sender)) { 93 | this.noPermission(sender); 94 | } else { 95 | handler.onCommand(sender, command, label, this.shortenArgs(args)); 96 | } 97 | return true; 98 | } 99 | 100 | SubCommand sub = getSubCommand(input); 101 | if (sub == null) { 102 | this.unknownCommand(sender, args); 103 | } else if (!sub.hasPermission(sender)) { 104 | this.noPermission(sender); 105 | } else { 106 | try { 107 | sub.execute(this.plugin, sender, this.shortenArgs(args)); 108 | } catch (Exception ex) { 109 | this.onException(sender, sub, ex); 110 | } 111 | } 112 | 113 | return true; 114 | } 115 | 116 | @Override 117 | public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { 118 | if (args.length == 0) return Collections.emptyList(); 119 | 120 | String input = args[0].toLowerCase(); 121 | if (args.length == 1) { 122 | return getExecutors().stream() 123 | .filter(e -> e.hasPermission(sender)) 124 | .map(NamedExecutor::getIdentifier) 125 | .filter(s -> StringUtil.startsWithIgnoreCase(s, input)) 126 | .collect(Collectors.toList()); 127 | } else { 128 | 129 | CommandHandler handler = getHandler(input); 130 | if (handler != null && handler.hasPermission(sender)) { 131 | return handler.onTabComplete(sender, command, alias, this.shortenArgs(args)); 132 | } 133 | 134 | SubCommand sub = getSubCommand(input); 135 | if (sub != null && sub.hasPermission(sender)) { 136 | return sub.tabComplete(this.plugin, sender, this.shortenArgs(args)); 137 | } 138 | 139 | return Collections.emptyList(); 140 | } 141 | } 142 | 143 | public List getExecutors() { 144 | Set executors = new HashSet<>(); 145 | executors.addAll(this.registeredHandlers.values()); 146 | executors.addAll(this.registeredCommands.values()); 147 | List sortedExecutors = new ArrayList<>(executors); 148 | sortedExecutors.sort(Comparator.comparing(NamedExecutor::getIdentifier)); 149 | return sortedExecutors; 150 | } 151 | 152 | protected @Nullable CommandHandler getHandler(@NotNull String name) { 153 | CommandHandler fromName = this.registeredHandlers.get(name); 154 | if (fromName != null) return fromName; 155 | 156 | String nameFromAlias = this.aliasesMap.get(name); 157 | if (nameFromAlias == null) return null; 158 | else return this.registeredHandlers.get(nameFromAlias); 159 | } 160 | 161 | protected @Nullable SubCommand getSubCommand(@NotNull String name) { 162 | SubCommand fromName = this.registeredCommands.get(name); 163 | if (fromName != null) return fromName; 164 | 165 | String nameFromAlias = this.aliasesMap.get(name); 166 | if (nameFromAlias == null) return null; 167 | else return this.registeredCommands.get(nameFromAlias); 168 | } 169 | 170 | protected String[] shortenArgs(String[] args) { 171 | if (args.length == 0) { 172 | return args; 173 | } else { 174 | List argList = new ArrayList<>(Arrays.asList(args).subList(1, args.length)); 175 | return argList.toArray(new String[0]); 176 | } 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /base/command/src/main/java/cc/carm/lib/easyplugin/command/NamedExecutor.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.command; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.Optional; 10 | import java.util.function.Function; 11 | 12 | public interface NamedExecutor { 13 | 14 | @NotNull String getIdentifier(); 15 | 16 | @NotNull List getAliases(); 17 | 18 | default boolean hasPermission(@NotNull CommandSender sender) { 19 | return true; 20 | } 21 | 22 | default Void sendMessage(@NotNull CommandSender sender, @NotNull String... messages) { 23 | return sendMessage(sender, Function.identity(), messages); 24 | } 25 | 26 | default Void sendMessage(@NotNull CommandSender sender, 27 | @Nullable Function parser, 28 | @NotNull String... messages) { 29 | if (messages == null || messages.length == 0) return null; 30 | Function finalParser = Optional.ofNullable(parser).orElse(Function.identity()); 31 | Arrays.stream(messages).map(finalParser).forEach(sender::sendMessage); 32 | return null; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /base/command/src/main/java/cc/carm/lib/easyplugin/command/SimpleCompleter.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.command; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.Material; 6 | import org.bukkit.OfflinePlayer; 7 | import org.bukkit.World; 8 | import org.bukkit.enchantments.Enchantment; 9 | import org.bukkit.entity.HumanEntity; 10 | import org.bukkit.potion.PotionEffectType; 11 | import org.bukkit.util.StringUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.Arrays; 15 | import java.util.Collection; 16 | import java.util.List; 17 | import java.util.Objects; 18 | import java.util.stream.Collectors; 19 | import java.util.stream.Stream; 20 | 21 | public class SimpleCompleter { 22 | 23 | public static @NotNull List none() { 24 | return ImmutableList.of(); 25 | } 26 | 27 | public static @NotNull List objects(@NotNull String input, Collection objects) { 28 | return objects(input, objects.size(), objects); 29 | } 30 | 31 | public static @NotNull List objects(@NotNull String input, int limit, Collection objects) { 32 | return objects(input, limit, objects.stream()); 33 | } 34 | 35 | public static @NotNull List objects(@NotNull String input, Stream stream) { 36 | return objects(input, 20, stream); 37 | } 38 | 39 | public static @NotNull List objects(@NotNull String input, int limit, Stream stream) { 40 | return stream.filter(Objects::nonNull).map(Object::toString) 41 | .filter(s -> StringUtil.startsWithIgnoreCase(s, input)) 42 | .limit(Math.max(0, limit)).collect(Collectors.toList()); 43 | } 44 | 45 | public static @NotNull List text(@NotNull String input, String... texts) { 46 | return text(input, texts.length, texts); 47 | } 48 | 49 | public static @NotNull List text(@NotNull String input, int limit, String... texts) { 50 | return text(input, limit, Arrays.asList(texts)); 51 | } 52 | 53 | public static @NotNull List text(@NotNull String input, Collection texts) { 54 | return text(input, texts.size(), texts); 55 | } 56 | 57 | public static @NotNull List text(@NotNull String input, int limit, Collection texts) { 58 | return objects(input, limit, texts); 59 | } 60 | 61 | public static @NotNull List onlinePlayers(@NotNull String input) { 62 | return onlinePlayers(input, 10); 63 | } 64 | 65 | public static @NotNull List onlinePlayers(@NotNull String input, int limit) { 66 | return objects(input, limit, Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName)); 67 | } 68 | 69 | public static @NotNull List allPlayers(@NotNull String input) { 70 | return allPlayers(input, 10); 71 | } 72 | 73 | public static @NotNull List allPlayers(@NotNull String input, int limit) { 74 | return objects(input, limit, Arrays.stream(Bukkit.getOfflinePlayers()).map(OfflinePlayer::getName)); 75 | } 76 | 77 | public static @NotNull List worlds(@NotNull String input) { 78 | return worlds(input, 10); 79 | } 80 | 81 | public static @NotNull List worlds(@NotNull String input, int limit) { 82 | return objects(input, limit, Bukkit.getWorlds().stream().map(World::getName)); 83 | } 84 | 85 | public static @NotNull List materials(@NotNull String input) { 86 | return materials(input, 10); 87 | } 88 | 89 | public static @NotNull List materials(@NotNull String input, int limit) { 90 | return objects(input, limit, Arrays.stream(Material.values()).map(Enum::name)); 91 | } 92 | 93 | public static @NotNull List effects(@NotNull String input) { 94 | return effects(input, 10); 95 | } 96 | 97 | public static @NotNull List effects(@NotNull String input, int limit) { 98 | return objects(input, limit, Arrays.stream(PotionEffectType.values()).map(PotionEffectType::getName)); 99 | } 100 | 101 | public static @NotNull List enchantments(@NotNull String input) { 102 | return effects(input, 10); 103 | } 104 | 105 | @SuppressWarnings("deprecation") 106 | public static @NotNull List enchantments(@NotNull String input, int limit) { 107 | return objects(input, limit, Arrays.stream(Enchantment.values()).map(Enchantment::getName)); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /base/command/src/main/java/cc/carm/lib/easyplugin/command/SubCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.command; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.plugin.java.JavaPlugin; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Unmodifiable; 7 | 8 | import java.util.Arrays; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | @SuppressWarnings("UnusedReturnValue") 13 | public abstract class SubCommand implements NamedExecutor { 14 | 15 | private final @NotNull C parent; 16 | 17 | private final String identifier; 18 | private final List aliases; 19 | 20 | public SubCommand(@NotNull C parent, String identifier, String... aliases) { 21 | this.parent = parent; 22 | this.identifier = identifier; 23 | this.aliases = Arrays.asList(aliases); 24 | } 25 | 26 | public @NotNull C getParent() { 27 | return parent; 28 | } 29 | 30 | @Override 31 | public @NotNull String getIdentifier() { 32 | return this.identifier; 33 | } 34 | 35 | @Override 36 | @Unmodifiable 37 | public @NotNull List getAliases() { 38 | return this.aliases; 39 | } 40 | 41 | public abstract Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception; 42 | 43 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 44 | return Collections.emptyList(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /base/gui/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | 14 | ${project.jdk.version} 15 | ${project.jdk.version} 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | easyplugin-gui 21 | jar 22 | 23 | EasyPlugin-GUI 24 | 轻松插件GUI接口模块,方便快捷的创建箱子GUI界面。 25 | https://github.com/CarmJos/EasyPlugin 26 | 27 | 28 | 29 | CarmJos 30 | Carm Jos 31 | carm@carm.cc 32 | https://www.carm.cc 33 | 34 | 35 | 36 | 37 | 38 | The MIT License 39 | https://opensource.org/licenses/MIT 40 | 41 | 42 | 43 | 44 | GitHub Issues 45 | https://github.com/CarmJos/EasyPlugin/issues 46 | 47 | 48 | 49 | GitHub Actions 50 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 51 | 52 | 53 | 54 | 55 | ${project.parent.groupId} 56 | easyplugin-main 57 | ${project.parent.version} 58 | provided 59 | 60 | 61 | 62 | 63 | 64 | 65 | org.apache.maven.plugins 66 | maven-javadoc-plugin 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/GUI.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui; 2 | 3 | import cc.carm.lib.easyplugin.utils.ColorParser; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.Material; 6 | import org.bukkit.entity.HumanEntity; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.inventory.InventoryClickEvent; 9 | import org.bukkit.event.inventory.InventoryDragEvent; 10 | import org.bukkit.inventory.Inventory; 11 | import org.bukkit.inventory.ItemStack; 12 | import org.bukkit.plugin.java.JavaPlugin; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.*; 17 | import java.util.stream.IntStream; 18 | 19 | public class GUI { 20 | 21 | private static JavaPlugin plugin; 22 | private static final Map openedGUIs = new HashMap<>(); 23 | 24 | public static void initialize(JavaPlugin plugin) { 25 | GUI.plugin = plugin; 26 | } 27 | 28 | public static JavaPlugin getPlugin() { 29 | return plugin; 30 | } 31 | 32 | public static Map getOpenedGUIs() { 33 | return openedGUIs; 34 | } 35 | 36 | protected final @NotNull GUIType type; 37 | protected @NotNull String title; 38 | protected Inventory inv; 39 | 40 | protected final SortedMap items = new TreeMap<>(); 41 | protected ItemStack emptyItem = null; 42 | 43 | protected boolean cancelOnTarget = true; // 当玩家点击GUI时是否取消对应事件 44 | protected boolean cancelOnSelf = true; // 当玩家点击自己背包时是否取消对应事件 45 | protected boolean cancelOnOuter = true; // 当玩家点击界面外时是否取消对应事件 46 | 47 | protected final Map flags = new LinkedHashMap<>(); 48 | 49 | protected GUIListener listener; 50 | 51 | public GUI(@NotNull GUIType type, @NotNull String title) { 52 | this.type = type; 53 | this.title = ColorParser.parse(title); 54 | } 55 | 56 | public SortedMap<@NotNull Integer, @NotNull GUIItem> getItems() { 57 | return items; 58 | } 59 | 60 | public final void setItem(int index, @Nullable GUIItem item) { 61 | if (item == null) { 62 | this.items.remove(index); 63 | } else { 64 | this.items.put(index, item); 65 | } 66 | } 67 | 68 | public void setItemStack(int index, @Nullable ItemStack item) { 69 | setItem(index, item == null ? null : new GUIItem(item)); 70 | } 71 | 72 | public void setItem(GUIItem item, int... index) { 73 | for (int i : index) { 74 | setItem(i, item); 75 | } 76 | } 77 | 78 | public void setItemStack(ItemStack item, int... index) { 79 | for (int i : index) { 80 | setItemStack(i, item); 81 | } 82 | } 83 | 84 | /** 85 | * 设置GUI上方(箱子部分) 86 | * @param row 行数,1为第1行 87 | * @param column 列数,1为第1列 88 | * @param item GUIItem 89 | */ 90 | public void setItem(int row, int column, @NotNull GUIItem item){ 91 | if(row <= 0 || column <= 0) throw new IllegalArgumentException("行数和列数都不能小于等于零"); 92 | if(row > type.getLines()) throw new IllegalArgumentException("行数("+row+")大于GUI大小限制("+type.getLines()+")"); 93 | if(column > 9) throw new IllegalArgumentException("列数("+column+")不能大于9"); 94 | setItem(9*(row-1)+column-1, item); 95 | } 96 | 97 | public GUIItem getItem(int index) { 98 | return this.items.get(index); 99 | } 100 | 101 | public void setEmptyItem(ItemStack item) { 102 | this.emptyItem = item; 103 | } 104 | 105 | protected void fillEmptySlots(@NotNull Inventory inventory) { 106 | if (emptyItem == null) return; 107 | IntStream.range(0, inventory.getSize()) 108 | .filter(i -> inventory.getItem(i) == null) 109 | .forEach(index -> inventory.setItem(index, emptyItem)); 110 | } 111 | 112 | protected void applyToInventory(Inventory inventory) { 113 | IntStream.range(0, inventory.getSize()).forEach(index -> inventory.setItem(index, new ItemStack(Material.AIR))); 114 | getItems().forEach((index, item) -> inventory.setItem(index, item.getDisplay())); 115 | fillEmptySlots(inventory); 116 | } 117 | 118 | public void updateTitle(@NotNull String title) { 119 | this.title = ColorParser.parse(title); 120 | if (this.inv != null) { 121 | this.inv = Bukkit.createInventory(null, this.type.getSize(), this.title); 122 | applyToInventory(this.inv); 123 | } 124 | } 125 | 126 | /** 127 | * 更新玩家箱子的视图 128 | */ 129 | public void updateView() { 130 | this.onUpdate(); 131 | if (this.inv != null) { 132 | List viewers = this.inv.getViewers(); 133 | applyToInventory(this.inv); 134 | viewers.forEach(p -> ((Player) p).updateInventory()); 135 | } 136 | } 137 | 138 | /** 139 | * 设置是否取消点击GUI内物品的事件 140 | * 如果不取消,玩家可以从GUI中拿取物品。 141 | * 142 | * @param b 是否取消 143 | */ 144 | public void setCancelOnTarget(boolean b) { 145 | this.cancelOnTarget = b; 146 | } 147 | 148 | /** 149 | * 设置是否取消点击自己背包内物品的事件 150 | * 如果不取消,玩家可以从自己的背包中拿取物品。 151 | * 152 | * @param b 是否取消 153 | */ 154 | public void setCancelOnSelf(boolean b) { 155 | this.cancelOnSelf = b; 156 | } 157 | 158 | /** 159 | * 设置是否取消点击GUI外的事件 160 | * 如果不取消,玩家可以把物品从GUI或背包中丢出去 161 | * 162 | * @param b 是否取消 163 | */ 164 | public void setCancelOnOuter(boolean b) { 165 | this.cancelOnOuter = b; 166 | } 167 | 168 | public Object getFlag(String flag) { 169 | return this.flags.get(flag); 170 | } 171 | 172 | public void setFlag(String flag, Object obj) { 173 | this.flags.put(flag, obj); 174 | } 175 | 176 | public void removeFlag(String flag) { 177 | this.flags.remove(flag); 178 | } 179 | 180 | public void rawClickListener(InventoryClickEvent event) { 181 | } 182 | 183 | public void openGUI(Player player) { 184 | if (this.type == GUIType.CANCEL) { 185 | throw new IllegalStateException("被取消或不存在的GUI"); 186 | } 187 | 188 | Inventory ui = Bukkit.createInventory(null, this.type.getSize(), this.title); 189 | applyToInventory(ui); 190 | 191 | GUI previous = getOpenedGUI(player); 192 | if (previous != null && previous.listener != null) { 193 | previous.listener.close(player); 194 | } 195 | 196 | setOpenedGUI(player, this); 197 | 198 | this.inv = ui; 199 | player.openInventory(ui); 200 | 201 | if (listener == null) { 202 | this.listener = new GUIListener(this); 203 | Bukkit.getPluginManager().registerEvents(this.listener, getPlugin()); 204 | } 205 | } 206 | 207 | /** 208 | * 拖动GUI内物品是执行的代码 209 | * 210 | * @param event InventoryDragEvent 211 | */ 212 | public void onDrag(InventoryDragEvent event) { 213 | } 214 | 215 | /** 216 | * 关闭GUI时执行的代码 217 | */ 218 | public void onClose() { 219 | } 220 | 221 | /** 222 | * 当GUI更新时执行的代码 223 | */ 224 | public void onUpdate() { 225 | } 226 | 227 | public GUIType getGUIType() { 228 | return type; 229 | } 230 | 231 | public String getGUIName() { 232 | return title; 233 | } 234 | 235 | public static void setOpenedGUI(Player player, GUI gui) { 236 | getOpenedGUIs().put(player.getUniqueId(), gui); 237 | } 238 | 239 | public static boolean hasOpenedGUI(Player player) { 240 | return getOpenedGUIs().containsKey(player.getUniqueId()); 241 | } 242 | 243 | public static GUI getOpenedGUI(Player player) { 244 | return getOpenedGUIs().get(player.getUniqueId()); 245 | } 246 | 247 | public static void removeOpenedGUI(Player player) { 248 | getOpenedGUIs().remove(player.getUniqueId()); 249 | } 250 | 251 | public static void closeAll() { 252 | Set viewers = new HashSet<>(); 253 | getOpenedGUIs().values().stream().flatMap(gui -> gui.inv.getViewers().stream()).forEach(viewers::add); 254 | viewers.forEach(HumanEntity::closeInventory); 255 | getOpenedGUIs().clear(); 256 | } 257 | 258 | } 259 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/GUIItem.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.inventory.ClickType; 5 | import org.bukkit.event.inventory.InventoryClickEvent; 6 | import org.bukkit.inventory.ItemStack; 7 | 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | public class GUIItem { 12 | 13 | protected ItemStack display; 14 | protected boolean actionActive = true; 15 | 16 | protected final Set actions = new HashSet<>(); 17 | protected final Set actionsIgnoreActive = new HashSet<>(); 18 | 19 | public GUIItem(ItemStack display) { 20 | this.display = display; 21 | } 22 | 23 | public final ItemStack getDisplay() { 24 | return this.display; 25 | } 26 | 27 | public final void setDisplay(ItemStack display) { 28 | this.display = display; 29 | } 30 | 31 | public final boolean isActionActive() { 32 | return this.actionActive; 33 | } 34 | 35 | public final void setActionActive(boolean b) { 36 | actionActive = b; 37 | } 38 | 39 | /** 40 | * 玩家点击该物品后执行的代码 41 | * 可以使用 {@link #onClick(Player, ClickType)} 操作点击者 42 | * 43 | * @param type 点击的类型 44 | */ 45 | @Deprecated 46 | @SuppressWarnings("DeprecatedIsStillUsed") 47 | public void onClick(ClickType type) { 48 | } 49 | 50 | /** 51 | * 玩家点击GUI后执行的代码 52 | * 53 | * @param clicker 点击的玩家 54 | * @param type 点击的类型 55 | */ 56 | public void onClick(Player clicker, ClickType type) { 57 | this.onClick(type); // Deprecated method support 58 | } 59 | 60 | public void addClickAction(GUIClickAction action) { 61 | actions.add(action); 62 | } 63 | 64 | public void addActionIgnoreActive(GUIClickAction action) { 65 | actionsIgnoreActive.add(action); 66 | } 67 | 68 | public void rawClickAction(InventoryClickEvent event) { 69 | 70 | } 71 | 72 | /** 73 | * 自定义点击事件代码 (须自行触发) 74 | * 75 | * @param player 点击GUI的玩家 76 | */ 77 | public void customAction(Player player) { 78 | 79 | } 80 | 81 | public Set getActions() { 82 | return actions; 83 | } 84 | 85 | public Set getActionsIgnoreActive() { 86 | return actionsIgnoreActive; 87 | } 88 | 89 | public abstract static class GUIClickAction { 90 | public abstract void run(ClickType type, Player player); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/GUIListener.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.HandlerList; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.event.inventory.InventoryClickEvent; 8 | import org.bukkit.event.inventory.InventoryCloseEvent; 9 | import org.bukkit.event.inventory.InventoryCreativeEvent; 10 | import org.bukkit.event.inventory.InventoryDragEvent; 11 | import org.bukkit.event.player.PlayerQuitEvent; 12 | 13 | public class GUIListener implements Listener { 14 | 15 | protected final GUI currentGUI; 16 | 17 | public GUIListener(GUI gui) { 18 | this.currentGUI = gui; 19 | } 20 | 21 | public GUI getCurrentGUI() { 22 | return currentGUI; 23 | } 24 | 25 | @EventHandler 26 | public void onInventoryClickEvent(InventoryClickEvent event) { 27 | if (!(event.getWhoClicked() instanceof Player)) return; 28 | Player player = (Player) event.getWhoClicked(); 29 | if (!GUI.hasOpenedGUI(player)) return; 30 | if (GUI.getOpenedGUI(player) != getCurrentGUI()) return; 31 | 32 | getCurrentGUI().rawClickListener(event); 33 | 34 | if (event.getSlot() == -999 && getCurrentGUI().cancelOnOuter) { 35 | event.setCancelled(true); 36 | return; 37 | } 38 | 39 | if (event.getClickedInventory() == null) return; 40 | 41 | if (event.getClickedInventory().equals(getCurrentGUI().inv)) { 42 | 43 | if (getCurrentGUI().cancelOnTarget) event.setCancelled(true); 44 | 45 | if (event.getSlot() != -999) { 46 | GUIItem clickedItem = getCurrentGUI().getItem(event.getSlot()); 47 | if (clickedItem != null) { 48 | if (clickedItem.isActionActive()) { 49 | clickedItem.onClick(player, event.getClick()); 50 | clickedItem.rawClickAction(event); 51 | clickedItem.actions.forEach(action -> action.run(event.getClick(), player)); 52 | } 53 | clickedItem.actionsIgnoreActive.forEach(action -> action.run(event.getClick(), player)); 54 | } 55 | } 56 | 57 | } else if (event.getClickedInventory().equals(player.getInventory()) && getCurrentGUI().cancelOnSelf) { 58 | event.setCancelled(true); 59 | } 60 | 61 | } 62 | 63 | @EventHandler 64 | public void onDrag(InventoryDragEvent e) { 65 | if (!(e.getWhoClicked() instanceof Player)) return; 66 | if (e.getInventory().equals(getCurrentGUI().inv) 67 | || e.getInventory().equals(e.getWhoClicked().getInventory())) { 68 | getCurrentGUI().onDrag(e); 69 | } 70 | } 71 | 72 | @EventHandler 73 | public void onInventoryCloseEvent(InventoryCloseEvent event) { 74 | if (!(event.getPlayer() instanceof Player)) return; 75 | if (!event.getInventory().equals(getCurrentGUI().inv)) return; 76 | 77 | close((Player) event.getPlayer()); 78 | 79 | } 80 | 81 | protected void close(Player p) { 82 | HandlerList.unregisterAll(this); 83 | getCurrentGUI().listener = null; 84 | GUI.removeOpenedGUI(p); 85 | getCurrentGUI().onClose(); 86 | } 87 | 88 | @EventHandler 89 | public void onPlayerLeave(PlayerQuitEvent event) { 90 | GUI.removeOpenedGUI(event.getPlayer()); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/GUIType.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Arrays; 6 | 7 | public enum GUIType { 8 | 9 | ONE_BY_NINE(1, 9), 10 | TWO_BY_NINE(2, 18), 11 | THREE_BY_NINE(3, 27), 12 | FOUR_BY_NINE(4, 36), 13 | FIVE_BY_NINE(5, 45), 14 | SIX_BY_NINE(6, 54), 15 | 16 | CANCEL(0, 0); 17 | 18 | private final int lines; 19 | private final int size; 20 | 21 | GUIType(int lines, int size) { 22 | this.lines = lines; 23 | this.size = size; 24 | } 25 | 26 | public int getLines() { 27 | return lines; 28 | } 29 | 30 | public int getSize() { 31 | return size; 32 | } 33 | 34 | @NotNull 35 | public static GUIType getBySize(int size) { 36 | return Arrays.stream(values()).filter(type -> type.getSize() == size).findFirst().orElse(CANCEL); 37 | } 38 | 39 | @NotNull 40 | public static GUIType getByLines(int lines) { 41 | return Arrays.stream(values()).filter(type -> type.getLines() == lines).findFirst().orElse(CANCEL); 42 | } 43 | 44 | 45 | @NotNull 46 | public static GUIType getByName(String name) { 47 | return Arrays.stream(values()).filter(type -> type.name().equalsIgnoreCase(name)).findFirst().orElse(CANCEL); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/configuration/GUIActionConfiguration.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui.configuration; 2 | 3 | import cc.carm.lib.easyplugin.gui.GUIItem; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.inventory.ClickType; 6 | import org.jetbrains.annotations.Contract; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | public class GUIActionConfiguration { 11 | 12 | public static @NotNull GUIActionConfiguration of(@NotNull GUIActionType actionType, 13 | @Nullable ClickType clickType, 14 | @Nullable String actionContent) { 15 | return new GUIActionConfiguration(actionType, clickType, actionContent); 16 | } 17 | 18 | public static @NotNull GUIActionConfiguration of(@NotNull GUIActionType actionType, 19 | @Nullable String actionContent) { 20 | return of(actionType, null, actionContent); 21 | } 22 | 23 | public static @NotNull GUIActionConfiguration of(@NotNull GUIActionType actionType, 24 | @Nullable ClickType clickType) { 25 | return of(actionType, clickType, null); 26 | } 27 | 28 | public static @NotNull GUIActionConfiguration of(@NotNull GUIActionType actionType) { 29 | return of(actionType, null, null); 30 | } 31 | 32 | protected final @NotNull GUIActionType actionType; 33 | 34 | protected final @Nullable ClickType clickType; 35 | protected final @Nullable String actionContent; 36 | 37 | public GUIActionConfiguration(@NotNull GUIActionType actionType, 38 | @Nullable ClickType clickType, 39 | @Nullable String actionContent) { 40 | this.clickType = clickType; 41 | this.actionType = actionType; 42 | this.actionContent = actionContent; 43 | } 44 | 45 | public @Nullable ClickType getClickType() { 46 | return clickType; 47 | } 48 | 49 | public @NotNull GUIActionType getActionType() { 50 | return actionType; 51 | } 52 | 53 | public @Nullable String getActionContent() { 54 | return actionContent; 55 | } 56 | 57 | public void checkAction(Player player, ClickType type) { 58 | if (getClickType() == null || getClickType() == type) executeAction(player); 59 | } 60 | 61 | public void executeAction(Player targetPlayer) { 62 | getActionType().getExecutor().accept(targetPlayer, getActionContent()); 63 | } 64 | 65 | public GUIItem.GUIClickAction toClickAction() { 66 | return new GUIItem.GUIClickAction() { 67 | @Override 68 | public void run(ClickType type, Player player) { 69 | checkAction(player, type); 70 | } 71 | }; 72 | } 73 | 74 | @Nullable 75 | @Contract("null->null") 76 | public static GUIActionConfiguration deserialize(@Nullable String actionString) { 77 | if (actionString == null) return null; 78 | 79 | int prefixStart = actionString.indexOf("["); 80 | int prefixEnd = actionString.indexOf("]"); 81 | if (prefixStart < 0 || prefixEnd < 0) return null; 82 | 83 | String prefix = actionString.substring(prefixStart + 1, prefixEnd); 84 | ClickType clickType = null; 85 | GUIActionType actionType; 86 | if (prefix.contains(":")) { 87 | String[] args = prefix.split(":"); 88 | clickType = GUIConfiguration.readClickType(args[0]); 89 | actionType = GUIActionType.readActionType(args[1]); 90 | } else { 91 | actionType = GUIActionType.readActionType(prefix); 92 | } 93 | 94 | if (actionType == null) return null; 95 | 96 | String content = actionString.substring(prefixEnd + 1).trim(); 97 | return of(actionType, clickType, content); 98 | } 99 | 100 | public @NotNull String serialize() { 101 | String prefix = "[" + getActionType().name() + (getClickType() == null ? "" : ":" + getClickType().name()) + "]"; 102 | String content = getActionContent() == null ? "" : " " + getActionContent(); 103 | return prefix + content; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/configuration/GUIActionType.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui.configuration; 2 | 3 | import cc.carm.lib.easyplugin.utils.MessageUtils; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.Sound; 6 | import org.bukkit.entity.Player; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.Arrays; 11 | import java.util.Collections; 12 | import java.util.function.BiConsumer; 13 | 14 | public enum GUIActionType { 15 | 16 | /** 17 | * 以玩家聊天的形式执行 18 | * 若内容以 “/" 开头,则会以玩家身份执行命令。 19 | */ 20 | CHAT((player, string) -> { 21 | if (string == null) return; 22 | MessageUtils.setPlaceholders(player, Collections.singletonList(string)).forEach(player::chat); 23 | }), 24 | 25 | /** 26 | * 以后台的形式执行指令 27 | * 指令内容不需要以“/”开头。 28 | */ 29 | CONSOLE((player, string) -> { 30 | if (string == null) return; 31 | MessageUtils.setPlaceholders(player, Collections.singletonList(string)) 32 | .forEach(message -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), message)); 33 | }), 34 | 35 | /** 36 | * 向玩家发送消息。 37 | */ 38 | MESSAGE(MessageUtils::send), 39 | 40 | /** 41 | * 向玩家发送声音。 42 | * 允许配置音量与音调 43 | *

48 | */ 49 | SOUND((player, string) -> { 50 | if (string == null) return; 51 | try { 52 | String[] args = string.contains(":") ? string.split(":") : new String[]{string}; 53 | Sound sound = Arrays.stream(Sound.values()) 54 | .filter(s -> s.name().equals(args[0])) 55 | .findFirst().orElse(null); 56 | 57 | if (sound == null) return; 58 | float volume = args.length > 1 ? Float.parseFloat(args[1]) : 1F; 59 | float pitch = args.length > 2 ? Float.parseFloat(args[2]) : 1F; 60 | 61 | player.playSound(player.getLocation(), sound, volume, pitch); 62 | } catch (Exception ignored) { 63 | } 64 | }), 65 | 66 | /** 67 | * 为玩家关闭GUI。 68 | */ 69 | CLOSE((player, string) -> player.closeInventory()); 70 | 71 | BiConsumer<@NotNull Player, @Nullable String> executor; 72 | 73 | 74 | GUIActionType(BiConsumer<@NotNull Player, @Nullable String> executor) { 75 | this.executor = executor; 76 | } 77 | 78 | public BiConsumer<@NotNull Player, @Nullable String> getExecutor() { 79 | return executor; 80 | } 81 | 82 | public static GUIActionType readActionType(String string) { 83 | return Arrays.stream(GUIActionType.values()) 84 | .filter(action -> action.name().equalsIgnoreCase(string)) 85 | .findFirst().orElse(null); 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/configuration/GUIConfiguration.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui.configuration; 2 | 3 | import cc.carm.lib.easyplugin.gui.GUI; 4 | import cc.carm.lib.easyplugin.gui.GUIType; 5 | import cc.carm.lib.easyplugin.utils.ColorParser; 6 | import org.bukkit.configuration.ConfigurationSection; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.inventory.ClickType; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.util.Arrays; 13 | import java.util.LinkedHashMap; 14 | import java.util.Map; 15 | import java.util.Optional; 16 | 17 | public class GUIConfiguration { 18 | 19 | protected String title; 20 | protected int lines; 21 | 22 | protected Map guiItems; 23 | 24 | public GUIConfiguration(String title, int lines) { 25 | this(title, lines, new LinkedHashMap<>(1)); 26 | } 27 | 28 | public GUIConfiguration(String title, int lines, Map guiItems) { 29 | this.title = title; 30 | this.lines = lines; 31 | this.guiItems = guiItems; 32 | } 33 | 34 | public String getTitle() { 35 | return ColorParser.parse(title); 36 | } 37 | 38 | public int getLines() { 39 | return lines; 40 | } 41 | 42 | public GUIType getGUIType() { 43 | return Optional.of(GUIType.getByLines(lines)) 44 | .map(type -> type == GUIType.CANCEL ? GUIType.SIX_BY_NINE : type) 45 | .get(); 46 | } 47 | 48 | public Map getGUIItems() { 49 | return guiItems; 50 | } 51 | 52 | public void setupItems(Player player, GUI gui) { 53 | getGUIItems().values().forEach(itemConfiguration -> itemConfiguration.setupItems(player, gui)); 54 | } 55 | 56 | public @NotNull Map serialize() { 57 | LinkedHashMap map = new LinkedHashMap<>(); 58 | 59 | map.put("title", this.title); 60 | map.put("lines", this.lines); 61 | if (!this.guiItems.isEmpty()) { 62 | LinkedHashMap items = new LinkedHashMap<>(); 63 | this.guiItems.forEach((key, value) -> items.put(key, value.serialize())); 64 | map.put("items", items); 65 | } 66 | return map; 67 | } 68 | 69 | 70 | public static GUIConfiguration readConfiguration(@Nullable ConfigurationSection section) { 71 | if (section == null) return new GUIConfiguration("name", 6); 72 | 73 | return new GUIConfiguration( 74 | section.getString("title", ""), 75 | section.getInt("lines", 6), 76 | readItems(section.getConfigurationSection("items")) 77 | ); 78 | } 79 | 80 | public static Map readItems(ConfigurationSection itemsSection) { 81 | Map items = new LinkedHashMap<>(); 82 | if (itemsSection == null) return items; 83 | 84 | for (String key : itemsSection.getKeys(false)) { 85 | GUIItemConfiguration item = GUIItemConfiguration.readFrom(itemsSection.getConfigurationSection(key)); 86 | if (item != null) items.put(key, item); 87 | } 88 | 89 | return items; 90 | } 91 | 92 | public static ClickType readClickType(String type) { 93 | return Arrays.stream(ClickType.values()) 94 | .filter(click -> click.name().equalsIgnoreCase(type)) 95 | .findFirst().orElse(null); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/configuration/GUIItemConfiguration.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui.configuration; 2 | 3 | import cc.carm.lib.easyplugin.gui.GUI; 4 | import cc.carm.lib.easyplugin.gui.GUIItem; 5 | import cc.carm.lib.easyplugin.utils.ColorParser; 6 | import cc.carm.lib.easyplugin.utils.ItemStackFactory; 7 | import cc.carm.lib.easyplugin.utils.MessageUtils; 8 | import org.bukkit.Material; 9 | import org.bukkit.configuration.ConfigurationSection; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.inventory.ItemStack; 12 | import org.bukkit.inventory.meta.ItemMeta; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.*; 17 | import java.util.stream.Collectors; 18 | 19 | public class GUIItemConfiguration { 20 | 21 | @Nullable ItemStack original; 22 | 23 | @NotNull Material type; 24 | int amount; 25 | int data; 26 | @Nullable String name; 27 | @NotNull List lore; 28 | 29 | @NotNull List slots; 30 | @NotNull List actions; 31 | 32 | public GUIItemConfiguration(@NotNull Material type, int amount, int data, 33 | @Nullable String name, @NotNull List lore, 34 | @NotNull List actions, 35 | @NotNull List slots) { 36 | this(null, type, amount, data, name, lore, actions, slots); 37 | } 38 | 39 | public GUIItemConfiguration(@Nullable ItemStack original, 40 | @NotNull Material type, int amount, int data, 41 | @Nullable String name, @NotNull List lore, 42 | @NotNull List actions, 43 | @NotNull List slots) { 44 | this.original = original; 45 | this.type = type; 46 | this.amount = amount; 47 | this.data = data; 48 | this.name = name; 49 | this.lore = lore; 50 | this.slots = slots; 51 | this.actions = actions; 52 | } 53 | 54 | public void setupItems(Player player, GUI gui) { 55 | ItemStack itemStack; 56 | if (original != null) { 57 | ItemStack tmp = original.clone(); 58 | ItemMeta originalMeta = original.getItemMeta(); 59 | if (originalMeta != null) { 60 | if (originalMeta.hasDisplayName()) { 61 | originalMeta.setDisplayName(parseText(player, originalMeta.getDisplayName())); 62 | } 63 | if (originalMeta.getLore() != null) { 64 | originalMeta.setLore(parseTexts(player, originalMeta.getLore())); 65 | } 66 | 67 | } 68 | 69 | tmp.setItemMeta(originalMeta); 70 | itemStack = tmp; 71 | } else { 72 | ItemStackFactory icon = new ItemStackFactory(this.type, this.amount, this.data); 73 | if (this.name != null) { 74 | icon.setDisplayName(parseText(player, this.name)); 75 | } 76 | if (!this.lore.isEmpty()) { 77 | icon.setLore(parseTexts(player, this.lore)); 78 | } 79 | itemStack = icon.toItemStack(); 80 | } 81 | 82 | 83 | GUIItem item = new GUIItem(itemStack); 84 | this.actions.stream().map(GUIActionConfiguration::toClickAction).forEach(item::addClickAction); 85 | this.slots.forEach(slot -> gui.setItem(slot, item)); 86 | } 87 | 88 | private List parseTexts(Player player, List lore) { 89 | return ColorParser.parse(MessageUtils.setPlaceholders(player, lore)); 90 | } 91 | 92 | @NotNull 93 | private String parseText(Player player, @NotNull String name) { 94 | return ColorParser.parse(MessageUtils.setPlaceholders(player, name)); 95 | } 96 | 97 | public @NotNull Map serialize() { 98 | LinkedHashMap map = new LinkedHashMap<>(); 99 | if (original != null) map.put("original", original); 100 | else { 101 | map.put("type", this.type.name()); 102 | if (this.data != 0) map.put("data", this.data); 103 | } 104 | 105 | if (this.name != null) map.put("name", this.name); 106 | if (this.amount != 1) map.put("amount", this.amount); 107 | if (!this.lore.isEmpty()) map.put("lore", this.lore); 108 | if (this.slots.size() > 1) { 109 | map.put("slots", this.slots); 110 | } else if (slots.size() == 1) { 111 | map.put("slot", this.slots.get(0)); 112 | } 113 | if (!this.actions.isEmpty()) { 114 | map.put("actions", this.actions.stream().map(GUIActionConfiguration::serialize).collect(Collectors.toList())); 115 | } 116 | return map; 117 | } 118 | 119 | @Nullable 120 | public static GUIItemConfiguration readFrom(@Nullable ConfigurationSection itemSection) { 121 | if (itemSection == null) return null; 122 | 123 | ItemStack original = null; 124 | if (itemSection.contains("original")) original = itemSection.getItemStack("original"); 125 | 126 | String material = Optional.ofNullable(itemSection.getString("type")).orElse("STONE"); 127 | Material type = Optional.ofNullable(Material.matchMaterial(material)).orElse(Material.STONE); 128 | int data = itemSection.getInt("data", 0); 129 | int amount = itemSection.getInt("amount", 1); 130 | String name = itemSection.getString("name"); 131 | List lore = itemSection.getStringList("lore"); 132 | 133 | List slots = itemSection.getIntegerList("slots"); 134 | int slot = itemSection.getInt("slot", 0); 135 | 136 | List actionsString = itemSection.getStringList("actions"); 137 | List actions = new ArrayList<>(); 138 | for (String actionString : actionsString) { 139 | GUIActionConfiguration action = GUIActionConfiguration.deserialize(actionString); 140 | if (action == null) continue; 141 | actions.add(action); 142 | } 143 | 144 | return new GUIItemConfiguration( 145 | original, type, amount, data, name, lore, actions, 146 | slots.size() > 0 ? slots : Collections.singletonList(slot) 147 | ); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/paged/AutoPagedGUI.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui.paged; 2 | 3 | import cc.carm.lib.easyplugin.gui.GUIItem; 4 | import cc.carm.lib.easyplugin.gui.GUIType; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.inventory.ClickType; 7 | import org.bukkit.inventory.Inventory; 8 | import org.bukkit.inventory.ItemStack; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.util.Arrays; 13 | import java.util.Optional; 14 | import java.util.Set; 15 | import java.util.function.Function; 16 | import java.util.stream.Collectors; 17 | import java.util.stream.IntStream; 18 | 19 | public class AutoPagedGUI extends CommonPagedGUI { 20 | 21 | public static Function defaultPreviousPage = null; 22 | public static Function defaultNextPage = null; 23 | 24 | protected ItemStack previousPageUI; 25 | protected ItemStack nextPageUI; 26 | protected ItemStack noPreviousPageUI; 27 | protected ItemStack noNextPageUI; 28 | protected int previousPageSlot = -1; 29 | protected int nextPageSlot = -1; 30 | 31 | public AutoPagedGUI(@NotNull GUIType type, @NotNull String title, int[] range) { 32 | super(type, title, range); 33 | } 34 | 35 | public AutoPagedGUI(@NotNull GUIType type, @NotNull String title, int a, int b) { 36 | super(type, title, a, b); 37 | } 38 | 39 | public void setPreviousPageUI(@Nullable ItemStack lastPageUI) { 40 | this.previousPageUI = lastPageUI; 41 | } 42 | 43 | public void setNoPreviousPageUI(@Nullable ItemStack noPreviousPageUI) { 44 | this.noPreviousPageUI = noPreviousPageUI; 45 | } 46 | 47 | public void setNextPageUI(@Nullable ItemStack nextPageUI) { 48 | this.nextPageUI = nextPageUI; 49 | } 50 | 51 | public void setNoNextPageUI(@Nullable ItemStack noNextPageUI) { 52 | this.noNextPageUI = noNextPageUI; 53 | } 54 | 55 | public void setPreviousPageSlot(int slot) { 56 | this.previousPageSlot = slot; 57 | } 58 | 59 | public void setNextPageSlot(int slot) { 60 | this.nextPageSlot = slot; 61 | } 62 | 63 | @Override 64 | protected void fillEmptySlots(@NotNull Inventory inventory) { 65 | if (emptyItem == null) return; 66 | Set rangeSet = Arrays.stream(this.range).boxed().collect(Collectors.toSet()); 67 | if (previousPageSlot >= 0) rangeSet.add(previousPageSlot); 68 | if (nextPageSlot >= 0) rangeSet.add(nextPageSlot); 69 | IntStream.range(0, inventory.getSize()) 70 | .filter(i -> inventory.getItem(i) == null) 71 | .filter(i -> !rangeSet.contains(i)) 72 | .forEach(index -> inventory.setItem(index, emptyItem)); 73 | } 74 | 75 | 76 | @Override 77 | public void openGUI(Player user) { 78 | if (previousPageSlot >= 0) { 79 | if (hasPreviousPage()) { 80 | ItemStack finalPreviousPageUI; 81 | if(previousPageUI != null) 82 | finalPreviousPageUI = previousPageUI; 83 | else if (defaultPreviousPage != null) 84 | finalPreviousPageUI = defaultPreviousPage.apply(user); 85 | else 86 | finalPreviousPageUI = null; 87 | setItem(previousPageSlot, new GUIItem(finalPreviousPageUI) { 88 | @Override 89 | public void onClick(Player clicker, ClickType type) { 90 | if (type == ClickType.RIGHT) { 91 | goFirstPage(); 92 | } else { 93 | goPreviousPage(); 94 | } 95 | openGUI(user); 96 | } 97 | }); 98 | } else { 99 | setItem(previousPageSlot, this.noPreviousPageUI == null ? null : new GUIItem(noPreviousPageUI)); 100 | } 101 | } 102 | 103 | if (nextPageSlot >= 0) { 104 | if (hasNextPage()) { 105 | ItemStack finalNextPageUI; 106 | if(previousPageUI != null) 107 | finalNextPageUI = nextPageUI; 108 | else if (defaultNextPage != null) 109 | finalNextPageUI = defaultNextPage.apply(user); 110 | else 111 | finalNextPageUI = null; 112 | setItem(nextPageSlot, new GUIItem(finalNextPageUI) { 113 | @Override 114 | public void onClick(Player clicker, ClickType type) { 115 | if (type == ClickType.RIGHT) { 116 | goLastPage(); 117 | } else { 118 | goNextPage(); 119 | } 120 | openGUI(user); 121 | } 122 | }); 123 | } else { 124 | setItem(nextPageSlot, this.noNextPageUI == null ? null : new GUIItem(noNextPageUI)); 125 | } 126 | } 127 | 128 | super.openGUI(user); 129 | } 130 | 131 | 132 | } 133 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/paged/CommonPagedGUI.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui.paged; 2 | 3 | 4 | import cc.carm.lib.easyplugin.gui.GUIItem; 5 | import cc.carm.lib.easyplugin.gui.GUIType; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.inventory.Inventory; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.Set; 14 | import java.util.stream.Collectors; 15 | import java.util.stream.IntStream; 16 | 17 | public class CommonPagedGUI extends PagedGUI { 18 | 19 | protected final int[] range; 20 | 21 | public CommonPagedGUI(@NotNull GUIType type, @NotNull String title, int a, int b) { 22 | this(type, title, toRange(type, a, b)); 23 | } 24 | 25 | public CommonPagedGUI(@NotNull GUIType type, @NotNull String title, int[] range) { 26 | super(type, title); 27 | Arrays.sort(range); 28 | this.range = range; 29 | } 30 | 31 | @Override 32 | protected void fillEmptySlots(@NotNull Inventory inventory) { 33 | if (emptyItem == null) return; 34 | Set rangeSet = Arrays.stream(this.range).boxed().collect(Collectors.toSet()); 35 | IntStream.range(0, inventory.getSize()) 36 | .filter(i -> inventory.getItem(i) == null) 37 | .filter(i -> !rangeSet.contains(i)) 38 | .forEach(index -> inventory.setItem(index, emptyItem)); 39 | } 40 | 41 | private static int getLine(int i) { 42 | return i / 9 + 1; 43 | } 44 | 45 | private static int getColumn(int i) { 46 | return i % 9 + 1; 47 | } 48 | 49 | @Override 50 | public boolean hasPreviousPage() { 51 | return page > 1; 52 | } 53 | 54 | @Override 55 | public boolean hasNextPage() { 56 | return page < getLastPageNumber(); 57 | } 58 | 59 | 60 | /** 61 | * 前往第一页 62 | */ 63 | public void goFirstPage() { 64 | this.page = 1; 65 | onPageChange(this.page); 66 | } 67 | 68 | 69 | /** 70 | * 前往最后一页 71 | */ 72 | public void goLastPage() { 73 | this.page = getLastPageNumber(); 74 | onPageChange(this.page); 75 | } 76 | 77 | 78 | /** 79 | * 得到最后一页的页码 80 | * 81 | * @return 最后一页的页码 82 | */ 83 | @Override 84 | public int getLastPageNumber() { 85 | return getLastPageNumber(range.length); 86 | } 87 | 88 | /** 89 | * 得到第一页的页码 90 | * 91 | * @return 第一页页码(默认为1) 92 | */ 93 | public int getFirstPageNumber() { 94 | return 1; 95 | } 96 | 97 | 98 | @Override 99 | public void openGUI(Player player) { 100 | if (container.isEmpty()) { 101 | super.openGUI(player); 102 | return; 103 | } 104 | if(page > getLastPageNumber()) 105 | page = getLastPageNumber(); 106 | List list = new ArrayList<>(); 107 | int start = (page - 1) * range.length; 108 | for (int i = start; i < start + range.length; i++) { 109 | if (i < container.size()) { 110 | list.add(container.get(i)); 111 | } else { 112 | break; 113 | } 114 | } 115 | 116 | int i = 0; 117 | Arrays.stream(range).forEach(index -> setItem(index, null)); 118 | for (int index : range) { 119 | if (i < list.size()) { 120 | setItem(index, list.get(i)); 121 | i++; 122 | } else { 123 | break; 124 | } 125 | } 126 | super.openGUI(player); 127 | } 128 | 129 | 130 | /* 131 | int[] matrix = new int[]{ 132 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 133 | 9, 10, 11, 12, 13, 14, 15, 16, 17, 134 | 18, 19, 20, 21, 22, 23, 24, 25, 26, 135 | 27, 28, 29, 30, 31, 32, 33, 34, 35, 136 | 36, 37, 38, 39, 40, 41, 42, 43, 44, 137 | 45, 46, 47, 48, 49, 50, 51, 52, 53 138 | } 139 | */ 140 | private static int[] toRange(GUIType type, int a, int b) { 141 | if (a > b) { 142 | a = a ^ b; 143 | b = a ^ b; 144 | a = a ^ b; 145 | } 146 | 147 | int lineA = getLine(a); 148 | int columnA = getColumn(a); 149 | int lineB = getLine(b); 150 | int columnB = getColumn(b); 151 | 152 | if (lineB > type.getLines()) 153 | throw new IndexOutOfBoundsException("页面内容范围超过了GUI的大小"); 154 | 155 | int[] range = new int[(lineB - lineA + 1) * (columnB - columnA + 1)]; 156 | 157 | int l = 0; 158 | for (int i = 0; i < type.getSize(); i++) { 159 | int li = getLine(i); 160 | int ci = getColumn(i); 161 | if (li >= lineA && li <= lineB && ci >= columnA && ci <= columnB) { 162 | range[l] = i; 163 | l++; 164 | } 165 | } 166 | 167 | return range; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /base/gui/src/main/java/cc/carm/lib/easyplugin/gui/paged/PagedGUI.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.gui.paged; 2 | 3 | 4 | import cc.carm.lib.easyplugin.gui.GUI; 5 | import cc.carm.lib.easyplugin.gui.GUIItem; 6 | import cc.carm.lib.easyplugin.gui.GUIType; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public abstract class PagedGUI extends GUI { 14 | 15 | protected List container = new ArrayList<>(); 16 | protected int page = 1; 17 | 18 | protected PagedGUI(@NotNull GUIType type, @NotNull String title) { 19 | super(type, title); 20 | } 21 | 22 | public int setCurrentPage(int page) { 23 | this.page = Math.max(1, page); 24 | return this.page; 25 | } 26 | 27 | public int getCurrentPage() { 28 | return page; 29 | } 30 | 31 | 32 | public int getLastPageNumber() { 33 | return getLastPageNumber(getGUIType().getSize()); 34 | } 35 | 36 | /** 37 | * 得到最后一页的页码 38 | * 39 | * @return 最后一页的页码 40 | */ 41 | public int getLastPageNumber(int size) { 42 | return (this.container.size() / size) + ((this.container.size() % size) == 0 ? 0 : 1); 43 | } 44 | 45 | public int addItem(@NotNull GUIItem i) { 46 | container.add(i); 47 | return container.size() - 1; 48 | } 49 | 50 | public int addItem(int index, @NotNull GUIItem i) { 51 | container.add(index, i); 52 | return container.size() - 1; 53 | } 54 | 55 | public int addItemStack(@NotNull ItemStack itemStack) { 56 | return addItem(new GUIItem(itemStack)); 57 | } 58 | 59 | /** 60 | * 从GUI中移除一个物品 61 | * 62 | * @param item 物品 63 | */ 64 | public void removeItem(@NotNull GUIItem item) { 65 | container.remove(item); 66 | } 67 | 68 | /** 69 | * 从GUI中移除一个物品 70 | * 71 | * @param index 物品格子数 72 | */ 73 | public void removeItem(int index) { 74 | container.remove(index); 75 | } 76 | 77 | public @NotNull List getPagedContainer() { 78 | return this.container; 79 | } 80 | 81 | /** 82 | * 当GUI改变页码时执行的代码 83 | */ 84 | public void onPageChange(int pageNum) { 85 | } 86 | 87 | /** 88 | * 前往上一页 89 | */ 90 | public void goPreviousPage() { 91 | if (hasPreviousPage()) { 92 | this.page--; 93 | this.onPageChange(this.page); 94 | } else throw new IndexOutOfBoundsException(); 95 | } 96 | 97 | 98 | /** 99 | * 前往下一页 100 | */ 101 | public void goNextPage() { 102 | if (hasNextPage()) { 103 | this.page++; 104 | this.onPageChange(this.page); 105 | } else throw new IndexOutOfBoundsException(); 106 | } 107 | 108 | 109 | /** 110 | * @return 是否有上一页 111 | */ 112 | public abstract boolean hasPreviousPage(); 113 | 114 | /** 115 | * @return 是否有下一页 116 | */ 117 | public abstract boolean hasNextPage(); 118 | 119 | } 120 | -------------------------------------------------------------------------------- /base/gui/src/test/java/ActionReadTest.java: -------------------------------------------------------------------------------- 1 | import cc.carm.lib.easyplugin.gui.configuration.GUIActionType; 2 | import cc.carm.lib.easyplugin.gui.configuration.GUIConfiguration; 3 | import org.bukkit.event.inventory.ClickType; 4 | import org.junit.Test; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | public class ActionReadTest { 10 | 11 | 12 | @Test 13 | public void test() { 14 | 15 | List actions = Arrays.asList( 16 | "[CHAT] 123123", 17 | "[SHIFT_LEFT:CHAT] /test qwq", 18 | "[CONSOLE] say hello", 19 | "[CLOSE]" 20 | ); 21 | 22 | for (String actionString : actions) { 23 | int prefixStart = actionString.indexOf("["); 24 | int prefixEnd = actionString.indexOf("]"); 25 | if (prefixStart < 0 || prefixEnd < 0) continue; 26 | 27 | String prefix = actionString.substring(prefixStart + 1, prefixEnd); 28 | ClickType clickType = null; 29 | GUIActionType actionType; 30 | if (prefix.contains(":")) { 31 | String[] args = prefix.split(":"); 32 | clickType = GUIConfiguration.readClickType(args[0]); 33 | actionType = GUIActionType.readActionType(args[1]); 34 | } else { 35 | actionType = GUIActionType.readActionType(prefix); 36 | } 37 | 38 | if (actionType == null) { 39 | System.out.println("# " + actionString); 40 | System.out.println("- actionType is Null"); 41 | continue; 42 | } 43 | 44 | System.out.println("# " + actionType.name() + " " + (clickType == null ? "" : clickType.name())); 45 | System.out.println("- " + actionString.substring(prefixEnd + 1).trim()); 46 | } 47 | 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /base/gui/src/test/java/PageTest.java: -------------------------------------------------------------------------------- 1 | import org.junit.Test; 2 | 3 | public class PageTest { 4 | 5 | 6 | @Test 7 | public void test() { 8 | System.out.println(maxPage(0, 10)); 9 | System.out.println(maxPage(10, 10)); 10 | System.out.println(maxPage(5, 10)); 11 | System.out.println(maxPage(15, 10)); 12 | System.out.println(maxPage(19, 10)); 13 | System.out.println(maxPage(20, 10)); 14 | 15 | } 16 | 17 | int maxPage(int contents, int size) { 18 | if (contents == 0 || size == 0) return 1; 19 | return (contents / size) + ((contents % size) == 0 ? 0 : 1); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /base/main/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | 14 | ${project.jdk.version} 15 | ${project.jdk.version} 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | 21 | easyplugin-main 22 | jar 23 | 24 | EasyPlugin-Main 25 | 轻松插件主要接口模块,包含便捷的插件入口类与相关工具类。 26 | https://github.com/CarmJos/EasyPlugin 27 | 28 | 29 | 30 | CarmJos 31 | Carm Jos 32 | carm@carm.cc 33 | https://www.carm.cc 34 | 35 | 36 | 37 | 38 | 39 | The MIT License 40 | https://opensource.org/licenses/MIT 41 | 42 | 43 | 44 | 45 | GitHub Issues 46 | https://github.com/CarmJos/EasyPlugin/issues 47 | 48 | 49 | 50 | GitHub Actions 51 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 52 | 53 | 54 | 55 | 56 | 57 | ${project.groupId} 58 | easyplugin-utils 59 | ${project.version} 60 | compile 61 | 62 | 63 | 64 | me.clip 65 | placeholderapi 66 | provided 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-javadoc-plugin 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /base/main/src/main/java/cc/carm/lib/easyplugin/EasyPlugin.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin; 2 | 3 | import cc.carm.lib.easyplugin.i18n.EasyPluginMessageProvider; 4 | import cc.carm.lib.easyplugin.utils.JarResourceUtils; 5 | import cc.carm.lib.easyplugin.utils.SchedulerUtils; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.command.CommandExecutor; 8 | import org.bukkit.command.PluginCommand; 9 | import org.bukkit.command.TabCompleter; 10 | import org.bukkit.event.Event; 11 | import org.bukkit.event.Listener; 12 | import org.bukkit.plugin.PluginDescriptionFile; 13 | import org.bukkit.plugin.java.JavaPlugin; 14 | import org.bukkit.plugin.java.JavaPluginLoader; 15 | import org.jetbrains.annotations.NotNull; 16 | import org.jetbrains.annotations.Nullable; 17 | 18 | import java.io.File; 19 | import java.lang.reflect.Method; 20 | import java.util.Arrays; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | import java.util.Optional; 24 | import java.util.concurrent.CompletableFuture; 25 | import java.util.function.Supplier; 26 | 27 | public abstract class EasyPlugin extends JavaPlugin { 28 | 29 | protected @NotNull EasyPluginMessageProvider messageProvider; 30 | 31 | public EasyPlugin() { 32 | this(EasyPluginMessageProvider.ZH_CN); 33 | } 34 | 35 | public EasyPlugin(@NotNull EasyPluginMessageProvider messageProvider) { 36 | this.messageProvider = messageProvider; 37 | } 38 | 39 | protected EasyPlugin(JavaPluginLoader loader, PluginDescriptionFile descriptionFile, File dataFolder, File file) { 40 | this(EasyPluginMessageProvider.ZH_CN, loader, descriptionFile, dataFolder, file); 41 | } 42 | 43 | protected EasyPlugin(@NotNull EasyPluginMessageProvider messageProvider, 44 | JavaPluginLoader loader, PluginDescriptionFile descriptionFile, File dataFolder, File file) { 45 | super(loader, descriptionFile, dataFolder, file); 46 | this.messageProvider = messageProvider; 47 | } 48 | 49 | protected SchedulerUtils scheduler; 50 | protected boolean initialized = false; 51 | 52 | @Override 53 | public final void onLoad() { 54 | scheduler = new SchedulerUtils(this); 55 | if (!hasOverride("load")) return; 56 | 57 | long startTime = System.currentTimeMillis(); 58 | 59 | log(messageProvider.loading(this)); 60 | load(); 61 | log(messageProvider.loaded(this, startTime)); 62 | } 63 | 64 | @Override 65 | public final void onEnable() { 66 | outputInfo(); 67 | 68 | log(messageProvider.enabling(this)); 69 | long startTime = System.currentTimeMillis(); 70 | 71 | if (!(this.initialized = initialize())) { 72 | setEnabled(false); 73 | log(messageProvider.enableFailure(this, startTime)); 74 | return; 75 | } 76 | 77 | log(messageProvider.enableSuccess(this, startTime)); 78 | } 79 | 80 | 81 | @Override 82 | public final void onDisable() { 83 | if (!hasOverride("shutdown") || !this.initialized) return; 84 | outputInfo(); 85 | 86 | log(messageProvider.disabling(this)); 87 | long startTime = System.currentTimeMillis(); 88 | shutdown(); 89 | log(messageProvider.disabled(this, startTime)); 90 | } 91 | 92 | protected void load() { 93 | } 94 | 95 | protected abstract boolean initialize(); 96 | 97 | protected void shutdown() { 98 | } 99 | 100 | /** 101 | * 重写以展示插件的相关信息,如插件横幅、下载地址等。 102 | */ 103 | public void outputInfo() { 104 | Optional.ofNullable(JarResourceUtils.readResource(this.getResource("PLUGIN_INFO"))).ifPresent(this::log); 105 | } 106 | 107 | public boolean isDebugging() { 108 | return false; 109 | } 110 | 111 | public SchedulerUtils getScheduler() { 112 | return scheduler; 113 | } 114 | 115 | public void registerListener(@NotNull Listener... listeners) { 116 | Arrays.stream(listeners).forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, this)); 117 | } 118 | 119 | public void registerCommand(String commandName, 120 | @NotNull CommandExecutor executor) { 121 | registerCommand(commandName, executor, executor instanceof TabCompleter ? (TabCompleter) executor : null); 122 | } 123 | 124 | public void registerCommand(String commandName, 125 | @NotNull CommandExecutor executor, 126 | @Nullable TabCompleter tabCompleter) { 127 | PluginCommand command = Bukkit.getPluginCommand(commandName); 128 | if (command == null) return; 129 | command.setExecutor(executor); 130 | if (tabCompleter != null) command.setTabCompleter(tabCompleter); 131 | } 132 | 133 | public void print(@Nullable String prefix, @Nullable String... messages) { 134 | messageProvider.print(this, prefix, messages); 135 | } 136 | 137 | public void log(@Nullable String... messages) { 138 | print(null, messages); 139 | } 140 | 141 | public void error(String... messages) { 142 | print("&c[ERROR] &r", messages); 143 | } 144 | 145 | public void debug(@Nullable String... messages) { 146 | if (isDebugging()) print("&8[DEBUG] &r", messages); 147 | } 148 | 149 | /** 150 | * 在主线程执行操作,并支持获取其结果。 151 | * 152 | * @param 结果类型 153 | * @param action 需要执行的内容 154 | * @return CompletableFuture 155 | */ 156 | public @NotNull CompletableFuture supplySync(@NotNull Supplier action) { 157 | CompletableFuture future = new CompletableFuture<>(); 158 | getScheduler().run(() -> future.complete(action.get())); 159 | return future; 160 | } 161 | 162 | /** 163 | * 在异步线程中执行一个操作,并获取操作的结果。 164 | * 165 | * @param 事件类型 166 | * @param action 需要执行的内容 167 | * @return CompletableFuture 168 | */ 169 | public @NotNull CompletableFuture supplyAsync(@NotNull Supplier action) { 170 | CompletableFuture future = new CompletableFuture<>(); 171 | getScheduler().runAsync(() -> future.complete(action.get())); 172 | return future; 173 | } 174 | 175 | /** 176 | * 在主线程唤起一个事件,并支持获取事件的结果。 177 | * 178 | * @param event 同步事件 (isAsync=false) 179 | * @param 事件类型 180 | * @return CompletableFuture 181 | */ 182 | public @NotNull CompletableFuture callSync(T event) { 183 | return supplySync(() -> { 184 | Bukkit.getPluginManager().callEvent(event); 185 | return event; 186 | }); 187 | } 188 | 189 | /** 190 | * 在异步线程中唤起一个事件,并支持获取事件的结果。 191 | * 192 | * @param event 异步事件 (isAsync=true) 193 | * @param 事件类型 194 | * @return CompletableFuture 195 | */ 196 | public @NotNull CompletableFuture callAsync(T event) { 197 | return supplyAsync(() -> { 198 | Bukkit.getPluginManager().callEvent(event); 199 | return event; 200 | }); 201 | } 202 | 203 | protected void setMessageProvider(@NotNull EasyPluginMessageProvider provider) { 204 | this.messageProvider = provider; 205 | } 206 | 207 | @SuppressWarnings("BooleanMethodIsAlwaysInverted") 208 | private boolean hasOverride(String methodName) { 209 | Map methodMap = new HashMap<>(); 210 | Arrays.stream(EasyPlugin.class.getDeclaredMethods()) 211 | .filter(method -> method.getName().equals(methodName)) 212 | .forEach(method -> Arrays.stream(getClass().getDeclaredMethods()) 213 | .filter(extend -> extend.getName().equals(methodName)) 214 | .filter(extend -> extend.getReturnType().equals(method.getReturnType())) 215 | .filter(extend -> extend.getParameterTypes().length == method.getParameterTypes().length) 216 | .findFirst().ifPresent(extendMethod -> methodMap.put(method, extendMethod)) 217 | ); 218 | return !methodMap.isEmpty(); 219 | } 220 | 221 | } 222 | -------------------------------------------------------------------------------- /base/main/src/main/java/cc/carm/lib/easyplugin/i18n/EasyPluginMessageProvider.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.i18n; 2 | 3 | import cc.carm.lib.easyplugin.utils.ColorParser; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.plugin.Plugin; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.Arrays; 10 | 11 | public interface EasyPluginMessageProvider { 12 | 13 | EasyPluginMessageProvider ZH_CN = new zh_CN(); 14 | EasyPluginMessageProvider EN_US = new en_US(); 15 | 16 | String loading(Plugin plugin); 17 | 18 | String loaded(Plugin plugin, long startMillis); 19 | 20 | String enabling(Plugin plugin); 21 | 22 | String enableSuccess(Plugin plugin, long startMillis); 23 | 24 | String enableFailure(Plugin plugin, long startMillis); 25 | 26 | String disabling(Plugin plugin); 27 | 28 | String disabled(Plugin plugin, long startMillis); 29 | 30 | default void print(@NotNull Plugin plugin, @Nullable String prefix, @Nullable String... messages) { 31 | Arrays.stream(messages) 32 | .map(message -> "[" + plugin.getName() + "] " + (prefix == null ? "" : prefix) + message) 33 | .map(ColorParser::parse) 34 | .forEach(message -> Bukkit.getConsoleSender().sendMessage(message)); 35 | } 36 | 37 | class zh_CN implements EasyPluginMessageProvider { 38 | 39 | @Override 40 | public String loading(Plugin plugin) { 41 | return "&f" + plugin.getName() + " " + plugin.getDescription().getVersion() + " 开始加载..."; 42 | } 43 | 44 | @Override 45 | public String loaded(Plugin plugin, long startMillis) { 46 | return "&f加载完成 ,共耗时 " + (System.currentTimeMillis() - startMillis) + " ms 。"; 47 | } 48 | 49 | @Override 50 | public String enabling(Plugin plugin) { 51 | return "&f" + plugin.getName() + " " + plugin.getDescription().getVersion() + " 开始启动..."; 52 | } 53 | 54 | @Override 55 | public String enableSuccess(Plugin plugin, long startMillis) { 56 | return "&a启用完成! &f共耗时 " + (System.currentTimeMillis() - startMillis) + " ms 。"; 57 | } 58 | 59 | @Override 60 | public String enableFailure(Plugin plugin, long startMillis) { 61 | return "&c启用失败! &f已耗时 " + (System.currentTimeMillis() - startMillis) + " ms 。"; 62 | } 63 | 64 | @Override 65 | public String disabling(Plugin plugin) { 66 | return "&f" + plugin.getName() + " " + plugin.getDescription().getVersion() + " 开始卸载..."; 67 | } 68 | 69 | @Override 70 | public String disabled(Plugin plugin, long startMillis) { 71 | return "&f卸载完成! 共耗时 " + (System.currentTimeMillis() - startMillis) + " ms 。"; 72 | } 73 | } 74 | 75 | class en_US implements EasyPluginMessageProvider { 76 | 77 | @Override 78 | public String loading(Plugin plugin) { 79 | return "&f" + plugin.getName() + " " + plugin.getDescription().getVersion() + " loading..."; 80 | } 81 | 82 | @Override 83 | public String loaded(Plugin plugin, long startMillis) { 84 | return "&fLoaded after " + (System.currentTimeMillis() - startMillis) + " ms."; 85 | } 86 | 87 | @Override 88 | public String enabling(Plugin plugin) { 89 | return "&f" + plugin.getName() + " " + plugin.getDescription().getVersion() + " enabling..."; 90 | } 91 | 92 | @Override 93 | public String enableSuccess(Plugin plugin, long startMillis) { 94 | return "&aEnabled successfully!&f Cost " + (System.currentTimeMillis() - startMillis) + " ms."; 95 | } 96 | 97 | @Override 98 | public String enableFailure(Plugin plugin, long startMillis) { 99 | return "&cEnabled failed after " + (System.currentTimeMillis() - startMillis) + " ms."; 100 | } 101 | 102 | @Override 103 | public String disabling(Plugin plugin) { 104 | return "&f" + plugin.getName() + " " + plugin.getDescription().getVersion() + " begin to shutdown..."; 105 | } 106 | 107 | @Override 108 | public String disabled(Plugin plugin, long startMillis) { 109 | return "&fShutdown successfully, cost " + (System.currentTimeMillis() - startMillis) + " ms."; 110 | } 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /base/main/src/main/java/cc/carm/lib/easyplugin/utils/ItemStackFactory.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.utils; 2 | 3 | 4 | import org.bukkit.Material; 5 | import org.bukkit.enchantments.Enchantment; 6 | import org.bukkit.inventory.ItemFlag; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.bukkit.inventory.meta.Damageable; 9 | import org.bukkit.inventory.meta.ItemMeta; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.stream.Collectors; 15 | 16 | public class ItemStackFactory { 17 | ItemStack item; 18 | 19 | private ItemStackFactory() { 20 | } 21 | 22 | public ItemStackFactory(ItemStack is) { 23 | this.item = is.clone(); 24 | } 25 | 26 | public ItemStackFactory(Material type) { 27 | this(type, 1); 28 | } 29 | 30 | public ItemStackFactory(Material type, int amount) { 31 | this(type, amount, (short) 0); 32 | } 33 | 34 | public ItemStackFactory(Material type, int amount, short data) { 35 | this.item = new ItemStack(type, amount, data); 36 | } 37 | 38 | public ItemStackFactory(Material type, int amount, int data) { 39 | this(type, amount, (short) data); 40 | } 41 | 42 | public ItemStack toItemStack() { 43 | return this.item; 44 | } 45 | 46 | public ItemStackFactory setType(Material type) { 47 | this.item.setType(type); 48 | return this; 49 | } 50 | 51 | public ItemStackFactory setDurability(int i) { 52 | ItemMeta im = this.item.getItemMeta(); 53 | if (im instanceof Damageable) { 54 | ((Damageable) im).setDamage(i); 55 | this.item.setItemMeta(im); 56 | } 57 | return this; 58 | } 59 | 60 | public ItemStackFactory setAmount(int a) { 61 | this.item.setAmount(a); 62 | return this; 63 | } 64 | 65 | public ItemStackFactory setDisplayName(@NotNull String name) { 66 | ItemMeta im = this.item.getItemMeta(); 67 | if (im != null) { 68 | im.setDisplayName(ColorParser.parse(name)); 69 | this.item.setItemMeta(im); 70 | } 71 | return this; 72 | } 73 | 74 | public ItemStackFactory setLore(@NotNull List loreList) { 75 | ItemMeta im = this.item.getItemMeta(); 76 | if (im != null) { 77 | im.setLore( 78 | loreList.stream() 79 | .map(ColorParser::parse) 80 | .collect(Collectors.toList()) 81 | ); 82 | this.item.setItemMeta(im); 83 | } 84 | return this; 85 | } 86 | 87 | public ItemStackFactory addLore(@NotNull String s) { 88 | ItemMeta im = this.item.getItemMeta(); 89 | if (im != null) { 90 | List lore = im.getLore() != null ? im.getLore() : new ArrayList<>(); 91 | lore.add(ColorParser.parse(s)); 92 | im.setLore(lore); 93 | this.item.setItemMeta(im); 94 | } 95 | return this; 96 | } 97 | 98 | public ItemStackFactory addEnchant(@NotNull Enchantment enchant, int level, boolean ignoreLevelRestriction) { 99 | ItemMeta im = this.item.getItemMeta(); 100 | if (im != null) { 101 | im.addEnchant(enchant, level, ignoreLevelRestriction); 102 | this.item.setItemMeta(im); 103 | } 104 | 105 | return this; 106 | } 107 | 108 | public ItemStackFactory removeEnchant(@NotNull Enchantment enchant) { 109 | ItemMeta im = this.item.getItemMeta(); 110 | if (im != null) { 111 | im.removeEnchant(enchant); 112 | this.item.setItemMeta(im); 113 | } 114 | return this; 115 | } 116 | 117 | public ItemStackFactory addFlag(@NotNull ItemFlag flag) { 118 | ItemMeta im = this.item.getItemMeta(); 119 | if (im != null) { 120 | im.addItemFlags(flag); 121 | this.item.setItemMeta(im); 122 | } 123 | 124 | return this; 125 | } 126 | 127 | public ItemStackFactory removeFlag(@NotNull ItemFlag flag) { 128 | ItemMeta im = this.item.getItemMeta(); 129 | if (im != null) { 130 | im.removeItemFlags(flag); 131 | this.item.setItemMeta(im); 132 | } 133 | return this; 134 | } 135 | 136 | public ItemStackFactory setUnbreakable(boolean unbreakable) { 137 | ItemMeta im = this.item.getItemMeta(); 138 | if (im != null) { 139 | im.setUnbreakable(unbreakable); 140 | this.item.setItemMeta(im); 141 | } 142 | return this; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /base/main/src/main/java/cc/carm/lib/easyplugin/utils/MessageUtils.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.utils; 2 | 3 | import me.clip.placeholderapi.PlaceholderAPI; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.entity.Player; 7 | import org.jetbrains.annotations.Contract; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.util.Arrays; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.stream.Collectors; 16 | 17 | public class MessageUtils { 18 | 19 | public static boolean hasPlaceholderAPI() { 20 | return Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null; 21 | } 22 | 23 | public static void send(@Nullable CommandSender sender, String... messages) { 24 | send(sender, Arrays.asList(messages)); 25 | } 26 | 27 | public static void send(@Nullable CommandSender sender, List messages) { 28 | if (messages == null || messages.isEmpty() || sender == null) return; 29 | for (String s : messages) { 30 | sender.sendMessage(ColorParser.parse(s)); 31 | } 32 | } 33 | 34 | public static void sendWithPlaceholders(CommandSender sender, String... messages) { 35 | sendWithPlaceholders(sender, Arrays.asList(messages)); 36 | } 37 | 38 | public static void sendWithPlaceholders(@Nullable CommandSender sender, List messages) { 39 | if (messages == null || messages.isEmpty() || sender == null) return; 40 | send(sender, setPlaceholders(sender, messages)); 41 | } 42 | 43 | public static void sendWithPlaceholders(@Nullable CommandSender sender, List messages, String param, Object value) { 44 | sendWithPlaceholders(sender, messages, new String[]{param}, new Object[]{value}); 45 | } 46 | 47 | public static void sendWithPlaceholders(@Nullable CommandSender sender, List messages, String[] params, Object[] values) { 48 | sendWithPlaceholders(sender, setCustomParams(messages, params, values)); 49 | } 50 | 51 | public static String setPlaceholders(@Nullable CommandSender sender, @Nullable String message) { 52 | if (message == null || sender == null) return message; 53 | if (hasPlaceholderAPI() && sender instanceof Player) { 54 | return PlaceholderAPI.setPlaceholders((Player) sender, message); 55 | } else { 56 | return message; 57 | } 58 | } 59 | 60 | 61 | @Nullable 62 | @Contract("_, !null -> !null") 63 | public static List setPlaceholders(@Nullable CommandSender sender, 64 | @Nullable List messages) { 65 | if (messages == null || messages.isEmpty() || sender == null) return messages; 66 | if (hasPlaceholderAPI() && sender instanceof Player) { 67 | return PlaceholderAPI.setPlaceholders((Player) sender, messages); 68 | } else { 69 | return messages; 70 | } 71 | } 72 | 73 | public static String setPlaceholders(@Nullable CommandSender sender, 74 | @NotNull String message, 75 | @Nullable String[] params, 76 | @Nullable Object[] values) { 77 | return setPlaceholders(sender, setCustomParams(message, params, values)); 78 | } 79 | 80 | public static List setPlaceholders(@Nullable CommandSender sender, 81 | @NotNull List messages, 82 | @Nullable String[] params, 83 | @Nullable Object[] values) { 84 | return setPlaceholders(sender, setCustomParams(messages, params, values)); 85 | } 86 | 87 | public static String setCustomParams(@NotNull String message, 88 | @NotNull String param, 89 | @NotNull Object value) { 90 | return setCustomParams(message, new String[]{param}, new Object[]{value}); 91 | } 92 | 93 | @Nullable 94 | @Contract("!null, _, _-> !null ; null, _, _->null ") 95 | public static String setCustomParams(@Nullable String message, 96 | @Nullable String[] params, 97 | @Nullable Object[] values) { 98 | if (message == null) return null; 99 | if (params == null || values == null) return message; 100 | if (params.length != values.length) return message; 101 | 102 | HashMap paramsMap = new HashMap<>(); 103 | for (int i = 0; i < params.length; i++) { 104 | paramsMap.put(params[i], values[i]); 105 | } 106 | return setCustomParams(message, paramsMap); 107 | } 108 | 109 | @NotNull 110 | public static String setCustomParams(@NotNull String message, @NotNull HashMap params) { 111 | String afterMessage = message; 112 | for (Map.Entry entry : params.entrySet()) { 113 | afterMessage = afterMessage.replace(entry.getKey(), entry.getValue().toString()); 114 | } 115 | return afterMessage; 116 | } 117 | 118 | @NotNull 119 | public static List setCustomParams(@NotNull List messages, 120 | @NotNull String param, 121 | @NotNull Object value) { 122 | return setCustomParams(messages, new String[]{param}, new Object[]{value}); 123 | } 124 | 125 | @NotNull 126 | public static List setCustomParams(@NotNull List messages, 127 | @Nullable String[] params, 128 | @Nullable Object[] values) { 129 | if (params == null || values == null) return messages; 130 | if (params.length != values.length) return messages; 131 | HashMap paramsMap = new HashMap<>(); 132 | for (int i = 0; i < params.length; i++) { 133 | paramsMap.put(params[i], values[i]); 134 | } 135 | return setCustomParams(messages, paramsMap); 136 | } 137 | 138 | @NotNull 139 | public static List setCustomParams(List messages, HashMap params) { 140 | return messages.stream() 141 | .map(message -> setCustomParams(message, params)) 142 | .collect(Collectors.toList()); 143 | } 144 | 145 | 146 | } 147 | -------------------------------------------------------------------------------- /base/main/src/main/java/cc/carm/lib/easyplugin/utils/SchedulerUtils.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.utils; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.plugin.java.JavaPlugin; 5 | import org.bukkit.scheduler.BukkitRunnable; 6 | 7 | import java.util.Arrays; 8 | import java.util.LinkedList; 9 | import java.util.Queue; 10 | import java.util.concurrent.Callable; 11 | 12 | @SuppressWarnings("DuplicatedCode") 13 | public class SchedulerUtils { 14 | 15 | private final JavaPlugin plugin; 16 | 17 | public SchedulerUtils(JavaPlugin plugin) { 18 | this.plugin = plugin; 19 | } 20 | 21 | private JavaPlugin getPlugin() { 22 | return plugin; 23 | } 24 | 25 | 26 | /** 27 | * 在服务端主线程中执行一个任务 28 | * 29 | * @param runnable 需要执行的任务 30 | */ 31 | public void run(Runnable runnable) { 32 | Bukkit.getScheduler().runTask(getPlugin(), runnable); 33 | } 34 | 35 | 36 | /** 37 | * 异步执行一个任务。 38 | * 39 | * @param runnable 需要执行的任务 40 | */ 41 | public void runAsync(Runnable runnable) { 42 | Bukkit.getScheduler().runTaskAsynchronously(getPlugin(), runnable); 43 | } 44 | 45 | /** 46 | * 在主线程延时执行一个任务。 47 | * 48 | * @param delay 延迟的ticks 49 | * @param runnable 需要执行的任务 50 | */ 51 | public void runLater(long delay, Runnable runnable) { 52 | Bukkit.getScheduler().runTaskLater(getPlugin(), runnable, delay); 53 | } 54 | 55 | /** 56 | * 异步延时执行一个任务。 57 | * 58 | * @param delay 延迟的ticks 59 | * @param runnable 需要执行的任务 60 | */ 61 | public void runLaterAsync(long delay, Runnable runnable) { 62 | Bukkit.getScheduler().runTaskLaterAsynchronously(getPlugin(), runnable, delay); 63 | } 64 | 65 | /** 66 | * 间隔一段时间按顺序执行列表中的任务 67 | * 68 | * @param interval 间隔时间 69 | * @param tasks 任务列表 70 | */ 71 | public void runAtInterval(long interval, Runnable... tasks) { 72 | runAtInterval(0L, interval, tasks); 73 | } 74 | 75 | 76 | /** 77 | * 间隔一段时间按顺序执行列表中的任务 78 | * 79 | * @param delay 延迟时间 80 | * @param interval 间隔时间 81 | * @param tasks 任务列表 82 | */ 83 | public void runAtInterval(long delay, long interval, Runnable... tasks) { 84 | new BukkitRunnable() { 85 | private int index; 86 | 87 | @Override 88 | public void run() { 89 | if (this.index >= tasks.length) { 90 | this.cancel(); 91 | return; 92 | } 93 | 94 | tasks[index].run(); 95 | index++; 96 | } 97 | }.runTaskTimer(getPlugin(), delay, interval); 98 | } 99 | 100 | /** 101 | * 间隔一段时间按顺序异步执行列表中的任务 102 | * 103 | * @param interval 间隔时间 104 | * @param tasks 任务列表 105 | */ 106 | public void runAtIntervalAsync(long interval, Runnable... tasks) { 107 | runAtIntervalAsync(0L, interval, tasks); 108 | } 109 | 110 | /** 111 | * 间隔一段时间按顺序异步执行列表中的任务 112 | * 113 | * @param delay 延迟时间 114 | * @param interval 间隔时间 115 | * @param tasks 任务列表 116 | */ 117 | public void runAtIntervalAsync(long delay, long interval, Runnable... tasks) { 118 | new BukkitRunnable() { 119 | private int index; 120 | 121 | @Override 122 | public void run() { 123 | if (this.index >= tasks.length) { 124 | this.cancel(); 125 | return; 126 | } 127 | 128 | tasks[index].run(); 129 | index++; 130 | } 131 | }.runTaskTimerAsynchronously(getPlugin(), delay, interval); 132 | } 133 | 134 | /** 135 | * 重复执行一个任务。 136 | * 137 | * @param repetitions 重复次数 138 | * @param interval 间隔时间 139 | * @param task 任务 140 | * @param onComplete 结束时执行的任务 141 | */ 142 | public void repeat(int repetitions, long interval, Runnable task, Runnable onComplete) { 143 | new BukkitRunnable() { 144 | private int index; 145 | 146 | @Override 147 | public void run() { 148 | index++; 149 | if (this.index >= repetitions) { 150 | this.cancel(); 151 | if (onComplete == null) { 152 | return; 153 | } 154 | 155 | onComplete.run(); 156 | return; 157 | } 158 | 159 | task.run(); 160 | } 161 | }.runTaskTimer(getPlugin(), 0L, interval); 162 | } 163 | 164 | /** 165 | * 重复执行一个任务。 166 | * 167 | * @param repetitions 重复次数 168 | * @param interval 间隔时间 169 | * @param task 任务 170 | * @param onComplete 结束时执行的任务 171 | */ 172 | public void repeatAsync(int repetitions, long interval, Runnable task, Runnable onComplete) { 173 | new BukkitRunnable() { 174 | private int index; 175 | 176 | @Override 177 | public void run() { 178 | index++; 179 | if (this.index >= repetitions) { 180 | this.cancel(); 181 | if (onComplete == null) { 182 | return; 183 | } 184 | 185 | onComplete.run(); 186 | return; 187 | } 188 | 189 | task.run(); 190 | } 191 | }.runTaskTimerAsynchronously(getPlugin(), 0L, interval); 192 | } 193 | 194 | /** 195 | * 在满足某个条件时,重复执行一个任务。 196 | * 197 | * @param interval 重复间隔时间 198 | * @param predicate 条件 199 | * @param task 任务 200 | * @param onComplete 结束时执行的任务 201 | */ 202 | public void repeatWhile(long interval, Callable predicate, Runnable task, Runnable onComplete) { 203 | new BukkitRunnable() { 204 | @Override 205 | public void run() { 206 | try { 207 | if (!predicate.call()) { 208 | this.cancel(); 209 | if (onComplete == null) { 210 | return; 211 | } 212 | 213 | onComplete.run(); 214 | return; 215 | } 216 | 217 | task.run(); 218 | } catch (Exception e) { 219 | e.printStackTrace(); 220 | } 221 | } 222 | }.runTaskTimer(getPlugin(), 0L, interval); 223 | } 224 | 225 | /** 226 | * 在满足某个条件时,重复执行一个任务。 227 | * 228 | * @param interval 重复间隔时间 229 | * @param predicate 条件 230 | * @param task 任务 231 | * @param onComplete 结束时执行的任务 232 | */ 233 | public void repeatWhileAsync(long interval, Callable predicate, Runnable task, Runnable onComplete) { 234 | new BukkitRunnable() { 235 | @Override 236 | public void run() { 237 | try { 238 | if (!predicate.call()) { 239 | this.cancel(); 240 | if (onComplete == null) { 241 | return; 242 | } 243 | 244 | onComplete.run(); 245 | return; 246 | } 247 | 248 | task.run(); 249 | } catch (Exception e) { 250 | e.printStackTrace(); 251 | } 252 | } 253 | }.runTaskTimerAsynchronously(getPlugin(), 0L, interval); 254 | } 255 | 256 | public interface Task { 257 | void start(Runnable onComplete); 258 | } 259 | 260 | public class TaskBuilder { 261 | private final Queue taskList; 262 | 263 | public TaskBuilder() { 264 | this.taskList = new LinkedList<>(); 265 | } 266 | 267 | public TaskBuilder append(TaskBuilder builder) { 268 | this.taskList.addAll(builder.taskList); 269 | return this; 270 | } 271 | 272 | public TaskBuilder appendDelay(long delay) { 273 | this.taskList.add(onComplete -> SchedulerUtils.this.runLater(delay, onComplete)); 274 | return this; 275 | } 276 | 277 | public TaskBuilder appendTask(Runnable task) { 278 | this.taskList.add(onComplete -> 279 | { 280 | task.run(); 281 | onComplete.run(); 282 | }); 283 | 284 | return this; 285 | } 286 | 287 | public TaskBuilder appendTask(Task task) { 288 | this.taskList.add(task); 289 | return this; 290 | } 291 | 292 | public TaskBuilder appendDelayedTask(long delay, Runnable task) { 293 | this.taskList.add(onComplete -> SchedulerUtils.this.runLater(delay, () -> 294 | { 295 | task.run(); 296 | onComplete.run(); 297 | })); 298 | 299 | return this; 300 | } 301 | 302 | public TaskBuilder appendTasks(long delay, long interval, Runnable... tasks) { 303 | this.taskList.add(onComplete -> 304 | { 305 | Runnable[] runnables = Arrays.copyOf(tasks, tasks.length + 1); 306 | runnables[runnables.length - 1] = onComplete; 307 | SchedulerUtils.this.runAtInterval(delay, interval, runnables); 308 | }); 309 | 310 | return this; 311 | } 312 | 313 | public TaskBuilder appendRepeatingTask(int repetitions, long interval, Runnable task) { 314 | this.taskList.add(onComplete -> SchedulerUtils.this.repeat(repetitions, interval, task, onComplete)); 315 | return this; 316 | } 317 | 318 | public TaskBuilder appendConditionalRepeatingTask(long interval, Callable predicate, Runnable task) { 319 | this.taskList.add(onComplete -> SchedulerUtils.this.repeatWhile(interval, predicate, task, onComplete)); 320 | return this; 321 | } 322 | 323 | public TaskBuilder waitFor(Callable predicate) { 324 | this.taskList.add(onComplete -> new BukkitRunnable() { 325 | @Override 326 | public void run() { 327 | try { 328 | if (!predicate.call()) { 329 | return; 330 | } 331 | 332 | this.cancel(); 333 | onComplete.run(); 334 | } catch (Exception e) { 335 | e.printStackTrace(); 336 | } 337 | } 338 | }.runTaskTimer(getPlugin(), 0L, 1L)); 339 | return this; 340 | } 341 | 342 | public void runTasks() { 343 | this.startNext(); 344 | } 345 | 346 | private void startNext() { 347 | Task task = this.taskList.poll(); 348 | if (task == null) { 349 | return; 350 | } 351 | 352 | task.start(this::startNext); 353 | } 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /base/messages/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | cc.carm.lib 8 | easyplugin-parent 9 | 1.5.13 10 | ../../pom.xml 11 | 12 | 13 | ${project.jdk.version} 14 | ${project.jdk.version} 15 | UTF-8 16 | UTF-8 17 | true 18 | 19 | easyplugin-messages 20 | 21 | EasyPlugin-Messages 22 | 23 | 轻松插件消息配置模块,支持多种消息配置,包括文本消息、ActionBar消息、Title消息、声音、粒子效果播放等。 24 | 25 | https://github.com/CarmJos/EasyPlugin 26 | 27 | 28 | 29 | ${project.groupId} 30 | easyplugin-color 31 | ${project.version} 32 | compile 33 | 34 | 35 | 36 | 37 | 38 | CarmJos 39 | Carm Jos 40 | carm@carm.cc 41 | https://www.carm.cc 42 | 43 | 44 | 45 | 46 | 47 | The MIT License 48 | https://opensource.org/licenses/MIT 49 | 50 | 51 | 52 | 53 | GitHub Issues 54 | https://github.com/CarmJos/EasyPlugin/issues 55 | 56 | 57 | 58 | GitHub Actions 59 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 60 | 61 | 62 | 63 | 64 | 65 | org.apache.maven.plugins 66 | maven-javadoc-plugin 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /base/storage/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | ${project.jdk.version} 14 | ${project.jdk.version} 15 | UTF-8 16 | UTF-8 17 | 18 | 19 | easyplugin-storage 20 | jar 21 | 22 | EasyPlugin-Storage 23 | 轻松插件存储接口模块,包含存储相关的统一接口。 24 | https://github.com/CarmJos/EasyPlugin 25 | 26 | 27 | 28 | 29 | org.apache.maven.plugins 30 | maven-javadoc-plugin 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /base/storage/src/main/java/cc/carm/lib/easyplugin/storage/DataStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.storage; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | public interface DataStorage { 7 | 8 | /** 9 | * 在插件加载存储源时执行。 10 | * 11 | * @throws Exception 当出现任何错误时抛出 12 | */ 13 | void initialize() throws Exception; 14 | 15 | /** 16 | * 在插件被卸载时执行。 17 | */ 18 | void shutdown(); 19 | 20 | /** 21 | * 用于加载数据的方法。该方法应当异步运行! 22 | *
23 | *
若不存在对应数据,请返回 null 。 24 | *
若加载出现任何错误,请抛出异常。 25 | * 26 | * @param key 数据主键 27 | * @throws Exception 当出现任何错误时抛出 28 | */ 29 | @Nullable 30 | T loadData(@NotNull K key) throws Exception; 31 | 32 | /** 33 | * 用于保存数据的方法。 该方法应当被异步运行! 34 | * 35 | * @param data 数据 36 | * @throws Exception 当出现任何错误时抛出 37 | */ 38 | void saveData(@NotNull T data) throws Exception; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /base/storage/src/main/java/cc/carm/lib/easyplugin/storage/StorageType.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.storage; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public interface StorageType> { 8 | 9 | int getID(); 10 | 11 | @NotNull List getAlias(); 12 | 13 | @NotNull Class getStorageClass(); 14 | 15 | default @NotNull S createStorage() throws Exception { 16 | return getStorageClass().newInstance(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /base/storage/src/main/java/cc/carm/lib/easyplugin/storage/file/FileBasedStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.storage.file; 2 | 3 | import cc.carm.lib.easyplugin.storage.DataStorage; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.io.File; 7 | 8 | public abstract class FileBasedStorage implements DataStorage { 9 | 10 | 11 | protected final String fileName; 12 | protected File dataFile; 13 | 14 | public FileBasedStorage(String fileName) { 15 | this.fileName = fileName; 16 | } 17 | 18 | protected @NotNull File initializeFile(@NotNull File parentFolder) throws Exception { 19 | this.dataFile = new File(parentFolder, fileName); 20 | if (!dataFile.exists()) { 21 | if (!dataFile.createNewFile()) throw new Exception("无法创建数据文件!"); 22 | } else if (dataFile.isDirectory()) { 23 | throw new Exception("文件路径对应的不是一个文件!"); 24 | } 25 | return dataFile; 26 | } 27 | 28 | public File getDataFile() { 29 | return dataFile; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /base/storage/src/main/java/cc/carm/lib/easyplugin/storage/file/FolderBasedStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.storage.file; 2 | 3 | import cc.carm.lib.easyplugin.storage.DataStorage; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.io.File; 7 | import java.util.Arrays; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | public abstract class FolderBasedStorage implements DataStorage { 12 | 13 | protected final @NotNull String folderPath; 14 | protected File dataFolder; 15 | 16 | public FolderBasedStorage(@NotNull String folderPath) { 17 | this.folderPath = folderPath; 18 | } 19 | 20 | protected @NotNull File initializeFolder(@NotNull File parentFolder) throws Exception { 21 | this.dataFolder = new File(parentFolder, folderPath); 22 | if (!dataFolder.exists()) { 23 | if (!dataFolder.mkdir()) { 24 | throw new Exception("无法创建数据文件夹!"); 25 | } 26 | } else if (!dataFolder.isDirectory()) { 27 | throw new Exception("数据文件夹路径对应的不是一个文件夹!"); 28 | } 29 | return dataFolder; 30 | } 31 | 32 | protected @NotNull List listFiles() { 33 | if (this.dataFolder == null) return Collections.emptyList(); 34 | if (!this.dataFolder.isDirectory()) return Collections.emptyList(); 35 | 36 | File[] files = this.dataFolder.listFiles(); 37 | if (files == null) return Collections.emptyList(); 38 | 39 | return Arrays.asList(files); 40 | } 41 | 42 | public File getDataFolder() { 43 | return dataFolder; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /base/storage/src/main/java/cc/carm/lib/easyplugin/storage/file/YAMLBasedStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.storage.file; 2 | 3 | import org.bukkit.configuration.file.FileConfiguration; 4 | import org.bukkit.configuration.file.YamlConfiguration; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.io.File; 8 | 9 | public abstract class YAMLBasedStorage extends FileBasedStorage { 10 | 11 | protected FileConfiguration configuration; 12 | 13 | public YAMLBasedStorage(String fileName) { 14 | super(fileName); 15 | } 16 | 17 | protected @NotNull FileConfiguration initializeConfiguration(@NotNull File parentFolder) throws Exception { 18 | return this.configuration = YamlConfiguration.loadConfiguration(initializeFile(parentFolder)); 19 | } 20 | 21 | public FileConfiguration getConfiguration() { 22 | return configuration; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /base/storage/src/main/java/cc/carm/lib/easyplugin/storage/plugin/PluginBasedStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.storage.plugin; 2 | 3 | import cc.carm.lib.easyplugin.storage.DataStorage; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.plugin.Plugin; 6 | 7 | public abstract class PluginBasedStorage implements DataStorage { 8 | 9 | protected Plugin dependPlugin; 10 | 11 | public PluginBasedStorage(String dependPluginName) { 12 | this(Bukkit.getPluginManager().getPlugin(dependPluginName)); 13 | } 14 | 15 | public PluginBasedStorage(Plugin dependPlugin) { 16 | this.dependPlugin = dependPlugin; 17 | } 18 | 19 | @Override 20 | public void initialize() throws NullPointerException { 21 | if (dependPlugin == null) { 22 | throw new NullPointerException("该存储类型依赖的插件不存在,请检查配置文件"); 23 | } 24 | } 25 | 26 | public Plugin getDependPlugin() { 27 | return dependPlugin; 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /base/user/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | cc.carm.lib 8 | easyplugin-parent 9 | 1.5.13 10 | ../../pom.xml 11 | 12 | 13 | ${project.jdk.version} 14 | ${project.jdk.version} 15 | UTF-8 16 | UTF-8 17 | 18 | easyplugin-user 19 | 20 | 21 | 22 | CarmJos 23 | Carm Jos 24 | carm@carm.cc 25 | https://www.carm.cc 26 | 27 | 28 | 29 | 30 | 31 | The MIT License 32 | https://opensource.org/licenses/MIT 33 | 34 | 35 | 36 | 37 | GitHub Issues 38 | https://github.com/CarmJos/EasyPlugin/issues 39 | 40 | 41 | 42 | GitHub Actions 43 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 44 | 45 | 46 | 47 | 48 | ${project.parent.groupId} 49 | easyplugin-main 50 | ${project.parent.version} 51 | provided 52 | 53 | 54 | 55 | 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-javadoc-plugin 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /base/user/src/main/java/cc/carm/lib/easyplugin/user/AbstractUserData.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.user; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Objects; 6 | 7 | public abstract class AbstractUserData implements UserData { 8 | 9 | protected final @NotNull K key; 10 | 11 | /** 12 | * Used to mark the data as dropping (save and unload) status. 13 | */ 14 | protected boolean dropping = false; 15 | 16 | protected AbstractUserData(@NotNull K key) { 17 | this.key = key; 18 | } 19 | 20 | /** 21 | * @param dropping true if the data is dropping, false otherwise 22 | */ 23 | public void setDropping(boolean dropping) { 24 | this.dropping = dropping; 25 | } 26 | 27 | /** 28 | * @return true if the data is dropping, false otherwise 29 | */ 30 | public boolean isDropping() { 31 | return dropping; 32 | } 33 | 34 | @Override 35 | public boolean equals(Object o) { 36 | if (this == o) return true; 37 | if (o == null || getClass() != o.getClass()) return false; 38 | AbstractUserData abstractUserData = (AbstractUserData) o; 39 | return key.equals(abstractUserData.key); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return Objects.hash(key); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /base/user/src/main/java/cc/carm/lib/easyplugin/user/UserData.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.user; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public interface UserData { 6 | 7 | @NotNull K key(); 8 | 9 | @Deprecated 10 | default @NotNull K getKey() { 11 | return key(); 12 | } 13 | 14 | /** 15 | * @param dropping true if the data is dropping, false otherwise 16 | */ 17 | void setDropping(boolean dropping); 18 | 19 | /** 20 | * @return true if the data is dropping, false otherwise 21 | */ 22 | boolean isDropping(); 23 | } 24 | -------------------------------------------------------------------------------- /base/user/src/main/java/cc/carm/lib/easyplugin/user/UserDataManager.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.user; 2 | 3 | import cc.carm.lib.easyplugin.EasyPlugin; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | import java.util.Map; 10 | import java.util.concurrent.CompletableFuture; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | import java.util.function.Consumer; 15 | import java.util.function.Function; 16 | import java.util.function.Predicate; 17 | import java.util.function.Supplier; 18 | import java.util.logging.Logger; 19 | import java.util.stream.Collectors; 20 | 21 | public abstract class UserDataManager> implements UserDataRegistry { 22 | 23 | protected final @NotNull EasyPlugin plugin; 24 | 25 | protected final @NotNull ExecutorService executor; 26 | protected final @NotNull Map dataCache; 27 | 28 | public UserDataManager(@NotNull EasyPlugin plugin) { 29 | this(plugin, Executors.newCachedThreadPool((r) -> { 30 | Thread t = new Thread(r); 31 | t.setDaemon(true); 32 | t.setName(plugin.getName() + "-UserManager"); 33 | return t; 34 | }), new ConcurrentHashMap<>()); 35 | } 36 | 37 | public UserDataManager(@NotNull EasyPlugin plugin, @NotNull ExecutorService executor) { 38 | this(plugin, executor, new ConcurrentHashMap<>()); 39 | } 40 | 41 | public UserDataManager(@NotNull EasyPlugin plugin, @NotNull ExecutorService executor, @NotNull Map cacheMap) { 42 | this.plugin = plugin; 43 | this.executor = executor; 44 | this.dataCache = cacheMap; 45 | } 46 | 47 | @Override 48 | public void shutdown() { 49 | this.executor.shutdown(); 50 | } 51 | 52 | protected @NotNull EasyPlugin getPlugin() { 53 | return plugin; 54 | } 55 | 56 | @Override 57 | public @NotNull Logger getLogger() { 58 | return getPlugin().getLogger(); 59 | } 60 | 61 | public abstract @NotNull U emptyUser(@NotNull K key); 62 | 63 | public @NotNull U errorUser(@NotNull K key) { 64 | return emptyUser(key); 65 | } 66 | 67 | protected abstract @Nullable U loadData(@NotNull K key) throws Exception; 68 | 69 | protected abstract void saveData(@NotNull U data) throws Exception; 70 | 71 | public @NotNull Map getDataCache() { 72 | return dataCache; 73 | } 74 | 75 | @Override 76 | public @NotNull CompletableFuture load(@NotNull K key, @NotNull Supplier cacheCondition) { 77 | U cached = getNullable(key); 78 | if (cached != null) { 79 | return CompletableFuture.supplyAsync(() -> cached); // Return cached data async. 80 | } 81 | return CompletableFuture.supplyAsync(() -> { 82 | String identifier = serializeKey(key); 83 | 84 | try { 85 | long s1 = System.currentTimeMillis(); 86 | getPlugin().debug("开始加载用户 " + identifier + " 的数据..."); 87 | U data = loadData(key); 88 | if (data == null) { 89 | getPlugin().debug("数据库内不存在用户 " + identifier + " 的数据,视作新档案。"); 90 | return emptyUser(key); 91 | } else { 92 | getPlugin().debug("加载用户 " + identifier + " 的数据完成,耗时 " + (System.currentTimeMillis() - s1) + " ms."); 93 | return data; 94 | } 95 | } catch (Exception ex) { 96 | getPlugin().error("加载用户 " + serializeKey(key) + " 数据失败,请检查相关配置!"); 97 | ex.printStackTrace(); 98 | return errorUser(key); 99 | } 100 | 101 | }, executor).thenApply((data) -> { 102 | if (cacheCondition.get() && !data.isDropping()) dataCache.put(key, data); 103 | return data; 104 | }); 105 | } 106 | 107 | @Override 108 | public @NotNull CompletableFuture save(@NotNull U user) { 109 | return CompletableFuture.supplyAsync(() -> { 110 | String identifier = serializeKey(user.getKey()); 111 | 112 | try { 113 | long s1 = System.currentTimeMillis(); 114 | getPlugin().debug("开始保存用户 " + identifier + " 的数据..."); 115 | saveData(user); 116 | getPlugin().debug("保存用户 " + identifier + " 的数据完成,耗时 " + (System.currentTimeMillis() - s1) + " ms."); 117 | return true; 118 | } catch (Exception ex) { 119 | getPlugin().error("保存用户 " + identifier + " 数据失败,请检查相关配置!"); 120 | ex.printStackTrace(); 121 | return false; 122 | } 123 | 124 | }, executor); 125 | } 126 | 127 | @Override 128 | public @NotNull CompletableFuture unload(@NotNull K key, boolean save) { 129 | U data = getNullable(key); 130 | if (data == null) return CompletableFuture.completedFuture(false); 131 | data.setDropping(true); // Mark the data as unloading. 132 | if (save) { 133 | return save(data).thenApply(result -> { 134 | // Check if the data is still unloading, 135 | // which cloud be interrupted by the next load. 136 | if (data.isDropping()) { 137 | this.dataCache.remove(key); 138 | } 139 | return result; 140 | }); 141 | } else { 142 | this.dataCache.remove(key); 143 | return CompletableFuture.completedFuture(true); 144 | } 145 | 146 | } 147 | 148 | @Override 149 | public @NotNull CompletableFuture modify(@NotNull K key, @NotNull Consumer consumer) { 150 | U cached = getNullable(key); 151 | if (cached != null) { 152 | return CompletableFuture.supplyAsync(() -> { 153 | consumer.accept(cached); 154 | return true; 155 | }, executor); 156 | } else { 157 | return load(key, true).thenApply((data) -> { 158 | consumer.accept(data); 159 | return data; 160 | }).thenCompose(data -> unload(key, true)); 161 | } 162 | } 163 | 164 | @Override 165 | public @NotNull CompletableFuture peek(@NotNull K key, @NotNull Function function) { 166 | U cached = getNullable(key); 167 | if (cached != null) { 168 | return CompletableFuture.supplyAsync(() -> function.apply(cached), executor); 169 | } else { 170 | return load(key, false).thenApply(function); 171 | } 172 | } 173 | 174 | public @NotNull CompletableFuture> loadGroup(@NotNull Collection users, 175 | @NotNull Function function, 176 | @NotNull Predicate cacheCondition) { 177 | CompletableFuture> task = CompletableFuture.completedFuture(new ConcurrentHashMap<>()); 178 | if (users.isEmpty()) return task; 179 | 180 | Map usersMap = users.stream().collect(Collectors.toMap(function, Function.identity())); 181 | for (Map.Entry entry : usersMap.entrySet()) { 182 | K key = entry.getKey(); 183 | T user = entry.getValue(); 184 | task = task.thenCombine( 185 | load(key, () -> cacheCondition.test(user)), 186 | (map, result) -> { 187 | map.put(key, result); 188 | return map; 189 | } 190 | ); 191 | } 192 | 193 | return task.thenApply(Collections::unmodifiableMap); 194 | } 195 | 196 | @Override 197 | public void saveAll() { 198 | if (getDataCache().isEmpty()) return; 199 | for (U u : getDataCache().values()) { 200 | try { 201 | saveData(u); 202 | } catch (Exception e) { 203 | getPlugin().error("保存用户 " + serializeKey(u.getKey()) + " 数据失败,请检查相关配置!"); 204 | e.printStackTrace(); 205 | } 206 | } 207 | } 208 | 209 | @Override 210 | public int unloadAll(boolean save) { 211 | if (save) saveAll(); 212 | int size = getDataCache().size(); 213 | getDataCache().clear(); 214 | return size; 215 | } 216 | 217 | 218 | } 219 | -------------------------------------------------------------------------------- /base/user/src/main/java/cc/carm/lib/easyplugin/user/UserDataRegistry.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.user; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.OfflinePlayer; 6 | import org.bukkit.entity.Player; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | import org.jetbrains.annotations.Unmodifiable; 10 | 11 | import java.util.Collection; 12 | import java.util.Map; 13 | import java.util.Optional; 14 | import java.util.Set; 15 | import java.util.concurrent.CompletableFuture; 16 | import java.util.function.Consumer; 17 | import java.util.function.Function; 18 | import java.util.function.Predicate; 19 | import java.util.function.Supplier; 20 | import java.util.logging.Logger; 21 | 22 | public interface UserDataRegistry> { 23 | 24 | void shutdown(); 25 | 26 | @NotNull Logger getLogger(); 27 | 28 | 29 | @NotNull Map cache(); 30 | 31 | default String serializeKey(@NotNull K key) { 32 | return key.toString(); 33 | } 34 | 35 | default @NotNull CompletableFuture load(@NotNull K key) { 36 | return load(key, false); 37 | } 38 | 39 | default @NotNull CompletableFuture load(@NotNull K key, boolean cache) { 40 | return load(key, () -> cache); 41 | } 42 | 43 | 44 | @Unmodifiable 45 | default @NotNull Set list() { 46 | return ImmutableSet.copyOf(cache().values()); 47 | } 48 | 49 | default @NotNull U get(@NotNull K key) { 50 | return Optional.ofNullable(getNullable(key)).orElseThrow(() -> new NullPointerException("User " + key + " not found.")); 51 | } 52 | 53 | default @Nullable U getNullable(@NotNull K key) { 54 | return cache().get(key); 55 | } 56 | 57 | default @NotNull Optional<@Nullable U> getOptional(@NotNull K key) { 58 | return Optional.ofNullable(getNullable(key)); 59 | } 60 | 61 | @NotNull CompletableFuture load(@NotNull K key, @NotNull Supplier cacheCondition); 62 | 63 | @NotNull CompletableFuture save(@NotNull U user); 64 | 65 | default @NotNull CompletableFuture unload(@NotNull K key) { 66 | return unload(key, true); 67 | } 68 | 69 | @NotNull CompletableFuture unload(@NotNull K key, boolean save); 70 | 71 | @NotNull CompletableFuture modify(@NotNull K key, @NotNull Consumer consumer); 72 | 73 | @NotNull CompletableFuture peek(@NotNull K key, @NotNull Function function); 74 | 75 | default @NotNull CompletableFuture> loadOnline(@NotNull Function function) { 76 | return loadGroup(Bukkit.getOnlinePlayers(), function, OfflinePlayer::isOnline); 77 | } 78 | 79 | @NotNull CompletableFuture> loadGroup(@NotNull Collection users, 80 | @NotNull Function function, 81 | @NotNull Predicate cacheCondition); 82 | 83 | default @NotNull CompletableFuture> loadGroup(@NotNull Collection allKeys, 84 | @NotNull Predicate cacheCondition) { 85 | return loadGroup(allKeys, Function.identity(), cacheCondition); 86 | } 87 | 88 | default @NotNull CompletableFuture> loadGroup(@NotNull Collection allKeys) { 89 | return loadGroup(allKeys, (v) -> false); 90 | } 91 | 92 | void saveAll(); 93 | 94 | int unloadAll(boolean save); 95 | } 96 | -------------------------------------------------------------------------------- /base/utils/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | ${project.jdk.version} 14 | ${project.jdk.version} 15 | UTF-8 16 | UTF-8 17 | 18 | 19 | easyplugin-utils 20 | 21 | EasyPlugin-Utils 22 | 轻松插件工具类模块,该模块中的内容支持在Bungee、Bukkit使用。 23 | https://github.com/CarmJos/EasyPlugin 24 | 25 | 26 | 27 | ${project.groupId} 28 | easyplugin-color 29 | ${project.version} 30 | compile 31 | 32 | 33 | 34 | 35 | 36 | CarmJos 37 | Carm Jos 38 | carm@carm.cc 39 | https://www.carm.cc 40 | 41 | 42 | 43 | 44 | 45 | The MIT License 46 | https://opensource.org/licenses/MIT 47 | 48 | 49 | 50 | 51 | GitHub Issues 52 | https://github.com/CarmJos/EasyPlugin/issues 53 | 54 | 55 | 56 | GitHub Actions 57 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.apache.maven.plugins 65 | maven-javadoc-plugin 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /base/utils/src/main/java/cc/carm/lib/easyplugin/utils/EasyCooldown.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.text.NumberFormat; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.function.Consumer; 9 | import java.util.function.Function; 10 | 11 | /** 12 | * Easy cooldown time utils. 13 | * 14 | * @param

Cooldown key provider 15 | * @param Cooldown key 16 | * @author CarmJos 17 | */ 18 | public class EasyCooldown { 19 | 20 | protected final NumberFormat numberFormatter; 21 | 22 | protected final @NotNull Map cooldown = new HashMap<>(); 23 | protected final @NotNull Function providerToKey; 24 | 25 | protected long defaultDuration; 26 | 27 | public EasyCooldown(@NotNull Function providerToKey) { 28 | this(defaultFormatter(), providerToKey, 1000L); 29 | } 30 | 31 | public EasyCooldown(@NotNull NumberFormat numberFormatter, 32 | @NotNull Function providerToKey) { 33 | this(numberFormatter, providerToKey, 1000L); 34 | } 35 | 36 | public EasyCooldown(@NotNull NumberFormat numberFormatter, 37 | @NotNull Function providerToKey, 38 | long defaultDuration) { 39 | this.numberFormatter = numberFormatter; 40 | this.providerToKey = providerToKey; 41 | this.defaultDuration = defaultDuration; 42 | } 43 | 44 | public long getCooldown(@NotNull P provider) { 45 | Long time = this.cooldown.get(this.providerToKey.apply(provider)); 46 | if (time == null || time < 0) return 0; 47 | 48 | long duration = getDuration(provider); 49 | if (duration <= 0) return 0; 50 | 51 | long past = System.currentTimeMillis() - time; 52 | return duration - past; 53 | } 54 | 55 | public @NotNull String getCooldownSeconds(@NotNull P provider) { 56 | return formatSeconds(getCooldown(provider)); 57 | } 58 | 59 | public void updateTime(@NotNull P provider) { 60 | this.cooldown.put(this.providerToKey.apply(provider), System.currentTimeMillis()); 61 | } 62 | 63 | public void clear(@NotNull P provider) { 64 | clearCooldown(this.providerToKey.apply(provider)); 65 | } 66 | 67 | public void clearCooldown(@NotNull K key) { 68 | this.cooldown.remove(key); 69 | } 70 | 71 | public boolean isCoolingDown(@NotNull P provider) { 72 | return getCooldown(provider) > 0; 73 | } 74 | 75 | public long getDuration(@NotNull P provider) { 76 | return this.defaultDuration; 77 | } 78 | 79 | public @NotNull String formatSeconds(long cooldownMillis) { 80 | return numberFormatter.format((double) cooldownMillis / 1000D); 81 | } 82 | 83 | public static NumberFormat createFormatter(@NotNull Consumer consumer) { 84 | NumberFormat format = NumberFormat.getInstance(); 85 | consumer.accept(format); 86 | return format; 87 | } 88 | 89 | public static NumberFormat defaultFormatter() { 90 | return createFormatter((f) -> f.setMaximumFractionDigits(2)); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /base/utils/src/main/java/cc/carm/lib/easyplugin/utils/JarResourceUtils.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.utils; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import java.io.*; 6 | import java.net.URI; 7 | import java.net.URISyntaxException; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Scanner; 11 | import java.util.zip.ZipEntry; 12 | import java.util.zip.ZipInputStream; 13 | 14 | @SuppressWarnings("ResultOfMethodCallIgnored") 15 | public class JarResourceUtils { 16 | public static final char JAR_SEPARATOR = '/'; 17 | 18 | public static @Nullable String[] readResource(@Nullable InputStream resourceStream) { 19 | if (resourceStream == null) return null; 20 | try (Scanner scanner = new Scanner(resourceStream, "UTF-8")) { 21 | List contents = new ArrayList<>(); 22 | while (scanner.hasNextLine()) { 23 | contents.add(scanner.nextLine()); 24 | } 25 | return contents.toArray(new String[0]); 26 | } catch (Exception e) { 27 | return null; 28 | } 29 | } 30 | 31 | public static void copyFolderFromJar(String folderName, File destFolder, CopyOption option) 32 | throws IOException { 33 | copyFolderFromJar(folderName, destFolder, option, null); 34 | } 35 | 36 | public static void copyFolderFromJar(String folderName, File destFolder, 37 | CopyOption option, PathTrimmer trimmer) throws IOException { 38 | if (!destFolder.exists()) 39 | destFolder.mkdirs(); 40 | 41 | byte[] buffer = new byte[1024]; 42 | 43 | File fullPath; 44 | String path = JarResourceUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 45 | if (trimmer != null) 46 | path = trimmer.trim(path); 47 | try { 48 | if (!path.startsWith("file")) 49 | path = "file://" + path; 50 | 51 | fullPath = new File(new URI(path)); 52 | } catch (URISyntaxException e) { 53 | e.printStackTrace(); 54 | return; 55 | } 56 | 57 | ZipInputStream zis = new ZipInputStream(new FileInputStream(fullPath)); 58 | 59 | ZipEntry entry; 60 | while ((entry = zis.getNextEntry()) != null) { 61 | if (!entry.getName().startsWith(folderName + JAR_SEPARATOR)) 62 | continue; 63 | 64 | String fileName = entry.getName(); 65 | 66 | if (fileName.charAt(fileName.length() - 1) == JAR_SEPARATOR) { 67 | File file = new File(destFolder + File.separator + fileName); 68 | if (file.isFile()) { 69 | file.delete(); 70 | } 71 | file.mkdirs(); 72 | continue; 73 | } 74 | 75 | File file = new File(destFolder + File.separator + fileName); 76 | if (option == CopyOption.COPY_IF_NOT_EXIST && file.exists()) 77 | continue; 78 | 79 | if (!file.getParentFile().exists()) 80 | file.getParentFile().mkdirs(); 81 | 82 | if (!file.exists()) 83 | file.createNewFile(); 84 | FileOutputStream fos = new FileOutputStream(file); 85 | 86 | int len; 87 | while ((len = zis.read(buffer)) > 0) { 88 | fos.write(buffer, 0, len); 89 | } 90 | fos.close(); 91 | } 92 | 93 | zis.closeEntry(); 94 | zis.close(); 95 | } 96 | 97 | public enum CopyOption { 98 | COPY_IF_NOT_EXIST, REPLACE_IF_EXIST 99 | } 100 | 101 | @FunctionalInterface 102 | public interface PathTrimmer { 103 | String trim(String original); 104 | } 105 | } -------------------------------------------------------------------------------- /collection/all/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | 14 | ${project.jdk.version} 15 | ${project.jdk.version} 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | easyplugin-all 21 | jar 22 | 23 | EasyPlugin-All 24 | 轻松插件全集,将打包全部工具类与工具接口。 25 | https://github.com/CarmJos/EasyPlugin 26 | 27 | 28 | 29 | CarmJos 30 | Carm Jos 31 | carm@carm.cc 32 | https://www.carm.cc 33 | 34 | 35 | 36 | 37 | 38 | The MIT License 39 | https://opensource.org/licenses/MIT 40 | 41 | 42 | 43 | 44 | GitHub Issues 45 | https://github.com/CarmJos/EasyPlugin/issues 46 | 47 | 48 | 49 | GitHub Actions 50 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 51 | 52 | 53 | 54 | 55 | 56 | 57 | ${project.parent.groupId} 58 | easyplugin-bom 59 | ${project.parent.version} 60 | pom 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.apache.maven.plugins 70 | maven-javadoc-plugin 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /collection/bom/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | 14 | ${project.jdk.version} 15 | ${project.jdk.version} 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | easyplugin-bom 21 | pom 22 | 23 | EasyPlugin-Bom 24 | 轻松插件汇总导入模块,允许快捷导入相关的接口并避免版本不一致问题。 25 | https://github.com/CarmJos/EasyPlugin 26 | 27 | 28 | 29 | CarmJos 30 | Carm Jos 31 | carm@carm.cc 32 | https://www.carm.cc 33 | 34 | 35 | 36 | 37 | 38 | The MIT License 39 | https://opensource.org/licenses/MIT 40 | 41 | 42 | 43 | 44 | GitHub Issues 45 | https://github.com/CarmJos/EasyPlugin/issues 46 | 47 | 48 | 49 | GitHub Actions 50 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 51 | 52 | 53 | 54 | 55 | 56 | 57 | ${project.parent.groupId} 58 | easyplugin-main 59 | ${project.parent.version} 60 | 61 | 62 | ${project.parent.groupId} 63 | easyplugin-command 64 | ${project.parent.version} 65 | 66 | 67 | ${project.parent.groupId} 68 | easyplugin-gui 69 | ${project.parent.version} 70 | 71 | 72 | ${project.parent.groupId} 73 | easyplugin-storage 74 | ${project.parent.version} 75 | 76 | 77 | ${project.parent.groupId} 78 | easyplugin-placeholderapi 79 | ${project.parent.version} 80 | 81 | 82 | ${project.parent.groupId} 83 | easyplugin-vault 84 | ${project.parent.version} 85 | 86 | 87 | 88 | ${project.parent.groupId} 89 | easyplugin-githubchecker 90 | ${project.parent.version} 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | ${project.parent.groupId} 99 | easyplugin-main 100 | ${project.parent.version} 101 | 102 | 103 | ${project.parent.groupId} 104 | easyplugin-gui 105 | ${project.parent.version} 106 | 107 | 108 | ${project.parent.groupId} 109 | easyplugin-command 110 | ${project.parent.version} 111 | 112 | 113 | ${project.parent.groupId} 114 | easyplugin-placeholderapi 115 | ${project.parent.version} 116 | 117 | 118 | ${project.parent.groupId} 119 | easyplugin-vault 120 | ${project.parent.version} 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | org.apache.maven.plugins 129 | maven-javadoc-plugin 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /collection/common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | 14 | ${project.jdk.version} 15 | ${project.jdk.version} 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | easyplugin-common 21 | jar 22 | 23 | EasyPlugin-Common 24 | 轻松插件常用接口集,包含除附属插件模块外的所有模块。 25 | https://github.com/CarmJos/EasyPlugin 26 | 27 | 28 | 29 | CarmJos 30 | Carm Jos 31 | carm@carm.cc 32 | https://www.carm.cc 33 | 34 | 35 | 36 | 37 | 38 | The MIT License 39 | https://opensource.org/licenses/MIT 40 | 41 | 42 | 43 | 44 | GitHub Issues 45 | https://github.com/CarmJos/EasyPlugin/issues 46 | 47 | 48 | 49 | GitHub Actions 50 | https://github.com/CarmJos/EasyPlugin/actions/workflows/maven.yml 51 | 52 | 53 | 54 | 55 | 56 | 57 | ${project.parent.groupId} 58 | easyplugin-bom 59 | ${project.parent.version} 60 | pom 61 | 62 | 63 | 64 | cc.carm.lib 65 | easyplugin-placeholderapi 66 | 67 | 68 | cc.carm.lib 69 | easyplugin-vault 70 | 71 | 72 | cc.carm.lib 73 | easyplugin-storage 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | org.apache.maven.plugins 85 | maven-javadoc-plugin 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /extension/gh-checker/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | ${project.jdk.version} 14 | ${project.jdk.version} 15 | UTF-8 16 | UTF-8 17 | 18 | easyplugin-githubchecker 19 | jar 20 | 21 | EasyPlugin-GithubChecker 22 | 23 | 24 | 25 | 26 | 27 | cc.carm.lib 28 | githubreleases4j 29 | compile 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-javadoc-plugin 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /extension/gh-checker/src/main/java/cc/carm/lib/easyplugin/updatechecker/GHUpdateChecker.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.updatechecker; 2 | 3 | import cc.carm.lib.githubreleases4j.GithubReleases4J; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.plugin.Plugin; 6 | import org.bukkit.scheduler.BukkitTask; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.List; 10 | import java.util.logging.Logger; 11 | import java.util.regex.Matcher; 12 | import java.util.regex.Pattern; 13 | 14 | public class GHUpdateChecker { 15 | 16 | protected static final @NotNull Pattern GH_URL_PATTERN = Pattern.compile("^https?://github.com/([A-Za-z\\d-_]+)/([^/]*?)/?"); 17 | 18 | public static @NotNull GHUpdateChecker of(@NotNull Logger logger, @NotNull String owner, @NotNull String repo) { 19 | return new GHUpdateChecker(logger, owner, repo); 20 | } 21 | 22 | public static @NotNull GHUpdateChecker of(@NotNull Plugin plugin) { 23 | return new GHUpdateChecker(plugin.getLogger(), getGithubOwner(plugin), plugin.getName()); 24 | } 25 | 26 | public static @NotNull Runnable runner(@NotNull Logger logger, 27 | @NotNull String owner, @NotNull String repo, 28 | @NotNull String currentVersion) { 29 | return of(logger, owner, repo).createRunner(currentVersion); 30 | } 31 | 32 | public static @NotNull Runnable runner(@NotNull Plugin plugin) { 33 | return of(plugin).createRunner(plugin.getDescription().getVersion()); 34 | } 35 | 36 | public static @NotNull BukkitTask run(@NotNull Plugin plugin) { 37 | return Bukkit.getScheduler().runTaskAsynchronously(plugin, runner(plugin)); 38 | } 39 | 40 | protected final @NotNull Logger logger; 41 | protected final @NotNull String owner; 42 | protected final @NotNull String repo; 43 | 44 | public GHUpdateChecker(@NotNull Logger logger, @NotNull String owner, @NotNull String repo) { 45 | this.logger = logger; 46 | this.owner = owner; 47 | this.repo = repo; 48 | } 49 | 50 | public void checkUpdate(@NotNull String currentVersion) { 51 | Integer behindVersions = GithubReleases4J.getVersionBehind(owner, repo, currentVersion); 52 | String downloadURL = GithubReleases4J.getReleasesURL(owner, repo); 53 | 54 | if (behindVersions == null) { 55 | this.logger.severe("检查更新失败,请您定期查看插件是否更新,避免安全问题。"); 56 | this.logger.severe("下载地址 " + downloadURL); 57 | } else if (behindVersions == 0) { 58 | this.logger.info("检查完成,当前已是最新版本。"); 59 | } else if (behindVersions > 0) { 60 | this.logger.info("发现新版本! 目前已落后 " + behindVersions + " 个版本。"); 61 | this.logger.info("最新版下载地址 " + downloadURL); 62 | } else { 63 | this.logger.severe("检查更新失败! 当前版本未知,请您使用原生版本以避免安全问题。"); 64 | this.logger.severe("最新版下载地址 " + downloadURL); 65 | } 66 | } 67 | 68 | public Runnable createRunner(@NotNull String currentVersion) { 69 | return () -> checkUpdate(currentVersion); 70 | } 71 | 72 | protected static String getGithubOwner(Plugin plugin) { 73 | // 首先,尝试从插件提供的网址中获取OWNER 74 | String websiteOwner = getGithubOwner(plugin.getDescription().getWebsite()); 75 | if (websiteOwner != null && !websiteOwner.isEmpty()) return websiteOwner; 76 | 77 | // 如果插件提供的网址中没有,则尝试获取插件的首位作者名 78 | List authors = plugin.getDescription().getAuthors(); 79 | if (!authors.isEmpty()) return authors.get(0); 80 | 81 | // 再没有的话只能返回插件的名称了 82 | return plugin.getName(); 83 | } 84 | 85 | protected static String getGithubOwner(String url) { 86 | Matcher matcher = GH_URL_PATTERN.matcher(url); 87 | return matcher.find() ? matcher.group(1) : null; 88 | } 89 | 90 | } -------------------------------------------------------------------------------- /extension/gh-checker/src/test/java/cc/carm/lib/easyplugin/updatechecker/RegexTest.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.updatechecker; 2 | 3 | import org.junit.Test; 4 | 5 | public class RegexTest { 6 | 7 | 8 | @Test 9 | public void onTest() { 10 | System.out.println(GHUpdateChecker.getGithubOwner("https://github.com/CarmJos/EasyPlugin")); 11 | System.out.println(GHUpdateChecker.getGithubOwner("https://github.com/Ghost-chu/QuickShop-Hikari/pulls")); 12 | System.out.println(GHUpdateChecker.getGithubOwner("https://github.com/QWQ123/QuickShop")); 13 | 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /extension/papi/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | 14 | ${project.jdk.version} 15 | ${project.jdk.version} 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | easyplugin-placeholderapi 21 | jar 22 | 23 | EasyPlugin-PlaceholderAPI 24 | EasyPlugin的 PlaceholderAPI 扩展模块,提供了方便的 PlaceholderAPI 变量注册方法。 25 | 26 | 27 | 28 | 29 | me.clip 30 | placeholderapi 31 | provided 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-javadoc-plugin 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /extension/papi/src/main/java/cc/carm/lib/easyplugin/papi/EasyPlaceholder.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.papi; 2 | 3 | import cc.carm.lib.easyplugin.papi.expansion.SectionExpansion; 4 | import cc.carm.lib.easyplugin.papi.expansion.SubExpansion; 5 | import cc.carm.lib.easyplugin.papi.handler.PlaceholderHandler; 6 | import me.clip.placeholderapi.expansion.PlaceholderExpansion; 7 | import org.bukkit.OfflinePlayer; 8 | import org.bukkit.plugin.java.JavaPlugin; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.function.Consumer; 15 | import java.util.function.Supplier; 16 | 17 | public class EasyPlaceholder extends PlaceholderExpansion { 18 | 19 | protected final @NotNull String plugin; 20 | protected final @NotNull SectionExpansion rootExpansion; 21 | 22 | protected final @NotNull String name; 23 | protected final @NotNull String author; 24 | protected final @NotNull String version; 25 | 26 | protected final boolean persistent; 27 | 28 | public EasyPlaceholder(@NotNull JavaPlugin plugin, @NotNull String rootIdentifier) { 29 | this( 30 | plugin.getName(), true, rootIdentifier, 31 | plugin.getName(), plugin.getDescription().getVersion(), 32 | String.join(", ", plugin.getDescription().getAuthors()) 33 | ); 34 | } 35 | 36 | public EasyPlaceholder(@NotNull JavaPlugin plugin, @NotNull SectionExpansion rootExpansion) { 37 | this( 38 | plugin.getName(), true, rootExpansion, 39 | plugin.getName(), plugin.getDescription().getVersion(), 40 | String.join(", ", plugin.getDescription().getAuthors()) 41 | ); 42 | } 43 | 44 | public EasyPlaceholder(@NotNull String plugin, boolean persistent, @NotNull String rootIdentifier, 45 | @NotNull String name, @NotNull String version, @NotNull String author) { 46 | super(); 47 | this.plugin = plugin; 48 | this.name = name; 49 | this.author = author; 50 | this.version = version; 51 | this.persistent = persistent; 52 | this.rootExpansion = new SectionExpansion(this, rootIdentifier); 53 | } 54 | 55 | public EasyPlaceholder(@NotNull String plugin, boolean persistent, 56 | @NotNull SectionExpansion rootExpansion, 57 | @NotNull String name, @NotNull String version, @NotNull String author) { 58 | super(); 59 | this.plugin = plugin; 60 | this.name = name; 61 | this.author = author; 62 | this.version = version; 63 | this.persistent = persistent; 64 | this.rootExpansion = rootExpansion; 65 | } 66 | 67 | /** 68 | * 得到根变量解析器 69 | * 70 | * @return 根变量解析器 71 | */ 72 | public @NotNull SectionExpansion getRootExpansion() { 73 | return rootExpansion; 74 | } 75 | 76 | /** 77 | * 当未找到对应变量处理器时调用 78 | * 79 | * @param player 变量解析时的目标玩家,可能为空或不在线。 80 | * @return 返回给玩家的内容 81 | */ 82 | public String onErrorParams(@Nullable OfflinePlayer player) { 83 | return "Wrong params"; 84 | } 85 | 86 | /** 87 | * 当变量处理器返回 NULL 值时调用 88 | * 89 | * @param player 变量解析时的目标玩家,可能为空或不在线。 90 | * @return 返回给玩家的内容 91 | */ 92 | public String onNullResponse(@Nullable OfflinePlayer player) { 93 | return ""; 94 | } 95 | 96 | /** 97 | * 当变量处理器抛出异常时调用 98 | * 99 | * @param player 变量解析时的目标玩家,可能为空或不在线。 100 | * @param expansion 抛出异常的变量处理器 101 | * @param exception 异常内容 102 | * @return 返回给玩家的内容 103 | */ 104 | public String onException(@Nullable OfflinePlayer player, @NotNull SubExpansion expansion, @NotNull Exception exception) { 105 | exception.printStackTrace(); 106 | return "Error \"" + expansion.getIdentifier() + "\""; 107 | } 108 | 109 | /** 110 | * 处理变量并返回对应内容。 111 | * 112 | * @param identifier 该变量的标识符 113 | * @param handler 该变量的处理器,返回值将会被转换为字符串。 114 | * @param aliases 该变量的别称 115 | * @return {@link EasyPlaceholder} 116 | */ 117 | public final EasyPlaceholder handle(@NotNull String identifier, @NotNull PlaceholderHandler handler, 118 | @NotNull String... aliases) { 119 | this.rootExpansion.handle(identifier, handler, aliases); 120 | return this; 121 | } 122 | 123 | /** 124 | * 处理变量并返回对应内容。 125 | * 126 | * @param identifier 该变量的标识符 127 | * @param handler 该变量的处理器,返回值将会被转换为字符串。 128 | * @param paramsConsumer 用于提供该变量的可用参数 129 | * @param aliases 该变量的别称 130 | * @return {@link EasyPlaceholder} 131 | */ 132 | public final EasyPlaceholder handle(@NotNull String identifier, @NotNull PlaceholderHandler handler, 133 | @NotNull Consumer> paramsConsumer, @NotNull String... aliases) { 134 | this.rootExpansion.handle(identifier, handler, paramsConsumer, aliases); 135 | return this; 136 | } 137 | 138 | /** 139 | * 处理变量并返回对应内容。 140 | * 141 | * @param identifier 该变量的标识符 142 | * @param handler 该变量的处理器,返回值将会被转换为字符串。 143 | * @param availableParams 该变量的可用参数 144 | * @param aliases 该变量的别称 145 | * @return {@link EasyPlaceholder} 146 | */ 147 | public final EasyPlaceholder handle(@NotNull String identifier, @NotNull PlaceholderHandler handler, 148 | @NotNull List availableParams, @NotNull String... aliases) { 149 | this.rootExpansion.handle(identifier, handler, availableParams, aliases); 150 | return this; 151 | } 152 | 153 | /** 154 | * 处理变量并返回对应内容。 155 | * 156 | * @param identifier 该变量的标识符 157 | * @param handler 该变量的处理器,返回值将会被转换为字符串。 158 | * @param availableParams 该变量的可用参数 159 | * @param aliases 该变量的别称 160 | * @return {@link EasyPlaceholder} 161 | */ 162 | public final EasyPlaceholder handle(String identifier, @NotNull PlaceholderHandler handler, 163 | @NotNull Supplier> availableParams, @NotNull String... aliases) { 164 | this.rootExpansion.handle(identifier, handler, availableParams, aliases); 165 | return this; 166 | } 167 | 168 | /** 169 | * 处理一组变量。 170 | * 171 | * @param section 该组变量的标识符 172 | * @param consumer 该组变量的处理器操作方法 173 | *
在其中可调用 {@link SectionExpansion#handle(String, PlaceholderHandler, String...)} 方法处理子变量, 174 | *
或者调用 {@link SectionExpansion#handleSection(String, Consumer, String...)} 方法处理下一层组变量 175 | * @param aliases 该变量的别称 176 | * @return {@link EasyPlaceholder} 177 | */ 178 | public final EasyPlaceholder handleSection(@NotNull String section, 179 | @NotNull Consumer consumer, 180 | @NotNull String... aliases) { 181 | this.rootExpansion.handleSection(section, consumer, aliases); 182 | return this; 183 | } 184 | 185 | @Override 186 | public String onRequest(@Nullable OfflinePlayer player, @NotNull String params) { 187 | String[] args = params.split("_"); 188 | if (args.length == 0) return onErrorParams(player); 189 | 190 | Object response = rootExpansion.handleRequest(player, args); 191 | if (response == null) return onNullResponse(player); 192 | else return response.toString(); 193 | } 194 | 195 | @Override 196 | public @Nullable String getRequiredPlugin() { 197 | return this.plugin; 198 | } 199 | 200 | @Override 201 | public @NotNull String getIdentifier() { 202 | return this.rootExpansion.getIdentifier(); 203 | } 204 | 205 | @Override 206 | public @NotNull String getAuthor() { 207 | return this.author; 208 | } 209 | 210 | @Override 211 | public @NotNull String getVersion() { 212 | return this.version; 213 | } 214 | 215 | @Override 216 | public @NotNull String getName() { 217 | return this.name; 218 | } 219 | 220 | @Override 221 | public @NotNull List getPlaceholders() { 222 | return this.rootExpansion.listPlaceholders(); 223 | } 224 | 225 | @Override 226 | public boolean persist() { 227 | return this.persistent; 228 | } 229 | 230 | 231 | } 232 | -------------------------------------------------------------------------------- /extension/papi/src/main/java/cc/carm/lib/easyplugin/papi/expansion/EasyExpansion.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.papi.expansion; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public interface EasyExpansion { 8 | 9 | @NotNull String getIdentifier(); 10 | 11 | @NotNull List getAliases(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /extension/papi/src/main/java/cc/carm/lib/easyplugin/papi/expansion/SectionExpansion.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.papi.expansion; 2 | 3 | import cc.carm.lib.easyplugin.papi.EasyPlaceholder; 4 | import cc.carm.lib.easyplugin.papi.handler.PlaceholderHandler; 5 | import org.bukkit.OfflinePlayer; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.*; 10 | import java.util.function.Consumer; 11 | import java.util.function.Supplier; 12 | 13 | public class SectionExpansion implements EasyExpansion { 14 | 15 | protected final EasyPlaceholder root; 16 | 17 | protected final @NotNull String identifier; 18 | protected final @NotNull List aliases; 19 | 20 | protected final @NotNull Map registeredSections = new HashMap<>(); 21 | protected final @NotNull Map> registeredExpansions = new HashMap<>(); 22 | 23 | protected final @NotNull Map aliasesMap = new HashMap<>(); 24 | 25 | public SectionExpansion(@NotNull EasyPlaceholder root, 26 | @NotNull String identifier, @NotNull String... aliases) { 27 | this(root, identifier, Arrays.asList(aliases)); 28 | } 29 | 30 | public SectionExpansion(@NotNull EasyPlaceholder root, 31 | @NotNull String identifier, @NotNull List aliases) { 32 | this.root = root; 33 | this.identifier = identifier; 34 | this.aliases = aliases; 35 | } 36 | 37 | public EasyPlaceholder getRoot() { 38 | return root; 39 | } 40 | 41 | @NotNull 42 | @Override 43 | public String getIdentifier() { 44 | return identifier; 45 | } 46 | 47 | @Override 48 | public @NotNull List getAliases() { 49 | return this.aliases; 50 | } 51 | 52 | public void register(@NotNull SubExpansion placeholder) { 53 | String name = placeholder.getIdentifier().toLowerCase(); 54 | this.registeredExpansions.put(name, placeholder); 55 | placeholder.getAliases().forEach(alias -> this.aliasesMap.put(alias.toLowerCase(), name)); 56 | } 57 | 58 | public final void register(@NotNull SectionExpansion placeholder) { 59 | String name = placeholder.getIdentifier().toLowerCase(); 60 | this.registeredSections.put(name, placeholder); 61 | placeholder.getAliases().forEach(alias -> this.aliasesMap.put(alias.toLowerCase(), name)); 62 | } 63 | 64 | /** 65 | * 处理变量并返回对应内容。 66 | * 67 | * @param identifier 该变量的标识符 68 | * @param handler 该变量的处理器,返回值将会被转换为字符串。 69 | * @param aliases 该变量的别称 70 | */ 71 | public final void handle(@NotNull String identifier, @NotNull PlaceholderHandler handler, 72 | @NotNull String... aliases) { 73 | handle(identifier, handler, Collections.emptyList(), aliases); 74 | } 75 | 76 | /** 77 | * 处理变量并返回对应内容。 78 | * 79 | * @param identifier 该变量的标识符 80 | * @param handler 该变量的处理器,返回值将会被转换为字符串。 81 | * @param paramsConsumer 用于提供该变量的可用参数 82 | * @param aliases 该变量的别称 83 | */ 84 | public final void handle(@NotNull String identifier, @NotNull PlaceholderHandler handler, 85 | @NotNull Consumer> paramsConsumer, @NotNull String... aliases) { 86 | handle(identifier, handler, () -> { 87 | ArrayList params = new ArrayList<>(); 88 | paramsConsumer.accept(params); 89 | return params; 90 | }, aliases); 91 | } 92 | 93 | /** 94 | * 处理变量并返回对应内容。 95 | * 96 | * @param identifier 该变量的标识符 97 | * @param handler 该变量的处理器,返回值将会被转换为字符串。 98 | * @param availableParams 该变量的可用参数 99 | * @param aliases 该变量的别称 100 | */ 101 | public final void handle(@NotNull String identifier, @NotNull PlaceholderHandler handler, 102 | @NotNull List availableParams, @NotNull String... aliases) { 103 | handle(identifier, handler, () -> availableParams, aliases); 104 | } 105 | 106 | /** 107 | * 处理变量并返回对应内容。 108 | * 109 | * @param identifier 该变量的标识符 110 | * @param handler 该变量的处理器,返回值将会被转换为字符串。 111 | * @param availableParams 该变量的可用参数 112 | * @param aliases 该变量的别称 113 | */ 114 | public final void handle(@NotNull String identifier, @NotNull PlaceholderHandler handler, 115 | @NotNull Supplier> availableParams, @NotNull String... aliases) { 116 | register(new SubExpansion(this, identifier, aliases) { 117 | @Override 118 | public Object handle(@Nullable OfflinePlayer player, @NotNull String[] args) throws Exception { 119 | return handler.handle(player, args); 120 | } 121 | 122 | @Override 123 | public List listAvailableParams() { 124 | return availableParams.get(); 125 | } 126 | }); 127 | } 128 | 129 | /** 130 | * 处理一组变量。 131 | * 132 | * @param section 该组变量的标识符 133 | * @param consumer 该组变量的处理器操作方法 134 | *
在其中可调用 {@link SectionExpansion#handle(String, PlaceholderHandler, String...)} 方法处理子变量, 135 | *
或者调用 {@link SectionExpansion#handleSection(String, Consumer, String...)} 方法处理下一层组变量 136 | * @param aliases 该变量的别称 137 | */ 138 | public final void handleSection(@NotNull String section, @NotNull Consumer consumer, 139 | @NotNull String... aliases) { 140 | SectionExpansion sectionExpansion = new SectionExpansion(getRoot(), section, aliases); 141 | consumer.accept(sectionExpansion); 142 | register(sectionExpansion); 143 | } 144 | 145 | public final @Nullable Object handleRequest(@Nullable OfflinePlayer player, @NotNull String[] args) { 146 | if (args.length == 0) return getRoot().onErrorParams(player); 147 | String input = args[0].toLowerCase(); 148 | 149 | SectionExpansion group = getHandler(input); 150 | if (group != null) return group.handleRequest(player, this.shortenArgs(args)); 151 | 152 | SubExpansion sub = getSubPlaceholder(input); 153 | if (sub == null) return getRoot().onErrorParams(player); 154 | 155 | try { 156 | return sub.handle(player, this.shortenArgs(args)); 157 | } catch (Exception ex) { 158 | return getRoot().onException(player, sub, ex); 159 | } 160 | } 161 | 162 | public List listPlaceholders() { 163 | List placeholders = new ArrayList<>(); 164 | 165 | String currentID = getIdentifier(); 166 | 167 | for (SectionExpansion section : this.registeredSections.values()) { 168 | for (String groupID : section.listPlaceholders()) { 169 | placeholders.add(currentID + "_" + groupID); 170 | } 171 | } 172 | 173 | for (SubExpansion placeholder : this.registeredExpansions.values()) { 174 | String identifier = placeholder.getIdentifier(); 175 | 176 | List params = placeholder.listAvailableParams(); 177 | if (params.isEmpty()) { 178 | placeholders.add(currentID + "_" + identifier); 179 | continue; 180 | } 181 | 182 | for (String param : params) { 183 | placeholders.add(currentID + "_" + identifier + "_" + param); 184 | } 185 | 186 | } 187 | 188 | return placeholders; 189 | } 190 | 191 | 192 | protected @Nullable SectionExpansion getHandler(@NotNull String name) { 193 | SectionExpansion fromName = this.registeredSections.get(name); 194 | if (fromName != null) return fromName; 195 | 196 | String nameFromAlias = this.aliasesMap.get(name); 197 | if (nameFromAlias == null) return null; 198 | else return this.registeredSections.get(nameFromAlias); 199 | } 200 | 201 | protected @Nullable SubExpansion getSubPlaceholder(@NotNull String name) { 202 | SubExpansion fromName = this.registeredExpansions.get(name); 203 | if (fromName != null) return fromName; 204 | 205 | String nameFromAlias = this.aliasesMap.get(name); 206 | if (nameFromAlias == null) return null; 207 | else return this.registeredExpansions.get(nameFromAlias); 208 | } 209 | 210 | protected String[] shortenArgs(String[] args) { 211 | if (args.length == 0) { 212 | return args; 213 | } else { 214 | List argList = new ArrayList<>(Arrays.asList(args).subList(1, args.length)); 215 | return argList.toArray(new String[0]); 216 | } 217 | } 218 | 219 | } 220 | -------------------------------------------------------------------------------- /extension/papi/src/main/java/cc/carm/lib/easyplugin/papi/expansion/SubExpansion.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.papi.expansion; 2 | 3 | import org.bukkit.OfflinePlayer; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.Arrays; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | public abstract class SubExpansion implements EasyExpansion { 12 | 13 | protected final @NotNull PARENT parent; 14 | protected final @NotNull String identifier; 15 | protected final @NotNull List aliases; 16 | 17 | public SubExpansion(@NotNull PARENT parent, 18 | @NotNull String identifier, @NotNull String... aliases) { 19 | this.parent = parent; 20 | this.identifier = identifier; 21 | this.aliases = Arrays.asList(aliases); 22 | } 23 | 24 | public abstract Object handle(@Nullable OfflinePlayer player, @NotNull String[] args) throws Exception; 25 | 26 | /** 27 | * 用于提示此子变量的全部可用参数 28 | * 29 | * @return 该子变量的全部可用参数 30 | */ 31 | public List listAvailableParams() { 32 | return Collections.emptyList(); 33 | } 34 | 35 | @Override 36 | public @NotNull String getIdentifier() { 37 | return this.identifier; 38 | } 39 | 40 | @Override 41 | public @NotNull List getAliases() { 42 | return this.aliases; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /extension/papi/src/main/java/cc/carm/lib/easyplugin/papi/handler/PlaceholderHandler.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.papi.handler; 2 | 3 | import org.bukkit.OfflinePlayer; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | @FunctionalInterface 8 | public interface PlaceholderHandler { 9 | 10 | @Nullable Object handle(@Nullable OfflinePlayer player, @NotNull String[] args) throws Exception; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /extension/papi/src/test/java/cc/carm/tests/easyplugin/papi/DemoPlaceholder.java: -------------------------------------------------------------------------------- 1 | package cc.carm.tests.easyplugin.papi; 2 | 3 | import cc.carm.lib.easyplugin.papi.EasyPlaceholder; 4 | import cc.carm.lib.easyplugin.papi.expansion.SubExpansion; 5 | import org.bukkit.OfflinePlayer; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.bukkit.inventory.PlayerInventory; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.util.Arrays; 13 | import java.util.Objects; 14 | 15 | public class DemoPlaceholder extends EasyPlaceholder { 16 | 17 | public DemoPlaceholder() { 18 | super( 19 | "TestPlugin", true, "TestPlaceholder", 20 | "TestPlugin", "1.0.0", "Carm" 21 | ); 22 | 23 | handle("version", (player, args) -> "1.0.0", "ver", "v"); 24 | handleSection("game", (section) -> { 25 | 26 | // 即处理 %TestPlaceholder_game_items% 27 | section.handle("items", ((player, args) -> { 28 | if (player == null || !player.isOnline() || !(player instanceof Player)) return -1; 29 | PlayerInventory inv = ((Player) player).getInventory(); 30 | return Arrays.stream(inv.getContents()) 31 | .filter(Objects::nonNull) 32 | .mapToInt(ItemStack::getAmount) 33 | .count(); 34 | })); 35 | 36 | // 即处理 %TestPlaceholder_game_location% 或 %TestPlaceholder_game_loc% 37 | section.handle("location", (player, args) -> { 38 | if (player == null || !player.isOnline() || !(player instanceof Player)) return "Unknown"; 39 | return ((Player) player).getLocation(); 40 | }, "loc" /* 声明此变量的别称*/); 41 | 42 | // 即处理 %TestPlaceholder_game_time% 43 | section.handle("time", (player, args) -> System.currentTimeMillis()); 44 | 45 | section.handle("random", 46 | (player, args) -> { 47 | if (args.length == 0) return Math.random(); 48 | else if (args.length == 1) return Math.random() * Double.parseDouble(args[0]); 49 | else if (args.length == 2) { 50 | return Math.random() * (Double.parseDouble(args[1]) - Double.parseDouble(args[0])) + Double.parseDouble(args[0]); 51 | } else return onErrorParams(player); 52 | }, 53 | (params) -> { 54 | params.add("<最小值>_<最大值>"); 55 | params.add("<基础值(乘随机数)>"); 56 | }); 57 | 58 | }, "g"); 59 | 60 | } 61 | 62 | @Override 63 | public String onErrorParams(@Nullable OfflinePlayer player) { 64 | return super.onErrorParams(player); 65 | } 66 | 67 | @Override 68 | public String onNullResponse(@Nullable OfflinePlayer player) { 69 | return super.onNullResponse(player); 70 | } 71 | 72 | @Override 73 | public String onException(@Nullable OfflinePlayer player, @NotNull SubExpansion expansion, @NotNull Exception exception) { 74 | return super.onException(player, expansion, exception); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /extension/papi/src/test/java/cc/carm/tests/easyplugin/papi/PlaceholderTest.java: -------------------------------------------------------------------------------- 1 | package cc.carm.tests.easyplugin.papi; 2 | 3 | import cc.carm.lib.easyplugin.papi.EasyPlaceholder; 4 | import org.junit.Test; 5 | 6 | public class PlaceholderTest { 7 | 8 | 9 | @Test 10 | public void onTest() { 11 | DemoPlaceholder placeholder = new DemoPlaceholder(); 12 | 13 | System.out.println("# Placeholders"); 14 | placeholder.getPlaceholders().forEach(s -> System.out.println(" -> " + s)); 15 | 16 | System.out.println(); 17 | System.out.println("# Request tests"); 18 | 19 | test(placeholder, "game_items"); 20 | test(placeholder, "g_time"); 21 | test(placeholder, "game_loc"); 22 | test(placeholder, "ver"); 23 | 24 | test(placeholder, "game_random"); 25 | test(placeholder, "game_random_0_5"); 26 | test(placeholder, "game_random_100"); 27 | 28 | System.out.println("# Error tests"); 29 | test(placeholder, "game_random_try"); 30 | } 31 | 32 | private void test(EasyPlaceholder placeholder, String input) { 33 | System.out.println(" " + input + " -> " + placeholder.onRequest(null, input)); 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /extension/vault/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easyplugin-parent 7 | cc.carm.lib 8 | 1.5.13 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | 14 | ${project.jdk.version} 15 | ${project.jdk.version} 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | easyplugin-vault 21 | jar 22 | 23 | EasyPlugin-Vault 24 | 25 | 26 | 27 | 28 | 29 | com.github.MilkBowl 30 | VaultAPI 31 | provided 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | org.apache.maven.plugins 41 | maven-javadoc-plugin 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /extension/vault/src/main/java/cc/carm/lib/easyplugin/vault/EasyVault.java: -------------------------------------------------------------------------------- 1 | package cc.carm.lib.easyplugin.vault; 2 | 3 | import net.milkbowl.vault.economy.Economy; 4 | import net.milkbowl.vault.economy.EconomyResponse; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.OfflinePlayer; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.plugin.RegisteredServiceProvider; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class EasyVault { 12 | public static boolean hasVault() { 13 | return Bukkit.getServer().getPluginManager().getPlugin("Vault") != null; 14 | } 15 | 16 | public static @NotNull EasyVault create() throws Exception { 17 | return new EasyVault(); 18 | } 19 | 20 | private Economy economy = null; 21 | 22 | public EasyVault() throws Exception { 23 | if (!setupEconomy()) throw new Exception("Vault not found!"); 24 | } 25 | 26 | public boolean setupEconomy() { 27 | if (!hasVault()) return false; 28 | RegisteredServiceProvider rsp = Bukkit.getServer().getServicesManager().getRegistration(Economy.class); 29 | if (rsp == null) return false; 30 | 31 | this.economy = rsp.getProvider(); 32 | return true; 33 | } 34 | 35 | public Economy getEconomy() { 36 | return economy; 37 | } 38 | 39 | public double getMoney(@NotNull Player player) { 40 | try { 41 | return getEconomy().getBalance(player); 42 | } catch (NullPointerException ignore) { 43 | return 0L; 44 | } 45 | } 46 | 47 | public double getMoney(@NotNull OfflinePlayer player) { 48 | try { 49 | return getEconomy().getBalance(player); 50 | } catch (NullPointerException ignore) { 51 | return 0L; 52 | } 53 | } 54 | 55 | public boolean checkMoney(@NotNull OfflinePlayer player, double amount) { 56 | return getMoney(player) >= amount; 57 | } 58 | 59 | public boolean checkMoney(@NotNull Player player, double amount) { 60 | return getMoney(player) >= amount; 61 | } 62 | 63 | public EconomyResponse removeMoney(Player player, double amount) { 64 | return getEconomy().withdrawPlayer(player, amount); 65 | } 66 | 67 | public EconomyResponse removeMoney(OfflinePlayer player, double amount) { 68 | return getEconomy().withdrawPlayer(player, amount); 69 | } 70 | 71 | public EconomyResponse addMoney(Player player, double amount) { 72 | return getEconomy().depositPlayer(player, amount); 73 | } 74 | 75 | public EconomyResponse addMoney(OfflinePlayer player, double amount) { 76 | return getEconomy().depositPlayer(player, amount); 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | --------------------------------------------------------------------------------