From ebe43a816e3294854022e0cbef4754105fc32301 Mon Sep 17 00:00:00 2001 From: carm Date: Wed, 22 Jun 2022 23:28:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(listener):=20=E6=8F=90=E4=BE=9B=E7=AE=80?= =?UTF-8?q?=E5=8D=95=E5=BF=AB=E6=8D=B7=E7=9A=84=E9=80=9A=E7=94=A8Spigot?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E7=9B=91=E5=90=AC=E5=99=A8=E7=B1=BB=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .documentation/javadoc/JAVADOC-README.md | 9 + .github/FUNDING.yml | 2 + .github/ISSUE_TEMPLATE/bugs_report.md | 37 +++ .github/ISSUE_TEMPLATE/feature_issues.md | 23 ++ .github/dependabot.yml | 11 + .github/gpg_public.key | 41 +++ .github/workflows/codeql-analysis.yml | 70 +++++ .github/workflows/deploy.yml | 61 +++++ .github/workflows/javadoc.yml | 74 +++++ .github/workflows/maven.yml | 36 +++ .gitignore | 3 + LICENSE | 165 +++++++++++ README.md | 133 +++++++++ pom.xml | 258 ++++++++++++++++++ .../carm/lib/easylisteners/EasyListener.java | 213 +++++++++++++++ src/test/java/DemoPlugin.java | 46 ++++ 16 files changed, 1182 insertions(+) create mode 100644 .documentation/javadoc/JAVADOC-README.md create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/bugs_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_issues.md create mode 100644 .github/dependabot.yml create mode 100644 .github/gpg_public.key create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/javadoc.yml create mode 100644 .github/workflows/maven.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/cc/carm/lib/easylisteners/EasyListener.java create mode 100644 src/test/java/DemoPlugin.java diff --git a/.documentation/javadoc/JAVADOC-README.md b/.documentation/javadoc/JAVADOC-README.md new file mode 100644 index 0000000..100125f --- /dev/null +++ b/.documentation/javadoc/JAVADOC-README.md @@ -0,0 +1,9 @@ +# EasyListener Javadoc + +基于 [Github Pages](https://pages.github.com/) 搭建,请访问 [JavaDoc](https://carmjos.github.io/EasyListener) 。 + +## 如何实现? + +若您也想通过 [Github Actions](https://docs.github.com/en/actions/learn-github-actions) +自动部署项目的Javadoc到 [Github Pages](https://pages.github.com/) , +可以参考我的文章 [《自动部署Javadoc到Github Pages》](https://pages.carm.cc/doc/javadoc-in-github.html) 。 \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..b5667d3 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [ CarmJos ] +custom: [ 'https://donate.carm.cc' ] diff --git a/.github/ISSUE_TEMPLATE/bugs_report.md b/.github/ISSUE_TEMPLATE/bugs_report.md new file mode 100644 index 0000000..0efcb43 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bugs_report.md @@ -0,0 +1,37 @@ +--- +name: 问题提交 +about: 描述问题并提交,帮助我们对其进行检查与修复。 +title: '' +labels: bug +assignees: '' + +--- + +### **问题简述** + +用简短的话语描述一下大概问题。 + +### **问题来源** + +描述一下通过哪些操作才发现的问题,如: + +1. 使用了 '...' +2. 输入了 '....' +3. 出现了报错 '....' + +### **预期结果** (可选) + +如果问题不发生,应该是什么情况 + +### **问题截图/问题报错** + +如果有报错或输出,请提供截图。 + +### **操作环境** + +- 系统环境: `Windows 10` / `Ubuntu` / `...` +- Java版本: `JDK11` / `OPENJDK8` / `JRE8` / `...` + +### **其他补充** + +如有其他补充,可以在这里描述。 diff --git a/.github/ISSUE_TEMPLATE/feature_issues.md b/.github/ISSUE_TEMPLATE/feature_issues.md new file mode 100644 index 0000000..779ae79 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_issues.md @@ -0,0 +1,23 @@ +--- +name: 功能需求 +about: 希望我们提供更多的功能。 +title: '' +labels: enhancement +assignees: '' +--- + +### **功能简述** + +简单的描述一下你想要的功能 + +### **需求来源** + +简单的描述一下为什么需要这个功能。 + +### **功能参考**(可选) + +如果有相关功能的参考,如文本、截图,请提供给我们。 + +### **附加内容** + +如果有什么小细节需要重点注意,请在这里告诉我们。 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..76e22be --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "maven" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" diff --git a/.github/gpg_public.key b/.github/gpg_public.key new file mode 100644 index 0000000..653bac3 --- /dev/null +++ b/.github/gpg_public.key @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +OK7d0W/LdJ3iFeselROADHgPQn14sg== +=rRA5 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..d6f8837 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Analysis" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '45 12 * * 1' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'java' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..ea42493 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,61 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: "Deploy & Publish" + +on: + # 支持手动触发构建 + workflow_dispatch: + release: + # 创建release的时候触发 + types: [ published ] + +jobs: + gh-deploy: + name: "Deploy Project (GitHub)" + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: "Set up JDK" + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + cache: maven + server-id: github + server-username: MAVEN_USERNAME + server-password: MAVEN_TOKEN + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import + gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase + + - name: "Maven Deploy" + run: mvn -B -Pgithub deploy --file pom.xml -DskipTests + env: + MAVEN_USERNAME: ${{ github.repository_owner }} + MAVEN_TOKEN: ${{secrets.GITHUB_TOKEN}} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + + central-deploy: + name: "Deploy Project (Central)" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: "Set up JDK" + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + cache: maven + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import + gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase + + - name: "Central Deploy" + run: mvn -B -Possrh deploy --file pom.xml -DskipTests + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USER }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_PASS }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml new file mode 100644 index 0000000..ce6c7c6 --- /dev/null +++ b/.github/workflows/javadoc.yml @@ -0,0 +1,74 @@ +name: "Publish Javadoc" + +on: + # 支持手动触发构建 + workflow_dispatch: + release: + # 创建release的时候触发 + types: [ published ] + + +jobs: + + javadoc-deploy: + name: "Deploy Javadoc (Github Pages)" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: "Set up JDK" + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + cache: maven + + - name: "Generate Javadoc" + run: mvn -B javadoc:aggregate --file pom.xml -DskipTests + + - name: "Copy Javadoc" + run: | + rm -rf docs + mkdir -vp docs + cp -vrf target/site/apidocs/* docs/ + cp -vrf .documentation/javadoc/JAVADOC-README.md docs/README.md + + - name: "Generate Sitemap" + id: sitemap + uses: cicirello/generate-sitemap@v1 + with: + base-url-path: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }} + path-to-root: docs + + - name: Output stats + run: | + echo "sitemap-path = ${{ steps.sitemap.outputs.sitemap-path }}" + echo "url-count = ${{ steps.sitemap.outputs.url-count }}" + echo "excluded-count = ${{ steps.sitemap.outputs.excluded-count }}" + ls -l docs + + - name: Configure Git + env: + DEPLOY_PRI: ${{secrets.DEPLOY_PRI}} + run: | + sudo timedatectl set-timezone "Asia/Shanghai" + mkdir -p ~/.ssh/ + echo "$DEPLOY_PRI" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + ssh-keyscan github.com >> ~/.ssh/known_hosts + git config --global user.name '${{ github.repository_owner }}' + git config --global user.email '${{ github.repository_owner }}@users.noreply.github.com' + + - name: Commit documentation changes + run: | + echo "Committing changes to git@github.com:${{ github.repository_owner }}/${{ github.event.repository.name }}.git ..." + cd docs + git init + git remote add origin git@github.com:${{ github.repository_owner }}/${{ github.event.repository.name }}.git + git checkout -b gh-pages + git add -A + git commit -m "API Document generated." + + - name: Javadoc Website Push + run: | + cd docs + git push origin HEAD:gh-pages --force \ No newline at end of file diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..372985b --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,36 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Build & Tests + +on: + # 支持手动触发构建 + workflow_dispatch: + pull_request: + push: + paths-ignore: + - ".github/**" + - "README.md" + - "LICENCE" + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: "Set up JDK" + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + - name: "Package" + run: mvn -B package --file pom.xml -Dgpg.skip + - name: "Target Stage" + run: mkdir staging && cp */target/*.jar staging + - name: "Upload artifact" + uses: actions/upload-artifact@v2 + with: + name: Artifact + path: staging diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7f0d54 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.idea/ +**/target/ +**.iml \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..153d416 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..22cf6fa --- /dev/null +++ b/README.md @@ -0,0 +1,133 @@ +# EasyListener + +[![version](https://img.shields.io/github/v/release/CarmJos/EasyListener)](https://github.com/CarmJos/EasyListener/releases) +[![License](https://img.shields.io/github/license/CarmJos/EasyListener)](https://opensource.org/licenses/MIT) +[![workflow](https://github.com/CarmJos/EasyListener/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/EasyListener/actions/workflows/maven.yml) +![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyListener) +![](https://visitor-badge.glitch.me/badge?page_id=EasyListener.readme) + +轻松(做)监听,简单快捷的通用Bukkit插件监听器类库。 + +### 开发示例 + +```java + +public class DemoPlugin extends JavaPlugin { + + protected final EasyListener listeners = new EasyListener(this); + + @Override + public void onEnable() { + listeners + .handle(PlayerInteractAtEntityEvent.class, (event) -> { + Entity clicked = event.getRightClicked(); + Player player = event.getPlayer(); + + if (clicked instanceof Player) { + player.sendMessage("你点了 " + clicked.getName() + " 一下!"); + } + + })// 处理一个事件 + .cancelDeath(null) // 所有玩家取消死亡 + .cancelBreak(player -> !player.isOp()) // 禁止非OP玩家破坏方块/接水或岩浆 + .cancelPlace(player -> !player.isOp()) // 禁止非OP玩家放置方块/放水或岩浆 + .cancelPVP((attacker, victim) -> !attacker.isOp()) // 禁止非op玩家PVP + .cancelWeatherChange() // 取消天气变更 + .cancelJoinMessage() // 取消加入消息 +// .cancelQuitMessage() +// .handleJoinMessage(player -> "玩家 " + player.getName() + " 加入了服务器。") + .handleQuitMessage(player -> "玩家 " + player.getName() + " 退出了服务器。") // 设定退出消息 + .cancel(PlayerPickupArrowEvent.class) // 禁止所有人捡箭 + .cancel( + EntityDamageEvent.class, EventPriority.HIGHEST, + (event) -> event.getCause() != EntityDamageEvent.DamageCause.ENTITY_ATTACK + ); // 有条件的取消一个事件 + + + } +} +``` + +### 依赖方式 + +
+展开查看Maven依赖方式 + +```xml + + + + + + + maven + Maven Central + https://repo1.maven.org/maven2 + + + + + EasyConfiguration + GitHub Packages + https://maven.pkg.github.com/CarmJos/EasyListener + + + + + carm-repo + Carm's Repo + https://repo.carm.cc/repository/maven-public/ + + + + + + + + cc.carm.lib + easylistener + [LATEST RELEASE] + compile + + + + + +``` + +
+ +
+展开查看Gradle依赖方式 + +```groovy +repositories { + + // 采用Maven中心库,安全稳定,但版本更新需要等待同步 + mavenCentral() + + // 采用github依赖库,实时更新,但需要配置 (推荐) + maven { url 'https://maven.pkg.github.com/CarmJos/EasyListener' } + + // 采用我的私人依赖库,简单方便,但可能因为变故而无法使用 + maven { url 'https://repo.carm.cc/repository/maven-public/' } +} + +dependencies { + api "cc.carm.lib:easylistener:[LATEST RELEASE]" +} +``` + +
+ +## 支持与捐赠 + +若您觉得本插件做的不错,您可以通过捐赠支持我! + +感谢您对开源项目的支持! + + + +## 开源协议 + +本项目源码采用 [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html) 开源协议。 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..547bba0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,258 @@ + + + 4.0.0 + + 8 + + ${project.jdk.version} + ${project.jdk.version} + UTF-8 + UTF-8 + + cc.carm.lib + easylistener + 1.0.0 + jar + + EasyListener + 轻松(做)监听,简单快捷的通用Bukkit插件监听器类库。 + https://github.com/CarmJos/EasyListener + + + scm:git:git@github.com:CarmJos/EasyListener.git + scm:git:git@github.com:CarmJos/EasyListener.git + https://github.com/CarmJos/EasyListener + HEAD + + + + + CarmJos + Carm Jos + carm@carm.cc + https://www.carm.cc + + + + + + GNU LESSER GENERAL PUBLIC LICENSE + https://www.gnu.org/licenses/lgpl-3.0.html + + + + + GitHub Issues + https://github.com/CarmJos/EasyListener/issues + + + + GitHub Actions + https://github.com/CarmJos/EasyListener/actions/workflows/maven.yml + + + + https://github.com/CarmJos/EasyListener/releases + + + + + + central + https://repo1.maven.org/maven2/ + + + + sonatype + https://oss.sonatype.org/content/groups/public + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + carm-repo + Carm's Repo + https://repo.carm.cc/repository/maven-public/ + + + + + + + + org.spigotmc + spigot + 1.13.2-R0.1-SNAPSHOT + provided + + + + org.jetbrains + annotations + 23.0.0 + provided + + + + junit + junit + 4.13.2 + test + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + false + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${project.jdk.version} + ${project.jdk.version} + UTF-8 + -parameters + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + package + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + javadoc + false + UTF-8 + UTF-8 + UTF-8 + zh_CN + + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.3 + + + package + + shade + + + false + + + + + + + *:* + + META-INF/MANIFEST.MF + META-INF/*.txt + + + + + + + + + + src/main/resources + true + + + + + + + + + ossrh + + + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + github + + + github + GitHub Packages + https://maven.pkg.github.com/CarmJos/EasyListener + + + + + + local + + + localRepository + file:${user.home}/local-deploy/ + + + localRepository + file:${user.home}/local-deploy/ + + + + + + + \ No newline at end of file diff --git a/src/main/java/cc/carm/lib/easylisteners/EasyListener.java b/src/main/java/cc/carm/lib/easylisteners/EasyListener.java new file mode 100644 index 0000000..db6d72b --- /dev/null +++ b/src/main/java/cc/carm/lib/easylisteners/EasyListener.java @@ -0,0 +1,213 @@ +package cc.carm.lib.easylisteners; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.*; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerBucketFillEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.weather.WeatherChangeEvent; +import org.bukkit.plugin.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Method; +import java.util.Optional; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +public class EasyListener implements Listener { + + protected final Plugin plugin; + + public EasyListener(Plugin plugin) { + this.plugin = plugin; + } + + private HandlerList getEventListeners(Class eventClass) { + try { + Method method = SimplePluginManager.class.getDeclaredMethod("getEventListeners", Class.class); + method.setAccessible(true); + return (HandlerList) method.invoke(Bukkit.getPluginManager(), eventClass); + } catch (Exception e) { + throw new IllegalPluginAccessException(e.toString()); + } + } + + private EventExecutor createExecutor(@NotNull Class eventClass, + @NotNull Consumer eventConsumer) { + return (listener, event) -> { + try { + if (!eventClass.isAssignableFrom(event.getClass())) return; + eventConsumer.accept(eventClass.cast(event)); + } catch (Throwable t) { + throw new EventException(t); + } + }; + } + + protected void register(Class eventClass, RegisteredListener listener) { + getEventListeners(eventClass).register(listener); + } + + public EasyListener handle(@NotNull Class eventClass, + @NotNull Consumer eventConsumer) { + return handle(eventClass, null, eventConsumer); + } + + public EasyListener handle(@NotNull Class eventClass, boolean ignoreCancelled, + @NotNull Consumer eventConsumer) { + return handle(eventClass, null, ignoreCancelled, eventConsumer); + } + + public EasyListener handle(@NotNull Class eventClass, @Nullable EventPriority priority, + @NotNull Consumer eventConsumer) { + return handle(eventClass, priority, false, eventConsumer); + } + + + public EasyListener handle(@NotNull Class eventClass, + @Nullable EventPriority priority, boolean ignoreCancelled, + @NotNull Consumer eventConsumer) { + final EventPriority eventPriority = Optional.ofNullable(priority).orElse(EventPriority.NORMAL); + + RegisteredListener registeredListener = new RegisteredListener( + this, createExecutor(eventClass, eventConsumer), + eventPriority, this.plugin, ignoreCancelled + ); + register(eventClass, registeredListener); + return this; + } + + public EasyListener cancel(@NotNull Class eventClass) { + return cancel(eventClass, null, null); + } + + public EasyListener cancel(@NotNull Class eventClass, @Nullable Predicate eventPredicate) { + return cancel(eventClass, null, eventPredicate); + } + + public EasyListener cancel(@NotNull Class eventClass, @Nullable EventPriority priority, @Nullable Predicate eventPredicate) { + if (!Cancellable.class.isAssignableFrom(eventClass)) { + throw new IllegalArgumentException("Event class " + eventClass.getName() + " is not cancellable"); + } + + Predicate predicate = Optional.ofNullable(eventPredicate).orElse(t -> true); + return handle(eventClass, priority, (event) -> { + if (predicate.test(event)) ((Cancellable) event).setCancelled(true); + }); + } + + public EasyListener cancelJoinMessage() { + return handleJoinMessage(null); + } + + public EasyListener handleJoinMessage(@Nullable Function joinMessage) { + final Function message = Optional.ofNullable(joinMessage).orElse(t -> ""); + return handle(PlayerJoinEvent.class, (event) -> event.setJoinMessage(message.apply(event.getPlayer()))); + } + + public EasyListener cancelQuitMessage() { + return handleQuitMessage(null); + } + + public EasyListener handleQuitMessage(@Nullable Function quitMessage) { + final Function message = Optional.ofNullable(quitMessage).orElse(t -> ""); + return handle(PlayerQuitEvent.class, (event) -> event.setQuitMessage(message.apply(event.getPlayer()))); + } + + public EasyListener cancelWeatherChange() { + return cancelWeatherChange(null); + } + + public EasyListener cancelWeatherChange(@Nullable Predicate weatherPredicate) { + return cancel(WeatherChangeEvent.class, weatherPredicate); + } + + public EasyListener cancelBreak(@Nullable Predicate player) { + final Predicate predicate = Optional.ofNullable(player).orElse(t -> true); + return cancelBreak( + (event) -> predicate.test(event.getPlayer()), + (event) -> predicate.test(event.getPlayer()) + ); + } + + public EasyListener cancelBreak(@Nullable Predicate blockBreakPredicate, + @Nullable Predicate bucketFillPredicate) { + return cancel(BlockBreakEvent.class, blockBreakPredicate) + .cancel(PlayerBucketFillEvent.class, bucketFillPredicate); + } + + public EasyListener cancelPlace(@Nullable Predicate player) { + final Predicate predicate = Optional.ofNullable(player).orElse(t -> true); + return cancelPlace( + (event) -> predicate.test(event.getPlayer()), + (event) -> predicate.test(event.getPlayer()) + ); + } + + public EasyListener cancelPlace(@Nullable Predicate blockBreakPredicate, + @Nullable Predicate bucketFillPredicate) { + return cancel(BlockPlaceEvent.class, blockBreakPredicate) + .cancel(PlayerBucketEmptyEvent.class, bucketFillPredicate); + } + + /** + * 有条件的取消玩家PVP。 + * + * @param predicate 判断器,返回true则取消事件。两参数分别为 attacker 与 victim 。 + * @return 当前实例 + */ + public EasyListener cancelPVP(@Nullable BiPredicate predicate) { + final BiPredicate p = Optional.ofNullable(predicate).orElse((attacker, victim) -> true); + return cancelAttack((attacker, damager) -> { + if (!(attacker instanceof Player) || !(damager instanceof Player)) return false; + else return p.test((Player) attacker, (Player) damager); + }); + } + + /** + * 有条件的取消两个实体间的伤害。 + * + * @param predicate 判断器,返回true则取消事件。两参数分别为 attacker 与 victim 。 + * @return 当前实例 + */ + public EasyListener cancelAttack(@Nullable BiPredicate predicate) { + final BiPredicate p = Optional.ofNullable(predicate).orElse((attacker, victim) -> true); + return cancel(EntityDamageByEntityEvent.class, (event) -> p.test(event.getDamager(), event.getEntity())); + } + + public EasyListener cancelDeath(@Nullable Predicate predicate) { + return cancelDeath(predicate, (event) -> { + event.setDeathMessage(null); + event.setKeepInventory(true); + event.setKeepLevel(true); + }); + } + + public EasyListener cancelDeath(@Nullable Predicate predicate, + @Nullable Consumer handler) { + final Predicate p = Optional.ofNullable(predicate).orElse((player) -> true); + return handle(PlayerDeathEvent.class, (event) -> { + if (!p.test(event.getEntity())) return; + event.getEntity().setHealth(event.getEntity().getMaxHealth()); + Optional.ofNullable(handler).ifPresent(consumer -> consumer.accept(event)); + }); + } + + public EasyListener cancelSpawn(@Nullable BiPredicate predicate) { + final BiPredicate p = Optional.ofNullable(predicate).orElse((entity, location) -> !(entity instanceof Player)); + return cancel(EntitySpawnEvent.class, (event) -> p.test(event.getEntity(), event.getLocation())); + } + +} diff --git a/src/test/java/DemoPlugin.java b/src/test/java/DemoPlugin.java new file mode 100644 index 0000000..70c2aed --- /dev/null +++ b/src/test/java/DemoPlugin.java @@ -0,0 +1,46 @@ +import cc.carm.lib.easylisteners.EasyListener; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerPickupArrowEvent; +import org.bukkit.plugin.java.JavaPlugin; + +public class DemoPlugin extends JavaPlugin { + + protected final EasyListener listeners = new EasyListener(this); + + + @Override + public void onEnable() { + listeners + .handle(PlayerInteractAtEntityEvent.class, (event) -> { + Entity clicked = event.getRightClicked(); + Player player = event.getPlayer(); + + if (clicked instanceof Player) { + player.sendMessage("你点了 " + clicked.getName() + " 一下!"); + } + + })// 处理一个事件 + .cancelDeath(null) // 所有玩家取消死亡 + .cancelBreak(player -> !player.isOp()) // 禁止非OP玩家破坏方块/接水或岩浆 + .cancelPlace(player -> !player.isOp()) // 禁止非OP玩家放置方块/放水或岩浆 + .cancelPVP((attacker, victim) -> !attacker.isOp()) // 禁止非op玩家PVP + .cancelWeatherChange() // 取消天气变更 + .cancelJoinMessage() // 取消加入消息 +// .cancelQuitMessage() +// .handleJoinMessage(player -> "玩家 " + player.getName() + " 加入了服务器。") + .handleQuitMessage(player -> "玩家 " + player.getName() + " 退出了服务器。") // 设定退出消息 + .cancel(PlayerPickupArrowEvent.class) // 禁止所有人捡箭 + .cancel( + EntityDamageEvent.class, EventPriority.HIGHEST, + (event) -> event.getCause() != EntityDamageEvent.DamageCause.ENTITY_ATTACK + ); // 有条件的取消一个事件 + + + } + + +}