diff --git a/.editorconfig b/.editorconfig index a8939e783fa5..198db6e8a17a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,6 +4,10 @@ end_of_line=lf insert_final_newline=true indent_style=space indent_size=4 +ij_any_block_comment_add_space = false +ij_any_block_comment_at_first_column = false +ij_any_line_comment_at_first_column = false +ij_any_line_comment_add_space = true [*.tiny] indent_style=tab @@ -16,3 +20,23 @@ indent_size=2 [*.patch] trim_trailing_whitespace=false + +[*.java] +ij_continuation_indent_size = 4 +ij_java_class_count_to_use_import_on_demand = 999999 +ij_java_insert_inner_class_imports = false +ij_java_names_count_to_use_import_on_demand = 999999 +ij_java_imports_layout = *,|,$* +ij_java_generate_final_locals = true +ij_java_generate_final_parameters = true +ij_java_method_parameters_new_line_after_left_paren = true +ij_java_method_parameters_right_paren_on_new_line = true + +[test-plugin/**/*.java] +ij_java_use_fq_class_names = false + +[Paper-Server/src/main/resources/data/**/*.json] +indent_size = 2 + +[paper-api-generator/generated/**/*.java] +ij_java_imports_layout = $*,|,* diff --git a/.gitattributes b/.gitattributes index 2fb638f44b9d..2ebd41bdf8ec 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ -* text=auto +* text=auto eol=lf *.sh text eol=lf gradlew text eol=lf diff --git a/.github/DISCUSSION_TEMPLATE/ideas.yml b/.github/DISCUSSION_TEMPLATE/ideas.yml new file mode 100644 index 000000000000..a7e34717244d --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/ideas.yml @@ -0,0 +1,42 @@ +labels: ["status: needs triage"] +body: + - type: markdown + attributes: + value: | + Thank you for filling out a feature request for Paper! Please be as detailed as possible so that we may consider and review the request easier. + We ask that you search all the issues to avoid a duplicate feature request. If one exists, please reply if you have anything to add. + Before requesting a new feature, please make sure you are using the latest version and that the feature you are requesting is not already in Paper. + + - type: textarea + attributes: + label: Is your feature request related to a problem? + description: Please give some context for this request. Why do you want it added? + validations: + required: true + + - type: textarea + attributes: + label: Describe the solution you'd like. + description: A clear and concise description of what you want. + validations: + required: true + + - type: textarea + attributes: + label: Describe alternatives you've considered. + description: List any alternatives you might have tried to get the feature you want. + validations: + required: true + + - type: textarea + attributes: + label: Other + description: Add any other context or screenshots about the feature request below. + validations: + required: false + + - type: markdown + attributes: + value: | + Before submitting this feature request, please search our issue tracker to ensure your feature has not + already been requested. diff --git a/.github/ISSUE_TEMPLATE/behavior-bug-or-plugin-incompatibility.yml b/.github/ISSUE_TEMPLATE/behavior-bug-or-plugin-incompatibility.yml deleted file mode 100644 index 51203455a302..000000000000 --- a/.github/ISSUE_TEMPLATE/behavior-bug-or-plugin-incompatibility.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: Behavior Bug or Plugin Incompatibility -description: Report issues with plugin incompatbility or other behavior related issues. -labels: [ "status: needs triage", "type: bug" ] -body: - - type: textarea - attributes: - label: Expected behavior - description: What you expected to see. - validations: - required: true - - - type: textarea - attributes: - label: Observed/Actual behavior - description: What you actually saw. - validations: - required: true - - - type: textarea - attributes: - label: Steps/models to reproduce - description: This may include a build schematic, a video, or detailed instructions to help reconstruct the issue. - validations: - required: true - - - type: textarea - attributes: - label: Plugin and Datapack List - description: | - All plugins and datapacks running on your server. - To list plugins, run `/plugins`. For datapacks, run `/datapack list`. - validations: - required: true - - - type: textarea - attributes: - label: Paper version - description: | - Run `/version` on your server and **paste** the full, unmodified output here. - "latest" is *not* a version; we require the output of `/version` so we can adequately track down the issue. - Additionally, do NOT provide a screenshot, you MUST paste the entire output. -
- Example - - ``` - > version - [20:34:42 INFO]: This server is running Paper version git-Paper-540 (MC: 1.16.5) (Implementing API version 1.16.5-R0.1-SNAPSHOT) - [20:34:42 INFO]: Checking version, please wait... - [20:34:42 INFO]: Previous version: git-Paper-538 (MC: 1.16.5) - [20:34:42 INFO]: You are running the latest version - ``` - -
- validations: - required: true - - - type: textarea - attributes: - label: Other - description: | - Please include other helpful information below. - The more information we receive, the quicker and more effective we can be at finding the solution to the issue. - validations: - required: false - - - type: markdown - attributes: - value: | - Before submitting this issue, please ensure the following: - - 1. You are running the latest version of Paper from [our downloads page](https://papermc.io/downloads). - 2. You searched for and ensured there isn't already an open issue regarding this. - 3. Your version of Minecraft is supported by Paper. - - If you think you have a bug but are not sure, feel free to ask the `#paper-help` channel of our - [Discord](https://discord.gg/papermc). - diff --git a/.github/ISSUE_TEMPLATE/bug-or-incompatibility.yml b/.github/ISSUE_TEMPLATE/bug-or-incompatibility.yml new file mode 100644 index 000000000000..5f25e871c956 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-or-incompatibility.yml @@ -0,0 +1,79 @@ +name: "🐛 Bug or Incompatibility" +description: Report issues related to unexpected behavior or vanilla/plugin incompatibility. +type: "Bug" +labels: + - "status: needs triage" +body: + - type: markdown + attributes: + value: | + Before submitting this issue, please ensure the following: + + 1. You are using the latest version of Paper, available on our [our downloads page](https://papermc.io/downloads/paper). + 2. You have searched to confirm there isn’t [an existing open issue](https://github.com/PaperMC/Paper/issues?q=is%3Aissue%20state%3Aopen%20type%3ABug) on this topic. + 3. Your version of Minecraft is supported by Paper. + + If you're unsure whether you've encountered a bug, feel free to ask in the `#paper-help` channel on our + [Discord](https://discord.gg/papermc). + + - type: textarea + attributes: + label: Expected behavior + description: What you expected to see. + validations: + required: true + + - type: textarea + attributes: + label: Observed/Actual behavior + description: What you actually saw. + validations: + required: true + + - type: textarea + attributes: + label: Steps/models to reproduce + description: This may include a build schematic, a video, or detailed instructions to help reconstruct the issue. + validations: + required: true + + - type: textarea + attributes: + label: Plugin and Datapack List + description: | + All plugins and datapacks running on your server. + To list plugins, run `/plugins`. For datapacks, run `/datapack list`. + validations: + required: true + + - type: textarea + attributes: + label: Paper version + description: | + Run `/version` on your server and **paste** the full, unmodified output here. + "latest" is *not* a version; we require the output of `/version` so we can adequately track down the issue. + Additionally, do NOT provide a screenshot, you MUST paste the entire output. +
+ Example + + ``` + > version + [20:34:42 INFO]: Checking version, please wait... + [20:34:42 INFO]: This server is running Paper version 1.21-105-master@7e91a2c (2024-07-20T21:04:31Z) (Implementing API version 1.21-R0.1-SNAPSHOT) + [20:34:42 INFO]: You are running the latest version + [20:34:42 INFO]: Previous version: 1.21-103-aa3b356 (MC: 1.21) + ``` + +
+ validations: + required: true + + - type: textarea + attributes: + label: Other + description: | + Please include other helpful information below. + The more information we receive, the quicker and more effective we can be at finding the solution to the issue. + validations: + required: false + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index eeba86028de1..7cf5bb011b07 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,10 +1,10 @@ blank_issues_enabled: false contact_links: - - name: PaperMC Discord - url: https://discord.gg/papermc - about: If you are having issues with timings or have other minor issues, come ask us on our Discord server! - - name: Exploit Report + - name: "❗Exploits" url: https://discord.gg/papermc about: | - Due to GitHub not currently allowing private issues, exploit reports are currently handled via our Discord. - To report an exploit, see the #paper-exploit-report channel. + Since GitHub doesn’t currently support private issues, exploit reports are managed through our Discord. + To report an exploit, please visit the #paper-exploit-report channel. + - name: "🗨 Questions" + url: https://discord.gg/papermc + about: If you have questions or need help with any minor issues, feel free to ask us on our Discord server! diff --git a/.github/ISSUE_TEMPLATE/crash-or-stacktrace.yml b/.github/ISSUE_TEMPLATE/crash-or-stacktrace.yml new file mode 100644 index 000000000000..badab09bbf77 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/crash-or-stacktrace.yml @@ -0,0 +1,78 @@ +name: "💥 Crash or Stacktrace" +description: Report any server crashes or alarming stack traces. +type: "Bug" +labels: + - "status: needs triage" +body: + - type: markdown + attributes: + value: | + Before submitting this issue, please ensure the following: + + 1. You are running the latest version of Paper from [our downloads page](https://papermc.io/downloads/paper). + 2. Your version of Minecraft is supported by Paper. + + If your server crash log contains `DO NOT REPORT THIS TO PAPER`, please ask in our + [Discord](https://discord.gg/papermc) before opening this issue. These messages are informing you of server + lag and providing debug information. + + - type: textarea + attributes: + label: Stack trace + description: | + We need all of the stack trace! Do not cut off parts of it. Please do not use attachments. + If you prefer, you can use a paste site like https://mclo.gs. + value: | + ``` + paste your stack trace or a mclo.gs link here! + ``` + placeholder: Please don't remove the backticks; it makes your issue a lot harder to read! + validations: + required: true + + - type: textarea + attributes: + label: Plugin and Datapack List + description: | + All plugins and datapacks running on your server. + To list plugins, run `/plugins`. For datapacks, run `/datapack list`. + validations: + required: true + + - type: textarea + attributes: + label: Actions to reproduce (if known) + description: This may include a build schematic, a video, or detailed instructions to help reconstruct the issue. Anything helps! + validations: + required: false + + - type: textarea + attributes: + label: Paper version + description: | + Run `/version` on your server and **paste** the full, unmodified output here. + "latest" is *not* a version; we require the output of `/version` so we can adequately track down the issue. + Additionally, do NOT provide a screenshot, you MUST paste the entire output. +
+ Example + + ``` + > version + [20:34:42 INFO]: Checking version, please wait... + [20:34:42 INFO]: This server is running Paper version 1.21-105-master@7e91a2c (2024-07-20T21:04:31Z) (Implementing API version 1.21-R0.1-SNAPSHOT) + [20:34:42 INFO]: You are running the latest version + [20:34:42 INFO]: Previous version: 1.21-103-aa3b356 (MC: 1.21) + ``` + +
+ validations: + required: true + + - type: textarea + attributes: + label: Other + description: | + Please include other helpful information below, if any. + The more information we receive, the quicker and more effective we can be at finding the solution to the issue. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml deleted file mode 100644 index 1d647a1ba46f..000000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Feature Request -description: Suggest an idea for Paper -labels: [ "status: needs triage", "type: feature" ] -body: - - type: markdown - attributes: - value: | - Thank you for filling out a feature request for Paper! Please be as detailed as possible so that we may consider and review the request easier. - We ask that you search all the issues to avoid a duplicate feature request. If one exists, please reply if you have anything to add. - Before requesting a new feature, please make sure you are using the latest version and that the feature you are requesting is not already in Paper. - - - type: textarea - attributes: - label: Is your feature request related to a problem? - description: Please give some context for this request. Why do you want it added? - validations: - required: true - - - type: textarea - attributes: - label: Describe the solution you'd like. - description: A clear and concise description of what you want. - validations: - required: true - - - type: textarea - attributes: - label: Describe alternatives you've considered. - description: List any alternatives you might have tried to get the feature you want. - validations: - required: true - - - type: textarea - attributes: - label: Other - description: Add any other context or screenshots about the feature request below. - validations: - required: false - - - type: markdown - attributes: - value: | - Before submitting this feature request, please search our issue tracker to ensure your feature has not - already been requested. diff --git a/.github/ISSUE_TEMPLATE/new-feature.yml b/.github/ISSUE_TEMPLATE/new-feature.yml new file mode 100644 index 000000000000..731b4a2f534e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new-feature.yml @@ -0,0 +1,53 @@ +name: "💡 New Feature" +description: Propose a new idea for Paper. +type: "Feature" +labels: + - "status: needs triage" +body: + - type: markdown + attributes: + value: | + Thank you for submitting a feature request for Paper! Please be as detailed as possible to help us review and consider your request effectively. + Before submitting, please ensure the following: + + 1. You are using a supported version of Paper. + 2. The feature you’re requesting isn’t already included in the version you’re using. + 3. You’ve searched for and confirmed there isn’t already [an open request](https://github.com/PaperMC/Paper/issues?q=is%3Aissue%20is%3Aopen%20type%3AFeature) for this feature. + - If a similar request exists, feel free to add any additional details you think are helpful. + + If you have any questions, feel free to ask in the `#paper-help` or `#paper-dev` channels on our [Discord](https://discord.gg/papermc). + + - type: textarea + attributes: + label: Is your feature request related to a problem? + description: Please provide some context for this request. Why do you want it added? + validations: + required: true + + - type: textarea + attributes: + label: Describe the solution you'd like. + description: A clear and concise description of what you want. + validations: + required: true + + - type: textarea + attributes: + label: Describe alternatives you've considered. + description: List any alternatives you might have tried to get the feature you want. + validations: + required: true + + - type: textarea + attributes: + label: Other + description: Add any other context or screenshots about the feature request below. + validations: + required: false + + - type: markdown + attributes: + value: | + Before submitting this feature request, please search our issue tracker to ensure your feature has not + already been requested. + diff --git a/.github/ISSUE_TEMPLATE/performance-problem.yml b/.github/ISSUE_TEMPLATE/performance-problem.yml index 808bd09d21af..e13221132c9e 100644 --- a/.github/ISSUE_TEMPLATE/performance-problem.yml +++ b/.github/ISSUE_TEMPLATE/performance-problem.yml @@ -1,7 +1,19 @@ -name: Performance Problem -description: Report performance related problems or other areas of concern -labels: [ "status: needs triage", "type: performance" ] +name: "🐌 Performance Problem" +description: Report any performance issues. +type: "Bug" +labels: + - "scope: performance" + - "status: needs triage" body: + - type: markdown + attributes: + value: | + Before submitting this issue, please ensure the following: + + 1. You are running the latest version of Paper from [our downloads page](https://papermc.io/downloads/paper). + 2. You searched for and ensured there isn't already [an open issue](https://github.com/PaperMC/Paper/issues?q=is%3Aissue%20state%3Aopen%20type%3ABug) regarding this. + 3. Your version of Minecraft is supported by Paper. + - type: markdown attributes: value: | @@ -10,9 +22,12 @@ body: - type: input attributes: - label: Timings or Profile link - description: We ask that all timings/profiles are a link, not a screenshot. Screenshots inhibit our ability to figure out the real cause of the issue. - placeholder: "Example: https://timings.aikar.co/?id=6b48586fbbdd48e585ca0ebb07c59dd0" + label: Spark Profile + description: | + Please provide all profiles as links rather than screenshots. Screenshots limit our ability to investigate the root cause of the issue. + + For more information, see our [profiling documentation](https://docs.papermc.io/paper/profiling). + placeholder: "Example: https://spark.lucko.me/XsN0hxGfsi" validations: required: true @@ -35,10 +50,10 @@ body: - type: textarea attributes: label: Server config files - description: We need bukkit.yml, spigot.yml, paper-global.yml, paper-world-defaults.yml and server.properties. If you use per-world Paper configs, make sure to include them. You can paste it below or use a paste site like https://paste.gg. + description: We need bukkit.yml, spigot.yml, paper-global.yml, paper-world-defaults.yml and server.properties. If you use per-world Paper configs, make sure to include them. You can paste it below or use a paste site like https://mclo.gs. value: | ``` - Paste configs or paste.gg link here! + Paste configs or mclo.gs link here! ``` placeholder: Please don't remove the backticks; it makes your issue a lot harder to read! validations: @@ -56,10 +71,10 @@ body: ``` > version - [20:34:42 INFO]: This server is running Paper version git-Paper-540 (MC: 1.16.5) (Implementing API version 1.16.5-R0.1-SNAPSHOT) [20:34:42 INFO]: Checking version, please wait... - [20:34:42 INFO]: Previous version: git-Paper-538 (MC: 1.16.5) + [20:34:42 INFO]: This server is running Paper version 1.21-105-master@7e91a2c (2024-07-20T21:04:31Z) (Implementing API version 1.21-R0.1-SNAPSHOT) [20:34:42 INFO]: You are running the latest version + [20:34:42 INFO]: Previous version: 1.21-103-aa3b356 (MC: 1.21) ``` @@ -74,11 +89,3 @@ body: The more information we receive, the quicker and more effective we can be at finding the solution to the issue. validations: required: false - - type: markdown - attributes: - value: | - Before submitting this issue, please ensure the following: - - 1. You are running the latest version of Paper from [our downloads page](https://papermc.io/downloads). - 2. You searched for and ensured there isn't already an open issue regarding this. - 3. Your version of Minecraft is supported by Paper. diff --git a/.github/ISSUE_TEMPLATE/server-crash-or-stacktrace.yml b/.github/ISSUE_TEMPLATE/server-crash-or-stacktrace.yml deleted file mode 100644 index 4925cfddf0f6..000000000000 --- a/.github/ISSUE_TEMPLATE/server-crash-or-stacktrace.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Server crash or Stacktrace -description: Report server crashes or scary stacktraces -labels: [ "status: needs triage" ] -body: - - type: textarea - attributes: - label: Stack trace - description: | - We need all of the stack trace! Do not cut off parts of it. Please do not use attachments. - If you prefer, you can use a paste site like https://paste.gg. - value: | - ``` - paste your stack trace or a paste.gg link here! - ``` - placeholder: Please don't remove the backticks; it makes your issue a lot harder to read! - validations: - required: true - - - type: textarea - attributes: - label: Plugin and Datapack List - description: | - All plugins and datapacks running on your server. - To list plugins, run `/plugins`. For datapacks, run `/datapack list`. - validations: - required: true - - - type: textarea - attributes: - label: Actions to reproduce (if known) - description: This may include a build schematic, a video, or detailed instructions to help reconstruct the issue. Anything helps! - validations: - required: false - - - type: textarea - attributes: - label: Paper version - description: | - Run `/version` on your server and **paste** the full, unmodified output here. - "latest" is *not* a version; we require the output of `/version` so we can adequately track down the issue. - Additionally, do NOT provide a screenshot, you MUST paste the entire output. -
- Example - - ``` - > version - [20:34:42 INFO]: This server is running Paper version git-Paper-540 (MC: 1.16.5) (Implementing API version 1.16.5-R0.1-SNAPSHOT) - [20:34:42 INFO]: Checking version, please wait... - [20:34:42 INFO]: Previous version: git-Paper-538 (MC: 1.16.5) - [20:34:42 INFO]: You are running the latest version - ``` - -
- validations: - required: true - - - type: textarea - attributes: - label: Other - description: | - Please include other helpful information below, if any. - The more information we receive, the quicker and more effective we can be at finding the solution to the issue. - validations: - required: false - - - type: markdown - attributes: - value: | - Before submitting this issue, please ensure the following: - - 1. You are running the latest version of Paper from [our downloads page](https://papermc.io/downloads). - 2. Your version of Minecraft is supported by Paper. - - If your server crash log contains `DO NOT REPORT THIS TO PAPER`, please ask in our - [Discord](https://discord.gg/papermc) before opening this issue. These messages are informing you of server - lag and providing debug information. diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index b67a072020bb..000000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,18 +0,0 @@ -daysUntilStale: 60 -daysUntilClose: 7 -exemptLabels: - - "for: future" - - "type: bug" - - "status: accepted" - - "status: blocked" - - "status: in progress" - - "status: rebase required" -staleLabel: "resolution: stale" -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -closeComment: > - This issue has been automatically closed because it has not had activity in - a long time. If the issue still applies to the most recent supported - version, please open a new issue referencing this original issue. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e2662858dab6..994ade949c05 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,33 +1,116 @@ # Here lie dragons! # -# Note that there is no artifact step in this script. We do not want Paperclip -# jars to be built for every push & PR; our CI handles pushes to branches, while -# PRs can themselves link to Paperclip jars if it is necessary. Official such -# PRs will take use of testing builds. +# This action either builds the server or +# builds a paperclip jar to be updated in the body +# of the PR relating to this action. name: Build Paper -on: [push, pull_request] +on: + push: + pull_request: + types: + - opened + - reopened + - synchronize + - labeled jobs: - build: - # Only run on PRs if the source branch is on someone else's repo - if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} - runs-on: ubuntu-latest - strategy: - matrix: - java: [17] - fail-fast: true - steps: - - uses: actions/checkout@v2.4.0 - - name: JDK ${{ matrix.java }} - uses: actions/setup-java@v3.1.0 - with: - java-version: ${{ matrix.java }} - cache: 'gradle' - distribution: 'temurin' - - name: Patch and build - run: | - git config --global user.email "no-reply@github.com" - git config --global user.name "Github Actions" - ./gradlew applyPatches --stacktrace - ./gradlew build --stacktrace + build: + # Run on all label events (won't be duplicated) or all push events or on PR syncs not from the same repo + if: (github.event_name == 'pull_request' && github.event.action == 'labeled') || github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name + runs-on: ubuntu-latest + strategy: + matrix: + java: [21] + fail-fast: true + steps: + - if: ${{ github.event_name == 'push' }} + uses: actions/checkout@v4 + - if: ${{ github.event_name == 'pull_request' }} + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: JDK ${{ matrix.java }} + uses: actions/setup-java@v4 + with: + java-version: ${{ matrix.java }} + distribution: 'zulu' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Configure Build + uses: actions/github-script@v7 + id: determine + env: + REF_NAME: "${{ github.ref_name }}" + REF_TYPE: "${{ github.ref_type }}" + EVENT: "${{ toJSON(github.event) }}" + EVENT_TYPE: "${{ github.event_name }}" + with: + script: | + const {owner, repo} = context.repo; + const event_name = `${process.env.EVENT_TYPE}`; + const event = JSON.parse(`${process.env.EVENT}`); + const ref_type = `${process.env.REF_TYPE}`; + const ref_name = `${process.env.REF_NAME}`; + const result = { + action: "build" + }; + + if (event_name === "push" && ref_type === "branch") { + const {data: pulls} = await github.rest.pulls.list({ owner, repo, head: `${owner}:${ref_name}`, state: "open" }); + const pull = pulls.find((pr) => !!pr.labels.find((l) => l.name === "build-pr-jar")); + if (pull) { + result["pr"] = pull.number; + result["action"] = "paperclip"; + core.notice(`This is a push action but to a branch with an open PR with the build paperclip label (${JSON.stringify(result)})`); + return result; + } + } else if (event_name === "pull_request" && event.pull_request.labels.find((l) => l.name === "build-pr-jar")) { + result["pr"] = event.pull_request.number; + result["action"] = "paperclip"; + core.notice(`This is a pull request action with a build paperclip label (${JSON.stringify(result)})`); + return result; + } + core.notice("This will not build a paperclip jar"); + return result; + + - name: Apply Patches + run: | + git config --global user.email "no-reply@github.com" + git config --global user.name "GitHub Actions" + ./gradlew applyPatches --stacktrace + + - name: Build + run: ./gradlew build --stacktrace + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: Test Results (${{ matrix.java }}) + path: | + **/build/test-results/test/TEST-*.xml + + - name: Create Paperclip Jar + if: fromJSON(steps.determine.outputs.result).action == 'paperclip' + run: ./gradlew createMojmapPaperclipJar --stacktrace + + - name: Upload Paperclip Jar + if: fromJSON(steps.determine.outputs.result).action == 'paperclip' + uses: actions/upload-artifact@v4 + with: + name: paper-${{ fromJSON(steps.determine.outputs.result).pr }} + path: build/libs/paper-paperclip-*-mojmap.jar + event_file: + name: "Event File" + # Only run on PRs if the source branch is on someone else's repo + if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} + runs-on: ubuntu-latest + steps: + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: Event File + path: ${{ github.event_path }} diff --git a/.github/workflows/close_invalid_prs.yml b/.github/workflows/close_invalid_prs.yml new file mode 100644 index 000000000000..ef572c25c8f8 --- /dev/null +++ b/.github/workflows/close_invalid_prs.yml @@ -0,0 +1,27 @@ +name: Close invalid PRs + +on: + pull_request_target: + types: [ opened ] + +jobs: + run: + if: | + github.repository != github.event.pull_request.head.repo.full_name && + ( + github.head_ref == 'master' || + github.event.pull_request.head.repo.owner.type != 'User' + ) + runs-on: ubuntu-latest + steps: + - uses: superbrothers/close-pull-request@v3 + id: "master_branch" + if: github.head_ref == 'master' + with: + comment: "Please do not open pull requests from the `master` branch, create a new branch instead." + + - uses: superbrothers/close-pull-request@v3 + id: "org_account" + if: github.event.pull_request.head.repo.owner.type != 'User' && steps.master_branch.outcome == 'skipped' + with: + comment: "Please do not open pull requests from non-user accounts like organizations. Create a fork on a user account instead." diff --git a/.github/workflows/pr_comment.yml b/.github/workflows/pr_comment.yml new file mode 100644 index 000000000000..60bed3fd38e5 --- /dev/null +++ b/.github/workflows/pr_comment.yml @@ -0,0 +1,84 @@ +# This workflow run on the completion of the +# build workflow but only does anything if the +# triggering workflow uploaded an artifact. +# +# Do note that it is then the trigger workflow that +# determines if this will update the PR text body. All +# this workflow does is check if an uploaded artifact +# exists and there is a PR tied to the previous workflow. + +name: Comment on pull request +on: + workflow_run: + workflows: ['Build Paper'] + types: [completed] +jobs: + pr_comment: + if: github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + env: + BRANCH_NAME: "${{ github.event.workflow_run.head_branch }}" + PR_OWNER: "${{ github.event.workflow_run.head_repository.owner.login }}" + PR_SHA: "${{ github.event.workflow_run.head_sha }}" + RUN_ID: "${{ github.event.workflow_run.id }}" + REPO_ID: "${{ github.event.repository.id }}" + EVENT_TYPE: "${{ github.event.workflow_run.event}}" + PULL_REQUESTS: "${{ toJSON(github.event.workflow_run.pull_requests) }}" + with: + # This snippet is public-domain, taken from + # https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml + # Modified extensively by Machine_Maker + script: | + async function updatePR(owner, repo, issue_number, purpose, body) { + const { data } = await github.rest.issues.get({ owner, repo, issue_number }); + core.debug(JSON.stringify(data, null, 2)); + + const marker = ``; + + let new_body = data.body ? data.body.trim().split(marker)[0].trim() : ""; + new_body += `\n${marker}\n---\n${body}`; + + core.info(`Updating the text body of PR #${issue_number} in ${owner}/${repo}`); + await github.rest.issues.update({ owner, repo, issue_number, body: new_body }); + } + + const { owner, repo } = context.repo; + const run_id = `${process.env.RUN_ID}`; + const repo_id = `${process.env.REPO_ID}`; + + let pulls = []; + const event_type = `${process.env.EVENT_TYPE}`; + if (event_type === "push") { // if push, it's from the same repo which means `pull_requests` is populated + pulls = JSON.parse(`${process.env.PULL_REQUESTS}`); + } else { + const pr_branch = `${process.env.BRANCH_NAME}`; + const pr_sha = `${process.env.PR_SHA}`; + const pr_owner = `${process.env.PR_OWNER}`; + const { data } = await github.rest.pulls.list({ owner, repo, head: `${pr_owner}:${pr_branch}`, state: "open" }); + core.debug(JSON.stringify(data, null, 2)); + pulls = data.filter((pr) => pr.head.sha === pr_sha && pr.labels.find((l) => l.name === "build-pr-jar")); + } + + if (!pulls.length) { + return core.notice("This workflow doesn't have any pull requests!"); + } else if (pulls.length > 1) { + core.info(JSON.stringify(pulls, null, 2)); + return core.error("Found multiple matching PRs"); + } + const pull_request = pulls[0]; + + const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { owner, repo, run_id }); + if (!artifacts.length) { + return core.info("Skipping comment due to no artifact found"); + } + const artifact = artifacts.find((art) => art.name === `paper-${pull_request.number}`); + if (!artifact) { + return core.info("Skipping comment to no matching artifact found"); + } + + const link = `https://nightly.link/${owner}/${repo}/actions/artifacts/${artifact.id}.zip`; + const body = `Download the paperclip jar for this pull request: [${artifact.name}.zip](${link})`; + core.info(`Adding a link to ${link}`); + await updatePR(owner, repo, pull_request.number, "paperclip-pr-build", body); diff --git a/.github/workflows/projects.yml b/.github/workflows/projects.yml new file mode 100644 index 000000000000..5a42cedc1046 --- /dev/null +++ b/.github/workflows/projects.yml @@ -0,0 +1,76 @@ +name: Update Projects + +on: + issues: + types: + - labeled + - unlabeled + - closed + - reopened + +jobs: + bugs: + if: "github.event_name == 'issues' && contains(github.event.*.labels.*.name, 'type: bug')" + concurrency: + group: update-bugs-project-${{ github.event.issue.number }} + cancel-in-progress: true + runs-on: ubuntu-latest + steps: + - name: "authenticate" + id: "authenticate" + uses: "tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92" # v1 + with: + app_id: "${{ secrets.PROJECTS_APP_ID }}" + installation_id: "36153445" + private_key: "${{ secrets.PROJECTS_PRIVATE_KEY }}" + + - uses: PaperMC/update-projects-action@v0.2.0 + name: Update open issue + if: github.event.issue.state == 'open' + with: + github-token: "${{ steps.authenticate.outputs.token }}" + project-url: https://github.com/orgs/PaperMC/projects/5/views/2 + column-field: Status + label-to-column-map: | + { + "resolution: awaiting response": "⌛ Awaiting Response", + "resolution: cannot reproduce": "Invalid", + "resolution: duplicate": "Invalid", + "resolution: incomplete": "Invalid", + "resolution: invalid": "Invalid", + "resolution: superseded": "Invalid", + "resolution: unsupported": "Invalid", + "resolution: won't fix": "Invalid", + "resolution: works as intended": "Invalid", + "status: accepted": "✅ Accepted", + "status: blocked": "Needs Work", + "status: defer upstream": "Needs Work", + "status: in progress": "Needs Work", + "status: input wanted": "Needs Work", + "status: needs triage": "🕑 Needs Triage", + "status: rebase required": "Needs Work", + "status: unlikely": "✅ Accepted" + } + + - uses: PaperMC/update-projects-action@v0.2.0 + name: Update closed issue + if: github.event.issue.state == 'closed' + with: + github-token: "${{ steps.authenticate.outputs.token }}" + project-url: https://github.com/orgs/PaperMC/projects/5/views/2 + column-field: Status + clear-on-no-match: false + # include "status: needs triage" below to catch any closed issues without setting a resolution + label-to-column-map: | + { + "resolution: cannot reproduce": "Invalid", + "resolution: duplicate": "Invalid", + "resolution: incomplete": "Invalid", + "resolution: invalid": "Invalid", + "resolution: superseded": "Invalid", + "resolution: unsupported": "Invalid", + "resolution: won't fix": "Invalid", + "resolution: works as intended": "Invalid", + "status: accepted": "Done", + "status: needs triage": "Invalid" + } diff --git a/.github/workflows/test_results.yml b/.github/workflows/test_results.yml new file mode 100644 index 000000000000..f3c63cf8fb87 --- /dev/null +++ b/.github/workflows/test_results.yml @@ -0,0 +1,32 @@ +name: Test Results + +on: + workflow_run: + workflows: [ "Build Paper" ] + types: + - completed +permissions: { } + +jobs: + test-results: + name: Test Results + runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion != 'skipped' + permissions: + checks: write + # for downloading test result artifacts + actions: read + steps: + - name: Download and Extract Artifacts + uses: dawidd6/action-download-artifact@v6 + with: + run_id: ${{ github.event.workflow_run.id }} + path: artifacts + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + with: + commit: ${{ github.event.workflow_run.head_sha }} + event_file: artifacts/Event File/event.json + event_name: ${{ github.event.workflow_run.event }} + files: "artifacts/**/*.xml" + comment_mode: off diff --git a/.gitignore b/.gitignore index aef03d6c8dbc..a2adff58b60b 100644 --- a/.gitignore +++ b/.gitignore @@ -53,11 +53,15 @@ work/ForgeFlower .idea/ out/ +# JetBrains Fleet +.fleet/ + # Linux temp files *~ # other stuff run/ +logs/ Paper-Server Paper-API @@ -69,3 +73,4 @@ paperclip.properties !gradle/wrapper/gradle-wrapper.jar test-plugin.settings.gradle.kts +paper-api-generator.settings.gradle.kts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 472a86bb2170..32be536ebcea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,11 +4,11 @@ PaperMC is happy you're willing to contribute to our projects. We are usually very lenient with all submitted PRs, but there are still some guidelines you can follow to make the approval process go more smoothly. -## Use a Personal Fork and not Organization +## Use a Personal Fork and not an Organization Paper will routinely modify your PR, whether it's a quick rebase or to take care of any minor nitpicks we might have. Often, it's better for us to solve these -problems for you than make you go back and forth trying to fix it yourself. +problems for you than make you go back and forth trying to fix them yourself. Unfortunately, if you use an organization for your PR, it prevents Paper from modifying it. This requires us to manually merge your PR, resulting in us @@ -27,12 +27,12 @@ which can be obtained in (most) package managers such as `apt` (Debian / Ubuntu; you will most likely use this for WSL), `homebrew` (macOS / Linux), and more: - `git` (package `git` everywhere); -- A Java 17 or later JDK (packages vary, use Google/DuckDuckGo/etc.). +- A Java 21 or later JDK (packages vary, use Google/DuckDuckGo/etc.). - [Adoptium](https://adoptium.net/) has builds for most operating systems. - - Paper requires JDK 17 to build, however makes use of Gradle's + - Paper requires JDK 21 to build, however, makes use of Gradle's [Toolchains](https://docs.gradle.org/current/userguide/toolchains.html) - feature to allow building with only JRE 8 or later installed. (Gradle will - automatically provision JDK 17 for compilation if it cannot find an existing + feature to allow building with only JRE 11 or later installed. (Gradle will + automatically provision JDK 21 for compilation if it cannot find an existing install). If you're on Windows, check @@ -42,11 +42,11 @@ If you're compiling with Docker, you can use Adoptium's [`eclipse-temurin`](https://hub.docker.com/_/eclipse-temurin/) images like so: ```console -# docker run -it -v "$(pwd)":/data --rm eclipse-temurin:17.0.1_12-jdk bash +# docker run -it -v "$(pwd)":/data --rm eclipse-temurin:21.0.3_9-jdk bash Pulling image... root@abcdefg1234:/# javac -version -javac 17.0.1 +javac 21.0.3 ``` ## Understanding Patches @@ -56,7 +56,6 @@ split into different directories which target certain parts of the code. These directories are: - `Paper-API` - Modifications to `Spigot-API`/`Bukkit`; -- `Paper-MojangAPI` - An API for [Mojang's Brigadier](https://github.com/Mojang/brigadier); - `Paper-Server` - Modifications to `Spigot`/`CraftBukkit`. Because the entire structure is based on patches and git, a basic understanding @@ -67,7 +66,7 @@ Assuming you have already forked the repository: 1. Clone your fork to your local machine; 2. Type `./gradlew applyPatches` in a terminal to apply the changes from upstream. -On Windows, leave out the `./` at the beginning for all `gradlew` commands; +On Windows, replace the `./` with `.\` at the beginning for all `gradlew` commands; 3. cd into `Paper-Server` for server changes, and `Paper-API` for API changes. - - com.google.code.gson - gson -- 2.8.9 +- 2.11.0 +- compile +- +- +- +- org.joml +- joml +- 1.10.8 - compile - - - net.md-5 - bungeecord-chat -- 1.16-R0.4 +- 1.20-R0.2 - jar - compile - - - org.yaml - snakeyaml -- 1.30 +- 2.2 - compile - - - - org.apache.maven - maven-resolver-provider -- 3.8.5 +- 3.9.6 - provided - - - org.apache.maven.resolver - maven-resolver-connector-basic -- 1.7.3 +- 1.9.18 - provided - - - org.apache.maven.resolver - maven-resolver-transport-http -- 1.7.3 +- 1.9.18 - provided - - - - org.jetbrains - annotations-java5 -- 23.0.0 +- 24.1.0 - provided - - - -- junit -- junit -- 4.13.2 +- org.junit.jupiter +- junit-jupiter +- 5.10.2 - test - - - org.hamcrest -- hamcrest-library -- 1.3 +- hamcrest +- 2.2 +- test +- +- +- org.mockito +- mockito-core +- 5.14.1 - test - - - org.ow2.asm - asm-tree -- 9.3 +- 9.7.1 - test - - @@ -229,7 +254,7 @@ index 5a45ab463e6df9adfbe905c1f456fd41fbf4b8be..00000000000000000000000000000000 - - net.md-5 - scriptus -- 0.4.1 +- 0.5.0 - - - initialize @@ -242,23 +267,16 @@ index 5a45ab463e6df9adfbe905c1f456fd41fbf4b8be..00000000000000000000000000000000 - - org.apache.maven.plugins - maven-compiler-plugin -- 3.10.1 +- 3.13.0 - -- -- eclipse +- +- false - -- -- -- org.codehaus.plexus -- plexus-compiler-eclipse -- 2.12.0 -- -- - - - org.apache.maven.plugins - maven-jar-plugin -- 3.2.2 +- 3.4.1 - - - @@ -273,7 +291,7 @@ index 5a45ab463e6df9adfbe905c1f456fd41fbf4b8be..00000000000000000000000000000000 - - org.apache.maven.plugins - maven-shade-plugin -- 3.2.4 +- 3.5.3 - - - package @@ -293,21 +311,32 @@ index 5a45ab463e6df9adfbe905c1f456fd41fbf4b8be..00000000000000000000000000000000 - - - true +- +- false - - - - org.apache.maven.plugins - maven-javadoc-plugin -- 3.4.0 +- 3.6.3 - - -- https://guava.dev/releases/31.0.1-jre/api/docs/ -- https://javadoc.io/doc/org.yaml/snakeyaml/1.30/ -- https://javadoc.io/doc/org.jetbrains/annotations-java5/23.0.0/ -- https://javadoc.io/doc/net.md-5/bungeecord-chat/1.16-R0.4/ +- https://guava.dev/releases/32.1.2-jre/api/docs/ - +- +- +- apiNote +- a +- API Note: +- +- - - +- +- org.apache.maven.plugins +- maven-surefire-plugin +- 3.2.5 +- - - - @@ -322,7 +351,7 @@ index 5a45ab463e6df9adfbe905c1f456fd41fbf4b8be..00000000000000000000000000000000 - - org.apache.maven.plugins - maven-checkstyle-plugin -- 3.1.2 +- 3.3.1 - - - process-classes @@ -333,7 +362,6 @@ index 5a45ab463e6df9adfbe905c1f456fd41fbf4b8be..00000000000000000000000000000000 - - - checkstyle.xml -- checkstyle-suppressions.xml - true - - @@ -347,7 +375,7 @@ index 5a45ab463e6df9adfbe905c1f456fd41fbf4b8be..00000000000000000000000000000000 - - org.codehaus.mojo - animal-sniffer-maven-plugin -- 1.21 +- 1.23 - - - process-classes diff --git a/patches/api/0002-Build-system-changes.patch b/patches/api/0002-Build-system-changes.patch index 677a85f5ecf2..8ef831d434b8 100644 --- a/patches/api/0002-Build-system-changes.patch +++ b/patches/api/0002-Build-system-changes.patch @@ -5,50 +5,56 @@ Subject: [PATCH] Build system changes diff --git a/build.gradle.kts b/build.gradle.kts -index b81a893bd5418779544872eb4006adc6b3017a43..0b30b1f1be8818934ba530dd263fe6c9484983e8 100644 +index dfb490fe94c1f543cc75e9f5ca76f8254bff9159..3667f27baa87c82e071cc14ca20491d38feee255 100644 --- a/build.gradle.kts +++ b/build.gradle.kts -@@ -14,15 +14,27 @@ dependencies { - api("com.google.code.gson:gson:2.8.9") - api("net.md-5:bungeecord-chat:1.16-R0.4") - api("org.yaml:snakeyaml:1.30") +@@ -20,15 +20,27 @@ dependencies { + api("org.joml:joml:1.10.8") { + isTransitive = false // https://github.com/JOML-CI/JOML/issues/352 + } + // Paper start + api("com.googlecode.json-simple:json-simple:1.1.1") { + isTransitive = false // includes junit + } + // Paper end - compileOnly("org.apache.maven:maven-resolver-provider:3.8.5") - compileOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.3") - compileOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.3") -+ compileOnly("com.google.code.findbugs:jsr305:1.3.9") // Paper + compileOnly("org.apache.maven:maven-resolver-provider:3.9.6") + compileOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") + compileOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") -- val annotations = "org.jetbrains:annotations-java5:23.0.0" -+ val annotations = "org.jetbrains:annotations:23.0.0" // Paper - we don't want Java 5 annotations... +- val annotations = "org.jetbrains:annotations-java5:$annotationsVersion" ++ val annotations = "org.jetbrains:annotations:$annotationsVersion" // Paper - we don't want Java 5 annotations... compileOnly(annotations) testCompileOnly(annotations) + // Paper start - add checker -+ val checkerQual = "org.checkerframework:checker-qual:3.21.0" ++ val checkerQual = "org.checkerframework:checker-qual:3.33.0" + compileOnlyApi(checkerQual) + testCompileOnly(checkerQual) + // Paper end ++ api("org.jspecify:jspecify:1.0.0") // Paper - add jspecify + testImplementation("org.apache.commons:commons-lang3:3.12.0") - testImplementation("junit:junit:4.13.2") - testImplementation("org.hamcrest:hamcrest-library:1.3") -@@ -63,7 +75,7 @@ tasks.withType { + testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") + testImplementation("org.hamcrest:hamcrest:2.2") +@@ -71,8 +83,13 @@ tasks.withType { options.links( - "https://guava.dev/releases/31.0.1-jre/api/docs/", - "https://javadoc.io/doc/org.yaml/snakeyaml/1.30/", -- "https://javadoc.io/doc/org.jetbrains/annotations-java5/23.0.0/", -+ "https://javadoc.io/doc/org.jetbrains/annotations/23.0.0/", // Paper - we don't want Java 5 annotations - "https://javadoc.io/doc/net.md-5/bungeecord-chat/1.16-R0.4/", + "https://guava.dev/releases/33.3.1-jre/api/docs/", + "https://javadoc.io/doc/org.yaml/snakeyaml/2.2/", +- "https://javadoc.io/doc/org.jetbrains/annotations-java5/$annotationsVersion/", ++ "https://javadoc.io/doc/org.jetbrains/annotations/$annotationsVersion/", // Paper - we don't want Java 5 annotations + "https://javadoc.io/doc/net.md-5/bungeecord-chat/$bungeeCordChatVersion/", ++ // Paper start - add missing javadoc links ++ "https://javadoc.io/doc/org.joml/joml/1.10.8/index.html", ++ "https://www.javadoc.io/doc/com.google.code.gson/gson/2.11.0", ++ "https://jspecify.dev/docs/api/", ++ // Paper end ) + options.tags("apiNote:a:API Note:") -@@ -78,3 +90,14 @@ tasks.withType { - } - } +@@ -91,3 +108,14 @@ tasks.withType { + tasks.test { + useJUnitPlatform() } + +// Paper start diff --git a/patches/api/0003-Annotation-Test-changes.patch b/patches/api/0003-Annotation-Test-changes.patch deleted file mode 100644 index cc18011b3cd1..000000000000 --- a/patches/api/0003-Annotation-Test-changes.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sun, 17 Mar 2019 23:04:30 +0000 -Subject: [PATCH] Annotation Test changes - -- Allow use of TYPE_USE annotations -- Ignore package-private methods for nullability annotations -- Add excludes for classes which don't pass - -diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java -index 0c7377247ad9251c9e498039511e7220370aba2d..c6a8a37a933cfc5a5885602a8a70fdda8fb6aa10 100644 ---- a/src/test/java/org/bukkit/AnnotationTest.java -+++ b/src/test/java/org/bukkit/AnnotationTest.java -@@ -40,7 +40,17 @@ public class AnnotationTest { - "org/bukkit/util/io/Wrapper", - "org/bukkit/plugin/java/PluginClassLoader", - // Generic functional interface -- "org/bukkit/util/Consumer" -+ "org/bukkit/util/Consumer", -+ // Paper start -+ // Timings history is broken in terms of nullability due to guavas Function defining that the param is NonNull -+ "co/aikar/timings/TimingHistory$2", -+ "co/aikar/timings/TimingHistory$2$1", -+ "co/aikar/timings/TimingHistory$2$1$1", -+ "co/aikar/timings/TimingHistory$2$1$2", -+ "co/aikar/timings/TimingHistory$3", -+ "co/aikar/timings/TimingHistory$4", -+ "co/aikar/timings/TimingHistoryEntry$1" -+ // Paper end - }; - - @Test -@@ -67,14 +77,40 @@ public class AnnotationTest { - } - - if (mustBeAnnotated(Type.getReturnType(method.desc)) && !isWellAnnotated(method.invisibleAnnotations)) { -+ // Paper start - Allow use of TYPE_USE annotations -+ boolean warn = true; -+ if (isWellAnnotated(method.visibleTypeAnnotations)) { -+ warn = false; -+ } else if (method.invisibleTypeAnnotations != null) { -+ dance: for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { -+ final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); -+ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_RETURN && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { -+ warn = false; -+ break dance; // cha cha real smooth -+ } -+ } -+ } -+ if (warn) -+ // Paper end - warn(errors, clazz, method, "return value"); - } - - Type[] paramTypes = Type.getArgumentTypes(method.desc); - List parameters = method.parameters; - -+ dancing: // Paper - for (int i = 0; i < paramTypes.length; i++) { - if (mustBeAnnotated(paramTypes[i]) && !isWellAnnotated(method.invisibleParameterAnnotations == null ? null : method.invisibleParameterAnnotations[i])) { -+ // Paper start -+ if (method.invisibleTypeAnnotations != null) { -+ for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { -+ final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); -+ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { -+ continue dancing; -+ } -+ } -+ } -+ // Paper end - Allow use of TYPE_USE annotations - ParameterNode paramNode = parameters == null ? null : parameters.get(i); - String paramName = paramNode == null ? null : paramNode.name; - -@@ -91,13 +127,18 @@ public class AnnotationTest { - - Collections.sort(errors); - -- System.out.println(errors.size() + " missing annotation(s):"); -+ StringBuilder builder = new StringBuilder() -+ .append("There ") -+ .append(errors.size() != 1 ? "are " : "is ") -+ .append(errors.size()) -+ .append(" missing annotation") -+ .append(errors.size() != 1 ? "s:\n" : ":\n"); -+ - for (String message : errors) { -- System.out.print("\t"); -- System.out.println(message); -+ builder.append("\t").append(message).append("\n"); - } - -- Assert.fail("There " + errors.size() + " are missing annotation(s)"); -+ Assert.fail(builder.toString()); - } - - private static void collectClasses(@NotNull File from, @NotNull Map to) throws IOException { -@@ -152,7 +193,7 @@ public class AnnotationTest { - - private static boolean isMethodIncluded(@NotNull ClassNode clazz, @NotNull MethodNode method, @NotNull Map allClasses) { - // Exclude private, synthetic and deprecated methods -- if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0) { -+ if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0 || (method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) == 0) { // Paper - ignore package-private - return false; - } - -@@ -174,7 +215,7 @@ public class AnnotationTest { - return true; - } - -- private static boolean isWellAnnotated(@Nullable List annotations) { -+ private static boolean isWellAnnotated(@Nullable List annotations) { // Paper - if (annotations == null) { - return false; - } diff --git a/patches/api/0003-Test-changes.patch b/patches/api/0003-Test-changes.patch new file mode 100644 index 000000000000..7649a1904f68 --- /dev/null +++ b/patches/api/0003-Test-changes.patch @@ -0,0 +1,349 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sun, 17 Mar 2019 23:04:30 +0000 +Subject: [PATCH] Test changes + +- Allow use of TYPE_USE annotations +- Ignore package-private methods for nullability annotations +- Add excludes for classes which don't pass +- Disable stupid BukkitMirrorTest +- configure mockito agent to address changes in newer java versions see https://openjdk.org/jeps/451 + +Co-authored-by: Riley Park +Co-authored-by: Jake Potrebic +Co-authored-by: Yannick Lamprecht + +diff --git a/build.gradle.kts b/build.gradle.kts +index 3667f27baa87c82e071cc14ca20491d38feee255..73aaa8a341565626556327cda6a73f98c318863a 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -11,6 +11,18 @@ java { + val annotationsVersion = "24.1.0" + val bungeeCordChatVersion = "1.20-R0.2" + ++// Paper start - configure mockito agent that is needed in newer java versions ++val mockitoAgent = configurations.register("mockitoAgent") ++abstract class MockitoAgentProvider : CommandLineArgumentProvider { ++ @get:CompileClasspath ++ abstract val fileCollection: ConfigurableFileCollection ++ ++ override fun asArguments(): Iterable { ++ return listOf("-javaagent:" + fileCollection.files.single().absolutePath) ++ } ++} ++// Paper end - configure mockito agent that is needed in newer java versions ++ + dependencies { + // api dependencies are listed transitively to API consumers + api("com.google.guava:guava:33.3.1-jre") +@@ -46,6 +58,7 @@ dependencies { + testImplementation("org.hamcrest:hamcrest:2.2") + testImplementation("org.mockito:mockito-core:5.14.1") + testImplementation("org.ow2.asm:asm-tree:9.7.1") ++ mockitoAgent("org.mockito:mockito-core:5.14.1") { isTransitive = false } // Paper - configure mockito agent that is needed in newer java versions + } + + configure { +@@ -107,8 +120,19 @@ tasks.withType { + + tasks.test { + useJUnitPlatform() ++ // Paper start - configure mockito agent that is needed in newer java versions ++ val provider = objects.newInstance() ++ provider.fileCollection.from(mockitoAgent) ++ jvmArgumentProviders.add(provider) ++ // Paper end - configure mockito agent that is needed in newer java versions + } + ++// Paper start - compile tests with -parameters for better junit parameterized test names ++tasks.compileTestJava { ++ options.compilerArgs.add("-parameters") ++} ++// Paper end ++ + // Paper start + val scanJar = tasks.register("scanJarForBadCalls", io.papermc.paperweight.tasks.ScanJarForBadCalls::class) { + badAnnotations.add("Lio/papermc/paper/annotation/DoNotUse;") +diff --git a/src/test/java/io/papermc/paper/testing/EmptyTag.java b/src/test/java/io/papermc/paper/testing/EmptyTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..77154095cfb8b259bdb318e8ff40cb6f559ebc18 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/testing/EmptyTag.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.testing; ++ ++import java.util.Collections; ++import java.util.Set; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Tag; ++import org.jetbrains.annotations.NotNull; ++ ++public record EmptyTag(NamespacedKey key) implements Tag { ++ ++ @SuppressWarnings("deprecation") ++ public EmptyTag() { ++ this(NamespacedKey.randomKey()); ++ } ++ ++ @Override ++ public @NotNull NamespacedKey getKey() { ++ return this.key; ++ } ++ ++ @Override ++ public boolean isTagged(@NotNull final Keyed item) { ++ return false; ++ } ++ ++ @Override ++ public @NotNull Set getValues() { ++ return Collections.emptySet(); ++ } ++} +diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java +index 64e7aef6220097edefdff3b98a771b988365930d..07f904a78f51b220a5891aca1afffac4f46d58b4 100644 +--- a/src/test/java/org/bukkit/AnnotationTest.java ++++ b/src/test/java/org/bukkit/AnnotationTest.java +@@ -29,7 +29,13 @@ public class AnnotationTest { + "Lorg/jetbrains/annotations/Nullable;", + "Lorg/jetbrains/annotations/NotNull;", + "Lorg/jetbrains/annotations/Contract;", +- "Lorg/bukkit/UndefinedNullability;" ++ "Lorg/bukkit/UndefinedNullability;", ++ // Paper start ++ "Lorg/checkerframework/checker/nullness/qual/MonotonicNonNull;", ++ "Lorg/checkerframework/checker/nullness/qual/NonNull;", ++ "Lorg/checkerframework/checker/nullness/qual/Nullable;", ++ "Lorg/checkerframework/checker/nullness/qual/PolyNull;", ++ // Paper end + }; + + private static final String[] EXCLUDED_CLASSES = { +@@ -40,7 +46,17 @@ public class AnnotationTest { + "org/bukkit/util/io/Wrapper", + "org/bukkit/plugin/java/PluginClassLoader", + // Generic functional interface +- "org/bukkit/util/Consumer" ++ "org/bukkit/util/Consumer", ++ // Paper start ++ // Timings history is broken in terms of nullability due to guavas Function defining that the param is NonNull ++ "co/aikar/timings/TimingHistory$2", ++ "co/aikar/timings/TimingHistory$2$1", ++ "co/aikar/timings/TimingHistory$2$1$1", ++ "co/aikar/timings/TimingHistory$2$1$2", ++ "co/aikar/timings/TimingHistory$3", ++ "co/aikar/timings/TimingHistory$4", ++ "co/aikar/timings/TimingHistoryEntry$1" ++ // Paper end + }; + + @Test +@@ -61,20 +77,60 @@ public class AnnotationTest { + continue; + } + ++ // Paper start - skip class if it's @NullMarked ++ if (isClassNullMarked(clazz, foundClasses)) { ++ continue; ++ } ++ // Paper end - skip class if it's @NullMarked ++ + for (MethodNode method : clazz.methods) { + if (!isMethodIncluded(clazz, method, foundClasses)) { + continue; + } + + if (mustBeAnnotated(Type.getReturnType(method.desc)) && !isWellAnnotated(method.invisibleAnnotations)) { ++ // Paper start - Allow use of TYPE_USE annotations ++ boolean warn = true; ++ if (isWellAnnotated(method.visibleTypeAnnotations)) { ++ warn = false; ++ } else if (method.invisibleTypeAnnotations != null) { ++ dance: for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { ++ final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); ++ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_RETURN && java.util.Arrays.asList(ACCEPTED_ANNOTATIONS).contains(invisibleTypeAnnotation.desc)) { ++ warn = false; ++ break dance; // cha cha real smooth ++ } ++ } ++ } ++ if (warn) ++ // Paper end + warn(errors, clazz, method, "return value"); + } + + Type[] paramTypes = Type.getArgumentTypes(method.desc); + List parameters = method.parameters; + ++ dancing: // Paper + for (int i = 0; i < paramTypes.length; i++) { + if (mustBeAnnotated(paramTypes[i]) ^ isWellAnnotated(method.invisibleParameterAnnotations == null ? null : method.invisibleParameterAnnotations[i])) { ++ // Paper start ++ if (method.invisibleTypeAnnotations != null) { ++ for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { ++ final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); ++ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.asList(ACCEPTED_ANNOTATIONS).contains(invisibleTypeAnnotation.desc)) { ++ continue dancing; ++ } ++ } ++ } ++ if (method.visibleTypeAnnotations != null) { ++ for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.visibleTypeAnnotations) { ++ final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); ++ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.asList(ACCEPTED_ANNOTATIONS).contains(invisibleTypeAnnotation.desc)) { ++ continue dancing; ++ } ++ } ++ } ++ // Paper end - Allow use of TYPE_USE annotations + ParameterNode paramNode = parameters == null ? null : parameters.get(i); + String paramName = paramNode == null ? null : paramNode.name; + +@@ -91,17 +147,37 @@ public class AnnotationTest { + + Collections.sort(errors); + +- System.out.println(errors.size() + " missing annotation(s):"); ++ StringBuilder builder = new StringBuilder() ++ .append("There ") ++ .append(errors.size() != 1 ? "are " : "is ") ++ .append(errors.size()) ++ .append(" missing annotation") ++ .append(errors.size() != 1 ? "s:\n" : ":\n"); ++ + for (String message : errors) { +- System.out.print("\t"); +- System.out.println(message); ++ builder.append("\t").append(message).append("\n"); + } + +- fail("There " + errors.size() + " are missing annotation(s)"); ++ fail(builder.toString()); + } + + private static void collectClasses(@NotNull File from, @NotNull Map to) throws IOException { + if (from.isDirectory()) { ++ // Paper start - skip packages with @NullMarked ++ final File packageInfo = new File(from, "package-info.class"); ++ if (packageInfo.exists()) { ++ try (final FileInputStream in = new FileInputStream(packageInfo)) { ++ final ClassReader cr = new ClassReader(in); ++ ++ final ClassNode node = new ClassNode(); ++ cr.accept(node, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); ++ ++ if (isClassNullMarked0(node)) { ++ return; // skip packages with @NullMarked ++ } ++ } ++ } ++ // Paper end - skip packages with @NullMarked + final File[] files = from.listFiles(); + assert files != null; + +@@ -125,6 +201,23 @@ public class AnnotationTest { + } + } + ++ // Paper start - skip class if it's @NullMarked ++ private static boolean isClassNullMarked(@NotNull ClassNode clazz, @NotNull Map allClasses) { ++ if (clazz.nestHostClass != null) { ++ final ClassNode nestHostNode = allClasses.get(clazz.nestHostClass); ++ if (nestHostNode != null) { ++ return isClassNullMarked0(nestHostNode); ++ } ++ } ++ ++ return isClassNullMarked0(clazz); ++ } ++ ++ private static boolean isClassNullMarked0(@NotNull ClassNode clazz) { ++ return clazz.visibleAnnotations != null && clazz.visibleAnnotations.stream().anyMatch(node -> "Lorg/jspecify/annotations/NullMarked;".equals(node.desc)); ++ } ++ // Paper end - skip class if it's @NullMarked ++ + private static boolean isClassIncluded(@NotNull ClassNode clazz, @NotNull Map allClasses) { + // Exclude private, synthetic or deprecated classes and annotations, since their members can't be null + if ((clazz.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED | Opcodes.ACC_ANNOTATION)) != 0) { +@@ -140,6 +233,11 @@ public class AnnotationTest { + // Exceptions are excluded + return false; + } ++ // Paper start ++ if (isInternal(clazz.invisibleAnnotations)) { ++ return false; ++ } ++ // Paper end + + for (String excludedClass : EXCLUDED_CLASSES) { + if (excludedClass.equals(clazz.name)) { +@@ -152,7 +250,7 @@ public class AnnotationTest { + + private static boolean isMethodIncluded(@NotNull ClassNode clazz, @NotNull MethodNode method, @NotNull Map allClasses) { + // Exclude private, synthetic and deprecated methods +- if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0) { ++ if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0 || (method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) == 0) { // Paper - ignore package-private + return false; + } + +@@ -170,11 +268,30 @@ public class AnnotationTest { + if ("".equals(method.name) && isAnonymous(clazz)) { + return false; + } ++ // Paper start ++ if (isInternal(method.invisibleAnnotations)) { ++ return false; ++ } ++ // Paper end + + return true; + } ++ // Paper start ++ private static boolean isInternal(List annotations) { ++ if (annotations == null) { ++ return false; ++ } ++ for (AnnotationNode node : annotations) { ++ if (node.desc.equals("Lorg/jetbrains/annotations/ApiStatus$Internal;")) { ++ return true; ++ } ++ } ++ ++ return false; ++ } ++ // Paper end + +- private static boolean isWellAnnotated(@Nullable List annotations) { ++ private static boolean isWellAnnotated(@Nullable List annotations) { // Paper + if (annotations == null) { + return false; + } +diff --git a/src/test/java/org/bukkit/BukkitMirrorTest.java b/src/test/java/org/bukkit/BukkitMirrorTest.java +index 89ca06ebecdaadd5dfc7bc74473ca15ad36f6eff..5974ceea58940e1799f3589eac0e39b925a42c3b 100644 +--- a/src/test/java/org/bukkit/BukkitMirrorTest.java ++++ b/src/test/java/org/bukkit/BukkitMirrorTest.java +@@ -9,6 +9,7 @@ import org.junit.jupiter.params.ParameterizedTest; + import org.junit.jupiter.params.provider.Arguments; + import org.junit.jupiter.params.provider.MethodSource; + ++@org.junit.jupiter.api.Disabled // Paper + public class BukkitMirrorTest { + + public static Stream data() { +diff --git a/src/test/java/org/bukkit/support/TestServer.java b/src/test/java/org/bukkit/support/TestServer.java +index c67e0784c043ed194f6acde32411e156412a9b24..eb1fd4b911c4af76cdd3eac85d5365e7941a4a2e 100644 +--- a/src/test/java/org/bukkit/support/TestServer.java ++++ b/src/test/java/org/bukkit/support/TestServer.java +@@ -83,6 +83,11 @@ public final class TestServer { + UnsafeValues unsafeValues = mock(withSettings().stubOnly()); + when(instance.getUnsafe()).thenReturn(unsafeValues); + ++ // Paper start - testing changes ++ when(instance.getTag(anyString(), any(NamespacedKey.class), any())).thenAnswer(ignored -> new io.papermc.paper.testing.EmptyTag()); ++ when(instance.getScoreboardCriteria(anyString())).thenReturn(null); ++ // Paper end - testing changes ++ + Bukkit.setServer(instance); + } + diff --git a/patches/api/0004-Add-FastUtil-to-Bukkit.patch b/patches/api/0004-Add-FastUtil-to-Bukkit.patch deleted file mode 100644 index 8c267a95b707..000000000000 --- a/patches/api/0004-Add-FastUtil-to-Bukkit.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 1 Apr 2016 00:02:47 -0400 -Subject: [PATCH] Add FastUtil to Bukkit - -Doesn't expose to plugins, just allows Paper-API to use it for optimization - -diff --git a/build.gradle.kts b/build.gradle.kts -index 044b7c49b569e1170108c912e9307f7fec278762..f0423df165bf7d0f3fad21d26b64f31ba3e6aeee 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -18,6 +18,7 @@ dependencies { - api("com.googlecode.json-simple:json-simple:1.1.1") { - isTransitive = false // includes junit - } -+ api("it.unimi.dsi:fastutil:8.5.6") - // Paper end - - compileOnly("org.apache.maven:maven-resolver-provider:3.8.5") diff --git a/patches/api/0004-Code-Generation.patch b/patches/api/0004-Code-Generation.patch new file mode 100644 index 000000000000..2cb22cc016d9 --- /dev/null +++ b/patches/api/0004-Code-Generation.patch @@ -0,0 +1,414 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 26 May 2023 18:14:44 -0700 +Subject: [PATCH] Code Generation + +Currently includes generated key holder classes for types +used in the Registry Modification API + +diff --git a/build.gradle.kts b/build.gradle.kts +index 73aaa8a341565626556327cda6a73f98c318863a..a214483db535890a4b89e35a8c50cfd709df36d4 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -1,6 +1,7 @@ + plugins { + `java-library` + `maven-publish` ++ idea // Paper + } + + java { +@@ -61,6 +62,22 @@ dependencies { + mockitoAgent("org.mockito:mockito-core:5.14.1") { isTransitive = false } // Paper - configure mockito agent that is needed in newer java versions + } + ++// Paper start ++val generatedApiPath: java.nio.file.Path = rootProject.projectDir.toPath().resolve("paper-api-generator/generated") ++idea { ++ module { ++ generatedSourceDirs.add(generatedApiPath.toFile()) ++ } ++} ++sourceSets { ++ main { ++ java { ++ srcDir(generatedApiPath) ++ } ++ } ++} ++// Paper end ++ + configure { + publications.create("maven") { + from(components["java"]) +@@ -143,3 +160,14 @@ tasks.check { + dependsOn(scanJar) + } + // Paper end ++// Paper start ++val scanJarForOldGeneratedCode = tasks.register("scanJarForOldGeneratedCode", io.papermc.paperweight.tasks.ScanJarForOldGeneratedCode::class) { ++ mcVersion.set(providers.gradleProperty("mcVersion")) ++ annotation.set("Lio/papermc/paper/generated/GeneratedFrom;") ++ jarToScan.set(tasks.jar.flatMap { it.archiveFile }) ++ classpath.from(configurations.compileClasspath) ++} ++tasks.check { ++ dependsOn(scanJarForOldGeneratedCode) ++} ++// Paper end +diff --git a/src/main/java/io/papermc/paper/generated/GeneratedFrom.java b/src/main/java/io/papermc/paper/generated/GeneratedFrom.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2512dba27edfdccbc4430815b6cba048e3d93484 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/generated/GeneratedFrom.java +@@ -0,0 +1,21 @@ ++package io.papermc.paper.generated; ++ ++import java.lang.annotation.Documented; ++import java.lang.annotation.ElementType; ++import java.lang.annotation.Retention; ++import java.lang.annotation.RetentionPolicy; ++import java.lang.annotation.Target; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Used to mark classes which are generated from ++ * a specific version of minecraft. ++ */ ++@ApiStatus.Internal ++@Documented ++@Retention(RetentionPolicy.RUNTIME) ++@Target(ElementType.TYPE) ++public @interface GeneratedFrom { ++ ++ String value(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java +new file mode 100644 +index 0000000000000000000000000000000000000000..647f6a1ec1f9d3c203b41f90a99bfd415bf67366 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java +@@ -0,0 +1,196 @@ ++package io.papermc.paper.registry; ++ ++import net.kyori.adventure.key.Keyed; ++import org.bukkit.Art; ++import org.bukkit.Fluid; ++import org.bukkit.GameEvent; ++import org.bukkit.JukeboxSong; ++import org.bukkit.MusicInstrument; ++import org.bukkit.Particle; ++import org.bukkit.Sound; ++import org.bukkit.attribute.Attribute; ++import org.bukkit.block.Biome; ++import org.bukkit.block.BlockType; ++import org.bukkit.block.banner.PatternType; ++import org.bukkit.damage.DamageType; ++import org.bukkit.enchantments.Enchantment; ++import org.bukkit.entity.Cat; ++import org.bukkit.entity.EntityType; ++import org.bukkit.entity.Frog; ++import org.bukkit.entity.Villager; ++import org.bukkit.entity.Wolf; ++import org.bukkit.entity.memory.MemoryKey; ++import org.bukkit.generator.structure.Structure; ++import org.bukkit.generator.structure.StructureType; ++import org.bukkit.inventory.ItemType; ++import org.bukkit.inventory.MenuType; ++import org.bukkit.inventory.meta.trim.TrimMaterial; ++import org.bukkit.inventory.meta.trim.TrimPattern; ++import org.bukkit.map.MapCursor; ++import org.bukkit.potion.PotionEffectType; ++import org.bukkit.potion.PotionType; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++import static io.papermc.paper.registry.RegistryKeyImpl.create; ++ ++/** ++ * Identifier for a specific registry. For use with ++ * {@link TypedKey} and the registry modification API. ++ *

++ * There are 2 types of registries, identified as "built-in" ++ * or "data-driven". The former are not changeable by datapacks (which ++ * doesn't necessarily mean they aren't changeable in the API) and ++ * are loaded first. "Data-driven" registries are all created by ++ * reading in data from the vanilla and other datapacks. ++ * ++ * @param the value type ++ */ ++@SuppressWarnings("unused") ++@NullMarked ++public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { ++ ++ /* ******************* * ++ * Built-in Registries * ++ * ******************* */ ++ /** ++ * Built-in registry for game events ++ * @see io.papermc.paper.registry.keys.GameEventKeys ++ */ ++ RegistryKey GAME_EVENT = create("game_event"); ++ /** ++ * Built-in registry for structure types. ++ * @see io.papermc.paper.registry.keys.StructureTypeKeys ++ */ ++ RegistryKey STRUCTURE_TYPE = create("worldgen/structure_type"); ++ /** ++ * Built-in registry for potion effect types (mob effects). ++ * @see io.papermc.paper.registry.keys.MobEffectKeys ++ */ ++ RegistryKey MOB_EFFECT = create("mob_effect"); ++ /** ++ * @apiNote DO NOT USE ++ */ ++ @ApiStatus.Internal ++ RegistryKey BLOCK = create("block"); ++ /** ++ * @apiNote DO NOT USE ++ */ ++ @ApiStatus.Internal ++ RegistryKey ITEM = create("item"); ++ /** ++ * Built-in registry for cat variants. ++ * @see io.papermc.paper.registry.keys.CatVariantKeys ++ */ ++ RegistryKey CAT_VARIANT = create("cat_variant"); ++ /** ++ * Built-in registry for frog variants. ++ * @see io.papermc.paper.registry.keys.FrogVariantKeys ++ */ ++ RegistryKey FROG_VARIANT = create("frog_variant"); ++ /** ++ * Built-in registry for villager professions. ++ * @see io.papermc.paper.registry.keys.VillagerProfessionKeys ++ */ ++ RegistryKey VILLAGER_PROFESSION = create("villager_profession"); ++ /** ++ * Built-in registry for villager types. ++ * @see io.papermc.paper.registry.keys.VillagerTypeKeys ++ */ ++ RegistryKey VILLAGER_TYPE = create("villager_type"); ++ /** ++ * Built-in registry for map decoration types. ++ * @see io.papermc.paper.registry.keys.MapDecorationTypeKeys ++ */ ++ RegistryKey MAP_DECORATION_TYPE = create("map_decoration_type"); ++ /** ++ * Built-in registry for menu types. ++ * @see io.papermc.paper.registry.keys.MenuTypeKeys ++ */ ++ RegistryKey MENU = create("menu"); ++ /** ++ * Built-in registry for attributes. ++ * @see io.papermc.paper.registry.keys.AttributeKeys ++ */ ++ RegistryKey ATTRIBUTE = create("attribute"); ++ /** ++ * Built-in registry for fluids. ++ * @see io.papermc.paper.registry.keys.FluidKeys ++ */ ++ RegistryKey FLUID = create("fluid"); ++ /** ++ * Built-in registry for sound events. ++ * @see io.papermc.paper.registry.keys.SoundEventKeys ++ */ ++ RegistryKey SOUND_EVENT = create("sound_event"); ++ ++ ++ ++ /* ********************** * ++ * Data-driven Registries * ++ * ********************** */ ++ /** ++ * Data-driven registry for biomes. ++ * @see io.papermc.paper.registry.keys.BiomeKeys ++ */ ++ RegistryKey BIOME = create("worldgen/biome"); ++ /** ++ * Data-driven registry for structures. ++ * @see io.papermc.paper.registry.keys.StructureKeys ++ */ ++ RegistryKey STRUCTURE = create("worldgen/structure"); ++ /** ++ * Data-driven registry for trim materials. ++ * @see io.papermc.paper.registry.keys.TrimMaterialKeys ++ */ ++ RegistryKey TRIM_MATERIAL = create("trim_material"); ++ /** ++ * Data-driven registry for trim patterns. ++ * @see io.papermc.paper.registry.keys.TrimPatternKeys ++ */ ++ RegistryKey TRIM_PATTERN = create("trim_pattern"); ++ /** ++ * Data-driven registry for damage types. ++ * @see io.papermc.paper.registry.keys.DamageTypeKeys ++ */ ++ RegistryKey DAMAGE_TYPE = create("damage_type"); ++ /** ++ * Data-driven registry for wolf variants. ++ * @see io.papermc.paper.registry.keys.WolfVariantKeys ++ */ ++ RegistryKey WOLF_VARIANT = create("wolf_variant"); ++ /** ++ * Data-driven registry for enchantments. ++ * @see io.papermc.paper.registry.keys.EnchantmentKeys ++ */ ++ RegistryKey ENCHANTMENT = create("enchantment"); ++ /** ++ * Data-driven registry for jukebox songs. ++ * @see io.papermc.paper.registry.keys.JukeboxSongKeys ++ */ ++ RegistryKey JUKEBOX_SONG = create("jukebox_song"); ++ /** ++ * Data-driven registry for banner patterns. ++ * @see io.papermc.paper.registry.keys.BannerPatternKeys ++ */ ++ RegistryKey BANNER_PATTERN = create("banner_pattern"); ++ /** ++ * Data-driven registry for painting variants. ++ * @see io.papermc.paper.registry.keys.PaintingVariantKeys ++ */ ++ RegistryKey PAINTING_VARIANT = create("painting_variant"); ++ /** ++ * Data-driven registry for instruments. ++ * @see io.papermc.paper.registry.keys.InstrumentKeys ++ */ ++ RegistryKey INSTRUMENT = create("instrument"); ++ ++ ++ /* ******************* * ++ * API-only Registries * ++ * ******************* */ ++ RegistryKey ENTITY_TYPE = create("entity_type"); ++ RegistryKey PARTICLE_TYPE = create("particle_type"); ++ RegistryKey POTION = create("potion"); ++ RegistryKey> MEMORY_MODULE_TYPE = create("memory_module_type"); ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..80e3e64f47ac55a4978c9e5b430e2f2d1c871d1b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.registry; ++ ++import com.google.common.collect.Sets; ++import java.util.Set; ++import net.kyori.adventure.key.Key; ++import org.intellij.lang.annotations.Subst; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@NullMarked ++record RegistryKeyImpl(Key key) implements RegistryKey { ++ ++ static final Set> REGISTRY_KEYS = Sets.newIdentityHashSet(); ++ ++ static RegistryKey create(@Subst("some_key") final String key) { ++ final RegistryKey registryKey = createInternal(key); ++ REGISTRY_KEYS.add(registryKey); ++ return registryKey; ++ } ++ ++ // creates the key without adding to the internal set of keys ++ static RegistryKey createInternal(@Subst("some_key") final String key) { ++ return new RegistryKeyImpl<>(Key.key(Key.MINECRAFT_NAMESPACE, key)); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/registry/TypedKey.java b/src/main/java/io/papermc/paper/registry/TypedKey.java +new file mode 100644 +index 0000000000000000000000000000000000000000..81bee5224196008662ddda528b5dcb8dd7cb9f21 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/TypedKey.java +@@ -0,0 +1,45 @@ ++package io.papermc.paper.registry; ++ ++import net.kyori.adventure.key.Key; ++import net.kyori.adventure.key.Keyed; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents a key for a value in a specific registry. ++ * ++ * @param the value type for the registry ++ */ ++@ApiStatus.Experimental ++@NullMarked ++public sealed interface TypedKey extends Key permits TypedKeyImpl { ++ ++ /** ++ * Gets the key for the value in the registry. ++ * ++ * @return the value's key ++ */ ++ @Override ++ Key key(); ++ ++ /** ++ * Gets the registry key for the value this key ++ * represents. ++ * ++ * @return the registry key ++ */ ++ RegistryKey registryKey(); ++ ++ /** ++ * Create a typed key from a key and a registry key. ++ * ++ * @param registryKey the registry this key is for ++ * @param key the key for the value in the registry ++ * @param value type ++ * @return a new key for the value key and registry key ++ */ ++ @ApiStatus.Experimental ++ static TypedKey create(final RegistryKey registryKey, final Key key) { ++ return new TypedKeyImpl<>(key, registryKey); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3e29f7007500582cdc3f84b91f11ebeb58f68bbf +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.registry; ++ ++import net.kyori.adventure.key.Key; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++record TypedKeyImpl(Key key, RegistryKey registryKey) implements TypedKey { ++ // Wrap key methods to make this easier to use ++ @Override ++ public String namespace() { ++ return this.key.namespace(); ++ } ++ ++ @Override ++ public String value() { ++ return this.key.value(); ++ } ++ ++ @Override ++ public String asString() { ++ return this.key.asString(); ++ } ++} +diff --git a/src/main/java/org/bukkit/MinecraftExperimental.java b/src/main/java/org/bukkit/MinecraftExperimental.java +index a86b87e4c3332202e40e484c3f9c6562b419c70f..e996a758fc1e4ecfec68641733d69665f30792e8 100644 +--- a/src/main/java/org/bukkit/MinecraftExperimental.java ++++ b/src/main/java/org/bukkit/MinecraftExperimental.java +@@ -47,5 +47,10 @@ public @interface MinecraftExperimental { + @ApiStatus.Internal + public enum Requires { + ++ // Paper start ++ TRADE_REBALANCE, ++ REDSTONE_EXPERIMENTS, ++ MINECART_IMPROVEMENTS ++ // Paper end + } + } diff --git a/patches/api/0005-Add-FastUtil-to-Bukkit.patch b/patches/api/0005-Add-FastUtil-to-Bukkit.patch new file mode 100644 index 000000000000..b5a3ecfd352e --- /dev/null +++ b/patches/api/0005-Add-FastUtil-to-Bukkit.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 1 Apr 2016 00:02:47 -0400 +Subject: [PATCH] Add FastUtil to Bukkit + +Doesn't expose to plugins, just allows Paper-API to use it for optimization + +diff --git a/build.gradle.kts b/build.gradle.kts +index a214483db535890a4b89e35a8c50cfd709df36d4..e1acfa9abed37e5332edf6b6cf66e3b9b926b366 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -37,6 +37,7 @@ dependencies { + api("com.googlecode.json-simple:json-simple:1.1.1") { + isTransitive = false // includes junit + } ++ api("it.unimi.dsi:fastutil:8.5.15") + // Paper end + + compileOnly("org.apache.maven:maven-resolver-provider:3.9.6") diff --git a/patches/api/0005-Adventure.patch b/patches/api/0005-Adventure.patch deleted file mode 100644 index b28fbac9f019..000000000000 --- a/patches/api/0005-Adventure.patch +++ /dev/null @@ -1,4349 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Riley Park -Date: Fri, 29 Jan 2021 17:21:55 +0100 -Subject: [PATCH] Adventure - -Co-authored-by: zml -Co-authored-by: Jake Potrebic - -diff --git a/build.gradle.kts b/build.gradle.kts -index cedf145d5024e1ed9ae0d815e7ad0afb87c9a8b0..237a0beff61f2384b9e9e18a9d7119fd1916e1bd 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -8,17 +8,37 @@ java { - withJavadocJar() - } - -+val adventureVersion = "4.11.0" -+val apiAndDocs: Configuration by configurations.creating { -+ attributes { -+ attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION)) -+ attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) -+ attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES)) -+ attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) -+ } -+} -+configurations.api { -+ extendsFrom(apiAndDocs) -+} -+ - dependencies { - // api dependencies are listed transitively to API consumers - api("com.google.guava:guava:31.0.1-jre") - api("com.google.code.gson:gson:2.8.9") -- api("net.md-5:bungeecord-chat:1.16-R0.4") -+ api("net.md-5:bungeecord-chat:1.16-R0.4-deprecated+build.6") // Paper - api("org.yaml:snakeyaml:1.30") - // Paper start - api("com.googlecode.json-simple:json-simple:1.1.1") { - isTransitive = false // includes junit - } - api("it.unimi.dsi:fastutil:8.5.6") -+ apiAndDocs(platform("net.kyori:adventure-bom:$adventureVersion")) -+ apiAndDocs("net.kyori:adventure-api") -+ apiAndDocs("net.kyori:adventure-text-minimessage") -+ apiAndDocs("net.kyori:adventure-text-serializer-gson") -+ apiAndDocs("net.kyori:adventure-text-serializer-legacy") -+ apiAndDocs("net.kyori:adventure-text-serializer-plain") -+ apiAndDocs("net.kyori:adventure-text-logger-slf4j") - // Paper end - - compileOnly("org.apache.maven:maven-resolver-provider:3.8.5") -@@ -77,9 +97,24 @@ tasks.withType { - "https://guava.dev/releases/31.0.1-jre/api/docs/", - "https://javadoc.io/doc/org.yaml/snakeyaml/1.30/", - "https://javadoc.io/doc/org.jetbrains/annotations/23.0.0/", // Paper - we don't want Java 5 annotations -- "https://javadoc.io/doc/net.md-5/bungeecord-chat/1.16-R0.4/", -+ // Paper start -+ //"https://javadoc.io/doc/net.md-5/bungeecord-chat/1.16-R0.4/", // don't link to bungee chat -+ "https://jd.adventure.kyori.net/api/$adventureVersion/", -+ "https://jd.adventure.kyori.net/text-minimessage/$adventureVersion/", -+ "https://jd.adventure.kyori.net/text-serializer-gson/$adventureVersion/", -+ "https://jd.adventure.kyori.net/text-serializer-legacy/$adventureVersion/", -+ "https://jd.adventure.kyori.net/text-serializer-plain/$adventureVersion/", -+ // Paper end - ) - -+ inputs.files(apiAndDocs).ignoreEmptyDirectories().withPropertyName(apiAndDocs.name + "-configuration") -+ doFirst { -+ options.addStringOption( -+ "sourcepath", -+ apiAndDocs.resolvedConfiguration.files.joinToString(separator = File.pathSeparator, transform = File::getPath) -+ ) -+ } -+ - // workaround for https://github.com/gradle/gradle/issues/4046 - inputs.dir("src/main/javadoc").withPropertyName("javadoc-sourceset") - doLast { -diff --git a/src/main/java/io/papermc/paper/chat/ChatRenderer.java b/src/main/java/io/papermc/paper/chat/ChatRenderer.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2fc47afbb233e6e5727a7b672f61b88ad3bab097 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/chat/ChatRenderer.java -@@ -0,0 +1,78 @@ -+package io.papermc.paper.chat; -+ -+import net.kyori.adventure.audience.Audience; -+import net.kyori.adventure.text.Component; -+import org.bukkit.entity.Player; -+import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -+import org.jetbrains.annotations.ApiStatus; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * A chat renderer is responsible for rendering chat messages sent by {@link Player}s to the server. -+ */ -+@FunctionalInterface -+public interface ChatRenderer { -+ /** -+ * Renders a chat message. This will be called once for each receiving {@link Audience}. -+ * -+ * @param source the message source -+ * @param sourceDisplayName the display name of the source player -+ * @param message the chat message -+ * @param viewer the receiving {@link Audience} -+ * @return a rendered chat message -+ */ -+ @ApiStatus.OverrideOnly -+ @NotNull -+ Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message, @NotNull Audience viewer); -+ -+ /** -+ * Create a new instance of the default {@link ChatRenderer}. -+ * -+ * @return a new {@link ChatRenderer} -+ */ -+ @NotNull -+ static ChatRenderer defaultRenderer() { -+ return viewerUnaware((source, sourceDisplayName, message) -> Component.translatable("chat.type.text", sourceDisplayName, message)); -+ } -+ -+ /** -+ * Creates a new viewer-unaware {@link ChatRenderer}, which will render the chat message a single time, -+ * displaying the same rendered message to every viewing {@link Audience}. -+ * -+ * @param renderer the viewer unaware renderer -+ * @return a new {@link ChatRenderer} -+ */ -+ @NotNull -+ static ChatRenderer viewerUnaware(final @NotNull ViewerUnaware renderer) { -+ return new ChatRenderer() { -+ private @MonotonicNonNull Component message; -+ -+ @Override -+ public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message, final @NotNull Audience viewer) { -+ if (this.message == null) { -+ this.message = renderer.render(source, sourceDisplayName, message); -+ } -+ return this.message; -+ } -+ }; -+ } -+ -+ /** -+ * Similar to {@link ChatRenderer}, but without knowledge of the message viewer. -+ * -+ * @see ChatRenderer#viewerUnaware(ViewerUnaware) -+ */ -+ interface ViewerUnaware { -+ /** -+ * Renders a chat message. -+ * -+ * @param source the message source -+ * @param sourceDisplayName the display name of the source player -+ * @param message the chat message -+ * @return a rendered chat message -+ */ -+ @ApiStatus.OverrideOnly -+ @NotNull -+ Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fa03a5cb2d3e3e0a60d84bacc911d96c454f81da ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java -@@ -0,0 +1,112 @@ -+package io.papermc.paper.event.player; -+ -+import java.util.Set; -+import io.papermc.paper.chat.ChatRenderer; -+import net.kyori.adventure.audience.Audience; -+import net.kyori.adventure.text.Component; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+import static java.util.Objects.requireNonNull; -+ -+/** -+ * An abstract implementation of a chat event, handling shared logic. -+ */ -+public abstract class AbstractChatEvent extends PlayerEvent implements Cancellable { -+ private final Set viewers; -+ private final Component originalMessage; -+ private ChatRenderer renderer; -+ private Component message; -+ private boolean cancelled = false; -+ -+ AbstractChatEvent(final boolean async, final @NotNull Player player, final @NotNull Set viewers, final @NotNull ChatRenderer renderer, final @NotNull Component message, final @NotNull Component originalMessage) { -+ super(player, async); -+ this.viewers = viewers; -+ this.renderer = renderer; -+ this.message = message; -+ this.originalMessage = originalMessage; -+ } -+ -+ /** -+ * Gets a set of {@link Audience audiences} that this chat message will be displayed to. -+ * -+ *

The set returned is not guaranteed to be mutable and may auto-populate -+ * on access. Any listener accessing the returned set should be aware that -+ * it may reduce performance for a lazy set implementation.

-+ * -+ *

Listeners should be aware that modifying the list may throw {@link -+ * UnsupportedOperationException} if the event caller provides an -+ * unmodifiable set.

-+ * -+ * @return a set of {@link Audience audiences} who will receive the chat message -+ */ -+ @NotNull -+ public final Set viewers() { -+ return this.viewers; -+ } -+ -+ /** -+ * Sets the chat renderer. -+ * -+ * @param renderer the chat renderer -+ * @throws NullPointerException if {@code renderer} is {@code null} -+ */ -+ public final void renderer(final @NotNull ChatRenderer renderer) { -+ this.renderer = requireNonNull(renderer, "renderer"); -+ } -+ -+ /** -+ * Gets the chat renderer. -+ * -+ * @return the chat renderer -+ */ -+ @NotNull -+ public final ChatRenderer renderer() { -+ return this.renderer; -+ } -+ -+ /** -+ * Gets the user-supplied message. -+ * The return value will reflect changes made using {@link #message(Component)}. -+ * -+ * @return the user-supplied message -+ */ -+ @NotNull -+ public final Component message() { -+ return this.message; -+ } -+ -+ /** -+ * Sets the user-supplied message. -+ * -+ * @param message the user-supplied message -+ * @throws NullPointerException if {@code message} is {@code null} -+ */ -+ public final void message(final @NotNull Component message) { -+ this.message = requireNonNull(message, "message"); -+ } -+ -+ /** -+ * Gets the original and unmodified user-supplied message. -+ * The return value will not reflect changes made using -+ * {@link #message(Component)}. -+ * -+ * @return the original user-supplied message -+ */ -+ @NotNull -+ public final Component originalMessage() { -+ return this.originalMessage; -+ } -+ -+ @Override -+ public final boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ @Override -+ public final void setCancelled(final boolean cancelled) { -+ this.cancelled = cancelled; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0d9e3c23027e3af90cb70e4bb6fb0ac1da35fc4d ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java -@@ -0,0 +1,31 @@ -+package io.papermc.paper.event.player; -+ -+import java.util.Set; -+import io.papermc.paper.chat.ChatRenderer; -+import net.kyori.adventure.audience.Audience; -+import net.kyori.adventure.text.Component; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * An event fired when a {@link Player} sends a chat message to the server. -+ */ -+public final class AsyncChatEvent extends AbstractChatEvent { -+ private static final HandlerList HANDLERS = new HandlerList(); -+ -+ public AsyncChatEvent(final boolean async, final @NotNull Player player, final @NotNull Set viewers, final @NotNull ChatRenderer renderer, final @NotNull Component message, final @NotNull Component originalMessage) { -+ super(async, player, viewers, renderer, message, originalMessage); -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLERS; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLERS; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/event/player/ChatEvent.java b/src/main/java/io/papermc/paper/event/player/ChatEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..eb179aae1e1d2ce842442e49fe275827a430ccd0 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/ChatEvent.java -@@ -0,0 +1,36 @@ -+package io.papermc.paper.event.player; -+ -+import java.util.Set; -+import io.papermc.paper.chat.ChatRenderer; -+import net.kyori.adventure.audience.Audience; -+import net.kyori.adventure.text.Component; -+import org.bukkit.Warning; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * An event fired when a {@link Player} sends a chat message to the server. -+ * -+ * @deprecated Listening to this event forces chat to wait for the main thread, delaying chat messages. It is recommended to use {@link AsyncChatEvent} instead, wherever possible. -+ */ -+@Deprecated -+@Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.") -+public final class ChatEvent extends AbstractChatEvent { -+ private static final HandlerList HANDLERS = new HandlerList(); -+ -+ public ChatEvent(final @NotNull Player player, final @NotNull Set viewers, final @NotNull ChatRenderer renderer, final @NotNull Component message, final @NotNull Component originalMessage) { -+ super(false, player, viewers, renderer, message, originalMessage); -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLERS; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLERS; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/text/PaperComponents.java b/src/main/java/io/papermc/paper/text/PaperComponents.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bff9a6295db367c6b89d69fb55459a40828265ea ---- /dev/null -+++ b/src/main/java/io/papermc/paper/text/PaperComponents.java -@@ -0,0 +1,112 @@ -+package io.papermc.paper.text; -+ -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.flattener.ComponentFlattener; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -+import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; -+import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -+import org.bukkit.Bukkit; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Paper API-specific methods for working with {@link Component}s and related. -+ */ -+public final class PaperComponents { -+ private PaperComponents() { -+ throw new RuntimeException("PaperComponents is not to be instantiated!"); -+ } -+ -+ /** -+ * Return a component flattener that can use game data to resolve extra information about components. -+ * -+ * @return a component flattener -+ */ -+ public static @NotNull ComponentFlattener flattener() { -+ return Bukkit.getUnsafe().componentFlattener(); -+ } -+ -+ /** -+ * Get a serializer for {@link Component}s that will convert components to -+ * a plain-text string. -+ * -+ *

Implementations may provide a serializer capable of processing any -+ * information that requires access to implementation details.

-+ * -+ * @return a serializer to plain text -+ * @deprecated will be removed in adventure 5.0.0, use {@link PlainTextComponentSerializer#plainText()} -+ */ -+ @Deprecated(forRemoval = true) -+ public static @NotNull PlainComponentSerializer plainSerializer() { -+ return Bukkit.getUnsafe().plainComponentSerializer(); -+ } -+ -+ /** -+ * Get a serializer for {@link Component}s that will convert components to -+ * a plain-text string. -+ * -+ *

Implementations may provide a serializer capable of processing any -+ * information that requires access to implementation details.

-+ * -+ * @return a serializer to plain text -+ * @deprecated use {@link PlainTextComponentSerializer#plainText()} -+ */ -+ @Deprecated(forRemoval = true) -+ public static @NotNull PlainTextComponentSerializer plainTextSerializer() { -+ return Bukkit.getUnsafe().plainTextSerializer(); -+ } -+ -+ /** -+ * Get a serializer for {@link Component}s that will convert to and from the -+ * standard JSON serialization format using Gson. -+ * -+ *

Implementations may provide a serializer capable of processing any -+ * information that requires implementation details, such as legacy -+ * (pre-1.16) hover events.

-+ * -+ * @return a json component serializer -+ * @deprecated use {@link GsonComponentSerializer#gson()} -+ */ -+ @Deprecated(forRemoval = true) -+ public static @NotNull GsonComponentSerializer gsonSerializer() { -+ return Bukkit.getUnsafe().gsonComponentSerializer(); -+ } -+ -+ /** -+ * Get a serializer for {@link Component}s that will convert to and from the -+ * standard JSON serialization format using Gson, downsampling any RGB colors -+ * to their nearest {@link NamedTextColor} counterpart. -+ * -+ *

Implementations may provide a serializer capable of processing any -+ * information that requires implementation details, such as legacy -+ * (pre-1.16) hover events.

-+ * -+ * @return a json component serializer -+ * @deprecated use {@link GsonComponentSerializer#colorDownsamplingGson()} -+ */ -+ @Deprecated(forRemoval = true) -+ public static @NotNull GsonComponentSerializer colorDownsamplingGsonSerializer() { -+ return Bukkit.getUnsafe().colorDownsamplingGsonComponentSerializer(); -+ } -+ -+ /** -+ * Get a serializer for {@link Component}s that will convert to and from the -+ * legacy component format used by Bukkit. This serializer uses the -+ * {@link LegacyComponentSerializer.Builder#useUnusualXRepeatedCharacterHexFormat()} -+ * option to match upstream behavior. -+ * -+ *

This legacy serializer uses the standard section symbol to mark -+ * formatting characters.

-+ * -+ *

Implementations may provide a serializer capable of processing any -+ * information that requires access to implementation details.

-+ * -+ * @return a section serializer -+ * @deprecated use {@link LegacyComponentSerializer#legacySection()} -+ */ -+ @Deprecated(forRemoval = true) -+ public static @NotNull LegacyComponentSerializer legacySectionSerializer() { -+ return Bukkit.getUnsafe().legacyComponentSerializer(); -+ } -+} -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 5029d98816c137fcc7068bd5596d6a38d96ee877..ba57a093a2df3c65036377e3093eedabeda7c6f5 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -357,7 +357,9 @@ public final class Bukkit { - * - * @param message the message - * @return the number of players -+ * @deprecated in favour of {@link Server#broadcast(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public static int broadcastMessage(@NotNull String message) { - return server.broadcastMessage(message); - } -@@ -1071,6 +1073,19 @@ public final class Bukkit { - server.shutdown(); - } - -+ // Paper start -+ /** -+ * Broadcast a message to all players. -+ *

-+ * This is the same as calling {@link #broadcast(net.kyori.adventure.text.Component, -+ * java.lang.String)} with the {@link Server#BROADCAST_CHANNEL_USERS} permission. -+ * -+ * @param message the message -+ * @return the number of players -+ */ -+ public static int broadcast(@NotNull net.kyori.adventure.text.Component message) { -+ return server.broadcast(message); -+ } - /** - * Broadcasts the specified message to every user with the given - * permission name. -@@ -1080,6 +1095,21 @@ public final class Bukkit { - * permissibles} must have to receive the broadcast - * @return number of message recipients - */ -+ public static int broadcast(@NotNull net.kyori.adventure.text.Component message, @NotNull String permission) { -+ return server.broadcast(message, permission); -+ } -+ // Paper end -+ /** -+ * Broadcasts the specified message to every user with the given -+ * permission name. -+ * -+ * @param message message to broadcast -+ * @param permission the required permission {@link Permissible -+ * permissibles} must have to receive the broadcast -+ * @return number of message recipients -+ * @deprecated in favour of {@link #broadcast(net.kyori.adventure.text.Component, String)} -+ */ -+ @Deprecated // Paper - public static int broadcast(@NotNull String message, @NotNull String permission) { - return server.broadcast(message, permission); - } -@@ -1318,6 +1348,7 @@ public final class Bukkit { - return server.createInventory(owner, type); - } - -+ // Paper start - /** - * Creates an empty inventory with the specified type and title. If the type - * is {@link InventoryType#CHEST}, the new inventory has a size of 27; -@@ -1343,6 +1374,38 @@ public final class Bukkit { - * @see InventoryType#isCreatable() - */ - @NotNull -+ public static Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull net.kyori.adventure.text.Component title) { -+ return server.createInventory(owner, type, title); -+ } -+ // Paper end -+ -+ /** -+ * Creates an empty inventory with the specified type and title. If the type -+ * is {@link InventoryType#CHEST}, the new inventory has a size of 27; -+ * otherwise the new inventory has the normal size for its type.
-+ * It should be noted that some inventory types do not support titles and -+ * may not render with said titles on the Minecraft client. -+ *
-+ * {@link InventoryType#WORKBENCH} will not process crafting recipes if -+ * created with this method. Use -+ * {@link Player#openWorkbench(Location, boolean)} instead. -+ *
-+ * {@link InventoryType#ENCHANTING} will not process {@link ItemStack}s -+ * for possible enchanting results. Use -+ * {@link Player#openEnchanting(Location, boolean)} instead. -+ * -+ * @param owner The holder of the inventory; can be null if there's no holder. -+ * @param type The type of inventory to create. -+ * @param title The title of the inventory, to be displayed when it is viewed. -+ * @return The new inventory. -+ * @throws IllegalArgumentException if the {@link InventoryType} cannot be -+ * viewed. -+ * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} -+ * -+ * @see InventoryType#isCreatable() -+ */ -+ @Deprecated // Paper -+ @NotNull - public static Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull String title) { - return server.createInventory(owner, type, title); - } -@@ -1361,6 +1424,7 @@ public final class Bukkit { - return server.createInventory(owner, size); - } - -+ // Paper start - /** - * Creates an empty inventory of type {@link InventoryType#CHEST} with the - * specified size and title. -@@ -1373,10 +1437,30 @@ public final class Bukkit { - * @throws IllegalArgumentException if the size is not a multiple of 9 - */ - @NotNull -+ public static Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull net.kyori.adventure.text.Component title) throws IllegalArgumentException { -+ return server.createInventory(owner, size, title); -+ } -+ // Paper end -+ -+ /** -+ * Creates an empty inventory of type {@link InventoryType#CHEST} with the -+ * specified size and title. -+ * -+ * @param owner the holder of the inventory, or null to indicate no holder -+ * @param size a multiple of 9 as the size of inventory to create -+ * @param title the title of the inventory, displayed when inventory is -+ * viewed -+ * @return a new inventory -+ * @throws IllegalArgumentException if the size is not a multiple of 9 -+ * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} -+ */ -+ @Deprecated // Paper -+ @NotNull - public static Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException { - return server.createInventory(owner, size, title); - } - -+ // Paper start - /** - * Creates an empty merchant. - * -@@ -1384,7 +1468,20 @@ public final class Bukkit { - * when the merchant inventory is viewed - * @return a new merchant - */ -+ public static @NotNull Merchant createMerchant(@Nullable net.kyori.adventure.text.Component title) { -+ return server.createMerchant(title); -+ } -+ // Paper start -+ /** -+ * Creates an empty merchant. -+ * -+ * @param title the title of the corresponding merchant inventory, displayed -+ * when the merchant inventory is viewed -+ * @return a new merchant -+ * @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)} -+ */ - @NotNull -+ @Deprecated // Paper - public static Merchant createMerchant(@Nullable String title) { - return server.createMerchant(title); - } -@@ -1501,22 +1598,47 @@ public final class Bukkit { - return server.isPrimaryThread(); - } - -+ // Paper start -+ /** -+ * Gets the message that is displayed on the server list. -+ * -+ * @return the server's MOTD -+ */ -+ @NotNull public static net.kyori.adventure.text.Component motd() { -+ return server.motd(); -+ } -+ // Paper end -+ - /** - * Gets the message that is displayed on the server list. - * - * @return the servers MOTD -+ * @deprecated in favour of {@link #motd()} - */ - @NotNull -+ @Deprecated // Paper - public static String getMotd() { - return server.getMotd(); - } - -+ // Paper start -+ /** -+ * Gets the default message that is displayed when the server is stopped. -+ * -+ * @return the shutdown message -+ */ -+ public static @Nullable net.kyori.adventure.text.Component shutdownMessage() { -+ return server.shutdownMessage(); -+ } -+ // Paper end - /** - * Gets the default message that is displayed when the server is stopped. - * - * @return the shutdown message -+ * @deprecated in favour of {@link #shutdownMessage()} - */ - @Nullable -+ @Deprecated // Paper - public static String getShutdownMessage() { - return server.getShutdownMessage(); - } -diff --git a/src/main/java/org/bukkit/Keyed.java b/src/main/java/org/bukkit/Keyed.java -index 32c92621c2c15eec14c50965f5ecda00c46e6c80..e076d447da62445764a9776ee2554c077637d270 100644 ---- a/src/main/java/org/bukkit/Keyed.java -+++ b/src/main/java/org/bukkit/Keyed.java -@@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; - /** - * Represents an object which has a {@link NamespacedKey} attached to it. - */ --public interface Keyed { -+public interface Keyed extends net.kyori.adventure.key.Keyed { // Paper -- extend Adventure Keyed - - /** - * Return the namespaced identifier for this object. -@@ -14,4 +14,16 @@ public interface Keyed { - */ - @NotNull - NamespacedKey getKey(); -+ -+ // Paper start -+ /** -+ * Returns the unique identifier for this object. -+ * -+ * @return this object's key -+ */ -+ @Override -+ default net.kyori.adventure.key.@NotNull Key key() { -+ return this.getKey(); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/Nameable.java b/src/main/java/org/bukkit/Nameable.java -index fee814e01a653d2b53c56e8b566383ca44aa5346..b71b780792b672b37c8fe65d43489b860a227381 100644 ---- a/src/main/java/org/bukkit/Nameable.java -+++ b/src/main/java/org/bukkit/Nameable.java -@@ -4,6 +4,30 @@ import org.jetbrains.annotations.Nullable; - - public interface Nameable { - -+ // Paper start -+ /** -+ * Gets the custom name. -+ * -+ *

This value has no effect on players, they will always use their real name.

-+ * -+ * @return the custom name -+ */ -+ @Nullable net.kyori.adventure.text.Component customName(); -+ -+ /** -+ * Sets the custom name. -+ * -+ *

This name will be used in death messages and can be sent to the client as a nameplate over the mob.

-+ * -+ *

Setting the name to {@code null} will clear it.

-+ * -+ *

This value has no effect on players, they will always use their real name.

-+ * -+ * @param customName the custom name to set -+ */ -+ void customName(final @Nullable net.kyori.adventure.text.Component customName); -+ // Paper end -+ - /** - * Gets the custom name on a mob or block. If there is no name this method - * will return null. -@@ -11,8 +35,10 @@ public interface Nameable { - * This value has no effect on players, they will always use their real - * name. - * -+ * @deprecated in favour of {@link #customName()} - * @return name of the mob/block or null - */ -+ @Deprecated // Paper - @Nullable - public String getCustomName(); - -@@ -25,7 +51,9 @@ public interface Nameable { - * This value has no effect on players, they will always use their real - * name. - * -+ * @deprecated in favour of {@link #customName(net.kyori.adventure.text.Component)} - * @param name the name to set - */ -+ @Deprecated // Paper - public void setCustomName(@Nullable String name); - } -diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java -index 803fa0019869127ee8c7e4fb1777a59c43e66f8a..c65f0d6569c130b4920a9e71ad24af6427f1f030 100644 ---- a/src/main/java/org/bukkit/NamespacedKey.java -+++ b/src/main/java/org/bukkit/NamespacedKey.java -@@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable; - * underscores, hyphens, and forward slashes. - * - */ --public final class NamespacedKey { -+public final class NamespacedKey implements net.kyori.adventure.key.Key { // Paper - implement Key - - /** - * The namespace representing all inbuilt keys. -@@ -212,4 +212,24 @@ public final class NamespacedKey { - public static NamespacedKey fromString(@NotNull String key) { - return fromString(key, null); - } -+ -+ // Paper start -+ @NotNull -+ @Override -+ public String namespace() { -+ return this.getNamespace(); -+ } -+ -+ @NotNull -+ @Override -+ public String value() { -+ return this.getKey(); -+ } -+ -+ @NotNull -+ @Override -+ public String asString() { -+ return this.namespace + ':' + this.key; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 6d6810cc51732830ef139f7099fbc5a45b124e8e..5af7da1d3d62cada69240e2d22db2a32278b0074 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -58,13 +58,13 @@ import org.jetbrains.annotations.Nullable; - /** - * Represents a server implementation. - */ --public interface Server extends PluginMessageRecipient { -+public interface Server extends PluginMessageRecipient, net.kyori.adventure.audience.ForwardingAudience { // Paper - - /** - * Used for all administrative messages, such as an operator using a - * command. - *

-- * For use in {@link #broadcast(java.lang.String, java.lang.String)}. -+ * For use in {@link #broadcast(net.kyori.adventure.text.Component, java.lang.String)}. - */ - public static final String BROADCAST_CHANNEL_ADMINISTRATIVE = "bukkit.broadcast.admin"; - -@@ -72,7 +72,7 @@ public interface Server extends PluginMessageRecipient { - * Used for all announcement messages, such as informing users that a - * player has joined. - *

-- * For use in {@link #broadcast(java.lang.String, java.lang.String)}. -+ * For use in {@link #broadcast(net.kyori.adventure.text.Component, java.lang.String)}. - */ - public static final String BROADCAST_CHANNEL_USERS = "bukkit.broadcast.user"; - -@@ -294,7 +294,9 @@ public interface Server extends PluginMessageRecipient { - * - * @param message the message - * @return the number of players -+ * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public int broadcastMessage(@NotNull String message); - - /** -@@ -910,8 +912,33 @@ public interface Server extends PluginMessageRecipient { - * @param permission the required permission {@link Permissible - * permissibles} must have to receive the broadcast - * @return number of message recipients -+ * @deprecated in favour of {@link #broadcast(net.kyori.adventure.text.Component, String)} - */ -+ @Deprecated // Paper - public int broadcast(@NotNull String message, @NotNull String permission); -+ // Paper start -+ /** -+ * Broadcast a message to all players. -+ *

-+ * This is the same as calling {@link #broadcast(net.kyori.adventure.text.Component, -+ * java.lang.String)} with the {@link #BROADCAST_CHANNEL_USERS} permission. -+ * -+ * @param message the message -+ * @return the number of players -+ */ -+ int broadcast(@NotNull net.kyori.adventure.text.Component message); -+ -+ /** -+ * Broadcasts the specified message to every user with the given -+ * permission name. -+ * -+ * @param message message to broadcast -+ * @param permission the required permission {@link Permissible -+ * permissibles} must have to receive the broadcast -+ * @return number of message recipients -+ */ -+ int broadcast(@NotNull net.kyori.adventure.text.Component message, @NotNull String permission); -+ // Paper end - - /** - * Gets the player by the given name, regardless if they are offline or -@@ -1109,6 +1136,7 @@ public interface Server extends PluginMessageRecipient { - @NotNull - Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type); - -+ // Paper start - /** - * Creates an empty inventory with the specified type and title. If the type - * is {@link InventoryType#CHEST}, the new inventory has a size of 27; -@@ -1134,6 +1162,36 @@ public interface Server extends PluginMessageRecipient { - * @see InventoryType#isCreatable() - */ - @NotNull -+ Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull net.kyori.adventure.text.Component title); -+ // Paper end -+ -+ /** -+ * Creates an empty inventory with the specified type and title. If the type -+ * is {@link InventoryType#CHEST}, the new inventory has a size of 27; -+ * otherwise the new inventory has the normal size for its type.
-+ * It should be noted that some inventory types do not support titles and -+ * may not render with said titles on the Minecraft client. -+ *
-+ * {@link InventoryType#WORKBENCH} will not process crafting recipes if -+ * created with this method. Use -+ * {@link Player#openWorkbench(Location, boolean)} instead. -+ *
-+ * {@link InventoryType#ENCHANTING} will not process {@link ItemStack}s -+ * for possible enchanting results. Use -+ * {@link Player#openEnchanting(Location, boolean)} instead. -+ * -+ * @param owner The holder of the inventory; can be null if there's no holder. -+ * @param type The type of inventory to create. -+ * @param title The title of the inventory, to be displayed when it is viewed. -+ * @return The new inventory. -+ * @throws IllegalArgumentException if the {@link InventoryType} cannot be -+ * viewed. -+ * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} -+ * -+ * @see InventoryType#isCreatable() -+ */ -+ @Deprecated // Paper -+ @NotNull - Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull String title); - - /** -@@ -1148,6 +1206,22 @@ public interface Server extends PluginMessageRecipient { - @NotNull - Inventory createInventory(@Nullable InventoryHolder owner, int size) throws IllegalArgumentException; - -+ // Paper start -+ /** -+ * Creates an empty inventory of type {@link InventoryType#CHEST} with the -+ * specified size and title. -+ * -+ * @param owner the holder of the inventory, or null to indicate no holder -+ * @param size a multiple of 9 as the size of inventory to create -+ * @param title the title of the inventory, displayed when inventory is -+ * viewed -+ * @return a new inventory -+ * @throws IllegalArgumentException if the size is not a multiple of 9 -+ */ -+ @NotNull -+ Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull net.kyori.adventure.text.Component title) throws IllegalArgumentException; -+ // Paper end -+ - /** - * Creates an empty inventory of type {@link InventoryType#CHEST} with the - * specified size and title. -@@ -1158,10 +1232,13 @@ public interface Server extends PluginMessageRecipient { - * viewed - * @return a new inventory - * @throws IllegalArgumentException if the size is not a multiple of 9 -+ * @deprecated in favour of {@link #createInventory(InventoryHolder, int, net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - @NotNull - Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException; - -+ // Paper start - /** - * Creates an empty merchant. - * -@@ -1169,7 +1246,18 @@ public interface Server extends PluginMessageRecipient { - * when the merchant inventory is viewed - * @return a new merchant - */ -+ @NotNull Merchant createMerchant(@Nullable net.kyori.adventure.text.Component title); -+ // Paper start -+ /** -+ * Creates an empty merchant. -+ * -+ * @param title the title of the corresponding merchant inventory, displayed -+ * when the merchant inventory is viewed -+ * @return a new merchant -+ * @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)} -+ */ - @NotNull -+ @Deprecated // Paper - Merchant createMerchant(@Nullable String title); - - /** -@@ -1265,20 +1353,41 @@ public interface Server extends PluginMessageRecipient { - */ - boolean isPrimaryThread(); - -+ // Paper start -+ /** -+ * Gets the message that is displayed on the server list. -+ * -+ * @return the server's MOTD -+ */ -+ @NotNull net.kyori.adventure.text.Component motd(); -+ // Paper end -+ - /** - * Gets the message that is displayed on the server list. - * - * @return the servers MOTD -+ * @deprecated in favour of {@link #motd()} - */ - @NotNull -+ @Deprecated // Paper - String getMotd(); - -+ // Paper start -+ /** -+ * Gets the default message that is displayed when the server is stopped. -+ * -+ * @return the shutdown message -+ */ -+ @Nullable net.kyori.adventure.text.Component shutdownMessage(); -+ // Paper end - /** - * Gets the default message that is displayed when the server is stopped. - * - * @return the shutdown message -+ * @deprecated in favour of {@link #shutdownMessage()} - */ - @Nullable -+ @Deprecated // Paper - String getShutdownMessage(); - - /** -@@ -1650,7 +1759,9 @@ public interface Server extends PluginMessageRecipient { - * Sends the component to the player - * - * @param component the components to send -+ * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -1659,7 +1770,9 @@ public interface Server extends PluginMessageRecipient { - * Sends an array of components as a single message to the player - * - * @param components the components to send -+ * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { - throw new UnsupportedOperationException("Not supported yet."); - } -diff --git a/src/main/java/org/bukkit/Sound.java b/src/main/java/org/bukkit/Sound.java -index 21b95d404fbdf7f972f8a13ecd07dc28481f2286..da844079a9d3efd1a92c892de79fc7b3aeecaf4b 100644 ---- a/src/main/java/org/bukkit/Sound.java -+++ b/src/main/java/org/bukkit/Sound.java -@@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull; - * guarantee values will not be removed from this Enum. As such, you should not - * depend on the ordinal values of this class. - */ --public enum Sound implements Keyed { -+public enum Sound implements Keyed, net.kyori.adventure.sound.Sound.Type { // Paper - implement Sound.Type - - AMBIENT_BASALT_DELTAS_ADDITIONS("ambient.basalt_deltas.additions"), - AMBIENT_BASALT_DELTAS_LOOP("ambient.basalt_deltas.loop"), -@@ -1345,4 +1345,12 @@ public enum Sound implements Keyed { - public NamespacedKey getKey() { - return key; - } -+ -+ // Paper start -+ @NotNull -+ @Override -+ public net.kyori.adventure.key.@org.checkerframework.checker.nullness.qual.NonNull Key key() { -+ return this.key; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/SoundCategory.java b/src/main/java/org/bukkit/SoundCategory.java -index ac5e263d737973af077e3406a84a84baca4370db..2d91924b7f5ef16a91d40cdc1bfc3d68e0fda38d 100644 ---- a/src/main/java/org/bukkit/SoundCategory.java -+++ b/src/main/java/org/bukkit/SoundCategory.java -@@ -3,7 +3,7 @@ package org.bukkit; - /** - * An Enum of categories for sounds. - */ --public enum SoundCategory { -+public enum SoundCategory implements net.kyori.adventure.sound.Sound.Source.Provider { // Paper - implement Sound.Source.Provider - - MASTER, - MUSIC, -@@ -15,4 +15,22 @@ public enum SoundCategory { - PLAYERS, - AMBIENT, - VOICE; -+ -+ // Paper start - implement Sound.Source.Provider -+ @Override -+ public net.kyori.adventure.sound.Sound.@org.jetbrains.annotations.NotNull Source soundSource() { -+ return switch (this) { -+ case MASTER -> net.kyori.adventure.sound.Sound.Source.MASTER; -+ case MUSIC -> net.kyori.adventure.sound.Sound.Source.MUSIC; -+ case RECORDS -> net.kyori.adventure.sound.Sound.Source.RECORD; -+ case WEATHER -> net.kyori.adventure.sound.Sound.Source.WEATHER; -+ case BLOCKS -> net.kyori.adventure.sound.Sound.Source.BLOCK; -+ case HOSTILE -> net.kyori.adventure.sound.Sound.Source.HOSTILE; -+ case NEUTRAL -> net.kyori.adventure.sound.Sound.Source.NEUTRAL; -+ case PLAYERS -> net.kyori.adventure.sound.Sound.Source.PLAYER; -+ case AMBIENT -> net.kyori.adventure.sound.Sound.Source.AMBIENT; -+ case VOICE -> net.kyori.adventure.sound.Sound.Source.VOICE; -+ }; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 01e11f882abb6c631f810584aa23646042688435..fa28b5bb0efd9d400277cd8969f38e039e6ea8ac 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -22,6 +22,14 @@ import org.bukkit.plugin.PluginDescriptionFile; - */ - @Deprecated - public interface UnsafeValues { -+ // Paper start -+ net.kyori.adventure.text.flattener.ComponentFlattener componentFlattener(); -+ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.plain.PlainComponentSerializer plainComponentSerializer(); -+ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer plainTextSerializer(); -+ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.gson.GsonComponentSerializer gsonComponentSerializer(); -+ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.gson.GsonComponentSerializer colorDownsamplingGsonComponentSerializer(); -+ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer legacyComponentSerializer(); -+ // Paper end - - Material toLegacy(Material material); - -diff --git a/src/main/java/org/bukkit/Warning.java b/src/main/java/org/bukkit/Warning.java -index efb97712cc9dc7c1e12a59f5b94e4f2ad7c6b7d8..3024468af4c073324e536c1cb26beffb1e09f3f4 100644 ---- a/src/main/java/org/bukkit/Warning.java -+++ b/src/main/java/org/bukkit/Warning.java -@@ -67,6 +67,7 @@ public @interface Warning { - * - */ - public boolean printFor(@Nullable Warning warning) { -+ if (Boolean.getBoolean("paper.alwaysPrintWarningState")) return true; // Paper - if (this == DEFAULT) { - return warning == null || warning.value(); - } -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 7e0c6c57976a00f989fe4e5dce83cd986b460e72..1d3bb553c944f5920e81e295f8cd5b7194d37aac 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -43,7 +43,7 @@ import org.jetbrains.annotations.Nullable; - /** - * Represents a world, which may contain entities, chunks and blocks - */ --public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, Keyed { -+public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, Keyed, net.kyori.adventure.audience.ForwardingAudience { // Paper - - /** - * Gets the {@link Block} at the given coordinates -@@ -638,6 +638,14 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - @NotNull - public List getPlayers(); - -+ // Paper start -+ @NotNull -+ @Override -+ default Iterable audiences() { -+ return this.getPlayers(); -+ } -+ // Paper end -+ - /** - * Returns a list of entities within a bounding box centered around a - * Location. -diff --git a/src/main/java/org/bukkit/block/CommandBlock.java b/src/main/java/org/bukkit/block/CommandBlock.java -index 372c0bd5a4d7800a11c24c95e39fe376a96232bf..73dce588d1f7a5048300073bf8c2b14d6da1e857 100644 ---- a/src/main/java/org/bukkit/block/CommandBlock.java -+++ b/src/main/java/org/bukkit/block/CommandBlock.java -@@ -33,7 +33,9 @@ public interface CommandBlock extends TileState { - * by default is "@". - * - * @return Name of this CommandBlock. -+ * @deprecated in favour of {@link #name()} - */ -+ @Deprecated // Paper - @NotNull - public String getName(); - -@@ -43,6 +45,28 @@ public interface CommandBlock extends TileState { - * same as setting it to "@". - * - * @param name New name for this CommandBlock. -+ * @deprecated in favour of {@link #name(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setName(@Nullable String name); -+ -+ // Paper start -+ /** -+ * Gets the name of this CommandBlock. The name is used with commands -+ * that this CommandBlock executes. This name will never be null, and -+ * by default is a {@link net.kyori.adventure.text.TextComponent} containing {@code @}. -+ * -+ * @return Name of this CommandBlock. -+ */ -+ public @NotNull net.kyori.adventure.text.Component name(); -+ -+ /** -+ * Sets the name of this CommandBlock. The name is used with commands -+ * that this CommandBlock executes. Setting the name to null is the -+ * same as setting it to a {@link net.kyori.adventure.text.TextComponent} containing {@code @}. -+ * -+ * @param name New name for this CommandBlock. -+ */ -+ public void name(@Nullable net.kyori.adventure.text.Component name); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/block/Sign.java b/src/main/java/org/bukkit/block/Sign.java -index ab6b0ec328e94bf65a0dafd0403e5ee3b870296c..c8d37184d8e882a4084a1bfef85faa330588600b 100644 ---- a/src/main/java/org/bukkit/block/Sign.java -+++ b/src/main/java/org/bukkit/block/Sign.java -@@ -7,13 +7,48 @@ import org.jetbrains.annotations.NotNull; - * Represents a captured state of either a SignPost or a WallSign. - */ - public interface Sign extends TileState, Colorable { -+ // Paper start -+ /** -+ * Gets all the lines of text currently on this sign. -+ * -+ * @return Array of Strings containing each line of text -+ */ -+ @NotNull -+ public java.util.List lines(); -+ -+ /** -+ * Gets the line of text at the specified index. -+ *

-+ * For example, getLine(0) will return the first line of text. -+ * -+ * @param index Line number to get the text from, starting at 0 -+ * @throws IndexOutOfBoundsException Thrown when the line does not exist -+ * @return Text on the given line -+ */ -+ @NotNull -+ public net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException; -+ -+ /** -+ * Sets the line of text at the specified index. -+ *

-+ * For example, setLine(0, "Line One") will set the first line of text to -+ * "Line One". -+ * -+ * @param index Line number to set the text at, starting from 0 -+ * @param line New text to set at the specified index -+ * @throws IndexOutOfBoundsException If the index is out of the range 0..3 -+ */ -+ public void line(int index, @NotNull net.kyori.adventure.text.Component line) throws IndexOutOfBoundsException; -+ // Paper end - - /** - * Gets all the lines of text currently on this sign. - * - * @return Array of Strings containing each line of text -+ * @deprecated in favour of {@link #lines()} - */ - @NotNull -+ @Deprecated // Paper - public String[] getLines(); - - /** -@@ -24,8 +59,10 @@ public interface Sign extends TileState, Colorable { - * @param index Line number to get the text from, starting at 0 - * @return Text on the given line - * @throws IndexOutOfBoundsException Thrown when the line does not exist -+ * @deprecated in favour of {@link #line(int)} - */ - @NotNull -+ @Deprecated // Paper - public String getLine(int index) throws IndexOutOfBoundsException; - - /** -@@ -37,7 +74,9 @@ public interface Sign extends TileState, Colorable { - * @param index Line number to set the text at, starting from 0 - * @param line New text to set at the specified index - * @throws IndexOutOfBoundsException If the index is out of the range 0..3 -+ * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException; - - /** -diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java -index 80209bb88a0294d4eedc78509533a6257315d856..57ade3963faae3724d9a01eeeb6d02168acb567e 100644 ---- a/src/main/java/org/bukkit/command/Command.java -+++ b/src/main/java/org/bukkit/command/Command.java -@@ -32,8 +32,7 @@ public abstract class Command { - protected String description; - protected String usageMessage; - private String permission; -- private String permissionMessage; -- public org.spigotmc.CustomTimingsHandler timings; // Spigot -+ private net.kyori.adventure.text.Component permissionMessage; // Paper - - protected Command(@NotNull String name) { - this(name, "", "/" + name, new ArrayList()); -@@ -186,10 +185,10 @@ public abstract class Command { - - if (permissionMessage == null) { - target.sendMessage(ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is a mistake."); -- } else if (permissionMessage.length() != 0) { -- for (String line : permissionMessage.replace("", permission).split("\n")) { -- target.sendMessage(line); -- } -+ // Paper start - use components for permissionMessage -+ } else if (!permissionMessage.equals(net.kyori.adventure.text.Component.empty())) { -+ target.sendMessage(permissionMessage.replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("").replacement(permission).build())); -+ // Paper end - } - - return false; -@@ -317,10 +316,12 @@ public abstract class Command { - * command - * - * @return Permission check failed message -+ * @deprecated use {@link #permissionMessage()} - */ - @Nullable -+ @Deprecated // Paper - public String getPermissionMessage() { -- return permissionMessage; -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serializeOrNull(permissionMessage); // Paper - } - - /** -@@ -381,10 +382,12 @@ public abstract class Command { - * @param permissionMessage new permission message, null to indicate - * default message, or an empty string to indicate no message - * @return this command object, for chaining -+ * @deprecated use {@link #permissionMessage(net.kyori.adventure.text.Component)} - */ - @NotNull -+ @Deprecated // Paper - public Command setPermissionMessage(@Nullable String permissionMessage) { -- this.permissionMessage = permissionMessage; -+ this.permissionMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(permissionMessage); // Paper - return this; - } - -@@ -399,13 +402,47 @@ public abstract class Command { - this.usageMessage = (usage == null) ? "" : usage; - return this; - } -+ // Paper start -+ /** -+ * Gets the permission message. -+ * -+ * @return the permission message -+ */ -+ public @Nullable net.kyori.adventure.text.Component permissionMessage() { -+ return this.permissionMessage; -+ } -+ -+ /** -+ * Sets the permission message. -+ * -+ * @param permissionMessage the permission message -+ */ -+ public void permissionMessage(@Nullable net.kyori.adventure.text.Component permissionMessage) { -+ this.permissionMessage = permissionMessage; -+ } -+ // Paper end - - public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull String message) { - broadcastCommandMessage(source, message, true); - } - - public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull String message, boolean sendToSource) { -- String result = source.getName() + ": " + message; -+ // Paper start -+ broadcastCommandMessage(source, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message), sendToSource); -+ } -+ -+ public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull net.kyori.adventure.text.Component message) { -+ broadcastCommandMessage(source, message, true); -+ } -+ -+ public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull net.kyori.adventure.text.Component message, boolean sendToSource) { -+ net.kyori.adventure.text.TextComponent.Builder result = net.kyori.adventure.text.Component.text() -+ .color(net.kyori.adventure.text.format.NamedTextColor.WHITE) -+ .decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false) -+ .append(source.name()) -+ .append(net.kyori.adventure.text.Component.text(": ")) -+ .append(message); -+ // Paper end - - if (source instanceof BlockCommandSender) { - BlockCommandSender blockCommandSender = (BlockCommandSender) source; -@@ -424,7 +461,12 @@ public abstract class Command { - } - - Set users = Bukkit.getPluginManager().getPermissionSubscriptions(Server.BROADCAST_CHANNEL_ADMINISTRATIVE); -- String colored = ChatColor.GRAY + "" + ChatColor.ITALIC + "[" + result + ChatColor.GRAY + ChatColor.ITALIC + "]"; -+ // Paper start -+ net.kyori.adventure.text.TextComponent.Builder colored = net.kyori.adventure.text.Component.text() -+ .color(net.kyori.adventure.text.format.NamedTextColor.GRAY) -+ .decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC) -+ .append(net.kyori.adventure.text.Component.text("["), result, net.kyori.adventure.text.Component.text("]")); -+ // Paper end - - if (sendToSource && !(source instanceof ConsoleCommandSender)) { - source.sendMessage(message); -diff --git a/src/main/java/org/bukkit/command/CommandSender.java b/src/main/java/org/bukkit/command/CommandSender.java -index 284be63a125624a8ae43d2c164aede810ce6bfe5..ec97093a4410322ad44e111d894a3b1a5c5f7b88 100644 ---- a/src/main/java/org/bukkit/command/CommandSender.java -+++ b/src/main/java/org/bukkit/command/CommandSender.java -@@ -6,12 +6,13 @@ import org.bukkit.permissions.Permissible; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; - --public interface CommandSender extends Permissible { -+public interface CommandSender extends net.kyori.adventure.audience.Audience, Permissible { // Paper - - /** - * Sends this sender a message - * - * @param message Message to be displayed -+ * @see #sendMessage(net.kyori.adventure.text.Component) - */ - public void sendMessage(@NotNull String message); - -@@ -19,6 +20,7 @@ public interface CommandSender extends Permissible { - * Sends this sender multiple messages - * - * @param messages An array of messages to be displayed -+ * @see #sendMessage(net.kyori.adventure.text.Component) - */ - public void sendMessage(@NotNull String... messages); - -@@ -27,6 +29,7 @@ public interface CommandSender extends Permissible { - * - * @param message Message to be displayed - * @param sender The sender of this message -+ * @see #sendMessage(net.kyori.adventure.identity.Identified, net.kyori.adventure.text.Component) - */ - public void sendMessage(@Nullable UUID sender, @NotNull String message); - -@@ -35,6 +38,7 @@ public interface CommandSender extends Permissible { - * - * @param messages An array of messages to be displayed - * @param sender The sender of this message -+ * @see #sendMessage(net.kyori.adventure.identity.Identified, net.kyori.adventure.text.Component) - */ - public void sendMessage(@Nullable UUID sender, @NotNull String... messages); - -@@ -61,7 +65,9 @@ public interface CommandSender extends Permissible { - * Sends this sender a chat component. - * - * @param component the components to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} - */ -+ @Deprecated // Paper - public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -70,7 +76,9 @@ public interface CommandSender extends Permissible { - * Sends an array of components as a single message to the sender. - * - * @param components the components to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} - */ -+ @Deprecated // Paper - public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -80,7 +88,9 @@ public interface CommandSender extends Permissible { - * - * @param component the components to send - * @param sender the sender of the message -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} - */ -+ @Deprecated // Paper - public void sendMessage(@Nullable UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent component) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -90,7 +100,9 @@ public interface CommandSender extends Permissible { - * - * @param components the components to send - * @param sender the sender of the message -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} - */ -+ @Deprecated // Paper - public void sendMessage(@Nullable UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -99,4 +111,39 @@ public interface CommandSender extends Permissible { - @NotNull - Spigot spigot(); - // Spigot end -+ -+ // Paper start -+ /** -+ * Gets the name of this command sender -+ * -+ * @return Name of the sender -+ */ -+ public @NotNull net.kyori.adventure.text.Component name(); -+ -+ @Override -+ default void sendMessage(final @NotNull net.kyori.adventure.identity.Identity identity, final @NotNull net.kyori.adventure.text.Component message, final @NotNull net.kyori.adventure.audience.MessageType type) { -+ this.sendMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); -+ } -+ -+ /** -+ * Sends a message with the MiniMessage format to the command sender. -+ *

-+ * See MiniMessage docs -+ * for more information on the format. -+ * -+ * @param message MiniMessage content -+ */ -+ default void sendRichMessage(final @NotNull String message) { -+ this.sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message)); -+ } -+ -+ /** -+ * Sends a plain message to the command sender. -+ * -+ * @param message plain message -+ */ -+ default void sendPlainMessage(final @NotNull String message) { -+ this.sendMessage(net.kyori.adventure.text.Component.text(message)); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/command/PluginCommandYamlParser.java b/src/main/java/org/bukkit/command/PluginCommandYamlParser.java -index a542c4bb3c973bbe4b976642feccde6a4d90cb7b..ef870b864c1e36032b54b31f3f85707edc06d764 100644 ---- a/src/main/java/org/bukkit/command/PluginCommandYamlParser.java -+++ b/src/main/java/org/bukkit/command/PluginCommandYamlParser.java -@@ -67,7 +67,7 @@ public class PluginCommandYamlParser { - } - - if (permissionMessage != null) { -- newCmd.setPermissionMessage(permissionMessage.toString()); -+ newCmd.permissionMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(permissionMessage.toString())); // Paper - } - - pluginCmds.add(newCmd); -diff --git a/src/main/java/org/bukkit/command/ProxiedCommandSender.java b/src/main/java/org/bukkit/command/ProxiedCommandSender.java -index fcc34b640265f4dccb46b9f09466ab8e1d96043e..74599b4ee0518481c0e3a5f6ab2f5302837f1ae3 100644 ---- a/src/main/java/org/bukkit/command/ProxiedCommandSender.java -+++ b/src/main/java/org/bukkit/command/ProxiedCommandSender.java -@@ -3,7 +3,7 @@ package org.bukkit.command; - - import org.jetbrains.annotations.NotNull; - --public interface ProxiedCommandSender extends CommandSender { -+public interface ProxiedCommandSender extends CommandSender, net.kyori.adventure.audience.ForwardingAudience.Single { // Paper - - /** - * Returns the CommandSender which triggered this proxied command -@@ -21,4 +21,16 @@ public interface ProxiedCommandSender extends CommandSender { - @NotNull - CommandSender getCallee(); - -+ // Paper start -+ @Override -+ default void sendMessage(final @NotNull net.kyori.adventure.identity.Identity source, final @NotNull net.kyori.adventure.text.Component message, final @NotNull net.kyori.adventure.audience.MessageType type) { -+ net.kyori.adventure.audience.ForwardingAudience.Single.super.sendMessage(source, message, type); -+ } -+ -+ @NotNull -+ @Override -+ default net.kyori.adventure.audience.Audience audience() { -+ return this.getCaller(); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/enchantments/Enchantment.java b/src/main/java/org/bukkit/enchantments/Enchantment.java -index e2800dc97af5bbb02c555069285a0fa155a9799d..5744a9f432ec75f6b6b1991ff488dffb9591c934 100644 ---- a/src/main/java/org/bukkit/enchantments/Enchantment.java -+++ b/src/main/java/org/bukkit/enchantments/Enchantment.java -@@ -299,6 +299,19 @@ public abstract class Enchantment implements Keyed { - * @return True if the enchantment may be applied, otherwise False - */ - public abstract boolean canEnchantItem(@NotNull ItemStack item); -+ // Paper start -+ /** -+ * Get the name of the enchantment with its applied level. -+ *

-+ * If the given {@code level} is either less than the {@link #getStartLevel()} or greater than the {@link #getMaxLevel()}, -+ * the level may not be shown in the numeral format one may otherwise expect. -+ *

-+ * -+ * @param level the level of the enchantment to show -+ * @return the name of the enchantment with {@code level} applied -+ */ -+ public abstract @NotNull net.kyori.adventure.text.Component displayName(int level); -+ // Paper end - - @Override - public boolean equals(Object obj) { -diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java -index 9566e4306ada5e82dede0f002aa06da12c44996b..4d5f0837bd0e02a30c943d8969fb6b13452322e0 100644 ---- a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java -+++ b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java -@@ -63,4 +63,11 @@ public class EnchantmentWrapper extends Enchantment { - public boolean conflictsWith(@NotNull Enchantment other) { - return getEnchantment().conflictsWith(other); - } -+ // Paper start -+ @NotNull -+ @Override -+ public net.kyori.adventure.text.Component displayName(int level) { -+ return getEnchantment().displayName(level); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 922d33ff4fa9d901d3c5c0a9f8399ad8aef62c37..cd287978c34873c7122794e4f3e762915978a1f0 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -25,7 +25,7 @@ import org.jetbrains.annotations.Nullable; - /** - * Represents a base entity in the world - */ --public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder { -+public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder, net.kyori.adventure.text.event.HoverEventSource, net.kyori.adventure.sound.Sound.Emitter { // Paper - - /** - * Gets the entity's current position -@@ -656,4 +656,20 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - @Override - Spigot spigot(); - // Spigot end -+ -+ // Paper start -+ /** -+ * Gets the entity's display name formatted with their team prefix/suffix and -+ * the entity's default hover/click events. -+ * -+ * @return the team display name -+ */ -+ @NotNull net.kyori.adventure.text.Component teamDisplayName(); -+ -+ @NotNull -+ @Override -+ default net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { -+ return net.kyori.adventure.text.event.HoverEvent.showEntity(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowEntity.of(this.getType().getKey(), this.getUniqueId(), this.customName()))); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 6cac14eabdbdf7fd8c322d5fb4dfbfbb266ae940..c580ec19cd2b55a4aeca49d9cd984ce7c2848cef 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -37,7 +37,28 @@ import org.jetbrains.annotations.Nullable; - /** - * Represents a player, connected or not - */ --public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient { -+public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified { // Paper -+ -+ // Paper start -+ @Override -+ default @NotNull net.kyori.adventure.identity.Identity identity() { -+ return net.kyori.adventure.identity.Identity.identity(this.getUniqueId()); -+ } -+ -+ /** -+ * Gets the "friendly" name to display of this player. -+ * -+ * @return the display name -+ */ -+ @NotNull net.kyori.adventure.text.Component displayName(); -+ -+ /** -+ * Sets the "friendly" name to display of this player. -+ * -+ * @param displayName the display name to set -+ */ -+ void displayName(final @Nullable net.kyori.adventure.text.Component displayName); -+ // Paper end - - /** - * Gets the "friendly" name to display of this player. This may include -@@ -47,7 +68,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * places defined by plugins. - * - * @return the friendly name -+ * @deprecated in favour of {@link #displayName()} - */ -+ @Deprecated // Paper - @NotNull - public String getDisplayName(); - -@@ -59,15 +82,50 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * places defined by plugins. - * - * @param name The new display name. -+ * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setDisplayName(@Nullable String name); - -+ // Paper start -+ /** -+ * Sets the name that is shown on the in-game player list. -+ *

-+ * If the value is null, the name will be identical to {@link #getName()}. -+ * -+ * @param name new player list name -+ */ -+ void playerListName(@Nullable net.kyori.adventure.text.Component name); -+ -+ /** -+ * Gets the name that is shown on the in-game player list. -+ * -+ * @return the player list name -+ */ -+ @NotNull net.kyori.adventure.text.Component playerListName(); -+ -+ /** -+ * Gets the currently displayed player list header for this player. -+ * -+ * @return player list header or null -+ */ -+ @Nullable net.kyori.adventure.text.Component playerListHeader(); -+ -+ /** -+ * Gets the currently displayed player list footer for this player. -+ * -+ * @return player list footer or null -+ */ -+ @Nullable net.kyori.adventure.text.Component playerListFooter(); -+ // Paper end - /** - * Gets the name that is shown on the player list. - * - * @return the player list name -+ * @deprecated in favour of {@link #playerListName()} - */ - @NotNull -+ @Deprecated // Paper - public String getPlayerListName(); - - /** -@@ -76,14 +134,18 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * If the value is null, the name will be identical to {@link #getName()}. - * - * @param name new player list name -+ * @deprecated in favour of {@link #playerListName(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setPlayerListName(@Nullable String name); - - /** - * Gets the currently displayed player list header for this player. - * - * @return player list header or null -+ * @deprecated in favour of {@link #playerListHeader()} - */ -+ @Deprecated // Paper - @Nullable - public String getPlayerListHeader(); - -@@ -91,7 +153,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * Gets the currently displayed player list footer for this player. - * - * @return player list header or null -+ * @deprecated in favour of {@link #playerListFooter()} - */ -+ @Deprecated // Paper - @Nullable - public String getPlayerListFooter(); - -@@ -99,14 +163,18 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * Sets the currently displayed player list header for this player. - * - * @param header player list header, null for empty -+ * @deprecated in favour of {@link #sendPlayerListHeader(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setPlayerListHeader(@Nullable String header); - - /** - * Sets the currently displayed player list footer for this player. - * - * @param footer player list footer, null for empty -+ * @deprecated in favour of {@link #sendPlayerListFooter(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setPlayerListFooter(@Nullable String footer); - - /** -@@ -115,7 +183,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * - * @param header player list header, null for empty - * @param footer player list footer, null for empty -+ * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setPlayerListHeaderFooter(@Nullable String header, @Nullable String footer); - - /** -@@ -153,9 +223,25 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * Kicks player with custom kick message. - * - * @param message kick message -+ * @deprecated in favour of {@link #kick(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void kickPlayer(@Nullable String message); - -+ // Paper start -+ /** -+ * Kicks the player with the default kick message. -+ * @see #kick(Component) -+ */ -+ void kick(); -+ /** -+ * Kicks player with custom kick message. -+ * -+ * @param message kick message -+ */ -+ void kick(final @Nullable net.kyori.adventure.text.Component message); -+ // Paper end -+ - /** - * Says a message (or runs a command). - * -@@ -507,6 +593,90 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - */ - public void sendEquipmentChange(@NotNull LivingEntity entity, @NotNull EquipmentSlot slot, @NotNull ItemStack item); - -+ // Paper start -+ /** -+ * Send a sign change. This fakes a sign change packet for a user at -+ * a certain location. This will not actually change the world in any way. -+ * This method will use a sign at the location's block or a faked sign -+ * sent via -+ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. -+ *

-+ * If the client does not have a sign at the given location it will -+ * display an error message to the user. -+ * -+ * @param loc the location of the sign -+ * @param lines the new text on the sign or null to clear it -+ * @throws IllegalArgumentException if location is null -+ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 -+ */ -+ default void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines) throws IllegalArgumentException { -+ this.sendSignChange(loc, lines, DyeColor.BLACK); -+ } -+ -+ /** -+ * Send a sign change. This fakes a sign change packet for a user at -+ * a certain location. This will not actually change the world in any way. -+ * This method will use a sign at the location's block or a faked sign -+ * sent via -+ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. -+ *

-+ * If the client does not have a sign at the given location it will -+ * display an error message to the user. -+ * -+ * @param loc the location of the sign -+ * @param lines the new text on the sign or null to clear it -+ * @param dyeColor the color of the sign -+ * @throws IllegalArgumentException if location is null -+ * @throws IllegalArgumentException if dyeColor is null -+ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 -+ */ -+ default void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException { -+ this.sendSignChange(loc, lines, dyeColor, false); -+ } -+ -+ /** -+ * Send a sign change. This fakes a sign change packet for a user at -+ * a certain location. This will not actually change the world in any way. -+ * This method will use a sign at the location's block or a faked sign -+ * sent via -+ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. -+ *

-+ * If the client does not have a sign at the given location it will -+ * display an error message to the user. -+ * -+ * @param loc the location of the sign -+ * @param lines the new text on the sign or null to clear it -+ * @param hasGlowingText whether the text of the sign should glow as if dyed with a glowing ink sac -+ * @throws IllegalArgumentException if location is null -+ * @throws IllegalArgumentException if dyeColor is null -+ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 -+ */ -+ default void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines, boolean hasGlowingText) throws IllegalArgumentException { -+ this.sendSignChange(loc, lines, DyeColor.BLACK, hasGlowingText); -+ } -+ -+ /** -+ * Send a sign change. This fakes a sign change packet for a user at -+ * a certain location. This will not actually change the world in any way. -+ * This method will use a sign at the location's block or a faked sign -+ * sent via -+ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. -+ *

-+ * If the client does not have a sign at the given location it will -+ * display an error message to the user. -+ * -+ * @param loc the location of the sign -+ * @param lines the new text on the sign or null to clear it -+ * @param dyeColor the color of the sign -+ * @param hasGlowingText whether the text of the sign should glow as if dyed with a glowing ink sac -+ * @throws IllegalArgumentException if location is null -+ * @throws IllegalArgumentException if dyeColor is null -+ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 -+ */ -+ void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines, @NotNull DyeColor dyeColor, boolean hasGlowingText) -+ throws IllegalArgumentException; -+ // Paper end -+ - /** - * Send a sign change. This fakes a sign change packet for a user at - * a certain location. This will not actually change the world in any way. -@@ -521,7 +691,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @param lines the new text on the sign or null to clear it - * @throws IllegalArgumentException if location is null - * @throws IllegalArgumentException if lines is non-null and has a length less than 4 -+ * @deprecated in favour of {@link #sendSignChange(org.bukkit.Location, java.util.List)} - */ -+ @Deprecated // Paper - public void sendSignChange(@NotNull Location loc, @Nullable String[] lines) throws IllegalArgumentException; - - /** -@@ -540,7 +712,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @throws IllegalArgumentException if location is null - * @throws IllegalArgumentException if dyeColor is null - * @throws IllegalArgumentException if lines is non-null and has a length less than 4 -+ * @deprecated in favour of {@link #sendSignChange(org.bukkit.Location, java.util.List, org.bukkit.DyeColor)} - */ -+ @Deprecated // Paper - public void sendSignChange(@NotNull Location loc, @Nullable String[] lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException; - - /** -@@ -560,7 +734,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @throws IllegalArgumentException if location is null - * @throws IllegalArgumentException if dyeColor is null - * @throws IllegalArgumentException if lines is non-null and has a length less than 4 -+ * @deprecated Deprecated in favour of {@link #sendSignChange(Location, java.util.List, DyeColor, boolean)} - */ -+ @Deprecated // Paper - public void sendSignChange(@NotNull Location loc, @Nullable String[] lines, @NotNull DyeColor dyeColor, boolean hasGlowingText) throws IllegalArgumentException; - - /** -@@ -1035,6 +1211,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * pack correctly. - * - * -+ * @deprecated in favour of {@link #setResourcePack(String, byte[], Component)} - * @param url The URL from which the client will download the resource - * pack. The string must contain only US-ASCII characters and should - * be encoded as per RFC 1738. -@@ -1048,8 +1225,57 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @throws IllegalArgumentException Thrown if the hash is not 20 bytes - * long. - */ -+ @Deprecated // Paper - public void setResourcePack(@NotNull String url, @Nullable byte[] hash, @Nullable String prompt); - -+ // Paper start -+ /** -+ * Request that the player's client download and switch resource packs. -+ *

-+ * The player's client will download the new resource pack asynchronously -+ * in the background, and will automatically switch to it once the -+ * download is complete. If the client has downloaded and cached a -+ * resource pack with the same hash in the past it will not download but -+ * directly apply the cached pack. If the hash is null and the client has -+ * downloaded and cached the same resource pack in the past, it will -+ * perform a file size check against the response content to determine if -+ * the resource pack has changed and needs to be downloaded again. When -+ * this request is sent for the very first time from a given server, the -+ * client will first display a confirmation GUI to the player before -+ * proceeding with the download. -+ *

-+ * Notes: -+ *

    -+ *
  • Players can disable server resources on their client, in which -+ * case this method will have no affect on them. Use the -+ * {@link PlayerResourcePackStatusEvent} to figure out whether or not -+ * the player loaded the pack! -+ *
  • There is no concept of resetting resource packs back to default -+ * within Minecraft, so players will have to relog to do so or you -+ * have to send an empty pack. -+ *
  • The request is sent with empty string as the hash when the hash is -+ * not provided. This might result in newer versions not loading the -+ * pack correctly. -+ *
-+ * -+ * @param url The URL from which the client will download the resource -+ * pack. The string must contain only US-ASCII characters and should -+ * be encoded as per RFC 1738. -+ * @param hash The sha1 hash sum of the resource pack file which is used -+ * to apply a cached version of the pack directly without downloading -+ * if it is available. Hast to be 20 bytes long! -+ * @param prompt The optional custom prompt message to be shown to client. -+ * @throws IllegalArgumentException Thrown if the URL is null. -+ * @throws IllegalArgumentException Thrown if the URL is too long. The -+ * length restriction is an implementation specific arbitrary value. -+ * @throws IllegalArgumentException Thrown if the hash is not 20 bytes -+ * long. -+ */ -+ default void setResourcePack(@NotNull String url, byte @Nullable [] hash, net.kyori.adventure.text.@Nullable Component prompt) { -+ this.setResourcePack(url, hash, prompt, false); -+ } -+ // Paper end -+ - /** - * Request that the player's client download and switch resource packs. - *

-@@ -1124,6 +1350,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * pack correctly. - * - * -+ * @deprecated in favour of {@link #setResourcePack(String, byte[], Component, boolean)} - * @param url The URL from which the client will download the resource - * pack. The string must contain only US-ASCII characters and should - * be encoded as per RFC 1738. -@@ -1139,8 +1366,57 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @throws IllegalArgumentException Thrown if the hash is not 20 bytes - * long. - */ -+ @Deprecated // Paper - public void setResourcePack(@NotNull String url, @Nullable byte[] hash, @Nullable String prompt, boolean force); - -+ // Paper start -+ /** -+ * Request that the player's client download and switch resource packs. -+ *

-+ * The player's client will download the new resource pack asynchronously -+ * in the background, and will automatically switch to it once the -+ * download is complete. If the client has downloaded and cached a -+ * resource pack with the same hash in the past it will not download but -+ * directly apply the cached pack. If the hash is null and the client has -+ * downloaded and cached the same resource pack in the past, it will -+ * perform a file size check against the response content to determine if -+ * the resource pack has changed and needs to be downloaded again. When -+ * this request is sent for the very first time from a given server, the -+ * client will first display a confirmation GUI to the player before -+ * proceeding with the download. -+ *

-+ * Notes: -+ *

    -+ *
  • Players can disable server resources on their client, in which -+ * case this method will have no affect on them. Use the -+ * {@link PlayerResourcePackStatusEvent} to figure out whether or not -+ * the player loaded the pack! -+ *
  • There is no concept of resetting resource packs back to default -+ * within Minecraft, so players will have to relog to do so or you -+ * have to send an empty pack. -+ *
  • The request is sent with empty string as the hash when the hash is -+ * not provided. This might result in newer versions not loading the -+ * pack correctly. -+ *
-+ * -+ * @param url The URL from which the client will download the resource -+ * pack. The string must contain only US-ASCII characters and should -+ * be encoded as per RFC 1738. -+ * @param hash The sha1 hash sum of the resource pack file which is used -+ * to apply a cached version of the pack directly without downloading -+ * if it is available. Hast to be 20 bytes long! -+ * @param prompt The optional custom prompt message to be shown to client. -+ * @param force If true, the client will be disconnected from the server -+ * when it declines to use the resource pack. -+ * @throws IllegalArgumentException Thrown if the URL is null. -+ * @throws IllegalArgumentException Thrown if the URL is too long. The -+ * length restriction is an implementation specific arbitrary value. -+ * @throws IllegalArgumentException Thrown if the hash is not 20 bytes -+ * long. -+ */ -+ public void setResourcePack(@NotNull String url, byte @Nullable [] hash, net.kyori.adventure.text.@Nullable Component prompt, boolean force); -+ // Paper end -+ - /** - * Gets the Scoreboard displayed to this player - * -@@ -1256,7 +1532,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * - * @param title Title text - * @param subtitle Subtitle text -- * @deprecated API behavior subject to change -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} - */ - @Deprecated - public void sendTitle(@Nullable String title, @Nullable String subtitle); -@@ -1275,7 +1551,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @param fadeIn time in ticks for titles to fade in. Defaults to 10. - * @param stay time in ticks for titles to stay. Defaults to 70. - * @param fadeOut time in ticks for titles to fade out. Defaults to 20. -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} - */ -+ @Deprecated // Paper - Adventure - public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int stay, int fadeOut); - - /** -@@ -1502,6 +1780,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - */ - public int getClientViewDistance(); - -+ // Paper start -+ /** -+ * Gets the player's current locale. -+ * -+ * @return the player's locale -+ */ -+ @NotNull java.util.Locale locale(); -+ // Paper end - /** - * Gets the player's estimated ping in milliseconds. - * -@@ -1527,8 +1813,10 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * they wish. - * - * @return the player's locale -+ * @deprecated in favour of {@link #locale()} - */ - @NotNull -+ @Deprecated // Paper - public String getLocale(); - - /** -@@ -1570,6 +1858,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - */ - public boolean isAllowingServerListings(); - -+ // Paper start -+ @NotNull -+ @Override -+ default net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { -+ return net.kyori.adventure.text.event.HoverEvent.showEntity(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowEntity.of(this.getType().getKey(), this.getUniqueId(), this.displayName()))); -+ } -+ // Paper end -+ - // Spigot start - public class Spigot extends Entity.Spigot { - -@@ -1624,11 +1920,13 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - throw new UnsupportedOperationException("Not supported yet."); - } - -+ @Deprecated // Paper - @Override - public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { - throw new UnsupportedOperationException("Not supported yet."); - } - -+ @Deprecated // Paper - @Override - public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { - throw new UnsupportedOperationException("Not supported yet."); -@@ -1639,7 +1937,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * - * @param position the screen position - * @param component the components to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} - */ -+ @Deprecated // Paper - public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @NotNull net.md_5.bungee.api.chat.BaseComponent component) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -1649,7 +1949,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * - * @param position the screen position - * @param components the components to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} - */ -+ @Deprecated // Paper - public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -1660,7 +1962,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @param position the screen position - * @param sender the sender of the message - * @param component the components to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} - */ -+ @Deprecated // Paper - public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @Nullable UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent component) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -1671,7 +1975,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @param position the screen position - * @param sender the sender of the message - * @param components the components to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} - */ -+ @Deprecated // Paper - public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @Nullable UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { - throw new UnsupportedOperationException("Not supported yet."); - } -diff --git a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java -index 63c80b4ee1f7adc8a9efc3b607993104b1991f90..91cab8b13d5bba34007f124838b32a1df58c5ac7 100644 ---- a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java -+++ b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java -@@ -32,7 +32,9 @@ public interface CommandMinecart extends Minecart { - * same as setting it to "@". - * - * @param name New name for this CommandMinecart. -+ * @deprecated in favour of {@link #customName(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setName(@Nullable String name); - - } -diff --git a/src/main/java/org/bukkit/event/block/SignChangeEvent.java b/src/main/java/org/bukkit/event/block/SignChangeEvent.java -index 7190db11eff7d48df8a99f405a9dbaefdfa76e3d..1268066e30ddb0cd3792ea4b3de894eb04196669 100644 ---- a/src/main/java/org/bukkit/event/block/SignChangeEvent.java -+++ b/src/main/java/org/bukkit/event/block/SignChangeEvent.java -@@ -16,12 +16,25 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); - private boolean cancel = false; - private final Player player; -- private final String[] lines; -+ // Paper start -+ private final java.util.List adventure$lines; - -+ public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player player, @NotNull final java.util.List adventure$lines) { -+ super(theBlock); -+ this.player = player; -+ this.adventure$lines = adventure$lines; -+ } -+ -+ @Deprecated // Paper end - public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player thePlayer, @NotNull final String[] theLines) { - super(theBlock); - this.player = thePlayer; -- this.lines = theLines; -+ // Paper start -+ this.adventure$lines = new java.util.ArrayList<>(); -+ for (String theLine : theLines) { -+ this.adventure$lines.add(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(theLine)); -+ } -+ // Paper end - } - - /** -@@ -34,14 +47,52 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { - return player; - } - -+ // Paper start -+ /** -+ * Gets all of the lines of text from the sign involved in this event. -+ * -+ * @return the String array for the sign's lines new text -+ */ -+ public @NotNull java.util.List lines() { -+ return this.adventure$lines; -+ } -+ -+ /** -+ * Gets a single line of text from the sign involved in this event. -+ * -+ * @param index index of the line to get -+ * @return the String containing the line of text associated with the -+ * provided index -+ * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 -+ * or < 0} -+ */ -+ public @Nullable net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException { -+ return this.adventure$lines.get(index); -+ } -+ -+ /** -+ * Sets a single line for the sign involved in this event -+ * -+ * @param index index of the line to set -+ * @param line text to set -+ * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 -+ * or < 0} -+ */ -+ public void line(int index, @Nullable net.kyori.adventure.text.Component line) throws IndexOutOfBoundsException { -+ this.adventure$lines.set(index, line); -+ } -+ // Paper end -+ - /** - * Gets all of the lines of text from the sign involved in this event. - * - * @return the String array for the sign's lines new text -+ * @deprecated in favour of {@link #lines()} - */ - @NotNull -+ @Deprecated // Paper - public String[] getLines() { -- return lines; -+ return adventure$lines.stream().map(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()::serialize).toArray(String[]::new); // Paper - } - - /** -@@ -52,10 +103,12 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { - * provided index - * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 - * or < 0} -+ * @deprecated in favour of {@link #line(int)} - */ - @Nullable -+ @Deprecated // Paper - public String getLine(int index) throws IndexOutOfBoundsException { -- return lines[index]; -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.adventure$lines.get(index)); // Paper - } - - /** -@@ -65,9 +118,11 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { - * @param line text to set - * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 - * or < 0} -+ * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setLine(int index, @Nullable String line) throws IndexOutOfBoundsException { -- lines[index] = line; -+ adventure$lines.set(index, line != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line) : null); // Paper - } - - @Override -diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -index 3c2ea8fec3a748cab7f5ad9100d12bd8213ec6c9..7941c60b0e1840785ba2b250071591bd75bc6e35 100644 ---- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -+++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -@@ -12,25 +12,48 @@ import org.jetbrains.annotations.Nullable; - public class PlayerDeathEvent extends EntityDeathEvent { - private int newExp = 0; - private String deathMessage = ""; -+ private net.kyori.adventure.text.Component adventure$deathMessage; // Paper - private int newLevel = 0; - private int newTotalExp = 0; - private boolean keepLevel = false; - private boolean keepInventory = false; -+ // Paper start -+ public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, @Nullable final net.kyori.adventure.text.Component adventure$deathMessage) { -+ this(player, drops, droppedExp, 0, adventure$deathMessage, null); -+ } -+ -+ public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, @Nullable final net.kyori.adventure.text.Component adventure$deathMessage, @Nullable String deathMessage) { -+ this(player, drops, droppedExp, newExp, 0, 0, adventure$deathMessage, deathMessage); -+ } - -+ public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final net.kyori.adventure.text.Component adventure$deathMessage, @Nullable String deathMessage) { -+ super(player, drops, droppedExp); -+ this.newExp = newExp; -+ this.newTotalExp = newTotalExp; -+ this.newLevel = newLevel; -+ this.deathMessage = deathMessage; -+ this.adventure$deathMessage = adventure$deathMessage; -+ } -+ // Paper end -+ -+ @Deprecated // Paper - public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, @Nullable final String deathMessage) { - this(player, drops, droppedExp, 0, deathMessage); - } - -+ @Deprecated // Paper - public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, @Nullable final String deathMessage) { - this(player, drops, droppedExp, newExp, 0, 0, deathMessage); - } - -+ @Deprecated // Paper - public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final String deathMessage) { - super(player, drops, droppedExp); - this.newExp = newExp; - this.newTotalExp = newTotalExp; - this.newLevel = newLevel; - this.deathMessage = deathMessage; -+ this.adventure$deathMessage = deathMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(deathMessage) : net.kyori.adventure.text.Component.empty(); // Paper - } - - @NotNull -@@ -39,25 +62,55 @@ public class PlayerDeathEvent extends EntityDeathEvent { - return (Player) entity; - } - -+ // Paper start -+ /** -+ * Set the death message that will appear to everyone on the server. -+ * -+ * @param deathMessage Message to appear to other players on the server. -+ */ -+ public void deathMessage(@Nullable net.kyori.adventure.text.Component deathMessage) { -+ this.deathMessage = null; -+ this.adventure$deathMessage = deathMessage; -+ } -+ -+ /** -+ * Get the death message that will appear to everyone on the server. -+ * -+ * @return Message to appear to other players on the server. -+ */ -+ public @Nullable net.kyori.adventure.text.Component deathMessage() { -+ return this.adventure$deathMessage; -+ } -+ // Paper end -+ - /** - * Set the death message that will appear to everyone on the server. - * - * @param deathMessage Message to appear to other players on the server. -+ * @deprecated in favour of {@link #deathMessage(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setDeathMessage(@Nullable String deathMessage) { - this.deathMessage = deathMessage; -+ this.adventure$deathMessage = deathMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(deathMessage) : net.kyori.adventure.text.Component.empty(); // Paper - } - - /** - * Get the death message that will appear to everyone on the server. - * - * @return Message to appear to other players on the server. -+ * @deprecated in favour of {@link #deathMessage()} - */ - @Nullable -+ @Deprecated // Paper - public String getDeathMessage() { -- return deathMessage; -+ return this.deathMessage != null ? this.deathMessage : (this.adventure$deathMessage != null ? getDeathMessageString(this.adventure$deathMessage) : null); // Paper - } -- -+ // Paper start //TODO: add translation API to drop String deathMessage in favor of just Adventure -+ private static String getDeathMessageString(net.kyori.adventure.text.Component component) { -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(component); -+ } -+ // Paper end - /** - * Gets how much EXP the Player should have at respawn. - *

-diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java -index 441362d2fbdc9413ed64a1f00b50fb6d06327e79..e1e7f45fd0f65d0874dd0698da436c7ac2e7951b 100644 ---- a/src/main/java/org/bukkit/event/inventory/InventoryType.java -+++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java -@@ -140,6 +140,18 @@ public enum InventoryType { - private final String title; - private final boolean isCreatable; - -+ // Paper start -+ private final net.kyori.adventure.text.Component defaultTitleComponent; -+ -+ /** -+ * Gets the inventory's default title. -+ * -+ * @return the inventory's default title -+ */ -+ public @NotNull net.kyori.adventure.text.Component defaultTitle() { -+ return defaultTitleComponent; -+ } -+ // Paper end - private InventoryType(int defaultSize, /*@NotNull*/ String defaultTitle) { - this(defaultSize, defaultTitle, true); - } -@@ -148,6 +160,7 @@ public enum InventoryType { - size = defaultSize; - title = defaultTitle; - this.isCreatable = isCreatable; -+ this.defaultTitleComponent = net.kyori.adventure.text.Component.text(defaultTitle); // Paper - Adventure - } - - public int getDefaultSize() { -@@ -155,6 +168,7 @@ public enum InventoryType { - } - - @NotNull -+ @Deprecated // Paper - public String getDefaultTitle() { - return title; - } -diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java -index 9c68c3f2d61500479f48b80264f625aaae2f3204..399afcd19fcb6acd24857ed6ab48cf0d105a01a3 100644 ---- a/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java -+++ b/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java -@@ -22,7 +22,11 @@ import org.jetbrains.annotations.NotNull; - *

- * Care should be taken to check {@link #isAsynchronous()} and treat the event - * appropriately. -+ * -+ * @deprecated use {@link io.papermc.paper.event.player.AsyncChatEvent} instead - */ -+@Deprecated // Paper -+@org.bukkit.Warning(value = false, reason = "Don't nag on old event yet") // Paper - public class AsyncPlayerChatEvent extends PlayerEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); - private boolean cancel = false; -diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -index 9866c07c999f46cb585709804aaad710c3031d5a..c7c45e2de8cca1bf8b8e12752e08db62403efa6a 100644 ---- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -+++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -@@ -14,7 +14,7 @@ import org.jetbrains.annotations.NotNull; - public class AsyncPlayerPreLoginEvent extends Event { - private static final HandlerList handlers = new HandlerList(); - private Result result; -- private String message; -+ private net.kyori.adventure.text.Component message; // Paper - private final String name; - private final InetAddress ipAddress; - private final UUID uniqueId; -@@ -27,7 +27,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId) { - super(true); - this.result = Result.ALLOWED; -- this.message = ""; -+ this.message = net.kyori.adventure.text.Component.empty(); // Paper - this.name = name; - this.ipAddress = ipAddress; - this.uniqueId = uniqueId; -@@ -79,6 +79,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - this.result = result == null ? null : Result.valueOf(result.name()); - } - -+ // Paper start - /** - * Gets the current kick message that will be used if getResult() != - * Result.ALLOWED -@@ -86,7 +87,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - * @return Current kick message - */ - @NotNull -- public String getKickMessage() { -+ public net.kyori.adventure.text.Component kickMessage() { - return message; - } - -@@ -95,16 +96,66 @@ public class AsyncPlayerPreLoginEvent extends Event { - * - * @param message New kick message - */ -- public void setKickMessage(@NotNull final String message) { -+ public void kickMessage(@NotNull final net.kyori.adventure.text.Component message) { -+ this.message = message; -+ } -+ -+ /** -+ * Disallows the player from logging in, with the given reason -+ * -+ * @param result New result for disallowing the player -+ * @param message Kick message to display to the user -+ */ -+ public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { -+ this.result = result; - this.message = message; - } - -+ /** -+ * Disallows the player from logging in, with the given reason -+ * -+ * @param result New result for disallowing the player -+ * @param message Kick message to display to the user -+ * @deprecated This method uses a deprecated enum from {@link -+ * PlayerPreLoginEvent} -+ * @see #disallow(Result, String) -+ */ -+ @Deprecated -+ public void disallow(@NotNull final PlayerPreLoginEvent.Result result, @NotNull final net.kyori.adventure.text.Component message) { -+ this.result = result == null ? null : Result.valueOf(result.name()); -+ this.message = message; -+ } -+ // Paper end -+ /** -+ * Gets the current kick message that will be used if getResult() != -+ * Result.ALLOWED -+ * -+ * @return Current kick message -+ * @deprecated in favour of {@link #kickMessage()} -+ */ -+ @NotNull -+ @Deprecated // Paper -+ public String getKickMessage() { -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper -+ } -+ -+ /** -+ * Sets the kick message to display if getResult() != Result.ALLOWED -+ * -+ * @param message New kick message -+ * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} -+ */ -+ @Deprecated // Paper -+ public void setKickMessage(@NotNull final String message) { -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper -+ } -+ - /** - * Allows the player to log in - */ - public void allow() { - result = Result.ALLOWED; -- message = ""; -+ message = net.kyori.adventure.text.Component.empty(); // Paper - } - - /** -@@ -112,10 +163,12 @@ public class AsyncPlayerPreLoginEvent extends Event { - * - * @param result New result for disallowing the player - * @param message Kick message to display to the user -+ * @deprecated in favour of {@link #disallow(org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void disallow(@NotNull final Result result, @NotNull final String message) { - this.result = result; -- this.message = message; -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper - } - - /** -@@ -130,7 +183,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - @Deprecated - public void disallow(@NotNull final PlayerPreLoginEvent.Result result, @NotNull final String message) { - this.result = result == null ? null : Result.valueOf(result.name()); -- this.message = message; -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper - } - - /** -diff --git a/src/main/java/org/bukkit/event/player/PlayerChatEvent.java b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java -index a1f4261eaa1497554f1e51d1d5a072c2eb9226df..3a1da86e3dbf18c6e1040086c1df4b8976bc2b9d 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerChatEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java -@@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull; - * Listening to this event forces chat to wait for the main thread which - * causes delays for chat. {@link AsyncPlayerChatEvent} is the encouraged - * alternative for thread safe implementations. -+ * @deprecated use {@link io.papermc.paper.event.player.ChatEvent} instead - */ - @Deprecated - @Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.") -diff --git a/src/main/java/org/bukkit/event/player/PlayerEvent.java b/src/main/java/org/bukkit/event/player/PlayerEvent.java -index 793b661b6d2d05de3d7f4fc26a4c018a2af58e62..f6d3b817de3001f04ea4554c7c39a1290af3fd6d 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerEvent.java -@@ -14,7 +14,7 @@ public abstract class PlayerEvent extends Event { - player = who; - } - -- PlayerEvent(@NotNull final Player who, boolean async) { -+ public PlayerEvent(@NotNull final Player who, boolean async) { // Paper - public - super(async); - player = who; - -diff --git a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java -index d06684aba7688ce06777dbd837a46856a9d7767f..4af1d064fcb57773dfa8f6ad40d6482973f8e1a8 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java -@@ -10,30 +10,60 @@ import org.jetbrains.annotations.Nullable; - */ - public class PlayerJoinEvent extends PlayerEvent { - private static final HandlerList handlers = new HandlerList(); -- private String joinMessage; -+ // Paper start -+ private net.kyori.adventure.text.Component joinMessage; -+ public PlayerJoinEvent(@NotNull final Player playerJoined, @Nullable final net.kyori.adventure.text.Component joinMessage) { -+ super(playerJoined); -+ this.joinMessage = joinMessage; -+ } - -+ @Deprecated // Paper end - public PlayerJoinEvent(@NotNull final Player playerJoined, @Nullable final String joinMessage) { - super(playerJoined); -+ this.joinMessage = joinMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(joinMessage) : null; // Paper end -+ } -+ -+ // Paper start -+ /** -+ * Gets the join message to send to all online players -+ * -+ * @return string join message. Can be null -+ */ -+ public @Nullable net.kyori.adventure.text.Component joinMessage() { -+ return this.joinMessage; -+ } -+ -+ /** -+ * Sets the join message to send to all online players -+ * -+ * @param joinMessage join message. If null, no message will be sent -+ */ -+ public void joinMessage(@Nullable net.kyori.adventure.text.Component joinMessage) { - this.joinMessage = joinMessage; - } -+ // Paper end - - /** - * Gets the join message to send to all online players - * - * @return string join message. Can be null -+ * @deprecated in favour of {@link #joinMessage()} - */ - @Nullable -+ @Deprecated // Paper - public String getJoinMessage() { -- return joinMessage; -+ return this.joinMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.joinMessage); // Paper - } - - /** - * Sets the join message to send to all online players - * - * @param joinMessage join message. If null, no message will be sent -+ * @deprecated in favour of {@link #joinMessage(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setJoinMessage(@Nullable String joinMessage) { -- this.joinMessage = joinMessage; -+ this.joinMessage = joinMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(joinMessage) : null; // Paper - } - - @NotNull -diff --git a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java -index 2f6ca42330675733b2b4132cbb66e433788d05d5..efbf4b657c99ce3a5096d041d275af9ccaea7911 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java -@@ -10,35 +10,84 @@ import org.jetbrains.annotations.NotNull; - */ - public class PlayerKickEvent extends PlayerEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); -- private String leaveMessage; -- private String kickReason; -+ private net.kyori.adventure.text.Component leaveMessage; // Paper -+ private net.kyori.adventure.text.Component kickReason; // Paper - private boolean cancel; - -+ @Deprecated // Paper - public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final String kickReason, @NotNull final String leaveMessage) { -+ super(playerKicked); -+ this.kickReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(kickReason); // Paper -+ this.leaveMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(leaveMessage); // Paper -+ this.cancel = false; -+ } -+ // Paper start -+ public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final net.kyori.adventure.text.Component kickReason, @NotNull final net.kyori.adventure.text.Component leaveMessage) { - super(playerKicked); - this.kickReason = kickReason; - this.leaveMessage = leaveMessage; - this.cancel = false; - } - -+ /** -+ * Gets the leave message send to all online players -+ * -+ * @return string kick reason -+ */ -+ public @NotNull net.kyori.adventure.text.Component leaveMessage() { -+ return this.leaveMessage; -+ } -+ -+ /** -+ * Sets the leave message send to all online players -+ * -+ * @param leaveMessage leave message -+ */ -+ public void leaveMessage(@NotNull net.kyori.adventure.text.Component leaveMessage) { -+ this.leaveMessage = leaveMessage; -+ } -+ - /** - * Gets the reason why the player is getting kicked - * - * @return string kick reason - */ -+ public @NotNull net.kyori.adventure.text.Component reason() { -+ return this.kickReason; -+ } -+ -+ /** -+ * Sets the reason why the player is getting kicked -+ * -+ * @param kickReason kick reason -+ */ -+ public void reason(@NotNull net.kyori.adventure.text.Component kickReason) { -+ this.kickReason = kickReason; -+ } -+ // Paper end -+ -+ /** -+ * Gets the reason why the player is getting kicked -+ * -+ * @return string kick reason -+ * @deprecated in favour of {@link #reason()} -+ */ - @NotNull -+ @Deprecated // Paper - public String getReason() { -- return kickReason; -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.kickReason); // Paper - } - - /** - * Gets the leave message send to all online players - * - * @return string kick reason -+ * @deprecated in favour of {@link #leaveMessage()} - */ - @NotNull -+ @Deprecated // Paper - public String getLeaveMessage() { -- return leaveMessage; -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.leaveMessage); // Paper - } - - @Override -@@ -55,18 +104,22 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { - * Sets the reason why the player is getting kicked - * - * @param kickReason kick reason -+ * @deprecated in favour of {@link #reason(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setReason(@NotNull String kickReason) { -- this.kickReason = kickReason; -+ this.kickReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(kickReason); // Paper - } - - /** - * Sets the leave message send to all online players - * - * @param leaveMessage leave message -+ * @deprecated in favour of {@link #leaveMessage(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setLeaveMessage(@NotNull String leaveMessage) { -- this.leaveMessage = leaveMessage; -+ this.leaveMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(leaveMessage); // Paper - } - - @NotNull -diff --git a/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java b/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java -index 36b436e145a7215682b692a87ab894df25752c1d..ebd499c1a2d11ea068e8c374edbc3967e4cece3d 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java -@@ -12,17 +12,31 @@ public class PlayerLocaleChangeEvent extends PlayerEvent { - private static final HandlerList handlers = new HandlerList(); - // - private final String locale; -+ // Paper start -+ private final java.util.Locale adventure$locale; -+ /** -+ * @see Player#getLocale() -+ * -+ * @return the player's new locale -+ */ -+ public @NotNull java.util.Locale locale() { -+ return this.adventure$locale; -+ } -+ // Paper end - - public PlayerLocaleChangeEvent(@NotNull Player who, @NotNull String locale) { - super(who); - this.locale = locale; -+ this.adventure$locale = net.kyori.adventure.translation.Translator.parseLocale(locale); // Paper - } - - /** - * @return the player's new locale - * @see Player#getLocale() -+ * @deprecated in favour of {@link #locale()} - */ - @NotNull -+ @Deprecated // Paper - public String getLocale() { - return locale; - } -diff --git a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java -index 084ca8cfcb7381bfa4fa6280748cf9b81210a9c1..95c53d934f928d25f7b20cfbf2e5faa3df31ddc4 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java -@@ -17,7 +17,7 @@ public class PlayerLoginEvent extends PlayerEvent { - private final InetAddress address; - private final String hostname; - private Result result = Result.ALLOWED; -- private String message = ""; -+ private net.kyori.adventure.text.Component message = net.kyori.adventure.text.Component.empty(); - private final InetAddress realAddress; // Spigot - - /** -@@ -53,12 +53,52 @@ public class PlayerLoginEvent extends PlayerEvent { - * @param result The result status for this event - * @param message The message to be displayed if result denies login - * @param realAddress the actual, unspoofed connecting address -+ * @deprecated in favour of {@link #PlayerLoginEvent(Player, String, InetAddress, Result, net.kyori.adventure.text.Component, InetAddress)} - */ -+ @Deprecated // Paper - public PlayerLoginEvent(@NotNull final Player player, @NotNull String hostname, @NotNull final InetAddress address, @NotNull final Result result, @NotNull final String message, @NotNull final InetAddress realAddress) { // Spigot - this(player, hostname, address, realAddress); // Spigot - this.result = result; -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper -+ } -+ -+ // Paper start -+ /** -+ * This constructor pre-configures the event with a result and message -+ * -+ * @param player The {@link Player} for this event -+ * @param hostname The hostname that was used to connect to the server -+ * @param address The address the player used to connect, provided for -+ * timing issues -+ * @param result The result status for this event -+ * @param message The message to be displayed if result denies login -+ * @param realAddress the actual, unspoofed connecting address -+ */ -+ public PlayerLoginEvent(@NotNull final Player player, @NotNull String hostname, @NotNull final InetAddress address, @NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message, @NotNull final InetAddress realAddress) { // Spigot -+ this(player, hostname, address, realAddress); // Spigot -+ this.result = result; -+ this.message = message; -+ } -+ -+ /** -+ * Gets the current kick message that will be used if getResult() != -+ * Result.ALLOWED -+ * -+ * @return Current kick message -+ */ -+ public @NotNull net.kyori.adventure.text.Component kickMessage() { -+ return this.message; -+ } -+ -+ /** -+ * Sets the kick message to display if getResult() != Result.ALLOWED -+ * -+ * @param message New kick message -+ */ -+ public void kickMessage(@NotNull net.kyori.adventure.text.Component message) { - this.message = message; - } -+ // Paper end - - // Spigot start - /** -@@ -96,19 +136,23 @@ public class PlayerLoginEvent extends PlayerEvent { - * Result.ALLOWED - * - * @return Current kick message -+ * @deprecated in favour of {@link #kickMessage()} - */ - @NotNull -+ @Deprecated // Paper - public String getKickMessage() { -- return message; -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper - } - - /** - * Sets the kick message to display if getResult() != Result.ALLOWED - * - * @param message New kick message -+ * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setKickMessage(@NotNull final String message) { -- this.message = message; -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper - } - - /** -@@ -127,7 +171,7 @@ public class PlayerLoginEvent extends PlayerEvent { - */ - public void allow() { - result = Result.ALLOWED; -- message = ""; -+ message = net.kyori.adventure.text.Component.empty(); // Paper - } - - /** -@@ -135,8 +179,21 @@ public class PlayerLoginEvent extends PlayerEvent { - * - * @param result New result for disallowing the player - * @param message Kick message to display to the user -+ * @deprecated in favour of {@link #disallow(Result, net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper start - public void disallow(@NotNull final Result result, @NotNull final String message) { -+ this.result = result; -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); -+ } -+ /** -+ * Disallows the player from logging in, with the given reason -+ * -+ * @param result New result for disallowing the player -+ * @param message Kick message to display to the user -+ */ -+ public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { -+ // Paper end - this.result = result; - this.message = message; - } -diff --git a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java -index fb066251f793ec3b41bfc075b9478901b15ee549..6800132c6288b4588fd02b08d26f016c38f27129 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java -@@ -19,7 +19,7 @@ import org.jetbrains.annotations.NotNull; - public class PlayerPreLoginEvent extends Event { - private static final HandlerList handlers = new HandlerList(); - private Result result; -- private String message; -+ private net.kyori.adventure.text.Component message; // Paper - private final String name; - private final InetAddress ipAddress; - private final UUID uniqueId; -@@ -31,7 +31,7 @@ public class PlayerPreLoginEvent extends Event { - - public PlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId) { - this.result = Result.ALLOWED; -- this.message = ""; -+ this.message = net.kyori.adventure.text.Component.empty(); // Paper - this.name = name; - this.ipAddress = ipAddress; - this.uniqueId = uniqueId; -@@ -56,6 +56,7 @@ public class PlayerPreLoginEvent extends Event { - this.result = result; - } - -+ // Paper start - /** - * Gets the current kick message that will be used if getResult() != - * Result.ALLOWED -@@ -63,7 +64,7 @@ public class PlayerPreLoginEvent extends Event { - * @return Current kick message - */ - @NotNull -- public String getKickMessage() { -+ public net.kyori.adventure.text.Component kickMessage() { - return message; - } - -@@ -72,16 +73,51 @@ public class PlayerPreLoginEvent extends Event { - * - * @param message New kick message - */ -- public void setKickMessage(@NotNull final String message) { -+ public void kickMessage(@NotNull final net.kyori.adventure.text.Component message) { - this.message = message; - } - -+ /** -+ * Disallows the player from logging in, with the given reason -+ * -+ * @param result New result for disallowing the player -+ * @param message Kick message to display to the user -+ */ -+ public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { -+ this.result = result; -+ this.message = message; -+ } -+ // Paper end -+ /** -+ * Gets the current kick message that will be used if getResult() != -+ * Result.ALLOWED -+ * -+ * @return Current kick message -+ * @deprecated in favour of {@link #kickMessage()} -+ */ -+ @Deprecated // Paper -+ @NotNull -+ public String getKickMessage() { -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper -+ } -+ -+ /** -+ * Sets the kick message to display if getResult() != Result.ALLOWED -+ * -+ * @param message New kick message -+ * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} -+ */ -+ @Deprecated // Paper -+ public void setKickMessage(@NotNull final String message) { -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper -+ } -+ - /** - * Allows the player to log in - */ - public void allow() { - result = Result.ALLOWED; -- message = ""; -+ message = net.kyori.adventure.text.Component.empty(); // Paper - } - - /** -@@ -89,10 +125,12 @@ public class PlayerPreLoginEvent extends Event { - * - * @param result New result for disallowing the player - * @param message Kick message to display to the user -+ * @deprecated in favour of {@link #disallow(org.bukkit.event.player.PlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void disallow(@NotNull final Result result, @NotNull final String message) { - this.result = result; -- this.message = message; -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper - } - - /** -diff --git a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java -index d70c25f404e994766a9ebce89a917c8d0719777c..0395ca85a466f6356259078d3bad48b2ce6e57b7 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java -@@ -10,30 +10,59 @@ import org.jetbrains.annotations.Nullable; - */ - public class PlayerQuitEvent extends PlayerEvent { - private static final HandlerList handlers = new HandlerList(); -- private String quitMessage; -+ private net.kyori.adventure.text.Component quitMessage; // Paper - -+ @Deprecated // Paper - public PlayerQuitEvent(@NotNull final Player who, @Nullable final String quitMessage) { - super(who); -+ this.quitMessage = quitMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(quitMessage) : null; // Paper -+ } -+ // Paper start -+ public PlayerQuitEvent(@NotNull final Player who, @Nullable final net.kyori.adventure.text.Component quitMessage) { -+ super(who); -+ this.quitMessage = quitMessage; -+ } -+ -+ /** -+ * Gets the quit message to send to all online players -+ * -+ * @return string quit message -+ */ -+ public @Nullable net.kyori.adventure.text.Component quitMessage() { -+ return quitMessage; -+ } -+ -+ /** -+ * Sets the quit message to send to all online players -+ * -+ * @param quitMessage quit message -+ */ -+ public void quitMessage(@Nullable net.kyori.adventure.text.Component quitMessage) { - this.quitMessage = quitMessage; - } -+ // Paper end - - /** - * Gets the quit message to send to all online players - * - * @return string quit message -+ * @deprecated in favour of {@link #quitMessage()} - */ - @Nullable -+ @Deprecated // Paper - public String getQuitMessage() { -- return quitMessage; -+ return this.quitMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.quitMessage); // Paper - } - - /** - * Sets the quit message to send to all online players - * - * @param quitMessage quit message -+ * @deprecated in favour of {@link #quitMessage(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setQuitMessage(@Nullable String quitMessage) { -- this.quitMessage = quitMessage; -+ this.quitMessage = quitMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(quitMessage) : null; // Paper - } - - @NotNull -diff --git a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java b/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java -index 03bfca9d368bbe4b7c1353d52c883e756bf69bda..943d324435350d3f16fad3e21cb472a01a3ff60b 100644 ---- a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java -+++ b/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java -@@ -18,7 +18,7 @@ import org.jetbrains.annotations.NotNull; - public class BroadcastMessageEvent extends ServerEvent implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); -- private String message; -+ private net.kyori.adventure.text.Component message; // Paper - private final Set recipients; - private boolean cancelled = false; - -@@ -27,29 +27,66 @@ public class BroadcastMessageEvent extends ServerEvent implements Cancellable { - this(false, message, recipients); - } - -+ @Deprecated // Paper - public BroadcastMessageEvent(boolean isAsync, @NotNull String message, @NotNull Set recipients) { -+ // Paper start -+ super(isAsync); -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); -+ this.recipients = recipients; -+ } -+ -+ @Deprecated -+ public BroadcastMessageEvent(@NotNull net.kyori.adventure.text.Component message, @NotNull Set recipients) { -+ this(false, message, recipients); -+ } -+ -+ public BroadcastMessageEvent(boolean isAsync, @NotNull net.kyori.adventure.text.Component message, @NotNull Set recipients) { -+ // Paper end - super(isAsync); - this.message = message; - this.recipients = recipients; - } -+ // Paper start -+ /** -+ * Get the broadcast message. -+ * -+ * @return Message to broadcast -+ */ -+ public @NotNull net.kyori.adventure.text.Component message() { -+ return this.message; -+ } -+ -+ /** -+ * Set the broadcast message. -+ * -+ * @param message New message to broadcast -+ */ -+ public void message(@NotNull net.kyori.adventure.text.Component message) { -+ this.message = message; -+ } -+ // Paper end - - /** - * Get the message to broadcast. - * - * @return Message to broadcast -+ * @deprecated in favour of {@link #message()} - */ - @NotNull -+ @Deprecated // Paper - public String getMessage() { -- return message; -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper - } - - /** - * Set the message to broadcast. - * - * @param message New message to broadcast -+ * @deprecated in favour of {@link #message(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setMessage(@NotNull String message) { -- this.message = message; -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper - } - - /** -diff --git a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java -index 92941af574945936c3714718ed3eea23697c99df..5b8a7b897d9f9d8df3705eef36388f41be4531a6 100644 ---- a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java -+++ b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java -@@ -22,15 +22,16 @@ public class ServerListPingEvent extends ServerEvent implements Iterable - private static final HandlerList handlers = new HandlerList(); - private final InetAddress address; - private final boolean shouldSendChatPreviews; -- private String motd; -+ private net.kyori.adventure.text.Component motd; // Paper - private final int numPlayers; - private int maxPlayers; - -+ @Deprecated // Paper - public ServerListPingEvent(@NotNull final InetAddress address, @NotNull final String motd, final boolean shouldSendChatPreviews, final int numPlayers, final int maxPlayers) { - super(true); - Preconditions.checkArgument(numPlayers >= 0, "Cannot have negative number of players online", numPlayers); - this.address = address; -- this.motd = motd; -+ this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper - this.shouldSendChatPreviews = shouldSendChatPreviews; - this.numPlayers = numPlayers; - this.maxPlayers = maxPlayers; -@@ -45,15 +46,61 @@ public class ServerListPingEvent extends ServerEvent implements Iterable - * @param motd the message of the day - * @param shouldSendChatPreviews if the server should send chat previews - * @param maxPlayers the max number of players -+ * @deprecated in favour of {@link #ServerListPingEvent(java.net.InetAddress, net.kyori.adventure.text.Component, boolean, int)} - */ -+ @Deprecated // Paper - protected ServerListPingEvent(@NotNull final InetAddress address, @NotNull final String motd, boolean shouldSendChatPreviews, final int maxPlayers) { - super(true); - this.numPlayers = MAGIC_PLAYER_COUNT; - this.address = address; -+ this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper -+ this.shouldSendChatPreviews = shouldSendChatPreviews; -+ this.maxPlayers = maxPlayers; -+ } -+ // Paper start -+ public ServerListPingEvent(@NotNull final InetAddress address, @NotNull final net.kyori.adventure.text.Component motd, boolean shouldSendChatPreviews, final int numPlayers, final int maxPlayers) { -+ super(true); -+ Preconditions.checkArgument(numPlayers >= 0, "Cannot have negative number of players online (%s)", numPlayers); -+ this.address = address; - this.motd = motd; - this.shouldSendChatPreviews = shouldSendChatPreviews; -+ this.numPlayers = numPlayers; - this.maxPlayers = maxPlayers; - } -+ /** -+ * This constructor is intended for implementations that provide the -+ * {@link #iterator()} method, thus provided the {@link #getNumPlayers()} -+ * count. -+ * -+ * @param address the address of the pinger -+ * @param motd the message of the day -+ * @param maxPlayers the max number of players -+ */ -+ protected ServerListPingEvent(@NotNull final InetAddress address, @NotNull final net.kyori.adventure.text.Component motd, boolean shouldSendChatPreviews, final int maxPlayers) { -+ super(true); -+ this.numPlayers = MAGIC_PLAYER_COUNT; -+ this.address = address; -+ this.motd = motd; -+ this.shouldSendChatPreviews = shouldSendChatPreviews; -+ this.maxPlayers = maxPlayers; -+ } -+ /** -+ * Get the message of the day message. -+ * -+ * @return the message of the day -+ */ -+ public @NotNull net.kyori.adventure.text.Component motd() { -+ return motd; -+ } -+ /** -+ * Change the message of the day message. -+ * -+ * @param motd the message of the day -+ */ -+ public void motd(@NotNull net.kyori.adventure.text.Component motd) { -+ this.motd = motd; -+ } -+ // Paper end - - /** - * Get the address the ping is coming from. -@@ -69,19 +116,23 @@ public class ServerListPingEvent extends ServerEvent implements Iterable - * Get the message of the day message. - * - * @return the message of the day -+ * @deprecated in favour of {@link #motd()} - */ - @NotNull -+ @Deprecated // Paper - public String getMotd() { -- return motd; -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.motd); // Paper - } - - /** - * Change the message of the day message. - * - * @param motd the message of the day -+ * @deprecated in favour of {@link #motd(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setMotd(@NotNull String motd) { -- this.motd = motd; -+ this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper - } - - /** -diff --git a/src/main/java/org/bukkit/inventory/InventoryView.java b/src/main/java/org/bukkit/inventory/InventoryView.java -index 14346d83bc99581b18e53d19af03708c0bf22cf7..a4e3d526db2d17dc923cbe82e53d3c902d61e1f3 100644 ---- a/src/main/java/org/bukkit/inventory/InventoryView.java -+++ b/src/main/java/org/bukkit/inventory/InventoryView.java -@@ -446,11 +446,25 @@ public abstract class InventoryView { - return getPlayer().setWindowProperty(prop, value); - } - -+ // Paper start - /** - * Get the title of this inventory window. - * - * @return The title. - */ - @NotNull -+ public /*abstract*/ net.kyori.adventure.text.Component title() { -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(this.getTitle()); -+ } -+ // Paper end -+ -+ /** -+ * Get the title of this inventory window. -+ * -+ * @return The title. -+ * @deprecated in favour of {@link #title()} -+ */ -+ @Deprecated // Paper -+ @NotNull - public abstract String getTitle(); - } -diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java -index f89d71b77d1200314df6ca23614d5ca6fb15ceb3..af4a7ce37eb10bab06eadb6583c7894b3ec55ae6 100644 ---- a/src/main/java/org/bukkit/inventory/ItemFactory.java -+++ b/src/main/java/org/bukkit/inventory/ItemFactory.java -@@ -159,4 +159,24 @@ public interface ItemFactory { - @Deprecated - @NotNull - Material updateMaterial(@NotNull final ItemMeta meta, @NotNull final Material material) throws IllegalArgumentException; -+ -+ // Paper start -+ /** -+ * Creates a hover event for the given item. -+ * -+ * @param item The item -+ * @return A hover event -+ */ -+ @NotNull -+ net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull ItemStack item, final @NotNull java.util.function.UnaryOperator op); -+ -+ /** -+ * Get the formatted display name of the {@link ItemStack}. -+ * -+ * @param itemStack the {@link ItemStack} -+ * @return display name of the {@link ItemStack} -+ */ -+ @NotNull -+ net.kyori.adventure.text.Component displayName(@NotNull ItemStack itemStack); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 7b904dd2c0a660df8874d4800919e16981877163..d168a836d655b369f67200d7afe101b56ff815b1 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -22,7 +22,7 @@ import org.jetbrains.annotations.Nullable; - * use this class to encapsulate Materials for which {@link Material#isItem()} - * returns false. - */ --public class ItemStack implements Cloneable, ConfigurationSerializable { -+public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyori.adventure.text.event.HoverEventSource { // Paper - private Material type = Material.AIR; - private int amount = 0; - private MaterialData data = null; -@@ -595,4 +595,21 @@ public class ItemStack implements Cloneable, ConfigurationSerializable { - - return true; - } -+ -+ // Paper start -+ @NotNull -+ @Override -+ public net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { -+ return org.bukkit.Bukkit.getServer().getItemFactory().asHoverEvent(this, op); -+ } -+ -+ /** -+ * Get the formatted display name of the {@link ItemStack}. -+ * -+ * @return display name of the {@link ItemStack} -+ */ -+ public @NotNull net.kyori.adventure.text.Component displayName() { -+ return Bukkit.getServer().getItemFactory().displayName(this); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/inventory/meta/BookMeta.java b/src/main/java/org/bukkit/inventory/meta/BookMeta.java -index 94852d50e88d0594b84b581cd627174043629995..36bcbb3f3acedf7ebecbf6f6b358cf64af0edfb2 100644 ---- a/src/main/java/org/bukkit/inventory/meta/BookMeta.java -+++ b/src/main/java/org/bukkit/inventory/meta/BookMeta.java -@@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable; - * Represents a book ({@link Material#WRITABLE_BOOK} or {@link - * Material#WRITTEN_BOOK}) that can have a title, an author, and pages. - */ --public interface BookMeta extends ItemMeta { -+public interface BookMeta extends ItemMeta, net.kyori.adventure.inventory.Book { // Paper - - /** - * Represents the generation (or level of copying) of a written book -@@ -119,6 +119,118 @@ public interface BookMeta extends ItemMeta { - */ - boolean hasPages(); - -+ // Paper start -+ /** -+ * Gets the title of the book. -+ *

-+ * Plugins should check that hasTitle() returns true before calling this -+ * method. -+ * -+ * @return the title of the book -+ */ -+ @Nullable -+ @Override -+ net.kyori.adventure.text.Component title(); -+ -+ /** -+ * Sets the title of the book. -+ *

-+ * Limited to 32 characters. Removes title when given null. -+ * -+ * @param title the title to set -+ * @return the same {@link BookMeta} instance -+ */ -+ @NotNull -+ @Override -+ @org.checkerframework.common.returnsreceiver.qual.This BookMeta title(@Nullable net.kyori.adventure.text.Component title); -+ -+ /** -+ * Gets the author of the book. -+ *

-+ * Plugins should check that hasAuthor() returns true before calling this -+ * method. -+ * -+ * @return the author of the book -+ */ -+ @Nullable -+ @Override -+ net.kyori.adventure.text.Component author(); -+ -+ /** -+ * Sets the author of the book. Removes author when given null. -+ * -+ * @param author the author to set -+ * @return the same {@link BookMeta} instance -+ */ -+ @NotNull -+ @Override -+ @org.checkerframework.common.returnsreceiver.qual.This BookMeta author(@Nullable net.kyori.adventure.text.Component author); -+ -+ /** -+ * Gets the specified page in the book. The page must exist. -+ *

-+ * Pages are 1-indexed. -+ * -+ * @param page the page number to get, in range [1, getPageCount()] -+ * @return the page from the book -+ */ -+ @NotNull net.kyori.adventure.text.Component page(int page); -+ -+ /** -+ * Sets the specified page in the book. Pages of the book must be -+ * contiguous. -+ *

-+ * The data can be up to 256 characters in length, additional characters -+ * are truncated. -+ *

-+ * Pages are 1-indexed. -+ * -+ * @param page the page number to set, in range [1, getPageCount()] -+ * @param data the data to set for that page -+ */ -+ void page(int page, @NotNull net.kyori.adventure.text.Component data); -+ -+ /** -+ * Adds new pages to the end of the book. Up to a maximum of 50 pages with -+ * 256 characters per page. -+ * -+ * @param pages A list of strings, each being a page -+ */ -+ void addPages(@NotNull net.kyori.adventure.text.Component... pages); -+ -+ interface BookMetaBuilder extends Builder { -+ -+ @NotNull -+ @Override -+ BookMetaBuilder title(@Nullable net.kyori.adventure.text.Component title); -+ -+ @NotNull -+ @Override -+ BookMetaBuilder author(@Nullable net.kyori.adventure.text.Component author); -+ -+ @NotNull -+ @Override -+ BookMetaBuilder addPage(@NotNull net.kyori.adventure.text.Component page); -+ -+ @NotNull -+ @Override -+ BookMetaBuilder pages(@NotNull net.kyori.adventure.text.Component... pages); -+ -+ @NotNull -+ @Override -+ BookMetaBuilder pages(@NotNull java.util.Collection pages); -+ -+ @NotNull -+ @Override -+ BookMeta build(); -+ } -+ -+ @Override -+ @org.checkerframework.checker.nullness.qual.NonNull -+ BookMetaBuilder toBuilder(); -+ -+ // Paper end -+ - /** - * Gets the specified page in the book. The given page must exist. - *

-@@ -126,8 +238,10 @@ public interface BookMeta extends ItemMeta { - * - * @param page the page number to get, in range [1, getPageCount()] - * @return the page from the book -+ * @deprecated in favour of {@link #page(int)} - */ - @NotNull -+ @Deprecated // Paper - String getPage(int page); - - /** -@@ -141,15 +255,19 @@ public interface BookMeta extends ItemMeta { - * - * @param page the page number to set, in range [1, getPageCount()] - * @param data the data to set for that page -+ * @deprecated in favour of {@link #page(int, net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - void setPage(int page, @NotNull String data); - - /** - * Gets all the pages in the book. - * - * @return list of all the pages in the book -+ * @deprecated in favour of {@link #pages()} - */ - @NotNull -+ @Deprecated // Paper - List getPages(); - - /** -@@ -157,7 +275,9 @@ public interface BookMeta extends ItemMeta { - * pages. Maximum 100 pages with 256 characters per page. - * - * @param pages A list of pages to set the book to use -+ * @deprecated in favour of {@link #pages(List)} - */ -+ @Deprecated // Paper - void setPages(@NotNull List pages); - - /** -@@ -165,7 +285,9 @@ public interface BookMeta extends ItemMeta { - * pages. Maximum 50 pages with 256 characters per page. - * - * @param pages A list of strings, each being a page -+ * @deprecated in favour of {@link #pages(net.kyori.adventure.text.Component...)} - */ -+ @Deprecated // Paper - void setPages(@NotNull String... pages); - - /** -@@ -173,7 +295,9 @@ public interface BookMeta extends ItemMeta { - * 256 characters per page. - * - * @param pages A list of strings, each being a page -+ * @deprecated in favour of {@link #addPages(net.kyori.adventure.text.Component...)} - */ -+ @Deprecated // Paper - void addPage(@NotNull String... pages); - - /** -@@ -195,8 +319,10 @@ public interface BookMeta extends ItemMeta { - * - * @param page the page number to get - * @return the page from the book -+ * @deprecated in favour of {@link #page(int)} - */ - @NotNull -+ @Deprecated // Paper - public BaseComponent[] getPage(int page) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -210,7 +336,9 @@ public interface BookMeta extends ItemMeta { - * - * @param page the page number to set - * @param data the data to set for that page -+ * @deprecated in favour of {@link #page(int, net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setPage(int page, @Nullable BaseComponent... data) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -219,8 +347,10 @@ public interface BookMeta extends ItemMeta { - * Gets all the pages in the book. - * - * @return list of all the pages in the book -+ * @deprecated in favour of {@link #pages()} - */ - @NotNull -+ @Deprecated // Paper - public List getPages() { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -230,7 +360,9 @@ public interface BookMeta extends ItemMeta { - * pages. Maximum 50 pages with 256 characters per page. - * - * @param pages A list of pages to set the book to use -+ * @deprecated in favour of {@link #pages(java.util.List)} - */ -+ @Deprecated // Paper - public void setPages(@NotNull List pages) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -240,7 +372,9 @@ public interface BookMeta extends ItemMeta { - * pages. Maximum 50 pages with 256 characters per page. - * - * @param pages A list of component arrays, each being a page -+ * @deprecated in favour of {@link #pages(net.kyori.adventure.text.Component...)} - */ -+ @Deprecated // Paper - public void setPages(@NotNull BaseComponent[]... pages) { - throw new UnsupportedOperationException("Not supported yet."); - } -@@ -250,7 +384,9 @@ public interface BookMeta extends ItemMeta { - * with 256 characters per page. - * - * @param pages A list of component arrays, each being a page -+ * @deprecated in favour of {@link #addPages(net.kyori.adventure.text.Component...)} - */ -+ @Deprecated // Paper - public void addPage(@NotNull BaseComponent[]... pages) { - throw new UnsupportedOperationException("Not supported yet."); - } -diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -index 2fbb0b7640dd9b9b0e70d4bc60fbb0310d5ec250..64114b1a9e201df369fc794fbee984d496385420 100644 ---- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -+++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -@@ -31,6 +31,24 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - */ - boolean hasDisplayName(); - -+ // Paper start -+ /** -+ * Gets the display name. -+ * -+ *

Plugins should check that {@link #hasDisplayName()} returns true before calling this method.

-+ * -+ * @return the display name -+ */ -+ @Nullable net.kyori.adventure.text.Component displayName(); -+ -+ /** -+ * Sets the display name. -+ * -+ * @param displayName the display name to set -+ */ -+ void displayName(final @Nullable net.kyori.adventure.text.Component displayName); -+ // Paper end -+ - /** - * Gets the display name that is set. - *

-@@ -38,7 +56,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - * before calling this method. - * - * @return the display name that is set -+ * @deprecated in favour of {@link #displayName()} - */ -+ @Deprecated // Paper - @NotNull - String getDisplayName(); - -@@ -46,7 +66,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - * Sets the display name. - * - * @param name the name to set -+ * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - void setDisplayName(@Nullable String name); - - /** -@@ -81,6 +103,24 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - */ - boolean hasLore(); - -+ // Paper start -+ /** -+ * Gets the lore. -+ * -+ *

Plugins should check that {@link #hasLore()} returns true before calling this method.

-+ * -+ * @return the lore -+ */ -+ @Nullable List lore(); -+ -+ /** -+ * Sets the lore. -+ * -+ * @param lore the lore to set -+ */ -+ void lore(final @Nullable List lore); -+ // Paper end -+ - /** - * Gets the lore that is set. - *

-@@ -88,7 +128,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - * calling this method. - * - * @return a list of lore that is set -+ * @deprecated in favour of {@link #lore()} - */ -+ @Deprecated // Paper - @Nullable - List getLore(); - -@@ -97,7 +139,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - * Removes lore when given null. - * - * @param lore the lore that will be set -+ * @deprecated in favour of {@link #lore(List)} - */ -+ @Deprecated // Paper - void setLore(@Nullable List lore); - - /** -diff --git a/src/main/java/org/bukkit/map/MapCursor.java b/src/main/java/org/bukkit/map/MapCursor.java -index 83354b2a38b6261b172b91c1008dcf3313cc4a8f..ca763b231749f108b6773040a5c6109378b21b31 100644 ---- a/src/main/java/org/bukkit/map/MapCursor.java -+++ b/src/main/java/org/bukkit/map/MapCursor.java -@@ -10,7 +10,7 @@ public final class MapCursor { - private byte x, y; - private byte direction, type; - private boolean visible; -- private String caption; -+ private net.kyori.adventure.text.Component caption; // Paper - - /** - * Initialize the map cursor. -@@ -24,7 +24,7 @@ public final class MapCursor { - */ - @Deprecated - public MapCursor(byte x, byte y, byte direction, byte type, boolean visible) { -- this(x, y, direction, type, visible, null); -+ this(x, y, direction, type, visible, (String) null); // Paper - } - - /** -@@ -37,7 +37,7 @@ public final class MapCursor { - * @param visible Whether the cursor is visible by default. - */ - public MapCursor(byte x, byte y, byte direction, @NotNull Type type, boolean visible) { -- this(x, y, direction, type, visible, null); -+ this(x, y, direction, type, visible, (String) null); // Paper - } - - /** -@@ -49,7 +49,7 @@ public final class MapCursor { - * @param type The type (color/style) of the map cursor. - * @param visible Whether the cursor is visible by default. - * @param caption cursor caption -- * @deprecated Magic value -+ * @deprecated Magic value. Use {@link #MapCursor(byte, byte, byte, byte, boolean, net.kyori.adventure.text.Component)} - */ - @Deprecated - public MapCursor(byte x, byte y, byte direction, byte type, boolean visible, @Nullable String caption) { -@@ -58,8 +58,42 @@ public final class MapCursor { - setDirection(direction); - setRawType(type); - this.visible = visible; -- this.caption = caption; -+ this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper - } -+ // Paper start -+ /** -+ * Initialize the map cursor. -+ * -+ * @param x The x coordinate, from -128 to 127. -+ * @param y The y coordinate, from -128 to 127. -+ * @param direction The facing of the cursor, from 0 to 15. -+ * @param type The type (color/style) of the map cursor. -+ * @param visible Whether the cursor is visible by default. -+ * @param caption cursor caption -+ * @deprecated Magic value -+ */ -+ @Deprecated -+ public MapCursor(byte x, byte y, byte direction, byte type, boolean visible, @Nullable net.kyori.adventure.text.Component caption) { -+ this.x = x; this.y = y; this.visible = visible; this.caption = caption; -+ setDirection(direction); -+ setRawType(type); -+ } -+ /** -+ * Initialize the map cursor. -+ * -+ * @param x The x coordinate, from -128 to 127. -+ * @param y The y coordinate, from -128 to 127. -+ * @param direction The facing of the cursor, from 0 to 15. -+ * @param type The type (color/style) of the map cursor. -+ * @param visible Whether the cursor is visible by default. -+ * @param caption cursor caption -+ */ -+ public MapCursor(byte x, byte y, byte direction, @NotNull Type type, boolean visible, @Nullable net.kyori.adventure.text.Component caption) { -+ this.x = x; this.y = y; this.visible = visible; this.caption = caption; -+ setDirection(direction); -+ setType(type); -+ } -+ // Paper end - - /** - * Initialize the map cursor. -@@ -77,7 +111,7 @@ public final class MapCursor { - setDirection(direction); - setType(type); - this.visible = visible; -- this.caption = caption; -+ this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper - } - - /** -@@ -200,23 +234,45 @@ public final class MapCursor { - this.visible = visible; - } - -+ // Paper start -+ /** -+ * Gets the caption on this cursor. -+ * -+ * @return caption -+ */ -+ public @Nullable net.kyori.adventure.text.Component caption() { -+ return this.caption; -+ } -+ /** -+ * Sets the caption on this cursor. -+ * -+ * @param caption new caption -+ */ -+ public void caption(@Nullable net.kyori.adventure.text.Component caption) { -+ this.caption = caption; -+ } -+ // Paper end - /** - * Gets the caption on this cursor. - * - * @return caption -+ * @deprecated in favour of {@link #caption()} - */ - @Nullable -+ @Deprecated // Paper - public String getCaption() { -- return caption; -+ return this.caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.caption); // Paper - } - - /** - * Sets the caption on this cursor. - * - * @param caption new caption -+ * @deprecated in favour of {@link #caption(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - public void setCaption(@Nullable String caption) { -- this.caption = caption; -+ this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper - } - - /** -diff --git a/src/main/java/org/bukkit/map/MapCursorCollection.java b/src/main/java/org/bukkit/map/MapCursorCollection.java -index 4dba721aefe4fc6699b3b4bfa7ecb0b19c2a2a1a..01dec2c877df58c9dc22445e8b1f9ce2e53066da 100644 ---- a/src/main/java/org/bukkit/map/MapCursorCollection.java -+++ b/src/main/java/org/bukkit/map/MapCursorCollection.java -@@ -117,4 +117,22 @@ public final class MapCursorCollection { - public MapCursor addCursor(int x, int y, byte direction, byte type, boolean visible, @Nullable String caption) { - return addCursor(new MapCursor((byte) x, (byte) y, direction, type, visible, caption)); - } -+ // Paper start -+ /** -+ * Add a cursor to the collection. -+ * -+ * @param x The x coordinate, from -128 to 127. -+ * @param y The y coordinate, from -128 to 127. -+ * @param direction The facing of the cursor, from 0 to 15. -+ * @param type The type (color/style) of the map cursor. -+ * @param visible Whether the cursor is visible. -+ * @param caption banner caption -+ * @return The newly added MapCursor. -+ * @deprecated Magic value -+ */ -+ @Deprecated -+ public @NotNull MapCursor addCursor(int x, int y, byte direction, byte type, boolean visible, @Nullable net.kyori.adventure.text.Component caption) { -+ return addCursor(new MapCursor((byte) x, (byte) y, direction, type, visible, caption)); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/permissions/Permissible.java b/src/main/java/org/bukkit/permissions/Permissible.java -index 228421154913116069c20323afb519bdde2134df..26791db3c267670d5782f1d2b67ff7d5b55b9dac 100644 ---- a/src/main/java/org/bukkit/permissions/Permissible.java -+++ b/src/main/java/org/bukkit/permissions/Permissible.java -@@ -126,4 +126,34 @@ public interface Permissible extends ServerOperator { - */ - @NotNull - public Set getEffectivePermissions(); -+ -+ // Paper start - add TriState permission checks -+ /** -+ * Checks if this object has a permission set and, if it is set, the value of the permission. -+ * -+ * @param permission the permission to check -+ * @return a tri-state of if the permission is set and, if it is set, it's value -+ */ -+ default net.kyori.adventure.util.@NotNull TriState permissionValue(final @NotNull Permission permission) { -+ if (this.isPermissionSet(permission)) { -+ return net.kyori.adventure.util.TriState.byBoolean(this.hasPermission(permission)); -+ } else { -+ return net.kyori.adventure.util.TriState.NOT_SET; -+ } -+ } -+ -+ /** -+ * Checks if this object has a permission set and, if it is set, the value of the permission. -+ * -+ * @param permission the permission to check -+ * @return a tri-state of if the permission is set and, if it is set, it's value -+ */ -+ default net.kyori.adventure.util.@NotNull TriState permissionValue(final @NotNull String permission) { -+ if (this.isPermissionSet(permission)) { -+ return net.kyori.adventure.util.TriState.byBoolean(this.hasPermission(permission)); -+ } else { -+ return net.kyori.adventure.util.TriState.NOT_SET; -+ } -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java -index 03ca87a1cbace2459174bb7bb8847bda766e80c5..b37938745f916b5f0111b07b1a1c97527f026e9d 100644 ---- a/src/main/java/org/bukkit/plugin/Plugin.java -+++ b/src/main/java/org/bukkit/plugin/Plugin.java -@@ -179,6 +179,13 @@ public interface Plugin extends TabExecutor { - @NotNull - public Logger getLogger(); - -+ // Paper start - Adventure component logger -+ @NotNull -+ default net.kyori.adventure.text.logger.slf4j.ComponentLogger getComponentLogger() { -+ return net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(getLogger().getName()); -+ } -+ // Paper end -+ - /** - * Returns the name of the plugin. - *

-diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java -index ff3fcb2697eb00736238d0efdcaefe43043334d3..75acd6f8f3d774bb79e8e513125e801c5569a244 100644 ---- a/src/main/java/org/bukkit/scoreboard/Objective.java -+++ b/src/main/java/org/bukkit/scoreboard/Objective.java -@@ -19,14 +19,35 @@ public interface Objective { - */ - @NotNull - String getName() throws IllegalStateException; -+ // Paper start -+ /** -+ * Gets the name displayed to players for this objective -+ * -+ * @return this objective's display name -+ * @throws IllegalStateException if this objective has been unregistered -+ */ -+ @NotNull net.kyori.adventure.text.Component displayName() throws IllegalStateException; -+ /** -+ * Sets the name displayed to players for this objective. -+ * -+ * @param displayName Display name to set -+ * @throws IllegalStateException if this objective has been unregistered -+ * @throws IllegalArgumentException if displayName is null -+ * @throws IllegalArgumentException if displayName is longer than 128 -+ * characters. -+ */ -+ void displayName(@Nullable net.kyori.adventure.text.Component displayName) throws IllegalStateException, IllegalArgumentException; -+ // Paper end - - /** - * Gets the name displayed to players for this objective - * - * @return this objective's display name - * @throws IllegalStateException if this objective has been unregistered -+ * @deprecated in favour of {@link #displayName()} - */ - @NotNull -+ @Deprecated // Paper - String getDisplayName() throws IllegalStateException; - - /** -@@ -37,7 +58,9 @@ public interface Objective { - * @throws IllegalArgumentException if displayName is null - * @throws IllegalArgumentException if displayName is longer than 128 - * characters. -+ * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - void setDisplayName(@NotNull String displayName) throws IllegalStateException, IllegalArgumentException; - - /** -diff --git a/src/main/java/org/bukkit/scoreboard/Scoreboard.java b/src/main/java/org/bukkit/scoreboard/Scoreboard.java -index 5c855dbd0da895392f7a6e92cdc90782baf614ad..1ada91d790abedbc9b3aeb6e96467a0d78560f15 100644 ---- a/src/main/java/org/bukkit/scoreboard/Scoreboard.java -+++ b/src/main/java/org/bukkit/scoreboard/Scoreboard.java -@@ -27,6 +27,48 @@ public interface Scoreboard { - @Deprecated - @NotNull - Objective registerNewObjective(@NotNull String name, @NotNull String criteria) throws IllegalArgumentException; -+ // Paper start -+ /** -+ * Registers an Objective on this Scoreboard -+ * -+ * @param name Name of the Objective -+ * @param criteria Criteria for the Objective -+ * @param displayName Name displayed to players for the Objective. -+ * @return The registered Objective -+ * @throws IllegalArgumentException if name is null -+ * @throws IllegalArgumentException if name is longer than 32767 -+ * characters. -+ * @throws IllegalArgumentException if criteria is null -+ * @throws IllegalArgumentException if displayName is null -+ * @throws IllegalArgumentException if displayName is longer than 128 -+ * characters. -+ * @throws IllegalArgumentException if an objective by that name already -+ * exists -+ */ -+ @NotNull -+ Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @Nullable net.kyori.adventure.text.Component displayName) throws IllegalArgumentException; -+ /** -+ * Registers an Objective on this Scoreboard -+ * -+ * @param name Name of the Objective -+ * @param criteria Criteria for the Objective -+ * @param displayName Name displayed to players for the Objective. -+ * @param renderType Manner of rendering the Objective -+ * @return The registered Objective -+ * @throws IllegalArgumentException if name is null -+ * @throws IllegalArgumentException if name is longer than 32767 -+ * characters. -+ * @throws IllegalArgumentException if criteria is null -+ * @throws IllegalArgumentException if displayName is null -+ * @throws IllegalArgumentException if displayName is longer than 128 -+ * characters. -+ * @throws IllegalArgumentException if renderType is null -+ * @throws IllegalArgumentException if an objective by that name already -+ * exists -+ */ -+ @NotNull -+ Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @Nullable net.kyori.adventure.text.Component displayName, @NotNull RenderType renderType) throws IllegalArgumentException; -+ // Paper end - - /** - * Registers an Objective on this Scoreboard -@@ -44,8 +86,10 @@ public interface Scoreboard { - * characters. - * @throws IllegalArgumentException if an objective by that name already - * exists -+ * @deprecated in favour of {@link #registerNewObjective(String, String, net.kyori.adventure.text.Component)} - */ - @NotNull -+ @Deprecated // Paper - Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @NotNull String displayName) throws IllegalArgumentException; - - /** -@@ -66,8 +110,10 @@ public interface Scoreboard { - * @throws IllegalArgumentException if renderType is null - * @throws IllegalArgumentException if an objective by that name already - * exists -+ * @deprecated in favour of {@link #registerNewObjective(String, String, net.kyori.adventure.text.Component, RenderType)} - */ - @NotNull -+ @Deprecated // Paper - Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @NotNull String displayName, @NotNull RenderType renderType) throws IllegalArgumentException; - - /** -diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java -index 0db7fe1b9fe5621ceed3f4f046691e359f5949dd..47b10df619ad2520b9bb673e2220f36391680f1b 100644 ---- a/src/main/java/org/bukkit/scoreboard/Team.java -+++ b/src/main/java/org/bukkit/scoreboard/Team.java -@@ -22,14 +22,100 @@ public interface Team { - */ - @NotNull - String getName() throws IllegalStateException; -+ // Paper start -+ /** -+ * Gets the name displayed to entries for this team -+ * -+ * @return Team display name -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ @NotNull net.kyori.adventure.text.Component displayName() throws IllegalStateException; -+ -+ /** -+ * Sets the name displayed to entries for this team -+ * -+ * @param displayName New display name -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ void displayName(@Nullable net.kyori.adventure.text.Component displayName) throws IllegalStateException, IllegalArgumentException; -+ -+ /** -+ * Gets the prefix prepended to the display of entries on this team. -+ * -+ * @return Team prefix -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ @NotNull net.kyori.adventure.text.Component prefix() throws IllegalStateException; -+ -+ /** -+ * Sets the prefix prepended to the display of entries on this team. -+ * -+ * @param prefix New prefix -+ * @throws IllegalArgumentException if prefix is null -+ * characters -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ void prefix(@Nullable net.kyori.adventure.text.Component prefix) throws IllegalStateException, IllegalArgumentException; -+ -+ /** -+ * Gets the suffix appended to the display of entries on this team. -+ * -+ * @return the team's current suffix -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ @NotNull net.kyori.adventure.text.Component suffix() throws IllegalStateException; -+ -+ /** -+ * Sets the suffix appended to the display of entries on this team. -+ * -+ * @param suffix the new suffix for this team. -+ * @throws IllegalArgumentException if suffix is null -+ * characters -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ void suffix(@Nullable net.kyori.adventure.text.Component suffix) throws IllegalStateException, IllegalArgumentException; -+ -+ /** -+ * Checks if the team has a color specified -+ * -+ * @return true if it has a color -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ boolean hasColor(); -+ -+ /** -+ * Gets the color of the team. -+ *
-+ * This only sets the team outline, other occurrences of colors such as in -+ * names are handled by prefixes / suffixes. -+ * -+ * @return team color -+ * @throws IllegalStateException if this team has been unregistered -+ * @throws IllegalStateException if the team doesn't have a color -+ * @see #hasColor() -+ */ -+ @NotNull net.kyori.adventure.text.format.TextColor color() throws IllegalStateException; -+ -+ /** -+ * Sets the color of the team. -+ *
-+ * This only sets the team outline, other occurrences of colors such as in -+ * names are handled by prefixes / suffixes. -+ * -+ * @param color new color, null for no color -+ */ -+ void color(@Nullable net.kyori.adventure.text.format.NamedTextColor color); -+ // Paper end - - /** - * Gets the name displayed to entries for this team - * - * @return Team display name - * @throws IllegalStateException if this team has been unregistered -+ * @deprecated in favour of {@link #displayName()} - */ - @NotNull -+ @Deprecated // Paper - String getDisplayName() throws IllegalStateException; - - /** -@@ -39,7 +125,9 @@ public interface Team { - * @throws IllegalArgumentException if displayName is longer than 128 - * characters. - * @throws IllegalStateException if this team has been unregistered -+ * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - void setDisplayName(@NotNull String displayName) throws IllegalStateException, IllegalArgumentException; - - /** -@@ -47,8 +135,10 @@ public interface Team { - * - * @return Team prefix - * @throws IllegalStateException if this team has been unregistered -+ * @deprecated in favour of {@link #prefix()} - */ - @NotNull -+ @Deprecated // Paper - String getPrefix() throws IllegalStateException; - - /** -@@ -59,7 +149,9 @@ public interface Team { - * @throws IllegalArgumentException if prefix is longer than 64 - * characters - * @throws IllegalStateException if this team has been unregistered -+ * @deprecated in favour of {@link #prefix(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - void setPrefix(@NotNull String prefix) throws IllegalStateException, IllegalArgumentException; - - /** -@@ -67,8 +159,10 @@ public interface Team { - * - * @return the team's current suffix - * @throws IllegalStateException if this team has been unregistered -+ * @deprecated in favour of {@link #suffix()} - */ - @NotNull -+ @Deprecated // Paper - String getSuffix() throws IllegalStateException; - - /** -@@ -79,7 +173,9 @@ public interface Team { - * @throws IllegalArgumentException if suffix is longer than 64 - * characters - * @throws IllegalStateException if this team has been unregistered -+ * @deprecated in favour of {@link #suffix(net.kyori.adventure.text.Component)} - */ -+ @Deprecated // Paper - void setSuffix(@NotNull String suffix) throws IllegalStateException, IllegalArgumentException; - - /** -@@ -90,8 +186,10 @@ public interface Team { - * - * @return team color, defaults to {@link ChatColor#RESET} - * @throws IllegalStateException if this team has been unregistered -+ * @deprecated in favour of {@link #color()} - */ - @NotNull -+ @Deprecated // Paper - ChatColor getColor() throws IllegalStateException; - - /** -@@ -102,7 +200,9 @@ public interface Team { - * - * @param color new color, must be non-null. Use {@link ChatColor#RESET} for - * no color -+ * @deprecated in favour of {@link #color(net.kyori.adventure.text.format.NamedTextColor)} - */ -+ @Deprecated // Paper - void setColor(@NotNull ChatColor color); - - /** -diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java -index c6a8a37a933cfc5a5885602a8a70fdda8fb6aa10..93498307004b68b934fbfa1aeb3aaf0e97cbdac7 100644 ---- a/src/test/java/org/bukkit/AnnotationTest.java -+++ b/src/test/java/org/bukkit/AnnotationTest.java -@@ -26,6 +26,12 @@ import org.objectweb.asm.tree.ParameterNode; - public class AnnotationTest { - - private static final String[] ACCEPTED_ANNOTATIONS = { -+ // Paper start -+ "Lorg/checkerframework/checker/nullness/qual/Nullable;", -+ "Lorg/checkerframework/checker/nullness/qual/NonNull;", -+ "Lorg/checkerframework/checker/nullness/qual/PolyNull;", -+ "Lorg/checkerframework/checker/nullness/qual/MonotonicNonNull;", -+ // Paper end - "Lorg/jetbrains/annotations/Nullable;", - "Lorg/jetbrains/annotations/NotNull;", - "Lorg/jetbrains/annotations/Contract;", -@@ -105,7 +111,7 @@ public class AnnotationTest { - if (method.invisibleTypeAnnotations != null) { - for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { - final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); -- if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { -+ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.asList(ACCEPTED_ANNOTATIONS).contains(invisibleTypeAnnotation.desc)) { - continue dancing; - } - } diff --git a/patches/api/0006-Adventure.patch b/patches/api/0006-Adventure.patch new file mode 100644 index 000000000000..43d2ca554749 --- /dev/null +++ b/patches/api/0006-Adventure.patch @@ -0,0 +1,5660 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Riley Park +Date: Fri, 29 Jan 2021 17:21:55 +0100 +Subject: [PATCH] Adventure + +Co-authored-by: zml +Co-authored-by: Jake Potrebic +Co-authored-by: Yannick Lamprecht + +diff --git a/build.gradle.kts b/build.gradle.kts +index e1acfa9abed37e5332edf6b6cf66e3b9b926b366..ed5d58d7569300c917dd52b11953a63fae6878d4 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -11,6 +11,18 @@ java { + + val annotationsVersion = "24.1.0" + val bungeeCordChatVersion = "1.20-R0.2" ++val adventureVersion = "4.17.0" ++val apiAndDocs: Configuration by configurations.creating { ++ attributes { ++ attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION)) ++ attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) ++ attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES)) ++ attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) ++ } ++} ++configurations.api { ++ extendsFrom(apiAndDocs) ++} + + // Paper start - configure mockito agent that is needed in newer java versions + val mockitoAgent = configurations.register("mockitoAgent") +@@ -28,7 +40,11 @@ dependencies { + // api dependencies are listed transitively to API consumers + api("com.google.guava:guava:33.3.1-jre") + api("com.google.code.gson:gson:2.11.0") +- api("net.md-5:bungeecord-chat:$bungeeCordChatVersion") ++ // Paper start - adventure ++ api("net.md-5:bungeecord-chat:$bungeeCordChatVersion-deprecated+build.19") { ++ exclude("com.google.guava", "guava") ++ } ++ // Paper - adventure + api("org.yaml:snakeyaml:2.2") + api("org.joml:joml:1.10.8") { + isTransitive = false // https://github.com/JOML-CI/JOML/issues/352 +@@ -38,6 +54,13 @@ dependencies { + isTransitive = false // includes junit + } + api("it.unimi.dsi:fastutil:8.5.15") ++ apiAndDocs(platform("net.kyori:adventure-bom:$adventureVersion")) ++ apiAndDocs("net.kyori:adventure-api") ++ apiAndDocs("net.kyori:adventure-text-minimessage") ++ apiAndDocs("net.kyori:adventure-text-serializer-gson") ++ apiAndDocs("net.kyori:adventure-text-serializer-legacy") ++ apiAndDocs("net.kyori:adventure-text-serializer-plain") ++ apiAndDocs("net.kyori:adventure-text-logger-slf4j") + // Paper end + + compileOnly("org.apache.maven:maven-resolver-provider:3.9.6") +@@ -115,15 +138,32 @@ tasks.withType { + "https://guava.dev/releases/33.3.1-jre/api/docs/", + "https://javadoc.io/doc/org.yaml/snakeyaml/2.2/", + "https://javadoc.io/doc/org.jetbrains/annotations/$annotationsVersion/", // Paper - we don't want Java 5 annotations +- "https://javadoc.io/doc/net.md-5/bungeecord-chat/$bungeeCordChatVersion/", ++ // "https://javadoc.io/doc/net.md-5/bungeecord-chat/$bungeeCordChatVersion/", // Paper - don't link to bungee chat + // Paper start - add missing javadoc links + "https://javadoc.io/doc/org.joml/joml/1.10.8/index.html", + "https://www.javadoc.io/doc/com.google.code.gson/gson/2.11.0", + "https://jspecify.dev/docs/api/", + // Paper end ++ // Paper start ++ "https://jd.advntr.dev/api/$adventureVersion/", ++ "https://jd.advntr.dev/key/$adventureVersion/", ++ "https://jd.advntr.dev/text-minimessage/$adventureVersion/", ++ "https://jd.advntr.dev/text-serializer-gson/$adventureVersion/", ++ "https://jd.advntr.dev/text-serializer-legacy/$adventureVersion/", ++ "https://jd.advntr.dev/text-serializer-plain/$adventureVersion/", ++ "https://jd.advntr.dev/text-logger-slf4j/$adventureVersion/", ++ // Paper end + ) + options.tags("apiNote:a:API Note:") + ++ inputs.files(apiAndDocs).ignoreEmptyDirectories().withPropertyName(apiAndDocs.name + "-configuration") ++ doFirst { ++ options.addStringOption( ++ "sourcepath", ++ apiAndDocs.elements.get().map { it.asFile }.joinToString(separator = File.pathSeparator, transform = File::getPath) ++ ) ++ } ++ + // workaround for https://github.com/gradle/gradle/issues/4046 + inputs.dir("src/main/javadoc").withPropertyName("javadoc-sourceset") + doLast { +diff --git a/src/main/java/io/papermc/paper/chat/ChatRenderer.java b/src/main/java/io/papermc/paper/chat/ChatRenderer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1288cdeafe587e9e78e7c5087742ea054ba8423d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/chat/ChatRenderer.java +@@ -0,0 +1,70 @@ ++package io.papermc.paper.chat; ++ ++import net.kyori.adventure.audience.Audience; ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A chat renderer is responsible for rendering chat messages sent by {@link Player}s to the server. ++ */ ++@NullMarked ++@FunctionalInterface ++public interface ChatRenderer { ++ ++ /** ++ * Renders a chat message. This will be called once for each receiving {@link Audience}. ++ * ++ * @param source the message source ++ * @param sourceDisplayName the display name of the source player ++ * @param message the chat message ++ * @param viewer the receiving {@link Audience} ++ * @return a rendered chat message ++ */ ++ @ApiStatus.OverrideOnly ++ Component render(Player source, Component sourceDisplayName, Component message, Audience viewer); ++ ++ /** ++ * Create a new instance of the default {@link ChatRenderer}. ++ * ++ * @return a new {@link ChatRenderer} ++ */ ++ static ChatRenderer defaultRenderer() { ++ return new ViewerUnawareImpl.Default((source, sourceDisplayName, message) -> Component.translatable("chat.type.text", sourceDisplayName, message)); ++ } ++ ++ @ApiStatus.Internal ++ sealed interface Default extends ChatRenderer, ViewerUnaware permits ViewerUnawareImpl.Default { ++ } ++ ++ /** ++ * Creates a new viewer-unaware {@link ChatRenderer}, which will render the chat message a single time, ++ * displaying the same rendered message to every viewing {@link Audience}. ++ * ++ * @param renderer the viewer unaware renderer ++ * @return a new {@link ChatRenderer} ++ */ ++ static ChatRenderer viewerUnaware(final ViewerUnaware renderer) { ++ return new ViewerUnawareImpl(renderer); ++ } ++ ++ /** ++ * Similar to {@link ChatRenderer}, but without knowledge of the message viewer. ++ * ++ * @see ChatRenderer#viewerUnaware(ViewerUnaware) ++ */ ++ interface ViewerUnaware { ++ ++ /** ++ * Renders a chat message. ++ * ++ * @param source the message source ++ * @param sourceDisplayName the display name of the source player ++ * @param message the chat message ++ * @return a rendered chat message ++ */ ++ @ApiStatus.OverrideOnly ++ Component render(Player source, Component sourceDisplayName, Component message); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java b/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e1ef23b4bdf60a299d6d37099cef777b3de13ac7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java +@@ -0,0 +1,38 @@ ++package io.papermc.paper.chat; ++ ++import net.kyori.adventure.audience.Audience; ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@ApiStatus.Internal ++@NullMarked ++sealed class ViewerUnawareImpl implements ChatRenderer, ChatRenderer.ViewerUnaware permits ViewerUnawareImpl.Default { ++ private final ViewerUnaware unaware; ++ private @Nullable Component message; ++ ++ ViewerUnawareImpl(final ViewerUnaware unaware) { ++ this.unaware = unaware; ++ } ++ ++ @Override ++ public Component render(final Player source, final Component sourceDisplayName, final Component message, final Audience viewer) { ++ return this.render(source, sourceDisplayName, message); ++ } ++ ++ @Override ++ public Component render(final Player source, final Component sourceDisplayName, final Component message) { ++ if (this.message == null) { ++ this.message = this.unaware.render(source, sourceDisplayName, message); ++ } ++ return this.message; ++ } ++ ++ static final class Default extends ViewerUnawareImpl implements ChatRenderer.Default { ++ Default(final ViewerUnaware unaware) { ++ super(unaware); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0facfaa305 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java +@@ -0,0 +1,122 @@ ++package io.papermc.paper.event.player; ++ ++import io.papermc.paper.chat.ChatRenderer; ++import java.util.Set; ++import net.kyori.adventure.audience.Audience; ++import net.kyori.adventure.chat.SignedMessage; ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++import static java.util.Objects.requireNonNull; ++ ++/** ++ * An abstract implementation of a chat event, handling shared logic. ++ */ ++@ApiStatus.NonExtendable ++@NullMarked ++public abstract class AbstractChatEvent extends PlayerEvent implements Cancellable { ++ ++ private final Set viewers; ++ private final Component originalMessage; ++ private final SignedMessage signedMessage; ++ private ChatRenderer renderer; ++ private Component message; ++ ++ private boolean cancelled; ++ ++ AbstractChatEvent(final boolean async, final Player player, final Set viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) { ++ super(player, async); ++ this.viewers = viewers; ++ this.renderer = renderer; ++ this.message = message; ++ this.originalMessage = originalMessage; ++ this.signedMessage = signedMessage; ++ } ++ ++ /** ++ * Gets a set of {@link Audience audiences} that this chat message will be displayed to. ++ * ++ *

The set returned may auto-populate on access. Any listener accessing the returned set should be aware that ++ * it may reduce performance for a lazy set implementation.

++ * ++ * @return a mutable set of {@link Audience audiences} who will receive the chat message ++ */ ++ public final Set viewers() { ++ return this.viewers; ++ } ++ ++ /** ++ * Sets the chat renderer. ++ * ++ * @param renderer the chat renderer ++ * @throws NullPointerException if {@code renderer} is {@code null} ++ */ ++ public final void renderer(final ChatRenderer renderer) { ++ this.renderer = requireNonNull(renderer, "renderer"); ++ } ++ ++ /** ++ * Gets the chat renderer. ++ * ++ * @return the chat renderer ++ */ ++ public final ChatRenderer renderer() { ++ return this.renderer; ++ } ++ ++ /** ++ * Gets the user-supplied message. ++ * The return value will reflect changes made using {@link #message(Component)}. ++ * ++ * @return the user-supplied message ++ */ ++ public final Component message() { ++ return this.message; ++ } ++ ++ /** ++ * Sets the user-supplied message. ++ * ++ * @param message the user-supplied message ++ * @throws NullPointerException if {@code message} is {@code null} ++ */ ++ public final void message(final Component message) { ++ this.message = requireNonNull(message, "message"); ++ } ++ ++ /** ++ * Gets the original and unmodified user-supplied message. ++ * The return value will not reflect changes made using ++ * {@link #message(Component)}. ++ * ++ * @return the original user-supplied message ++ */ ++ public final Component originalMessage() { ++ return this.originalMessage; ++ } ++ ++ /** ++ * Gets the signed message. ++ * Changes made in this event will not update ++ * the signed message. ++ * ++ * @return the signed message ++ */ ++ public final SignedMessage signedMessage() { ++ return this.signedMessage; ++ } ++ ++ @Override ++ public final boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public final void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ddd4c90f83b5cb8f069ff53760abb3c4adfd1168 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java +@@ -0,0 +1,29 @@ ++package io.papermc.paper.event.player; ++ ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@ApiStatus.Experimental ++@NullMarked ++public class AsyncChatCommandDecorateEvent extends AsyncChatDecorateEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ @ApiStatus.Internal ++ public AsyncChatCommandDecorateEvent(final @Nullable Player player, final Component originalMessage) { ++ super(player, originalMessage); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9e5ea0cd006bd9744b84923620841f07fa40c2cb +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java +@@ -0,0 +1,105 @@ ++package io.papermc.paper.event.player; ++ ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.server.ServerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * This event is fired when the server decorates a component for chat purposes. This is called ++ * before {@link AsyncChatEvent} and the other chat events. It is recommended that you modify the ++ * message here, and use the chat events for modifying receivers and later the chat type. If you ++ * want to keep the message as "signed" for the clients who get it, be sure to include the entire ++ * original message somewhere in the final message. ++ *
++ * See {@link AsyncChatCommandDecorateEvent} for the decoration of messages sent via commands ++ */ ++@ApiStatus.Experimental ++@NullMarked ++public class AsyncChatDecorateEvent extends ServerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final @Nullable Player player; ++ private final Component originalMessage; ++ private Component result; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public AsyncChatDecorateEvent(final @Nullable Player player, final Component originalMessage) { ++ super(true); ++ this.player = player; ++ this.originalMessage = originalMessage; ++ this.result = originalMessage; ++ } ++ ++ /** ++ * Gets the player (if available) associated with this event. ++ *

++ * Certain commands request decorations without a player context ++ * which is why this is possibly null. ++ * ++ * @return the player or {@code null} ++ */ ++ public @Nullable Player player() { ++ return this.player; ++ } ++ ++ /** ++ * Gets the original decoration input ++ * ++ * @return the input ++ */ ++ public Component originalMessage() { ++ return this.originalMessage; ++ } ++ ++ /** ++ * Gets the decoration result. This may already be different from ++ * {@link #originalMessage()} if some other listener to this event ++ * changed the result. ++ * ++ * @return the result ++ */ ++ public Component result() { ++ return this.result; ++ } ++ ++ /** ++ * Sets the resulting decorated component. ++ * ++ * @param result the result ++ */ ++ public void result(final Component result) { ++ this.result = result; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * A cancelled decorating event means that no changes to the result component ++ * will have any effect. The decorated component will be equal to the original ++ * component. ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..50c3e117dec63811823b4e6395bf4f090692ee8c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java +@@ -0,0 +1,44 @@ ++package io.papermc.paper.event.player; ++ ++import io.papermc.paper.chat.ChatRenderer; ++import java.util.Set; ++import net.kyori.adventure.audience.Audience; ++import net.kyori.adventure.chat.SignedMessage; ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * An event fired when a {@link Player} sends a chat message to the server. ++ *

++ * This event will sometimes fire synchronously, depending on how it was ++ * triggered. ++ *

++ * If a player is the direct cause of this event by an incoming packet, this ++ * event will be asynchronous. If a plugin triggers this event by compelling a ++ * player to chat, this event will be synchronous. ++ *

++ * Care should be taken to check {@link #isAsynchronous()} and treat the event ++ * appropriately. ++ */ ++@NullMarked ++public final class AsyncChatEvent extends AbstractChatEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ @ApiStatus.Internal ++ public AsyncChatEvent(final boolean async, final Player player, final Set viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) { ++ super(async, player, viewers, renderer, message, originalMessage, signedMessage); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/ChatEvent.java b/src/main/java/io/papermc/paper/event/player/ChatEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..42a82ce2316a4aad2883d24c7e2ff95d95f5881a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/ChatEvent.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.event.player; ++ ++import io.papermc.paper.chat.ChatRenderer; ++import java.util.Set; ++import net.kyori.adventure.audience.Audience; ++import net.kyori.adventure.chat.SignedMessage; ++import net.kyori.adventure.text.Component; ++import org.bukkit.Warning; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * An event fired when a {@link Player} sends a chat message to the server. ++ * ++ * @deprecated Listening to this event forces chat to wait for the main thread, delaying chat messages. ++ * It is recommended to use {@link AsyncChatEvent} instead, wherever possible. ++ */ ++@Deprecated ++@Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.") ++@NullMarked ++public final class ChatEvent extends AbstractChatEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ @ApiStatus.Internal ++ public ChatEvent(final Player player, final Set viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) { ++ super(false, player, viewers, renderer, message, originalMessage, signedMessage); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/text/PaperComponents.java b/src/main/java/io/papermc/paper/text/PaperComponents.java +new file mode 100644 +index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bde50e0147 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/text/PaperComponents.java +@@ -0,0 +1,180 @@ ++package io.papermc.paper.text; ++ ++import java.io.IOException; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.flattener.ComponentFlattener; ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; ++import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; ++import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; ++import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; ++import org.bukkit.Bukkit; ++import org.bukkit.command.CommandSender; ++import org.bukkit.entity.Entity; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Paper API-specific methods for working with {@link Component}s and related. ++ */ ++@NullMarked ++public final class PaperComponents { ++ ++ private PaperComponents() { ++ throw new RuntimeException("PaperComponents is not to be instantiated!"); ++ } ++ ++ /** ++ * Resolves a component with a specific command sender and subject. ++ *

++ * Note that in Vanilla, elevated permissions are usually required to use ++ * '@' selectors in various component types, but this method should not ++ * check such permissions from the sender. ++ *

++ * A {@link CommandSender} argument is required to resolve: ++ *

    ++ *
  • {@link net.kyori.adventure.text.NBTComponent}
  • ++ *
  • {@link net.kyori.adventure.text.ScoreComponent}
  • ++ *
  • {@link net.kyori.adventure.text.SelectorComponent}
  • ++ *
++ * A {@link Entity} argument is optional to help resolve: ++ *
    ++ *
  • {@link net.kyori.adventure.text.ScoreComponent}
  • ++ *
++ * {@link net.kyori.adventure.text.TranslatableComponent}s don't require any extra arguments. ++ * ++ * @param input the component to resolve ++ * @param context the command sender to resolve with ++ * @param scoreboardSubject the scoreboard subject to use (for use with {@link net.kyori.adventure.text.ScoreComponent}s) ++ * @return the resolved component ++ * @throws IOException if a syntax error tripped during resolving ++ */ ++ public static Component resolveWithContext(final Component input, final @Nullable CommandSender context, final @Nullable Entity scoreboardSubject) throws IOException { ++ return resolveWithContext(input, context, scoreboardSubject, true); ++ } ++ ++ /** ++ * Resolves a component with a specific command sender and subject. ++ *

++ * Note that in Vanilla, elevated permissions are required to use ++ * '@' selectors in various component types. If the boolean {@code bypassPermissions} ++ * argument is {@code false}, the {@link CommandSender} argument will be used to query ++ * those permissions. ++ *

++ * A {@link CommandSender} argument is required to resolve: ++ *

    ++ *
  • {@link net.kyori.adventure.text.NBTComponent}
  • ++ *
  • {@link net.kyori.adventure.text.ScoreComponent}
  • ++ *
  • {@link net.kyori.adventure.text.SelectorComponent}
  • ++ *
++ * A {@link Entity} argument is optional to help resolve: ++ *
    ++ *
  • {@link net.kyori.adventure.text.ScoreComponent}
  • ++ *
++ * {@link net.kyori.adventure.text.TranslatableComponent}s don't require any extra arguments. ++ * ++ * @param input the component to resolve ++ * @param context the command sender to resolve with ++ * @param scoreboardSubject the scoreboard subject to use (for use with {@link net.kyori.adventure.text.ScoreComponent}s) ++ * @param bypassPermissions true to bypass permissions checks for resolving components ++ * @return the resolved component ++ * @throws IOException if a syntax error tripped during resolving ++ */ ++ @SuppressWarnings("deprecation") // using unsafe as a bridge ++ public static Component resolveWithContext(final Component input, final @Nullable CommandSender context, final @Nullable Entity scoreboardSubject, final boolean bypassPermissions) throws IOException { ++ return Bukkit.getUnsafe().resolveWithContext(input, context, scoreboardSubject, bypassPermissions); ++ } ++ ++ /** ++ * Return a component flattener that can use game data to resolve extra information about components. ++ * ++ * @return a component flattener ++ */ ++ @SuppressWarnings("deprecation") // using unsafe as a bridge ++ public static ComponentFlattener flattener() { ++ return Bukkit.getUnsafe().componentFlattener(); ++ } ++ ++ /** ++ * Get a serializer for {@link Component}s that will convert components to ++ * a plain-text string. ++ * ++ *

Implementations may provide a serializer capable of processing any ++ * information that requires access to implementation details.

++ * ++ * @return a serializer to plain text ++ * @deprecated will be removed in adventure 5.0.0, use {@link PlainTextComponentSerializer#plainText()} ++ */ ++ @Deprecated(forRemoval = true, since = "1.18.1") ++ public static PlainComponentSerializer plainSerializer() { ++ return Bukkit.getUnsafe().plainComponentSerializer(); ++ } ++ ++ /** ++ * Get a serializer for {@link Component}s that will convert components to ++ * a plain-text string. ++ * ++ *

Implementations may provide a serializer capable of processing any ++ * information that requires access to implementation details.

++ * ++ * @return a serializer to plain text ++ * @deprecated use {@link PlainTextComponentSerializer#plainText()} ++ */ ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ public static PlainTextComponentSerializer plainTextSerializer() { ++ return Bukkit.getUnsafe().plainTextSerializer(); ++ } ++ ++ /** ++ * Get a serializer for {@link Component}s that will convert to and from the ++ * standard JSON serialization format using Gson. ++ * ++ *

Implementations may provide a serializer capable of processing any ++ * information that requires implementation details, such as legacy ++ * (pre-1.16) hover events.

++ * ++ * @return a json component serializer ++ * @deprecated use {@link GsonComponentSerializer#gson()} ++ */ ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ public static GsonComponentSerializer gsonSerializer() { ++ return Bukkit.getUnsafe().gsonComponentSerializer(); ++ } ++ ++ /** ++ * Get a serializer for {@link Component}s that will convert to and from the ++ * standard JSON serialization format using Gson, downsampling any RGB colors ++ * to their nearest {@link NamedTextColor} counterpart. ++ * ++ *

Implementations may provide a serializer capable of processing any ++ * information that requires implementation details, such as legacy ++ * (pre-1.16) hover events.

++ * ++ * @return a json component serializer ++ * @deprecated use {@link GsonComponentSerializer#colorDownsamplingGson()} ++ */ ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ public static GsonComponentSerializer colorDownsamplingGsonSerializer() { ++ return Bukkit.getUnsafe().colorDownsamplingGsonComponentSerializer(); ++ } ++ ++ /** ++ * Get a serializer for {@link Component}s that will convert to and from the ++ * legacy component format used by Bukkit. This serializer uses the ++ * {@link LegacyComponentSerializer.Builder#useUnusualXRepeatedCharacterHexFormat()} ++ * option to match upstream behavior. ++ * ++ *

This legacy serializer uses the standard section symbol to mark ++ * formatting characters.

++ * ++ *

Implementations may provide a serializer capable of processing any ++ * information that requires access to implementation details.

++ * ++ * @return a section serializer ++ * @deprecated use {@link LegacyComponentSerializer#legacySection()} ++ */ ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ public static LegacyComponentSerializer legacySectionSerializer() { ++ return Bukkit.getUnsafe().legacyComponentSerializer(); ++ } ++} +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index c869a1c0f658fa8fb6b4d15a4292f9e8b60339a3..6391011464ac0c95d4da7fb9c698f35c58b40922 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -423,7 +423,9 @@ public final class Bukkit { + * + * @param message the message + * @return the number of players ++ * @deprecated in favour of {@link Server#broadcast(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public static int broadcastMessage(@NotNull String message) { + return server.broadcastMessage(message); + } +@@ -1227,6 +1229,19 @@ public final class Bukkit { + server.shutdown(); + } + ++ // Paper start ++ /** ++ * Broadcast a message to all players. ++ *

++ * This is the same as calling {@link #broadcast(net.kyori.adventure.text.Component, ++ * java.lang.String)} with the {@link Server#BROADCAST_CHANNEL_USERS} permission. ++ * ++ * @param message the message ++ * @return the number of players ++ */ ++ public static int broadcast(net.kyori.adventure.text.@NotNull Component message) { ++ return server.broadcast(message); ++ } + /** + * Broadcasts the specified message to every user with the given + * permission name. +@@ -1236,6 +1251,21 @@ public final class Bukkit { + * permissibles} must have to receive the broadcast + * @return number of message recipients + */ ++ public static int broadcast(net.kyori.adventure.text.@NotNull Component message, @NotNull String permission) { ++ return server.broadcast(message, permission); ++ } ++ // Paper end ++ /** ++ * Broadcasts the specified message to every user with the given ++ * permission name. ++ * ++ * @param message message to broadcast ++ * @param permission the required permission {@link Permissible ++ * permissibles} must have to receive the broadcast ++ * @return number of message recipients ++ * @deprecated in favour of {@link #broadcast(net.kyori.adventure.text.Component, String)} ++ */ ++ @Deprecated // Paper + public static int broadcast(@NotNull String message, @NotNull String permission) { + return server.broadcast(message, permission); + } +@@ -1497,6 +1527,7 @@ public final class Bukkit { + return server.createInventory(owner, type); + } + ++ // Paper start + /** + * Creates an empty inventory with the specified type and title. If the type + * is {@link InventoryType#CHEST}, the new inventory has a size of 27; +@@ -1522,6 +1553,38 @@ public final class Bukkit { + * @see InventoryType#isCreatable() + */ + @NotNull ++ public static Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, net.kyori.adventure.text.@NotNull Component title) { ++ return server.createInventory(owner, type, title); ++ } ++ // Paper end ++ ++ /** ++ * Creates an empty inventory with the specified type and title. If the type ++ * is {@link InventoryType#CHEST}, the new inventory has a size of 27; ++ * otherwise the new inventory has the normal size for its type.
++ * It should be noted that some inventory types do not support titles and ++ * may not render with said titles on the Minecraft client. ++ *
++ * {@link InventoryType#WORKBENCH} will not process crafting recipes if ++ * created with this method. Use ++ * {@link Player#openWorkbench(Location, boolean)} instead. ++ *
++ * {@link InventoryType#ENCHANTING} will not process {@link ItemStack}s ++ * for possible enchanting results. Use ++ * {@link Player#openEnchanting(Location, boolean)} instead. ++ * ++ * @param owner The holder of the inventory; can be null if there's no holder. ++ * @param type The type of inventory to create. ++ * @param title The title of the inventory, to be displayed when it is viewed. ++ * @return The new inventory. ++ * @throws IllegalArgumentException if the {@link InventoryType} cannot be ++ * viewed. ++ * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} ++ * ++ * @see InventoryType#isCreatable() ++ */ ++ @Deprecated // Paper ++ @NotNull + public static Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull String title) { + return server.createInventory(owner, type, title); + } +@@ -1540,6 +1603,7 @@ public final class Bukkit { + return server.createInventory(owner, size); + } + ++ // Paper start + /** + * Creates an empty inventory of type {@link InventoryType#CHEST} with the + * specified size and title. +@@ -1552,10 +1616,30 @@ public final class Bukkit { + * @throws IllegalArgumentException if the size is not a multiple of 9 + */ + @NotNull ++ public static Inventory createInventory(@Nullable InventoryHolder owner, int size, net.kyori.adventure.text.@NotNull Component title) throws IllegalArgumentException { ++ return server.createInventory(owner, size, title); ++ } ++ // Paper end ++ ++ /** ++ * Creates an empty inventory of type {@link InventoryType#CHEST} with the ++ * specified size and title. ++ * ++ * @param owner the holder of the inventory, or null to indicate no holder ++ * @param size a multiple of 9 as the size of inventory to create ++ * @param title the title of the inventory, displayed when inventory is ++ * viewed ++ * @return a new inventory ++ * @throws IllegalArgumentException if the size is not a multiple of 9 ++ * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} ++ */ ++ @Deprecated // Paper ++ @NotNull + public static Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException { + return server.createInventory(owner, size, title); + } + ++ // Paper start + /** + * Creates an empty merchant. + * +@@ -1563,7 +1647,20 @@ public final class Bukkit { + * when the merchant inventory is viewed + * @return a new merchant + */ ++ public static @NotNull Merchant createMerchant(net.kyori.adventure.text.@Nullable Component title) { ++ return server.createMerchant(title); ++ } ++ // Paper start ++ /** ++ * Creates an empty merchant. ++ * ++ * @param title the title of the corresponding merchant inventory, displayed ++ * when the merchant inventory is viewed ++ * @return a new merchant ++ * @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)} ++ */ + @NotNull ++ @Deprecated // Paper + public static Merchant createMerchant(@Nullable String title) { + return server.createMerchant(title); + } +@@ -1680,12 +1777,43 @@ public final class Bukkit { + return server.isPrimaryThread(); + } + ++ // Paper start ++ /** ++ * Gets the message that is displayed on the server list. ++ * ++ * @return the server's MOTD ++ */ ++ @NotNull public static net.kyori.adventure.text.Component motd() { ++ return server.motd(); ++ } ++ ++ /** ++ * Set the message that is displayed on the server list. ++ * ++ * @param motd The message to be displayed ++ */ ++ public static void motd(final net.kyori.adventure.text.@NotNull Component motd) { ++ server.motd(motd); ++ } ++ ++ /** ++ * Gets the default message that is displayed when the server is stopped. ++ * ++ * @return the shutdown message ++ */ ++ public static net.kyori.adventure.text.@Nullable Component shutdownMessage() { ++ return server.shutdownMessage(); ++ } ++ // Paper end ++ + /** + * Gets the message that is displayed on the server list. + * + * @return the servers MOTD ++ * @deprecated in favour of {@link #motd()} + */ + @NotNull ++ @Deprecated // Paper + public static String getMotd() { + return server.getMotd(); + } +@@ -1694,7 +1822,9 @@ public final class Bukkit { + * Set the message that is displayed on the server list. + * + * @param motd The message to be displayed ++ * @deprecated in favour of {@link #motd(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public static void setMotd(@NotNull String motd) { + server.setMotd(motd); + } +@@ -1714,8 +1844,10 @@ public final class Bukkit { + * Gets the default message that is displayed when the server is stopped. + * + * @return the shutdown message ++ * @deprecated in favour of {@link #shutdownMessage()} + */ + @Nullable ++ @Deprecated // Paper + public static String getShutdownMessage() { + return server.getShutdownMessage(); + } +diff --git a/src/main/java/org/bukkit/ChatColor.java b/src/main/java/org/bukkit/ChatColor.java +index e3f185dc982d1c38195a4e01ddd485c13ffa58c0..918a045165cdcde264bc24082b7afebb407271de 100644 +--- a/src/main/java/org/bukkit/ChatColor.java ++++ b/src/main/java/org/bukkit/ChatColor.java +@@ -10,7 +10,9 @@ import org.jetbrains.annotations.Nullable; + + /** + * All supported color values for chat ++ * @deprecated ChatColor has been deprecated in favor of Adventure API. See {@link net.kyori.adventure.text.format.NamedTextColor} for the adventure equivalent of pre-defined text colors + */ ++@Deprecated // Paper + public enum ChatColor { + /** + * Represents black +diff --git a/src/main/java/org/bukkit/JukeboxSong.java b/src/main/java/org/bukkit/JukeboxSong.java +index 5872188c2f3c610ab220a30cf60f45c1eba1b372..c6feb13c735fabbd08676fa8828ce0b9fd54da32 100644 +--- a/src/main/java/org/bukkit/JukeboxSong.java ++++ b/src/main/java/org/bukkit/JukeboxSong.java +@@ -33,4 +33,14 @@ public interface JukeboxSong extends Keyed, Translatable { + private static JukeboxSong get(@NotNull String key) { + return Registry.JUKEBOX_SONG.getOrThrow(NamespacedKey.minecraft(key)); + } ++ ++ // Paper start - adventure ++ /** ++ * @deprecated this method assumes that jukebox song description will ++ * always be a translatable component which is not guaranteed. ++ */ ++ @Override ++ @Deprecated(forRemoval = true) ++ @org.jetbrains.annotations.NotNull String getTranslationKey(); ++ // Paper end - adventure + } +diff --git a/src/main/java/org/bukkit/Keyed.java b/src/main/java/org/bukkit/Keyed.java +index 32c92621c2c15eec14c50965f5ecda00c46e6c80..e076d447da62445764a9776ee2554c077637d270 100644 +--- a/src/main/java/org/bukkit/Keyed.java ++++ b/src/main/java/org/bukkit/Keyed.java +@@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents an object which has a {@link NamespacedKey} attached to it. + */ +-public interface Keyed { ++public interface Keyed extends net.kyori.adventure.key.Keyed { // Paper -- extend Adventure Keyed + + /** + * Return the namespaced identifier for this object. +@@ -14,4 +14,16 @@ public interface Keyed { + */ + @NotNull + NamespacedKey getKey(); ++ ++ // Paper start ++ /** ++ * Returns the unique identifier for this object. ++ * ++ * @return this object's key ++ */ ++ @Override ++ default net.kyori.adventure.key.@NotNull Key key() { ++ return this.getKey(); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/Nameable.java b/src/main/java/org/bukkit/Nameable.java +index b79daa857fc686f00ac06b8851e0ab68d83ae949..45d996878ba8d314a47078589b6da59dc84d589e 100644 +--- a/src/main/java/org/bukkit/Nameable.java ++++ b/src/main/java/org/bukkit/Nameable.java +@@ -7,6 +7,30 @@ import org.jetbrains.annotations.Nullable; + */ + public interface Nameable { + ++ // Paper start ++ /** ++ * Gets the custom name. ++ * ++ *

This value has no effect on players, they will always use their real name.

++ * ++ * @return the custom name ++ */ ++ net.kyori.adventure.text.@Nullable Component customName(); ++ ++ /** ++ * Sets the custom name. ++ * ++ *

This name will be used in death messages and can be sent to the client as a nameplate over the mob.

++ * ++ *

Setting the name to {@code null} will clear it.

++ * ++ *

This value has no effect on players, they will always use their real name.

++ * ++ * @param customName the custom name to set ++ */ ++ void customName(final net.kyori.adventure.text.@Nullable Component customName); ++ // Paper end ++ + /** + * Gets the custom name on a mob or block. If there is no name this method + * will return null. +@@ -14,8 +38,10 @@ public interface Nameable { + * This value has no effect on players, they will always use their real + * name. + * ++ * @deprecated in favour of {@link #customName()} + * @return name of the mob/block or null + */ ++ @Deprecated // Paper + @Nullable + public String getCustomName(); + +@@ -28,7 +54,9 @@ public interface Nameable { + * This value has no effect on players, they will always use their real + * name. + * ++ * @deprecated in favour of {@link #customName(net.kyori.adventure.text.Component)} + * @param name the name to set + */ ++ @Deprecated // Paper + public void setCustomName(@Nullable String name); + } +diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java +index dd3c9dfde4152bd832096ac2ddbfe0d2f9204a8c..499c2293fe2eea3eaf7ede476e836704e13e5a02 100644 +--- a/src/main/java/org/bukkit/NamespacedKey.java ++++ b/src/main/java/org/bukkit/NamespacedKey.java +@@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable; + * underscores, hyphens, and forward slashes. + * + */ +-public final class NamespacedKey { ++public final class NamespacedKey implements net.kyori.adventure.key.Key { // Paper - implement Key + + /** + * The namespace representing all inbuilt keys. +@@ -130,10 +130,11 @@ public final class NamespacedKey { + + @Override + public int hashCode() { +- int hash = 5; +- hash = 47 * hash + this.namespace.hashCode(); +- hash = 47 * hash + this.key.hashCode(); +- return hash; ++ // Paper start ++ int result = this.namespace.hashCode(); ++ result = (31 * result) + this.key.hashCode(); ++ return result; ++ // Paper end + } + + @Override +@@ -141,11 +142,10 @@ public final class NamespacedKey { + if (obj == null) { + return false; + } +- if (getClass() != obj.getClass()) { +- return false; +- } +- final NamespacedKey other = (NamespacedKey) obj; +- return this.namespace.equals(other.namespace) && this.key.equals(other.key); ++ // Paper start ++ if (!(obj instanceof net.kyori.adventure.key.Key key)) return false; ++ return this.namespace.equals(key.namespace()) && this.key.equals(key.value()); ++ // Paper end + } + + @Override +@@ -248,4 +248,24 @@ public final class NamespacedKey { + public static NamespacedKey fromString(@NotNull String key) { + return fromString(key, null); + } ++ ++ // Paper start ++ @NotNull ++ @Override ++ public String namespace() { ++ return this.getNamespace(); ++ } ++ ++ @NotNull ++ @Override ++ public String value() { ++ return this.getKey(); ++ } ++ ++ @NotNull ++ @Override ++ public String asString() { ++ return this.namespace + ':' + this.key; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 1fb51550953866ec9cde931987f8cfab2acc6b9b..01f8e0811f8b337acac31819a85bb44b189b3c21 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -66,13 +66,13 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a server implementation. + */ +-public interface Server extends PluginMessageRecipient { ++public interface Server extends PluginMessageRecipient, net.kyori.adventure.audience.ForwardingAudience { // Paper + + /** + * Used for all administrative messages, such as an operator using a + * command. + *

+- * For use in {@link #broadcast(java.lang.String, java.lang.String)}. ++ * For use in {@link #broadcast(net.kyori.adventure.text.Component, java.lang.String)}. + */ + public static final String BROADCAST_CHANNEL_ADMINISTRATIVE = "bukkit.broadcast.admin"; + +@@ -80,7 +80,7 @@ public interface Server extends PluginMessageRecipient { + * Used for all announcement messages, such as informing users that a + * player has joined. + *

+- * For use in {@link #broadcast(java.lang.String, java.lang.String)}. ++ * For use in {@link #broadcast(net.kyori.adventure.text.Component, java.lang.String)}. + */ + public static final String BROADCAST_CHANNEL_USERS = "bukkit.broadcast.user"; + +@@ -356,7 +356,9 @@ public interface Server extends PluginMessageRecipient { + * + * @param message the message + * @return the number of players ++ * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public int broadcastMessage(@NotNull String message); + + /** +@@ -1053,8 +1055,33 @@ public interface Server extends PluginMessageRecipient { + * @param permission the required permission {@link Permissible + * permissibles} must have to receive the broadcast + * @return number of message recipients ++ * @deprecated in favour of {@link #broadcast(net.kyori.adventure.text.Component, String)} + */ ++ @Deprecated // Paper + public int broadcast(@NotNull String message, @NotNull String permission); ++ // Paper start ++ /** ++ * Broadcast a message to all players. ++ *

++ * This is the same as calling {@link #broadcast(net.kyori.adventure.text.Component, ++ * java.lang.String)} with the {@link #BROADCAST_CHANNEL_USERS} permission. ++ * ++ * @param message the message ++ * @return the number of players ++ */ ++ int broadcast(net.kyori.adventure.text.@NotNull Component message); ++ ++ /** ++ * Broadcasts the specified message to every user with the given ++ * permission name. ++ * ++ * @param message message to broadcast ++ * @param permission the required permission {@link Permissible ++ * permissibles} must have to receive the broadcast ++ * @return number of message recipients ++ */ ++ int broadcast(net.kyori.adventure.text.@NotNull Component message, @NotNull String permission); ++ // Paper end + + /** + * Gets the player by the given name, regardless if they are offline or +@@ -1271,6 +1298,35 @@ public interface Server extends PluginMessageRecipient { + @NotNull + Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type); + ++ // Paper start ++ /** ++ * Creates an empty inventory with the specified type and title. If the type ++ * is {@link InventoryType#CHEST}, the new inventory has a size of 27; ++ * otherwise the new inventory has the normal size for its type.
++ * It should be noted that some inventory types do not support titles and ++ * may not render with said titles on the Minecraft client. ++ *
++ * {@link InventoryType#WORKBENCH} will not process crafting recipes if ++ * created with this method. Use ++ * {@link Player#openWorkbench(Location, boolean)} instead. ++ *
++ * {@link InventoryType#ENCHANTING} will not process {@link ItemStack}s ++ * for possible enchanting results. Use ++ * {@link Player#openEnchanting(Location, boolean)} instead. ++ * ++ * @param owner The holder of the inventory; can be null if there's no holder. ++ * @param type The type of inventory to create. ++ * @param title The title of the inventory, to be displayed when it is viewed. ++ * @return The new inventory. ++ * @throws IllegalArgumentException if the {@link InventoryType} cannot be ++ * viewed. ++ * ++ * @see InventoryType#isCreatable() ++ */ ++ @NotNull ++ Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, net.kyori.adventure.text.@NotNull Component title); ++ // Paper end ++ + /** + * Creates an empty inventory with the specified type and title. If the type + * is {@link InventoryType#CHEST}, the new inventory has a size of 27; +@@ -1292,9 +1348,11 @@ public interface Server extends PluginMessageRecipient { + * @return The new inventory. + * @throws IllegalArgumentException if the {@link InventoryType} cannot be + * viewed. ++ * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} + * + * @see InventoryType#isCreatable() + */ ++ @Deprecated // Paper + @NotNull + Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull String title); + +@@ -1310,6 +1368,22 @@ public interface Server extends PluginMessageRecipient { + @NotNull + Inventory createInventory(@Nullable InventoryHolder owner, int size) throws IllegalArgumentException; + ++ // Paper start ++ /** ++ * Creates an empty inventory of type {@link InventoryType#CHEST} with the ++ * specified size and title. ++ * ++ * @param owner the holder of the inventory, or null to indicate no holder ++ * @param size a multiple of 9 as the size of inventory to create ++ * @param title the title of the inventory, displayed when inventory is ++ * viewed ++ * @return a new inventory ++ * @throws IllegalArgumentException if the size is not a multiple of 9 ++ */ ++ @NotNull ++ Inventory createInventory(@Nullable InventoryHolder owner, int size, net.kyori.adventure.text.@NotNull Component title) throws IllegalArgumentException; ++ // Paper end ++ + /** + * Creates an empty inventory of type {@link InventoryType#CHEST} with the + * specified size and title. +@@ -1320,18 +1394,32 @@ public interface Server extends PluginMessageRecipient { + * viewed + * @return a new inventory + * @throws IllegalArgumentException if the size is not a multiple of 9 ++ * @deprecated in favour of {@link #createInventory(InventoryHolder, int, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + @NotNull + Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException; + ++ // Paper start ++ /** ++ * Creates an empty merchant. ++ * ++ * @param title the title of the corresponding merchant inventory, displayed ++ * when the merchant inventory is viewed ++ * @return a new merchant ++ */ ++ @NotNull Merchant createMerchant(net.kyori.adventure.text.@Nullable Component title); ++ // Paper start + /** + * Creates an empty merchant. + * + * @param title the title of the corresponding merchant inventory, displayed + * when the merchant inventory is viewed + * @return a new merchant ++ * @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)} + */ + @NotNull ++ @Deprecated // Paper + Merchant createMerchant(@Nullable String title); + + /** +@@ -1427,19 +1515,46 @@ public interface Server extends PluginMessageRecipient { + */ + boolean isPrimaryThread(); + ++ // Paper start ++ /** ++ * Gets the message that is displayed on the server list. ++ * ++ * @return the server's MOTD ++ */ ++ net.kyori.adventure.text.@NotNull Component motd(); ++ ++ /** ++ * Set the message that is displayed on the server list. ++ * ++ * @param motd The message to be displayed ++ */ ++ void motd(final net.kyori.adventure.text.@NotNull Component motd); ++ ++ /** ++ * Gets the default message that is displayed when the server is stopped. ++ * ++ * @return the shutdown message ++ */ ++ net.kyori.adventure.text.@Nullable Component shutdownMessage(); ++ // Paper end ++ + /** + * Gets the message that is displayed on the server list. + * + * @return the servers MOTD ++ * @deprecated in favour of {@link #motd()} + */ + @NotNull ++ @Deprecated // Paper + String getMotd(); + + /** + * Set the message that is displayed on the server list. + * + * @param motd The message to be displayed ++ * @deprecated in favour of {@link #motd(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + void setMotd(@NotNull String motd); + + /** +@@ -1455,8 +1570,10 @@ public interface Server extends PluginMessageRecipient { + * Gets the default message that is displayed when the server is stopped. + * + * @return the shutdown message ++ * @deprecated in favour of {@link #shutdownMessage()} + */ + @Nullable ++ @Deprecated // Paper + String getShutdownMessage(); + + /** +@@ -1865,7 +1982,9 @@ public interface Server extends PluginMessageRecipient { + * Sends the component to the player + * + * @param component the components to send ++ * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -1874,7 +1993,9 @@ public interface Server extends PluginMessageRecipient { + * Sends an array of components as a single message to the player + * + * @param components the components to send ++ * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { + throw new UnsupportedOperationException("Not supported yet."); + } +diff --git a/src/main/java/org/bukkit/ServerLinks.java b/src/main/java/org/bukkit/ServerLinks.java +index 18a53194483410c4d5ad35f901c90d44efaeef60..aff43d77f31d81b82e5fc5fea6272dda24506562 100644 +--- a/src/main/java/org/bukkit/ServerLinks.java ++++ b/src/main/java/org/bukkit/ServerLinks.java +@@ -50,13 +50,27 @@ public interface ServerLinks { + @NotNull + ServerLink addLink(@NotNull Type type, @NotNull URI url); + ++ // Paper start - Adventure ++ /** ++ * Adds the given link to the list of links. ++ * ++ * @param displayName link name / display text Component ++ * @param url link url ++ * @return the added link ++ */ ++ @NotNull ++ ServerLink addLink(@NotNull net.kyori.adventure.text.Component displayName, @NotNull URI url); ++ // Paper end - Adventure ++ + /** + * Adds the given link to the list of links. + * + * @param displayName link name / display text + * @param url link url + * @return the added link ++ * @deprecated in favour of {@link ServerLinks#addLink(net.kyori.adventure.text.Component, URI)} + */ ++ @Deprecated // Paper - Adventure + @NotNull + ServerLink addLink(@NotNull String displayName, @NotNull URI url); + +@@ -89,11 +103,23 @@ public interface ServerLinks { + @Nullable + Type getType(); + ++ // Paper start - Adventure ++ /** ++ * Gets the display name/text Component of this link. ++ * ++ * @return display name Component ++ */ ++ @NotNull ++ net.kyori.adventure.text.Component displayName(); ++ // Paper end - Adventure ++ + /** + * Gets the display name/text of this link. + * + * @return display name ++ * @deprecated in favour of {@link ServerLink#displayName()} + */ ++ @Deprecated // Paper - Adventure + @NotNull + String getDisplayName(); + +diff --git a/src/main/java/org/bukkit/Sound.java b/src/main/java/org/bukkit/Sound.java +index fab510afe4fa67d3171e23d739765095916197cb..779fd6dd572dea41e7e22464c9c6068a0fb71b9d 100644 +--- a/src/main/java/org/bukkit/Sound.java ++++ b/src/main/java/org/bukkit/Sound.java +@@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull; + * guarantee values will not be removed from this interface. As such, you should not + * depend on the ordinal values of this class. + */ +-public interface Sound extends OldEnum, Keyed { ++public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound.Sound.Type { // Paper - implement Sound.Type + + Sound AMBIENT_BASALT_DELTAS_ADDITIONS = getSound("ambient.basalt_deltas.additions"); + Sound AMBIENT_BASALT_DELTAS_LOOP = getSound("ambient.basalt_deltas.loop"); +@@ -1713,4 +1713,11 @@ public interface Sound extends OldEnum, Keyed { + static Sound[] values() { + return Lists.newArrayList(Registry.SOUNDS).toArray(new Sound[0]); + } ++ ++ // Paper start ++ @Override ++ default net.kyori.adventure.key.@NotNull Key key() { ++ return this.getKey(); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/SoundCategory.java b/src/main/java/org/bukkit/SoundCategory.java +index ac5e263d737973af077e3406a84a84baca4370db..2d91924b7f5ef16a91d40cdc1bfc3d68e0fda38d 100644 +--- a/src/main/java/org/bukkit/SoundCategory.java ++++ b/src/main/java/org/bukkit/SoundCategory.java +@@ -3,7 +3,7 @@ package org.bukkit; + /** + * An Enum of categories for sounds. + */ +-public enum SoundCategory { ++public enum SoundCategory implements net.kyori.adventure.sound.Sound.Source.Provider { // Paper - implement Sound.Source.Provider + + MASTER, + MUSIC, +@@ -15,4 +15,22 @@ public enum SoundCategory { + PLAYERS, + AMBIENT, + VOICE; ++ ++ // Paper start - implement Sound.Source.Provider ++ @Override ++ public net.kyori.adventure.sound.Sound.@org.jetbrains.annotations.NotNull Source soundSource() { ++ return switch (this) { ++ case MASTER -> net.kyori.adventure.sound.Sound.Source.MASTER; ++ case MUSIC -> net.kyori.adventure.sound.Sound.Source.MUSIC; ++ case RECORDS -> net.kyori.adventure.sound.Sound.Source.RECORD; ++ case WEATHER -> net.kyori.adventure.sound.Sound.Source.WEATHER; ++ case BLOCKS -> net.kyori.adventure.sound.Sound.Source.BLOCK; ++ case HOSTILE -> net.kyori.adventure.sound.Sound.Source.HOSTILE; ++ case NEUTRAL -> net.kyori.adventure.sound.Sound.Source.NEUTRAL; ++ case PLAYERS -> net.kyori.adventure.sound.Sound.Source.PLAYER; ++ case AMBIENT -> net.kyori.adventure.sound.Sound.Source.AMBIENT; ++ case VOICE -> net.kyori.adventure.sound.Sound.Source.VOICE; ++ }; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index ea786130380315660a60830e9c4d00b1ccc8bb70..89d5def8c1dcdab0a9e2d1809badcbbd112c3d9c 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -31,6 +31,15 @@ import org.jetbrains.annotations.Nullable; + */ + @Deprecated(since = "1.7.2") + public interface UnsafeValues { ++ // Paper start ++ net.kyori.adventure.text.flattener.ComponentFlattener componentFlattener(); ++ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.plain.PlainComponentSerializer plainComponentSerializer(); ++ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer plainTextSerializer(); ++ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.gson.GsonComponentSerializer gsonComponentSerializer(); ++ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.gson.GsonComponentSerializer colorDownsamplingGsonComponentSerializer(); ++ @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer legacyComponentSerializer(); ++ net.kyori.adventure.text.Component resolveWithContext(net.kyori.adventure.text.Component component, org.bukkit.command.CommandSender context, org.bukkit.entity.Entity scoreboardSubject, boolean bypassPermissions) throws java.io.IOException; ++ // Paper end + + Material toLegacy(Material material); + +diff --git a/src/main/java/org/bukkit/Warning.java b/src/main/java/org/bukkit/Warning.java +index 0208fc2bcd5c99c60b37419b92248db76681fc1e..5c1dda6888561a7eba0fbf9ba6ca7d7fe856eb53 100644 +--- a/src/main/java/org/bukkit/Warning.java ++++ b/src/main/java/org/bukkit/Warning.java +@@ -68,6 +68,7 @@ public @interface Warning { + * + */ + public boolean printFor(@Nullable Warning warning) { ++ if (Boolean.getBoolean("paper.alwaysPrintWarningState")) return true; // Paper + if (this == DEFAULT) { + return warning == null || warning.value(); + } +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 55cfe19be7a6f4ffa8cc31f6fbfffb592d96a085..ed87e82eb0e30bdea6f7760bb80addcb3bbe59cc 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -47,7 +47,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a world, which may contain entities, chunks and blocks + */ +-public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, Keyed { ++public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, Keyed, net.kyori.adventure.audience.ForwardingAudience { // Paper + + /** + * Gets the {@link Block} at the given coordinates +@@ -644,6 +644,14 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @NotNull + public List getPlayers(); + ++ // Paper start ++ @NotNull ++ @Override ++ default Iterable audiences() { ++ return this.getPlayers(); ++ } ++ // Paper end ++ + /** + * Returns a list of entities within a bounding box centered around a + * Location. +diff --git a/src/main/java/org/bukkit/block/CommandBlock.java b/src/main/java/org/bukkit/block/CommandBlock.java +index 372c0bd5a4d7800a11c24c95e39fe376a96232bf..9c88be68b4f403d0500cb607394b3a1646675ef7 100644 +--- a/src/main/java/org/bukkit/block/CommandBlock.java ++++ b/src/main/java/org/bukkit/block/CommandBlock.java +@@ -33,7 +33,9 @@ public interface CommandBlock extends TileState { + * by default is "@". + * + * @return Name of this CommandBlock. ++ * @deprecated in favour of {@link #name()} + */ ++ @Deprecated // Paper + @NotNull + public String getName(); + +@@ -43,6 +45,28 @@ public interface CommandBlock extends TileState { + * same as setting it to "@". + * + * @param name New name for this CommandBlock. ++ * @deprecated in favour of {@link #name(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setName(@Nullable String name); ++ ++ // Paper start ++ /** ++ * Gets the name of this CommandBlock. The name is used with commands ++ * that this CommandBlock executes. This name will never be null, and ++ * by default is a {@link net.kyori.adventure.text.TextComponent} containing {@code @}. ++ * ++ * @return Name of this CommandBlock. ++ */ ++ public net.kyori.adventure.text.@NotNull Component name(); ++ ++ /** ++ * Sets the name of this CommandBlock. The name is used with commands ++ * that this CommandBlock executes. Setting the name to null is the ++ * same as setting it to a {@link net.kyori.adventure.text.TextComponent} containing {@code @}. ++ * ++ * @param name New name for this CommandBlock. ++ */ ++ public void name(net.kyori.adventure.text.@Nullable Component name); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/block/Sign.java b/src/main/java/org/bukkit/block/Sign.java +index 5aa7148dd24009564f1e6f07007a7a921eec6a39..be36f722c7e465fae09ae7c99d92bfa032b66cc3 100644 +--- a/src/main/java/org/bukkit/block/Sign.java ++++ b/src/main/java/org/bukkit/block/Sign.java +@@ -12,12 +12,51 @@ import org.jetbrains.annotations.Nullable; + * Represents a captured state of either a SignPost or a WallSign. + */ + public interface Sign extends TileState, Colorable { ++ // Paper start ++ /** ++ * Gets all the lines of text currently on the {@link Side#FRONT} of this sign. ++ * ++ * @return List of components containing each line of text ++ * @deprecated A sign may have multiple writable sides now. Use {@link Sign#getSide(Side)} and {@link SignSide#lines()}. ++ */ ++ @NotNull ++ @Deprecated ++ public java.util.List lines(); ++ ++ /** ++ * Gets the line of text at the specified index on the {@link Side#FRONT}. ++ *

++ * For example, getLine(0) will return the first line of text. ++ * ++ * @param index Line number to get the text from, starting at 0 ++ * @throws IndexOutOfBoundsException Thrown when the line does not exist ++ * @return Text on the given line ++ * @deprecated A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#line(int)}. ++ */ ++ @NotNull ++ @Deprecated ++ public net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException; ++ ++ /** ++ * Sets the line of text at the specified index on the {@link Side#FRONT}. ++ *

++ * For example, setLine(0, "Line One") will set the first line of text to ++ * "Line One". ++ * ++ * @param index Line number to set the text at, starting from 0 ++ * @param line New text to set at the specified index ++ * @throws IndexOutOfBoundsException If the index is out of the range 0..3 ++ * @deprecated A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#line(int, net.kyori.adventure.text.Component)}. ++ */ ++ @Deprecated ++ public void line(int index, net.kyori.adventure.text.@NotNull Component line) throws IndexOutOfBoundsException; ++ // Paper end + + /** + * Gets all the lines of text currently on the {@link Side#FRONT} of this sign. + * + * @return Array of Strings containing each line of text +- * @deprecated A sign may have multiple writable sides now. Use {@link Sign#getSide(Side)} and {@link SignSide#getLines()}. ++ * @deprecated A sign may have multiple writable sides now. Use {@link Sign#getSide(Side)} and {@link SignSide#lines()}. + */ + @Deprecated(since = "1.20") + @NotNull +@@ -31,7 +70,7 @@ public interface Sign extends TileState, Colorable { + * @param index Line number to get the text from, starting at 0 + * @return Text on the given line + * @throws IndexOutOfBoundsException Thrown when the line does not exist +- * @deprecated A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#getLine(int)}. ++ * @deprecated A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#line(int)}. + */ + @Deprecated(since = "1.20") + @NotNull +@@ -46,7 +85,7 @@ public interface Sign extends TileState, Colorable { + * @param index Line number to set the text at, starting from 0 + * @param line New text to set at the specified index + * @throws IndexOutOfBoundsException If the index is out of the range 0..3 +- * @deprecated A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#setLine(int, String)}. ++ * @deprecated A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#line(int, net.kyori.adventure.text.Component)}. + */ + @Deprecated(since = "1.20") + public void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException; +diff --git a/src/main/java/org/bukkit/block/sign/SignSide.java b/src/main/java/org/bukkit/block/sign/SignSide.java +index 0f4ae7bd2ad379b5edb40f49f93de9e18c38f415..575e545a69b5279b90067d7ebee08b7b59288496 100644 +--- a/src/main/java/org/bukkit/block/sign/SignSide.java ++++ b/src/main/java/org/bukkit/block/sign/SignSide.java +@@ -7,13 +7,48 @@ import org.jetbrains.annotations.NotNull; + * Represents a side of a sign. + */ + public interface SignSide extends Colorable { ++ // Paper start ++ /** ++ * Gets all the lines of text currently on the sign. ++ * ++ * @return List of components containing each line of text ++ */ ++ @NotNull ++ public java.util.List lines(); ++ ++ /** ++ * Gets the line of text at the specified index. ++ *

++ * For example, getLine(0) will return the first line of text. ++ * ++ * @param index Line number to get the text from, starting at 0 ++ * @throws IndexOutOfBoundsException Thrown when the line does not exist ++ * @return Text on the given line ++ */ ++ @NotNull ++ public net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException; ++ ++ /** ++ * Sets the line of text at the specified index. ++ *

++ * For example, setLine(0, "Line One") will set the first line of text to ++ * "Line One". ++ * ++ * @param index Line number to set the text at, starting from 0 ++ * @param line New text to set at the specified index ++ * @throws IndexOutOfBoundsException If the index is out of the range 0..3 ++ */ ++ public void line(int index, net.kyori.adventure.text.@NotNull Component line) throws IndexOutOfBoundsException; ++ // Paper end + + /** + * Gets all the lines of text currently on this side of the sign. + * + * @return Array of Strings containing each line of text ++ * @deprecated in favour of {@link #lines()} + */ + @NotNull ++ @Deprecated // Paper + public String[] getLines(); + + /** +@@ -24,8 +59,10 @@ public interface SignSide extends Colorable { + * @param index Line number to get the text from, starting at 0 + * @return Text on the given line + * @throws IndexOutOfBoundsException Thrown when the line does not exist ++ * @deprecated in favour of {@link #line(int)} + */ + @NotNull ++ @Deprecated // Paper + public String getLine(int index) throws IndexOutOfBoundsException; + + /** +@@ -37,7 +74,9 @@ public interface SignSide extends Colorable { + * @param index Line number to set the text at, starting from 0 + * @param line New text to set at the specified index + * @throws IndexOutOfBoundsException If the index is out of the range 0..3 ++ * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException; + + /** +diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java +index 9019ebeefc9492d7c982b09fc9438d58c4233df0..6686d025222dc50156347a1757c88da02f882eec 100644 +--- a/src/main/java/org/bukkit/command/Command.java ++++ b/src/main/java/org/bukkit/command/Command.java +@@ -32,7 +32,7 @@ public abstract class Command { + protected String description; + protected String usageMessage; + private String permission; +- private String permissionMessage; ++ private net.kyori.adventure.text.Component permissionMessage; // Paper + public org.spigotmc.CustomTimingsHandler timings; // Spigot + + protected Command(@NotNull String name) { +@@ -186,10 +186,10 @@ public abstract class Command { + + if (permissionMessage == null) { + target.sendMessage(ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is a mistake."); +- } else if (permissionMessage.length() != 0) { +- for (String line : permissionMessage.replace("", permission).split("\n")) { +- target.sendMessage(line); +- } ++ // Paper start - use components for permissionMessage ++ } else if (!permissionMessage.equals(net.kyori.adventure.text.Component.empty())) { ++ target.sendMessage(permissionMessage.replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("").replacement(permission).build())); ++ // Paper end + } + + return false; +@@ -327,7 +327,7 @@ public abstract class Command { + @Deprecated(since = "1.20.4") + @Nullable + public String getPermissionMessage() { +- return permissionMessage; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serializeOrNull(permissionMessage); // Paper + } + + /** +@@ -398,7 +398,7 @@ public abstract class Command { + @Deprecated(since = "1.20.4") + @NotNull + public Command setPermissionMessage(@Nullable String permissionMessage) { +- this.permissionMessage = permissionMessage; ++ this.permissionMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(permissionMessage); // Paper + return this; + } + +@@ -413,13 +413,61 @@ public abstract class Command { + this.usageMessage = (usage == null) ? "" : usage; + return this; + } ++ // Paper start ++ /** ++ * Gets the permission message. ++ * ++ * @return the permission message ++ * @deprecated permission messages have not worked for player-executed ++ * commands since 1.13 as clients without permission to execute a command ++ * are unaware of its existence and therefore will not send an unknown ++ * command execution to the server. This message will only ever be shown to ++ * consoles or when this command is executed with ++ * {@link Bukkit#dispatchCommand(CommandSender, String)}. ++ */ ++ @Deprecated ++ public net.kyori.adventure.text.@Nullable Component permissionMessage() { ++ return this.permissionMessage; ++ } ++ ++ /** ++ * Sets the permission message. ++ * ++ * @param permissionMessage the permission message ++ * @deprecated permission messages have not worked for player-executed ++ * commands since 1.13 as clients without permission to execute a command ++ * are unaware of its existence and therefore will not send an unknown ++ * command execution to the server. This message will only ever be shown to ++ * consoles or when this command is executed with ++ * {@link Bukkit#dispatchCommand(CommandSender, String)}. ++ */ ++ @Deprecated ++ public void permissionMessage(net.kyori.adventure.text.@Nullable Component permissionMessage) { ++ this.permissionMessage = permissionMessage; ++ } ++ // Paper end + + public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull String message) { + broadcastCommandMessage(source, message, true); + } + + public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull String message, boolean sendToSource) { +- String result = source.getName() + ": " + message; ++ // Paper start ++ broadcastCommandMessage(source, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message), sendToSource); ++ } ++ ++ public static void broadcastCommandMessage(@NotNull CommandSender source, net.kyori.adventure.text.@NotNull Component message) { ++ broadcastCommandMessage(source, message, true); ++ } ++ ++ public static void broadcastCommandMessage(@NotNull CommandSender source, net.kyori.adventure.text.@NotNull Component message, boolean sendToSource) { ++ net.kyori.adventure.text.TextComponent.Builder result = net.kyori.adventure.text.Component.text() ++ .color(net.kyori.adventure.text.format.NamedTextColor.WHITE) ++ .decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false) ++ .append(source.name()) ++ .append(net.kyori.adventure.text.Component.text(": ")) ++ .append(message); ++ // Paper end + + if (source instanceof BlockCommandSender) { + BlockCommandSender blockCommandSender = (BlockCommandSender) source; +@@ -438,7 +486,12 @@ public abstract class Command { + } + + Set users = Bukkit.getPluginManager().getPermissionSubscriptions(Server.BROADCAST_CHANNEL_ADMINISTRATIVE); +- String colored = ChatColor.GRAY + "" + ChatColor.ITALIC + "[" + result + ChatColor.GRAY + ChatColor.ITALIC + "]"; ++ // Paper start ++ net.kyori.adventure.text.TextComponent.Builder colored = net.kyori.adventure.text.Component.text() ++ .color(net.kyori.adventure.text.format.NamedTextColor.GRAY) ++ .decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC) ++ .append(net.kyori.adventure.text.Component.text("["), result, net.kyori.adventure.text.Component.text("]")); ++ // Paper end + + if (sendToSource && !(source instanceof ConsoleCommandSender)) { + source.sendMessage(message); +diff --git a/src/main/java/org/bukkit/command/CommandSender.java b/src/main/java/org/bukkit/command/CommandSender.java +index 284be63a125624a8ae43d2c164aede810ce6bfe5..70fec73328227725f519af845ecbdce8be2fa4e2 100644 +--- a/src/main/java/org/bukkit/command/CommandSender.java ++++ b/src/main/java/org/bukkit/command/CommandSender.java +@@ -6,20 +6,28 @@ import org.bukkit.permissions.Permissible; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +-public interface CommandSender extends Permissible { ++public interface CommandSender extends net.kyori.adventure.audience.Audience, Permissible { // Paper + + /** + * Sends this sender a message + * + * @param message Message to be displayed ++ * @see #sendMessage(net.kyori.adventure.text.Component) ++ * @see #sendPlainMessage(String) ++ * @see #sendRichMessage(String) + */ ++ @org.jetbrains.annotations.ApiStatus.Obsolete // Paper + public void sendMessage(@NotNull String message); + + /** + * Sends this sender multiple messages + * + * @param messages An array of messages to be displayed ++ * @see #sendMessage(net.kyori.adventure.text.Component) ++ * @see #sendPlainMessage(String) ++ * @see #sendRichMessage(String) + */ ++ @org.jetbrains.annotations.ApiStatus.Obsolete // Paper + public void sendMessage(@NotNull String... messages); + + /** +@@ -27,7 +35,10 @@ public interface CommandSender extends Permissible { + * + * @param message Message to be displayed + * @param sender The sender of this message ++ * @see #sendMessage(net.kyori.adventure.identity.Identified, net.kyori.adventure.text.Component) ++ * @deprecated sender UUID is ignored + */ ++ @Deprecated // Paper + public void sendMessage(@Nullable UUID sender, @NotNull String message); + + /** +@@ -35,7 +46,10 @@ public interface CommandSender extends Permissible { + * + * @param messages An array of messages to be displayed + * @param sender The sender of this message ++ * @see #sendMessage(net.kyori.adventure.identity.Identified, net.kyori.adventure.text.Component) ++ * @deprecated sender UUID is ignored + */ ++ @Deprecated // Paper + public void sendMessage(@Nullable UUID sender, @NotNull String... messages); + + /** +@@ -61,7 +75,9 @@ public interface CommandSender extends Permissible { + * Sends this sender a chat component. + * + * @param component the components to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} + */ ++ @Deprecated // Paper + public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -70,7 +86,9 @@ public interface CommandSender extends Permissible { + * Sends an array of components as a single message to the sender. + * + * @param components the components to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} + */ ++ @Deprecated // Paper + public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -80,7 +98,9 @@ public interface CommandSender extends Permissible { + * + * @param component the components to send + * @param sender the sender of the message ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} + */ ++ @Deprecated // Paper + public void sendMessage(@Nullable UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent component) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -90,7 +110,9 @@ public interface CommandSender extends Permissible { + * + * @param components the components to send + * @param sender the sender of the message ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} + */ ++ @Deprecated // Paper + public void sendMessage(@Nullable UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -99,4 +121,52 @@ public interface CommandSender extends Permissible { + @NotNull + Spigot spigot(); + // Spigot end ++ ++ // Paper start ++ /** ++ * Gets the name of this command sender ++ * ++ * @return Name of the sender ++ */ ++ public net.kyori.adventure.text.@NotNull Component name(); ++ ++ @Override ++ default void sendMessage(final net.kyori.adventure.identity.@NotNull Identity identity, final net.kyori.adventure.text.@NotNull Component message, final net.kyori.adventure.audience.@NotNull MessageType type) { ++ this.sendMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); ++ } ++ ++ /** ++ * Sends a message with the MiniMessage format to the command sender. ++ *

++ * See MiniMessage docs ++ * for more information on the format. ++ * ++ * @param message MiniMessage content ++ */ ++ default void sendRichMessage(final @NotNull String message) { ++ this.sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message)); ++ } ++ ++ /** ++ * Sends a message with the MiniMessage format to the command sender. ++ *

++ * See MiniMessage docs and MiniMessage Placeholders docs ++ * for more information on the format. ++ * ++ * @param message MiniMessage content ++ * @param resolvers resolvers to use ++ */ ++ default void sendRichMessage(final @NotNull String message, final net.kyori.adventure.text.minimessage.tag.resolver.@NotNull TagResolver... resolvers) { ++ this.sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message, resolvers)); ++ } ++ ++ /** ++ * Sends a plain message to the command sender. ++ * ++ * @param message plain message ++ */ ++ default void sendPlainMessage(final @NotNull String message) { ++ this.sendMessage(net.kyori.adventure.text.Component.text(message)); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/command/PluginCommandYamlParser.java b/src/main/java/org/bukkit/command/PluginCommandYamlParser.java +index a542c4bb3c973bbe4b976642feccde6a4d90cb7b..ef870b864c1e36032b54b31f3f85707edc06d764 100644 +--- a/src/main/java/org/bukkit/command/PluginCommandYamlParser.java ++++ b/src/main/java/org/bukkit/command/PluginCommandYamlParser.java +@@ -67,7 +67,7 @@ public class PluginCommandYamlParser { + } + + if (permissionMessage != null) { +- newCmd.setPermissionMessage(permissionMessage.toString()); ++ newCmd.permissionMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(permissionMessage.toString())); // Paper + } + + pluginCmds.add(newCmd); +diff --git a/src/main/java/org/bukkit/command/ProxiedCommandSender.java b/src/main/java/org/bukkit/command/ProxiedCommandSender.java +index fcc34b640265f4dccb46b9f09466ab8e1d96043e..5c813ac024f675951159a59d88d8baa0d49840e9 100644 +--- a/src/main/java/org/bukkit/command/ProxiedCommandSender.java ++++ b/src/main/java/org/bukkit/command/ProxiedCommandSender.java +@@ -3,7 +3,7 @@ package org.bukkit.command; + + import org.jetbrains.annotations.NotNull; + +-public interface ProxiedCommandSender extends CommandSender { ++public interface ProxiedCommandSender extends CommandSender, net.kyori.adventure.audience.ForwardingAudience.Single { // Paper + + /** + * Returns the CommandSender which triggered this proxied command +@@ -21,4 +21,16 @@ public interface ProxiedCommandSender extends CommandSender { + @NotNull + CommandSender getCallee(); + ++ // Paper start ++ @Override ++ default void sendMessage(final net.kyori.adventure.identity.@NotNull Identity source, final net.kyori.adventure.text.@NotNull Component message, final net.kyori.adventure.audience.@NotNull MessageType type) { ++ net.kyori.adventure.audience.ForwardingAudience.Single.super.sendMessage(source, message, type); ++ } ++ ++ @NotNull ++ @Override ++ default net.kyori.adventure.audience.Audience audience() { ++ return this.getCaller(); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/configuration/ConfigurationSection.java b/src/main/java/org/bukkit/configuration/ConfigurationSection.java +index b6b00af08f12f838411845e4f4e29e62826dfc7f..d168b1e58b4b4ad00466fab60232d516551668e0 100644 +--- a/src/main/java/org/bukkit/configuration/ConfigurationSection.java ++++ b/src/main/java/org/bukkit/configuration/ConfigurationSection.java +@@ -1058,4 +1058,98 @@ public interface ConfigurationSection { + * one line. + */ + public void setInlineComments(@NotNull String path, @Nullable List comments); ++ ++ // Paper start - add rich message component support to configuration ++ /** ++ * Gets the requested MiniMessage formatted String as Component by path. ++ *

++ * If the Component does not exist but a default value has been specified, ++ * this will return the default value. If the Component does not exist and no ++ * default value was specified, this will return null. ++ * ++ * @param path Path of the Component to get. ++ * @return Requested Component. ++ */ ++ default net.kyori.adventure.text.@Nullable Component getRichMessage(final @NotNull String path) { ++ return this.getRichMessage(path, null); ++ } ++ ++ /** ++ * Gets the requested MiniMessage formatted String as Component by path. ++ *

++ * If the Component does not exist but a default value has been specified, ++ * this will return the default value. If the Component does not exist and no ++ * default value was specified, this will return null. ++ * ++ * @param path Path of the Component to get. ++ * @param fallback component that will be used as fallback ++ * @return Requested Component. ++ */ ++ @Contract("_, !null -> !null") ++ default net.kyori.adventure.text.@Nullable Component getRichMessage(final @NotNull String path, final net.kyori.adventure.text.@Nullable Component fallback) { ++ return this.getComponent(path, net.kyori.adventure.text.minimessage.MiniMessage.miniMessage(), fallback); ++ } ++ ++ /** ++ * Sets the specified path to the given value. ++ *

++ * If value is null, the entry will be removed. Any existing entry will be ++ * replaced, regardless of what the new value is. ++ * ++ * @param path Path of the object to set. ++ * @param value New value to set the path to. ++ */ ++ default void setRichMessage(final @NotNull String path, final net.kyori.adventure.text.@Nullable Component value) { ++ this.setComponent(path, net.kyori.adventure.text.minimessage.MiniMessage.miniMessage(), value); ++ } ++ ++ /** ++ * Gets the requested formatted String as Component by path deserialized by the ComponentDecoder. ++ *

++ * If the Component does not exist but a default value has been specified, ++ * this will return the default value. If the Component does not exist and no ++ * default value was specified, this will return null. ++ * ++ * @param path Path of the Component to get. ++ * @param decoder ComponentDecoder instance used for deserialization ++ * @return Requested Component. ++ */ ++ default @Nullable C getComponent(final @NotNull String path, final net.kyori.adventure.text.serializer.@NotNull ComponentDecoder decoder) { ++ return this.getComponent(path, decoder, null); ++ } ++ ++ /** ++ * Gets the requested formatted String as Component by path deserialized by the ComponentDecoder. ++ *

++ * If the Component does not exist but a default value has been specified, ++ * this will return the default value. If the Component does not exist and no ++ * default value was specified, this will return null. ++ * ++ * @param path Path of the Component to get. ++ * @param decoder ComponentDecoder instance used for deserialization ++ * @param fallback component that will be used as fallback ++ * @return Requested Component. ++ */ ++ @Contract("_, _, !null -> !null") ++ default @Nullable C getComponent(final @NotNull String path, final net.kyori.adventure.text.serializer.@NotNull ComponentDecoder decoder, final @Nullable C fallback) { ++ java.util.Objects.requireNonNull(decoder, "decoder"); ++ final String value = this.getString(path); ++ return decoder.deserializeOr(value, fallback); ++ } ++ ++ /** ++ * Sets the specified path to the given value. ++ *

++ * If value is null, the entry will be removed. Any existing entry will be ++ * replaced, regardless of what the new value is. ++ * ++ * @param path Path of the object to set. ++ * @param encoder the encoder used to transform the value ++ * @param value New value to set the path to. ++ */ ++ default void setComponent(final @NotNull String path, final net.kyori.adventure.text.serializer.@NotNull ComponentEncoder encoder, final @Nullable C value) { ++ java.util.Objects.requireNonNull(encoder, "encoder"); ++ this.set(path, encoder.serializeOrNull(value)); ++ } ++ // Paper end - add rich message component support to configuration + } +diff --git a/src/main/java/org/bukkit/conversations/Conversable.java b/src/main/java/org/bukkit/conversations/Conversable.java +index b7d8dd30360a38dbdc7bbce40c8e6ced7261f833..0817f2395c2b18828565435568ce651f5ba99a99 100644 +--- a/src/main/java/org/bukkit/conversations/Conversable.java ++++ b/src/main/java/org/bukkit/conversations/Conversable.java +@@ -55,6 +55,7 @@ public interface Conversable { + * + * @param message Message to be displayed + */ ++ @org.jetbrains.annotations.ApiStatus.Obsolete // Paper + public void sendRawMessage(@NotNull String message); + + /** +@@ -62,6 +63,8 @@ public interface Conversable { + * + * @param message Message to be displayed + * @param sender The sender of this message ++ * @deprecated sender UUID is ignored + */ ++ @Deprecated // Paper + public void sendRawMessage(@Nullable UUID sender, @NotNull String message); + } +diff --git a/src/main/java/org/bukkit/enchantments/Enchantment.java b/src/main/java/org/bukkit/enchantments/Enchantment.java +index e560a13a1b2f51da041aa58082800d47cf6eddae..4d8defb32544c4cb972d257f58e4eabbc14a2176 100644 +--- a/src/main/java/org/bukkit/enchantments/Enchantment.java ++++ b/src/main/java/org/bukkit/enchantments/Enchantment.java +@@ -310,6 +310,19 @@ public abstract class Enchantment implements Keyed, Translatable { + * @return True if the enchantment may be applied, otherwise False + */ + public abstract boolean canEnchantItem(@NotNull ItemStack item); ++ // Paper start ++ /** ++ * Get the name of the enchantment with its applied level. ++ *

++ * If the given {@code level} is either less than the {@link #getStartLevel()} or greater than the {@link #getMaxLevel()}, ++ * the level may not be shown in the numeral format one may otherwise expect. ++ *

++ * ++ * @param level the level of the enchantment to show ++ * @return the name of the enchantment with {@code level} applied ++ */ ++ public abstract net.kyori.adventure.text.@NotNull Component displayName(int level); ++ // Paper end + + /** + * Gets the Enchantment at the specified key +diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java +index ac3a61fb5d81c73326d3c313dc4b8b02ea322d42..865ab3d2015e114d3cac72e0e26e4086a3913b38 100644 +--- a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java ++++ b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java +@@ -20,4 +20,11 @@ public abstract class EnchantmentWrapper extends Enchantment { + public Enchantment getEnchantment() { + return this; + } ++ // Paper start ++ @NotNull ++ @Override ++ public net.kyori.adventure.text.Component displayName(int level) { ++ return getEnchantment().displayName(level); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index a4cf548b5f1e182282483a89a447a6616faf1f25..d7f95863922bf332c674d538eb187015fadae9d8 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -30,7 +30,7 @@ import org.jetbrains.annotations.Nullable; + * Not all methods are guaranteed to work/may have side effects when + * {@link #isInWorld()} is false. + */ +-public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder { ++public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder, net.kyori.adventure.text.event.HoverEventSource, net.kyori.adventure.sound.Sound.Emitter { // Paper + + /** + * Gets the entity's current position +@@ -776,4 +776,20 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + @Override + Spigot spigot(); + // Spigot end ++ ++ // Paper start ++ /** ++ * Gets the entity's display name formatted with their team prefix/suffix and ++ * the entity's default hover/click events. ++ * ++ * @return the team display name ++ */ ++ net.kyori.adventure.text.@NotNull Component teamDisplayName(); ++ ++ @NotNull ++ @Override ++ default net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { ++ return net.kyori.adventure.text.event.HoverEvent.showEntity(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowEntity.of(this.getType().getKey(), this.getUniqueId(), this.customName()))); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 299c3d4c91341b91da8675d741ba2254db337640..64d32c377d0303ed28011a5f002274de3c16b383 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -58,7 +58,41 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a player, connected or not + */ +-public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient { ++public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, net.kyori.adventure.bossbar.BossBarViewer { // Paper ++ ++ // Paper start ++ @Override ++ default net.kyori.adventure.identity.@NotNull Identity identity() { ++ return net.kyori.adventure.identity.Identity.identity(this.getUniqueId()); ++ } ++ ++ /** ++ * Gets an unmodifiable view of all known currently active bossbars. ++ *

++ * This currently only returns bossbars shown to the player via ++ * {@link #showBossBar(net.kyori.adventure.bossbar.BossBar)} and does not contain bukkit ++ * {@link org.bukkit.boss.BossBar} instances shown to the player. ++ * ++ * @return an unmodifiable view of all known currently active bossbars ++ * @since 4.14.0 ++ */ ++ @Override ++ @org.jetbrains.annotations.UnmodifiableView @NotNull Iterable activeBossBars(); ++ ++ /** ++ * Gets the "friendly" name to display of this player. ++ * ++ * @return the display name ++ */ ++ net.kyori.adventure.text.@NotNull Component displayName(); ++ ++ /** ++ * Sets the "friendly" name to display of this player. ++ * ++ * @param displayName the display name to set ++ */ ++ void displayName(final net.kyori.adventure.text.@Nullable Component displayName); ++ // Paper end + + /** + * {@inheritDoc} +@@ -75,7 +109,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * places defined by plugins. + * + * @return the friendly name ++ * @deprecated in favour of {@link #displayName()} + */ ++ @Deprecated // Paper + @NotNull + public String getDisplayName(); + +@@ -87,15 +123,50 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * places defined by plugins. + * + * @param name The new display name. ++ * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setDisplayName(@Nullable String name); + ++ // Paper start ++ /** ++ * Sets the name that is shown on the in-game player list. ++ *

++ * If the value is null, the name will be identical to {@link #getName()}. ++ * ++ * @param name new player list name ++ */ ++ void playerListName(net.kyori.adventure.text.@Nullable Component name); ++ ++ /** ++ * Gets the name that is shown on the in-game player list. ++ * ++ * @return the player list name ++ */ ++ net.kyori.adventure.text.@NotNull Component playerListName(); ++ ++ /** ++ * Gets the currently displayed player list header for this player. ++ * ++ * @return player list header or null ++ */ ++ net.kyori.adventure.text.@Nullable Component playerListHeader(); ++ ++ /** ++ * Gets the currently displayed player list footer for this player. ++ * ++ * @return player list footer or null ++ */ ++ net.kyori.adventure.text.@Nullable Component playerListFooter(); ++ // Paper end + /** + * Gets the name that is shown on the player list. + * + * @return the player list name ++ * @deprecated in favour of {@link #playerListName()} + */ + @NotNull ++ @Deprecated // Paper + public String getPlayerListName(); + + /** +@@ -104,7 +175,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * If the value is null, the name will be identical to {@link #getName()}. + * + * @param name new player list name ++ * @deprecated in favour of {@link #playerListName(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setPlayerListName(@Nullable String name); + + /** +@@ -126,7 +199,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * Gets the currently displayed player list header for this player. + * + * @return player list header or null ++ * @deprecated in favour of {@link #playerListHeader()} + */ ++ @Deprecated // Paper + @Nullable + public String getPlayerListHeader(); + +@@ -134,7 +209,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * Gets the currently displayed player list footer for this player. + * + * @return player list header or null ++ * @deprecated in favour of {@link #playerListFooter()} + */ ++ @Deprecated // Paper + @Nullable + public String getPlayerListFooter(); + +@@ -142,14 +219,18 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * Sets the currently displayed player list header for this player. + * + * @param header player list header, null for empty ++ * @deprecated in favour of {@link #sendPlayerListHeader(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setPlayerListHeader(@Nullable String header); + + /** + * Sets the currently displayed player list footer for this player. + * + * @param footer player list footer, null for empty ++ * @deprecated in favour of {@link #sendPlayerListFooter(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setPlayerListFooter(@Nullable String footer); + + /** +@@ -158,7 +239,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * + * @param header player list header, null for empty + * @param footer player list footer, null for empty ++ * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setPlayerListHeaderFooter(@Nullable String header, @Nullable String footer); + + /** +@@ -235,9 +318,25 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * Kicks player with custom kick message. + * + * @param message kick message ++ * @deprecated in favour of {@link #kick(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void kickPlayer(@Nullable String message); + ++ // Paper start ++ /** ++ * Kicks the player with the default kick message. ++ * @see #kick(net.kyori.adventure.text.Component) ++ */ ++ void kick(); ++ /** ++ * Kicks player with custom kick message. ++ * ++ * @param message kick message ++ */ ++ void kick(final net.kyori.adventure.text.@Nullable Component message); ++ // Paper end ++ + /** + * Adds this user to the {@link ProfileBanList}. If a previous ban exists, this will + * update the entry. +@@ -924,6 +1023,106 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public void sendEquipmentChange(@NotNull LivingEntity entity, @NotNull Map items); + ++ // Paper start ++ /** ++ * Send a sign change. This fakes a sign change packet for a user at ++ * a certain location. This will not actually change the world in any way. ++ * This method will use a sign at the location's block or a faked sign ++ * sent via ++ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. ++ *

++ * If the client does not have a sign at the given location it will ++ * display an error message to the user. ++ * ++ * @param loc the location of the sign ++ * @param lines the new text on the sign or null to clear it ++ * @throws IllegalArgumentException if location is null ++ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 ++ * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual ++ * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} ++ * (constructed e.g. via {@link Material#createBlockData()}) ++ */ ++ @Deprecated ++ default void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines) throws IllegalArgumentException { ++ this.sendSignChange(loc, lines, DyeColor.BLACK); ++ } ++ ++ /** ++ * Send a sign change. This fakes a sign change packet for a user at ++ * a certain location. This will not actually change the world in any way. ++ * This method will use a sign at the location's block or a faked sign ++ * sent via ++ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. ++ *

++ * If the client does not have a sign at the given location it will ++ * display an error message to the user. ++ * ++ * @param loc the location of the sign ++ * @param lines the new text on the sign or null to clear it ++ * @param dyeColor the color of the sign ++ * @throws IllegalArgumentException if location is null ++ * @throws IllegalArgumentException if dyeColor is null ++ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 ++ * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual ++ * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} ++ * (constructed e.g. via {@link Material#createBlockData()}) ++ */ ++ @Deprecated ++ default void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException { ++ this.sendSignChange(loc, lines, dyeColor, false); ++ } ++ ++ /** ++ * Send a sign change. This fakes a sign change packet for a user at ++ * a certain location. This will not actually change the world in any way. ++ * This method will use a sign at the location's block or a faked sign ++ * sent via ++ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. ++ *

++ * If the client does not have a sign at the given location it will ++ * display an error message to the user. ++ * ++ * @param loc the location of the sign ++ * @param lines the new text on the sign or null to clear it ++ * @param hasGlowingText whether the text of the sign should glow as if dyed with a glowing ink sac ++ * @throws IllegalArgumentException if location is null ++ * @throws IllegalArgumentException if dyeColor is null ++ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 ++ * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual ++ * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} ++ * (constructed e.g. via {@link Material#createBlockData()}) ++ */ ++ @Deprecated ++ default void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines, boolean hasGlowingText) throws IllegalArgumentException { ++ this.sendSignChange(loc, lines, DyeColor.BLACK, hasGlowingText); ++ } ++ ++ /** ++ * Send a sign change. This fakes a sign change packet for a user at ++ * a certain location. This will not actually change the world in any way. ++ * This method will use a sign at the location's block or a faked sign ++ * sent via ++ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. ++ *

++ * If the client does not have a sign at the given location it will ++ * display an error message to the user. ++ * ++ * @param loc the location of the sign ++ * @param lines the new text on the sign or null to clear it ++ * @param dyeColor the color of the sign ++ * @param hasGlowingText whether the text of the sign should glow as if dyed with a glowing ink sac ++ * @throws IllegalArgumentException if location is null ++ * @throws IllegalArgumentException if dyeColor is null ++ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 ++ * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual ++ * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} ++ * (constructed e.g. via {@link Material#createBlockData()}) ++ */ ++ @Deprecated ++ void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines, @NotNull DyeColor dyeColor, boolean hasGlowingText) ++ throws IllegalArgumentException; ++ // Paper end ++ + /** + * Send a sign change. This fakes a sign change packet for a user at + * a certain location. This will not actually change the world in any way. +@@ -941,7 +1140,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param lines the new text on the sign or null to clear it + * @throws IllegalArgumentException if location is null + * @throws IllegalArgumentException if lines is non-null and has a length less than 4 ++ * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual ++ * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} ++ * (constructed e.g. via {@link Material#createBlockData()}) + */ ++ @Deprecated // Paper + public void sendSignChange(@NotNull Location loc, @Nullable String[] lines) throws IllegalArgumentException; + + /** +@@ -963,7 +1166,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @throws IllegalArgumentException if location is null + * @throws IllegalArgumentException if dyeColor is null + * @throws IllegalArgumentException if lines is non-null and has a length less than 4 ++ * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual ++ * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} ++ * (constructed e.g. via {@link Material#createBlockData()}) + */ ++ @Deprecated // Paper + public void sendSignChange(@NotNull Location loc, @Nullable String[] lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException; + + /** +@@ -986,7 +1193,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @throws IllegalArgumentException if location is null + * @throws IllegalArgumentException if dyeColor is null + * @throws IllegalArgumentException if lines is non-null and has a length less than 4 ++ * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual ++ * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} ++ * (constructed e.g. via {@link Material#createBlockData()}) + */ ++ @Deprecated // Paper + public void sendSignChange(@NotNull Location loc, @Nullable String[] lines, @NotNull DyeColor dyeColor, boolean hasGlowingText) throws IllegalArgumentException; + + /** +@@ -1461,7 +1672,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @throws IllegalArgumentException Thrown if the URL is null. + * @throws IllegalArgumentException Thrown if the URL is too long. + * @deprecated Minecraft no longer uses textures packs. Instead you +- * should use {@link #setResourcePack(String)}. ++ * should use {@link #setResourcePack(UUID, String, byte[], net.kyori.adventure.text.Component, boolean)}. + */ + @Deprecated(since = "1.7.2") + public void setTexturePack(@NotNull String url); +@@ -1497,7 +1708,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @throws IllegalArgumentException Thrown if the URL is null. + * @throws IllegalArgumentException Thrown if the URL is too long. The + * length restriction is an implementation specific arbitrary value. ++ * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} + */ ++ @Deprecated // Paper - adventure + public void setResourcePack(@NotNull String url); + + /** +@@ -1529,6 +1742,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * pack correctly. + * + * ++ * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} + * @param url The URL from which the client will download the resource + * pack. The string must contain only US-ASCII characters and should + * be encoded as per RFC 1738. +@@ -1541,6 +1755,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @throws IllegalArgumentException Thrown if the hash is not 20 bytes + * long. + */ ++ @Deprecated // Paper - adventure + public void setResourcePack(@NotNull String url, @Nullable byte[] hash); + + /** +@@ -1565,12 +1780,13 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! + *

  • To remove a resource pack you can use +- * {@link #removeResourcePack(UUID)} or {@link #removeResourcePacks()}. ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. + *
  • The request is sent with empty string as the hash when the hash is + * not provided. This might result in newer versions not loading the + * pack correctly. + * + * ++ * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} + * @param url The URL from which the client will download the resource + * pack. The string must contain only US-ASCII characters and should + * be encoded as per RFC 1738. +@@ -1584,8 +1800,10 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @throws IllegalArgumentException Thrown if the hash is not 20 bytes + * long. + */ ++ @Deprecated // Paper - adventure + public void setResourcePack(@NotNull String url, @Nullable byte[] hash, @Nullable String prompt); + ++ // Paper start + /** + * Request that the player's client download and switch resource packs. + *

    +@@ -1608,7 +1826,54 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! + *

  • To remove a resource pack you can use +- * {@link #removeResourcePack(UUID)} or {@link #removeResourcePacks()}. ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. ++ *
  • The request is sent with empty string as the hash when the hash is ++ * not provided. This might result in newer versions not loading the ++ * pack correctly. ++ * ++ * ++ * @param url The URL from which the client will download the resource ++ * pack. The string must contain only US-ASCII characters and should ++ * be encoded as per RFC 1738. ++ * @param hash The sha1 hash sum of the resource pack file which is used ++ * to apply a cached version of the pack directly without downloading ++ * if it is available. Hast to be 20 bytes long! ++ * @param prompt The optional custom prompt message to be shown to client. ++ * @throws IllegalArgumentException Thrown if the URL is null. ++ * @throws IllegalArgumentException Thrown if the URL is too long. The ++ * length restriction is an implementation specific arbitrary value. ++ * @throws IllegalArgumentException Thrown if the hash is not 20 bytes ++ * long. ++ * @see #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest) ++ */ ++ default void setResourcePack(final @NotNull String url, final byte @Nullable [] hash, final net.kyori.adventure.text.@Nullable Component prompt) { ++ this.setResourcePack(url, hash, prompt, false); ++ } ++ // Paper end ++ ++ /** ++ * Request that the player's client download and switch resource packs. ++ *

    ++ * The player's client will download the new resource pack asynchronously ++ * in the background, and will automatically switch to it once the ++ * download is complete. If the client has downloaded and cached a ++ * resource pack with the same hash in the past it will not download but ++ * directly apply the cached pack. If the hash is null and the client has ++ * downloaded and cached the same resource pack in the past, it will ++ * perform a file size check against the response content to determine if ++ * the resource pack has changed and needs to be downloaded again. When ++ * this request is sent for the very first time from a given server, the ++ * client will first display a confirmation GUI to the player before ++ * proceeding with the download. ++ *

    ++ * Notes: ++ *

      ++ *
    • Players can disable server resources on their client, in which ++ * case this method will have no affect on them. Use the ++ * {@link PlayerResourcePackStatusEvent} to figure out whether or not ++ * the player loaded the pack! ++ *
    • To remove a resource pack you can use ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. + *
    • The request is sent with empty string as the hash when the hash is + * not provided. This might result in newer versions not loading the + * pack correctly. +@@ -1627,7 +1892,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * length restriction is an implementation specific arbitrary value. + * @throws IllegalArgumentException Thrown if the hash is not 20 bytes + * long. ++ * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} + */ ++ @Deprecated // Paper - adventure + public void setResourcePack(@NotNull String url, @Nullable byte[] hash, boolean force); + + /** +@@ -1652,7 +1919,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! + *
    • To remove a resource pack you can use +- * {@link #removeResourcePack(UUID)} or {@link #removeResourcePacks()}. ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. + *
    • The request is sent with empty string as the hash when the hash is + * not provided. This might result in newer versions not loading the + * pack correctly. +@@ -1672,9 +1939,61 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * length restriction is an implementation specific arbitrary value. + * @throws IllegalArgumentException Thrown if the hash is not 20 bytes + * long. ++ * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} + */ ++ @Deprecated // Paper + public void setResourcePack(@NotNull String url, @Nullable byte[] hash, @Nullable String prompt, boolean force); + ++ // Paper start ++ /** ++ * Request that the player's client download and switch resource packs. ++ *

      ++ * The player's client will download the new resource pack asynchronously ++ * in the background, and will automatically switch to it once the ++ * download is complete. If the client has downloaded and cached a ++ * resource pack with the same hash in the past it will not download but ++ * directly apply the cached pack. If the hash is null and the client has ++ * downloaded and cached the same resource pack in the past, it will ++ * perform a file size check against the response content to determine if ++ * the resource pack has changed and needs to be downloaded again. When ++ * this request is sent for the very first time from a given server, the ++ * client will first display a confirmation GUI with a custom prompt ++ * to the player before proceeding with the download. ++ *

      ++ * Notes: ++ *

        ++ *
      • Players can disable server resources on their client, in which ++ * case this method will have no affect on them. Use the ++ * {@link PlayerResourcePackStatusEvent} to figure out whether or not ++ * the player loaded the pack! ++ *
      • To remove a resource pack you can use ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. ++ *
      • The request is sent with empty string as the hash when the hash is ++ * not provided. This might result in newer versions not loading the ++ * pack correctly. ++ *
      ++ * ++ * @param url The URL from which the client will download the resource ++ * pack. The string must contain only US-ASCII characters and should ++ * be encoded as per RFC 1738. ++ * @param hash The sha1 hash sum of the resource pack file which is used ++ * to apply a cached version of the pack directly without downloading ++ * if it is available. Hast to be 20 bytes long! ++ * @param prompt The optional custom prompt message to be shown to client. ++ * @param force If true, the client will be disconnected from the server ++ * when it declines to use the resource pack. ++ * @throws IllegalArgumentException Thrown if the URL is null. ++ * @throws IllegalArgumentException Thrown if the URL is too long. The ++ * length restriction is an implementation specific arbitrary value. ++ * @throws IllegalArgumentException Thrown if the hash is not 20 bytes ++ * long. ++ * @see #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest) ++ */ ++ default void setResourcePack(final @NotNull String url, final byte @Nullable [] hash, final net.kyori.adventure.text.@Nullable Component prompt, final boolean force) { ++ this.setResourcePack(UUID.nameUUIDFromBytes(url.getBytes(java.nio.charset.StandardCharsets.UTF_8)), url, hash, prompt, force); ++ } ++ // Paper end ++ + /** + * Request that the player's client download and switch resource packs. + *

      +@@ -1697,7 +2016,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! + *

    • To remove a resource pack you can use +- * {@link #removeResourcePack(UUID)} or {@link #removeResourcePacks()}. ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. + *
    • The request is sent with empty string as the hash when the hash is + * not provided. This might result in newer versions not loading the + * pack correctly. +@@ -1718,9 +2037,60 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * length restriction is an implementation specific arbitrary value. + * @throws IllegalArgumentException Thrown if the hash is not 20 bytes + * long. ++ * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} + */ ++ @Deprecated // Paper - adventure + public void setResourcePack(@NotNull UUID id, @NotNull String url, @Nullable byte[] hash, @Nullable String prompt, boolean force); + ++ // Paper start ++ /** ++ * Request that the player's client download and switch resource packs. ++ *

      ++ * The player's client will download the new resource pack asynchronously ++ * in the background, and will automatically switch to it once the ++ * download is complete. If the client has downloaded and cached a ++ * resource pack with the same hash in the past it will not download but ++ * directly apply the cached pack. If the hash is null and the client has ++ * downloaded and cached the same resource pack in the past, it will ++ * perform a file size check against the response content to determine if ++ * the resource pack has changed and needs to be downloaded again. When ++ * this request is sent for the very first time from a given server, the ++ * client will first display a confirmation GUI to the player before ++ * proceeding with the download. ++ *

      ++ * Notes: ++ *

        ++ *
      • Players can disable server resources on their client, in which ++ * case this method will have no affect on them. Use the ++ * {@link PlayerResourcePackStatusEvent} to figure out whether or not ++ * the player loaded the pack! ++ *
      • To remove a resource pack you can use ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. ++ *
      • The request is sent with empty string as the hash when the hash is ++ * not provided. This might result in newer versions not loading the ++ * pack correctly. ++ *
      ++ * ++ * @param uuid Unique resource pack ID. ++ * @param url The URL from which the client will download the resource ++ * pack. The string must contain only US-ASCII characters and should ++ * be encoded as per RFC 1738. ++ * @param hash The sha1 hash sum of the resource pack file which is used ++ * to apply a cached version of the pack directly without downloading ++ * if it is available. Hast to be 20 bytes long! ++ * @param prompt The optional custom prompt message to be shown to client. ++ * @param force If true, the client will be disconnected from the server ++ * when it declines to use the resource pack. ++ * @throws IllegalArgumentException Thrown if the URL is null. ++ * @throws IllegalArgumentException Thrown if the URL is too long. The ++ * length restriction is an implementation specific arbitrary value. ++ * @throws IllegalArgumentException Thrown if the hash is not 20 bytes ++ * long. ++ * @see #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest) ++ */ ++ void setResourcePack(@NotNull UUID uuid, @NotNull String url, byte @Nullable [] hash, net.kyori.adventure.text.@Nullable Component prompt, boolean force); ++ // Paper end ++ + /** + * Request that the player's client download and include another resource pack. + *

      +@@ -1773,12 +2143,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * + * @param id the id of the resource pack. + * @throws IllegalArgumentException If the ID is null. ++ * @see #removeResourcePacks(UUID, UUID...) + */ + public void removeResourcePack(@NotNull UUID id); + + /** + * Request that the player's client remove all loaded resource pack sent by + * the server. ++ * @see #clearResourcePacks() + */ + public void removeResourcePacks(); + +@@ -1916,7 +2288,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * + * @param title Title text + * @param subtitle Subtitle text +- * @deprecated API behavior subject to change ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} + */ + @Deprecated(since = "1.8.7") + public void sendTitle(@Nullable String title, @Nullable String subtitle); +@@ -1935,7 +2307,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param fadeIn time in ticks for titles to fade in. Defaults to 10. + * @param stay time in ticks for titles to stay. Defaults to 70. + * @param fadeOut time in ticks for titles to fade out. Defaults to 20. ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} + */ ++ @Deprecated // Paper - Adventure + public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int stay, int fadeOut); + + /** +@@ -2210,6 +2584,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public int getClientViewDistance(); + ++ // Paper start ++ /** ++ * Gets the player's current locale. ++ * ++ * @return the player's locale ++ */ ++ @NotNull java.util.Locale locale(); ++ // Paper end + /** + * Gets the player's estimated ping in milliseconds. + * +@@ -2235,8 +2617,10 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * they wish. + * + * @return the player's locale ++ * @deprecated in favour of {@link #locale()} + */ + @NotNull ++ @Deprecated // Paper + public String getLocale(); + + /** +@@ -2288,6 +2672,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public boolean isAllowingServerListings(); + ++ // Paper start ++ @NotNull ++ @Override ++ default net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { ++ return net.kyori.adventure.text.event.HoverEvent.showEntity(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowEntity.of(this.getType().getKey(), this.getUniqueId(), this.displayName()))); ++ } ++ // Paper end ++ + // Spigot start + public class Spigot extends Entity.Spigot { + +@@ -2319,11 +2711,13 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + throw new UnsupportedOperationException("Not supported yet."); + } + ++ @Deprecated // Paper + @Override + public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { + throw new UnsupportedOperationException("Not supported yet."); + } + ++ @Deprecated // Paper + @Override + public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { + throw new UnsupportedOperationException("Not supported yet."); +@@ -2334,7 +2728,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * + * @param position the screen position + * @param component the components to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} + */ ++ @Deprecated // Paper + public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @NotNull net.md_5.bungee.api.chat.BaseComponent component) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -2344,7 +2740,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * + * @param position the screen position + * @param components the components to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} + */ ++ @Deprecated // Paper + public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -2355,7 +2753,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param position the screen position + * @param sender the sender of the message + * @param component the components to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} + */ ++ @Deprecated // Paper + public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @Nullable java.util.UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent component) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -2366,7 +2766,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param position the screen position + * @param sender the sender of the message + * @param components the components to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} + */ ++ @Deprecated // Paper + public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @Nullable java.util.UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { + throw new UnsupportedOperationException("Not supported yet."); + } +diff --git a/src/main/java/org/bukkit/entity/TextDisplay.java b/src/main/java/org/bukkit/entity/TextDisplay.java +index bbce00a6d84aaad4a0ec892ec5cb1b995a0a5a05..a8277270e81bc3d9bbc64c029fe11e3d11e1d9ac 100644 +--- a/src/main/java/org/bukkit/entity/TextDisplay.java ++++ b/src/main/java/org/bukkit/entity/TextDisplay.java +@@ -13,17 +13,37 @@ public interface TextDisplay extends Display { + * Gets the displayed text. + * + * @return the displayed text. ++ * @deprecated in favour of {@link #text()} + */ + @Nullable ++ @Deprecated // Paper + String getText(); + + /** + * Sets the displayed text. + * + * @param text the new text ++ * @deprecated in favour of {@link #text(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + void setText(@Nullable String text); + ++ // Paper start ++ /** ++ * Gets the displayed text. ++ * ++ * @return the displayed text ++ */ ++ net.kyori.adventure.text.@NotNull Component text(); ++ ++ /** ++ * Sets the displayed text. ++ * ++ * @param text the new text ++ */ ++ void text(net.kyori.adventure.text.@Nullable Component text); ++ // Paper end ++ + /** + * Gets the maximum line width before wrapping. + * +diff --git a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java +index 63c80b4ee1f7adc8a9efc3b607993104b1991f90..91cab8b13d5bba34007f124838b32a1df58c5ac7 100644 +--- a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java ++++ b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java +@@ -32,7 +32,9 @@ public interface CommandMinecart extends Minecart { + * same as setting it to "@". + * + * @param name New name for this CommandMinecart. ++ * @deprecated in favour of {@link #customName(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setName(@Nullable String name); + + } +diff --git a/src/main/java/org/bukkit/event/block/SignChangeEvent.java b/src/main/java/org/bukkit/event/block/SignChangeEvent.java +index 5cf3a7890f0e56ded53966348752615590eb16d6..e7538a863ddb2c4283a7f1c418b2beffc8d9ae35 100644 +--- a/src/main/java/org/bukkit/event/block/SignChangeEvent.java ++++ b/src/main/java/org/bukkit/event/block/SignChangeEvent.java +@@ -17,18 +17,38 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancel = false; + private final Player player; +- private final String[] lines; ++ private final java.util.List adventure$lines; // Paper + private final Side side; + ++ // Paper start ++ public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player player, @NotNull final java.util.List adventure$lines, @NotNull Side side) { ++ super(theBlock); ++ this.player = player; ++ this.adventure$lines = adventure$lines; ++ this.side = side; ++ } ++ ++ @Deprecated ++ public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player player, @NotNull final java.util.List adventure$lines) { ++ this(theBlock, player, adventure$lines, Side.FRONT); ++ } ++ // Paper end ++ + @Deprecated(since = "1.19.4") + public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player thePlayer, @NotNull final String[] theLines) { + this(theBlock, thePlayer, theLines, Side.FRONT); + } + ++ @Deprecated // Paper + public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player thePlayer, @NotNull final String[] theLines, @NotNull Side side) { + super(theBlock); + this.player = thePlayer; +- this.lines = theLines; ++ // Paper start ++ this.adventure$lines = new java.util.ArrayList<>(); ++ for (String theLine : theLines) { ++ this.adventure$lines.add(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(theLine)); ++ } ++ // Paper end + this.side = side; + } + +@@ -42,14 +62,52 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { + return player; + } + ++ // Paper start ++ /** ++ * Gets all of the lines of text from the sign involved in this event. ++ * ++ * @return the String array for the sign's lines new text ++ */ ++ public @NotNull java.util.List lines() { ++ return this.adventure$lines; ++ } ++ ++ /** ++ * Gets a single line of text from the sign involved in this event. ++ * ++ * @param index index of the line to get ++ * @return the String containing the line of text associated with the ++ * provided index ++ * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 ++ * or < 0} ++ */ ++ public net.kyori.adventure.text.@Nullable Component line(int index) throws IndexOutOfBoundsException { ++ return this.adventure$lines.get(index); ++ } ++ ++ /** ++ * Sets a single line for the sign involved in this event ++ * ++ * @param index index of the line to set ++ * @param line text to set ++ * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 ++ * or < 0} ++ */ ++ public void line(int index, net.kyori.adventure.text.@Nullable Component line) throws IndexOutOfBoundsException { ++ this.adventure$lines.set(index, line); ++ } ++ // Paper end ++ + /** + * Gets all of the lines of text from the sign involved in this event. + * + * @return the String array for the sign's lines new text ++ * @deprecated in favour of {@link #lines()} + */ + @NotNull ++ @Deprecated // Paper + public String[] getLines() { +- return lines; ++ return adventure$lines.stream().map(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()::serialize).toArray(String[]::new); // Paper + } + + /** +@@ -60,10 +118,12 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { + * provided index + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} ++ * @deprecated in favour of {@link #line(int)} + */ + @Nullable ++ @Deprecated // Paper + public String getLine(int index) throws IndexOutOfBoundsException { +- return lines[index]; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.adventure$lines.get(index)); // Paper + } + + /** +@@ -73,9 +133,11 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { + * @param line text to set + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} ++ * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setLine(int index, @Nullable String line) throws IndexOutOfBoundsException { +- lines[index] = line; ++ adventure$lines.set(index, line != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line) : null); // Paper + } + + /** +diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +index 133760be6c73436512ba684a3ac77a514b2d8765..9473303bd8ab1f6b63b6999a5f5ff3eca1cc23d6 100644 +--- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java ++++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +@@ -12,26 +12,49 @@ import org.jetbrains.annotations.Nullable; + */ + public class PlayerDeathEvent extends EntityDeathEvent { + private int newExp = 0; +- private String deathMessage = ""; ++ private net.kyori.adventure.text.Component deathMessage; // Paper - adventure + private int newLevel = 0; + private int newTotalExp = 0; + private boolean keepLevel = false; + private boolean keepInventory = false; ++ // Paper start - adventure ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public PlayerDeathEvent(final @NotNull Player player, final @NotNull DamageSource damageSource, final @NotNull List drops, final int droppedExp, final @Nullable net.kyori.adventure.text.Component deathMessage) { ++ this(player, damageSource, drops, droppedExp, 0, deathMessage); ++ } ++ ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public PlayerDeathEvent(final @NotNull Player player, final @NotNull DamageSource damageSource, final @NotNull List drops, final int droppedExp, final int newExp, final @Nullable net.kyori.adventure.text.Component deathMessage) { ++ this(player, damageSource, drops, droppedExp, newExp, 0, 0, deathMessage); ++ } ++ ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public PlayerDeathEvent(final @NotNull Player player, final @NotNull DamageSource damageSource, final @NotNull List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, final @Nullable net.kyori.adventure.text.Component deathMessage) { ++ super(player, damageSource, drops, droppedExp); ++ this.newExp = newExp; ++ this.newTotalExp = newTotalExp; ++ this.newLevel = newLevel; ++ this.deathMessage = deathMessage; ++ } ++ // Paper end - adventure + ++ @Deprecated // Paper + public PlayerDeathEvent(@NotNull final Player player, @NotNull DamageSource damageSource, @NotNull final List drops, final int droppedExp, @Nullable final String deathMessage) { + this(player, damageSource, drops, droppedExp, 0, deathMessage); + } + ++ @Deprecated // Paper + public PlayerDeathEvent(@NotNull final Player player, @NotNull DamageSource damageSource, @NotNull final List drops, final int droppedExp, final int newExp, @Nullable final String deathMessage) { + this(player, damageSource, drops, droppedExp, newExp, 0, 0, deathMessage); + } + ++ @Deprecated // Paper + public PlayerDeathEvent(@NotNull final Player player, @NotNull DamageSource damageSource, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final String deathMessage) { + super(player, damageSource, drops, droppedExp); + this.newExp = newExp; + this.newTotalExp = newTotalExp; + this.newLevel = newLevel; +- this.deathMessage = deathMessage; ++ this.deathMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(deathMessage); // Paper + } + + @NotNull +@@ -40,25 +63,49 @@ public class PlayerDeathEvent extends EntityDeathEvent { + return (Player) entity; + } + ++ // Paper start - adventure ++ /** ++ * Set the death message that will appear to everyone on the server. ++ * ++ * @param deathMessage Component message to appear to other players on the server. ++ */ ++ public void deathMessage(final net.kyori.adventure.text.@Nullable Component deathMessage) { ++ this.deathMessage = deathMessage; ++ } ++ ++ /** ++ * Get the death message that will appear to everyone on the server. ++ * ++ * @return Component message to appear to other players on the server. ++ */ ++ public net.kyori.adventure.text.@Nullable Component deathMessage() { ++ return this.deathMessage; ++ } ++ // Paper end - adventure ++ + /** + * Set the death message that will appear to everyone on the server. + * + * @param deathMessage Message to appear to other players on the server. ++ * @deprecated in favour of {@link #deathMessage(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setDeathMessage(@Nullable String deathMessage) { +- this.deathMessage = deathMessage; ++ this.deathMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(deathMessage); // Paper + } + + /** + * Get the death message that will appear to everyone on the server. + * + * @return Message to appear to other players on the server. ++ * @deprecated in favour of {@link #deathMessage()} + */ + @Nullable ++ @Deprecated // Paper + public String getDeathMessage() { +- return deathMessage; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serializeOrNull(this.deathMessage); // Paper + } +- ++ // Paper end + /** + * Gets how much EXP the Player should have at respawn. + *

      +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java +index c2af9a9832fb7c3ebb397a4c5fb8604b90216f0c..f80d5bc893efd8846365b4677ef1407158b1abc8 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java +@@ -163,7 +163,18 @@ public enum InventoryType { + private final String title; + private final MenuType menuType; + private final boolean isCreatable; ++ // Paper start ++ private final net.kyori.adventure.text.Component defaultTitleComponent; + ++ /** ++ * Gets the inventory's default title. ++ * ++ * @return the inventory's default title ++ */ ++ public net.kyori.adventure.text.@NotNull Component defaultTitle() { ++ return defaultTitleComponent; ++ } ++ // Paper end + private InventoryType(int defaultSize, /*@NotNull*/ String defaultTitle, @Nullable MenuType type) { + this(defaultSize, defaultTitle, type, true); + } +@@ -173,6 +184,7 @@ public enum InventoryType { + title = defaultTitle; + this.menuType = type; + this.isCreatable = isCreatable; ++ this.defaultTitleComponent = net.kyori.adventure.text.Component.text(defaultTitle); // Paper - Adventure + } + + public int getDefaultSize() { +@@ -180,6 +192,7 @@ public enum InventoryType { + } + + @NotNull ++ @Deprecated // Paper + public String getDefaultTitle() { + return title; + } +diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java +index 9c68c3f2d61500479f48b80264f625aaae2f3204..399afcd19fcb6acd24857ed6ab48cf0d105a01a3 100644 +--- a/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java ++++ b/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java +@@ -22,7 +22,11 @@ import org.jetbrains.annotations.NotNull; + *

      + * Care should be taken to check {@link #isAsynchronous()} and treat the event + * appropriately. ++ * ++ * @deprecated use {@link io.papermc.paper.event.player.AsyncChatEvent} instead + */ ++@Deprecated // Paper ++@org.bukkit.Warning(value = false, reason = "Don't nag on old event yet") // Paper + public class AsyncPlayerChatEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancel = false; +diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +index 23257ae3953d1aa5ba96c69485a5e3d7889ad8de..b2f32debd32f78e7df4851866a47da3ff0d1f015 100644 +--- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +@@ -10,11 +10,18 @@ import org.jetbrains.annotations.NotNull; + * Stores details for players attempting to log in. + *

      + * This event is asynchronous, and not run using main thread. ++ *

      ++ * When this event is fired, the player's locale is not ++ * available. Therefore, any translatable component will be ++ * rendered with the default locale, {@link java.util.Locale#US}. ++ *

      ++ * Consider rendering any translatable yourself with {@link net.kyori.adventure.translation.GlobalTranslator#render} ++ * if the client's language is known. + */ + public class AsyncPlayerPreLoginEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private Result result; +- private String message; ++ private net.kyori.adventure.text.Component message; // Paper + private final String name; + private final InetAddress ipAddress; + private final UUID uniqueId; +@@ -33,7 +40,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId, boolean transferred) { + super(true); + this.result = Result.ALLOWED; +- this.message = ""; ++ this.message = net.kyori.adventure.text.Component.empty(); // Paper + this.name = name; + this.ipAddress = ipAddress; + this.uniqueId = uniqueId; +@@ -86,6 +93,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + this.result = result == null ? null : Result.valueOf(result.name()); + } + ++ // Paper start + /** + * Gets the current kick message that will be used if getResult() != + * Result.ALLOWED +@@ -93,7 +101,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + * @return Current kick message + */ + @NotNull +- public String getKickMessage() { ++ public net.kyori.adventure.text.Component kickMessage() { + return message; + } + +@@ -102,16 +110,66 @@ public class AsyncPlayerPreLoginEvent extends Event { + * + * @param message New kick message + */ +- public void setKickMessage(@NotNull final String message) { ++ public void kickMessage(@NotNull final net.kyori.adventure.text.Component message) { ++ this.message = message; ++ } ++ ++ /** ++ * Disallows the player from logging in, with the given reason ++ * ++ * @param result New result for disallowing the player ++ * @param message Kick message to display to the user ++ */ ++ public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { ++ this.result = result; ++ this.message = message; ++ } ++ ++ /** ++ * Disallows the player from logging in, with the given reason ++ * ++ * @param result New result for disallowing the player ++ * @param message Kick message to display to the user ++ * @deprecated This method uses a deprecated enum from {@link ++ * PlayerPreLoginEvent} ++ * @see #disallow(Result, String) ++ */ ++ @Deprecated ++ public void disallow(@NotNull final PlayerPreLoginEvent.Result result, @NotNull final net.kyori.adventure.text.Component message) { ++ this.result = result == null ? null : Result.valueOf(result.name()); + this.message = message; + } ++ // Paper end ++ /** ++ * Gets the current kick message that will be used if getResult() != ++ * Result.ALLOWED ++ * ++ * @return Current kick message ++ * @deprecated in favour of {@link #kickMessage()} ++ */ ++ @NotNull ++ @Deprecated // Paper ++ public String getKickMessage() { ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper ++ } ++ ++ /** ++ * Sets the kick message to display if getResult() != Result.ALLOWED ++ * ++ * @param message New kick message ++ * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} ++ */ ++ @Deprecated // Paper ++ public void setKickMessage(@NotNull final String message) { ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper ++ } + + /** + * Allows the player to log in + */ + public void allow() { + result = Result.ALLOWED; +- message = ""; ++ message = net.kyori.adventure.text.Component.empty(); // Paper + } + + /** +@@ -119,10 +177,12 @@ public class AsyncPlayerPreLoginEvent extends Event { + * + * @param result New result for disallowing the player + * @param message Kick message to display to the user ++ * @deprecated in favour of {@link #disallow(org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void disallow(@NotNull final Result result, @NotNull final String message) { + this.result = result; +- this.message = message; ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + + /** +@@ -137,7 +197,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + @Deprecated(since = "1.3.2") + public void disallow(@NotNull final PlayerPreLoginEvent.Result result, @NotNull final String message) { + this.result = result == null ? null : Result.valueOf(result.name()); +- this.message = message; ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + + /** +diff --git a/src/main/java/org/bukkit/event/player/PlayerChatEvent.java b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java +index eb1018a84aac4f8265f3f848fa6f78781d85de4f..373162d96fbf65286adf35a1c32031e1ac846346 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerChatEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java +@@ -12,12 +12,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Holds information for player chat and commands + * +- * @deprecated This event will fire from the main thread and allows the use of +- * all of the Bukkit API, unlike the {@link AsyncPlayerChatEvent}. +- *

      +- * Listening to this event forces chat to wait for the main thread which +- * causes delays for chat. {@link AsyncPlayerChatEvent} is the encouraged +- * alternative for thread safe implementations. ++ * @deprecated Listening to this event forces chat to wait for the main thread, delaying chat messages. It is recommended to use {@link io.papermc.paper.event.player.AsyncChatEvent} instead, wherever possible. + */ + @Deprecated(since = "1.3.1") + @Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.") +diff --git a/src/main/java/org/bukkit/event/player/PlayerEvent.java b/src/main/java/org/bukkit/event/player/PlayerEvent.java +index 793b661b6d2d05de3d7f4fc26a4c018a2af58e62..f6d3b817de3001f04ea4554c7c39a1290af3fd6d 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerEvent.java +@@ -14,7 +14,7 @@ public abstract class PlayerEvent extends Event { + player = who; + } + +- PlayerEvent(@NotNull final Player who, boolean async) { ++ public PlayerEvent(@NotNull final Player who, boolean async) { // Paper - public + super(async); + player = who; + +diff --git a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java +index d06684aba7688ce06777dbd837a46856a9d7767f..3e1e7cd0415509da4dd887db59efa55011b1dab4 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java +@@ -10,30 +10,60 @@ import org.jetbrains.annotations.Nullable; + */ + public class PlayerJoinEvent extends PlayerEvent { + private static final HandlerList handlers = new HandlerList(); +- private String joinMessage; ++ // Paper start ++ private net.kyori.adventure.text.Component joinMessage; ++ public PlayerJoinEvent(@NotNull final Player playerJoined, @Nullable final net.kyori.adventure.text.Component joinMessage) { ++ super(playerJoined); ++ this.joinMessage = joinMessage; ++ } + ++ @Deprecated // Paper end + public PlayerJoinEvent(@NotNull final Player playerJoined, @Nullable final String joinMessage) { + super(playerJoined); ++ this.joinMessage = joinMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(joinMessage) : null; // Paper end ++ } ++ ++ // Paper start ++ /** ++ * Gets the join message to send to all online players ++ * ++ * @return string join message. Can be null ++ */ ++ public net.kyori.adventure.text.@Nullable Component joinMessage() { ++ return this.joinMessage; ++ } ++ ++ /** ++ * Sets the join message to send to all online players ++ * ++ * @param joinMessage join message. If null, no message will be sent ++ */ ++ public void joinMessage(net.kyori.adventure.text.@Nullable Component joinMessage) { + this.joinMessage = joinMessage; + } ++ // Paper end + + /** + * Gets the join message to send to all online players + * + * @return string join message. Can be null ++ * @deprecated in favour of {@link #joinMessage()} + */ + @Nullable ++ @Deprecated // Paper + public String getJoinMessage() { +- return joinMessage; ++ return this.joinMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.joinMessage); // Paper + } + + /** + * Sets the join message to send to all online players + * + * @param joinMessage join message. If null, no message will be sent ++ * @deprecated in favour of {@link #joinMessage(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setJoinMessage(@Nullable String joinMessage) { +- this.joinMessage = joinMessage; ++ this.joinMessage = joinMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(joinMessage) : null; // Paper + } + + @NotNull +diff --git a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java +index 2f6ca42330675733b2b4132cbb66e433788d05d5..997b06c19a5277656521e0e298f2958c209f1da1 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java +@@ -10,35 +10,84 @@ import org.jetbrains.annotations.NotNull; + */ + public class PlayerKickEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); +- private String leaveMessage; +- private String kickReason; ++ private net.kyori.adventure.text.Component leaveMessage; // Paper ++ private net.kyori.adventure.text.Component kickReason; // Paper + private boolean cancel; + ++ @Deprecated // Paper + public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final String kickReason, @NotNull final String leaveMessage) { ++ super(playerKicked); ++ this.kickReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(kickReason); // Paper ++ this.leaveMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(leaveMessage); // Paper ++ this.cancel = false; ++ } ++ // Paper start ++ public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final net.kyori.adventure.text.Component kickReason, @NotNull final net.kyori.adventure.text.Component leaveMessage) { + super(playerKicked); + this.kickReason = kickReason; + this.leaveMessage = leaveMessage; + this.cancel = false; + } + ++ /** ++ * Gets the leave message send to all online players ++ * ++ * @return string kick reason ++ */ ++ public net.kyori.adventure.text.@NotNull Component leaveMessage() { ++ return this.leaveMessage; ++ } ++ ++ /** ++ * Sets the leave message send to all online players ++ * ++ * @param leaveMessage leave message ++ */ ++ public void leaveMessage(net.kyori.adventure.text.@NotNull Component leaveMessage) { ++ this.leaveMessage = leaveMessage; ++ } ++ + /** + * Gets the reason why the player is getting kicked + * + * @return string kick reason + */ ++ public net.kyori.adventure.text.@NotNull Component reason() { ++ return this.kickReason; ++ } ++ ++ /** ++ * Sets the reason why the player is getting kicked ++ * ++ * @param kickReason kick reason ++ */ ++ public void reason(net.kyori.adventure.text.@NotNull Component kickReason) { ++ this.kickReason = kickReason; ++ } ++ // Paper end ++ ++ /** ++ * Gets the reason why the player is getting kicked ++ * ++ * @return string kick reason ++ * @deprecated in favour of {@link #reason()} ++ */ + @NotNull ++ @Deprecated // Paper + public String getReason() { +- return kickReason; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.kickReason); // Paper + } + + /** + * Gets the leave message send to all online players + * + * @return string kick reason ++ * @deprecated in favour of {@link #leaveMessage()} + */ + @NotNull ++ @Deprecated // Paper + public String getLeaveMessage() { +- return leaveMessage; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.leaveMessage); // Paper + } + + @Override +@@ -55,18 +104,22 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + * Sets the reason why the player is getting kicked + * + * @param kickReason kick reason ++ * @deprecated in favour of {@link #reason(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setReason(@NotNull String kickReason) { +- this.kickReason = kickReason; ++ this.kickReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(kickReason); // Paper + } + + /** + * Sets the leave message send to all online players + * + * @param leaveMessage leave message ++ * @deprecated in favour of {@link #leaveMessage(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setLeaveMessage(@NotNull String leaveMessage) { +- this.leaveMessage = leaveMessage; ++ this.leaveMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(leaveMessage); // Paper + } + + @NotNull +diff --git a/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java b/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java +index 36b436e145a7215682b692a87ab894df25752c1d..dc6b41950570c3a8b02415dd9017b2336e6e7f0c 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java +@@ -12,17 +12,31 @@ public class PlayerLocaleChangeEvent extends PlayerEvent { + private static final HandlerList handlers = new HandlerList(); + // + private final String locale; ++ // Paper start ++ private final java.util.Locale adventure$locale; ++ /** ++ * @see Player#locale() ++ * ++ * @return the player's new locale ++ */ ++ public @NotNull java.util.Locale locale() { ++ return this.adventure$locale; ++ } ++ // Paper end + + public PlayerLocaleChangeEvent(@NotNull Player who, @NotNull String locale) { + super(who); + this.locale = locale; ++ this.adventure$locale = java.util.Objects.requireNonNullElse(net.kyori.adventure.translation.Translator.parseLocale(locale), java.util.Locale.US); // Paper start + } + + /** + * @return the player's new locale + * @see Player#getLocale() ++ * @deprecated in favour of {@link #locale()} + */ + @NotNull ++ @Deprecated // Paper + public String getLocale() { + return locale; + } +diff --git a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java +index 2bc81b0aa73f7f5b0352121f6bf18fa63acf7a83..eaa0548cf430bf5b58ff84e0a4403c451699db28 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java +@@ -18,7 +18,7 @@ public class PlayerLoginEvent extends PlayerEvent { + private final InetAddress realAddress; + private final String hostname; + private Result result = Result.ALLOWED; +- private String message = ""; ++ private net.kyori.adventure.text.Component message = net.kyori.adventure.text.Component.empty(); + + /** + * This constructor defaults message to an empty string, and result to +@@ -60,13 +60,53 @@ public class PlayerLoginEvent extends PlayerEvent { + * @param result The result status for this event + * @param message The message to be displayed if result denies login + * @param realAddress the actual, unspoofed connecting address ++ * @deprecated in favour of {@link #PlayerLoginEvent(Player, String, InetAddress, Result, net.kyori.adventure.text.Component, InetAddress)} + */ ++ @Deprecated // Paper + public PlayerLoginEvent(@NotNull final Player player, @NotNull String hostname, @NotNull final InetAddress address, @NotNull final Result result, @NotNull final String message, @NotNull final InetAddress realAddress) { + this(player, hostname, address, realAddress); + this.result = result; ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper ++ } ++ ++ // Paper start ++ /** ++ * This constructor pre-configures the event with a result and message ++ * ++ * @param player The {@link Player} for this event ++ * @param hostname The hostname that was used to connect to the server ++ * @param address The address the player used to connect, provided for ++ * timing issues ++ * @param result The result status for this event ++ * @param message The message to be displayed if result denies login ++ * @param realAddress the actual, unspoofed connecting address ++ */ ++ public PlayerLoginEvent(@NotNull final Player player, @NotNull String hostname, @NotNull final InetAddress address, @NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message, @NotNull final InetAddress realAddress) { ++ this(player, hostname, address, realAddress); // Spigot ++ this.result = result; + this.message = message; + } + ++ /** ++ * Gets the current kick message that will be used if getResult() != ++ * Result.ALLOWED ++ * ++ * @return Current kick message ++ */ ++ public net.kyori.adventure.text.@NotNull Component kickMessage() { ++ return this.message; ++ } ++ ++ /** ++ * Sets the kick message to display if getResult() != Result.ALLOWED ++ * ++ * @param message New kick message ++ */ ++ public void kickMessage(net.kyori.adventure.text.@NotNull Component message) { ++ this.message = message; ++ } ++ // Paper end ++ + /** + * Gets the current result of the login, as an enum + * +@@ -91,19 +131,23 @@ public class PlayerLoginEvent extends PlayerEvent { + * Result.ALLOWED + * + * @return Current kick message ++ * @deprecated in favour of {@link #kickMessage()} + */ + @NotNull ++ @Deprecated // Paper + public String getKickMessage() { +- return message; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper + } + + /** + * Sets the kick message to display if getResult() != Result.ALLOWED + * + * @param message New kick message ++ * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setKickMessage(@NotNull final String message) { +- this.message = message; ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + + /** +@@ -122,7 +166,7 @@ public class PlayerLoginEvent extends PlayerEvent { + */ + public void allow() { + result = Result.ALLOWED; +- message = ""; ++ message = net.kyori.adventure.text.Component.empty(); // Paper + } + + /** +@@ -130,8 +174,21 @@ public class PlayerLoginEvent extends PlayerEvent { + * + * @param result New result for disallowing the player + * @param message Kick message to display to the user ++ * @deprecated in favour of {@link #disallow(Result, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper start + public void disallow(@NotNull final Result result, @NotNull final String message) { ++ this.result = result; ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); ++ } ++ /** ++ * Disallows the player from logging in, with the given reason ++ * ++ * @param result New result for disallowing the player ++ * @param message Kick message to display to the user ++ */ ++ public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { ++ // Paper end + this.result = result; + this.message = message; + } +diff --git a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java +index 203d030dbb2312a06bfb526351c1af92ddbc351a..b323212f11f831a96d87f6c9d746a90d119a3efd 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java +@@ -9,6 +9,13 @@ import org.jetbrains.annotations.NotNull; + + /** + * Stores details for players attempting to log in ++ *

      ++ * When this event is fired, the player's locale is not ++ * available. Therefore, any translatable component will be ++ * rendered with the default locale, {@link java.util.Locale#US}. ++ *

      ++ * Consider rendering any translatable yourself with {@link net.kyori.adventure.translation.GlobalTranslator#render} ++ * if the client's language is known. + * + * @deprecated This event causes synchronization from the login thread; {@link + * AsyncPlayerPreLoginEvent} is preferred to keep the secondary threads +@@ -19,7 +26,7 @@ import org.jetbrains.annotations.NotNull; + public class PlayerPreLoginEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private Result result; +- private String message; ++ private net.kyori.adventure.text.Component message; // Paper + private final String name; + private final InetAddress ipAddress; + private final UUID uniqueId; +@@ -31,7 +38,7 @@ public class PlayerPreLoginEvent extends Event { + + public PlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId) { + this.result = Result.ALLOWED; +- this.message = ""; ++ this.message = net.kyori.adventure.text.Component.empty(); // Paper + this.name = name; + this.ipAddress = ipAddress; + this.uniqueId = uniqueId; +@@ -56,6 +63,7 @@ public class PlayerPreLoginEvent extends Event { + this.result = result; + } + ++ // Paper start + /** + * Gets the current kick message that will be used if getResult() != + * Result.ALLOWED +@@ -63,7 +71,7 @@ public class PlayerPreLoginEvent extends Event { + * @return Current kick message + */ + @NotNull +- public String getKickMessage() { ++ public net.kyori.adventure.text.Component kickMessage() { + return message; + } + +@@ -72,16 +80,51 @@ public class PlayerPreLoginEvent extends Event { + * + * @param message New kick message + */ +- public void setKickMessage(@NotNull final String message) { ++ public void kickMessage(@NotNull final net.kyori.adventure.text.Component message) { + this.message = message; + } + ++ /** ++ * Disallows the player from logging in, with the given reason ++ * ++ * @param result New result for disallowing the player ++ * @param message Kick message to display to the user ++ */ ++ public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { ++ this.result = result; ++ this.message = message; ++ } ++ // Paper end ++ /** ++ * Gets the current kick message that will be used if getResult() != ++ * Result.ALLOWED ++ * ++ * @return Current kick message ++ * @deprecated in favour of {@link #kickMessage()} ++ */ ++ @Deprecated // Paper ++ @NotNull ++ public String getKickMessage() { ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper ++ } ++ ++ /** ++ * Sets the kick message to display if getResult() != Result.ALLOWED ++ * ++ * @param message New kick message ++ * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} ++ */ ++ @Deprecated // Paper ++ public void setKickMessage(@NotNull final String message) { ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper ++ } ++ + /** + * Allows the player to log in + */ + public void allow() { + result = Result.ALLOWED; +- message = ""; ++ message = net.kyori.adventure.text.Component.empty(); // Paper + } + + /** +@@ -89,10 +132,12 @@ public class PlayerPreLoginEvent extends Event { + * + * @param result New result for disallowing the player + * @param message Kick message to display to the user ++ * @deprecated in favour of {@link #disallow(org.bukkit.event.player.PlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void disallow(@NotNull final Result result, @NotNull final String message) { + this.result = result; +- this.message = message; ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + + /** +diff --git a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +index d70c25f404e994766a9ebce89a917c8d0719777c..14b27eaaf744736b3e56bb1383481df98a218c43 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +@@ -10,30 +10,59 @@ import org.jetbrains.annotations.Nullable; + */ + public class PlayerQuitEvent extends PlayerEvent { + private static final HandlerList handlers = new HandlerList(); +- private String quitMessage; ++ private net.kyori.adventure.text.Component quitMessage; // Paper + ++ @Deprecated // Paper + public PlayerQuitEvent(@NotNull final Player who, @Nullable final String quitMessage) { + super(who); ++ this.quitMessage = quitMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(quitMessage) : null; // Paper ++ } ++ // Paper start ++ public PlayerQuitEvent(@NotNull final Player who, @Nullable final net.kyori.adventure.text.Component quitMessage) { ++ super(who); ++ this.quitMessage = quitMessage; ++ } ++ ++ /** ++ * Gets the quit message to send to all online players ++ * ++ * @return string quit message ++ */ ++ public net.kyori.adventure.text.@Nullable Component quitMessage() { ++ return quitMessage; ++ } ++ ++ /** ++ * Sets the quit message to send to all online players ++ * ++ * @param quitMessage quit message ++ */ ++ public void quitMessage(net.kyori.adventure.text.@Nullable Component quitMessage) { + this.quitMessage = quitMessage; + } ++ // Paper end + + /** + * Gets the quit message to send to all online players + * + * @return string quit message ++ * @deprecated in favour of {@link #quitMessage()} + */ + @Nullable ++ @Deprecated // Paper + public String getQuitMessage() { +- return quitMessage; ++ return this.quitMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.quitMessage); // Paper + } + + /** + * Sets the quit message to send to all online players + * + * @param quitMessage quit message ++ * @deprecated in favour of {@link #quitMessage(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setQuitMessage(@Nullable String quitMessage) { +- this.quitMessage = quitMessage; ++ this.quitMessage = quitMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(quitMessage) : null; // Paper + } + + @NotNull +diff --git a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java b/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java +index 24d57cf17639f51b9557aec17a3686816542cfc6..173cdb379217d38af0df7a38e009553d0b257ea6 100644 +--- a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java ++++ b/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java +@@ -9,16 +9,16 @@ import org.jetbrains.annotations.NotNull; + + /** + * Event triggered for server broadcast messages such as from +- * {@link org.bukkit.Server#broadcast(String, String)}. ++ * {@link org.bukkit.Server#broadcast(net.kyori.adventure.text.Component)} (String, String)}. + * +- * This event behaves similarly to {@link AsyncPlayerChatEvent} in that it ++ * This event behaves similarly to {@link io.papermc.paper.event.player.AsyncChatEvent} in that it + * should be async if fired from an async thread. Please see that event for + * further information. + */ + public class BroadcastMessageEvent extends ServerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); +- private String message; ++ private net.kyori.adventure.text.Component message; // Paper + private final Set recipients; + private boolean cancelled = false; + +@@ -27,29 +27,66 @@ public class BroadcastMessageEvent extends ServerEvent implements Cancellable { + this(false, message, recipients); + } + ++ @Deprecated // Paper + public BroadcastMessageEvent(boolean isAsync, @NotNull String message, @NotNull Set recipients) { ++ // Paper start ++ super(isAsync); ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); ++ this.recipients = recipients; ++ } ++ ++ @Deprecated ++ public BroadcastMessageEvent(net.kyori.adventure.text.@NotNull Component message, @NotNull Set recipients) { ++ this(false, message, recipients); ++ } ++ ++ public BroadcastMessageEvent(boolean isAsync, net.kyori.adventure.text.@NotNull Component message, @NotNull Set recipients) { ++ // Paper end + super(isAsync); + this.message = message; + this.recipients = recipients; + } ++ // Paper start ++ /** ++ * Get the broadcast message. ++ * ++ * @return Message to broadcast ++ */ ++ public net.kyori.adventure.text.@NotNull Component message() { ++ return this.message; ++ } ++ ++ /** ++ * Set the broadcast message. ++ * ++ * @param message New message to broadcast ++ */ ++ public void message(net.kyori.adventure.text.@NotNull Component message) { ++ this.message = message; ++ } ++ // Paper end + + /** + * Get the message to broadcast. + * + * @return Message to broadcast ++ * @deprecated in favour of {@link #message()} + */ + @NotNull ++ @Deprecated // Paper + public String getMessage() { +- return message; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper + } + + /** + * Set the message to broadcast. + * + * @param message New message to broadcast ++ * @deprecated in favour of {@link #message(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setMessage(@NotNull String message) { +- this.message = message; ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + + /** +diff --git a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java +index 689e533a61be76b96312daf52db00d9885f1fb5a..1cc5a0abce39c939398ce945dd916dc086888b13 100644 +--- a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java ++++ b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java +@@ -22,7 +22,7 @@ public class ServerListPingEvent extends ServerEvent implements Iterable + private static final HandlerList handlers = new HandlerList(); + private final String hostname; + private final InetAddress address; +- private String motd; ++ private net.kyori.adventure.text.Component motd; // Paper + private final int numPlayers; + private int maxPlayers; + +@@ -31,7 +31,7 @@ public class ServerListPingEvent extends ServerEvent implements Iterable + Preconditions.checkArgument(numPlayers >= 0, "Cannot have negative number of players online", numPlayers); + this.hostname = hostname; + this.address = address; +- this.motd = motd; ++ this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper + this.numPlayers = numPlayers; + this.maxPlayers = maxPlayers; + } +@@ -45,15 +45,80 @@ public class ServerListPingEvent extends ServerEvent implements Iterable + * @param address the address of the pinger + * @param motd the message of the day + * @param maxPlayers the max number of players ++ * @deprecated in favour of {@link #ServerListPingEvent(String, java.net.InetAddress, net.kyori.adventure.text.Component, int)} + */ ++ @Deprecated // Paper + protected ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final String motd, final int maxPlayers) { + super(true); + this.numPlayers = MAGIC_PLAYER_COUNT; + this.hostname = hostname; + this.address = address; ++ this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper ++ this.maxPlayers = maxPlayers; ++ } ++ // Paper start ++ @Deprecated ++ public ServerListPingEvent(@NotNull final InetAddress address, @NotNull final net.kyori.adventure.text.Component motd, final int numPlayers, final int maxPlayers) { ++ this("", address, motd, numPlayers, maxPlayers); ++ } ++ public ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final net.kyori.adventure.text.Component motd, final int numPlayers, final int maxPlayers) { ++ super(true); ++ Preconditions.checkArgument(numPlayers >= 0, "Cannot have negative number of players online (%s)", numPlayers); ++ this.hostname = hostname; ++ this.address = address; + this.motd = motd; ++ this.numPlayers = numPlayers; + this.maxPlayers = maxPlayers; + } ++ /** ++ * This constructor is intended for implementations that provide the ++ * {@link #iterator()} method, thus provided the {@link #getNumPlayers()} ++ * count. ++ * ++ * @param address the address of the pinger ++ * @param motd the message of the day ++ * @param maxPlayers the max number of players ++ * @deprecated in favour of {@link #ServerListPingEvent(String, java.net.InetAddress, net.kyori.adventure.text.Component, int)} ++ */ ++ @Deprecated ++ protected ServerListPingEvent(@NotNull final InetAddress address, @NotNull final net.kyori.adventure.text.Component motd, final int maxPlayers) { ++ this("", address, motd, maxPlayers); ++ } ++ ++ /** ++ * This constructor is intended for implementations that provide the ++ * {@link #iterator()} method, thus provided the {@link #getNumPlayers()} ++ * count. ++ * ++ * @param hostname The hostname that was used to connect to the server ++ * @param address the address of the pinger ++ * @param motd the message of the day ++ * @param maxPlayers the max number of players ++ */ ++ protected ServerListPingEvent(final @NotNull String hostname, final @NotNull InetAddress address, final net.kyori.adventure.text.@NotNull Component motd, final int maxPlayers) { ++ this.numPlayers = MAGIC_PLAYER_COUNT; ++ this.hostname = hostname; ++ this.address = address; ++ this.motd = motd; ++ this.maxPlayers = maxPlayers; ++ } ++ /** ++ * Get the message of the day message. ++ * ++ * @return the message of the day ++ */ ++ public net.kyori.adventure.text.@NotNull Component motd() { ++ return motd; ++ } ++ /** ++ * Change the message of the day message. ++ * ++ * @param motd the message of the day ++ */ ++ public void motd(net.kyori.adventure.text.@NotNull Component motd) { ++ this.motd = motd; ++ } ++ // Paper end + + /** + * Gets the hostname that the player used to connect to the server, or +@@ -80,19 +145,23 @@ public class ServerListPingEvent extends ServerEvent implements Iterable + * Get the message of the day message. + * + * @return the message of the day ++ * @deprecated in favour of {@link #motd()} + */ + @NotNull ++ @Deprecated // Paper + public String getMotd() { +- return motd; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.motd); // Paper + } + + /** + * Change the message of the day message. + * + * @param motd the message of the day ++ * @deprecated in favour of {@link #motd(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setMotd(@NotNull String motd) { +- this.motd = motd; ++ this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper + } + + /** +diff --git a/src/main/java/org/bukkit/inventory/InventoryView.java b/src/main/java/org/bukkit/inventory/InventoryView.java +index 021d9491d0b7337e036bc95aad076b923f7451dd..0b5e2f4760a43a7a8d3de7bca557027822145a18 100644 +--- a/src/main/java/org/bukkit/inventory/InventoryView.java ++++ b/src/main/java/org/bukkit/inventory/InventoryView.java +@@ -269,12 +269,26 @@ public interface InventoryView { + */ + public boolean setProperty(@NotNull Property prop, int value); + ++ // Paper start + /** + * Get the title of this inventory window. + * + * @return The title. + */ + @NotNull ++ default net.kyori.adventure.text.Component title() { ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(this.getTitle()); ++ } ++ // Paper end ++ ++ /** ++ * Get the title of this inventory window. ++ * ++ * @return The title. ++ * @deprecated in favour of {@link #title()} ++ */ ++ @Deprecated // Paper ++ @NotNull + public String getTitle(); + + /** +diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java +index aa7fcae0de70aa5c10a331dfb076efd2f2c64065..d5342258086066d3b9ef404916bad8440f0cf0cd 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFactory.java ++++ b/src/main/java/org/bukkit/inventory/ItemFactory.java +@@ -200,4 +200,24 @@ public interface ItemFactory { + */ + @NotNull + ItemStack enchantItem(@NotNull final ItemStack item, final int level, final boolean allowTreasures); ++ ++ // Paper start - Adventure ++ /** ++ * Creates a hover event for the given item. ++ * ++ * @param item The item ++ * @return A hover event ++ */ ++ @NotNull ++ net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull ItemStack item, final @NotNull java.util.function.UnaryOperator op); ++ ++ /** ++ * Get the formatted display name of the {@link ItemStack}. ++ * ++ * @param itemStack the {@link ItemStack} ++ * @return display name of the {@link ItemStack} ++ */ ++ @NotNull ++ net.kyori.adventure.text.Component displayName(@NotNull ItemStack itemStack); ++ // Paper end - Adventure + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index 8d9c309067235b24893de6a86ae8efe1f30015bd..a71a37e3833b6a339c4df8939768c2bd46a816a5 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable; + * use this class to encapsulate Materials for which {@link Material#isItem()} + * returns false. + */ +-public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable { ++public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource { // Paper + private Material type = Material.AIR; + private int amount = 0; + private MaterialData data = null; +@@ -626,4 +626,21 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + public String getTranslationKey() { + return Bukkit.getUnsafe().getTranslationKey(this); + } ++ ++ // Paper start ++ @NotNull ++ @Override ++ public net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { ++ return org.bukkit.Bukkit.getServer().getItemFactory().asHoverEvent(this, op); ++ } ++ ++ /** ++ * Get the formatted display name of the {@link ItemStack}. ++ * ++ * @return display name of the {@link ItemStack} ++ */ ++ public net.kyori.adventure.text.@NotNull Component displayName() { ++ return Bukkit.getServer().getItemFactory().displayName(this); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/MenuType.java b/src/main/java/org/bukkit/inventory/MenuType.java +index 45d3889206fb3b7a7303490b8d4e67ede2aae7a4..34d45a105da72481a7c4f2e3831f5d2a676c91c6 100644 +--- a/src/main/java/org/bukkit/inventory/MenuType.java ++++ b/src/main/java/org/bukkit/inventory/MenuType.java +@@ -145,11 +145,45 @@ public interface MenuType extends Keyed { + * @param player the player the view belongs to + * @param title the title of the view + * @return the created {@link InventoryView} ++ * @deprecated Use {@link #create(HumanEntity, net.kyori.adventure.text.Component)} instead. + */ + @NotNull ++ @Deprecated(since = "1.21") // Paper - adventure + V create(@NotNull HumanEntity player, @NotNull String title); ++ ++ // Paper start - adventure ++ /** ++ * Creates a view of the specified menu type. ++ *

      ++ * The player provided to create this view must be the player the view ++ * is opened for. See {@link HumanEntity#openInventory(InventoryView)} ++ * for more information. ++ * ++ * @param player the player the view belongs to ++ * @param title the title of the view ++ * @return the created {@link InventoryView} ++ */ ++ @NotNull ++ V create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title); ++ // Paper end - adventure + } + ++ // Paper start - adventure ++ /** ++ * Creates a view of the specified menu type. ++ *

      ++ * The player provided to create this view must be the player the view ++ * is opened for. See {@link HumanEntity#openInventory(InventoryView)} ++ * for more information. ++ * ++ * @param player the player the view belongs to ++ * @param title the title of the view ++ * @return the created {@link InventoryView} ++ */ ++ @NotNull ++ InventoryView create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title); ++ // Paper end - adventure ++ + /** + * Yields this MenuType as a typed version of itself with a plain + * {@link InventoryView} representing it. +diff --git a/src/main/java/org/bukkit/inventory/meta/BookMeta.java b/src/main/java/org/bukkit/inventory/meta/BookMeta.java +index 9bab73c3c2ca759b8e1c7d07d98cc593c961666a..f0c6943da3f783101ca647b75b3230fae3a310da 100644 +--- a/src/main/java/org/bukkit/inventory/meta/BookMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/BookMeta.java +@@ -7,10 +7,15 @@ import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + + /** +- * Represents a {@link Material#WRITTEN_BOOK}) that can have a title, an author, ++ * Represents a {@link Material#WRITTEN_BOOK} that can have a title, an author, + * and pages. ++ *

      ++ * Before using this type, make sure to check the itemstack's material with ++ * {@link org.bukkit.inventory.ItemStack#getType()}. {@code instanceof} on ++ * the meta instance is not sufficient due to unusual inheritance ++ * with relation to {@link WritableBookMeta}. + */ +-public interface BookMeta extends WritableBookMeta { ++public interface BookMeta extends WritableBookMeta, net.kyori.adventure.inventory.Book { // Paper - adventure + + /** + * Represents the generation (or level of copying) of a written book +@@ -116,6 +121,153 @@ public interface BookMeta extends WritableBookMeta { + @NotNull + BookMeta clone(); + ++ // Paper start - adventure ++ // ++ /** ++ * @deprecated use {@link #page(int)} ++ */ ++ @Deprecated ++ @Override ++ @NotNull String getPage(int page); ++ ++ /** ++ * @deprecated use {@link #page(int, net.kyori.adventure.text.Component)} ++ */ ++ @Deprecated ++ @Override ++ void setPage(int page, @NotNull String data); ++ ++ /** ++ * @deprecated use {@link #pages()} ++ */ ++ @Deprecated ++ @Override ++ @NotNull List getPages(); ++ ++ /** ++ * @deprecated use {@link #pages(List)} ++ */ ++ @Deprecated ++ @Override ++ void setPages(@NotNull List pages); ++ ++ /** ++ * @deprecated use {@link #pages(net.kyori.adventure.text.Component...)} ++ */ ++ @Deprecated ++ @Override ++ void setPages(@NotNull String... pages); ++ ++ /** ++ * @deprecated use {@link #addPages(net.kyori.adventure.text.Component...)} ++ */ ++ @Deprecated ++ @Override ++ void addPage(@NotNull String... pages); ++ // ++ ++ /** ++ * Gets the title of the book. ++ *

      ++ * Plugins should check that hasTitle() returns true before calling this ++ * method. ++ * ++ * @return the title of the book ++ */ ++ @Override ++ net.kyori.adventure.text.@Nullable Component title(); ++ ++ /** ++ * Sets the title of the book. ++ *

      ++ * Limited to 32 characters. Removes title when given null. ++ * ++ * @param title the title to set ++ * @return the same {@link BookMeta} instance ++ */ ++ @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false) ++ @Override ++ @NotNull BookMeta title(net.kyori.adventure.text.@Nullable Component title); ++ ++ /** ++ * Gets the author of the book. ++ *

      ++ * Plugins should check that hasAuthor() returns true before calling this ++ * method. ++ * ++ * @return the author of the book ++ */ ++ @Override ++ net.kyori.adventure.text.@Nullable Component author(); ++ ++ /** ++ * Sets the author of the book. Removes author when given null. ++ * ++ * @param author the author to set ++ * @return the same {@link BookMeta} instance ++ */ ++ @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false) ++ @Override ++ @NotNull BookMeta author(net.kyori.adventure.text.@Nullable Component author); ++ ++ ++ /** ++ * Gets the specified page in the book. The page must exist. ++ *

      ++ * Pages are 1-indexed. ++ * ++ * @param page the page number to get, in range [1, getPageCount()] ++ * @return the page from the book ++ */ ++ net.kyori.adventure.text.@NotNull Component page(int page); ++ ++ /** ++ * Sets the specified page in the book. Pages of the book must be ++ * contiguous. ++ *

      ++ * The data can be up to 1024 characters in length, additional characters ++ * are truncated. ++ *

      ++ * Pages are 1-indexed. ++ * ++ * @param page the page number to set, in range [1, getPageCount()] ++ * @param data the data to set for that page ++ */ ++ void page(int page, net.kyori.adventure.text.@NotNull Component data); ++ ++ /** ++ * Adds new pages to the end of the book. Up to a maximum of 100 pages with ++ * 1024 characters per page. ++ * ++ * @param pages A list of strings, each being a page ++ */ ++ void addPages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages); ++ ++ interface BookMetaBuilder extends net.kyori.adventure.inventory.Book.Builder { ++ ++ @Override ++ @NotNull BookMetaBuilder title(net.kyori.adventure.text.@Nullable Component title); ++ ++ @Override ++ @NotNull BookMetaBuilder author(net.kyori.adventure.text.@Nullable Component author); ++ ++ @Override ++ @NotNull BookMetaBuilder addPage(net.kyori.adventure.text.@NotNull Component page); ++ ++ @Override ++ @NotNull BookMetaBuilder pages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages); ++ ++ @Override ++ @NotNull BookMetaBuilder pages(java.util.@NotNull Collection pages); ++ ++ @Override ++ @NotNull BookMeta build(); ++ } ++ ++ @Override ++ @NotNull BookMetaBuilder toBuilder(); ++ // Paper end ++ + // Spigot start + public class Spigot { + +@@ -124,8 +276,10 @@ public interface BookMeta extends WritableBookMeta { + * + * @param page the page number to get + * @return the page from the book ++ * @deprecated in favour of {@link #page(int)} + */ + @NotNull ++ @Deprecated // Paper + public BaseComponent[] getPage(int page) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -139,7 +293,9 @@ public interface BookMeta extends WritableBookMeta { + * + * @param page the page number to set + * @param data the data to set for that page ++ * @deprecated in favour of {@link #page(int, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setPage(int page, @Nullable BaseComponent... data) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -148,8 +304,10 @@ public interface BookMeta extends WritableBookMeta { + * Gets all the pages in the book. + * + * @return list of all the pages in the book ++ * @deprecated in favour of {@link #pages()} + */ + @NotNull ++ @Deprecated // Paper + public List getPages() { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -159,7 +317,9 @@ public interface BookMeta extends WritableBookMeta { + * pages. Maximum 50 pages with 256 characters per page. + * + * @param pages A list of pages to set the book to use ++ * @deprecated in favour of {@link #pages(java.util.List)} + */ ++ @Deprecated // Paper + public void setPages(@NotNull List pages) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -169,7 +329,9 @@ public interface BookMeta extends WritableBookMeta { + * pages. Maximum 50 pages with 256 characters per page. + * + * @param pages A list of component arrays, each being a page ++ * @deprecated in favour of {@link #pages(net.kyori.adventure.text.Component...)} + */ ++ @Deprecated // Paper + public void setPages(@NotNull BaseComponent[]... pages) { + throw new UnsupportedOperationException("Not supported yet."); + } +@@ -179,7 +341,9 @@ public interface BookMeta extends WritableBookMeta { + * with 256 characters per page. + * + * @param pages A list of component arrays, each being a page ++ * @deprecated in favour of {@link #addPages(net.kyori.adventure.text.Component...)} + */ ++ @Deprecated // Paper + public void addPage(@NotNull BaseComponent[]... pages) { + throw new UnsupportedOperationException("Not supported yet."); + } +diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +index 69d6de6e9618dd27f5ba73b931f8455912caf060..753a756525f6afea981dd0c2984e7a747d4d148b 100644 +--- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +@@ -38,12 +38,65 @@ import org.jetbrains.annotations.Nullable; + */ + public interface ItemMeta extends Cloneable, ConfigurationSerializable, PersistentDataHolder { + ++ // Paper start ++ /** ++ * Checks for existence of a custom name. ++ * ++ * @return true if this has a custom name ++ */ ++ boolean hasCustomName(); ++ ++ /** ++ * Gets the custom name. ++ * ++ *

      Plugins should check that {@link #hasCustomName()} returns {@code true} before calling this method.

      ++ * ++ * @return the custom name ++ */ ++ net.kyori.adventure.text.@Nullable Component customName(); ++ ++ /** ++ * Sets the custom name. ++ * ++ * @param customName the custom name to set ++ */ ++ void customName(final net.kyori.adventure.text.@Nullable Component customName); ++ + /** + * Checks for existence of a display name. + * ++ * @apiNote This method is obsolete, use {@link #hasCustomName()} instead. + * @return true if this has a display name + */ +- boolean hasDisplayName(); ++ @ApiStatus.Obsolete(since = "1.21.4") ++ default boolean hasDisplayName() { ++ return this.hasCustomName(); ++ } ++ ++ /** ++ * Gets the display name. ++ * ++ *

      Plugins should check that {@link #hasDisplayName()} returns true before calling this method.

      ++ * ++ * @apiNote This method is obsolete, use {@link #customName()} instead. ++ * @return the display name ++ */ ++ @ApiStatus.Obsolete(since = "1.21.4") ++ default net.kyori.adventure.text.@Nullable Component displayName() { ++ return this.customName(); ++ } ++ ++ /** ++ * Sets the display name. ++ * ++ * @param displayName the display name to set ++ * @apiNote This method is obsolete, use {@link #customName(Component)} instead. ++ */ ++ @ApiStatus.Obsolete(since = "1.21.4") ++ default void displayName(final net.kyori.adventure.text.@Nullable Component displayName) { ++ this.customName(displayName); ++ } ++ // Paper end + + /** + * Gets the display name that is set. +@@ -52,7 +105,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * before calling this method. + * + * @return the display name that is set ++ * @deprecated in favour of {@link #displayName()} + */ ++ @Deprecated // Paper + @NotNull + String getDisplayName(); + +@@ -60,7 +115,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * Sets the display name. + * + * @param name the name to set ++ * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + void setDisplayName(@Nullable String name); + + /** +@@ -73,6 +130,32 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + */ + boolean hasItemName(); + ++ // Paper start ++ /** ++ * Gets the item name component that is set. ++ *
      ++ * Item name differs from display name in that it is cannot be edited by an ++ * anvil, is not styled with italics, and does not show labels. ++ *

      ++ * Plugins should check that {@link #hasItemName()} returns true before ++ * calling this method. ++ * ++ * @return the item name that is set ++ * @see #hasItemName() ++ */ ++ @org.jetbrains.annotations.NotNull ++ Component itemName(); ++ ++ /** ++ * Sets the item name. ++ *
      ++ * Item name differs from display name in that it is cannot be edited by an ++ * anvil, is not styled with italics, and does not show labels. ++ * ++ * @param name the name to set, null to remove it ++ */ ++ void itemName(@Nullable final Component name); ++ // Paper end + /** + * Gets the item name that is set. + *
      +@@ -83,7 +166,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * calling this method. + * + * @return the item name that is set ++ * @deprecated in favour of {@link #itemName()} + */ ++ @Deprecated // Paper + @NotNull + String getItemName(); + +@@ -94,7 +179,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * anvil, is not styled with italics, and does not show labels. + * + * @param name the name to set ++ * @deprecated in favour of {@link #itemName(Component)} + */ ++ @Deprecated // Paper + void setItemName(@Nullable String name); + + /** +@@ -135,6 +222,24 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + */ + boolean hasLore(); + ++ // Paper start ++ /** ++ * Gets the lore. ++ * ++ *

      Plugins should check that {@link #hasLore()} returns true before calling this method.

      ++ * ++ * @return the lore ++ */ ++ @Nullable List lore(); ++ ++ /** ++ * Sets the lore. ++ * ++ * @param lore the lore to set ++ */ ++ void lore(final @Nullable List lore); ++ // Paper end ++ + /** + * Gets the lore that is set. + *

      +@@ -142,7 +247,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * calling this method. + * + * @return a list of lore that is set ++ * @deprecated in favour of {@link #lore()} + */ ++ @Deprecated // Paper + @Nullable + List getLore(); + +@@ -151,7 +258,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * Removes lore when given null. + * + * @param lore the lore that will be set ++ * @deprecated in favour of {@link #lore(List)} + */ ++ @Deprecated // Paper + void setLore(@Nullable List lore); + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/PotionMeta.java b/src/main/java/org/bukkit/inventory/meta/PotionMeta.java +index b61d2e322f80fcabae5e286cba8df9701ebcf5ea..ada7b3d8f5743fa4dd7809060f1c5a5608b7aec3 100644 +--- a/src/main/java/org/bukkit/inventory/meta/PotionMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/PotionMeta.java +@@ -149,27 +149,64 @@ public interface PotionMeta extends ItemMeta { + /** + * Checks for existence of a custom potion name translation suffix. + * ++ * @deprecated conflicting name, use {@link #hasCustomPotionName()} + * @return true if this has a custom potion name + */ +- boolean hasCustomName(); ++ @Deprecated(forRemoval = true, since = "1.21.4") ++ default boolean hasCustomName() { ++ return this.hasCustomPotionName(); ++ } + + /** + * Gets the potion name translation suffix that is set. + *

      +- * Plugins should check that hasCustomName() returns true ++ * Plugins should check that {@link #hasCustomPotionName()} returns {@code true} + * before calling this method. + * ++ * @deprecated conflicting name, use {@link #getCustomPotionName()} + * @return the potion name that is set + */ ++ @Deprecated(forRemoval = true, since = "1.21.4") + @Nullable +- String getCustomName(); ++ default String getCustomName() { ++ return this.getCustomPotionName(); ++ } + + /** + * Sets the potion name translation suffix. + * ++ * @deprecated conflicting name, use {@link #setCustomPotionName(String)} + * @param name the name to set + */ +- void setCustomName(@Nullable String name); ++ @Deprecated(forRemoval = true, since = "1.21.4") ++ default void setCustomName(@Nullable String name) { ++ this.setCustomPotionName(name); ++ } ++ ++ /** ++ * Checks for existence of a custom potion name translation suffix. ++ * ++ * @return true if this has a custom potion name ++ */ ++ boolean hasCustomPotionName(); ++ ++ /** ++ * Gets the potion name translation suffix that is set. ++ *

      ++ * Plugins should check that {@link #hasCustomPotionName()} returns {@code true} ++ * before calling this method. ++ * ++ * @return the potion name that is set ++ */ ++ @Nullable ++ String getCustomPotionName(); ++ ++ /** ++ * Sets the potion name translation suffix. ++ * ++ * @param name the name to set ++ */ ++ void setCustomPotionName(@Nullable String name); + + @Override + PotionMeta clone(); +diff --git a/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java b/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java +index 12595536080ffe09df2b6ecdb83d846f50100d38..9fc47c879ee6b8edf2503f20e4736c2997d2de2e 100644 +--- a/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java +@@ -5,8 +5,14 @@ import org.bukkit.Material; + import org.jetbrains.annotations.NotNull; + + /** +- * Represents a book ({@link Material#WRITABLE_BOOK} or {@link +- * Material#WRITTEN_BOOK}) that can have pages. ++ * Represents a book ({@link Material#WRITABLE_BOOK}) that can have pages. ++ *

      ++ * For {@link Material#WRITTEN_BOOK}, use {@link BookMeta}. ++ *

      ++ * Before using this type, make sure to check the itemstack's material with ++ * {@link org.bukkit.inventory.ItemStack#getType()}. {@code instanceof} on ++ * the meta instance is not sufficient due to unusual inheritance ++ * with relation to {@link BookMeta}. + */ + public interface WritableBookMeta extends ItemMeta { + +diff --git a/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java b/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java +index ebfd6f5523205cfc932e3d6b351ff26da855fb15..cc38bee3c412bef4767f08407c0f5559a113fce5 100644 +--- a/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java ++++ b/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java +@@ -61,4 +61,21 @@ public interface TrimMaterial extends Keyed, Translatable { + private static TrimMaterial getTrimMaterial(@NotNull String key) { + return Registry.TRIM_MATERIAL.getOrThrow(NamespacedKey.minecraft(key)); + } ++ ++ // Paper start - adventure ++ /** ++ * Get the description of this {@link TrimMaterial}. ++ * ++ * @return the description ++ */ ++ net.kyori.adventure.text.@org.jetbrains.annotations.NotNull Component description(); ++ ++ /** ++ * @deprecated this method assumes that {@link #description()} will ++ * always be a translatable component which is not guaranteed. ++ */ ++ @Override ++ @Deprecated(forRemoval = true) ++ @org.jetbrains.annotations.NotNull String getTranslationKey(); ++ // Paper end - adventure + } +diff --git a/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java b/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java +index e8e0786467bfcea14d30b352489b7bfb1a06addc..56cfe665daba1754e41f633d7c18172bebf87028 100644 +--- a/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java ++++ b/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java +@@ -89,4 +89,21 @@ public interface TrimPattern extends Keyed, Translatable { + private static TrimPattern getTrimPattern(@NotNull String key) { + return Registry.TRIM_PATTERN.getOrThrow(NamespacedKey.minecraft(key)); + } ++ ++ // Paper start - adventure ++ /** ++ * Get the description of this {@link TrimPattern}. ++ * ++ * @return the description ++ */ ++ net.kyori.adventure.text.@org.jetbrains.annotations.NotNull Component description(); ++ ++ /** ++ * @deprecated this method assumes that {@link #description()} will ++ * always be a translatable component which is not guaranteed. ++ */ ++ @Override ++ @Deprecated(forRemoval = true) ++ @org.jetbrains.annotations.NotNull String getTranslationKey(); ++ // Paper end - adventure + } +diff --git a/src/main/java/org/bukkit/map/MapCursor.java b/src/main/java/org/bukkit/map/MapCursor.java +index 3ca6d94e9930c93013ee654d5bc5a5d6656c6c0e..8de6d0c53bce0279a82b84b408e83d2128077400 100644 +--- a/src/main/java/org/bukkit/map/MapCursor.java ++++ b/src/main/java/org/bukkit/map/MapCursor.java +@@ -17,7 +17,7 @@ public final class MapCursor { + private byte x, y; + private byte direction; + private boolean visible; +- private String caption; ++ private net.kyori.adventure.text.Component caption; // Paper + private Type type; + + /** +@@ -32,7 +32,7 @@ public final class MapCursor { + */ + @Deprecated(since = "1.6.2") + public MapCursor(byte x, byte y, byte direction, byte type, boolean visible) { +- this(x, y, direction, type, visible, null); ++ this(x, y, direction, type, visible, (String) null); // Paper + } + + /** +@@ -45,7 +45,7 @@ public final class MapCursor { + * @param visible Whether the cursor is visible by default. + */ + public MapCursor(byte x, byte y, byte direction, @NotNull Type type, boolean visible) { +- this(x, y, direction, type, visible, null); ++ this(x, y, direction, type, visible, (String) null); // Paper + } + + /** +@@ -57,7 +57,7 @@ public final class MapCursor { + * @param type The type (color/style) of the map cursor. + * @param visible Whether the cursor is visible by default. + * @param caption cursor caption +- * @deprecated Magic value, use {@link #MapCursor(byte, byte, byte, Type, boolean, String)} ++ * @deprecated Magic value. Use {@link #MapCursor(byte, byte, byte, Type, boolean, net.kyori.adventure.text.Component)} + */ + @Deprecated(since = "1.13") + public MapCursor(byte x, byte y, byte direction, byte type, boolean visible, @Nullable String caption) { +@@ -66,8 +66,42 @@ public final class MapCursor { + setDirection(direction); + setRawType(type); + this.visible = visible; +- this.caption = caption; ++ this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper ++ } ++ // Paper start ++ /** ++ * Initialize the map cursor. ++ * ++ * @param x The x coordinate, from -128 to 127. ++ * @param y The y coordinate, from -128 to 127. ++ * @param direction The facing of the cursor, from 0 to 15. ++ * @param type The type (color/style) of the map cursor. ++ * @param visible Whether the cursor is visible by default. ++ * @param caption cursor caption ++ * @deprecated Magic value ++ */ ++ @Deprecated ++ public MapCursor(byte x, byte y, byte direction, byte type, boolean visible, net.kyori.adventure.text.@Nullable Component caption) { ++ this.x = x; this.y = y; this.visible = visible; this.caption = caption; ++ setDirection(direction); ++ setRawType(type); ++ } ++ /** ++ * Initialize the map cursor. ++ * ++ * @param x The x coordinate, from -128 to 127. ++ * @param y The y coordinate, from -128 to 127. ++ * @param direction The facing of the cursor, from 0 to 15. ++ * @param type The type (color/style) of the map cursor. ++ * @param visible Whether the cursor is visible by default. ++ * @param caption cursor caption ++ */ ++ public MapCursor(byte x, byte y, byte direction, @NotNull Type type, boolean visible, net.kyori.adventure.text.@Nullable Component caption) { ++ this.x = x; this.y = y; this.visible = visible; this.caption = caption; ++ setDirection(direction); ++ setType(type); + } ++ // Paper end + + /** + * Initialize the map cursor. +@@ -85,7 +119,7 @@ public final class MapCursor { + setDirection(direction); + this.type = type; + this.visible = visible; +- this.caption = caption; ++ this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper + } + + /** +@@ -204,23 +238,45 @@ public final class MapCursor { + this.visible = visible; + } + ++ // Paper start + /** + * Gets the caption on this cursor. + * + * @return caption + */ ++ public net.kyori.adventure.text.@Nullable Component caption() { ++ return this.caption; ++ } ++ /** ++ * Sets the caption on this cursor. ++ * ++ * @param caption new caption ++ */ ++ public void caption(net.kyori.adventure.text.@Nullable Component caption) { ++ this.caption = caption; ++ } ++ // Paper end ++ /** ++ * Gets the caption on this cursor. ++ * ++ * @return caption ++ * @deprecated in favour of {@link #caption()} ++ */ + @Nullable ++ @Deprecated // Paper + public String getCaption() { +- return caption; ++ return this.caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.caption); // Paper + } + + /** + * Sets the caption on this cursor. + * + * @param caption new caption ++ * @deprecated in favour of {@link #caption(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setCaption(@Nullable String caption) { +- this.caption = caption; ++ this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper + } + + /** +diff --git a/src/main/java/org/bukkit/map/MapCursorCollection.java b/src/main/java/org/bukkit/map/MapCursorCollection.java +index 986f9c8a659ed5cdda9fc4528bff23bf0e9f801e..f95a9aaa0cb020ea71d4c8a8e71bceb7147cbe4d 100644 +--- a/src/main/java/org/bukkit/map/MapCursorCollection.java ++++ b/src/main/java/org/bukkit/map/MapCursorCollection.java +@@ -117,4 +117,22 @@ public final class MapCursorCollection { + public MapCursor addCursor(int x, int y, byte direction, byte type, boolean visible, @Nullable String caption) { + return addCursor(new MapCursor((byte) x, (byte) y, direction, type, visible, caption)); + } ++ // Paper start ++ /** ++ * Add a cursor to the collection. ++ * ++ * @param x The x coordinate, from -128 to 127. ++ * @param y The y coordinate, from -128 to 127. ++ * @param direction The facing of the cursor, from 0 to 15. ++ * @param type The type (color/style) of the map cursor. ++ * @param visible Whether the cursor is visible. ++ * @param caption banner caption ++ * @return The newly added MapCursor. ++ * @deprecated Magic value ++ */ ++ @Deprecated ++ public @NotNull MapCursor addCursor(int x, int y, byte direction, byte type, boolean visible, net.kyori.adventure.text.@Nullable Component caption) { ++ return addCursor(new MapCursor((byte) x, (byte) y, direction, type, visible, caption)); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/permissions/Permissible.java b/src/main/java/org/bukkit/permissions/Permissible.java +index 228421154913116069c20323afb519bdde2134df..26791db3c267670d5782f1d2b67ff7d5b55b9dac 100644 +--- a/src/main/java/org/bukkit/permissions/Permissible.java ++++ b/src/main/java/org/bukkit/permissions/Permissible.java +@@ -126,4 +126,34 @@ public interface Permissible extends ServerOperator { + */ + @NotNull + public Set getEffectivePermissions(); ++ ++ // Paper start - add TriState permission checks ++ /** ++ * Checks if this object has a permission set and, if it is set, the value of the permission. ++ * ++ * @param permission the permission to check ++ * @return a tri-state of if the permission is set and, if it is set, it's value ++ */ ++ default net.kyori.adventure.util.@NotNull TriState permissionValue(final @NotNull Permission permission) { ++ if (this.isPermissionSet(permission)) { ++ return net.kyori.adventure.util.TriState.byBoolean(this.hasPermission(permission)); ++ } else { ++ return net.kyori.adventure.util.TriState.NOT_SET; ++ } ++ } ++ ++ /** ++ * Checks if this object has a permission set and, if it is set, the value of the permission. ++ * ++ * @param permission the permission to check ++ * @return a tri-state of if the permission is set and, if it is set, it's value ++ */ ++ default net.kyori.adventure.util.@NotNull TriState permissionValue(final @NotNull String permission) { ++ if (this.isPermissionSet(permission)) { ++ return net.kyori.adventure.util.TriState.byBoolean(this.hasPermission(permission)); ++ } else { ++ return net.kyori.adventure.util.TriState.NOT_SET; ++ } ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java +index 03ca87a1cbace2459174bb7bb8847bda766e80c5..b37938745f916b5f0111b07b1a1c97527f026e9d 100644 +--- a/src/main/java/org/bukkit/plugin/Plugin.java ++++ b/src/main/java/org/bukkit/plugin/Plugin.java +@@ -179,6 +179,13 @@ public interface Plugin extends TabExecutor { + @NotNull + public Logger getLogger(); + ++ // Paper start - Adventure component logger ++ @NotNull ++ default net.kyori.adventure.text.logger.slf4j.ComponentLogger getComponentLogger() { ++ return net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(getLogger().getName()); ++ } ++ // Paper end ++ + /** + * Returns the name of the plugin. + *

      +diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java +index c15e056e7697aac9079d3506911d82cb71aa9d23..d57634dd3796a695aba7623d2b04e35d630887b3 100644 +--- a/src/main/java/org/bukkit/scoreboard/Objective.java ++++ b/src/main/java/org/bukkit/scoreboard/Objective.java +@@ -20,13 +20,35 @@ public interface Objective { + @NotNull + String getName(); + ++ // Paper start - Adventure ++ /** ++ * Gets the display name for this objective ++ * ++ * @return this objective's display name ++ * @throws IllegalStateException if this objective has been unregistered ++ */ ++ net.kyori.adventure.text.@NotNull Component displayName(); ++ /** ++ * Sets the name displayed to players for this objective. ++ * ++ * @param displayName Display name to set ++ * @throws IllegalStateException if this objective has been unregistered ++ * @throws IllegalArgumentException if displayName is null ++ * @throws IllegalArgumentException if displayName is longer than 128 ++ * characters. ++ */ ++ void displayName(net.kyori.adventure.text.@Nullable Component displayName); ++ // Paper end - Adventure ++ + /** + * Gets the name displayed to players for this objective + * + * @return this objective's display name + * @throws IllegalStateException if this objective has been unregistered ++ * @deprecated in favour of {@link #displayName()} + */ + @NotNull ++ @Deprecated // Paper + String getDisplayName(); + + /** +@@ -34,7 +56,9 @@ public interface Objective { + * + * @param displayName Display name to set + * @throws IllegalStateException if this objective has been unregistered ++ * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + void setDisplayName(@NotNull String displayName); + + /** +diff --git a/src/main/java/org/bukkit/scoreboard/Scoreboard.java b/src/main/java/org/bukkit/scoreboard/Scoreboard.java +index a55188ec3ec1c038fdd96da62f534cb71686da97..1cba9a96cc7efce2a4394add33e4c0369f94be31 100644 +--- a/src/main/java/org/bukkit/scoreboard/Scoreboard.java ++++ b/src/main/java/org/bukkit/scoreboard/Scoreboard.java +@@ -26,6 +26,71 @@ public interface Scoreboard { + @NotNull + Objective registerNewObjective(@NotNull String name, @NotNull String criteria); + ++ // Paper start - Adventure ++ /** ++ * Registers an Objective on this Scoreboard ++ * ++ * @param name Name of the Objective ++ * @param criteria Criteria for the Objective ++ * @param displayName display name for the Objective. ++ * @return The registered Objective ++ * @throws IllegalArgumentException if name is longer than 32767 ++ * characters. ++ * @throws IllegalArgumentException if an objective by that name already ++ * exists ++ * @deprecated use {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component)} ++ */ ++ @NotNull ++ @Deprecated ++ Objective registerNewObjective(@NotNull String name, @NotNull String criteria, net.kyori.adventure.text.@Nullable Component displayName); ++ /** ++ * Registers an Objective on this Scoreboard ++ * ++ * @param name Name of the Objective ++ * @param criteria Criteria for the Objective ++ * @param displayName Name displayed to players for the Objective. ++ * @param renderType Manner of rendering the Objective ++ * @return The registered Objective ++ * @throws IllegalArgumentException if name is longer than 32767 ++ * characters. ++ * @throws IllegalArgumentException if an objective by that name already ++ * exists ++ * @deprecated use {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component, RenderType)} ++ */ ++ @NotNull ++ @Deprecated ++ Objective registerNewObjective(@NotNull String name, @NotNull String criteria, net.kyori.adventure.text.@Nullable Component displayName, @NotNull RenderType renderType) throws IllegalArgumentException; ++ /** ++ * Registers an Objective on this Scoreboard ++ * ++ * @param name Name of the Objective ++ * @param criteria Criteria for the Objective ++ * @param displayName Name displayed to players for the Objective. ++ * @return The registered Objective ++ * @throws IllegalArgumentException if name is longer than 32767 ++ * characters. ++ * @throws IllegalArgumentException if an objective by that name already ++ * exists ++ */ ++ @NotNull ++ Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, net.kyori.adventure.text.@Nullable Component displayName) throws IllegalArgumentException; ++ /** ++ * Registers an Objective on this Scoreboard ++ * ++ * @param name Name of the Objective ++ * @param criteria Criteria for the Objective ++ * @param displayName Name displayed to players for the Objective. ++ * @param renderType Manner of rendering the Objective ++ * @return The registered Objective ++ * @throws IllegalArgumentException if name is longer than 32767 ++ * characters. ++ * @throws IllegalArgumentException if an objective by that name already ++ * exists ++ */ ++ @NotNull ++ Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, net.kyori.adventure.text.@Nullable Component displayName, @NotNull RenderType renderType) throws IllegalArgumentException; ++ // Paper end - Adventure ++ + /** + * Registers an Objective on this Scoreboard + * +@@ -37,7 +102,7 @@ public interface Scoreboard { + * characters. + * @throws IllegalArgumentException if an objective by that name already + * exists +- * @deprecated use {@link #registerNewObjective(String, Criteria, String)} ++ * @deprecated use {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component)} + */ + @Deprecated(since = "1.20.5") + @NotNull +@@ -55,7 +120,7 @@ public interface Scoreboard { + * characters. + * @throws IllegalArgumentException if an objective by that name already + * exists +- * @deprecated use {@link #registerNewObjective(String, Criteria, String, RenderType)} ++ * @deprecated use {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component, RenderType)} + */ + @Deprecated(since = "1.20.5") + @NotNull +@@ -72,8 +137,10 @@ public interface Scoreboard { + * characters. + * @throws IllegalArgumentException if an objective by that name already + * exists ++ * @deprecated in favour of {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component)} + */ + @NotNull ++ @Deprecated // Paper + Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, @NotNull String displayName); + + /** +@@ -88,8 +155,10 @@ public interface Scoreboard { + * characters. + * @throws IllegalArgumentException if an objective by that name already + * exists ++ * @deprecated in favour of {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component, RenderType)} + */ + @NotNull ++ @Deprecated // Paper + Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, @NotNull String displayName, @NotNull RenderType renderType); + + /** +diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java +index f6e684853fbca3f015f4948db5603eb155ea1f2f..284468fd3d310a7acdffa31f0f6593f5a98419ba 100644 +--- a/src/main/java/org/bukkit/scoreboard/Team.java ++++ b/src/main/java/org/bukkit/scoreboard/Team.java +@@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable; + * properties. This team is only relevant to the display of the associated + * {@link #getScoreboard() scoreboard}. + */ +-public interface Team { ++public interface Team extends net.kyori.adventure.audience.ForwardingAudience { // Paper - Make Team extend ForwardingAudience + + /** + * Gets the name of this Team +@@ -23,13 +23,96 @@ public interface Team { + @NotNull + String getName(); + ++ // Paper start - Adventure ++ /** ++ * Gets the display name for this team ++ * ++ * @return Team display name ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ net.kyori.adventure.text.@NotNull Component displayName(); ++ ++ /** ++ * Sets the name displayed to entries for this team ++ * ++ * @param displayName New display name ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ void displayName(net.kyori.adventure.text.@Nullable Component displayName); ++ ++ /** ++ * Gets the prefix prepended to the display of entries on this team. ++ * ++ * @return Team prefix ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ net.kyori.adventure.text.@NotNull Component prefix(); ++ ++ /** ++ * Sets the prefix prepended to the display of entries on this team. ++ * ++ * @param prefix New prefix ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ void prefix(net.kyori.adventure.text.@Nullable Component prefix); ++ ++ /** ++ * Gets the suffix appended to the display of entries on this team. ++ * ++ * @return the team's current suffix ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ net.kyori.adventure.text.@NotNull Component suffix(); ++ ++ /** ++ * Sets the suffix appended to the display of entries on this team. ++ * ++ * @param suffix the new suffix for this team. ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ void suffix(net.kyori.adventure.text.@Nullable Component suffix); ++ ++ /** ++ * Checks if the team has a color specified ++ * ++ * @return true if it has a color ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ boolean hasColor(); ++ ++ /** ++ * Gets the color of the team. ++ *
      ++ * This only sets the team outline, other occurrences of colors such as in ++ * names are handled by prefixes / suffixes. ++ * ++ * @return team color ++ * @throws IllegalStateException if this team has been unregistered ++ * @throws IllegalStateException if the team doesn't have a color ++ * @see #hasColor() ++ */ ++ net.kyori.adventure.text.format.@NotNull TextColor color(); ++ ++ /** ++ * Sets the color of the team. ++ *
      ++ * This only sets the team outline, other occurrences of colors such as in ++ * names are handled by prefixes / suffixes. ++ * ++ * @param color new color, null for no color ++ */ ++ void color(net.kyori.adventure.text.format.@Nullable NamedTextColor color); ++ // Paper end - Adventure ++ + /** + * Gets the name displayed to entries for this team + * + * @return Team display name + * @throws IllegalStateException if this team has been unregistered ++ * @deprecated in favour of {@link #displayName()} + */ + @NotNull ++ @Deprecated // Paper + String getDisplayName(); + + /** +@@ -37,7 +120,9 @@ public interface Team { + * + * @param displayName New display name + * @throws IllegalStateException if this team has been unregistered ++ * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + void setDisplayName(@NotNull String displayName); + + /** +@@ -45,8 +130,10 @@ public interface Team { + * + * @return Team prefix + * @throws IllegalStateException if this team has been unregistered ++ * @deprecated in favour of {@link #prefix()} + */ + @NotNull ++ @Deprecated // Paper + String getPrefix(); + + /** +@@ -54,7 +141,9 @@ public interface Team { + * + * @param prefix New prefix + * @throws IllegalStateException if this team has been unregistered ++ * @deprecated in favour of {@link #prefix(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + void setPrefix(@NotNull String prefix); + + /** +@@ -62,8 +151,10 @@ public interface Team { + * + * @return the team's current suffix + * @throws IllegalStateException if this team has been unregistered ++ * @deprecated in favour of {@link #suffix()} + */ + @NotNull ++ @Deprecated // Paper + String getSuffix(); + + /** +@@ -71,7 +162,9 @@ public interface Team { + * + * @param suffix the new suffix for this team. + * @throws IllegalStateException if this team has been unregistered ++ * @deprecated in favour of {@link #suffix(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + void setSuffix(@NotNull String suffix); + + /** +@@ -82,8 +175,10 @@ public interface Team { + * + * @return team color, defaults to {@link ChatColor#RESET} + * @throws IllegalStateException if this team has been unregistered ++ * @deprecated in favour of {@link #color()} + */ + @NotNull ++ @Deprecated // Paper + ChatColor getColor(); + + /** +@@ -94,7 +189,9 @@ public interface Team { + * + * @param color new color, must be non-null. Use {@link ChatColor#RESET} for + * no color ++ * @deprecated in favour of {@link #color(net.kyori.adventure.text.format.NamedTextColor)} + */ ++ @Deprecated // Paper + void setColor(@NotNull ChatColor color); + + /** +diff --git a/src/test/java/io/papermc/paper/adventure/KeyTest.java b/src/test/java/io/papermc/paper/adventure/KeyTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7ede17d60358e0e3a04f3166ea9657e5239e0d8f +--- /dev/null ++++ b/src/test/java/io/papermc/paper/adventure/KeyTest.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.adventure; ++ ++import java.util.HashSet; ++import java.util.Set; ++import net.kyori.adventure.key.Key; ++import org.bukkit.NamespacedKey; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++import static org.junit.jupiter.api.Assertions.assertTrue; ++ ++public class KeyTest { ++ ++ @Test ++ public void equalsTest() { ++ Key key = new NamespacedKey("test", "key"); ++ Key key1 = Key.key("test", "key"); ++ assertEquals(key, key1); ++ assertEquals(key1, key); ++ } ++ ++ @Test ++ public void setTest() { ++ Key key = new NamespacedKey("test", "key"); ++ Key key1 = Key.key("test", "key"); ++ Set set = new HashSet<>(Set.of(key)); ++ Set set1 = new HashSet<>(Set.of(key1)); ++ assertTrue(set.contains(key1)); ++ assertTrue(set1.contains(key)); ++ } ++} diff --git a/patches/api/0006-Paper-Utils.patch b/patches/api/0006-Paper-Utils.patch deleted file mode 100644 index a647b698adaa..000000000000 --- a/patches/api/0006-Paper-Utils.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 23 Feb 2019 11:26:21 -0500 -Subject: [PATCH] Paper Utils - - -diff --git a/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java b/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9db0056ab94145819628b3ad8d8d26130d117fcf ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java -@@ -0,0 +1,16 @@ -+package com.destroystokyo.paper.util; -+ -+import org.jetbrains.annotations.NotNull; -+ -+public class SneakyThrow { -+ -+ public static void sneaky(@NotNull Throwable exception) { -+ SneakyThrow.throwSneaky(exception); -+ } -+ -+ @SuppressWarnings("unchecked") -+ private static void throwSneaky(@NotNull Throwable exception) throws T { -+ throw (T) exception; -+ } -+ -+} diff --git a/patches/api/0007-Paper-Utils.patch b/patches/api/0007-Paper-Utils.patch new file mode 100644 index 000000000000..38f5ac80adaf --- /dev/null +++ b/patches/api/0007-Paper-Utils.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 23 Feb 2019 11:26:21 -0500 +Subject: [PATCH] Paper Utils + + +diff --git a/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java b/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fbcd82b513b4cb9839f9d2b38d9c6c73148e30a6 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java +@@ -0,0 +1,19 @@ ++package com.destroystokyo.paper.util; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@ApiStatus.Internal ++@NullMarked ++public final class SneakyThrow { ++ ++ public static void sneaky(final Throwable exception) { ++ SneakyThrow.throwSneaky(exception); ++ } ++ ++ @SuppressWarnings("unchecked") ++ private static void throwSneaky(final Throwable exception) throws T { ++ throw (T) exception; ++ } ++ ++} diff --git a/patches/api/0007-Timings-v2.patch b/patches/api/0007-Timings-v2.patch deleted file mode 100644 index 1bcbda8a362c..000000000000 --- a/patches/api/0007-Timings-v2.patch +++ /dev/null @@ -1,3745 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 29 Feb 2016 18:48:17 -0600 -Subject: [PATCH] Timings v2 - -TODO: Add #isStopping to FullServerTickHandler#stopTiming in patch 191 -expose isRunning - -diff --git a/src/main/java/co/aikar/timings/FullServerTickHandler.java b/src/main/java/co/aikar/timings/FullServerTickHandler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..43b85ce3a6c27a2f92c67d62bee7484c2652b72a ---- /dev/null -+++ b/src/main/java/co/aikar/timings/FullServerTickHandler.java -@@ -0,0 +1,85 @@ -+package co.aikar.timings; -+ -+import static co.aikar.timings.TimingsManager.*; -+ -+import org.bukkit.Bukkit; -+import org.jetbrains.annotations.NotNull; -+ -+public class FullServerTickHandler extends TimingHandler { -+ private static final TimingIdentifier IDENTITY = new TimingIdentifier("Minecraft", "Full Server Tick", null); -+ final TimingData minuteData; -+ double avgFreeMemory = -1D; -+ double avgUsedMemory = -1D; -+ FullServerTickHandler() { -+ super(IDENTITY); -+ minuteData = new TimingData(id); -+ -+ TIMING_MAP.put(IDENTITY, this); -+ } -+ -+ @NotNull -+ @Override -+ public Timing startTiming() { -+ if (TimingsManager.needsFullReset) { -+ TimingsManager.resetTimings(); -+ } else if (TimingsManager.needsRecheckEnabled) { -+ TimingsManager.recheckEnabled(); -+ } -+ return super.startTiming(); -+ } -+ -+ @Override -+ public void stopTiming() { -+ super.stopTiming(); -+ if (!isEnabled()) { -+ return; -+ } -+ if (TimingHistory.timedTicks % 20 == 0) { -+ final Runtime runtime = Runtime.getRuntime(); -+ double usedMemory = runtime.totalMemory() - runtime.freeMemory(); -+ double freeMemory = runtime.maxMemory() - usedMemory; -+ if (this.avgFreeMemory == -1) { -+ this.avgFreeMemory = freeMemory; -+ } else { -+ this.avgFreeMemory = (this.avgFreeMemory * (59 / 60D)) + (freeMemory * (1 / 60D)); -+ } -+ -+ if (this.avgUsedMemory == -1) { -+ this.avgUsedMemory = usedMemory; -+ } else { -+ this.avgUsedMemory = (this.avgUsedMemory * (59 / 60D)) + (usedMemory * (1 / 60D)); -+ } -+ } -+ -+ long start = System.nanoTime(); -+ TimingsManager.tick(); -+ long diff = System.nanoTime() - start; -+ TIMINGS_TICK.addDiff(diff, null); -+ // addDiff for TIMINGS_TICK incremented this, bring it back down to 1 per tick. -+ record.setCurTickCount(record.getCurTickCount()-1); -+ -+ minuteData.setCurTickTotal(record.getCurTickTotal()); -+ minuteData.setCurTickCount(1); -+ -+ boolean violated = isViolated(); -+ minuteData.processTick(violated); -+ TIMINGS_TICK.processTick(violated); -+ processTick(violated); -+ -+ -+ if (TimingHistory.timedTicks % 1200 == 0) { -+ MINUTE_REPORTS.add(new TimingHistory.MinuteReport()); -+ TimingHistory.resetTicks(false); -+ minuteData.reset(); -+ } -+ if (TimingHistory.timedTicks % Timings.getHistoryInterval() == 0) { -+ TimingsManager.HISTORY.add(new TimingHistory()); -+ TimingsManager.resetTimings(); -+ } -+ Bukkit.getUnsafe().reportTimings(); -+ } -+ -+ boolean isViolated() { -+ return record.getCurTickTotal() > 50000000; -+ } -+} -diff --git a/src/main/java/co/aikar/timings/NullTimingHandler.java b/src/main/java/co/aikar/timings/NullTimingHandler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9b45ce887b9172f30302b83fe24b99b76b16dac3 ---- /dev/null -+++ b/src/main/java/co/aikar/timings/NullTimingHandler.java -@@ -0,0 +1,68 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public final class NullTimingHandler implements Timing { -+ public static final Timing NULL = new NullTimingHandler(); -+ @NotNull -+ @Override -+ public Timing startTiming() { -+ return this; -+ } -+ -+ @Override -+ public void stopTiming() { -+ -+ } -+ -+ @NotNull -+ @Override -+ public Timing startTimingIfSync() { -+ return this; -+ } -+ -+ @Override -+ public void stopTimingIfSync() { -+ -+ } -+ -+ @Override -+ public void abort() { -+ -+ } -+ -+ @Nullable -+ @Override -+ public TimingHandler getTimingHandler() { -+ return null; -+ } -+ -+ @Override -+ public void close() { -+ -+ } -+} -diff --git a/src/main/java/co/aikar/timings/TimedEventExecutor.java b/src/main/java/co/aikar/timings/TimedEventExecutor.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4e6e1b8e8aeb07e34536941d2cbfc25e5cfa6c27 ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimedEventExecutor.java -@@ -0,0 +1,83 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import org.bukkit.Bukkit; -+import org.bukkit.event.Event; -+import org.bukkit.event.EventException; -+import org.bukkit.event.Listener; -+import org.bukkit.plugin.EventExecutor; -+import org.bukkit.plugin.Plugin; -+ -+import java.lang.reflect.Method; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class TimedEventExecutor implements EventExecutor { -+ -+ private final EventExecutor executor; -+ private final Timing timings; -+ -+ /** -+ * Wraps an event executor and associates a timing handler to it. -+ * -+ * @param executor Executor to wrap -+ * @param plugin Owning plugin -+ * @param method EventHandler method -+ * @param eventClass Owning class -+ */ -+ public TimedEventExecutor(@NotNull EventExecutor executor, @NotNull Plugin plugin, @Nullable Method method, @NotNull Class eventClass) { -+ this.executor = executor; -+ String id; -+ -+ if (method == null) { -+ if (executor.getClass().getEnclosingClass() != null) { // Oh Skript, how we love you -+ method = executor.getClass().getEnclosingMethod(); -+ } -+ } -+ -+ if (method != null) { -+ id = method.getDeclaringClass().getName(); -+ } else { -+ id = executor.getClass().getName(); -+ } -+ -+ -+ final String eventName = eventClass.getSimpleName(); -+ boolean verbose = "BlockPhysicsEvent".equals(eventName); -+ this.timings = Timings.ofSafe(plugin, (verbose ? "## " : "") + -+ "Event: " + id + " (" + eventName + ")"); -+ } -+ -+ @Override -+ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { -+ if (event.isAsynchronous() || !Timings.timingsEnabled || !Bukkit.isPrimaryThread()) { -+ executor.execute(listener, event); -+ return; -+ } -+ try (Timing ignored = timings.startTiming()){ -+ executor.execute(listener, event); -+ } -+ } -+} -diff --git a/src/main/java/co/aikar/timings/Timing.java b/src/main/java/co/aikar/timings/Timing.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a21e5ead5024fd0058c5e3302d8201dd249d32bc ---- /dev/null -+++ b/src/main/java/co/aikar/timings/Timing.java -@@ -0,0 +1,83 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Provides an ability to time sections of code within the Minecraft Server -+ */ -+public interface Timing extends AutoCloseable { -+ /** -+ * Starts timing the execution until {@link #stopTiming()} is called. -+ * -+ * @return Timing -+ */ -+ @NotNull -+ Timing startTiming(); -+ -+ /** -+ *

      Stops timing and records the data. Propagates the data up to group handlers.

      -+ * -+ * Will automatically be called when this Timing is used with try-with-resources -+ */ -+ void stopTiming(); -+ -+ /** -+ * Starts timing the execution until {@link #stopTiming()} is called. -+ * -+ * But only if we are on the primary thread. -+ * -+ * @return Timing -+ */ -+ @NotNull -+ Timing startTimingIfSync(); -+ -+ /** -+ *

      Stops timing and records the data. Propagates the data up to group handlers.

      -+ * -+ *

      Will automatically be called when this Timing is used with try-with-resources

      -+ * -+ * But only if we are on the primary thread. -+ */ -+ void stopTimingIfSync(); -+ -+ /** -+ * @deprecated Doesn't do anything - Removed -+ */ -+ @Deprecated -+ void abort(); -+ -+ /** -+ * Used internally to get the actual backing Handler in the case of delegated Handlers -+ * -+ * @return TimingHandler -+ */ -+ @Nullable -+ TimingHandler getTimingHandler(); -+ -+ @Override -+ void close(); -+} -diff --git a/src/main/java/co/aikar/timings/TimingData.java b/src/main/java/co/aikar/timings/TimingData.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a5d13a1e44edb861f45c83a9b4309fbf799d407d ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimingData.java -@@ -0,0 +1,122 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import java.util.List; -+import org.jetbrains.annotations.NotNull; -+ -+import static co.aikar.util.JSONUtil.toArray; -+ -+/** -+ *

      Lightweight object for tracking timing data

      -+ * -+ * This is broken out to reduce memory usage -+ */ -+class TimingData { -+ private final int id; -+ private int count = 0; -+ private int lagCount = 0; -+ private long totalTime = 0; -+ private long lagTotalTime = 0; -+ private int curTickCount = 0; -+ private long curTickTotal = 0; -+ -+ TimingData(int id) { -+ this.id = id; -+ } -+ -+ private TimingData(TimingData data) { -+ this.id = data.id; -+ this.totalTime = data.totalTime; -+ this.lagTotalTime = data.lagTotalTime; -+ this.count = data.count; -+ this.lagCount = data.lagCount; -+ } -+ -+ void add(long diff) { -+ ++curTickCount; -+ curTickTotal += diff; -+ } -+ -+ void processTick(boolean violated) { -+ totalTime += curTickTotal; -+ count += curTickCount; -+ if (violated) { -+ lagTotalTime += curTickTotal; -+ lagCount += curTickCount; -+ } -+ curTickTotal = 0; -+ curTickCount = 0; -+ } -+ -+ void reset() { -+ count = 0; -+ lagCount = 0; -+ curTickTotal = 0; -+ curTickCount = 0; -+ totalTime = 0; -+ lagTotalTime = 0; -+ } -+ -+ protected TimingData clone() { -+ return new TimingData(this); -+ } -+ -+ @NotNull -+ List export() { -+ List list = toArray( -+ id, -+ count, -+ totalTime); -+ if (lagCount > 0) { -+ list.add(lagCount); -+ list.add(lagTotalTime); -+ } -+ return list; -+ } -+ -+ boolean hasData() { -+ return count > 0; -+ } -+ -+ long getTotalTime() { -+ return totalTime; -+ } -+ -+ int getCurTickCount() { -+ return curTickCount; -+ } -+ -+ void setCurTickCount(int curTickCount) { -+ this.curTickCount = curTickCount; -+ } -+ -+ long getCurTickTotal() { -+ return curTickTotal; -+ } -+ -+ void setCurTickTotal(long curTickTotal) { -+ this.curTickTotal = curTickTotal; -+ } -+} -diff --git a/src/main/java/co/aikar/timings/TimingHandler.java b/src/main/java/co/aikar/timings/TimingHandler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..199789d56d22fcb1b77ebd56805cc28aa5a5ab0a ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimingHandler.java -@@ -0,0 +1,226 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import co.aikar.util.LoadingIntMap; -+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -+ -+import java.util.ArrayDeque; -+import java.util.Deque; -+import java.util.concurrent.atomic.AtomicInteger; -+import java.util.logging.Level; -+import java.util.logging.Logger; -+ -+import org.bukkit.Bukkit; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+class TimingHandler implements Timing { -+ -+ private static AtomicInteger idPool = new AtomicInteger(1); -+ private static Deque TIMING_STACK = new ArrayDeque<>(); -+ final int id = idPool.getAndIncrement(); -+ -+ final TimingIdentifier identifier; -+ private final boolean verbose; -+ -+ private final Int2ObjectOpenHashMap children = new LoadingIntMap<>(TimingData::new); -+ -+ final TimingData record; -+ private TimingHandler startParent; -+ private final TimingHandler groupHandler; -+ -+ private long start = 0; -+ private int timingDepth = 0; -+ private boolean added; -+ private boolean timed; -+ private boolean enabled; -+ -+ TimingHandler(@NotNull TimingIdentifier id) { -+ this.identifier = id; -+ this.verbose = id.name.startsWith("##"); -+ this.record = new TimingData(this.id); -+ this.groupHandler = id.groupHandler; -+ -+ TimingIdentifier.getGroup(id.group).handlers.add(this); -+ checkEnabled(); -+ } -+ -+ final void checkEnabled() { -+ enabled = Timings.timingsEnabled && (!verbose || Timings.verboseEnabled); -+ } -+ -+ void processTick(boolean violated) { -+ if (timingDepth != 0 || record.getCurTickCount() == 0) { -+ timingDepth = 0; -+ start = 0; -+ return; -+ } -+ -+ record.processTick(violated); -+ for (TimingData handler : children.values()) { -+ handler.processTick(violated); -+ } -+ } -+ -+ @NotNull -+ @Override -+ public Timing startTimingIfSync() { -+ startTiming(); -+ return this; -+ } -+ -+ @Override -+ public void stopTimingIfSync() { -+ stopTiming(); -+ } -+ -+ @NotNull -+ public Timing startTiming() { -+ if (!enabled || !Bukkit.isPrimaryThread()) { -+ return this; -+ } -+ if (++timingDepth == 1) { -+ startParent = TIMING_STACK.peekLast(); -+ start = System.nanoTime(); -+ } -+ TIMING_STACK.addLast(this); -+ return this; -+ } -+ -+ public void stopTiming() { -+ if (!enabled || timingDepth <= 0 || start == 0 || !Bukkit.isPrimaryThread()) { -+ return; -+ } -+ -+ popTimingStack(); -+ if (--timingDepth == 0) { -+ addDiff(System.nanoTime() - start, startParent); -+ startParent = null; -+ start = 0; -+ } -+ } -+ -+ private void popTimingStack() { -+ TimingHandler last; -+ while ((last = TIMING_STACK.removeLast()) != this) { -+ last.timingDepth = 0; -+ if ("Minecraft".equalsIgnoreCase(last.identifier.group)) { -+ Logger.getGlobal().log(Level.SEVERE, "TIMING_STACK_CORRUPTION - Look above this for any errors and report this to Paper unless it has a plugin in the stack trace (" + last.identifier + " did not stopTiming)"); -+ } else { -+ Logger.getGlobal().log(Level.SEVERE, "TIMING_STACK_CORRUPTION - Report this to the plugin " + last.identifier.group + " (Look for errors above this in the logs) (" + last.identifier + " did not stopTiming)", new Throwable()); -+ } -+ -+ boolean found = TIMING_STACK.contains(this); -+ if (!found) { -+ // We aren't even in the stack... Don't pop everything -+ TIMING_STACK.addLast(last); -+ break; -+ } -+ } -+ } -+ -+ @Override -+ public final void abort() { -+ -+ } -+ -+ void addDiff(long diff, @Nullable TimingHandler parent) { -+ if (parent != null) { -+ parent.children.get(id).add(diff); -+ } -+ -+ record.add(diff); -+ if (!added) { -+ added = true; -+ timed = true; -+ TimingsManager.HANDLERS.add(this); -+ } -+ if (groupHandler != null) { -+ groupHandler.addDiff(diff, parent); -+ groupHandler.children.get(id).add(diff); -+ } -+ } -+ -+ /** -+ * Reset this timer, setting all values to zero. -+ */ -+ void reset(boolean full) { -+ record.reset(); -+ if (full) { -+ timed = false; -+ } -+ start = 0; -+ timingDepth = 0; -+ added = false; -+ children.clear(); -+ checkEnabled(); -+ } -+ -+ @NotNull -+ @Override -+ public TimingHandler getTimingHandler() { -+ return this; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ return (this == o); -+ } -+ -+ @Override -+ public int hashCode() { -+ return id; -+ } -+ -+ /** -+ * This is simply for the Closeable interface so it can be used with try-with-resources () -+ */ -+ @Override -+ public void close() { -+ stopTimingIfSync(); -+ } -+ -+ public boolean isSpecial() { -+ return this == TimingsManager.FULL_SERVER_TICK || this == TimingsManager.TIMINGS_TICK; -+ } -+ -+ boolean isTimed() { -+ return timed; -+ } -+ -+ public boolean isEnabled() { -+ return enabled; -+ } -+ -+ @NotNull -+ TimingData[] cloneChildren() { -+ final TimingData[] clonedChildren = new TimingData[children.size()]; -+ int i = 0; -+ for (TimingData child : children.values()) { -+ clonedChildren[i++] = child.clone(); -+ } -+ return clonedChildren; -+ } -+} -diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ddaed81275fcc12d1671b668697acf318e96888b ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimingHistory.java -@@ -0,0 +1,354 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import co.aikar.timings.TimingHistory.RegionData.RegionId; -+import com.google.common.base.Function; -+import com.google.common.collect.Sets; -+import org.bukkit.Bukkit; -+import org.bukkit.Chunk; -+import org.bukkit.Material; -+import org.bukkit.World; -+import org.bukkit.block.BlockState; -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.EntityType; -+import org.bukkit.entity.Player; -+import co.aikar.util.LoadingMap; -+import co.aikar.util.MRUMapCache; -+ -+import java.lang.management.ManagementFactory; -+import java.util.Collection; -+import java.util.EnumMap; -+import java.util.List; -+import java.util.Map; -+import java.util.Set; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import static co.aikar.timings.TimingsManager.FULL_SERVER_TICK; -+import static co.aikar.timings.TimingsManager.MINUTE_REPORTS; -+import static co.aikar.util.JSONUtil.*; -+ -+@SuppressWarnings({"deprecation", "SuppressionAnnotation", "Convert2Lambda", "Anonymous2MethodRef"}) -+public class TimingHistory { -+ public static long lastMinuteTime; -+ public static long timedTicks; -+ public static long playerTicks; -+ public static long entityTicks; -+ public static long tileEntityTicks; -+ public static long activatedEntityTicks; -+ private static int worldIdPool = 1; -+ static Map worldMap = LoadingMap.newHashMap(new Function() { -+ @NotNull -+ @Override -+ public Integer apply(@Nullable String input) { -+ return worldIdPool++; -+ } -+ }); -+ private final long endTime; -+ private final long startTime; -+ private final long totalTicks; -+ private final long totalTime; // Represents all time spent running the server this history -+ private final MinuteReport[] minuteReports; -+ -+ private final TimingHistoryEntry[] entries; -+ final Set tileEntityTypeSet = Sets.newHashSet(); -+ final Set entityTypeSet = Sets.newHashSet(); -+ private final Map worlds; -+ -+ TimingHistory() { -+ this.endTime = System.currentTimeMillis() / 1000; -+ this.startTime = TimingsManager.historyStart / 1000; -+ if (timedTicks % 1200 != 0 || MINUTE_REPORTS.isEmpty()) { -+ this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[MINUTE_REPORTS.size() + 1]); -+ this.minuteReports[this.minuteReports.length - 1] = new MinuteReport(); -+ } else { -+ this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[MINUTE_REPORTS.size()]); -+ } -+ long ticks = 0; -+ for (MinuteReport mp : this.minuteReports) { -+ ticks += mp.ticksRecord.timed; -+ } -+ this.totalTicks = ticks; -+ this.totalTime = FULL_SERVER_TICK.record.getTotalTime(); -+ this.entries = new TimingHistoryEntry[TimingsManager.HANDLERS.size()]; -+ -+ int i = 0; -+ for (TimingHandler handler : TimingsManager.HANDLERS) { -+ entries[i++] = new TimingHistoryEntry(handler); -+ } -+ -+ // Information about all loaded chunks/entities -+ //noinspection unchecked -+ this.worlds = toObjectMapper(Bukkit.getWorlds(), new Function() { -+ @NotNull -+ @Override -+ public JSONPair apply(World world) { -+ Map regions = LoadingMap.newHashMap(RegionData.LOADER); -+ -+ for (Chunk chunk : world.getLoadedChunks()) { -+ RegionData data = regions.get(new RegionId(chunk.getX(), chunk.getZ())); -+ -+ for (Entity entity : chunk.getEntities()) { -+ if (entity == null) { -+ Bukkit.getLogger().warning("Null entity detected in chunk at position x: " + chunk.getX() + ", z: " + chunk.getZ()); -+ continue; -+ } -+ -+ data.entityCounts.get(entity.getType()).increment(); -+ } -+ -+ for (BlockState tileEntity : chunk.getTileEntities()) { -+ if (tileEntity == null) { -+ Bukkit.getLogger().warning("Null tileentity detected in chunk at position x: " + chunk.getX() + ", z: " + chunk.getZ()); -+ continue; -+ } -+ -+ data.tileEntityCounts.get(tileEntity.getBlock().getType()).increment(); -+ } -+ } -+ return pair( -+ worldMap.get(world.getName()), -+ toArrayMapper(regions.values(),new Function() { -+ @NotNull -+ @Override -+ public Object apply(RegionData input) { -+ return toArray( -+ input.regionId.x, -+ input.regionId.z, -+ toObjectMapper(input.entityCounts.entrySet(), -+ new Function, JSONPair>() { -+ @NotNull -+ @Override -+ public JSONPair apply(Map.Entry entry) { -+ entityTypeSet.add(entry.getKey()); -+ return pair( -+ String.valueOf(entry.getKey().ordinal()), -+ entry.getValue().count() -+ ); -+ } -+ } -+ ), -+ toObjectMapper(input.tileEntityCounts.entrySet(), -+ new Function, JSONPair>() { -+ @NotNull -+ @Override -+ public JSONPair apply(Map.Entry entry) { -+ tileEntityTypeSet.add(entry.getKey()); -+ return pair( -+ String.valueOf(entry.getKey().ordinal()), -+ entry.getValue().count() -+ ); -+ } -+ } -+ ) -+ ); -+ } -+ }) -+ ); -+ } -+ }); -+ } -+ static class RegionData { -+ final RegionId regionId; -+ @SuppressWarnings("Guava") -+ static Function LOADER = new Function() { -+ @NotNull -+ @Override -+ public RegionData apply(@NotNull RegionId id) { -+ return new RegionData(id); -+ } -+ }; -+ RegionData(@NotNull RegionId id) { -+ this.regionId = id; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (this == o) { -+ return true; -+ } -+ if (o == null || getClass() != o.getClass()) { -+ return false; -+ } -+ -+ RegionData that = (RegionData) o; -+ -+ return regionId.equals(that.regionId); -+ -+ } -+ -+ @Override -+ public int hashCode() { -+ return regionId.hashCode(); -+ } -+ -+ @SuppressWarnings("unchecked") -+ final Map entityCounts = MRUMapCache.of(LoadingMap.of( -+ new EnumMap(EntityType.class), k -> new Counter() -+ )); -+ @SuppressWarnings("unchecked") -+ final Map tileEntityCounts = MRUMapCache.of(LoadingMap.of( -+ new EnumMap(Material.class), k -> new Counter() -+ )); -+ -+ static class RegionId { -+ final int x, z; -+ final long regionId; -+ RegionId(int x, int z) { -+ this.x = x >> 5 << 5; -+ this.z = z >> 5 << 5; -+ this.regionId = ((long) (this.x) << 32) + (this.z >> 5 << 5) - Integer.MIN_VALUE; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (this == o) return true; -+ if (o == null || getClass() != o.getClass()) return false; -+ -+ RegionId regionId1 = (RegionId) o; -+ -+ return regionId == regionId1.regionId; -+ -+ } -+ -+ @Override -+ public int hashCode() { -+ return (int) (regionId ^ (regionId >>> 32)); -+ } -+ } -+ } -+ static void resetTicks(boolean fullReset) { -+ if (fullReset) { -+ // Non full is simply for 1 minute reports -+ timedTicks = 0; -+ } -+ lastMinuteTime = System.nanoTime(); -+ playerTicks = 0; -+ tileEntityTicks = 0; -+ entityTicks = 0; -+ activatedEntityTicks = 0; -+ } -+ -+ @NotNull -+ Object export() { -+ return createObject( -+ pair("s", startTime), -+ pair("e", endTime), -+ pair("tk", totalTicks), -+ pair("tm", totalTime), -+ pair("w", worlds), -+ pair("h", toArrayMapper(entries, new Function() { -+ @Nullable -+ @Override -+ public Object apply(TimingHistoryEntry entry) { -+ TimingData record = entry.data; -+ if (!record.hasData()) { -+ return null; -+ } -+ return entry.export(); -+ } -+ })), -+ pair("mp", toArrayMapper(minuteReports, new Function() { -+ @NotNull -+ @Override -+ public Object apply(MinuteReport input) { -+ return input.export(); -+ } -+ })) -+ ); -+ } -+ -+ static class MinuteReport { -+ final long time = System.currentTimeMillis() / 1000; -+ -+ final TicksRecord ticksRecord = new TicksRecord(); -+ final PingRecord pingRecord = new PingRecord(); -+ final TimingData fst = TimingsManager.FULL_SERVER_TICK.minuteData.clone(); -+ final double tps = 1E9 / ( System.nanoTime() - lastMinuteTime ) * ticksRecord.timed; -+ final double usedMemory = TimingsManager.FULL_SERVER_TICK.avgUsedMemory; -+ final double freeMemory = TimingsManager.FULL_SERVER_TICK.avgFreeMemory; -+ final double loadAvg = ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage(); -+ -+ @NotNull -+ List export() { -+ return toArray( -+ time, -+ Math.round(tps * 100D) / 100D, -+ Math.round(pingRecord.avg * 100D) / 100D, -+ fst.export(), -+ toArray(ticksRecord.timed, -+ ticksRecord.player, -+ ticksRecord.entity, -+ ticksRecord.activatedEntity, -+ ticksRecord.tileEntity -+ ), -+ usedMemory, -+ freeMemory, -+ loadAvg -+ ); -+ } -+ } -+ -+ private static class TicksRecord { -+ final long timed; -+ final long player; -+ final long entity; -+ final long tileEntity; -+ final long activatedEntity; -+ -+ TicksRecord() { -+ timed = timedTicks - (TimingsManager.MINUTE_REPORTS.size() * 1200); -+ player = playerTicks; -+ entity = entityTicks; -+ tileEntity = tileEntityTicks; -+ activatedEntity = activatedEntityTicks; -+ } -+ -+ } -+ -+ private static class PingRecord { -+ final double avg; -+ -+ PingRecord() { -+ final Collection onlinePlayers = Bukkit.getOnlinePlayers(); -+ int totalPing = 0; -+ for (Player player : onlinePlayers) { -+ totalPing += player.spigot().getPing(); -+ } -+ avg = onlinePlayers.isEmpty() ? 0 : totalPing / onlinePlayers.size(); -+ } -+ } -+ -+ -+ private static class Counter { -+ private int count = 0; -+ public int increment() { -+ return ++count; -+ } -+ public int count() { -+ return count; -+ } -+ } -+} -diff --git a/src/main/java/co/aikar/timings/TimingHistoryEntry.java b/src/main/java/co/aikar/timings/TimingHistoryEntry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..86d5ac6bd0d7d0003688761aceb3f3343575319f ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimingHistoryEntry.java -@@ -0,0 +1,58 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import com.google.common.base.Function; -+ -+import java.util.List; -+import org.jetbrains.annotations.NotNull; -+ -+import static co.aikar.util.JSONUtil.toArrayMapper; -+ -+class TimingHistoryEntry { -+ final TimingData data; -+ private final TimingData[] children; -+ -+ TimingHistoryEntry(@NotNull TimingHandler handler) { -+ this.data = handler.record.clone(); -+ children = handler.cloneChildren(); -+ } -+ -+ @NotNull -+ List export() { -+ List result = data.export(); -+ if (children.length > 0) { -+ result.add( -+ toArrayMapper(children, new Function() { -+ @NotNull -+ @Override -+ public Object apply(TimingData child) { -+ return child.export(); -+ } -+ }) -+ ); -+ } -+ return result; -+ } -+} -diff --git a/src/main/java/co/aikar/timings/TimingIdentifier.java b/src/main/java/co/aikar/timings/TimingIdentifier.java -new file mode 100644 -index 0000000000000000000000000000000000000000..df142a89b8c43acb81eb383eac0ef048a1f49a6e ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimingIdentifier.java -@@ -0,0 +1,116 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import co.aikar.util.LoadingMap; -+ -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.List; -+import java.util.Map; -+import java.util.Objects; -+import java.util.concurrent.ConcurrentHashMap; -+import java.util.concurrent.atomic.AtomicInteger; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ *

      Used as a basis for fast HashMap key comparisons for the Timing Map.

      -+ * -+ * This class uses interned strings giving us the ability to do an identity check instead of equals() on the strings -+ */ -+final class TimingIdentifier { -+ /** -+ * Holds all groups. Autoloads on request for a group by name. -+ */ -+ static final Map GROUP_MAP = LoadingMap.of(new ConcurrentHashMap<>(64, .5F), TimingGroup::new); -+ private static final TimingGroup DEFAULT_GROUP = getGroup("Minecraft"); -+ final String group; -+ final String name; -+ final TimingHandler groupHandler; -+ private final int hashCode; -+ -+ TimingIdentifier(@Nullable String group, @NotNull String name, @Nullable Timing groupHandler) { -+ this.group = group != null ? group: DEFAULT_GROUP.name; -+ this.name = name; -+ this.groupHandler = groupHandler != null ? groupHandler.getTimingHandler() : null; -+ this.hashCode = (31 * this.group.hashCode()) + this.name.hashCode(); -+ } -+ -+ @NotNull -+ static TimingGroup getGroup(@Nullable String groupName) { -+ if (groupName == null) { -+ //noinspection ConstantConditions -+ return DEFAULT_GROUP; -+ } -+ -+ return GROUP_MAP.get(groupName); -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (o == null) { -+ return false; -+ } -+ -+ TimingIdentifier that = (TimingIdentifier) o; -+ return Objects.equals(group, that.group) && Objects.equals(name, that.name); -+ } -+ -+ @Override -+ public int hashCode() { -+ return hashCode; -+ } -+ -+ @Override -+ public String toString() { -+ return "TimingIdentifier{id=" + group + ":" + name +'}'; -+ } -+ -+ static class TimingGroup { -+ -+ private static AtomicInteger idPool = new AtomicInteger(1); -+ final int id = idPool.getAndIncrement(); -+ -+ final String name; -+ final List handlers = Collections.synchronizedList(new ArrayList<>(64)); -+ -+ private TimingGroup(String name) { -+ this.name = name; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (this == o) return true; -+ if (o == null || getClass() != o.getClass()) return false; -+ TimingGroup that = (TimingGroup) o; -+ return id == that.id; -+ } -+ -+ @Override -+ public int hashCode() { -+ return id; -+ } -+ } -+} -diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java -new file mode 100644 -index 0000000000000000000000000000000000000000..dd72a34eaa4bedd9ea0b92eaa79091b00eb4dd09 ---- /dev/null -+++ b/src/main/java/co/aikar/timings/Timings.java -@@ -0,0 +1,295 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import com.google.common.base.Preconditions; -+import com.google.common.collect.EvictingQueue; -+import com.google.common.collect.Lists; -+import org.bukkit.Bukkit; -+import org.bukkit.command.CommandSender; -+import org.bukkit.plugin.Plugin; -+ -+import java.util.List; -+import java.util.Queue; -+import java.util.logging.Level; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+@SuppressWarnings({"UnusedDeclaration", "WeakerAccess", "SameParameterValue"}) -+public final class Timings { -+ -+ final static List requestingReport = Lists.newArrayList(); -+ private static final int MAX_HISTORY_FRAMES = 12; -+ public static final Timing NULL_HANDLER = new NullTimingHandler(); -+ static boolean timingsEnabled = false; -+ static boolean verboseEnabled = false; -+ private static int historyInterval = -1; -+ private static int historyLength = -1; -+ -+ private Timings() {} -+ -+ /** -+ * Returns a Timing for a plugin corresponding to a name. -+ * -+ * @param plugin Plugin to own the Timing -+ * @param name Name of Timing -+ * @return Handler -+ */ -+ @NotNull -+ public static Timing of(@NotNull Plugin plugin, @NotNull String name) { -+ Timing pluginHandler = null; -+ if (plugin != null) { -+ pluginHandler = ofSafe(plugin.getName(), "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER); -+ } -+ return of(plugin, name, pluginHandler); -+ } -+ -+ /** -+ *

      Returns a handler that has a groupHandler timer handler. Parent timers should not have their -+ * start/stop methods called directly, as the children will call it for you.

      -+ * -+ * Parent Timers are used to group multiple subsections together and get a summary of them combined -+ * Parent Handler can not be changed after first call -+ * -+ * @param plugin Plugin to own the Timing -+ * @param name Name of Timing -+ * @param groupHandler Parent handler to mirror .start/stop calls to -+ * @return Timing Handler -+ */ -+ @NotNull -+ public static Timing of(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) { -+ Preconditions.checkNotNull(plugin, "Plugin can not be null"); -+ return TimingsManager.getHandler(plugin.getName(), name, groupHandler); -+ } -+ -+ /** -+ * Returns a Timing object after starting it, useful for Java7 try-with-resources. -+ * -+ * try (Timing ignored = Timings.ofStart(plugin, someName)) { -+ * // timed section -+ * } -+ * -+ * @param plugin Plugin to own the Timing -+ * @param name Name of Timing -+ * @return Timing Handler -+ */ -+ @NotNull -+ public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name) { -+ return ofStart(plugin, name, null); -+ } -+ -+ /** -+ * Returns a Timing object after starting it, useful for Java7 try-with-resources. -+ * -+ * try (Timing ignored = Timings.ofStart(plugin, someName, groupHandler)) { -+ * // timed section -+ * } -+ * -+ * @param plugin Plugin to own the Timing -+ * @param name Name of Timing -+ * @param groupHandler Parent handler to mirror .start/stop calls to -+ * @return Timing Handler -+ */ -+ @NotNull -+ public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) { -+ Timing timing = of(plugin, name, groupHandler); -+ timing.startTiming(); -+ return timing; -+ } -+ -+ /** -+ * Gets whether or not the Spigot Timings system is enabled -+ * -+ * @return Enabled or not -+ */ -+ public static boolean isTimingsEnabled() { -+ return timingsEnabled; -+ } -+ -+ /** -+ *

      Sets whether or not the Spigot Timings system should be enabled

      -+ * -+ * Calling this will reset timing data. -+ * -+ * @param enabled Should timings be reported -+ */ -+ public static void setTimingsEnabled(boolean enabled) { -+ timingsEnabled = enabled; -+ reset(); -+ } -+ -+ /** -+ *

      Sets whether or not the Timings should monitor at Verbose level.

      -+ * -+ *

      When Verbose is disabled, high-frequency timings will not be available.

      -+ * -+ * @return Enabled or not -+ */ -+ public static boolean isVerboseTimingsEnabled() { -+ return verboseEnabled; -+ } -+ -+ /** -+ *

      Sets whether or not the Timings should monitor at Verbose level.

      -+ * -+ * When Verbose is disabled, high-frequency timings will not be available. -+ * Calling this will reset timing data. -+ * -+ * @param enabled Should high-frequency timings be reported -+ */ -+ public static void setVerboseTimingsEnabled(boolean enabled) { -+ verboseEnabled = enabled; -+ TimingsManager.needsRecheckEnabled = true; -+ } -+ -+ /** -+ *

      Gets the interval between Timing History report generation.

      -+ * -+ * Defaults to 5 minutes (6000 ticks) -+ * -+ * @return Interval in ticks -+ */ -+ public static int getHistoryInterval() { -+ return historyInterval; -+ } -+ -+ /** -+ *

      Sets the interval between Timing History report generations.

      -+ * -+ *

      Defaults to 5 minutes (6000 ticks)

      -+ * -+ * This will recheck your history length, so lowering this value will lower your -+ * history length if you need more than 60 history windows. -+ * -+ * @param interval Interval in ticks -+ */ -+ public static void setHistoryInterval(int interval) { -+ historyInterval = Math.max(20*60, interval); -+ // Recheck the history length with the new Interval -+ if (historyLength != -1) { -+ setHistoryLength(historyLength); -+ } -+ } -+ -+ /** -+ * Gets how long in ticks Timings history is kept for the server. -+ * -+ * Defaults to 1 hour (72000 ticks) -+ * -+ * @return Duration in Ticks -+ */ -+ public static int getHistoryLength() { -+ return historyLength; -+ } -+ -+ /** -+ * Sets how long Timing History reports are kept for the server. -+ * -+ * Defaults to 1 hours(72000 ticks) -+ * -+ * This value is capped at a maximum of getHistoryInterval() * MAX_HISTORY_FRAMES (12) -+ * -+ * Will not reset Timing Data but may truncate old history if the new length is less than old length. -+ * -+ * @param length Duration in ticks -+ */ -+ public static void setHistoryLength(int length) { -+ // Cap at 12 History Frames, 1 hour at 5 minute frames. -+ int maxLength = historyInterval * MAX_HISTORY_FRAMES; -+ // For special cases of servers with special permission to bypass the max. -+ // This max helps keep data file sizes reasonable for processing on Aikar's Timing parser side. -+ // Setting this will not help you bypass the max unless Aikar has added an exception on the API side. -+ if (System.getProperty("timings.bypassMax") != null) { -+ maxLength = Integer.MAX_VALUE; -+ } -+ historyLength = Math.max(Math.min(maxLength, length), historyInterval); -+ Queue oldQueue = TimingsManager.HISTORY; -+ int frames = (getHistoryLength() / getHistoryInterval()); -+ if (length > maxLength) { -+ Bukkit.getLogger().log(Level.WARNING, "Timings Length too high. Requested " + length + ", max is " + maxLength + ". To get longer history, you must increase your interval. Set Interval to " + Math.ceil(length / MAX_HISTORY_FRAMES) + " to achieve this length."); -+ } -+ TimingsManager.HISTORY = EvictingQueue.create(frames); -+ TimingsManager.HISTORY.addAll(oldQueue); -+ } -+ -+ /** -+ * Resets all Timing Data -+ */ -+ public static void reset() { -+ TimingsManager.reset(); -+ } -+ -+ /** -+ * Generates a report and sends it to the specified command sender. -+ * -+ * If sender is null, ConsoleCommandSender will be used. -+ * @param sender The sender to send to, or null to use the ConsoleCommandSender -+ */ -+ public static void generateReport(@Nullable CommandSender sender) { -+ if (sender == null) { -+ sender = Bukkit.getConsoleSender(); -+ } -+ requestingReport.add(sender); -+ } -+ -+ /** -+ * Generates a report and sends it to the specified listener. -+ * Use with {@link org.bukkit.command.BufferedCommandSender} to get full response when done! -+ * @param sender The listener to send responses too. -+ */ -+ public static void generateReport(@NotNull TimingsReportListener sender) { -+ Preconditions.checkNotNull(sender); -+ requestingReport.add(sender); -+ } -+ -+ /* -+ ================= -+ Protected API: These are for internal use only in Bukkit/CraftBukkit -+ These do not have isPrimaryThread() checks in the startTiming/stopTiming -+ ================= -+ */ -+ @NotNull -+ static TimingHandler ofSafe(@NotNull String name) { -+ return ofSafe(null, name, null); -+ } -+ -+ @NotNull -+ static Timing ofSafe(@Nullable Plugin plugin, @NotNull String name) { -+ Timing pluginHandler = null; -+ if (plugin != null) { -+ pluginHandler = ofSafe(plugin.getName(), "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER); -+ } -+ return ofSafe(plugin != null ? plugin.getName() : "Minecraft - Invalid Plugin", name, pluginHandler); -+ } -+ -+ @NotNull -+ static TimingHandler ofSafe(@NotNull String name, @Nullable Timing groupHandler) { -+ return ofSafe(null, name, groupHandler); -+ } -+ -+ @NotNull -+ static TimingHandler ofSafe(@Nullable String groupName, @NotNull String name, @Nullable Timing groupHandler) { -+ return TimingsManager.getHandler(groupName, name, groupHandler); -+ } -+} -diff --git a/src/main/java/co/aikar/timings/TimingsCommand.java b/src/main/java/co/aikar/timings/TimingsCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3132dc98d26c54c5e46162e53aaed195d7335c8d ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimingsCommand.java -@@ -0,0 +1,120 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import com.google.common.base.Preconditions; -+import com.google.common.collect.ImmutableList; -+import net.kyori.adventure.text.format.NamedTextColor; -+import org.bukkit.command.CommandSender; -+import org.bukkit.command.defaults.BukkitCommand; -+import org.bukkit.util.StringUtil; -+ -+import java.util.ArrayList; -+import java.util.List; -+import org.jetbrains.annotations.NotNull; -+ -+import static net.kyori.adventure.text.Component.text; -+ -+ -+public class TimingsCommand extends BukkitCommand { -+ private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("report", "reset", "on", "off", "paste", "verbon", "verboff"); -+ private long lastResetAttempt = 0; -+ -+ public TimingsCommand(@NotNull String name) { -+ super(name); -+ this.description = "Manages Spigot Timings data to see performance of the server."; -+ this.usageMessage = "/timings "; -+ this.setPermission("bukkit.command.timings"); -+ } -+ -+ @Override -+ public boolean execute(@NotNull CommandSender sender, @NotNull String currentAlias, @NotNull String[] args) { -+ if (!testPermission(sender)) { -+ return true; -+ } -+ if (args.length < 1) { -+ sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED)); -+ return true; -+ } -+ final String arg = args[0]; -+ if ("on".equalsIgnoreCase(arg)) { -+ Timings.setTimingsEnabled(true); -+ sender.sendMessage(text("Enabled Timings & Reset")); -+ return true; -+ } else if ("off".equalsIgnoreCase(arg)) { -+ Timings.setTimingsEnabled(false); -+ sender.sendMessage(text("Disabled Timings")); -+ return true; -+ } -+ -+ if (!Timings.isTimingsEnabled()) { -+ sender.sendMessage(text("Please enable timings by typing /timings on")); -+ return true; -+ } -+ -+ long now = System.currentTimeMillis(); -+ if ("verbon".equalsIgnoreCase(arg)) { -+ Timings.setVerboseTimingsEnabled(true); -+ sender.sendMessage(text("Enabled Verbose Timings")); -+ return true; -+ } else if ("verboff".equalsIgnoreCase(arg)) { -+ Timings.setVerboseTimingsEnabled(false); -+ sender.sendMessage(text("Disabled Verbose Timings")); -+ return true; -+ } else if ("reset".equalsIgnoreCase(arg)) { -+ if (now - lastResetAttempt < 30000) { -+ TimingsManager.reset(); -+ sender.sendMessage(text("Timings reset. Please wait 5-10 minutes before using /timings report.", NamedTextColor.RED)); -+ } else { -+ lastResetAttempt = now; -+ sender.sendMessage(text("WARNING: Timings v2 should not be reset. If you are experiencing lag, please wait 3 minutes and then issue a report. The best timings will include 10+ minutes, with data before and after your lag period. If you really want to reset, run this command again within 30 seconds.", NamedTextColor.RED)); -+ } -+ } else if ( -+ "paste".equalsIgnoreCase(arg) || -+ "report".equalsIgnoreCase(arg) || -+ "get".equalsIgnoreCase(arg) || -+ "merged".equalsIgnoreCase(arg) || -+ "separate".equalsIgnoreCase(arg) -+ ) { -+ Timings.generateReport(sender); -+ } else { -+ sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED)); -+ } -+ return true; -+ } -+ -+ @NotNull -+ @Override -+ public List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { -+ Preconditions.checkNotNull(sender, "Sender cannot be null"); -+ Preconditions.checkNotNull(args, "Arguments cannot be null"); -+ Preconditions.checkNotNull(alias, "Alias cannot be null"); -+ -+ if (args.length == 1) { -+ return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS, -+ new ArrayList(TIMINGS_SUBCOMMANDS.size())); -+ } -+ return ImmutableList.of(); -+ } -+} -diff --git a/src/main/java/co/aikar/timings/TimingsManager.java b/src/main/java/co/aikar/timings/TimingsManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a92925d41110226f7fda055b71ce7be60eedd038 ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimingsManager.java -@@ -0,0 +1,188 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import co.aikar.util.LoadingMap; -+import com.google.common.collect.EvictingQueue; -+import org.bukkit.Bukkit; -+import org.bukkit.Server; -+import org.bukkit.command.Command; -+import org.bukkit.plugin.Plugin; -+import org.bukkit.plugin.java.PluginClassLoader; -+ -+import java.util.ArrayList; -+import java.util.List; -+import java.util.Map; -+import java.util.concurrent.ConcurrentHashMap; -+import java.util.logging.Level; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public final class TimingsManager { -+ static final Map TIMING_MAP = LoadingMap.of( -+ new ConcurrentHashMap<>(4096, .5F), TimingHandler::new -+ ); -+ public static final FullServerTickHandler FULL_SERVER_TICK = new FullServerTickHandler(); -+ public static final TimingHandler TIMINGS_TICK = Timings.ofSafe("Timings Tick", FULL_SERVER_TICK); -+ public static final Timing PLUGIN_GROUP_HANDLER = Timings.ofSafe("Plugins"); -+ public static String url = "https://timings.aikar.co/"; -+ public static List hiddenConfigs = new ArrayList(); -+ public static boolean privacy = false; -+ -+ static final List HANDLERS = new ArrayList<>(1024); -+ static final List MINUTE_REPORTS = new ArrayList<>(64); -+ -+ static EvictingQueue HISTORY = EvictingQueue.create(12); -+ static long timingStart = 0; -+ static long historyStart = 0; -+ static boolean needsFullReset = false; -+ static boolean needsRecheckEnabled = false; -+ -+ private TimingsManager() {} -+ -+ /** -+ * Resets all timing data on the next tick -+ */ -+ static void reset() { -+ needsFullReset = true; -+ } -+ -+ /** -+ * Ticked every tick by CraftBukkit to count the number of times a timer -+ * caused TPS loss. -+ */ -+ static void tick() { -+ if (Timings.timingsEnabled) { -+ boolean violated = FULL_SERVER_TICK.isViolated(); -+ -+ for (TimingHandler handler : HANDLERS) { -+ if (handler.isSpecial()) { -+ // We manually call this -+ continue; -+ } -+ handler.processTick(violated); -+ } -+ -+ TimingHistory.playerTicks += Bukkit.getOnlinePlayers().size(); -+ TimingHistory.timedTicks++; -+ // Generate TPS/Ping/Tick reports every minute -+ } -+ } -+ static void stopServer() { -+ Timings.timingsEnabled = false; -+ recheckEnabled(); -+ } -+ static void recheckEnabled() { -+ synchronized (TIMING_MAP) { -+ for (TimingHandler timings : TIMING_MAP.values()) { -+ timings.checkEnabled(); -+ } -+ } -+ needsRecheckEnabled = false; -+ } -+ static void resetTimings() { -+ if (needsFullReset) { -+ // Full resets need to re-check every handlers enabled state -+ // Timing map can be modified from async so we must sync on it. -+ synchronized (TIMING_MAP) { -+ for (TimingHandler timings : TIMING_MAP.values()) { -+ timings.reset(true); -+ } -+ } -+ Bukkit.getLogger().log(Level.INFO, "Timings Reset"); -+ HISTORY.clear(); -+ needsFullReset = false; -+ needsRecheckEnabled = false; -+ timingStart = System.currentTimeMillis(); -+ } else { -+ // Soft resets only need to act on timings that have done something -+ // Handlers can only be modified on main thread. -+ for (TimingHandler timings : HANDLERS) { -+ timings.reset(false); -+ } -+ } -+ -+ HANDLERS.clear(); -+ MINUTE_REPORTS.clear(); -+ -+ TimingHistory.resetTicks(true); -+ historyStart = System.currentTimeMillis(); -+ } -+ -+ @NotNull -+ static TimingHandler getHandler(@Nullable String group, @NotNull String name, @Nullable Timing parent) { -+ return TIMING_MAP.get(new TimingIdentifier(group, name, parent)); -+ } -+ -+ -+ /** -+ *

      Due to access restrictions, we need a helper method to get a Command TimingHandler with String group

      -+ * -+ * Plugins should never call this -+ * -+ * @param pluginName Plugin this command is associated with -+ * @param command Command to get timings for -+ * @return TimingHandler -+ */ -+ @NotNull -+ public static Timing getCommandTiming(@Nullable String pluginName, @NotNull Command command) { -+ Plugin plugin = null; -+ final Server server = Bukkit.getServer(); -+ if (!( server == null || pluginName == null || -+ "minecraft".equals(pluginName) || "bukkit".equals(pluginName) || -+ "spigot".equalsIgnoreCase(pluginName) || "paper".equals(pluginName) -+ )) { -+ plugin = server.getPluginManager().getPlugin(pluginName); -+ } -+ if (plugin == null) { -+ // Plugin is passing custom fallback prefix, try to look up by class loader -+ plugin = getPluginByClassloader(command.getClass()); -+ } -+ if (plugin == null) { -+ return Timings.ofSafe("Command: " + pluginName + ":" + command.getTimingName()); -+ } -+ -+ return Timings.ofSafe(plugin, "Command: " + pluginName + ":" + command.getTimingName()); -+ } -+ -+ /** -+ * Looks up the class loader for the specified class, and if it is a PluginClassLoader, return the -+ * Plugin that created this class. -+ * -+ * @param clazz Class to check -+ * @return Plugin if created by a plugin -+ */ -+ @Nullable -+ public static Plugin getPluginByClassloader(@Nullable Class clazz) { -+ if (clazz == null) { -+ return null; -+ } -+ final ClassLoader classLoader = clazz.getClassLoader(); -+ if (classLoader instanceof PluginClassLoader) { -+ PluginClassLoader pluginClassLoader = (PluginClassLoader) classLoader; -+ return pluginClassLoader.getPlugin(); -+ } -+ return null; -+ } -+} -diff --git a/src/main/java/co/aikar/timings/TimingsReportListener.java b/src/main/java/co/aikar/timings/TimingsReportListener.java -new file mode 100644 -index 0000000000000000000000000000000000000000..34f4c02c3bdbe571a7efb1f8c61d8924b0c81268 ---- /dev/null -+++ b/src/main/java/co/aikar/timings/TimingsReportListener.java -@@ -0,0 +1,86 @@ -+package co.aikar.timings; -+ -+import com.google.common.base.Preconditions; -+import com.google.common.collect.Lists; -+import org.bukkit.Bukkit; -+import org.bukkit.command.CommandSender; -+import org.bukkit.command.ConsoleCommandSender; -+import org.bukkit.command.MessageCommandSender; -+import org.bukkit.command.RemoteConsoleCommandSender; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.List; -+ -+@SuppressWarnings("WeakerAccess") -+public class TimingsReportListener implements net.kyori.adventure.audience.ForwardingAudience, MessageCommandSender { -+ private final List senders; -+ private final Runnable onDone; -+ private String timingsURL; -+ -+ public TimingsReportListener(@NotNull CommandSender senders) { -+ this(senders, null); -+ } -+ public TimingsReportListener(@NotNull CommandSender sender, @Nullable Runnable onDone) { -+ this(Lists.newArrayList(sender), onDone); -+ } -+ public TimingsReportListener(@NotNull List senders) { -+ this(senders, null); -+ } -+ public TimingsReportListener(@NotNull List senders, @Nullable Runnable onDone) { -+ Preconditions.checkNotNull(senders); -+ Preconditions.checkArgument(!senders.isEmpty(), "senders is empty"); -+ -+ this.senders = Lists.newArrayList(senders); -+ this.onDone = onDone; -+ } -+ -+ @Nullable -+ public String getTimingsURL() { -+ return timingsURL; -+ } -+ -+ public void done() { -+ done(null); -+ } -+ -+ public void done(@Nullable String url) { -+ this.timingsURL = url; -+ if (onDone != null) { -+ onDone.run(); -+ } -+ for (CommandSender sender : senders) { -+ if (sender instanceof TimingsReportListener) { -+ ((TimingsReportListener) sender).done(); -+ } -+ } -+ } -+ -+ @Override -+ public void sendMessage(final @NotNull net.kyori.adventure.identity.Identity source, final @NotNull net.kyori.adventure.text.Component message, final @NotNull net.kyori.adventure.audience.MessageType type) { -+ net.kyori.adventure.audience.ForwardingAudience.super.sendMessage(source, message, type); -+ } -+ -+ @NotNull -+ @Override -+ public Iterable audiences() { -+ return this.senders; -+ } -+ -+ @Override -+ public void sendMessage(@NotNull String message) { -+ senders.forEach((sender) -> sender.sendMessage(message)); -+ } -+ -+ public void addConsoleIfNeeded() { -+ boolean hasConsole = false; -+ for (CommandSender sender : this.senders) { -+ if (sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) { -+ hasConsole = true; -+ } -+ } -+ if (!hasConsole) { -+ this.senders.add(Bukkit.getConsoleSender()); -+ } -+ } -+} -diff --git a/src/main/java/co/aikar/timings/UnsafeTimingHandler.java b/src/main/java/co/aikar/timings/UnsafeTimingHandler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..632c4961515f5052551f841cfa840e60bba7a257 ---- /dev/null -+++ b/src/main/java/co/aikar/timings/UnsafeTimingHandler.java -@@ -0,0 +1,53 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.timings; -+ -+import org.bukkit.Bukkit; -+import org.jetbrains.annotations.NotNull; -+ -+class UnsafeTimingHandler extends TimingHandler { -+ -+ UnsafeTimingHandler(@NotNull TimingIdentifier id) { -+ super(id); -+ } -+ -+ private static void checkThread() { -+ if (!Bukkit.isPrimaryThread()) { -+ throw new IllegalStateException("Calling Timings from Async Operation"); -+ } -+ } -+ -+ @NotNull -+ @Override -+ public Timing startTiming() { -+ checkThread(); -+ return super.startTiming(); -+ } -+ -+ @Override -+ public void stopTiming() { -+ checkThread(); -+ super.stopTiming(); -+ } -+} -diff --git a/src/main/java/co/aikar/util/Counter.java b/src/main/java/co/aikar/util/Counter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..eff63c371c39e21a5a9cb5af8c2dcf78a60dd52b ---- /dev/null -+++ b/src/main/java/co/aikar/util/Counter.java -@@ -0,0 +1,38 @@ -+package co.aikar.util; -+ -+import com.google.common.collect.ForwardingMap; -+ -+import java.util.HashMap; -+import java.util.Map; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class Counter extends ForwardingMap { -+ private final Map counts = new HashMap<>(); -+ -+ public long decrement(@Nullable T key) { -+ return increment(key, -1); -+ } -+ public long increment(@Nullable T key) { -+ return increment(key, 1); -+ } -+ public long decrement(@Nullable T key, long amount) { -+ return increment(key, -amount); -+ } -+ public long increment(@Nullable T key, long amount) { -+ Long count = this.getCount(key); -+ count += amount; -+ this.counts.put(key, count); -+ return count; -+ } -+ -+ public long getCount(@Nullable T key) { -+ return this.counts.getOrDefault(key, 0L); -+ } -+ -+ @NotNull -+ @Override -+ protected Map delegate() { -+ return this.counts; -+ } -+} -diff --git a/src/main/java/co/aikar/util/JSONUtil.java b/src/main/java/co/aikar/util/JSONUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..190bf0598442c89c2a1c93ad7c8c1a29797304ae ---- /dev/null -+++ b/src/main/java/co/aikar/util/JSONUtil.java -@@ -0,0 +1,140 @@ -+package co.aikar.util; -+ -+import com.google.common.base.Function; -+import com.google.common.collect.Lists; -+import com.google.common.collect.Maps; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+import org.json.simple.JSONArray; -+import org.json.simple.JSONObject; -+ -+import java.util.ArrayList; -+import java.util.LinkedHashMap; -+import java.util.List; -+import java.util.Map; -+ -+/** -+ * Provides Utility methods that assist with generating JSON Objects -+ */ -+@SuppressWarnings({"rawtypes", "SuppressionAnnotation"}) -+public final class JSONUtil { -+ private JSONUtil() {} -+ -+ /** -+ * Creates a key/value "JSONPair" object -+ * -+ * @param key Key to use -+ * @param obj Value to use -+ * @return JSONPair -+ */ -+ @NotNull -+ public static JSONPair pair(@NotNull String key, @Nullable Object obj) { -+ return new JSONPair(key, obj); -+ } -+ -+ @NotNull -+ public static JSONPair pair(long key, @Nullable Object obj) { -+ return new JSONPair(String.valueOf(key), obj); -+ } -+ -+ /** -+ * Creates a new JSON object from multiple JSONPair key/value pairs -+ * -+ * @param data JSONPairs -+ * @return Map -+ */ -+ @NotNull -+ public static Map createObject(@NotNull JSONPair... data) { -+ return appendObjectData(new LinkedHashMap(), data); -+ } -+ -+ /** -+ * This appends multiple key/value Obj pairs into a JSON Object -+ * -+ * @param parent Map to be appended to -+ * @param data Data to append -+ * @return Map -+ */ -+ @NotNull -+ public static Map appendObjectData(@NotNull Map parent, @NotNull JSONPair... data) { -+ for (JSONPair JSONPair : data) { -+ parent.put(JSONPair.key, JSONPair.val); -+ } -+ return parent; -+ } -+ -+ /** -+ * This builds a JSON array from a set of data -+ * -+ * @param data Data to build JSON array from -+ * @return List -+ */ -+ @NotNull -+ public static List toArray(@NotNull Object... data) { -+ return Lists.newArrayList(data); -+ } -+ -+ /** -+ * These help build a single JSON array using a mapper function -+ * -+ * @param collection Collection to apply to -+ * @param mapper Mapper to apply -+ * @param Element Type -+ * @return List -+ */ -+ @NotNull -+ public static List toArrayMapper(@NotNull E[] collection, @NotNull Function mapper) { -+ return toArrayMapper(Lists.newArrayList(collection), mapper); -+ } -+ -+ @NotNull -+ public static List toArrayMapper(@NotNull Iterable collection, @NotNull Function mapper) { -+ List array = Lists.newArrayList(); -+ for (E e : collection) { -+ Object object = mapper.apply(e); -+ if (object != null) { -+ array.add(object); -+ } -+ } -+ return array; -+ } -+ -+ /** -+ * These help build a single JSON Object from a collection, using a mapper function -+ * -+ * @param collection Collection to apply to -+ * @param mapper Mapper to apply -+ * @param Element Type -+ * @return Map -+ */ -+ @NotNull -+ public static Map toObjectMapper(@NotNull E[] collection, @NotNull Function mapper) { -+ return toObjectMapper(Lists.newArrayList(collection), mapper); -+ } -+ -+ @NotNull -+ public static Map toObjectMapper(@NotNull Iterable collection, @NotNull Function mapper) { -+ Map object = Maps.newLinkedHashMap(); -+ for (E e : collection) { -+ JSONPair JSONPair = mapper.apply(e); -+ if (JSONPair != null) { -+ object.put(JSONPair.key, JSONPair.val); -+ } -+ } -+ return object; -+ } -+ -+ /** -+ * Simply stores a key and a value, used internally by many methods below. -+ */ -+ @SuppressWarnings("PublicInnerClass") -+ public static class JSONPair { -+ final String key; -+ final Object val; -+ -+ JSONPair(@NotNull String key, @NotNull Object val) { -+ this.key = key; -+ this.val = val; -+ } -+ } -+} -diff --git a/src/main/java/co/aikar/util/LoadingIntMap.java b/src/main/java/co/aikar/util/LoadingIntMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..63a899c7dbdb69daa4876a2ce2a7dfb734b5af9d ---- /dev/null -+++ b/src/main/java/co/aikar/util/LoadingIntMap.java -@@ -0,0 +1,76 @@ -+/* -+ * Copyright (c) 2015. Starlis LLC / dba Empire Minecraft -+ * -+ * This source code is proprietary software and must not be redistributed without Starlis LLC's approval -+ * -+ */ -+package co.aikar.util; -+ -+ -+import com.google.common.base.Function; -+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Allows you to pass a Loader function that when a key is accessed that doesn't exist, -+ * automatically loads the entry into the map by calling the loader Function. -+ * -+ * .get() Will only return null if the Loader can return null. -+ * -+ * You may pass any backing Map to use. -+ * -+ * This class is not thread safe and should be wrapped with Collections.synchronizedMap on the OUTSIDE of the LoadingMap if needed. -+ * -+ * Do not wrap the backing map with Collections.synchronizedMap. -+ * -+ * @param Value -+ */ -+public class LoadingIntMap extends Int2ObjectOpenHashMap { -+ private final Function loader; -+ -+ public LoadingIntMap(@NotNull Function loader) { -+ super(); -+ this.loader = loader; -+ } -+ -+ public LoadingIntMap(int expectedSize, @NotNull Function loader) { -+ super(expectedSize); -+ this.loader = loader; -+ } -+ -+ public LoadingIntMap(int expectedSize, float loadFactor, @NotNull Function loader) { -+ super(expectedSize, loadFactor); -+ this.loader = loader; -+ } -+ -+ -+ @Nullable -+ @Override -+ public V get(int key) { -+ V res = super.get(key); -+ if (res == null) { -+ res = loader.apply(key); -+ if (res != null) { -+ put(key, res); -+ } -+ } -+ return res; -+ } -+ -+ /** -+ * Due to java stuff, you will need to cast it to (Function) for some cases -+ * -+ * @param Type -+ */ -+ public abstract static class Feeder implements Function { -+ @Nullable -+ @Override -+ public T apply(@Nullable Object input) { -+ return apply(); -+ } -+ -+ @Nullable -+ public abstract T apply(); -+ } -+} -diff --git a/src/main/java/co/aikar/util/LoadingMap.java b/src/main/java/co/aikar/util/LoadingMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..aedbb03321886cb267879d7994653e447b485f6a ---- /dev/null -+++ b/src/main/java/co/aikar/util/LoadingMap.java -@@ -0,0 +1,368 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.util; -+ -+import com.google.common.base.Preconditions; -+import java.lang.reflect.Constructor; -+import java.util.AbstractMap; -+import java.util.Collection; -+import java.util.HashMap; -+import java.util.IdentityHashMap; -+import java.util.Map; -+import java.util.Set; -+import java.util.function.Function; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Allows you to pass a Loader function that when a key is accessed that doesn't exists, -+ * automatically loads the entry into the map by calling the loader Function. -+ * -+ * .get() Will only return null if the Loader can return null. -+ * -+ * You may pass any backing Map to use. -+ * -+ * This class is not thread safe and should be wrapped with Collections.synchronizedMap on the OUTSIDE of the LoadingMap if needed. -+ * -+ * Do not wrap the backing map with Collections.synchronizedMap. -+ * -+ * @param Key -+ * @param Value -+ */ -+public class LoadingMap extends AbstractMap { -+ private final Map backingMap; -+ private final java.util.function.Function loader; -+ -+ /** -+ * Initializes an auto loading map using specified loader and backing map -+ * @param backingMap Map to wrap -+ * @param loader Loader -+ */ -+ public LoadingMap(@NotNull Map backingMap, @NotNull java.util.function.Function loader) { -+ this.backingMap = backingMap; -+ this.loader = loader; -+ } -+ -+ /** -+ * Creates a new LoadingMap with the specified map and loader -+ * -+ * @param backingMap Actual map being used. -+ * @param loader Loader to use -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map -+ */ -+ @NotNull -+ public static Map of(@NotNull Map backingMap, @NotNull Function loader) { -+ return new LoadingMap<>(backingMap, loader); -+ } -+ -+ /** -+ * Creates a LoadingMap with an auto instantiating loader. -+ * -+ * Will auto construct class of of Value when not found -+ * -+ * Since this uses Reflection, It is more effecient to define your own static loader -+ * than using this helper, but if performance is not critical, this is easier. -+ * -+ * @param backingMap Actual map being used. -+ * @param keyClass Class used for the K generic -+ * @param valueClass Class used for the V generic -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map that auto instantiates on .get() -+ */ -+ @NotNull -+ public static Map newAutoMap(@NotNull Map backingMap, @Nullable final Class keyClass, -+ @NotNull final Class valueClass) { -+ return new LoadingMap<>(backingMap, new AutoInstantiatingLoader<>(keyClass, valueClass)); -+ } -+ /** -+ * Creates a LoadingMap with an auto instantiating loader. -+ * -+ * Will auto construct class of of Value when not found -+ * -+ * Since this uses Reflection, It is more effecient to define your own static loader -+ * than using this helper, but if performance is not critical, this is easier. -+ * -+ * @param backingMap Actual map being used. -+ * @param valueClass Class used for the V generic -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map that auto instantiates on .get() -+ */ -+ @NotNull -+ public static Map newAutoMap(@NotNull Map backingMap, -+ @NotNull final Class valueClass) { -+ return newAutoMap(backingMap, null, valueClass); -+ } -+ -+ /** -+ * @see #newAutoMap -+ * -+ * new Auto initializing map using a HashMap. -+ * -+ * @param keyClass Class used for the K generic -+ * @param valueClass Class used for the V generic -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map that auto instantiates on .get() -+ */ -+ @NotNull -+ public static Map newHashAutoMap(@Nullable final Class keyClass, @NotNull final Class valueClass) { -+ return newAutoMap(new HashMap<>(), keyClass, valueClass); -+ } -+ -+ /** -+ * @see #newAutoMap -+ * -+ * new Auto initializing map using a HashMap. -+ * -+ * @param valueClass Class used for the V generic -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map that auto instantiates on .get() -+ */ -+ @NotNull -+ public static Map newHashAutoMap(@NotNull final Class valueClass) { -+ return newHashAutoMap(null, valueClass); -+ } -+ -+ /** -+ * @see #newAutoMap -+ * -+ * new Auto initializing map using a HashMap. -+ * -+ * @param keyClass Class used for the K generic -+ * @param valueClass Class used for the V generic -+ * @param initialCapacity Initial capacity to use -+ * @param loadFactor Load factor to use -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map that auto instantiates on .get() -+ */ -+ @NotNull -+ public static Map newHashAutoMap(@Nullable final Class keyClass, @NotNull final Class valueClass, int initialCapacity, float loadFactor) { -+ return newAutoMap(new HashMap<>(initialCapacity, loadFactor), keyClass, valueClass); -+ } -+ -+ /** -+ * @see #newAutoMap -+ * -+ * new Auto initializing map using a HashMap. -+ * -+ * @param valueClass Class used for the V generic -+ * @param initialCapacity Initial capacity to use -+ * @param loadFactor Load factor to use -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map that auto instantiates on .get() -+ */ -+ @NotNull -+ public static Map newHashAutoMap(@NotNull final Class valueClass, int initialCapacity, float loadFactor) { -+ return newHashAutoMap(null, valueClass, initialCapacity, loadFactor); -+ } -+ -+ /** -+ * Initializes an auto loading map using a HashMap -+ * -+ * @param loader Loader to use -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map -+ */ -+ @NotNull -+ public static Map newHashMap(@NotNull Function loader) { -+ return new LoadingMap<>(new HashMap<>(), loader); -+ } -+ -+ /** -+ * Initializes an auto loading map using a HashMap -+ * -+ * @param loader Loader to use -+ * @param initialCapacity Initial capacity to use -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map -+ */ -+ @NotNull -+ public static Map newHashMap(@NotNull Function loader, int initialCapacity) { -+ return new LoadingMap<>(new HashMap<>(initialCapacity), loader); -+ } -+ /** -+ * Initializes an auto loading map using a HashMap -+ * -+ * @param loader Loader to use -+ * @param initialCapacity Initial capacity to use -+ * @param loadFactor Load factor to use -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map -+ */ -+ @NotNull -+ public static Map newHashMap(@NotNull Function loader, int initialCapacity, float loadFactor) { -+ return new LoadingMap<>(new HashMap<>(initialCapacity, loadFactor), loader); -+ } -+ -+ /** -+ * Initializes an auto loading map using an Identity HashMap -+ * -+ * @param loader Loader to use -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map -+ */ -+ @NotNull -+ public static Map newIdentityHashMap(@NotNull Function loader) { -+ return new LoadingMap<>(new IdentityHashMap<>(), loader); -+ } -+ -+ /** -+ * Initializes an auto loading map using an Identity HashMap -+ * -+ * @param loader Loader to use -+ * @param initialCapacity Initial capacity to use -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map -+ */ -+ @NotNull -+ public static Map newIdentityHashMap(@NotNull Function loader, int initialCapacity) { -+ return new LoadingMap<>(new IdentityHashMap<>(initialCapacity), loader); -+ } -+ -+ @Override -+ public int size() {return backingMap.size();} -+ -+ @Override -+ public boolean isEmpty() {return backingMap.isEmpty();} -+ -+ @Override -+ public boolean containsKey(@Nullable Object key) {return backingMap.containsKey(key);} -+ -+ @Override -+ public boolean containsValue(@Nullable Object value) {return backingMap.containsValue(value);} -+ -+ @Nullable -+ @Override -+ public V get(@Nullable Object key) { -+ V v = backingMap.get(key); -+ if (v != null) { -+ return v; -+ } -+ return backingMap.computeIfAbsent((K) key, loader); -+ } -+ -+ @Nullable -+ public V put(@Nullable K key, @Nullable V value) {return backingMap.put(key, value);} -+ -+ @Nullable -+ @Override -+ public V remove(@Nullable Object key) {return backingMap.remove(key);} -+ -+ public void putAll(@NotNull Map m) {backingMap.putAll(m);} -+ -+ @Override -+ public void clear() {backingMap.clear();} -+ -+ @NotNull -+ @Override -+ public Set keySet() {return backingMap.keySet();} -+ -+ @NotNull -+ @Override -+ public Collection values() {return backingMap.values();} -+ -+ @Override -+ public boolean equals(@Nullable Object o) {return backingMap.equals(o);} -+ -+ @Override -+ public int hashCode() {return backingMap.hashCode();} -+ -+ @NotNull -+ @Override -+ public Set> entrySet() { -+ return backingMap.entrySet(); -+ } -+ -+ @NotNull -+ public LoadingMap clone() { -+ return new LoadingMap<>(backingMap, loader); -+ } -+ -+ private static class AutoInstantiatingLoader implements Function { -+ final Constructor constructor; -+ private final Class valueClass; -+ -+ AutoInstantiatingLoader(@Nullable Class keyClass, @NotNull Class valueClass) { -+ try { -+ this.valueClass = valueClass; -+ if (keyClass != null) { -+ constructor = valueClass.getConstructor(keyClass); -+ } else { -+ constructor = null; -+ } -+ } catch (NoSuchMethodException e) { -+ throw new IllegalStateException( -+ valueClass.getName() + " does not have a constructor for " + (keyClass != null ? keyClass.getName() : null)); -+ } -+ } -+ -+ @NotNull -+ @Override -+ public V apply(@Nullable K input) { -+ try { -+ return (constructor != null ? constructor.newInstance(input) : valueClass.newInstance()); -+ } catch (Exception e) { -+ throw new ExceptionInInitializerError(e); -+ } -+ } -+ -+ @Override -+ public int hashCode() { -+ return super.hashCode(); -+ } -+ -+ @Override -+ public boolean equals(Object object) { -+ return false; -+ } -+ } -+ -+ /** -+ * Due to java stuff, you will need to cast it to (Function) for some cases -+ * -+ * @param Type -+ */ -+ public abstract static class Feeder implements Function { -+ @Nullable -+ @Override -+ public T apply(@Nullable Object input) { -+ return apply(); -+ } -+ -+ @Nullable -+ public abstract T apply(); -+ } -+} -diff --git a/src/main/java/co/aikar/util/MRUMapCache.java b/src/main/java/co/aikar/util/MRUMapCache.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5989ee21297935651b0edd44b8239e655eaef1d9 ---- /dev/null -+++ b/src/main/java/co/aikar/util/MRUMapCache.java -@@ -0,0 +1,111 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+package co.aikar.util; -+ -+import java.util.AbstractMap; -+import java.util.Collection; -+import java.util.Map; -+import java.util.Set; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Implements a Most Recently Used cache in front of a backing map, to quickly access the last accessed result. -+ * -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ */ -+public class MRUMapCache extends AbstractMap { -+ final Map backingMap; -+ Object cacheKey; -+ V cacheValue; -+ public MRUMapCache(@NotNull final Map backingMap) { -+ this.backingMap = backingMap; -+ } -+ -+ public int size() {return backingMap.size();} -+ -+ public boolean isEmpty() {return backingMap.isEmpty();} -+ -+ public boolean containsKey(@Nullable Object key) { -+ return key != null && key.equals(cacheKey) || backingMap.containsKey(key); -+ } -+ -+ public boolean containsValue(@Nullable Object value) { -+ return value != null && value == cacheValue || backingMap.containsValue(value); -+ } -+ -+ @Nullable -+ public V get(@Nullable Object key) { -+ if (cacheKey != null && cacheKey.equals(key)) { -+ return cacheValue; -+ } -+ cacheKey = key; -+ return cacheValue = backingMap.get(key); -+ } -+ -+ @Nullable -+ public V put(@Nullable K key, @Nullable V value) { -+ cacheKey = key; -+ return cacheValue = backingMap.put(key, value); -+ } -+ -+ @Nullable -+ public V remove(@Nullable Object key) { -+ if (key != null && key.equals(cacheKey)) { -+ cacheKey = null; -+ } -+ return backingMap.remove(key); -+ } -+ -+ public void putAll(@NotNull Map m) {backingMap.putAll(m);} -+ -+ public void clear() { -+ cacheKey = null; -+ cacheValue = null; -+ backingMap.clear(); -+ } -+ -+ @NotNull -+ public Set keySet() {return backingMap.keySet();} -+ -+ @NotNull -+ public Collection values() {return backingMap.values();} -+ -+ @NotNull -+ public Set> entrySet() {return backingMap.entrySet();} -+ -+ /** -+ * Wraps the specified map with a most recently used cache -+ * -+ * @param map Map to be wrapped -+ * @param Key Type of the Map -+ * @param Value Type of the Map -+ * @return Map -+ */ -+ @NotNull -+ public static Map of(@NotNull Map map) { -+ return new MRUMapCache(map); -+ } -+} -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index ba57a093a2df3c65036377e3093eedabeda7c6f5..9b118067de5eb54b266b8349fce7efdec2cb36eb 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -801,7 +801,6 @@ public final class Bukkit { - */ - public static void reload() { - server.reload(); -- org.spigotmc.CustomTimingsHandler.reload(); // Spigot - } - - /** -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 5af7da1d3d62cada69240e2d22db2a32278b0074..0a433146ebec4416339c4ab33f3523a22d23d332 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1755,6 +1755,26 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - throw new UnsupportedOperationException("Not supported yet."); - } - -+ // Paper start -+ @NotNull -+ public org.bukkit.configuration.file.YamlConfiguration getBukkitConfig() -+ { -+ throw new UnsupportedOperationException( "Not supported yet." ); -+ } -+ -+ @NotNull -+ public org.bukkit.configuration.file.YamlConfiguration getSpigotConfig() -+ { -+ throw new UnsupportedOperationException("Not supported yet."); -+ } -+ -+ @NotNull -+ public org.bukkit.configuration.file.YamlConfiguration getPaperConfig() -+ { -+ throw new UnsupportedOperationException("Not supported yet."); -+ } -+ // Paper end -+ - /** - * Sends the component to the player - * -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index fa28b5bb0efd9d400277cd8969f38e039e6ea8ac..c9ecd5b1908e05a1b39dadcded27241672adcddf 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -31,6 +31,7 @@ public interface UnsafeValues { - @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer legacyComponentSerializer(); - // Paper end - -+ void reportTimings(); // Paper - Material toLegacy(Material material); - - Material fromLegacy(Material material); -@@ -86,4 +87,12 @@ public interface UnsafeValues { - Multimap getDefaultAttributeModifiers(Material material, EquipmentSlot slot); - - CreativeCategory getCreativeCategory(Material material); -+ -+ // Paper start -+ /** -+ * Server name to report to timings v2 -+ * @return name -+ */ -+ String getTimingsServerName(); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/command/BufferedCommandSender.java b/src/main/java/org/bukkit/command/BufferedCommandSender.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f9a00aecca5ec41b460bf41dfe1c69694768cf98 ---- /dev/null -+++ b/src/main/java/org/bukkit/command/BufferedCommandSender.java -@@ -0,0 +1,21 @@ -+package org.bukkit.command; -+ -+import org.jetbrains.annotations.NotNull; -+ -+public class BufferedCommandSender implements MessageCommandSender { -+ private final StringBuffer buffer = new StringBuffer(); -+ @Override -+ public void sendMessage(@NotNull String message) { -+ buffer.append(message); -+ buffer.append("\n"); -+ } -+ -+ @NotNull -+ public String getBuffer() { -+ return buffer.toString(); -+ } -+ -+ public void reset() { -+ this.buffer.setLength(0); -+ } -+} -diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java -index 57ade3963faae3724d9a01eeeb6d02168acb567e..6fd341482d5250ad814e870360e40b52427f799a 100644 ---- a/src/main/java/org/bukkit/command/Command.java -+++ b/src/main/java/org/bukkit/command/Command.java -@@ -33,6 +33,8 @@ public abstract class Command { - protected String usageMessage; - private String permission; - private net.kyori.adventure.text.Component permissionMessage; // Paper -+ public co.aikar.timings.Timing timings; // Paper -+ @NotNull public String getTimingName() {return getName();} // Paper - - protected Command(@NotNull String name) { - this(name, "", "/" + name, new ArrayList()); -@@ -46,7 +48,6 @@ public abstract class Command { - this.usageMessage = (usageMessage == null) ? "/" + name : usageMessage; - this.aliases = aliases; - this.activeAliases = new ArrayList(aliases); -- this.timings = new org.spigotmc.CustomTimingsHandler("** Command: " + name); // Spigot - } - - /** -@@ -244,7 +245,6 @@ public abstract class Command { - } - this.nextLabel = name; - if (!isRegistered()) { -- this.timings = new org.spigotmc.CustomTimingsHandler("** Command: " + name); // Spigot - this.label = name; - return true; - } -diff --git a/src/main/java/org/bukkit/command/FormattedCommandAlias.java b/src/main/java/org/bukkit/command/FormattedCommandAlias.java -index d6c8938b1e13b63116b7b0e074ea8ef5997f8dc3..a6ad94ef98a1df1d2842635d850bc990b0137849 100644 ---- a/src/main/java/org/bukkit/command/FormattedCommandAlias.java -+++ b/src/main/java/org/bukkit/command/FormattedCommandAlias.java -@@ -9,6 +9,7 @@ public class FormattedCommandAlias extends Command { - - public FormattedCommandAlias(@NotNull String alias, @NotNull String[] formatStrings) { - super(alias); -+ timings = co.aikar.timings.TimingsManager.getCommandTiming("minecraft", this); // Spigot - this.formatStrings = formatStrings; - } - -@@ -113,6 +114,10 @@ public class FormattedCommandAlias extends Command { - return formatString; - } - -+ @NotNull -+ @Override // Paper -+ public String getTimingName() {return "Command Forwarder - " + super.getTimingName();} // Paper -+ - private static boolean inRange(int i, int j, int k) { - return i >= j && i <= k; - } -diff --git a/src/main/java/org/bukkit/command/MessageCommandSender.java b/src/main/java/org/bukkit/command/MessageCommandSender.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9d263ab3afb938c215c0b64d9171345fca6ceb2c ---- /dev/null -+++ b/src/main/java/org/bukkit/command/MessageCommandSender.java -@@ -0,0 +1,135 @@ -+package org.bukkit.command; -+ -+import org.bukkit.Bukkit; -+import org.bukkit.Server; -+import org.bukkit.permissions.Permission; -+import org.bukkit.permissions.PermissionAttachment; -+import org.bukkit.permissions.PermissionAttachmentInfo; -+import org.bukkit.plugin.Plugin; -+ -+import java.util.Set; -+import java.util.UUID; -+ -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * For when all you care about is just messaging -+ */ -+public interface MessageCommandSender extends CommandSender { -+ -+ @Override -+ default void sendMessage(@NotNull String[] messages) { -+ for (String message : messages) { -+ sendMessage(message); -+ } -+ } -+ -+ @Override -+ default void sendMessage(@Nullable UUID sender, @NotNull String message) { -+ sendMessage(message); -+ } -+ -+ @Override -+ default void sendMessage(@Nullable UUID sender, @NotNull String[] messages) { -+ for (String message : messages) { -+ sendMessage(message); -+ } -+ } -+ -+ @NotNull -+ @Override -+ default Server getServer() { -+ return Bukkit.getServer(); -+ } -+ -+ // Paper start -+ @Override -+ default net.kyori.adventure.text.@org.jetbrains.annotations.NotNull Component name() { -+ throw new UnsupportedOperationException(); -+ } -+ // Paper end -+ -+ @NotNull -+ @Override -+ default String getName() { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ default boolean isOp() { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ default void setOp(boolean value) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ default boolean isPermissionSet(@NotNull String name) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ default boolean isPermissionSet(@NotNull Permission perm) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ default boolean hasPermission(@NotNull String name) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ default boolean hasPermission(@NotNull Permission perm) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @NotNull -+ @Override -+ default PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @NotNull -+ @Override -+ default PermissionAttachment addAttachment(@NotNull Plugin plugin) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @NotNull -+ @Override -+ default PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value, int ticks) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @NotNull -+ @Override -+ default PermissionAttachment addAttachment(@NotNull Plugin plugin, int ticks) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ default void removeAttachment(@NotNull PermissionAttachment attachment) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ default void recalculatePermissions() { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @NotNull -+ @Override -+ default Set getEffectivePermissions() { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @NotNull -+ @Override -+ default Spigot spigot() { -+ throw new UnsupportedOperationException(); -+ } -+ -+} -diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java -index e195e74c48c69047aa825b75fad95419c505b41f..f99d71301ceaa3af07ff0525f7d657ac6253d0e6 100644 ---- a/src/main/java/org/bukkit/command/SimpleCommandMap.java -+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java -@@ -15,7 +15,6 @@ import org.bukkit.command.defaults.BukkitCommand; - import org.bukkit.command.defaults.HelpCommand; - import org.bukkit.command.defaults.PluginsCommand; - import org.bukkit.command.defaults.ReloadCommand; --import org.bukkit.command.defaults.TimingsCommand; - import org.bukkit.command.defaults.VersionCommand; - import org.bukkit.entity.Player; - import org.bukkit.util.StringUtil; -@@ -35,7 +34,7 @@ public class SimpleCommandMap implements CommandMap { - register("bukkit", new VersionCommand("version")); - register("bukkit", new ReloadCommand("reload")); - register("bukkit", new PluginsCommand("plugins")); -- register("bukkit", new TimingsCommand("timings")); -+ register("bukkit", new co.aikar.timings.TimingsCommand("timings")); // Paper - } - - public void setFallbackCommands() { -@@ -67,6 +66,7 @@ public class SimpleCommandMap implements CommandMap { - */ - @Override - public boolean register(@NotNull String label, @NotNull String fallbackPrefix, @NotNull Command command) { -+ command.timings = co.aikar.timings.TimingsManager.getCommandTiming(fallbackPrefix, command); // Paper - label = label.toLowerCase(java.util.Locale.ENGLISH).trim(); - fallbackPrefix = fallbackPrefix.toLowerCase(java.util.Locale.ENGLISH).trim(); - boolean registered = register(label, command, false, fallbackPrefix); -@@ -143,16 +143,22 @@ public class SimpleCommandMap implements CommandMap { - return false; - } - -+ // Paper start - Plugins do weird things to workaround normal registration -+ if (target.timings == null) { -+ target.timings = co.aikar.timings.TimingsManager.getCommandTiming(null, target); -+ } -+ // Paper end -+ - try { -- target.timings.startTiming(); // Spigot -+ try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources - // Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false) - target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length)); -- target.timings.stopTiming(); // Spigot -+ } // target.timings.stopTiming(); // Spigot // Paper - } catch (CommandException ex) { -- target.timings.stopTiming(); // Spigot -+ //target.timings.stopTiming(); // Spigot // Paper - throw ex; - } catch (Throwable ex) { -- target.timings.stopTiming(); // Spigot -+ //target.timings.stopTiming(); // Spigot // Paper - throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex); - } - -diff --git a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java -deleted file mode 100644 -index 516d7fc7812aac343782861d0d567f54aa578c2a..0000000000000000000000000000000000000000 ---- a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java -+++ /dev/null -@@ -1,250 +0,0 @@ --package org.bukkit.command.defaults; -- --import com.google.common.base.Preconditions; --import com.google.common.collect.ImmutableList; --import java.io.File; --import java.io.IOException; --import java.io.PrintStream; --import java.util.ArrayList; --import java.util.List; --import org.bukkit.Bukkit; --import org.bukkit.ChatColor; --import org.bukkit.command.CommandSender; --import org.bukkit.event.Event; --import org.bukkit.event.HandlerList; --import org.bukkit.plugin.Plugin; --import org.bukkit.plugin.RegisteredListener; --import org.bukkit.plugin.TimedRegisteredListener; --import org.bukkit.util.StringUtil; --import org.jetbrains.annotations.NotNull; -- --// Spigot start --// CHECKSTYLE:OFF --import java.io.ByteArrayOutputStream; --import java.io.OutputStream; --import java.net.HttpURLConnection; --import java.net.URL; --import java.util.logging.Level; --import org.bukkit.command.RemoteConsoleCommandSender; --import org.bukkit.plugin.SimplePluginManager; --import org.spigotmc.CustomTimingsHandler; --// CHECKSTYLE:ON --// Spigot end -- --public class TimingsCommand extends BukkitCommand { -- private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("report", "reset", "on", "off", "paste"); // Spigot -- public static long timingStart = 0; // Spigot -- -- public TimingsCommand(@NotNull String name) { -- super(name); -- this.description = "Manages Spigot Timings data to see performance of the server."; // Spigot -- this.usageMessage = "/timings "; // Spigot -- this.setPermission("bukkit.command.timings"); -- } -- -- // Spigot start - redesigned Timings Command -- public void executeSpigotTimings(@NotNull CommandSender sender, @NotNull String[] args) { -- if ("on".equals(args[0])) { -- ((SimplePluginManager) Bukkit.getPluginManager()).useTimings(true); -- CustomTimingsHandler.reload(); -- sender.sendMessage("Enabled Timings & Reset"); -- return; -- } else if ("off".equals(args[0])) { -- ((SimplePluginManager) Bukkit.getPluginManager()).useTimings(false); -- sender.sendMessage("Disabled Timings"); -- return; -- } -- -- if (!Bukkit.getPluginManager().useTimings()) { -- sender.sendMessage("Please enable timings by typing /timings on"); -- return; -- } -- -- boolean paste = "paste".equals(args[0]); -- if ("reset".equals(args[0])) { -- CustomTimingsHandler.reload(); -- sender.sendMessage("Timings reset"); -- } else if ("merged".equals(args[0]) || "report".equals(args[0]) || paste) { -- long sampleTime = System.nanoTime() - timingStart; -- int index = 0; -- File timingFolder = new File("timings"); -- timingFolder.mkdirs(); -- File timings = new File(timingFolder, "timings.txt"); -- ByteArrayOutputStream bout = (paste) ? new ByteArrayOutputStream() : null; -- while (timings.exists()) timings = new File(timingFolder, "timings" + (++index) + ".txt"); -- PrintStream fileTimings = null; -- try { -- fileTimings = (paste) ? new PrintStream(bout) : new PrintStream(timings); -- -- CustomTimingsHandler.printTimings(fileTimings); -- fileTimings.println("Sample time " + sampleTime + " (" + sampleTime / 1E9 + "s)"); -- -- fileTimings.println(""); -- fileTimings.println(Bukkit.spigot().getConfig().saveToString()); -- fileTimings.println(""); -- -- if (paste) { -- new PasteThread(sender, bout).start(); -- return; -- } -- -- sender.sendMessage("Timings written to " + timings.getPath()); -- sender.sendMessage("Paste contents of file into form at http://www.spigotmc.org/go/timings to read results."); -- -- } catch (IOException e) { -- } finally { -- if (fileTimings != null) { -- fileTimings.close(); -- } -- } -- } -- } -- // Spigot end -- -- @Override -- public boolean execute(@NotNull CommandSender sender, @NotNull String currentAlias, @NotNull String[] args) { -- if (!testPermission(sender)) return true; -- if (args.length < 1) { // Spigot -- sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); -- return false; -- } -- // Spigot start -- if (true) { -- executeSpigotTimings(sender, args); -- return true; -- } -- // Spigot end -- if (!sender.getServer().getPluginManager().useTimings()) { -- sender.sendMessage("Please enable timings by setting \"settings.plugin-profiling\" to true in bukkit.yml"); -- return true; -- } -- -- boolean separate = "separate".equalsIgnoreCase(args[0]); -- if ("reset".equalsIgnoreCase(args[0])) { -- for (HandlerList handlerList : HandlerList.getHandlerLists()) { -- for (RegisteredListener listener : handlerList.getRegisteredListeners()) { -- if (listener instanceof TimedRegisteredListener) { -- ((TimedRegisteredListener) listener).reset(); -- } -- } -- } -- sender.sendMessage("Timings reset"); -- } else if ("merged".equalsIgnoreCase(args[0]) || separate) { -- -- int index = 0; -- int pluginIdx = 0; -- File timingFolder = new File("timings"); -- timingFolder.mkdirs(); -- File timings = new File(timingFolder, "timings.txt"); -- File names = null; -- while (timings.exists()) timings = new File(timingFolder, "timings" + (++index) + ".txt"); -- PrintStream fileTimings = null; -- PrintStream fileNames = null; -- try { -- fileTimings = new PrintStream(timings); -- if (separate) { -- names = new File(timingFolder, "names" + index + ".txt"); -- fileNames = new PrintStream(names); -- } -- for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { -- pluginIdx++; -- long totalTime = 0; -- if (separate) { -- fileNames.println(pluginIdx + " " + plugin.getDescription().getFullName()); -- fileTimings.println("Plugin " + pluginIdx); -- } else { -- fileTimings.println(plugin.getDescription().getFullName()); -- } -- for (RegisteredListener listener : HandlerList.getRegisteredListeners(plugin)) { -- if (listener instanceof TimedRegisteredListener) { -- TimedRegisteredListener trl = (TimedRegisteredListener) listener; -- long time = trl.getTotalTime(); -- int count = trl.getCount(); -- if (count == 0) continue; -- long avg = time / count; -- totalTime += time; -- Class eventClass = trl.getEventClass(); -- if (count > 0 && eventClass != null) { -- fileTimings.println(" " + eventClass.getSimpleName() + (trl.hasMultiple() ? " (and sub-classes)" : "") + " Time: " + time + " Count: " + count + " Avg: " + avg); -- } -- } -- } -- fileTimings.println(" Total time " + totalTime + " (" + totalTime / 1000000000 + "s)"); -- } -- sender.sendMessage("Timings written to " + timings.getPath()); -- if (separate) sender.sendMessage("Names written to " + names.getPath()); -- } catch (IOException e) { -- } finally { -- if (fileTimings != null) { -- fileTimings.close(); -- } -- if (fileNames != null) { -- fileNames.close(); -- } -- } -- } else { -- sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); -- return false; -- } -- return true; -- } -- -- @NotNull -- @Override -- public List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { -- Preconditions.checkArgument(sender != null, "Sender cannot be null"); -- Preconditions.checkArgument(args != null, "Arguments cannot be null"); -- Preconditions.checkArgument(alias != null, "Alias cannot be null"); -- -- if (args.length == 1) { -- return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS, new ArrayList(TIMINGS_SUBCOMMANDS.size())); -- } -- return ImmutableList.of(); -- } -- -- // Spigot start -- private static class PasteThread extends Thread { -- -- private final CommandSender sender; -- private final ByteArrayOutputStream bout; -- -- public PasteThread(@NotNull CommandSender sender, @NotNull ByteArrayOutputStream bout) { -- super("Timings paste thread"); -- this.sender = sender; -- this.bout = bout; -- } -- -- @Override -- public synchronized void start() { -- if (sender instanceof RemoteConsoleCommandSender) { -- run(); -- } else { -- super.start(); -- } -- } -- -- @Override -- public void run() { -- try { -- HttpURLConnection con = (HttpURLConnection) new URL("https://timings.spigotmc.org/paste").openConnection(); -- con.setDoOutput(true); -- con.setRequestMethod("POST"); -- con.setInstanceFollowRedirects(false); -- -- OutputStream out = con.getOutputStream(); -- out.write(bout.toByteArray()); -- out.close(); -- -- com.google.gson.JsonObject location = new com.google.gson.Gson().fromJson(new java.io.InputStreamReader(con.getInputStream()), com.google.gson.JsonObject.class); -- con.getInputStream().close(); -- -- String pasteID = location.get("key").getAsString(); -- sender.sendMessage(ChatColor.GREEN + "Timings results can be viewed at https://www.spigotmc.org/go/timings?url=" + pasteID); -- } catch (IOException ex) { -- sender.sendMessage(ChatColor.RED + "Error pasting timings, check your console for more information"); -- Bukkit.getServer().getLogger().log(Level.WARNING, "Could not paste timings", ex); -- } -- } -- } -- // Spigot end --} -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index c580ec19cd2b55a4aeca49d9cd984ce7c2848cef..ab127d622b51e423883cbd9a7218f1cff6c2fdc1 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -1980,7 +1980,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - @Deprecated // Paper - public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @Nullable UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { - throw new UnsupportedOperationException("Not supported yet."); -+ -+ } -+ -+ // Paper start -+ public int getPing() { -+ throw new UnsupportedOperationException( "Not supported yet." ); - } -+ // Paper end - } - - @NotNull -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index f5710d53296564eb4cd94382dc79f4c29769b672..fca73778c341df36becbf1ad1ad42ce8d1aa634c 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -357,7 +357,6 @@ public final class SimplePluginManager implements PluginManager { - } - } - -- org.bukkit.command.defaults.TimingsCommand.timingStart = System.nanoTime(); // Spigot - return result.toArray(new Plugin[result.size()]); - } - -@@ -396,9 +395,9 @@ public final class SimplePluginManager implements PluginManager { - - if (result != null) { - plugins.add(result); -- lookupNames.put(result.getDescription().getName(), result); -+ lookupNames.put(result.getDescription().getName().toLowerCase(java.util.Locale.ENGLISH), result); // Paper - for (String provided : result.getDescription().getProvides()) { -- lookupNames.putIfAbsent(provided, result); -+ lookupNames.putIfAbsent(provided.toLowerCase(java.util.Locale.ENGLISH), result); // Paper - } - } - -@@ -427,7 +426,7 @@ public final class SimplePluginManager implements PluginManager { - @Override - @Nullable - public synchronized Plugin getPlugin(@NotNull String name) { -- return lookupNames.get(name.replace(' ', '_')); -+ return lookupNames.get(name.replace(' ', '_').toLowerCase(java.util.Locale.ENGLISH)); // Paper - } - - @Override -@@ -645,7 +644,8 @@ public final class SimplePluginManager implements PluginManager { - throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled"); - } - -- if (useTimings) { -+ executor = new co.aikar.timings.TimedEventExecutor(executor, plugin, null, event); // Paper -+ if (false) { // Spigot - RL handles useTimings check now // Paper - getEventListeners(event).register(new TimedRegisteredListener(listener, executor, priority, plugin, ignoreCancelled)); - } else { - getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled)); -@@ -860,7 +860,7 @@ public final class SimplePluginManager implements PluginManager { - - @Override - public boolean useTimings() { -- return useTimings; -+ return co.aikar.timings.Timings.isTimingsEnabled(); // Spigot - } - - /** -@@ -869,6 +869,6 @@ public final class SimplePluginManager implements PluginManager { - * @param use True if per event timing code should be used - */ - public void useTimings(boolean use) { -- useTimings = use; -+ co.aikar.timings.Timings.setTimingsEnabled(use); // Paper - } - } -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index 047c0304fd617cec990f80815b43916c6ef5a94c..5c1b8b05d8a5408bb4830942c74ebfe400ab5a32 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -54,7 +54,6 @@ public final class JavaPluginLoader implements PluginLoader { - private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")}; - private final List loaders = new CopyOnWriteArrayList(); - private final LibraryLoader libraryLoader; -- public static final CustomTimingsHandler pluginParentTimer = new CustomTimingsHandler("** Plugins"); // Spigot - - /** - * This class was not meant to be constructed explicitly -@@ -292,27 +291,21 @@ public final class JavaPluginLoader implements PluginLoader { - } - } - -- final CustomTimingsHandler timings = new CustomTimingsHandler("Plugin: " + plugin.getDescription().getFullName() + " Event: " + listener.getClass().getName() + "::" + method.getName() + "(" + eventClass.getSimpleName() + ")", pluginParentTimer); // Spigot -- EventExecutor executor = new EventExecutor() { -+ EventExecutor executor = new co.aikar.timings.TimedEventExecutor(new EventExecutor() { // Paper - @Override -- public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { -+ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { // Paper - try { - if (!eventClass.isAssignableFrom(event.getClass())) { - return; - } -- // Spigot start -- boolean isAsync = event.isAsynchronous(); -- if (!isAsync) timings.startTiming(); - method.invoke(listener, event); -- if (!isAsync) timings.stopTiming(); -- // Spigot end - } catch (InvocationTargetException ex) { - throw new EventException(ex.getCause()); - } catch (Throwable t) { - throw new EventException(t); - } - } -- }; -+ }, plugin, method, eventClass); // Paper - if (false) { // Spigot - RL handles useTimings check now - eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); - } else { -diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -index 2f74ec96ece706de23156ebabfe493211bc05391..6148b69af39344f758b05a28c7c572befa9b8f3f 100644 ---- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -@@ -29,7 +29,8 @@ import org.jetbrains.annotations.Nullable; - /** - * A ClassLoader for plugins, to allow shared classes across multiple plugins - */ --final class PluginClassLoader extends URLClassLoader { -+public final class PluginClassLoader extends URLClassLoader { // Spigot -+ public JavaPlugin getPlugin() { return plugin; } // Spigot - private final JavaPluginLoader loader; - private final Map> classes = new ConcurrentHashMap>(); - private final PluginDescriptionFile description; -diff --git a/src/main/java/org/bukkit/util/CachedServerIcon.java b/src/main/java/org/bukkit/util/CachedServerIcon.java -index 5ca863b3692b2e1b58e7fb4d82f554a92cc4f01e..612958a331575d1da2715531ebdf6b1168f2e860 100644 ---- a/src/main/java/org/bukkit/util/CachedServerIcon.java -+++ b/src/main/java/org/bukkit/util/CachedServerIcon.java -@@ -2,6 +2,7 @@ package org.bukkit.util; - - import org.bukkit.Server; - import org.bukkit.event.server.ServerListPingEvent; -+import org.jetbrains.annotations.Nullable; - - /** - * This is a cached version of a server-icon. It's internal representation -@@ -12,4 +13,9 @@ import org.bukkit.event.server.ServerListPingEvent; - * @see Server#loadServerIcon(java.io.File) - * @see ServerListPingEvent#setServerIcon(CachedServerIcon) - */ --public interface CachedServerIcon {} -+public interface CachedServerIcon { -+ -+ @Nullable -+ public String getData(); // Paper -+ -+} -diff --git a/src/main/java/org/spigotmc/CustomTimingsHandler.java b/src/main/java/org/spigotmc/CustomTimingsHandler.java -index 44badfedcc3fdc26bdc293b85d8c781d6f659faa..123647bb10fc89508437d7a0bd3fd31d58ee7c82 100644 ---- a/src/main/java/org/spigotmc/CustomTimingsHandler.java -+++ b/src/main/java/org/spigotmc/CustomTimingsHandler.java -@@ -1,137 +1,67 @@ -+/* -+ * This file is licensed under the MIT License (MIT). -+ * -+ * Copyright (c) 2014 Daniel Ennis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ - package org.spigotmc; - --import java.io.PrintStream; --import java.util.Queue; --import java.util.concurrent.ConcurrentLinkedQueue; - import org.bukkit.Bukkit; --import org.bukkit.World; --import org.bukkit.command.defaults.TimingsCommand; - import org.jetbrains.annotations.NotNull; --import org.jetbrains.annotations.Nullable; -+import org.bukkit.plugin.AuthorNagException; -+import co.aikar.timings.Timing; -+import co.aikar.timings.Timings; -+import co.aikar.timings.TimingsManager; -+ -+import java.lang.reflect.Method; -+import java.util.logging.Level; - - /** -- * Provides custom timing sections for /timings merged. -+ * This is here for legacy purposes incase any plugin used it. -+ * -+ * If you use this, migrate ASAP as this will be removed in the future! -+ * -+ * @deprecated -+ * @see co.aikar.timings.Timings#of - */ --public class CustomTimingsHandler { -- -- private static Queue HANDLERS = new ConcurrentLinkedQueue(); -- /*========================================================================*/ -- private final String name; -- private final CustomTimingsHandler parent; -- private long count = 0; -- private long start = 0; -- private long timingDepth = 0; -- private long totalTime = 0; -- private long curTickTotal = 0; -- private long violations = 0; -+@Deprecated -+public final class CustomTimingsHandler { -+ private final Timing handler; - - public CustomTimingsHandler(@NotNull String name) { -- this(name, null); -- } -- -- public CustomTimingsHandler(@NotNull String name, @Nullable CustomTimingsHandler parent) { -- this.name = name; -- this.parent = parent; -- HANDLERS.add(this); -- } -- -- /** -- * Prints the timings and extra data to the given stream. -- * -- * @param printStream output stream -- */ -- public static void printTimings(@NotNull PrintStream printStream) { -- printStream.println("Minecraft"); -- for (CustomTimingsHandler timings : HANDLERS) { -- long time = timings.totalTime; -- long count = timings.count; -- if (count == 0) { -- continue; -- } -- long avg = time / count; -- -- printStream.println(" " + timings.name + " Time: " + time + " Count: " + count + " Avg: " + avg + " Violations: " + timings.violations); -- } -- printStream.println("# Version " + Bukkit.getVersion()); -- int entities = 0; -- int livingEntities = 0; -- for (World world : Bukkit.getWorlds()) { -- entities += world.getEntities().size(); -- livingEntities += world.getLivingEntities().size(); -- } -- printStream.println("# Entities " + entities); -- printStream.println("# LivingEntities " + livingEntities); -- } -- -- /** -- * Resets all timings. -- */ -- public static void reload() { -- if (Bukkit.getPluginManager().useTimings()) { -- for (CustomTimingsHandler timings : HANDLERS) { -- timings.reset(); -- } -- } -- TimingsCommand.timingStart = System.nanoTime(); -- } -- -- /** -- * Ticked every tick by CraftBukkit to count the number of times a timer -- * caused TPS loss. -- */ -- public static void tick() { -- if (Bukkit.getPluginManager().useTimings()) { -- for (CustomTimingsHandler timings : HANDLERS) { -- if (timings.curTickTotal > 50000000) { -- timings.violations += Math.ceil(timings.curTickTotal / 50000000); -- } -- timings.curTickTotal = 0; -- timings.timingDepth = 0; // incase reset messes this up -- } -- } -- } -+ Timing timing; - -- /** -- * Starts timing to track a section of code. -- */ -- public void startTiming() { -- // If second condtion fails we are already timing -- if (Bukkit.getPluginManager().useTimings() && ++timingDepth == 1) { -- start = System.nanoTime(); -- if (parent != null && ++parent.timingDepth == 1) { -- parent.start = start; -- } -+ new AuthorNagException("Deprecated use of CustomTimingsHandler. Please Switch to Timings.of ASAP").printStackTrace(); -+ try { -+ final Method ofSafe = TimingsManager.class.getDeclaredMethod("getHandler", String.class, String.class, Timing.class); -+ ofSafe.setAccessible(true); -+ timing = (Timing) ofSafe.invoke(null,"Minecraft", "(Deprecated API) " + name, null); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ Bukkit.getLogger().log(Level.SEVERE, "This handler could not be registered"); -+ timing = Timings.NULL_HANDLER; - } -+ handler = timing; - } - -- /** -- * Stops timing a section of code. -- */ -- public void stopTiming() { -- if (Bukkit.getPluginManager().useTimings()) { -- if (--timingDepth != 0 || start == 0) { -- return; -- } -- long diff = System.nanoTime() - start; -- totalTime += diff; -- curTickTotal += diff; -- count++; -- start = 0; -- if (parent != null) { -- parent.stopTiming(); -- } -- } -- } -+ public void startTiming() { handler.startTiming(); } -+ public void stopTiming() { handler.stopTiming(); } - -- /** -- * Reset this timer, setting all values to zero. -- */ -- public void reset() { -- count = 0; -- violations = 0; -- curTickTotal = 0; -- totalTime = 0; -- start = 0; -- timingDepth = 0; -- } - } diff --git a/patches/api/0008-Add-command-line-option-to-load-extra-plugin-jars-no.patch b/patches/api/0008-Add-command-line-option-to-load-extra-plugin-jars-no.patch deleted file mode 100644 index 50d4749ccb1f..000000000000 --- a/patches/api/0008-Add-command-line-option-to-load-extra-plugin-jars-no.patch +++ /dev/null @@ -1,181 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Tue, 18 May 2021 14:42:26 -0700 -Subject: [PATCH] Add command line option to load extra plugin jars not in the - plugins folder - -ex: java -jar paperclip.jar nogui -add-plugin=/path/to/plugin.jar -add-plugin=/path/to/another/plugin_jar.jar - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 35de49ea52b507dd925ed3c118518a335035a710..5c6b7f5095a5bb7290e1edefb0c9e985123f80d8 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -75,6 +75,20 @@ public final class Bukkit { - return server; - } - -+ /** -+ * Returns the de facto plugins directory, generally used for storing plugin jars to be loaded, -+ * as well as their {@link org.bukkit.plugin.Plugin#getDataFolder() data folders}. -+ * -+ *

      Plugins should use {@link org.bukkit.plugin.Plugin#getDataFolder()} rather than traversing this -+ * directory manually when determining the location in which to store their data and configuration files.

      -+ * -+ * @return plugins directory -+ */ -+ @NotNull -+ public static File getPluginsFolder() { -+ return server.getPluginsFolder(); -+ } -+ - /** - * Attempts to set the {@link Server} singleton. - *

      -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index bbb4eb3c4e46ade7dd939c2b0e4436161d6f8a1e..1dedbea03e259679e101a8443b662b20375adfd0 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -60,6 +60,18 @@ import org.jetbrains.annotations.Nullable; - */ - public interface Server extends PluginMessageRecipient, net.kyori.adventure.audience.ForwardingAudience { // Paper - -+ /** -+ * Returns the de facto plugins directory, generally used for storing plugin jars to be loaded, -+ * as well as their {@link org.bukkit.plugin.Plugin#getDataFolder() data folders}. -+ * -+ *

      Plugins should use {@link org.bukkit.plugin.Plugin#getDataFolder()} rather than traversing this -+ * directory manually when determining the location in which to store their data and configuration files.

      -+ * -+ * @return plugins directory -+ */ -+ @NotNull -+ File getPluginsFolder(); -+ - /** - * Used for all administrative messages, such as an operator using a - * command. -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index fca73778c341df36becbf1ad1ad42ce8d1aa634c..50a2e8c138c677c91dad65c850acf840f7517e86 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -110,6 +110,12 @@ public final class SimplePluginManager implements PluginManager { - @Override - @NotNull - public Plugin[] loadPlugins(@NotNull File directory) { -+ // Paper start - extra jars -+ return this.loadPlugins(directory, java.util.Collections.emptyList()); -+ } -+ @NotNull -+ public Plugin[] loadPlugins(final @NotNull File directory, final @NotNull List extraPluginJars) { -+ // Paper end - Preconditions.checkArgument(directory != null, "Directory cannot be null"); - Preconditions.checkArgument(directory.isDirectory(), "Directory must be a directory"); - -@@ -127,7 +133,11 @@ public final class SimplePluginManager implements PluginManager { - Map> softDependencies = new HashMap>(); - - // This is where it figures out all possible plugins -- for (File file : directory.listFiles()) { -+ // Paper start - extra jars -+ final List pluginJars = new ArrayList<>(java.util.Arrays.asList(directory.listFiles())); -+ pluginJars.addAll(extraPluginJars); -+ for (File file : pluginJars) { -+ // Paper end - PluginLoader loader = null; - for (Pattern filter : filters) { - Matcher match = filter.matcher(file.getName()); -@@ -143,14 +153,14 @@ public final class SimplePluginManager implements PluginManager { - description = loader.getPluginDescription(file); - String name = description.getName(); - if (name.equalsIgnoreCase("bukkit") || name.equalsIgnoreCase("minecraft") || name.equalsIgnoreCase("mojang")) { -- server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': Restricted Name"); -+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + file.getParentFile().getPath() + "': Restricted Name"); // Paper - continue; - } else if (description.rawName.indexOf(' ') != -1) { -- server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': uses the space-character (0x20) in its name"); -+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + file.getParentFile().getPath() + "': uses the space-character (0x20) in its name"); // Paper - continue; - } - } catch (InvalidDescriptionException ex) { -- server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex); -+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + file.getParentFile().getPath() + "'", ex); // Paper - continue; - } - -@@ -161,7 +171,7 @@ public final class SimplePluginManager implements PluginManager { - description.getName(), - file.getPath(), - replacedFile.getPath(), -- directory.getPath() -+ file.getParentFile().getPath() // Paper - )); - } - -@@ -182,7 +192,7 @@ public final class SimplePluginManager implements PluginManager { - file.getPath(), - provided, - pluginFile.getPath(), -- directory.getPath() -+ file.getParentFile().getPath() // Paper - )); - } else { - String replacedPlugin = pluginsProvided.put(provided, description.getName()); -@@ -264,7 +274,7 @@ public final class SimplePluginManager implements PluginManager { - - server.getLogger().log( - Level.SEVERE, -- "Could not load '" + entry.getValue().getPath() + "' in folder '" + directory.getPath() + "'", -+ "Could not load '" + entry.getValue().getPath() + "' in folder '" + entry.getValue().getParentFile().getPath() + "'", // Paper - new UnknownDependencyException("Unknown dependency " + dependency + ". Please download and install " + dependency + " to run this plugin.")); - break; - } -@@ -303,11 +313,11 @@ public final class SimplePluginManager implements PluginManager { - loadedPlugins.add(loadedPlugin.getName()); - loadedPlugins.addAll(loadedPlugin.getDescription().getProvides()); - } else { -- server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'"); -+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + file.getParentFile().getPath() + "'"); // Paper - } - continue; - } catch (InvalidPluginException ex) { -- server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex); -+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + file.getParentFile().getPath() + "'", ex); // Paper - } - } - } -@@ -334,11 +344,11 @@ public final class SimplePluginManager implements PluginManager { - loadedPlugins.add(loadedPlugin.getName()); - loadedPlugins.addAll(loadedPlugin.getDescription().getProvides()); - } else { -- server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'"); -+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + file.getParentFile().getPath() + "'"); // Paper - } - break; - } catch (InvalidPluginException ex) { -- server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex); -+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + file.getParentFile().getPath() + "'", ex); // Paper - } - } - } -@@ -351,7 +361,7 @@ public final class SimplePluginManager implements PluginManager { - while (failedPluginIterator.hasNext()) { - File file = failedPluginIterator.next(); - failedPluginIterator.remove(); -- server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': circular dependency detected"); -+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + file.getParentFile().getPath() + "': circular dependency detected"); // Paper - } - } - } -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index 5c1b8b05d8a5408bb4830942c74ebfe400ab5a32..333c47a1f7e9d7ddf91aad5ec15163427f7b8039 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -91,7 +91,7 @@ public final class JavaPluginLoader implements PluginLoader { - throw new InvalidPluginException(ex); - } - -- final File parentFile = file.getParentFile(); -+ final File parentFile = this.server.getPluginsFolder(); // Paper - final File dataFolder = new File(parentFile, description.getName()); - @SuppressWarnings("deprecation") - final File oldDataFolder = new File(parentFile, description.getRawName()); diff --git a/patches/api/0008-Use-ASM-for-event-executors.patch b/patches/api/0008-Use-ASM-for-event-executors.patch new file mode 100644 index 000000000000..31a3b5a44b05 --- /dev/null +++ b/patches/api/0008-Use-ASM-for-event-executors.patch @@ -0,0 +1,381 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Thu, 3 Mar 2016 13:20:33 -0700 +Subject: [PATCH] Use ASM for event executors. + +Uses method handles for private or static methods. + +diff --git a/build.gradle.kts b/build.gradle.kts +index ed5d58d7569300c917dd52b11953a63fae6878d4..43086f7d201c0988086ef06cfe5a0f866d130961 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -61,6 +61,9 @@ dependencies { + apiAndDocs("net.kyori:adventure-text-serializer-legacy") + apiAndDocs("net.kyori:adventure-text-serializer-plain") + apiAndDocs("net.kyori:adventure-text-logger-slf4j") ++ ++ implementation("org.ow2.asm:asm:9.7.1") ++ implementation("org.ow2.asm:asm-commons:9.7.1") + // Paper end + + compileOnly("org.apache.maven:maven-resolver-provider:3.9.6") +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5a702481d28d90cb503faad0d9b9c3231bbff940 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java +@@ -0,0 +1,46 @@ ++package com.destroystokyo.paper.event.executor; ++ ++import com.destroystokyo.paper.util.SneakyThrow; ++import java.lang.invoke.MethodHandle; ++import java.lang.invoke.MethodHandles; ++import java.lang.reflect.Method; ++import org.bukkit.event.Event; ++import org.bukkit.event.EventException; ++import org.bukkit.event.Listener; ++import org.bukkit.plugin.EventExecutor; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@ApiStatus.Internal ++@NullMarked ++public class MethodHandleEventExecutor implements EventExecutor { ++ ++ private final Class eventClass; ++ private final MethodHandle handle; ++ ++ public MethodHandleEventExecutor(final Class eventClass, final MethodHandle handle) { ++ this.eventClass = eventClass; ++ this.handle = handle; ++ } ++ ++ public MethodHandleEventExecutor(final Class eventClass, final Method m) { ++ this.eventClass = eventClass; ++ try { ++ m.setAccessible(true); ++ this.handle = MethodHandles.lookup().unreflect(m); ++ } catch (final IllegalAccessException e) { ++ throw new AssertionError("Unable to set accessible", e); ++ } ++ } ++ ++ @Override ++ public void execute(final Listener listener, final Event event) throws EventException { ++ if (!this.eventClass.isInstance(event)) return; ++ try { ++ this.handle.invoke(listener, event); ++ } catch (final Throwable t) { ++ SneakyThrow.sneaky(t); ++ } ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bbdb5b472df116b71c459bdc6cc4b74267ea0f5e +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java +@@ -0,0 +1,44 @@ ++package com.destroystokyo.paper.event.executor; ++ ++import com.destroystokyo.paper.util.SneakyThrow; ++import com.google.common.base.Preconditions; ++import java.lang.invoke.MethodHandle; ++import java.lang.invoke.MethodHandles; ++import java.lang.reflect.Method; ++import java.lang.reflect.Modifier; ++import org.bukkit.event.Event; ++import org.bukkit.event.EventException; ++import org.bukkit.event.Listener; ++import org.bukkit.plugin.EventExecutor; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@ApiStatus.Internal ++@NullMarked ++public class StaticMethodHandleEventExecutor implements EventExecutor { ++ ++ private final Class eventClass; ++ private final MethodHandle handle; ++ ++ public StaticMethodHandleEventExecutor(final Class eventClass, final Method m) { ++ Preconditions.checkArgument(Modifier.isStatic(m.getModifiers()), "Not a static method: %s", m); ++ Preconditions.checkArgument(eventClass != null, "eventClass is null"); ++ this.eventClass = eventClass; ++ try { ++ m.setAccessible(true); ++ this.handle = MethodHandles.lookup().unreflect(m); ++ } catch (final IllegalAccessException e) { ++ throw new AssertionError("Unable to set accessible", e); ++ } ++ } ++ ++ @Override ++ public void execute(final Listener listener, final Event event) throws EventException { ++ if (!this.eventClass.isInstance(event)) return; ++ try { ++ this.handle.invoke(event); ++ } catch (final Throwable throwable) { ++ SneakyThrow.sneaky(throwable); ++ } ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java +new file mode 100644 +index 0000000000000000000000000000000000000000..abfcb6e8383ff311940d82afe4ff990649a082dc +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java +@@ -0,0 +1,59 @@ ++package com.destroystokyo.paper.event.executor.asm; ++ ++import java.lang.reflect.Method; ++import java.util.concurrent.atomic.AtomicInteger; ++import org.bukkit.plugin.EventExecutor; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.objectweb.asm.ClassWriter; ++import org.objectweb.asm.Type; ++import org.objectweb.asm.commons.GeneratorAdapter; ++ ++import static org.objectweb.asm.Opcodes.ACC_PUBLIC; ++import static org.objectweb.asm.Opcodes.INVOKEINTERFACE; ++import static org.objectweb.asm.Opcodes.INVOKESPECIAL; ++import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; ++import static org.objectweb.asm.Opcodes.V1_8; ++ ++@ApiStatus.Internal ++@NullMarked ++public final class ASMEventExecutorGenerator { ++ ++ private static final String EXECUTE_DESCRIPTOR = "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Event;)V"; ++ ++ public static byte[] generateEventExecutor(final Method m, final String name) { ++ final ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ++ writer.visit(V1_8, ACC_PUBLIC, name.replace('.', '/'), null, Type.getInternalName(Object.class), new String[]{Type.getInternalName(EventExecutor.class)}); ++ // Generate constructor ++ GeneratorAdapter methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "", "()V", null, null), ACC_PUBLIC, "", "()V"); ++ methodGenerator.loadThis(); ++ methodGenerator.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); // Invoke the super class (Object) constructor ++ methodGenerator.returnValue(); ++ methodGenerator.endMethod(); ++ // Generate the execute method ++ methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "execute", EXECUTE_DESCRIPTOR, null, null), ACC_PUBLIC, "execute", EXECUTE_DESCRIPTOR); ++ methodGenerator.loadArg(0); ++ methodGenerator.checkCast(Type.getType(m.getDeclaringClass())); ++ methodGenerator.loadArg(1); ++ methodGenerator.checkCast(Type.getType(m.getParameterTypes()[0])); ++ methodGenerator.visitMethodInsn(m.getDeclaringClass().isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, Type.getInternalName(m.getDeclaringClass()), m.getName(), Type.getMethodDescriptor(m), m.getDeclaringClass().isInterface()); ++ // The only purpose of this switch statement is to generate the correct pop instruction, should the event handler method return something other than void. ++ // Non-void event handlers will be unsupported in a future release. ++ switch (Type.getType(m.getReturnType()).getSize()) { ++ // case 0 is omitted because the only type that has size 0 is void - no pop instruction needed. ++ case 1 -> methodGenerator.pop(); // handles reference types and most primitives ++ case 2 -> methodGenerator.pop2(); // handles long and double ++ } ++ methodGenerator.returnValue(); ++ methodGenerator.endMethod(); ++ writer.visitEnd(); ++ return writer.toByteArray(); ++ } ++ ++ public static AtomicInteger NEXT_ID = new AtomicInteger(1); ++ ++ public static String generateName() { ++ final int id = NEXT_ID.getAndIncrement(); ++ return "com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor" + id; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java +new file mode 100644 +index 0000000000000000000000000000000000000000..581561fbd32c81ab1774ba8f0b7f3cec9392d99a +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java +@@ -0,0 +1,35 @@ ++package com.destroystokyo.paper.event.executor.asm; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@ApiStatus.Internal ++@NullMarked ++public interface ClassDefiner { ++ ++ /** ++ * Returns if the defined classes can bypass access checks ++ * ++ * @return if classes bypass access checks ++ */ ++ default boolean isBypassAccessChecks() { ++ return false; ++ } ++ ++ /** ++ * Define a class ++ * ++ * @param parentLoader the parent classloader ++ * @param name the name of the class ++ * @param data the class data to load ++ * @return the defined class ++ * @throws ClassFormatError if the class data is invalid ++ * @throws NullPointerException if any of the arguments are null ++ */ ++ Class defineClass(ClassLoader parentLoader, String name, byte[] data); ++ ++ static ClassDefiner getInstance() { ++ return SafeClassDefiner.INSTANCE; ++ } ++ ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java +new file mode 100644 +index 0000000000000000000000000000000000000000..48bcc72293c2a31b6e2dd2dcd6a79d618c72a137 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java +@@ -0,0 +1,66 @@ ++package com.destroystokyo.paper.event.executor.asm; ++ ++import com.google.common.base.Preconditions; ++import com.google.common.collect.MapMaker; ++import java.util.concurrent.ConcurrentMap; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@ApiStatus.Internal ++@NullMarked ++public class SafeClassDefiner implements ClassDefiner { ++ ++ /* default */ static final SafeClassDefiner INSTANCE = new SafeClassDefiner(); ++ ++ private SafeClassDefiner() { ++ } ++ ++ private final ConcurrentMap loaders = new MapMaker().weakKeys().makeMap(); ++ ++ @Override ++ public Class defineClass(final ClassLoader parentLoader, final String name, final byte[] data) { ++ final GeneratedClassLoader loader = this.loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new); ++ synchronized (loader.getClassLoadingLock(name)) { ++ Preconditions.checkState(!loader.hasClass(name), "%s already defined", name); ++ final Class c = loader.define(name, data); ++ assert c.getName().equals(name); ++ return c; ++ } ++ } ++ ++ private static class GeneratedClassLoader extends ClassLoader { ++ ++ static { ++ ClassLoader.registerAsParallelCapable(); ++ } ++ ++ protected GeneratedClassLoader(final ClassLoader parent) { ++ super(parent); ++ } ++ ++ private Class define(final String name, final byte[] data) { ++ synchronized (this.getClassLoadingLock(name)) { ++ assert !this.hasClass(name); ++ final Class c = this.defineClass(name, data, 0, data.length); ++ this.resolveClass(c); ++ return c; ++ } ++ } ++ ++ @Override ++ public Object getClassLoadingLock(final String name) { ++ return super.getClassLoadingLock(name); ++ } ++ ++ public boolean hasClass(final String name) { ++ synchronized (this.getClassLoadingLock(name)) { ++ try { ++ Class.forName(name); ++ return true; ++ } catch (final ClassNotFoundException e) { ++ return false; ++ } ++ } ++ } ++ } ++} +diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java +index a850f0780de05463fc0d3f9e15ff7f19d88b2aed..9026e108ccd3a88aee1267ee275137befa646455 100644 +--- a/src/main/java/org/bukkit/plugin/EventExecutor.java ++++ b/src/main/java/org/bukkit/plugin/EventExecutor.java +@@ -5,9 +5,75 @@ import org.bukkit.event.EventException; + import org.bukkit.event.Listener; + import org.jetbrains.annotations.NotNull; + ++// Paper start ++import java.lang.reflect.Method; ++import java.lang.reflect.Modifier; ++import java.util.concurrent.ConcurrentHashMap; ++import java.util.concurrent.ConcurrentMap; ++import java.util.function.Function; ++ ++import com.destroystokyo.paper.event.executor.MethodHandleEventExecutor; ++import com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor; ++import com.destroystokyo.paper.event.executor.asm.ASMEventExecutorGenerator; ++import com.destroystokyo.paper.event.executor.asm.ClassDefiner; ++import com.google.common.base.Preconditions; ++// Paper end ++ + /** + * Interface which defines the class for event call backs to plugins + */ + public interface EventExecutor { + public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException; ++ ++ // Paper start ++ ConcurrentMap> eventExecutorMap = new ConcurrentHashMap>() { ++ @NotNull ++ @Override ++ public Class computeIfAbsent(@NotNull Method key, @NotNull Function> mappingFunction) { ++ Class executorClass = get(key); ++ if (executorClass != null) ++ return executorClass; ++ ++ //noinspection SynchronizationOnLocalVariableOrMethodParameter ++ synchronized (key) { ++ executorClass = get(key); ++ if (executorClass != null) ++ return executorClass; ++ ++ return super.computeIfAbsent(key, mappingFunction); ++ } ++ } ++ }; ++ ++ @NotNull ++ public static EventExecutor create(@NotNull Method m, @NotNull Class eventClass) { ++ Preconditions.checkNotNull(m, "Null method"); ++ Preconditions.checkArgument(m.getParameterCount() != 0, "Incorrect number of arguments %s", m.getParameterCount()); ++ Preconditions.checkArgument(m.getParameterTypes()[0] == eventClass, "First parameter %s doesn't match event class %s", m.getParameterTypes()[0], eventClass); ++ ClassDefiner definer = ClassDefiner.getInstance(); ++ if (Modifier.isStatic(m.getModifiers())) { ++ return new StaticMethodHandleEventExecutor(eventClass, m); ++ } else if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) { ++ // get the existing generated EventExecutor class for the Method or generate one ++ Class executorClass = eventExecutorMap.computeIfAbsent(m, (__) -> { ++ String name = ASMEventExecutorGenerator.generateName(); ++ byte[] classData = ASMEventExecutorGenerator.generateEventExecutor(m, name); ++ return definer.defineClass(m.getDeclaringClass().getClassLoader(), name, classData).asSubclass(EventExecutor.class); ++ }); ++ ++ try { ++ EventExecutor asmExecutor = executorClass.newInstance(); ++ // Define a wrapper to conform to bukkit stupidity (passing in events that don't match and wrapper exception) ++ return (listener, event) -> { ++ if (!eventClass.isInstance(event)) return; ++ asmExecutor.execute(listener, event); ++ }; ++ } catch (InstantiationException | IllegalAccessException e) { ++ throw new AssertionError("Unable to initialize generated event executor", e); ++ } ++ } else { ++ return new MethodHandleEventExecutor(eventClass, m); ++ } ++ } ++ // Paper end + } diff --git a/patches/api/0009-Paper-Plugins.patch b/patches/api/0009-Paper-Plugins.patch new file mode 100644 index 000000000000..afecfce3b304 --- /dev/null +++ b/patches/api/0009-Paper-Plugins.patch @@ -0,0 +1,2550 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 6 Jul 2022 23:00:36 -0400 +Subject: [PATCH] Paper Plugins + + +diff --git a/build.gradle.kts b/build.gradle.kts +index 43086f7d201c0988086ef06cfe5a0f866d130961..305c2f3226f59e36ab1059b52e111178790aa6e8 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -66,7 +66,7 @@ dependencies { + implementation("org.ow2.asm:asm-commons:9.7.1") + // Paper end + +- compileOnly("org.apache.maven:maven-resolver-provider:3.9.6") ++ api("org.apache.maven:maven-resolver-provider:3.9.6") // Paper - make API dependency for Paper Plugins + compileOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") + compileOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") + +@@ -156,6 +156,7 @@ tasks.withType { + "https://jd.advntr.dev/text-serializer-plain/$adventureVersion/", + "https://jd.advntr.dev/text-logger-slf4j/$adventureVersion/", + // Paper end ++ "https://javadoc.io/doc/org.apache.maven.resolver/maven-resolver-api/1.7.3", // Paper + ) + options.tags("apiNote:a:API Note:") + +diff --git a/src/main/java/io/papermc/paper/plugin/PermissionManager.java b/src/main/java/io/papermc/paper/plugin/PermissionManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1dac94e481 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/PermissionManager.java +@@ -0,0 +1,166 @@ ++package io.papermc.paper.plugin; ++ ++import java.util.List; ++import java.util.Set; ++import org.bukkit.permissions.Permissible; ++import org.bukkit.permissions.Permission; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * A permission manager implementation to keep backwards compatibility partially alive with existing plugins that used ++ * the bukkit one before. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++public interface PermissionManager { ++ ++ /** ++ * Gets a {@link Permission} from its fully qualified name ++ * ++ * @param name Name of the permission ++ * @return Permission, or null if none ++ */ ++ @Nullable Permission getPermission(String name); ++ ++ /** ++ * Adds a {@link Permission} to this plugin manager. ++ *

      ++ * If a permission is already defined with the given name of the new ++ * permission, an exception will be thrown. ++ * ++ * @param perm Permission to add ++ * @throws IllegalArgumentException Thrown when a permission with the same ++ * name already exists ++ */ ++ void addPermission(Permission perm); ++ ++ /** ++ * Removes a {@link Permission} registration from this plugin manager. ++ *

      ++ * If the specified permission does not exist in this plugin manager, ++ * nothing will happen. ++ *

      ++ * Removing a permission registration will not remove the ++ * permission from any {@link Permissible}s that have it. ++ * ++ * @param perm Permission to remove ++ */ ++ void removePermission(Permission perm); ++ ++ /** ++ * Removes a {@link Permission} registration from this plugin manager. ++ *

      ++ * If the specified permission does not exist in this plugin manager, ++ * nothing will happen. ++ *

      ++ * Removing a permission registration will not remove the ++ * permission from any {@link Permissible}s that have it. ++ * ++ * @param name Permission to remove ++ */ ++ void removePermission(String name); ++ ++ /** ++ * Gets the default permissions for the given op status ++ * ++ * @param op Which set of default permissions to get ++ * @return The default permissions ++ */ ++ Set getDefaultPermissions(boolean op); ++ ++ /** ++ * Recalculates the defaults for the given {@link Permission}. ++ *

      ++ * This will have no effect if the specified permission is not registered ++ * here. ++ * ++ * @param perm Permission to recalculate ++ */ ++ void recalculatePermissionDefaults(Permission perm); ++ ++ /** ++ * Subscribes the given Permissible for information about the requested ++ * Permission, by name. ++ *

      ++ * If the specified Permission changes in any form, the Permissible will ++ * be asked to recalculate. ++ * ++ * @param permission Permission to subscribe to ++ * @param permissible Permissible subscribing ++ */ ++ void subscribeToPermission(String permission, Permissible permissible); ++ ++ /** ++ * Unsubscribes the given Permissible for information about the requested ++ * Permission, by name. ++ * ++ * @param permission Permission to unsubscribe from ++ * @param permissible Permissible subscribing ++ */ ++ void unsubscribeFromPermission(String permission, Permissible permissible); ++ ++ /** ++ * Gets a set containing all subscribed {@link Permissible}s to the given ++ * permission, by name ++ * ++ * @param permission Permission to query for ++ * @return Set containing all subscribed permissions ++ */ ++ Set getPermissionSubscriptions(String permission); ++ ++ /** ++ * Subscribes to the given Default permissions by operator status ++ *

      ++ * If the specified defaults change in any form, the Permissible will be ++ * asked to recalculate. ++ * ++ * @param op Default list to subscribe to ++ * @param permissible Permissible subscribing ++ */ ++ void subscribeToDefaultPerms(boolean op, Permissible permissible); ++ ++ /** ++ * Unsubscribes from the given Default permissions by operator status ++ * ++ * @param op Default list to unsubscribe from ++ * @param permissible Permissible subscribing ++ */ ++ void unsubscribeFromDefaultPerms(boolean op, Permissible permissible); ++ ++ /** ++ * Gets a set containing all subscribed {@link Permissible}s to the given ++ * default list, by op status ++ * ++ * @param op Default list to query for ++ * @return Set containing all subscribed permissions ++ */ ++ Set getDefaultPermSubscriptions(boolean op); ++ ++ /** ++ * Gets a set of all registered permissions. ++ *

      ++ * This set is a copy and will not be modified live. ++ * ++ * @return Set containing all current registered permissions ++ */ ++ Set getPermissions(); ++ ++ /** ++ * Adds a list of permissions. ++ *

      ++ * This is meant as an optimization for adding multiple permissions without recalculating each permission. ++ * ++ * @param perm permission ++ */ ++ void addPermissions(List perm); ++ ++ /** ++ * Clears the current registered permissinos. ++ *

      ++ * This is used for reloading. ++ */ ++ void clearPermissions(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4c47414fc08e1183b1e59369bacc4d7f7042f262 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java +@@ -0,0 +1,16 @@ ++package io.papermc.paper.plugin.bootstrap; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents the context provided to a {@link PluginBootstrap} during both the bootstrapping and plugin ++ * instantiation logic. ++ * A bootstrap context may be used to access data or logic usually provided to {@link org.bukkit.plugin.Plugin} instances ++ * like the plugin's configuration or logger during the plugins bootstrap. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface BootstrapContext extends PluginProviderContext { ++} +diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e6696dcd8049e869bd1733f7c67ff802c54d7c37 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java +@@ -0,0 +1,41 @@ ++package io.papermc.paper.plugin.bootstrap; ++ ++import io.papermc.paper.plugin.provider.util.ProviderUtil; ++import org.bukkit.plugin.java.JavaPlugin; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A plugin bootstrap is meant for loading certain parts of the plugin before the server is loaded. ++ *

      ++ * Plugin bootstrapping allows values to be initialized in certain parts of the server that might not be allowed ++ * when the server is running. ++ *

      ++ * Your bootstrap class will be on the same classloader as your JavaPlugin. ++ *

      ++ * All calls to Bukkit may throw a NullPointerExceptions or return null unexpectedly. You should only call api methods that are explicitly documented to work in the bootstrapper ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.OverrideOnly ++public interface PluginBootstrap { ++ ++ /** ++ * Called by the server, allowing you to bootstrap the plugin with a context that provides things like a logger and your shared plugin configuration file. ++ * ++ * @param context the server provided context ++ */ ++ void bootstrap(BootstrapContext context); ++ ++ /** ++ * Called by the server to instantiate your main class. ++ * Plugins may override this logic to define custom creation logic for said instance, like passing addition ++ * constructor arguments. ++ * ++ * @param context the server created bootstrap object ++ * @return the server requested instance of the plugins main class. ++ */ ++ default JavaPlugin createPlugin(final PluginProviderContext context) { ++ return ProviderUtil.loadClass(context.getConfiguration().getMainClass(), JavaPlugin.class, this.getClass().getClassLoader()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java +new file mode 100644 +index 0000000000000000000000000000000000000000..19bb302ab264b72306d9bd15e9c40ade6dde7ee7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java +@@ -0,0 +1,48 @@ ++package io.papermc.paper.plugin.bootstrap; ++ ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import java.nio.file.Path; ++import net.kyori.adventure.text.logger.slf4j.ComponentLogger; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents the context provided to a {@link PluginBootstrap} during both the bootstrapping and plugin ++ * instantiation logic. ++ * A bootstrap context may be used to access data or logic usually provided to {@link org.bukkit.plugin.Plugin} instances ++ * like the plugin's configuration or logger during the plugins bootstrap. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface PluginProviderContext { ++ ++ /** ++ * Provides the plugin's configuration. ++ * ++ * @return the plugin's configuration ++ */ ++ PluginMeta getConfiguration(); ++ ++ /** ++ * Provides the path to the data directory of the plugin. ++ * ++ * @return the previously described path ++ */ ++ Path getDataDirectory(); ++ ++ /** ++ * Provides the logger used for this plugin. ++ * ++ * @return the logger instance ++ */ ++ ComponentLogger getLogger(); ++ ++ /** ++ * Provides the path to the originating source of the plugin, such as the plugin's JAR file. ++ * ++ * @return the previously described path ++ */ ++ Path getPluginSource(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java b/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c85670bad8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java +@@ -0,0 +1,186 @@ ++package io.papermc.paper.plugin.configuration; ++ ++import java.util.List; ++import org.bukkit.permissions.Permission; ++import org.bukkit.permissions.PermissionDefault; ++import org.bukkit.plugin.PluginLoadOrder; ++import org.bukkit.plugin.java.JavaPlugin; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * This class acts as an abstraction for a plugin configuration. ++ */ ++@ApiStatus.Experimental // Subject to change! ++@NullMarked ++@ApiStatus.NonExtendable ++public interface PluginMeta { ++ ++ /** ++ * Provides the name of the plugin. This name uniquely identifies the plugin amongst all loaded plugins on the ++ * server. ++ *

        ++ *
      • Will only contain alphanumeric characters, underscores, hyphens, ++ * and periods: [a-zA-Z0-9_\-\.]. ++ *
      • Typically used for identifying the plugin data folder. ++ *
      • The name also acts as the token referenced in {@link #getPluginDependencies()}, ++ * {@link #getPluginSoftDependencies()}, and {@link #getLoadBeforePlugins()}. ++ *
      ++ *

      ++ * In the plugin.yml, this entry is named name. ++ *

      ++ * Example:

      name: MyPlugin
      ++ * ++ * @return the name of the plugin ++ */ ++ String getName(); ++ ++ /** ++ * Returns the display name of the plugin, including the version. ++ * ++ * @return a descriptive name of the plugin and respective version ++ */ ++ default String getDisplayName() { ++ return this.getName() + " v" + this.getVersion(); ++ } ++ ++ /** ++ * Provides the fully qualified class name of the main class for the plugin. ++ * A subtype of {@link JavaPlugin} is expected at this location. ++ * ++ * @return the fully qualified class name of the plugin's main class. ++ */ ++ String getMainClass(); ++ ++ /** ++ * Returns the phase of the server startup logic that the plugin should be loaded. ++ * ++ * @return the plugin load order ++ * @see PluginLoadOrder for further details regards the available load orders. ++ */ ++ PluginLoadOrder getLoadOrder(); ++ ++ /** ++ * Provides the version of this plugin as defined by the plugin. ++ * There is no inherit format defined/enforced for the version of a plugin, however a common approach ++ * might be semantic versioning. ++ * ++ * @return the string representation of the plugin's version ++ */ ++ String getVersion(); ++ ++ /** ++ * Provides the prefix that should be used for the plugin logger. ++ * The logger prefix allows plugins to overwrite the usual default of the logger prefix, which is the name of the ++ * plugin. ++ * ++ * @return the specific overwrite of the logger prefix as defined by the plugin. If the plugin did not define a ++ * custom logger prefix, this method will return null ++ */ ++ @Nullable String getLoggerPrefix(); ++ ++ /** ++ * Provides a list of dependencies that are required for this plugin to load. ++ * The list holds the unique identifiers, following the constraints laid out in {@link #getName()}, of the ++ * dependencies. ++ *

      ++ * If any of the dependencies defined by this list are not installed on the server, this plugin will fail to load. ++ * ++ * @return an immutable list of required dependency names ++ */ ++ List getPluginDependencies(); ++ ++ /** ++ * Provides a list of dependencies that are used but not required by this plugin. ++ * The list holds the unique identifiers, following the constraints laid out in {@link #getName()}, of the soft ++ * dependencies. ++ *

      ++ * If these dependencies are installed on the server, they will be loaded first and supplied as dependencies to this ++ * plugin, however the plugin will load even if these dependencies are not installed. ++ * ++ * @return immutable list of soft dependencies ++ */ ++ List getPluginSoftDependencies(); ++ ++ /** ++ * Provides a list of plugins that should be loaded before this plugin is loaded. ++ * The list holds the unique identifiers, following the constraints laid out in {@link #getName()}, of the ++ * plugins that should be loaded before the plugin described by this plugin meta. ++ *

      ++ * The plugins referenced in the list provided by this method are not considered dependencies of this plugin and ++ * are hence not available to the plugin at runtime. They merely load before this plugin. ++ * ++ * @return immutable list of plugins to load before this plugin ++ */ ++ List getLoadBeforePlugins(); ++ ++ /** ++ * Returns the list of plugins/dependencies that this plugin provides. ++ * The list holds the unique identifiers, following the constraints laid out in {@link #getName()}, for each plugin ++ * it provides the expected classes for. ++ * ++ * @return immutable list of provided plugins/dependencies ++ */ ++ List getProvidedPlugins(); ++ ++ /** ++ * Provides the list of authors that are credited with creating this plugin. ++ * The author names are in no particular format. ++ * ++ * @return an immutable list of the plugin's authors ++ */ ++ List getAuthors(); ++ ++ /** ++ * Provides a list of contributors that contributed to the plugin but are not considered authors. ++ * The names of the contributors are in no particular format. ++ * ++ * @return an immutable list of the plugin's contributors ++ */ ++ List getContributors(); ++ ++ /** ++ * Gives a human-friendly description of the functionality the plugin ++ * provides. ++ * ++ * @return description or null if the plugin did not define a human readable description. ++ */ ++ @Nullable String getDescription(); ++ ++ /** ++ * Provides the website for the plugin or the plugin's author. ++ * The defined string value is not guaranteed to be in the form of a url. ++ * ++ * @return a string representation of the website that serves as the main hub for this plugin/its author. ++ */ ++ @Nullable String getWebsite(); ++ ++ /** ++ * Provides the list of permissions that are defined via the plugin meta instance. ++ * ++ * @return an immutable list of permissions ++ */ ++ // TODO: Do we even want this? Why not just use the bootstrapper ++ List getPermissions(); ++ ++ /** ++ * Provides the default values that apply to the permissions defined in this plugin meta. ++ * ++ * @return the bukkit permission default container. ++ * @see #getPermissions() ++ */ ++ // TODO: Do we even want this? Why not just use the bootstrapper ++ PermissionDefault getPermissionDefault(); ++ ++ /** ++ * Gets the api version that this plugin supports. ++ * Nullable if this version is not specified, and should be ++ * considered legacy (spigot plugins only) ++ * ++ * @return the version string made up of the major and minor version (e.g. 1.18 or 1.19). Minor versions like 1.18.2 ++ * are unified to their major release version (in this example 1.18) ++ */ ++ @Nullable String getAPIVersion(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/configuration/package-info.java b/src/main/java/io/papermc/paper/plugin/configuration/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ddb3076124365d0d1a5caa32d4dcb1f4314dd7ae +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/configuration/package-info.java +@@ -0,0 +1,8 @@ ++/** ++ * The paper configuration package contains the new java representation of a plugins configuration file. ++ * While most values are described in detail on {@link io.papermc.paper.plugin.configuration.PluginMeta}, a full ++ * entry on the paper contains a full and extensive example of possible configurations of the paper-plugin.yml. ++ * @see Extensive documentation and examples of the paper-plugin.yml ++ * ++ */ ++package io.papermc.paper.plugin.configuration; +diff --git a/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java b/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ddb768057cdfd9202e4386494fd5f643692c73a1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java +@@ -0,0 +1,37 @@ ++package io.papermc.paper.plugin.loader; ++ ++import io.papermc.paper.plugin.bootstrap.PluginProviderContext; ++import io.papermc.paper.plugin.loader.library.ClassPathLibrary; ++import io.papermc.paper.plugin.loader.library.LibraryStore; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A mutable builder that may be used to collect and register all {@link ClassPathLibrary} instances a ++ * {@link PluginLoader} aims to provide to its plugin at runtime. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface PluginClasspathBuilder { ++ ++ /** ++ * Adds a new classpath library to this classpath builder. ++ *

      ++ * As a builder, this method does not invoke {@link ClassPathLibrary#register(LibraryStore)} and ++ * may hence be run without invoking potential IO performed by a {@link ClassPathLibrary} during resolution. ++ *

      ++ * The paper api provides pre implemented {@link ClassPathLibrary} types that allow easy inclusion of existing ++ * libraries on disk or on remote maven repositories. ++ * ++ * @param classPathLibrary the library instance to add to this builder ++ * @return self ++ * @see io.papermc.paper.plugin.loader.library.impl.JarLibrary ++ * @see io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver ++ */ ++ @Contract("_ -> this") ++ PluginClasspathBuilder addLibrary(ClassPathLibrary classPathLibrary); ++ ++ PluginProviderContext getContext(); ++} +diff --git a/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java b/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c2d029e4474cc00c84e5b3f7fceec4c3f30b486b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.plugin.loader; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A plugin loader is responsible for creating certain aspects of a plugin before it is created. ++ *

      ++ * The goal of the plugin loader is the creation of an expected/dynamic environment for the plugin to load into. ++ * This, as of right now, only applies to creating the expected classpath for the plugin, e.g. supplying external ++ * libraries to the plugin. ++ *

      ++ * It should be noted that this class will be called from a different classloader, this will cause any static values ++ * set in this class/any other classes loaded not to persist when the plugin loads. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.OverrideOnly ++public interface PluginLoader { ++ ++ /** ++ * Called by the server to allows plugins to configure the runtime classpath that the plugin is run on. ++ * This allows plugin loaders to configure dependencies for the plugin where jars can be downloaded or ++ * provided during runtime. ++ * ++ * @param classpathBuilder a mutable classpath builder that may be used to register custom runtime dependencies ++ * for the plugin the loader was registered for. ++ */ ++ void classloader(PluginClasspathBuilder classpathBuilder); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java b/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8a07333a592056bab1d26d811316bb5ea5f30e18 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java +@@ -0,0 +1,21 @@ ++package io.papermc.paper.plugin.loader.library; ++ ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * The classpath library interface represents libraries that are capable of registering themselves via ++ * {@link #register(LibraryStore)} on any given {@link LibraryStore}. ++ */ ++@NullMarked ++public interface ClassPathLibrary { ++ ++ /** ++ * Called to register the library this class path library represents into the passed library store. ++ * This method may either be implemented by the plugins themselves if they need complex logic, or existing ++ * API exposed implementations of this interface may be used. ++ * ++ * @param store the library store instance to register this library into ++ * @throws LibraryLoadingException if library loading failed for this classpath library ++ */ ++ void register(LibraryStore store) throws LibraryLoadingException; ++} +diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/LibraryLoadingException.java b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryLoadingException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..79ba423a364b50588f3ee87fdc69155cb8e64ad0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryLoadingException.java +@@ -0,0 +1,15 @@ ++package io.papermc.paper.plugin.loader.library; ++ ++/** ++ * Indicates that an exception has occured while loading a library. ++ */ ++public class LibraryLoadingException extends RuntimeException { ++ ++ public LibraryLoadingException(String s) { ++ super(s); ++ } ++ ++ public LibraryLoadingException(String s, Exception e) { ++ super(s, e); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/LibraryStore.java b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryStore.java +new file mode 100644 +index 0000000000000000000000000000000000000000..93ef8e369a158c25bc4fdd553faf13c1826ad872 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryStore.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.plugin.loader.library; ++ ++import java.nio.file.Path; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents a storage that stores library jars. ++ *

      ++ * The library store api allows plugins to register specific dependencies into their runtime classloader when their ++ * {@link io.papermc.paper.plugin.loader.PluginLoader} is processed. ++ * ++ * @see io.papermc.paper.plugin.loader.PluginLoader ++ */ ++@ApiStatus.Internal ++@NullMarked ++public interface LibraryStore { ++ ++ /** ++ * Adds the provided library path to this library store. ++ * ++ * @param library path to the libraries jar file on the disk ++ */ ++ void addLibrary(Path library); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java b/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9efcd9a62d6439eb27fc4e08498b4b7fbbdecb3c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java +@@ -0,0 +1,45 @@ ++package io.papermc.paper.plugin.loader.library.impl; ++ ++import io.papermc.paper.plugin.loader.library.ClassPathLibrary; ++import io.papermc.paper.plugin.loader.library.LibraryLoadingException; ++import io.papermc.paper.plugin.loader.library.LibraryStore; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A simple jar library implementation of the {@link ClassPathLibrary} that allows {@link io.papermc.paper.plugin.loader.PluginLoader}s to ++ * append a jar stored on the local file system into their runtime classloader. ++ *

      ++ * An example creation of the jar library type may look like this: ++ *

      {@code
      ++ *   final JarLibrary customLibrary = new JarLibrary(Path.of("libs/custom-library-1.24.jar"));
      ++ * }
      ++ * resulting in a jar library that provides the jar at {@code libs/custom-library-1.24.jar} to the plugins classloader ++ * at runtime. ++ *

      ++ * The jar library implementation will error if the file does not exist at the specified path. ++ */ ++@NullMarked ++public class JarLibrary implements ClassPathLibrary { ++ ++ private final Path path; ++ ++ /** ++ * Creates a new jar library that references the jar file found at the provided path. ++ * ++ * @param path the path, relative to the JVMs start directory. ++ */ ++ public JarLibrary(final Path path) { ++ this.path = path; ++ } ++ ++ @Override ++ public void register(final LibraryStore store) throws LibraryLoadingException { ++ if (Files.notExists(this.path)) { ++ throw new LibraryLoadingException("Could not find library at " + this.path); ++ } ++ ++ store.addLibrary(this.path); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java +new file mode 100644 +index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0bc3b03831 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java +@@ -0,0 +1,133 @@ ++package io.papermc.paper.plugin.loader.library.impl; ++ ++import io.papermc.paper.plugin.loader.library.ClassPathLibrary; ++import io.papermc.paper.plugin.loader.library.LibraryLoadingException; ++import io.papermc.paper.plugin.loader.library.LibraryStore; ++import java.io.File; ++import java.util.ArrayList; ++import java.util.List; ++import org.apache.maven.repository.internal.MavenRepositorySystemUtils; ++import org.eclipse.aether.DefaultRepositorySystemSession; ++import org.eclipse.aether.RepositorySystem; ++import org.eclipse.aether.collection.CollectRequest; ++import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; ++import org.eclipse.aether.graph.Dependency; ++import org.eclipse.aether.impl.DefaultServiceLocator; ++import org.eclipse.aether.repository.LocalRepository; ++import org.eclipse.aether.repository.RemoteRepository; ++import org.eclipse.aether.repository.RepositoryPolicy; ++import org.eclipse.aether.resolution.ArtifactResult; ++import org.eclipse.aether.resolution.DependencyRequest; ++import org.eclipse.aether.resolution.DependencyResolutionException; ++import org.eclipse.aether.resolution.DependencyResult; ++import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; ++import org.eclipse.aether.spi.connector.transport.TransporterFactory; ++import org.eclipse.aether.transfer.AbstractTransferListener; ++import org.eclipse.aether.transfer.TransferCancelledException; ++import org.eclipse.aether.transfer.TransferEvent; ++import org.eclipse.aether.transport.http.HttpTransporterFactory; ++import org.jspecify.annotations.NullMarked; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; ++ ++/** ++ * The maven library resolver acts as a resolver for yet to be resolved jar libraries that may be pulled from a ++ * remote maven repository. ++ *

      ++ * Plugins may create and configure a {@link MavenLibraryResolver} by creating a new one and registering both ++ * a dependency artifact that should be resolved to a library at runtime and the repository it is found in. ++ * An example of this would be the inclusion of the jooq library for typesafe SQL queries: ++ *

      {@code
      ++ * MavenLibraryResolver resolver = new MavenLibraryResolver();
      ++ * resolver.addDependency(new Dependency(new DefaultArtifact("org.jooq:jooq:3.17.7"), null));
      ++ * resolver.addRepository(new RemoteRepository.Builder(
      ++ *     "central", "default", "https://repo1.maven.org/maven2/"
      ++ * ).build());
      ++ * }
      ++ *

      ++ * Plugins may create and register a {@link MavenLibraryResolver} after configuring it. ++ */ ++@NullMarked ++public class MavenLibraryResolver implements ClassPathLibrary { ++ ++ private static final Logger LOGGER = LoggerFactory.getLogger("MavenLibraryResolver"); ++ ++ private final RepositorySystem repository; ++ private final DefaultRepositorySystemSession session; ++ private final List repositories = new ArrayList<>(); ++ private final List dependencies = new ArrayList<>(); ++ ++ /** ++ * Creates a new maven library resolver instance. ++ *

      ++ * The created instance will use the servers {@code libraries} folder to cache fetched libraries in. ++ * Notably, the resolver is created without any repository, not even maven central. ++ * It is hence crucial that plugins which aim to use this api register all required repositories before ++ * submitting the {@link MavenLibraryResolver} to the {@link io.papermc.paper.plugin.loader.PluginClasspathBuilder}. ++ */ ++ public MavenLibraryResolver() { ++ final DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); ++ locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); ++ locator.addService(TransporterFactory.class, HttpTransporterFactory.class); ++ ++ this.repository = locator.getService(RepositorySystem.class); ++ this.session = MavenRepositorySystemUtils.newSession(); ++ ++ this.session.setSystemProperties(System.getProperties()); ++ this.session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_FAIL); ++ this.session.setLocalRepositoryManager(this.repository.newLocalRepositoryManager(this.session, new LocalRepository("libraries"))); ++ this.session.setTransferListener(new AbstractTransferListener() { ++ @Override ++ public void transferInitiated(final TransferEvent event) throws TransferCancelledException { ++ LOGGER.info("Downloading {}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName()); ++ } ++ }); ++ this.session.setReadOnly(); ++ } ++ ++ /** ++ * Adds the provided dependency to the library resolver. ++ * The artifact from the first valid repository matching the passed dependency will be chosen. ++ * ++ * @param dependency the definition of the dependency the maven library resolver should resolve when running ++ * @see MavenLibraryResolver#addRepository(RemoteRepository) ++ */ ++ public void addDependency(final Dependency dependency) { ++ this.dependencies.add(dependency); ++ } ++ ++ /** ++ * Adds the provided repository to the library resolver. ++ * The order in which these are added does matter, as dependency resolving will start at the first added ++ * repository. ++ * ++ * @param remoteRepository the configuration that defines the maven repository this library resolver should fetch ++ * dependencies from ++ */ ++ public void addRepository(final RemoteRepository remoteRepository) { ++ this.repositories.add(remoteRepository); ++ } ++ ++ /** ++ * Resolves the provided dependencies and adds them to the library store. ++ * ++ * @param store the library store the then resolved and downloaded dependencies are registered into ++ * @throws LibraryLoadingException if resolving a dependency failed ++ */ ++ @Override ++ public void register(final LibraryStore store) throws LibraryLoadingException { ++ final List repos = this.repository.newResolutionRepositories(this.session, this.repositories); ++ ++ final DependencyResult result; ++ try { ++ result = this.repository.resolveDependencies(this.session, new DependencyRequest(new CollectRequest((Dependency) null, this.dependencies, repos), null)); ++ } catch (final DependencyResolutionException ex) { ++ throw new LibraryLoadingException("Error resolving libraries", ex); ++ } ++ ++ for (final ArtifactResult artifact : result.getArtifactResults()) { ++ final File file = artifact.getArtifact().getFile(); ++ store.addLibrary(file.toPath()); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..75fe408ec742319c3cba2461b33b2a6e8b22d231 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper.plugin.provider.classloader; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * The class loader access interface is an internal representation of a class accesses' ability to see types ++ * from other {@link ConfiguredPluginClassLoader}. ++ *

      ++ * An example of this would be a class loader access representing a plugin. The class loader access in that case would ++ * only return {@code true} on calls for {@link #canAccess(ConfiguredPluginClassLoader)} if the passed class loader ++ * is owned by a direct or transitive dependency of the plugin, preventing the plugin for accidentally discovering and ++ * using class types that are supplied by plugins/libraries the plugin did not actively define as a dependency. ++ */ ++@NullMarked ++@ApiStatus.Internal ++public interface ClassLoaderAccess { ++ ++ /** ++ * Evaluates if this class loader access is allowed to access types provided by the passed {@link ++ * ConfiguredPluginClassLoader}. ++ *

      ++ * This interface method does not offer any further contracts on the interface level, as the logic to determine ++ * what class loaders this class loader access is allowed to retrieve types from depends heavily on the type of ++ * access. ++ * Legacy spigot types for example may access any class loader available on the server, while modern paper plugins ++ * are properly limited to their dependency tree. ++ * ++ * @param classLoader the class loader for which access should be evaluated ++ * @return a plain boolean flag, {@code true} indicating that this class loader access is allowed to access types ++ * from the passed configured plugin class loader, {@code false} indicating otherwise. ++ */ ++ boolean canAccess(ConfiguredPluginClassLoader classLoader); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7c23e0a1a38f8b89484aee160647f751088903cd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java +@@ -0,0 +1,70 @@ ++package io.papermc.paper.plugin.provider.classloader; ++ ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import java.io.Closeable; ++import org.bukkit.plugin.java.JavaPlugin; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * The configured plugin class loader represents an internal abstraction over the classloaders used by the server ++ * to load and access a plugins classes during runtime. ++ *

      ++ * It implements {@link Closeable} to define the ability to shutdown and close the classloader that implements this ++ * interface. ++ */ ++@NullMarked ++@ApiStatus.Internal ++public interface ConfiguredPluginClassLoader extends Closeable { ++ ++ /** ++ * Provides the configuration of the plugin that this plugin classloader provides type access to. ++ * ++ * @return the plugin meta instance, holding all meta information about the plugin instance. ++ */ ++ PluginMeta getConfiguration(); ++ ++ /** ++ * Attempts to load a class from this plugin class loader using the passed fully qualified name. ++ * This lookup logic can be configured through the following parameters to define how wide or how narrow the ++ * class lookup should be. ++ * ++ * @param name the fully qualified name of the class to load ++ * @param resolve whether the class should be resolved if needed or not ++ * @param checkGlobal whether this lookup should check transitive dependencies, including either the legacy spigot ++ * global class loader or the paper {@link PluginClassLoaderGroup} ++ * @param checkLibraries whether the defined libraries should be checked for the class or not ++ * @return the class found at the fully qualified class name passed under the passed restrictions ++ * @throws ClassNotFoundException if the class could not be found considering the passed restrictions ++ * @see ClassLoader#loadClass(String) ++ * @see Class#forName(String, boolean, ClassLoader) ++ */ ++ Class loadClass(String name, ++ boolean resolve, ++ boolean checkGlobal, ++ boolean checkLibraries) throws ClassNotFoundException; ++ ++ /** ++ * Initializes both this configured plugin class loader and the java plugin passed to link to each other. ++ * This logic is to be called exactly once when the initial setup between the class loader and the instantiated ++ * {@link JavaPlugin} is loaded. ++ * ++ * @param plugin the {@link JavaPlugin} that should be interlinked with this class loader. ++ */ ++ void init(JavaPlugin plugin); ++ ++ /** ++ * Gets the plugin held by this class loader. ++ * ++ * @return the plugin or null if it doesn't exist yet ++ */ ++ @Nullable JavaPlugin getPlugin(); ++ ++ /** ++ * Get the plugin classloader group ++ * that is used by the underlying classloader ++ * @return classloader ++ */ ++ @Nullable PluginClassLoaderGroup getGroup(); ++} +diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorage.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorage.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fefc87d5ffd36b848a7adb326a3a741e9edb28df +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorage.java +@@ -0,0 +1,92 @@ ++package io.papermc.paper.plugin.provider.classloader; ++ ++import org.bukkit.plugin.java.PluginClassLoader; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * The plugin classloader storage is an internal type that is used to manage existing classloaders on the server. ++ *

      ++ * The paper classloader storage is also responsible for storing added {@link ConfiguredPluginClassLoader}s into ++ * {@link PluginClassLoaderGroup}s, via {@link #registerOpenGroup(ConfiguredPluginClassLoader)}, ++ * {@link #registerSpigotGroup(PluginClassLoader)} and {@link ++ * #registerAccessBackedGroup(ConfiguredPluginClassLoader, ClassLoaderAccess)}. ++ *

      ++ * Groups are differentiated into the global group or plugin owned groups. ++ *

        ++ *
      • The global group holds all registered class loaders and merely exists to maintain backwards compatibility with ++ * spigots legacy classloader handling.
      • ++ *
      • The plugin groups only contains the classloaders that each plugin has access to and hence serves to properly ++ * separates unrelated classloaders.
      • ++ *
      ++ */ ++@ApiStatus.Internal ++public interface PaperClassLoaderStorage { ++ ++ /** ++ * Access to the shared instance of the {@link PaperClassLoaderStorageAccess}. ++ * ++ * @return the singleton instance of the {@link PaperClassLoaderStorage} used throughout the server ++ */ ++ static PaperClassLoaderStorage instance() { ++ return PaperClassLoaderStorageAccess.INSTANCE; ++ } ++ ++ /** ++ * Registers a legacy spigot {@link PluginClassLoader} into the loader storage, creating a group wrapping ++ * the single plugin class loader with transitive access to the global group. ++ * ++ * @param pluginClassLoader the legacy spigot plugin class loader to register ++ * @return the group the plugin class loader was placed into ++ */ ++ PluginClassLoaderGroup registerSpigotGroup(PluginClassLoader pluginClassLoader); ++ ++ /** ++ * Registers a paper configured plugin classloader into a new open group, with full access to the global ++ * plugin class loader group. ++ *

      ++ * This method hence allows the configured plugin class loader to access all other class loaders registered in this ++ * storage. ++ * ++ * @param classLoader the configured plugin class loader to register ++ * @return the group the plugin class loader was placed into ++ */ ++ PluginClassLoaderGroup registerOpenGroup(ConfiguredPluginClassLoader classLoader); ++ ++ /** ++ * Registers a paper configured classloader into a new, access backed group. ++ * The access backed classloader group, different from an open group, only has access to the classloaders ++ * the passed {@link ClassLoaderAccess} grants access to. ++ * ++ * @param classLoader the configured plugin class loader to register ++ * @param access the class loader access that defines what other classloaders the passed plugin class loader ++ * should be granted access to. ++ * @return the group the plugin class loader was placed into. ++ */ ++ PluginClassLoaderGroup registerAccessBackedGroup(ConfiguredPluginClassLoader classLoader, ClassLoaderAccess access); ++ ++ /** ++ * Unregisters a configured class loader from this storage. ++ * This removes the passed class loaders from any group it may have been a part of, including the global group. ++ *

      ++ * Note: this method is highly discouraged from being used, as mutation of the classloaders at runtime ++ * is not encouraged ++ * ++ * @param configuredPluginClassLoader the class loader to remove from this storage. ++ */ ++ void unregisterClassloader(ConfiguredPluginClassLoader configuredPluginClassLoader); ++ ++ /** ++ * Registers a configured plugin class loader directly into the global group without adding it to ++ * any existing groups. ++ *

      ++ * Note: this method unsafely injects the plugin classloader directly into the global group, which bypasses the ++ * group structure paper's plugin API introduced. This method should hence be used with caution. ++ * ++ * @param pluginLoader the configured plugin classloader instance that should be registered directly into the global ++ * group. ++ * @return a simple boolean flag, {@code true} if the classloader was registered or {@code false} if the classloader ++ * was already part of the global group. ++ */ ++ boolean registerUnsafePlugin(ConfiguredPluginClassLoader pluginLoader); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorageAccess.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorageAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2c0e5ba6f8eba7a632180491843071b8a8558e56 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorageAccess.java +@@ -0,0 +1,17 @@ ++package io.papermc.paper.plugin.provider.classloader; ++ ++import net.kyori.adventure.util.Services; ++ ++/** ++ * The paper classloader storage access acts as the holder for the server provided implementation of the ++ * {@link PaperClassLoaderStorage} interface. ++ */ ++class PaperClassLoaderStorageAccess { ++ ++ /** ++ * The shared instance of the {@link PaperClassLoaderStorage}, supplied through the {@link java.util.ServiceLoader} ++ * by the server. ++ */ ++ static final PaperClassLoaderStorage INSTANCE = Services.service(PaperClassLoaderStorage.class).orElseThrow(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java +new file mode 100644 +index 0000000000000000000000000000000000000000..dd3bfbf8a30c9ac6a82dcbdf879bbf120d920e20 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java +@@ -0,0 +1,66 @@ ++package io.papermc.paper.plugin.provider.classloader; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * A plugin classloader group represents a group of classloaders that a plugins classloader may access. ++ *

      ++ * An example of this would be a classloader group that holds all direct and transitive dependencies a plugin declared, ++ * allowing a plugins classloader to access classes included in these dependencies via this group. ++ */ ++@NullMarked ++@ApiStatus.Internal ++public interface PluginClassLoaderGroup { ++ ++ /** ++ * Attempts to find/load a class from this plugin class loader group using the passed fully qualified name ++ * in any of the classloaders that are part of this group. ++ *

      ++ * The lookup order across the contained loaders is not defined on the API level and depends purely on the ++ * implementation. ++ * ++ * @param name the fully qualified name of the class to load ++ * @param resolve whether the class should be resolved if needed or not ++ * @param requester plugin classloader that is requesting the class from this loader group ++ * @return the class found at the fully qualified class name passed. If the class could not be found, {@code null} ++ * will be returned. ++ * @see ConfiguredPluginClassLoader#loadClass(String, boolean, boolean, boolean) ++ */ ++ @Nullable Class getClassByName(String name, boolean resolve, ConfiguredPluginClassLoader requester); ++ ++ /** ++ * Removes a configured plugin classloader from this class loader group. ++ * If the classloader is not currently in the list, this method will simply do nothing. ++ * ++ * @param configuredPluginClassLoader the plugin classloader to remove from the group ++ */ ++ @Contract(mutates = "this") ++ void remove(ConfiguredPluginClassLoader configuredPluginClassLoader); ++ ++ /** ++ * Adds the passed plugin classloader to this group, allowing this group to use it during ++ * {@link #getClassByName(String, boolean, ConfiguredPluginClassLoader)} lookups. ++ *

      ++ * This method does not query the {@link ClassLoaderAccess} (exposed via {@link #getAccess()}) to ensure ++ * if this group has access to the class loader passed. ++ * ++ * @param configuredPluginClassLoader the plugin classloader to add to this group. ++ */ ++ @Contract(mutates = "this") ++ void add(ConfiguredPluginClassLoader configuredPluginClassLoader); ++ ++ /** ++ * Provides the class loader access that guards and defines the content of this classloader group. ++ * While not guaranteed contractually (see {@link #add(ConfiguredPluginClassLoader)}), the access generally is ++ * responsible for defining which {@link ConfiguredPluginClassLoader}s should be part of this group and which ones ++ * should not. ++ * ++ * @return the classloader access governing which classloaders should be part of this group and which ones should ++ * not. ++ */ ++ ClassLoaderAccess getAccess(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java b/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java +new file mode 100644 +index 0000000000000000000000000000000000000000..338dc25d5161b7378dd17b17d6f603c92eb0a894 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java +@@ -0,0 +1,49 @@ ++package io.papermc.paper.plugin.provider.entrypoint; ++ ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A dependency context is a read-only abstraction of a type/concept that can resolve dependencies between plugins. ++ *

      ++ * This may for example be the server wide plugin manager itself, capable of validating if a dependency exists between ++ * two {@link PluginMeta} instances, however the implementation is not limited to such a concrete use-case. ++ */ ++@NullMarked ++@ApiStatus.Internal ++public interface DependencyContext { ++ ++ /** ++ * Computes if the passed {@link PluginMeta} defined the passed dependency as a transitive dependency. ++ * A transitive dependency, as implied by its name, may not have been configured directly by the passed plugin ++ * but could also simply be a dependency of a dependency. ++ *

      ++ * A simple example of this method would be ++ *

      {@code
      ++     * dependencyContext.isTransitiveDependency(pluginMetaA, pluginMetaC);
      ++     * }
      ++ * which would return {@code true} if {@code pluginMetaA} directly or indirectly depends on {@code pluginMetaC}. ++ * ++ * @param plugin the plugin meta this computation should consider the requester of the dependency status for the ++ * passed potential dependency. ++ * @param depend the potential transitive dependency of the {@code plugin} parameter. ++ * @return a simple boolean flag indicating if {@code plugin} considers {@code depend} as a transitive dependency. ++ */ ++ boolean isTransitiveDependency(PluginMeta plugin, PluginMeta depend); ++ ++ /** ++ * Computes if this dependency context is aware of a dependency that provides/matches the passed identifier. ++ *

      ++ * A dependency in this methods context is any dependable artefact. It does not matter if anything actually depends ++ * on said artefact, its mere existence as a potential dependency is enough for this method to consider it a ++ * dependency. If this dependency context is hence aware of an artefact with the matching identifier, this ++ * method returns {@code true}. ++ * ++ * @param pluginIdentifier the unique identifier of the dependency with which to probe this dependency context. ++ * @return a plain boolean flag indicating if this dependency context is aware of a potential dependency with the ++ * passed identifier. ++ */ ++ boolean hasDependency(String pluginIdentifier); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java b/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java +new file mode 100644 +index 0000000000000000000000000000000000000000..48a67c1b6070292dbf4ea3081f89b530207f9f6d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java +@@ -0,0 +1,77 @@ ++package io.papermc.paper.plugin.provider.util; ++ ++import com.destroystokyo.paper.util.SneakyThrow; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * An internal utility type that holds logic for loading a provider-like type from a classloaders. ++ * Provides, at least in the context of this utility, define themselves as implementations of a specific parent ++ * interface/type, e.g. {@link org.bukkit.plugin.java.JavaPlugin} and implement a no-args constructor. ++ */ ++@NullMarked ++@ApiStatus.Internal ++public final class ProviderUtil { ++ ++ /** ++ * Loads the class found at the provided fully qualified class name from the passed classloader, creates a new ++ * instance of it using the no-args constructor, that should exist as per this method contract, and casts it to the ++ * provided parent type. ++ * ++ * @param clazz the fully qualified name of the class to load ++ * @param classType the parent type that the created object found at the {@code clazz} name should be cast to ++ * @param loader the loader from which the class should be loaded ++ * @param the generic type of the parent class the created object will be cast to ++ * @return the object instantiated from the class found at the provided FQN, cast to the parent type ++ */ ++ public static T loadClass(final String clazz, final Class classType, final ClassLoader loader) { ++ return loadClass(clazz, classType, loader, null); ++ } ++ ++ /** ++ * Loads the class found at the provided fully qualified class name from the passed classloader, creates a new ++ * instance of it using the no-args constructor, that should exist as per this method contract, and casts it to the ++ * provided parent type. ++ * ++ * @param clazz the fully qualified name of the class to load ++ * @param classType the parent type that the created object found at the {@code clazz} name should be cast to ++ * @param loader the loader from which the class should be loaded ++ * @param onError a runnable that is executed before any unknown exception is raised through a sneaky throw. ++ * @param the generic type of the parent class the created object will be cast to ++ * @return the object instantiated from the class found at the provided fully qualified class name, cast to the ++ * parent type ++ */ ++ public static T loadClass(final String clazz, final Class classType, final ClassLoader loader, final @Nullable Runnable onError) { ++ try { ++ final T clazzInstance; ++ ++ try { ++ final Class jarClass = Class.forName(clazz, true, loader); ++ ++ final Class pluginClass; ++ try { ++ pluginClass = jarClass.asSubclass(classType); ++ } catch (final ClassCastException ex) { ++ throw new ClassCastException("class '%s' does not extend '%s'".formatted(clazz, classType)); ++ } ++ ++ clazzInstance = pluginClass.getDeclaredConstructor().newInstance(); ++ } catch (final IllegalAccessException exception) { ++ throw new RuntimeException("No public constructor"); ++ } catch (final InstantiationException exception) { ++ throw new RuntimeException("Abnormal class instantiation", exception); ++ } ++ ++ return clazzInstance; ++ } catch (final Throwable e) { ++ if (onError != null) { ++ onError.run(); ++ } ++ SneakyThrow.sneaky(e); ++ } ++ ++ throw new AssertionError(); // Shouldn't happen ++ } ++ ++} +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 89d5def8c1dcdab0a9e2d1809badcbbd112c3d9c..aec092e019667d53faf3e7352799772804d5d260 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -146,4 +146,14 @@ public interface UnsafeValues { + + @ApiStatus.Internal + Biome getCustomBiome(); ++ ++ // Paper start ++ @Deprecated(forRemoval = true) ++ boolean isSupportedApiVersion(String apiVersion); ++ ++ @Deprecated(forRemoval = true) ++ static boolean isLegacyPlugin(org.bukkit.plugin.Plugin plugin) { ++ return !Bukkit.getUnsafe().isSupportedApiVersion(plugin.getDescription().getAPIVersion()); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/command/PluginCommand.java b/src/main/java/org/bukkit/command/PluginCommand.java +index 1dbbc244309043b18c1d71707c4fb066c0d0e02d..551c5af6a7bfa2268cbc63be8e70d129bccaa912 100644 +--- a/src/main/java/org/bukkit/command/PluginCommand.java ++++ b/src/main/java/org/bukkit/command/PluginCommand.java +@@ -14,7 +14,7 @@ public final class PluginCommand extends Command implements PluginIdentifiableCo + private CommandExecutor executor; + private TabCompleter completer; + +- protected PluginCommand(@NotNull String name, @NotNull Plugin owner) { ++ PluginCommand(@NotNull String name, @NotNull Plugin owner) { + super(name); + this.executor = owner; + this.owningPlugin = owner; +diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java +index fd5a7a55484deb3fdcced7ebd1f4f6c14d5b4f4f..9207ae900cb4cc8ce41dd4e63d7ad8b35b0ac048 100644 +--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java ++++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java +@@ -35,7 +35,7 @@ public class SimpleCommandMap implements CommandMap { + private void setDefaultCommands() { + register("bukkit", new VersionCommand("version")); + register("bukkit", new ReloadCommand("reload")); +- register("bukkit", new PluginsCommand("plugins")); ++ //register("bukkit", new PluginsCommand("plugins")); // Paper + register("bukkit", new TimingsCommand("timings")); + } + +diff --git a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java +index bcb576a4271b1ec7b1cfe6f83cf161b7d89ed2e5..4d849e1283fdf6b0872a0f2183964cc93748c116 100644 +--- a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java ++++ b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java +@@ -9,6 +9,7 @@ import org.bukkit.command.CommandSender; + import org.bukkit.plugin.Plugin; + import org.jetbrains.annotations.NotNull; + ++@Deprecated(forRemoval = true) // Paper + public class PluginsCommand extends BukkitCommand { + public PluginsCommand(@NotNull String name) { + super(name); +diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java +index b37938745f916b5f0111b07b1a1c97527f026e9d..8c76716249e44ed8bf6be94c1f5c7b6d9bb35be2 100644 +--- a/src/main/java/org/bukkit/plugin/Plugin.java ++++ b/src/main/java/org/bukkit/plugin/Plugin.java +@@ -30,10 +30,21 @@ public interface Plugin extends TabExecutor { + * Returns the plugin.yaml file containing the details for this plugin + * + * @return Contents of the plugin.yaml file ++ * @deprecated May be inaccurate due to different plugin implementations. ++ * @see Plugin#getPluginMeta() + */ ++ @Deprecated // Paper + @NotNull + public PluginDescriptionFile getDescription(); + ++ // Paper start ++ /** ++ * Gets the plugin meta for this plugin. ++ * @return configuration ++ */ ++ @NotNull ++ io.papermc.paper.plugin.configuration.PluginMeta getPluginMeta(); ++ // Paper end + /** + * Gets a {@link FileConfiguration} for this plugin, read through + * "config.yml" +@@ -94,6 +105,7 @@ public interface Plugin extends TabExecutor { + * + * @return PluginLoader that controls this plugin + */ ++ @Deprecated(forRemoval = true) // Paper - The PluginLoader system will not function in the near future + @NotNull + public PluginLoader getPluginLoader(); + +diff --git a/src/main/java/org/bukkit/plugin/PluginBase.java b/src/main/java/org/bukkit/plugin/PluginBase.java +index 94f8ceb965cecb5669a84a0ec61c0f706c2a2673..e773db6da357ad210eb24d4c389af2dc84ce450a 100644 +--- a/src/main/java/org/bukkit/plugin/PluginBase.java ++++ b/src/main/java/org/bukkit/plugin/PluginBase.java +@@ -31,6 +31,6 @@ public abstract class PluginBase implements Plugin { + @Override + @NotNull + public final String getName() { +- return getDescription().getName(); ++ return getPluginMeta().getName(); // Paper + } + } +diff --git a/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java b/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java +index 4d444ed5bcfcd5bc3fd52fd5f28b8f8e0e006d1c..d24dc9dfe169089f26d1844d73b98b3d78fa9452 100644 +--- a/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java ++++ b/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java +@@ -199,7 +199,7 @@ import org.yaml.snakeyaml.representer.Representer; + * inferno.burningdeaths: true + * + */ +-public final class PluginDescriptionFile { ++public final class PluginDescriptionFile implements io.papermc.paper.plugin.configuration.PluginMeta { // Paper + private static final Pattern VALID_NAME = Pattern.compile("^[A-Za-z0-9 _.-]+$"); + private static final ThreadLocal YAML = new ThreadLocal() { + @Override +@@ -260,6 +260,70 @@ public final class PluginDescriptionFile { + private Set awareness = ImmutableSet.of(); + private String apiVersion = null; + private List libraries = ImmutableList.of(); ++ // Paper start - oh my goddddd ++ /** ++ * Don't use this. ++ */ ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public PluginDescriptionFile(String rawName, String name, List provides, String main, String classLoaderOf, List depend, List softDepend, List loadBefore, String version, Map> commands, String description, List authors, List contributors, String website, String prefix, PluginLoadOrder order, List permissions, PermissionDefault defaultPerm, Set awareness, String apiVersion, List libraries) { ++ this.rawName = rawName; ++ this.name = name; ++ this.provides = provides; ++ this.main = main; ++ this.classLoaderOf = classLoaderOf; ++ this.depend = depend; ++ this.softDepend = softDepend; ++ this.loadBefore = loadBefore; ++ this.version = version; ++ this.commands = commands; ++ this.description = description; ++ this.authors = authors; ++ this.contributors = contributors; ++ this.website = website; ++ this.prefix = prefix; ++ this.order = order; ++ this.permissions = permissions; ++ this.defaultPerm = defaultPerm; ++ this.awareness = awareness; ++ this.apiVersion = apiVersion; ++ this.libraries = libraries; ++ } ++ ++ @Override ++ public @NotNull String getMainClass() { ++ return this.main; ++ } ++ ++ @Override ++ public @NotNull PluginLoadOrder getLoadOrder() { ++ return this.order; ++ } ++ ++ @Override ++ public @Nullable String getLoggerPrefix() { ++ return this.prefix; ++ } ++ ++ @Override ++ public @NotNull List getPluginDependencies() { ++ return this.depend; ++ } ++ ++ @Override ++ public @NotNull List getPluginSoftDependencies() { ++ return this.softDepend; ++ } ++ ++ @Override ++ public @NotNull List getLoadBeforePlugins() { ++ return this.loadBefore; ++ } ++ ++ @Override ++ public @NotNull List getProvidedPlugins() { ++ return this.provides; ++ } ++ // Paper end + + public PluginDescriptionFile(@NotNull final InputStream stream) throws InvalidDescriptionException { + loadMap(asMap(YAML.get().load(stream))); +diff --git a/src/main/java/org/bukkit/plugin/PluginLoader.java b/src/main/java/org/bukkit/plugin/PluginLoader.java +index a88733f1cd1ddb5d85ab1b0e6af4fd5b80bbc1c6..cb530369e667c426c842da356c31304bb5c3ecfa 100644 +--- a/src/main/java/org/bukkit/plugin/PluginLoader.java ++++ b/src/main/java/org/bukkit/plugin/PluginLoader.java +@@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull; + * Represents a plugin loader, which handles direct access to specific types + * of plugins + */ ++@Deprecated(forRemoval = true) // Paper - The PluginLoader system will not function in the near future + public interface PluginLoader { + + /** +diff --git a/src/main/java/org/bukkit/plugin/PluginManager.java b/src/main/java/org/bukkit/plugin/PluginManager.java +index ae3e68562c29992fab627428db3ff0006d8216f9..47153dee66782a00b980ecf15e8774ab6f3d887d 100644 +--- a/src/main/java/org/bukkit/plugin/PluginManager.java ++++ b/src/main/java/org/bukkit/plugin/PluginManager.java +@@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Handles all plugin management from the Server + */ +-public interface PluginManager { ++public interface PluginManager extends io.papermc.paper.plugin.PermissionManager { // Paper + + /** + * Registers the specified plugin loader +@@ -23,6 +23,7 @@ public interface PluginManager { + * @throws IllegalArgumentException Thrown when the given Class is not a + * valid PluginLoader + */ ++ @Deprecated(forRemoval = true) // Paper - The PluginLoader system will not function in the near future + public void registerInterface(@NotNull Class loader) throws IllegalArgumentException; + + /** +@@ -312,4 +313,17 @@ public interface PluginManager { + * @return True if event timings are to be used + */ + public boolean useTimings(); ++ ++ // Paper start ++ @org.jetbrains.annotations.ApiStatus.Internal ++ boolean isTransitiveDependency(io.papermc.paper.plugin.configuration.PluginMeta pluginMeta, io.papermc.paper.plugin.configuration.PluginMeta dependencyConfig); ++ ++ /** ++ * Sets the permission manager to be used for this server. ++ * ++ * @param permissionManager permission manager ++ */ ++ @org.jetbrains.annotations.ApiStatus.Experimental ++ void overridePermissionManager(@NotNull Plugin plugin, @Nullable io.papermc.paper.plugin.PermissionManager permissionManager); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +index ccf2aafca03c96ad8d28571eb7172989f75c29db..d6f3c8da8bae1f70e0f9bee3e688a04801a3b546 100644 +--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java ++++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +@@ -44,6 +44,8 @@ import org.jetbrains.annotations.Nullable; + /** + * Handles all plugin management from the Server + */ ++@Deprecated(forRemoval = true) // Paper - This implementation may be replaced in a future version of Paper. ++// Plugins may still reflect into this class to modify permission logic for the time being. + public final class SimplePluginManager implements PluginManager { + private final Server server; + private final Map fileAssociations = new HashMap(); +@@ -52,10 +54,13 @@ public final class SimplePluginManager implements PluginManager { + private MutableGraph dependencyGraph = GraphBuilder.directed().build(); + private File updateDirectory; + private final SimpleCommandMap commandMap; +- private final Map permissions = new HashMap(); +- private final Map> defaultPerms = new LinkedHashMap>(); +- private final Map> permSubs = new HashMap>(); +- private final Map> defSubs = new HashMap>(); ++ // Paper start ++ public final Map permissions = new HashMap(); ++ public final Map> defaultPerms = new LinkedHashMap>(); ++ public final Map> permSubs = new HashMap>(); ++ public final Map> defSubs = new HashMap>(); ++ public PluginManager paperPluginManager; ++ // Paper end + private boolean useTimings = false; + + public SimplePluginManager(@NotNull Server instance, @NotNull SimpleCommandMap commandMap) { +@@ -112,6 +117,11 @@ public final class SimplePluginManager implements PluginManager { + @Override + @NotNull + public Plugin[] loadPlugins(@NotNull File directory) { ++ if (true) { ++ List pluginList = new ArrayList<>(); ++ java.util.Collections.addAll(pluginList, this.paperPluginManager.loadPlugins(directory)); ++ return pluginList.toArray(new Plugin[0]); ++ } + Preconditions.checkArgument(directory != null, "Directory cannot be null"); + Preconditions.checkArgument(directory.isDirectory(), "Directory must be a directory"); + +@@ -130,6 +140,7 @@ public final class SimplePluginManager implements PluginManager { + */ + @NotNull + public Plugin[] loadPlugins(@NotNull File[] files) { ++ // TODO Replace with Paper plugin loader + Preconditions.checkArgument(files != null, "File list cannot be null"); + + List result = new ArrayList(); +@@ -390,6 +401,15 @@ public final class SimplePluginManager implements PluginManager { + @Nullable + public synchronized Plugin loadPlugin(@NotNull File file) throws InvalidPluginException, UnknownDependencyException { + Preconditions.checkArgument(file != null, "File cannot be null"); ++ // Paper start ++ if (true) { ++ try { ++ return this.paperPluginManager.loadPlugin(file); ++ } catch (org.bukkit.plugin.InvalidDescriptionException ignored) { ++ return null; ++ } ++ } ++ // Paper end + + checkUpdate(file); + +@@ -440,12 +460,14 @@ public final class SimplePluginManager implements PluginManager { + @Override + @Nullable + public synchronized Plugin getPlugin(@NotNull String name) { ++ if (true) {return this.paperPluginManager.getPlugin(name);} // Paper + return lookupNames.get(name.replace(' ', '_')); + } + + @Override + @NotNull + public synchronized Plugin[] getPlugins() { ++ if (true) {return this.paperPluginManager.getPlugins();} // Paper + return plugins.toArray(new Plugin[plugins.size()]); + } + +@@ -459,6 +481,7 @@ public final class SimplePluginManager implements PluginManager { + */ + @Override + public boolean isPluginEnabled(@NotNull String name) { ++ if (true) {return this.paperPluginManager.isPluginEnabled(name);} // Paper + Plugin plugin = getPlugin(name); + + return isPluginEnabled(plugin); +@@ -472,6 +495,7 @@ public final class SimplePluginManager implements PluginManager { + */ + @Override + public boolean isPluginEnabled(@Nullable Plugin plugin) { ++ if (true) {return this.paperPluginManager.isPluginEnabled(plugin);} // Paper + if ((plugin != null) && (plugins.contains(plugin))) { + return plugin.isEnabled(); + } else { +@@ -481,6 +505,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public void enablePlugin(@NotNull final Plugin plugin) { ++ if (true) {this.paperPluginManager.enablePlugin(plugin); return;} // Paper + if (!plugin.isEnabled()) { + List pluginCommands = PluginCommandYamlParser.parse(plugin); + +@@ -500,6 +525,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public void disablePlugins() { ++ if (true) {this.paperPluginManager.disablePlugins(); return;} // Paper + Plugin[] plugins = getPlugins(); + for (int i = plugins.length - 1; i >= 0; i--) { + disablePlugin(plugins[i]); +@@ -508,6 +534,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public void disablePlugin(@NotNull final Plugin plugin) { ++ if (true) {this.paperPluginManager.disablePlugin(plugin); return;} // Paper + if (plugin.isEnabled()) { + try { + plugin.getPluginLoader().disablePlugin(plugin); +@@ -552,6 +579,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public void clearPlugins() { ++ if (true) {this.paperPluginManager.clearPlugins(); return;} // Paper + synchronized (this) { + disablePlugins(); + plugins.clear(); +@@ -572,6 +600,7 @@ public final class SimplePluginManager implements PluginManager { + */ + @Override + public void callEvent(@NotNull Event event) { ++ if (true) {this.paperPluginManager.callEvent(event); return;} // Paper + if (event.isAsynchronous()) { + if (Thread.holdsLock(this)) { + throw new IllegalStateException(event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); +@@ -620,6 +649,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public void registerEvents(@NotNull Listener listener, @NotNull Plugin plugin) { ++ if (true) {this.paperPluginManager.registerEvents(listener, plugin); return;} // Paper + if (!plugin.isEnabled()) { + throw new IllegalPluginAccessException("Plugin attempted to register " + listener + " while not enabled"); + } +@@ -653,6 +683,7 @@ public final class SimplePluginManager implements PluginManager { + Preconditions.checkArgument(priority != null, "Priority cannot be null"); + Preconditions.checkArgument(executor != null, "Executor cannot be null"); + Preconditions.checkArgument(plugin != null, "Plugin cannot be null"); ++ if (true) {this.paperPluginManager.registerEvent(event, listener, priority, executor, plugin, ignoreCancelled); return;} // Paper + + if (!plugin.isEnabled()) { + throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled"); +@@ -700,16 +731,19 @@ public final class SimplePluginManager implements PluginManager { + @Override + @Nullable + public Permission getPermission(@NotNull String name) { ++ if (true) {return this.paperPluginManager.getPermission(name);} // Paper + return permissions.get(name.toLowerCase(Locale.ROOT)); + } + + @Override + public void addPermission(@NotNull Permission perm) { ++ if (true) {this.paperPluginManager.addPermission(perm); return;} // Paper + addPermission(perm, true); + } + + @Deprecated(since = "1.12") + public void addPermission(@NotNull Permission perm, boolean dirty) { ++ if (true) {this.paperPluginManager.addPermission(perm); return;} // Paper - This just has a performance implication, use the better api to avoid this. + String name = perm.getName().toLowerCase(Locale.ROOT); + + if (permissions.containsKey(name)) { +@@ -723,21 +757,25 @@ public final class SimplePluginManager implements PluginManager { + @Override + @NotNull + public Set getDefaultPermissions(boolean op) { ++ if (true) {return this.paperPluginManager.getDefaultPermissions(op);} // Paper + return ImmutableSet.copyOf(defaultPerms.get(op)); + } + + @Override + public void removePermission(@NotNull Permission perm) { ++ if (true) {this.paperPluginManager.removePermission(perm); return;} // Paper + removePermission(perm.getName()); + } + + @Override + public void removePermission(@NotNull String name) { ++ if (true) {this.paperPluginManager.removePermission(name); return;} // Paper + permissions.remove(name.toLowerCase(Locale.ROOT)); + } + + @Override + public void recalculatePermissionDefaults(@NotNull Permission perm) { ++ if (true) {this.paperPluginManager.recalculatePermissionDefaults(perm); return;} // Paper + if (perm != null && permissions.containsKey(perm.getName().toLowerCase(Locale.ROOT))) { + defaultPerms.get(true).remove(perm); + defaultPerms.get(false).remove(perm); +@@ -777,6 +815,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public void subscribeToPermission(@NotNull String permission, @NotNull Permissible permissible) { ++ if (true) {this.paperPluginManager.subscribeToPermission(permission, permissible); return;} // Paper + String name = permission.toLowerCase(Locale.ROOT); + Map map = permSubs.get(name); + +@@ -790,6 +829,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public void unsubscribeFromPermission(@NotNull String permission, @NotNull Permissible permissible) { ++ if (true) {this.paperPluginManager.unsubscribeFromPermission(permission, permissible); return;} // Paper + String name = permission.toLowerCase(Locale.ROOT); + Map map = permSubs.get(name); + +@@ -805,6 +845,7 @@ public final class SimplePluginManager implements PluginManager { + @Override + @NotNull + public Set getPermissionSubscriptions(@NotNull String permission) { ++ if (true) {return this.paperPluginManager.getPermissionSubscriptions(permission);} // Paper + String name = permission.toLowerCase(Locale.ROOT); + Map map = permSubs.get(name); + +@@ -817,6 +858,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public void subscribeToDefaultPerms(boolean op, @NotNull Permissible permissible) { ++ if (true) {this.paperPluginManager.subscribeToDefaultPerms(op, permissible); return;} // Paper + Map map = defSubs.get(op); + + if (map == null) { +@@ -829,6 +871,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public void unsubscribeFromDefaultPerms(boolean op, @NotNull Permissible permissible) { ++ if (true) {this.paperPluginManager.unsubscribeFromDefaultPerms(op, permissible); return;} // Paper + Map map = defSubs.get(op); + + if (map != null) { +@@ -843,6 +886,7 @@ public final class SimplePluginManager implements PluginManager { + @Override + @NotNull + public Set getDefaultPermSubscriptions(boolean op) { ++ if (true) {return this.paperPluginManager.getDefaultPermSubscriptions(op);} // Paper + Map map = defSubs.get(op); + + if (map == null) { +@@ -855,6 +899,7 @@ public final class SimplePluginManager implements PluginManager { + @Override + @NotNull + public Set getPermissions() { ++ if (true) {return this.paperPluginManager.getPermissions();} // Paper + return new HashSet(permissions.values()); + } + +@@ -878,6 +923,7 @@ public final class SimplePluginManager implements PluginManager { + + @Override + public boolean useTimings() { ++ if (true) {return this.paperPluginManager.useTimings();} // Paper + return useTimings; + } + +@@ -889,4 +935,28 @@ public final class SimplePluginManager implements PluginManager { + public void useTimings(boolean use) { + useTimings = use; + } ++ ++ // Paper start ++ public void clearPermissions() { ++ if (true) {this.paperPluginManager.clearPermissions(); return;} // Paper ++ permissions.clear(); ++ defaultPerms.get(true).clear(); ++ defaultPerms.get(false).clear(); ++ } ++ ++ @Override ++ public boolean isTransitiveDependency(io.papermc.paper.plugin.configuration.PluginMeta pluginMeta, io.papermc.paper.plugin.configuration.PluginMeta dependencyConfig) { ++ return this.paperPluginManager.isTransitiveDependency(pluginMeta, dependencyConfig); ++ } ++ ++ @Override ++ public void overridePermissionManager(@NotNull Plugin plugin, @Nullable io.papermc.paper.plugin.PermissionManager permissionManager) { ++ this.paperPluginManager.overridePermissionManager(plugin, permissionManager); ++ } ++ ++ @Override ++ public void addPermissions(@NotNull List perm) { ++ this.paperPluginManager.addPermissions(perm); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/plugin/UnknownDependencyException.java b/src/main/java/org/bukkit/plugin/UnknownDependencyException.java +index a80251eff75430863b37db1c131e22593f3fcd5e..310c4041963a3f1e0a26e39a6da12a9bfdb51edc 100644 +--- a/src/main/java/org/bukkit/plugin/UnknownDependencyException.java ++++ b/src/main/java/org/bukkit/plugin/UnknownDependencyException.java +@@ -43,4 +43,16 @@ public class UnknownDependencyException extends RuntimeException { + public UnknownDependencyException() { + + } ++ // Paper start ++ /** ++ * Create a new {@link UnknownDependencyException} with a message informing ++ * about which dependencies are missing for what plugin. ++ * ++ * @param missingDependencies missing dependencies ++ * @param pluginName plugin which is missing said dependencies ++ */ ++ public UnknownDependencyException(final @org.jetbrains.annotations.NotNull java.util.Collection missingDependencies, final @org.jetbrains.annotations.NotNull String pluginName) { ++ this("Unknown/missing dependency plugins: [" + String.join(", ", missingDependencies) + "]. Please download and install these plugins to run '" + pluginName + "'."); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +index 7fca39df009308adad55a6e9dc10a4a0dead86f2..2a14522c484febcd880d00197df4359a0020dddd 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +@@ -41,6 +41,7 @@ public abstract class JavaPlugin extends PluginBase { + private Server server = null; + private File file = null; + private PluginDescriptionFile description = null; ++ private io.papermc.paper.plugin.configuration.PluginMeta pluginMeta = null; // Paper + private File dataFolder = null; + private ClassLoader classLoader = null; + private boolean naggable = true; +@@ -49,13 +50,16 @@ public abstract class JavaPlugin extends PluginBase { + private PluginLogger logger = null; + + public JavaPlugin() { +- final ClassLoader classLoader = this.getClass().getClassLoader(); +- if (!(classLoader instanceof PluginClassLoader)) { +- throw new IllegalStateException("JavaPlugin requires " + PluginClassLoader.class.getName()); ++ // Paper start ++ if (this.getClass().getClassLoader() instanceof io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader configuredPluginClassLoader) { ++ configuredPluginClassLoader.init(this); ++ } else { ++ throw new IllegalStateException("JavaPlugin requires to be created by a valid classloader."); + } +- ((PluginClassLoader) classLoader).initialize(this); ++ // Paper end + } + ++ @Deprecated(forRemoval = true) // Paper + protected JavaPlugin(@NotNull final JavaPluginLoader loader, @NotNull final PluginDescriptionFile description, @NotNull final File dataFolder, @NotNull final File file) { + final ClassLoader classLoader = this.getClass().getClassLoader(); + if (classLoader instanceof PluginClassLoader) { +@@ -80,9 +84,12 @@ public abstract class JavaPlugin extends PluginBase { + * Gets the associated PluginLoader responsible for this plugin + * + * @return PluginLoader that controls this plugin ++ * @deprecated Plugin loading now occurs at a point which makes it impossible to expose this ++ * behavior. This instance will only throw unsupported operation exceptions. + */ + @NotNull + @Override ++ @Deprecated(forRemoval = true) // Paper + public final PluginLoader getPluginLoader() { + return loader; + } +@@ -123,13 +130,20 @@ public abstract class JavaPlugin extends PluginBase { + * Returns the plugin.yaml file containing the details for this plugin + * + * @return Contents of the plugin.yaml file ++ * @deprecated No longer applicable to all types of plugins + */ + @NotNull + @Override ++ @Deprecated + public final PluginDescriptionFile getDescription() { + return description; + } + ++ @NotNull ++ public final io.papermc.paper.plugin.configuration.PluginMeta getPluginMeta() { ++ return this.pluginMeta; ++ } ++ + @NotNull + @Override + public FileConfiguration getConfig() { +@@ -259,7 +273,8 @@ public abstract class JavaPlugin extends PluginBase { + * + * @param enabled true if enabled, otherwise false + */ +- protected final void setEnabled(final boolean enabled) { ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper ++ public final void setEnabled(final boolean enabled) { // Paper + if (isEnabled != enabled) { + isEnabled = enabled; + +@@ -271,9 +286,18 @@ public abstract class JavaPlugin extends PluginBase { + } + } + +- +- final void init(@NotNull PluginLoader loader, @NotNull Server server, @NotNull PluginDescriptionFile description, @NotNull File dataFolder, @NotNull File file, @NotNull ClassLoader classLoader) { +- this.loader = loader; ++ // Paper start ++ private static class DummyPluginLoaderImplHolder { ++ private static final PluginLoader INSTANCE = net.kyori.adventure.util.Services.service(PluginLoader.class) ++ .orElseThrow(); ++ } ++ public final void init(@NotNull PluginLoader loader, @NotNull Server server, @NotNull PluginDescriptionFile description, @NotNull File dataFolder, @NotNull File file, @NotNull ClassLoader classLoader) { ++ init(server, description, dataFolder, file, classLoader, description); ++ this.pluginMeta = description; ++ } ++ public final void init(@NotNull Server server, @NotNull PluginDescriptionFile description, @NotNull File dataFolder, @NotNull File file, @NotNull ClassLoader classLoader, @Nullable io.papermc.paper.plugin.configuration.PluginMeta configuration) { ++ // Paper end ++ this.loader = DummyPluginLoaderImplHolder.INSTANCE; // Paper + this.server = server; + this.file = file; + this.description = description; +@@ -281,6 +305,7 @@ public abstract class JavaPlugin extends PluginBase { + this.classLoader = classLoader; + this.configFile = new File(dataFolder, "config.yml"); + this.logger = new PluginLogger(this); ++ this.pluginMeta = configuration; // Paper + } + + /** +@@ -397,10 +422,10 @@ public abstract class JavaPlugin extends PluginBase { + throw new IllegalArgumentException(clazz + " does not extend " + JavaPlugin.class); + } + final ClassLoader cl = clazz.getClassLoader(); +- if (!(cl instanceof PluginClassLoader)) { +- throw new IllegalArgumentException(clazz + " is not initialized by " + PluginClassLoader.class); ++ if (!(cl instanceof io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader configuredPluginClassLoader)) { // Paper ++ throw new IllegalArgumentException(clazz + " is not initialized by a " + io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader.class); // Paper + } +- JavaPlugin plugin = ((PluginClassLoader) cl).plugin; ++ JavaPlugin plugin = configuredPluginClassLoader.getPlugin(); // Paper + if (plugin == null) { + throw new IllegalStateException("Cannot get plugin for " + clazz + " from a static initializer"); + } +@@ -423,10 +448,10 @@ public abstract class JavaPlugin extends PluginBase { + public static JavaPlugin getProvidingPlugin(@NotNull Class clazz) { + Preconditions.checkArgument(clazz != null, "Null class cannot have a plugin"); + final ClassLoader cl = clazz.getClassLoader(); +- if (!(cl instanceof PluginClassLoader)) { +- throw new IllegalArgumentException(clazz + " is not provided by " + PluginClassLoader.class); ++ if (!(cl instanceof io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader configuredPluginClassLoader)) { // Paper ++ throw new IllegalArgumentException(clazz + " is not provided by a " + io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader.class); // Paper + } +- JavaPlugin plugin = ((PluginClassLoader) cl).plugin; ++ JavaPlugin plugin = configuredPluginClassLoader.getPlugin(); // Paper + if (plugin == null) { + throw new IllegalStateException("Cannot get plugin for " + clazz + " from a static initializer"); + } +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +index 29a8efdf3a8a68903a37924bbd5a24f5213aff6e..70ac93d420d0a8528428a3d038a2ef6a86d2fddd 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +@@ -49,6 +49,7 @@ import org.yaml.snakeyaml.error.YAMLException; + /** + * Represents a Java plugin loader, allowing plugins in the form of .jar + */ ++@Deprecated(forRemoval = true) // Paper - The PluginLoader system will not function in the near future. This implementation will be moved. + public final class JavaPluginLoader implements PluginLoader { + final Server server; + private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")}; +@@ -79,6 +80,7 @@ public final class JavaPluginLoader implements PluginLoader { + @Override + @NotNull + public Plugin loadPlugin(@NotNull final File file) throws InvalidPluginException { ++ if (true) throw new UnsupportedOperationException(); // Paper + Preconditions.checkArgument(file != null, "File cannot be null"); + + if (!file.exists()) { +@@ -142,7 +144,7 @@ public final class JavaPluginLoader implements PluginLoader { + + final PluginClassLoader loader; + try { +- loader = new PluginClassLoader(this, getClass().getClassLoader(), description, dataFolder, file, (libraryLoader != null) ? libraryLoader.createLoader(description) : null); ++ loader = new PluginClassLoader(getClass().getClassLoader(), description, dataFolder, file, (libraryLoader != null) ? libraryLoader.createLoader(description) : null, null, null); // Paper + } catch (InvalidPluginException ex) { + throw ex; + } catch (Throwable ex) { +diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +index 160f8c348271154c672adf936b358ffeb3b63e69..f4d655a158410039305ac68cebe0d79000f73df8 100644 +--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +@@ -36,7 +36,10 @@ import org.eclipse.aether.transport.http.HttpTransporterFactory; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +-class LibraryLoader ++// Paper start ++@org.jetbrains.annotations.ApiStatus.Internal ++public class LibraryLoader ++// Paper end + { + + private final Logger logger; +@@ -55,6 +58,7 @@ class LibraryLoader + this.repository = locator.getService( RepositorySystem.class ); + this.session = MavenRepositorySystemUtils.newSession(); + ++ session.setSystemProperties(System.getProperties()); // Paper - paper plugins, backport system properties fix for transitive dependency parsing, see #10116 + session.setChecksumPolicy( RepositoryPolicy.CHECKSUM_POLICY_FAIL ); + session.setLocalRepositoryManager( repository.newLocalRepositoryManager( session, new LocalRepository( "libraries" ) ) ); + session.setTransferListener( new AbstractTransferListener() +@@ -84,7 +88,7 @@ class LibraryLoader + } + logger.log( Level.INFO, "[{0}] Loading {1} libraries... please wait", new Object[] + { +- desc.getName(), desc.getLibraries().size() ++ java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), desc.getLibraries().size() // Paper - use configured log prefix + } ); + + List dependencies = new ArrayList<>(); +@@ -122,7 +126,7 @@ class LibraryLoader + jarFiles.add( url ); + logger.log( Level.INFO, "[{0}] Loaded library {1}", new Object[] + { +- desc.getName(), file ++ java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), file // Paper - use configured log prefix + } ); + } + +diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +index 64a294aeb6fb548794708b38c3707f9dd882b2ff..58d20eff7e0da2d7fcb1609d55e4284715355634 100644 +--- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +@@ -31,7 +31,8 @@ import org.jetbrains.annotations.Nullable; + /** + * A ClassLoader for plugins, to allow shared classes across multiple plugins + */ +-final class PluginClassLoader extends URLClassLoader { ++@org.jetbrains.annotations.ApiStatus.Internal // Paper ++public final class PluginClassLoader extends URLClassLoader implements io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader { // Paper + private final JavaPluginLoader loader; + private final Map> classes = new ConcurrentHashMap>(); + private final PluginDescriptionFile description; +@@ -45,24 +46,32 @@ final class PluginClassLoader extends URLClassLoader { + private JavaPlugin pluginInit; + private IllegalStateException pluginState; + private final Set seenIllegalAccess = Collections.newSetFromMap(new ConcurrentHashMap<>()); ++ private java.util.logging.Logger logger; // Paper - add field ++ private io.papermc.paper.plugin.provider.classloader.PluginClassLoaderGroup classLoaderGroup; // Paper ++ public io.papermc.paper.plugin.provider.entrypoint.DependencyContext dependencyContext; // Paper + + static { + ClassLoader.registerAsParallelCapable(); + } + +- PluginClassLoader(@NotNull final JavaPluginLoader loader, @Nullable final ClassLoader parent, @NotNull final PluginDescriptionFile description, @NotNull final File dataFolder, @NotNull final File file, @Nullable ClassLoader libraryLoader) throws IOException, InvalidPluginException, MalformedURLException { ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper ++ public PluginClassLoader(@Nullable final ClassLoader parent, @NotNull final PluginDescriptionFile description, @NotNull final File dataFolder, @NotNull final File file, @Nullable ClassLoader libraryLoader, JarFile jarFile, io.papermc.paper.plugin.provider.entrypoint.DependencyContext dependencyContext) throws IOException, InvalidPluginException, MalformedURLException { // Paper - use JarFile provided by SpigotPluginProvider + super(new URL[] {file.toURI().toURL()}, parent); +- Preconditions.checkArgument(loader != null, "Loader cannot be null"); ++ this.loader = null; // Paper - pass null into loader field + +- this.loader = loader; + this.description = description; + this.dataFolder = dataFolder; + this.file = file; +- this.jar = new JarFile(file); ++ this.jar = jarFile; // Paper - use JarFile provided by SpigotPluginProvider + this.manifest = jar.getManifest(); + this.url = file.toURI().toURL(); + this.libraryLoader = libraryLoader; + ++ // Paper start ++ this.dependencyContext = dependencyContext; ++ this.classLoaderGroup = io.papermc.paper.plugin.provider.classloader.PaperClassLoaderStorage.instance().registerSpigotGroup(this); ++ // Paper end ++ + Class jarClass; + try { + jarClass = Class.forName(description.getMain(), true, this); +@@ -107,6 +116,27 @@ final class PluginClassLoader extends URLClassLoader { + return findResources(name); + } + ++ // Paper start ++ @Override ++ public Class loadClass(@NotNull String name, boolean resolve, boolean checkGlobal, boolean checkLibraries) throws ClassNotFoundException { ++ return this.loadClass0(name, resolve, checkGlobal, checkLibraries); ++ } ++ @Override ++ public io.papermc.paper.plugin.configuration.PluginMeta getConfiguration() { ++ return this.description; ++ } ++ ++ @Override ++ public void init(JavaPlugin plugin) { ++ this.initialize(plugin); ++ } ++ ++ @Override ++ public JavaPlugin getPlugin() { ++ return this.plugin; ++ } ++ // Paper end ++ + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + return loadClass0(name, resolve, true, true); +@@ -132,26 +162,11 @@ final class PluginClassLoader extends URLClassLoader { + + if (checkGlobal) { + // This ignores the libraries of other plugins, unless they are transitive dependencies. +- Class result = loader.getClassByName(name, resolve, description); ++ Class result = this.classLoaderGroup.getClassByName(name, resolve, this); // Paper + + if (result != null) { + // If the class was loaded from a library instead of a PluginClassLoader, we can assume that its associated plugin is a transitive dependency and can therefore skip this check. +- if (result.getClassLoader() instanceof PluginClassLoader) { +- PluginDescriptionFile provider = ((PluginClassLoader) result.getClassLoader()).description; +- +- if (provider != description +- && !seenIllegalAccess.contains(provider.getName()) +- && !((SimplePluginManager) loader.server.getPluginManager()).isTransitiveDepend(description, provider)) { +- +- seenIllegalAccess.add(provider.getName()); +- if (plugin != null) { +- plugin.getLogger().log(Level.WARNING, "Loaded class {0} from {1} which is not a depend or softdepend of this plugin.", new Object[]{name, provider.getFullName()}); +- } else { +- // In case the bad access occurs on construction +- loader.server.getLogger().log(Level.WARNING, "[{0}] Loaded class {1} from {2} which is not a depend or softdepend of this plugin.", new Object[]{description.getName(), name, provider.getFullName()}); +- } +- } +- } ++ // Paper - Totally delete the illegal access logic, we are never going to enforce it anyways here. + + return result; + } +@@ -180,7 +195,7 @@ final class PluginClassLoader extends URLClassLoader { + throw new ClassNotFoundException(name, ex); + } + +- classBytes = loader.server.getUnsafe().processClass(description, path, classBytes); ++ classBytes = org.bukkit.Bukkit.getServer().getUnsafe().processClass(description, path, classBytes); // Paper + + int dot = name.lastIndexOf('.'); + if (dot != -1) { +@@ -210,8 +225,8 @@ final class PluginClassLoader extends URLClassLoader { + result = super.findClass(name); + } + +- loader.setClass(name, result); + classes.put(name, result); ++ this.setClass(name, result); // Paper + } + + return result; +@@ -220,6 +235,12 @@ final class PluginClassLoader extends URLClassLoader { + @Override + public void close() throws IOException { + try { ++ // Paper start ++ Collection> classes = getClasses(); ++ for (Class clazz : classes) { ++ removeClass(clazz); ++ } ++ // Paper end + super.close(); + } finally { + jar.close(); +@@ -231,7 +252,7 @@ final class PluginClassLoader extends URLClassLoader { + return classes.values(); + } + +- synchronized void initialize(@NotNull JavaPlugin javaPlugin) { ++ public synchronized void initialize(@NotNull JavaPlugin javaPlugin) { // Paper + Preconditions.checkArgument(javaPlugin != null, "Initializing plugin cannot be null"); + Preconditions.checkArgument(javaPlugin.getClass().getClassLoader() == this, "Cannot initialize plugin outside of this class loader"); + if (this.plugin != null || this.pluginInit != null) { +@@ -241,6 +262,38 @@ final class PluginClassLoader extends URLClassLoader { + pluginState = new IllegalStateException("Initial initialization"); + this.pluginInit = javaPlugin; + +- javaPlugin.init(loader, loader.server, description, dataFolder, file, this); ++ javaPlugin.init(null, org.bukkit.Bukkit.getServer(), description, dataFolder, file, this); // Paper ++ } ++ ++ // Paper start ++ @Override ++ public String toString() { ++ JavaPlugin currPlugin = plugin != null ? plugin : pluginInit; ++ return "PluginClassLoader{" + ++ "plugin=" + currPlugin + ++ ", pluginEnabled=" + (currPlugin == null ? "uninitialized" : currPlugin.isEnabled()) + ++ ", url=" + file + ++ '}'; ++ } ++ ++ void setClass(@NotNull final String name, @NotNull final Class clazz) { ++ if (org.bukkit.configuration.serialization.ConfigurationSerializable.class.isAssignableFrom(clazz)) { ++ Class serializable = clazz.asSubclass(org.bukkit.configuration.serialization.ConfigurationSerializable.class); ++ org.bukkit.configuration.serialization.ConfigurationSerialization.registerClass(serializable); ++ } ++ } ++ ++ private void removeClass(@NotNull Class clazz) { ++ if (org.bukkit.configuration.serialization.ConfigurationSerializable.class.isAssignableFrom(clazz)) { ++ Class serializable = clazz.asSubclass(org.bukkit.configuration.serialization.ConfigurationSerializable.class); ++ org.bukkit.configuration.serialization.ConfigurationSerialization.unregisterClass(serializable); ++ } + } ++ ++ @Override ++ public @Nullable io.papermc.paper.plugin.provider.classloader.PluginClassLoaderGroup getGroup() { ++ return this.classLoaderGroup; ++ } ++ ++ // Paper end + } +diff --git a/src/test/java/org/bukkit/event/SyntheticEventTest.java b/src/test/java/org/bukkit/event/SyntheticEventTest.java +deleted file mode 100644 +index 40a086f2883c4419d2bf0bd44285f7c55562ba3e..0000000000000000000000000000000000000000 +--- a/src/test/java/org/bukkit/event/SyntheticEventTest.java ++++ /dev/null +@@ -1,49 +0,0 @@ +-package org.bukkit.event; +- +-import static org.junit.jupiter.api.Assertions.*; +-import org.bukkit.Bukkit; +-import org.bukkit.plugin.PluginLoader; +-import org.bukkit.plugin.SimplePluginManager; +-import org.bukkit.plugin.TestPlugin; +-import org.bukkit.plugin.java.JavaPluginLoader; +-import org.bukkit.support.AbstractTestingBase; +-import org.junit.jupiter.api.Test; +- +-public class SyntheticEventTest extends AbstractTestingBase { +- @SuppressWarnings("deprecation") +- @Test +- public void test() { +- final JavaPluginLoader loader = new JavaPluginLoader(Bukkit.getServer()); +- TestPlugin plugin = new TestPlugin(getClass().getName()) { +- @Override +- public PluginLoader getPluginLoader() { +- return loader; +- } +- }; +- SimplePluginManager pluginManager = new SimplePluginManager(Bukkit.getServer(), null); +- +- TestEvent event = new TestEvent(false); +- Impl impl = new Impl(); +- +- pluginManager.registerEvents(impl, plugin); +- pluginManager.callEvent(event); +- +- assertEquals(1, impl.callCount); +- } +- +- public abstract static class Base implements Listener { +- int callCount = 0; +- +- public void accept(E evt) { +- callCount++; +- } +- } +- +- public static class Impl extends Base { +- @Override +- @EventHandler +- public void accept(TestEvent evt) { +- super.accept(evt); +- } +- } +-} +diff --git a/src/test/java/org/bukkit/plugin/PluginManagerTest.java b/src/test/java/org/bukkit/plugin/PluginManagerTest.java +deleted file mode 100644 +index 03b08e47e91e8b56c1992fcd749a62eb9e7d4d68..0000000000000000000000000000000000000000 +--- a/src/test/java/org/bukkit/plugin/PluginManagerTest.java ++++ /dev/null +@@ -1,185 +0,0 @@ +-package org.bukkit.plugin; +- +-import static org.bukkit.support.MatcherAssert.*; +-import static org.hamcrest.Matchers.*; +-import org.bukkit.Bukkit; +-import org.bukkit.event.Event; +-import org.bukkit.event.TestEvent; +-import org.bukkit.permissions.Permission; +-import org.bukkit.support.AbstractTestingBase; +-import org.junit.jupiter.api.AfterEach; +-import org.junit.jupiter.api.Test; +- +-public class PluginManagerTest extends AbstractTestingBase { +- private class MutableObject { +- volatile Object value = null; +- } +- +- private static final PluginManager pm = Bukkit.getServer().getPluginManager(); +- +- private final MutableObject store = new MutableObject(); +- +- @Test +- public void testAsyncSameThread() { +- final Event event = new TestEvent(true); +- try { +- pm.callEvent(event); +- } catch (IllegalStateException ex) { +- assertThat(event.getEventName() + " cannot be triggered asynchronously from primary server thread.", is(ex.getMessage())); +- return; +- } +- throw new IllegalStateException("No exception thrown"); +- } +- +- @Test +- public void testSyncSameThread() { +- final Event event = new TestEvent(false); +- pm.callEvent(event); +- } +- +- @Test +- public void testAsyncLocked() throws InterruptedException { +- final Event event = new TestEvent(true); +- Thread secondThread = new Thread( +- new Runnable() { +- @Override +- public void run() { +- try { +- synchronized (pm) { +- pm.callEvent(event); +- } +- } catch (Throwable ex) { +- store.value = ex; +- } +- } +- } +- ); +- secondThread.start(); +- secondThread.join(); +- assertThat(store.value, is(instanceOf(IllegalStateException.class))); +- assertThat(event.getEventName() + " cannot be triggered asynchronously from inside synchronized code.", is(((Throwable) store.value).getMessage())); +- } +- +- @Test +- public void testAsyncUnlocked() throws InterruptedException { +- final Event event = new TestEvent(true); +- Thread secondThread = new Thread( +- new Runnable() { +- @Override +- public void run() { +- try { +- pm.callEvent(event); +- } catch (Throwable ex) { +- store.value = ex; +- } +- } +- } +- ); +- secondThread.start(); +- secondThread.join(); +- if (store.value != null) { +- throw new RuntimeException((Throwable) store.value); +- } +- } +- +- @Test +- public void testSyncUnlocked() throws InterruptedException { +- final Event event = new TestEvent(false); +- Thread secondThread = new Thread( +- new Runnable() { +- @Override +- public void run() { +- try { +- pm.callEvent(event); +- } catch (Throwable ex) { +- store.value = ex; +- assertThat(event.getEventName() + " cannot be triggered asynchronously from another thread.", is(ex.getMessage())); +- return; +- } +- } +- } +- ); +- secondThread.start(); +- secondThread.join(); +- if (store.value == null) { +- throw new IllegalStateException("No exception thrown"); +- } +- } +- +- @Test +- public void testSyncLocked() throws InterruptedException { +- final Event event = new TestEvent(false); +- Thread secondThread = new Thread( +- new Runnable() { +- @Override +- public void run() { +- try { +- synchronized (pm) { +- pm.callEvent(event); +- } +- } catch (Throwable ex) { +- store.value = ex; +- assertThat(event.getEventName() + " cannot be triggered asynchronously from another thread.", is(ex.getMessage())); +- return; +- } +- } +- } +- ); +- secondThread.start(); +- secondThread.join(); +- if (store.value == null) { +- throw new IllegalStateException("No exception thrown"); +- } +- } +- +- @Test +- public void testRemovePermissionByNameLower() { +- this.testRemovePermissionByName("lower"); +- } +- +- @Test +- public void testRemovePermissionByNameUpper() { +- this.testRemovePermissionByName("UPPER"); +- } +- +- @Test +- public void testRemovePermissionByNameCamel() { +- this.testRemovePermissionByName("CaMeL"); +- } +- +- public void testRemovePermissionByPermissionLower() { +- this.testRemovePermissionByPermission("lower"); +- } +- +- @Test +- public void testRemovePermissionByPermissionUpper() { +- this.testRemovePermissionByPermission("UPPER"); +- } +- +- @Test +- public void testRemovePermissionByPermissionCamel() { +- this.testRemovePermissionByPermission("CaMeL"); +- } +- +- private void testRemovePermissionByName(final String name) { +- final Permission perm = new Permission(name); +- pm.addPermission(perm); +- assertThat(pm.getPermission(name), is(perm), "Permission \"" + name + "\" was not added"); +- pm.removePermission(name); +- assertThat(pm.getPermission(name), is(nullValue()), "Permission \"" + name + "\" was not removed"); +- } +- +- private void testRemovePermissionByPermission(final String name) { +- final Permission perm = new Permission(name); +- pm.addPermission(perm); +- assertThat(pm.getPermission(name), is(perm), "Permission \"" + name + "\" was not added"); +- pm.removePermission(perm); +- assertThat(pm.getPermission(name), is(nullValue()), "Permission \"" + name + "\" was not removed"); +- } +- +- @AfterEach +- public void tearDown() { +- pm.clearPlugins(); +- assertThat(pm.getPermissions(), is(empty())); +- } +-} +diff --git a/src/test/java/org/bukkit/plugin/TestPlugin.java b/src/test/java/org/bukkit/plugin/TestPlugin.java +index a8be3e23e3e280ad301d9530de50028515612966..43b58e920e739bb949ac0673e9ef73ba7b500dc9 100644 +--- a/src/test/java/org/bukkit/plugin/TestPlugin.java ++++ b/src/test/java/org/bukkit/plugin/TestPlugin.java +@@ -32,6 +32,12 @@ public class TestPlugin extends PluginBase { + public PluginDescriptionFile getDescription() { + return new PluginDescriptionFile(pluginName, "1.0", "test.test"); + } ++ // Paper start ++ @Override ++ public io.papermc.paper.plugin.configuration.PluginMeta getPluginMeta() { ++ return getDescription(); ++ } ++ // Paper end + + @Override + public FileConfiguration getConfig() { +diff --git a/src/test/java/org/bukkit/support/TestServer.java b/src/test/java/org/bukkit/support/TestServer.java +index eb1fd4b911c4af76cdd3eac85d5365e7941a4a2e..2a3ae4afef2716a5fdcefbb6d5e0e011d1db9934 100644 +--- a/src/test/java/org/bukkit/support/TestServer.java ++++ b/src/test/java/org/bukkit/support/TestServer.java +@@ -27,8 +27,7 @@ public final class TestServer { + Thread creatingThread = Thread.currentThread(); + when(instance.isPrimaryThread()).then(mock -> Thread.currentThread().equals(creatingThread)); + +- PluginManager pluginManager = new SimplePluginManager(instance, new SimpleCommandMap(instance)); +- when(instance.getPluginManager()).thenReturn(pluginManager); ++ // Paper - remove plugin manager for Paper Plugins + + Logger logger = Logger.getLogger(TestServer.class.getCanonicalName()); + when(instance.getLogger()).thenReturn(logger); diff --git a/patches/api/0009-Player-affects-spawning-API.patch b/patches/api/0009-Player-affects-spawning-API.patch deleted file mode 100644 index dc3d1182f1fa..000000000000 --- a/patches/api/0009-Player-affects-spawning-API.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jedediah Smith -Date: Mon, 29 Feb 2016 17:22:34 -0600 -Subject: [PATCH] Player affects spawning API - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index ab127d622b51e423883cbd9a7218f1cff6c2fdc1..e03ab25cf2add5edbf0d3a28451ac47360fad080 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -1819,6 +1819,22 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - @Deprecated // Paper - public String getLocale(); - -+ // Paper start -+ /** -+ * Get whether the player can affect mob spawning -+ * -+ * @return if the player can affect mob spawning -+ */ -+ public boolean getAffectsSpawning(); -+ -+ /** -+ * Set whether the player can affect mob spawning -+ * -+ * @param affects Whether the player can affect mob spawning -+ */ -+ public void setAffectsSpawning(boolean affects); -+ // Paper end -+ - /** - * Update the list of commands sent to the client. - *
      diff --git a/patches/api/0010-Add-Position.patch b/patches/api/0010-Add-Position.patch new file mode 100644 index 000000000000..23e8152911b9 --- /dev/null +++ b/patches/api/0010-Add-Position.patch @@ -0,0 +1,438 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 20 Mar 2022 10:42:28 -0700 +Subject: [PATCH] Add Position + + +diff --git a/src/main/java/io/papermc/paper/math/BlockPosition.java b/src/main/java/io/papermc/paper/math/BlockPosition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c358bfdefc9bc7598dbd0d89a6b0b8a9408b5bb3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/math/BlockPosition.java +@@ -0,0 +1,100 @@ ++package io.papermc.paper.math; ++ ++import org.bukkit.Axis; ++import org.bukkit.block.BlockFace; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A position represented with integers. ++ *

      ++ * May see breaking changes until Experimental annotation is removed. ++ * ++ * @see FinePosition ++ */ ++@ApiStatus.Experimental ++@NullMarked ++public interface BlockPosition extends Position { ++ ++ @Override ++ default double x() { ++ return this.blockX(); ++ } ++ ++ @Override ++ default double y() { ++ return this.blockY(); ++ } ++ ++ @Override ++ default double z() { ++ return this.blockZ(); ++ } ++ ++ @Override ++ default boolean isBlock() { ++ return true; ++ } ++ ++ @Override ++ default boolean isFine() { ++ return false; ++ } ++ ++ @Override ++ default BlockPosition toBlock() { ++ return this; ++ } ++ ++ @Override ++ default BlockPosition offset(final int x, final int y, final int z) { ++ return x == 0 && y == 0 && z == 0 ? this : new BlockPositionImpl(this.blockX() + x, this.blockY() + y, this.blockZ() + z); ++ } ++ ++ @Override ++ default FinePosition offset(final double x, final double y, final double z) { ++ return new FinePositionImpl(this.blockX() + x, this.blockY() + y, this.blockZ() + z); ++ } ++ ++ /** ++ * Returns a block position offset by 1 in the direction specified. ++ * ++ * @param blockFace the block face to offset towards ++ * @return the offset block position ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ default BlockPosition offset(final BlockFace blockFace) { ++ return this.offset(blockFace, 1); ++ } ++ ++ /** ++ * Returns a block position offset in the direction specified ++ * multiplied by the amount. ++ * ++ * @param blockFace the block face to offset towards ++ * @param amount the number of times to move in that direction ++ * @return the offset block position ++ */ ++ @Contract(pure = true) ++ default BlockPosition offset(final BlockFace blockFace, final int amount) { ++ return amount == 0 ? this : new BlockPositionImpl(this.blockX() + (blockFace.getModX() * amount), this.blockY() + (blockFace.getModY() * amount), this.blockZ() + (blockFace.getModZ() * amount)); ++ } ++ ++ /** ++ * Returns a block position offset by the amount along ++ * the specified axis. ++ * ++ * @param axis the axis to offset along ++ * @param amount the amount to offset along that axis ++ * @return the offset block position ++ */ ++ @Contract(pure = true) ++ default BlockPosition offset(final Axis axis, final int amount) { ++ return amount == 0 ? this : switch (axis) { ++ case X -> new BlockPositionImpl(this.blockX() + amount, this.blockY(), this.blockZ()); ++ case Y -> new BlockPositionImpl(this.blockX(), this.blockY() + amount, this.blockZ()); ++ case Z -> new BlockPositionImpl(this.blockX(), this.blockY(), this.blockZ() + amount); ++ }; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/math/BlockPositionImpl.java b/src/main/java/io/papermc/paper/math/BlockPositionImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..eb5a3f26c7ba56c6715827f52c0013a860ec7d9a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/math/BlockPositionImpl.java +@@ -0,0 +1,4 @@ ++package io.papermc.paper.math; ++ ++record BlockPositionImpl(int blockX, int blockY, int blockZ) implements BlockPosition { ++} +diff --git a/src/main/java/io/papermc/paper/math/FinePosition.java b/src/main/java/io/papermc/paper/math/FinePosition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b9c0065d8a9dedc3bd1a2d8bfbedfbc7f952ff93 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/math/FinePosition.java +@@ -0,0 +1,57 @@ ++package io.papermc.paper.math; ++ ++import org.bukkit.util.NumberConversions; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A position represented with doubles. ++ *

      ++ * May see breaking changes until Experimental annotation is removed. ++ * ++ * @see BlockPosition ++ */ ++@ApiStatus.Experimental ++@NullMarked ++public interface FinePosition extends Position { ++ ++ @Override ++ default int blockX() { ++ return NumberConversions.floor(this.x()); ++ } ++ ++ @Override ++ default int blockY() { ++ return NumberConversions.floor(this.y()); ++ } ++ ++ @Override ++ default int blockZ() { ++ return NumberConversions.floor(this.z()); ++ } ++ ++ @Override ++ default boolean isBlock() { ++ return false; ++ } ++ ++ @Override ++ default boolean isFine() { ++ return true; ++ } ++ ++ @Override ++ default BlockPosition toBlock() { ++ return new BlockPositionImpl(this.blockX(), this.blockY(), this.blockZ()); ++ } ++ ++ @Override ++ default FinePosition offset(final int x, final int y, final int z) { ++ return this.offset((double) x, y, z); ++ } ++ ++ @Override ++ default FinePosition offset(final double x, final double y, final double z) { ++ return x == 0.0 && y == 0.0 && z == 0.0 ? this : new FinePositionImpl(this.x() + x, this.y() + y, this.z() + z); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/math/FinePositionImpl.java b/src/main/java/io/papermc/paper/math/FinePositionImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..93476aaf8d21efb5a30b6d2cc2eeda8100fb72d0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/math/FinePositionImpl.java +@@ -0,0 +1,4 @@ ++package io.papermc.paper.math; ++ ++record FinePositionImpl(double x, double y, double z) implements FinePosition { ++} +diff --git a/src/main/java/io/papermc/paper/math/Position.java b/src/main/java/io/papermc/paper/math/Position.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0e6a6a6738353b118e0ed093994dda06750700c4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/math/Position.java +@@ -0,0 +1,192 @@ ++package io.papermc.paper.math; ++ ++import org.bukkit.Location; ++import org.bukkit.World; ++import org.bukkit.util.Vector; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Common interface for {@link FinePosition} and {@link BlockPosition}. ++ *

      ++ * May see breaking changes until Experimental annotation is removed. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++public interface Position { ++ ++ FinePosition FINE_ZERO = new FinePositionImpl(0, 0, 0); ++ BlockPosition BLOCK_ZERO = new BlockPositionImpl(0, 0, 0); ++ ++ /** ++ * Gets the block x value for this position ++ * ++ * @return the block x value ++ */ ++ int blockX(); ++ ++ /** ++ * Gets the block x value for this position ++ * ++ * @return the block x value ++ */ ++ int blockY(); ++ ++ /** ++ * Gets the block x value for this position ++ * ++ * @return the block x value ++ */ ++ int blockZ(); ++ ++ /** ++ * Gets the x value for this position ++ * ++ * @return the x value ++ */ ++ double x(); ++ ++ /** ++ * Gets the y value for this position ++ * ++ * @return the y value ++ */ ++ double y(); ++ ++ /** ++ * Gets the z value for this position ++ * ++ * @return the z value ++ */ ++ double z(); ++ ++ /** ++ * Checks of this position represents a {@link BlockPosition} ++ * ++ * @return true if block ++ */ ++ boolean isBlock(); ++ ++ /** ++ * Checks if this position represents a {@link FinePosition} ++ * ++ * @return true if fine ++ */ ++ boolean isFine(); ++ ++ /** ++ * Checks if each component of this position is finite. ++ */ ++ default boolean isFinite() { ++ return Double.isFinite(this.x()) && Double.isFinite(this.y()) && Double.isFinite(this.z()); ++ } ++ ++ /** ++ * Returns a position offset by the specified amounts. ++ * ++ * @param x x value to offset ++ * @param y y value to offset ++ * @param z z value to offset ++ * @return the offset position ++ */ ++ Position offset(int x, int y, int z); ++ ++ /** ++ * Returns a position offset by the specified amounts. ++ * ++ * @param x x value to offset ++ * @param y y value to offset ++ * @param z z value to offset ++ * @return the offset position ++ */ ++ FinePosition offset(double x, double y, double z); ++ ++ /** ++ * Returns a new position at the center of the block position this represents ++ * ++ * @return a new center position ++ */ ++ @Contract(value = "-> new", pure = true) ++ default FinePosition toCenter() { ++ return new FinePositionImpl(this.blockX() + 0.5, this.blockY() + 0.5, this.blockZ() + 0.5); ++ } ++ ++ /** ++ * Returns the block position of this position ++ * or itself if it already is a block position ++ * ++ * @return the block position ++ */ ++ @Contract(pure = true) ++ BlockPosition toBlock(); ++ ++ /** ++ * Converts this position to a vector ++ * ++ * @return a new vector ++ */ ++ @Contract(value = "-> new", pure = true) ++ default Vector toVector() { ++ return new Vector(this.x(), this.y(), this.z()); ++ } ++ ++ /** ++ * Creates a new location object at this position with the specified world ++ * ++ * @param world the world for the location object ++ * @return a new location ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ default Location toLocation(final World world) { ++ return new Location(world, this.x(), this.y(), this.z()); ++ } ++ ++ /** ++ * Creates a position at the coordinates ++ * ++ * @param x x coord ++ * @param y y coord ++ * @param z z coord ++ * @return a position with those coords ++ */ ++ @Contract(value = "_, _, _ -> new", pure = true) ++ static BlockPosition block(final int x, final int y, final int z) { ++ return new BlockPositionImpl(x, y, z); ++ } ++ ++ /** ++ * Creates a position from the location. ++ * ++ * @param location the location to copy the position of ++ * @return a new position at that location ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ static BlockPosition block(final Location location) { ++ return new BlockPositionImpl(location.getBlockX(), location.getBlockY(), location.getBlockZ()); ++ } ++ ++ /** ++ * Creates a position at the coordinates ++ * ++ * @param x x coord ++ * @param y y coord ++ * @param z z coord ++ * @return a position with those coords ++ */ ++ @Contract(value = "_, _, _ -> new", pure = true) ++ static FinePosition fine(final double x, final double y, final double z) { ++ return new FinePositionImpl(x, y, z); ++ } ++ ++ /** ++ * Creates a position from the location. ++ * ++ * @param location the location to copy the position of ++ * @return a new position at that location ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ static FinePosition fine(final Location location) { ++ return new FinePositionImpl(location.getX(), location.getY(), location.getZ()); ++ } ++} +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index 734054f1e8dad74c13d7ae0b1c1af2d9f45b2636..bc8a64d54e001eae6ef4520a49e261b96c5ae9f3 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -20,7 +20,7 @@ import org.jetbrains.annotations.Nullable; + * magnitude than 360 are valid, but may be normalized to any other equivalent + * representation by the implementation. + */ +-public class Location implements Cloneable, ConfigurationSerializable { ++public class Location implements Cloneable, ConfigurationSerializable, io.papermc.paper.math.FinePosition { // Paper + private Reference world; + private double x; + private double y; +@@ -706,4 +706,31 @@ public class Location implements Cloneable, ConfigurationSerializable { + } + return pitch; + } ++ ++ // Paper - add Position ++ @Override ++ public double x() { ++ return this.getX(); ++ } ++ ++ @Override ++ public double y() { ++ return this.getY(); ++ } ++ ++ @Override ++ public double z() { ++ return this.getZ(); ++ } ++ ++ @Override ++ public boolean isFinite() { ++ return io.papermc.paper.math.FinePosition.super.isFinite() && Float.isFinite(this.getYaw()) && Float.isFinite(this.getPitch()); ++ } ++ ++ @Override ++ public @NotNull Location toLocation(@NotNull World world) { ++ return new Location(world, this.x(), this.y(), this.z(), this.getYaw(), this.getPitch()); ++ } ++ // Paper end + } diff --git a/patches/api/0010-Add-getTPS-method.patch b/patches/api/0010-Add-getTPS-method.patch deleted file mode 100644 index 043bc0c56360..000000000000 --- a/patches/api/0010-Add-getTPS-method.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 29 Feb 2016 17:24:57 -0600 -Subject: [PATCH] Add getTPS method - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index fddd0ff9accd661c47c7ccc6d7035c042d991e8b..362b879996623832d436bb987630b115b7d86f99 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -1876,6 +1876,17 @@ public final class Bukkit { - return server.getEntity(uuid); - } - -+ // Paper start -+ /** -+ * Gets the current server TPS -+ * @return current server TPS (1m, 5m, 15m in Paper-Server) -+ */ -+ @NotNull -+ public static double[] getTPS() { -+ return server.getTPS(); -+ } -+ // Paper end -+ - /** - * Get the advancement specified by this key. - * -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 768ae36e3e2fdff753f4f14aa79eb36026fb38c3..8dda96966061bb3a12b63fff74a378857ec43200 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1592,6 +1592,16 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - @Nullable - Entity getEntity(@NotNull UUID uuid); - -+ // Paper start -+ /** -+ * Gets the current server TPS -+ * -+ * @return current server TPS (1m, 5m, 15m in Paper-Server) -+ */ -+ @NotNull -+ public double[] getTPS(); -+ // Paper end -+ - /** - * Get the advancement specified by this key. - * diff --git a/patches/api/0011-Timings-v2.patch b/patches/api/0011-Timings-v2.patch new file mode 100644 index 000000000000..00348af95d9c --- /dev/null +++ b/patches/api/0011-Timings-v2.patch @@ -0,0 +1,3798 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 29 Feb 2016 18:48:17 -0600 +Subject: [PATCH] Timings v2 + +TODO: Add #isStopping to FullServerTickHandler#stopTiming in patch 191 +expose isRunning + +diff --git a/src/main/java/co/aikar/timings/FullServerTickHandler.java b/src/main/java/co/aikar/timings/FullServerTickHandler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..73b125979e2f2dfd13cbf689a90b29cc68a36e09 +--- /dev/null ++++ b/src/main/java/co/aikar/timings/FullServerTickHandler.java +@@ -0,0 +1,89 @@ ++package co.aikar.timings; ++ ++import static co.aikar.timings.TimingsManager.*; ++ ++import org.bukkit.Bukkit; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++public class FullServerTickHandler extends TimingHandler { ++ private static final TimingIdentifier IDENTITY = new TimingIdentifier("Minecraft", "Full Server Tick", null); ++ final TimingData minuteData; ++ double avgFreeMemory = -1D; ++ double avgUsedMemory = -1D; ++ FullServerTickHandler() { ++ super(IDENTITY); ++ minuteData = new TimingData(id); ++ ++ TIMING_MAP.put(IDENTITY, this); ++ } ++ ++ @NotNull ++ @Override ++ public Timing startTiming() { ++ if (TimingsManager.needsFullReset) { ++ TimingsManager.resetTimings(); ++ } else if (TimingsManager.needsRecheckEnabled) { ++ TimingsManager.recheckEnabled(); ++ } ++ return super.startTiming(); ++ } ++ ++ @Override ++ public void stopTiming() { ++ super.stopTiming(); ++ if (!isEnabled()) { ++ return; ++ } ++ if (TimingHistory.timedTicks % 20 == 0) { ++ final Runtime runtime = Runtime.getRuntime(); ++ double usedMemory = runtime.totalMemory() - runtime.freeMemory(); ++ double freeMemory = runtime.maxMemory() - usedMemory; ++ if (this.avgFreeMemory == -1) { ++ this.avgFreeMemory = freeMemory; ++ } else { ++ this.avgFreeMemory = (this.avgFreeMemory * (59 / 60D)) + (freeMemory * (1 / 60D)); ++ } ++ ++ if (this.avgUsedMemory == -1) { ++ this.avgUsedMemory = usedMemory; ++ } else { ++ this.avgUsedMemory = (this.avgUsedMemory * (59 / 60D)) + (usedMemory * (1 / 60D)); ++ } ++ } ++ ++ long start = System.nanoTime(); ++ TimingsManager.tick(); ++ long diff = System.nanoTime() - start; ++ TIMINGS_TICK.addDiff(diff, null); ++ // addDiff for TIMINGS_TICK incremented this, bring it back down to 1 per tick. ++ record.setCurTickCount(record.getCurTickCount()-1); ++ ++ minuteData.setCurTickTotal(record.getCurTickTotal()); ++ minuteData.setCurTickCount(1); ++ ++ boolean violated = isViolated(); ++ minuteData.processTick(violated); ++ TIMINGS_TICK.processTick(violated); ++ processTick(violated); ++ ++ ++ if (TimingHistory.timedTicks % 1200 == 0) { ++ MINUTE_REPORTS.add(new TimingHistory.MinuteReport()); ++ TimingHistory.resetTicks(false); ++ minuteData.reset(); ++ } ++ if (TimingHistory.timedTicks % Timings.getHistoryInterval() == 0) { ++ TimingsManager.HISTORY.add(new TimingHistory()); ++ TimingsManager.resetTimings(); ++ } ++ //Bukkit.getUnsafe().reportTimings(); ++ } ++ ++ boolean isViolated() { ++ return record.getCurTickTotal() > 50000000; ++ } ++} +diff --git a/src/main/java/co/aikar/timings/NullTimingHandler.java b/src/main/java/co/aikar/timings/NullTimingHandler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..42e7e712403676171d34d5f2be27e48e7a071ebd +--- /dev/null ++++ b/src/main/java/co/aikar/timings/NullTimingHandler.java +@@ -0,0 +1,72 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++public final class NullTimingHandler implements Timing { ++ public static final Timing NULL = new NullTimingHandler(); ++ @NotNull ++ @Override ++ public Timing startTiming() { ++ return this; ++ } ++ ++ @Override ++ public void stopTiming() { ++ ++ } ++ ++ @NotNull ++ @Override ++ public Timing startTimingIfSync() { ++ return this; ++ } ++ ++ @Override ++ public void stopTimingIfSync() { ++ ++ } ++ ++ @Override ++ public void abort() { ++ ++ } ++ ++ @Nullable ++ @Override ++ public TimingHandler getTimingHandler() { ++ return null; ++ } ++ ++ @Override ++ public void close() { ++ ++ } ++} +diff --git a/src/main/java/co/aikar/timings/TimedEventExecutor.java b/src/main/java/co/aikar/timings/TimedEventExecutor.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a3ad690691eb5537a565d7ba684354acfec5ee2d +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimedEventExecutor.java +@@ -0,0 +1,87 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import org.bukkit.Bukkit; ++import org.bukkit.event.Event; ++import org.bukkit.event.EventException; ++import org.bukkit.event.Listener; ++import org.bukkit.plugin.EventExecutor; ++import org.bukkit.plugin.Plugin; ++ ++import java.lang.reflect.Method; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++public class TimedEventExecutor implements EventExecutor { ++ ++ private final EventExecutor executor; ++ private final Timing timings; ++ ++ /** ++ * Wraps an event executor and associates a timing handler to it. ++ * ++ * @param executor Executor to wrap ++ * @param plugin Owning plugin ++ * @param method EventHandler method ++ * @param eventClass Owning class ++ */ ++ public TimedEventExecutor(@NotNull EventExecutor executor, @NotNull Plugin plugin, @Nullable Method method, @NotNull Class eventClass) { ++ this.executor = executor; ++ String id; ++ ++ if (method == null) { ++ if (executor.getClass().getEnclosingClass() != null) { // Oh Skript, how we love you ++ method = executor.getClass().getEnclosingMethod(); ++ } ++ } ++ ++ if (method != null) { ++ id = method.getDeclaringClass().getName(); ++ } else { ++ id = executor.getClass().getName(); ++ } ++ ++ ++ final String eventName = eventClass.getSimpleName(); ++ boolean verbose = "BlockPhysicsEvent".equals(eventName); ++ this.timings = Timings.ofSafe(plugin, (verbose ? "## " : "") + ++ "Event: " + id + " (" + eventName + ")"); ++ } ++ ++ @Override ++ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { ++ if (event.isAsynchronous() || !Timings.timingsEnabled || !Bukkit.isPrimaryThread()) { ++ executor.execute(listener, event); ++ return; ++ } ++ try (Timing ignored = timings.startTiming()){ ++ executor.execute(listener, event); ++ } ++ } ++} +diff --git a/src/main/java/co/aikar/timings/Timing.java b/src/main/java/co/aikar/timings/Timing.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4195efcfe044618052bb03dea34a4fb2ca7c44f0 +--- /dev/null ++++ b/src/main/java/co/aikar/timings/Timing.java +@@ -0,0 +1,86 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Provides an ability to time sections of code within the Minecraft Server ++ * ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++public interface Timing extends AutoCloseable { ++ /** ++ * Starts timing the execution until {@link #stopTiming()} is called. ++ * ++ * @return Timing ++ */ ++ @NotNull ++ Timing startTiming(); ++ ++ /** ++ *

      Stops timing and records the data. Propagates the data up to group handlers.

      ++ * ++ * Will automatically be called when this Timing is used with try-with-resources ++ */ ++ void stopTiming(); ++ ++ /** ++ * Starts timing the execution until {@link #stopTiming()} is called. ++ * ++ * But only if we are on the primary thread. ++ * ++ * @return Timing ++ */ ++ @NotNull ++ Timing startTimingIfSync(); ++ ++ /** ++ *

      Stops timing and records the data. Propagates the data up to group handlers.

      ++ * ++ *

      Will automatically be called when this Timing is used with try-with-resources

      ++ * ++ * But only if we are on the primary thread. ++ */ ++ void stopTimingIfSync(); ++ ++ /** ++ * @deprecated Doesn't do anything - Removed ++ */ ++ @Deprecated ++ void abort(); ++ ++ /** ++ * Used internally to get the actual backing Handler in the case of delegated Handlers ++ * ++ * @return TimingHandler ++ */ ++ @Nullable ++ TimingHandler getTimingHandler(); ++ ++ @Override ++ void close(); ++} +diff --git a/src/main/java/co/aikar/timings/TimingData.java b/src/main/java/co/aikar/timings/TimingData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a5d13a1e44edb861f45c83a9b4309fbf799d407d +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimingData.java +@@ -0,0 +1,122 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import java.util.List; ++import org.jetbrains.annotations.NotNull; ++ ++import static co.aikar.util.JSONUtil.toArray; ++ ++/** ++ *

      Lightweight object for tracking timing data

      ++ * ++ * This is broken out to reduce memory usage ++ */ ++class TimingData { ++ private final int id; ++ private int count = 0; ++ private int lagCount = 0; ++ private long totalTime = 0; ++ private long lagTotalTime = 0; ++ private int curTickCount = 0; ++ private long curTickTotal = 0; ++ ++ TimingData(int id) { ++ this.id = id; ++ } ++ ++ private TimingData(TimingData data) { ++ this.id = data.id; ++ this.totalTime = data.totalTime; ++ this.lagTotalTime = data.lagTotalTime; ++ this.count = data.count; ++ this.lagCount = data.lagCount; ++ } ++ ++ void add(long diff) { ++ ++curTickCount; ++ curTickTotal += diff; ++ } ++ ++ void processTick(boolean violated) { ++ totalTime += curTickTotal; ++ count += curTickCount; ++ if (violated) { ++ lagTotalTime += curTickTotal; ++ lagCount += curTickCount; ++ } ++ curTickTotal = 0; ++ curTickCount = 0; ++ } ++ ++ void reset() { ++ count = 0; ++ lagCount = 0; ++ curTickTotal = 0; ++ curTickCount = 0; ++ totalTime = 0; ++ lagTotalTime = 0; ++ } ++ ++ protected TimingData clone() { ++ return new TimingData(this); ++ } ++ ++ @NotNull ++ List export() { ++ List list = toArray( ++ id, ++ count, ++ totalTime); ++ if (lagCount > 0) { ++ list.add(lagCount); ++ list.add(lagTotalTime); ++ } ++ return list; ++ } ++ ++ boolean hasData() { ++ return count > 0; ++ } ++ ++ long getTotalTime() { ++ return totalTime; ++ } ++ ++ int getCurTickCount() { ++ return curTickCount; ++ } ++ ++ void setCurTickCount(int curTickCount) { ++ this.curTickCount = curTickCount; ++ } ++ ++ long getCurTickTotal() { ++ return curTickTotal; ++ } ++ ++ void setCurTickTotal(long curTickTotal) { ++ this.curTickTotal = curTickTotal; ++ } ++} +diff --git a/src/main/java/co/aikar/timings/TimingHandler.java b/src/main/java/co/aikar/timings/TimingHandler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..199789d56d22fcb1b77ebd56805cc28aa5a5ab0a +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimingHandler.java +@@ -0,0 +1,226 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import co.aikar.util.LoadingIntMap; ++import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; ++ ++import java.util.ArrayDeque; ++import java.util.Deque; ++import java.util.concurrent.atomic.AtomicInteger; ++import java.util.logging.Level; ++import java.util.logging.Logger; ++ ++import org.bukkit.Bukkit; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++class TimingHandler implements Timing { ++ ++ private static AtomicInteger idPool = new AtomicInteger(1); ++ private static Deque TIMING_STACK = new ArrayDeque<>(); ++ final int id = idPool.getAndIncrement(); ++ ++ final TimingIdentifier identifier; ++ private final boolean verbose; ++ ++ private final Int2ObjectOpenHashMap children = new LoadingIntMap<>(TimingData::new); ++ ++ final TimingData record; ++ private TimingHandler startParent; ++ private final TimingHandler groupHandler; ++ ++ private long start = 0; ++ private int timingDepth = 0; ++ private boolean added; ++ private boolean timed; ++ private boolean enabled; ++ ++ TimingHandler(@NotNull TimingIdentifier id) { ++ this.identifier = id; ++ this.verbose = id.name.startsWith("##"); ++ this.record = new TimingData(this.id); ++ this.groupHandler = id.groupHandler; ++ ++ TimingIdentifier.getGroup(id.group).handlers.add(this); ++ checkEnabled(); ++ } ++ ++ final void checkEnabled() { ++ enabled = Timings.timingsEnabled && (!verbose || Timings.verboseEnabled); ++ } ++ ++ void processTick(boolean violated) { ++ if (timingDepth != 0 || record.getCurTickCount() == 0) { ++ timingDepth = 0; ++ start = 0; ++ return; ++ } ++ ++ record.processTick(violated); ++ for (TimingData handler : children.values()) { ++ handler.processTick(violated); ++ } ++ } ++ ++ @NotNull ++ @Override ++ public Timing startTimingIfSync() { ++ startTiming(); ++ return this; ++ } ++ ++ @Override ++ public void stopTimingIfSync() { ++ stopTiming(); ++ } ++ ++ @NotNull ++ public Timing startTiming() { ++ if (!enabled || !Bukkit.isPrimaryThread()) { ++ return this; ++ } ++ if (++timingDepth == 1) { ++ startParent = TIMING_STACK.peekLast(); ++ start = System.nanoTime(); ++ } ++ TIMING_STACK.addLast(this); ++ return this; ++ } ++ ++ public void stopTiming() { ++ if (!enabled || timingDepth <= 0 || start == 0 || !Bukkit.isPrimaryThread()) { ++ return; ++ } ++ ++ popTimingStack(); ++ if (--timingDepth == 0) { ++ addDiff(System.nanoTime() - start, startParent); ++ startParent = null; ++ start = 0; ++ } ++ } ++ ++ private void popTimingStack() { ++ TimingHandler last; ++ while ((last = TIMING_STACK.removeLast()) != this) { ++ last.timingDepth = 0; ++ if ("Minecraft".equalsIgnoreCase(last.identifier.group)) { ++ Logger.getGlobal().log(Level.SEVERE, "TIMING_STACK_CORRUPTION - Look above this for any errors and report this to Paper unless it has a plugin in the stack trace (" + last.identifier + " did not stopTiming)"); ++ } else { ++ Logger.getGlobal().log(Level.SEVERE, "TIMING_STACK_CORRUPTION - Report this to the plugin " + last.identifier.group + " (Look for errors above this in the logs) (" + last.identifier + " did not stopTiming)", new Throwable()); ++ } ++ ++ boolean found = TIMING_STACK.contains(this); ++ if (!found) { ++ // We aren't even in the stack... Don't pop everything ++ TIMING_STACK.addLast(last); ++ break; ++ } ++ } ++ } ++ ++ @Override ++ public final void abort() { ++ ++ } ++ ++ void addDiff(long diff, @Nullable TimingHandler parent) { ++ if (parent != null) { ++ parent.children.get(id).add(diff); ++ } ++ ++ record.add(diff); ++ if (!added) { ++ added = true; ++ timed = true; ++ TimingsManager.HANDLERS.add(this); ++ } ++ if (groupHandler != null) { ++ groupHandler.addDiff(diff, parent); ++ groupHandler.children.get(id).add(diff); ++ } ++ } ++ ++ /** ++ * Reset this timer, setting all values to zero. ++ */ ++ void reset(boolean full) { ++ record.reset(); ++ if (full) { ++ timed = false; ++ } ++ start = 0; ++ timingDepth = 0; ++ added = false; ++ children.clear(); ++ checkEnabled(); ++ } ++ ++ @NotNull ++ @Override ++ public TimingHandler getTimingHandler() { ++ return this; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ return (this == o); ++ } ++ ++ @Override ++ public int hashCode() { ++ return id; ++ } ++ ++ /** ++ * This is simply for the Closeable interface so it can be used with try-with-resources () ++ */ ++ @Override ++ public void close() { ++ stopTimingIfSync(); ++ } ++ ++ public boolean isSpecial() { ++ return this == TimingsManager.FULL_SERVER_TICK || this == TimingsManager.TIMINGS_TICK; ++ } ++ ++ boolean isTimed() { ++ return timed; ++ } ++ ++ public boolean isEnabled() { ++ return enabled; ++ } ++ ++ @NotNull ++ TimingData[] cloneChildren() { ++ final TimingData[] clonedChildren = new TimingData[children.size()]; ++ int i = 0; ++ for (TimingData child : children.values()) { ++ clonedChildren[i++] = child.clone(); ++ } ++ return clonedChildren; ++ } ++} +diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3d4390f263e52aafa24b306b1fd20d088a4ffcd7 +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimingHistory.java +@@ -0,0 +1,357 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import co.aikar.timings.TimingHistory.RegionData.RegionId; ++import com.google.common.base.Function; ++import com.google.common.collect.Sets; ++import org.bukkit.Bukkit; ++import org.bukkit.Chunk; ++import org.bukkit.Material; ++import org.bukkit.World; ++import org.bukkit.block.BlockState; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.EntityType; ++import org.bukkit.entity.Player; ++import co.aikar.util.LoadingMap; ++import co.aikar.util.MRUMapCache; ++ ++import java.lang.management.ManagementFactory; ++import java.util.Collection; ++import java.util.EnumMap; ++import java.util.List; ++import java.util.Map; ++import java.util.Set; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import static co.aikar.timings.TimingsManager.FULL_SERVER_TICK; ++import static co.aikar.timings.TimingsManager.MINUTE_REPORTS; ++import static co.aikar.util.JSONUtil.*; ++ ++/** ++ * Internal. ++ * ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++@SuppressWarnings({"deprecation", "SuppressionAnnotation", "Convert2Lambda", "Anonymous2MethodRef"}) ++public class TimingHistory { ++ public static long lastMinuteTime; ++ public static long timedTicks; ++ public static long playerTicks; ++ public static long entityTicks; ++ public static long tileEntityTicks; ++ public static long activatedEntityTicks; ++ private static int worldIdPool = 1; ++ static Map worldMap = LoadingMap.newHashMap(new Function() { ++ @NotNull ++ @Override ++ public Integer apply(@Nullable String input) { ++ return worldIdPool++; ++ } ++ }); ++ private final long endTime; ++ private final long startTime; ++ private final long totalTicks; ++ private final long totalTime; // Represents all time spent running the server this history ++ private final MinuteReport[] minuteReports; ++ ++ private final TimingHistoryEntry[] entries; ++ final Set tileEntityTypeSet = Sets.newHashSet(); ++ final Set entityTypeSet = Sets.newHashSet(); ++ private final Map worlds; ++ ++ TimingHistory() { ++ this.endTime = System.currentTimeMillis() / 1000; ++ this.startTime = TimingsManager.historyStart / 1000; ++ if (timedTicks % 1200 != 0 || MINUTE_REPORTS.isEmpty()) { ++ this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[MINUTE_REPORTS.size() + 1]); ++ this.minuteReports[this.minuteReports.length - 1] = new MinuteReport(); ++ } else { ++ this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[MINUTE_REPORTS.size()]); ++ } ++ long ticks = 0; ++ for (MinuteReport mp : this.minuteReports) { ++ ticks += mp.ticksRecord.timed; ++ } ++ this.totalTicks = ticks; ++ this.totalTime = FULL_SERVER_TICK.record.getTotalTime(); ++ this.entries = new TimingHistoryEntry[TimingsManager.HANDLERS.size()]; ++ ++ int i = 0; ++ for (TimingHandler handler : TimingsManager.HANDLERS) { ++ entries[i++] = new TimingHistoryEntry(handler); ++ } ++ ++ // Information about all loaded chunks/entities ++ //noinspection unchecked ++ this.worlds = toObjectMapper(Bukkit.getWorlds(), new Function() { ++ @NotNull ++ @Override ++ public JSONPair apply(World world) { ++ Map regions = LoadingMap.newHashMap(RegionData.LOADER); ++ ++ for (Chunk chunk : world.getLoadedChunks()) { ++ RegionData data = regions.get(new RegionId(chunk.getX(), chunk.getZ())); ++ ++ for (Entity entity : chunk.getEntities()) { ++ if (entity == null) { ++ Bukkit.getLogger().warning("Null entity detected in chunk at position x: " + chunk.getX() + ", z: " + chunk.getZ()); ++ continue; ++ } ++ ++ data.entityCounts.get(entity.getType()).increment(); ++ } ++ ++ for (BlockState tileEntity : chunk.getTileEntities()) { ++ if (tileEntity == null) { ++ Bukkit.getLogger().warning("Null tileentity detected in chunk at position x: " + chunk.getX() + ", z: " + chunk.getZ()); ++ continue; ++ } ++ ++ data.tileEntityCounts.get(tileEntity.getBlock().getType()).increment(); ++ } ++ } ++ return pair( ++ worldMap.get(world.getName()), ++ toArrayMapper(regions.values(),new Function() { ++ @NotNull ++ @Override ++ public Object apply(RegionData input) { ++ return toArray( ++ input.regionId.x, ++ input.regionId.z, ++ toObjectMapper(input.entityCounts.entrySet(), ++ new Function, JSONPair>() { ++ @NotNull ++ @Override ++ public JSONPair apply(Map.Entry entry) { ++ entityTypeSet.add(entry.getKey()); ++ return pair( ++ String.valueOf(entry.getKey().ordinal()), ++ entry.getValue().count() ++ ); ++ } ++ } ++ ), ++ toObjectMapper( ++ input.tileEntityCounts.entrySet(), ++ entry -> { ++ tileEntityTypeSet.add(entry.getKey()); ++ return pair( ++ String.valueOf(entry.getKey().ordinal()), ++ entry.getValue().count() ++ ); ++ } ++ ) ++ ); ++ } ++ }) ++ ); ++ } ++ }); ++ } ++ static class RegionData { ++ final RegionId regionId; ++ @SuppressWarnings("Guava") ++ static Function LOADER = new Function() { ++ @NotNull ++ @Override ++ public RegionData apply(@NotNull RegionId id) { ++ return new RegionData(id); ++ } ++ }; ++ RegionData(@NotNull RegionId id) { ++ this.regionId = id; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) { ++ return true; ++ } ++ if (o == null || getClass() != o.getClass()) { ++ return false; ++ } ++ ++ RegionData that = (RegionData) o; ++ ++ return regionId.equals(that.regionId); ++ ++ } ++ ++ @Override ++ public int hashCode() { ++ return regionId.hashCode(); ++ } ++ ++ @SuppressWarnings("unchecked") ++ final Map entityCounts = MRUMapCache.of(LoadingMap.of( ++ new EnumMap(EntityType.class), k -> new Counter() ++ )); ++ @SuppressWarnings("unchecked") ++ final Map tileEntityCounts = MRUMapCache.of(LoadingMap.of( ++ new EnumMap(Material.class), k -> new Counter() ++ )); ++ ++ static class RegionId { ++ final int x, z; ++ final long regionId; ++ RegionId(int x, int z) { ++ this.x = x >> 5 << 5; ++ this.z = z >> 5 << 5; ++ this.regionId = ((long) (this.x) << 32) + (this.z >> 5 << 5) - Integer.MIN_VALUE; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) return true; ++ if (o == null || getClass() != o.getClass()) return false; ++ ++ RegionId regionId1 = (RegionId) o; ++ ++ return regionId == regionId1.regionId; ++ ++ } ++ ++ @Override ++ public int hashCode() { ++ return (int) (regionId ^ (regionId >>> 32)); ++ } ++ } ++ } ++ static void resetTicks(boolean fullReset) { ++ if (fullReset) { ++ // Non full is simply for 1 minute reports ++ timedTicks = 0; ++ } ++ lastMinuteTime = System.nanoTime(); ++ playerTicks = 0; ++ tileEntityTicks = 0; ++ entityTicks = 0; ++ activatedEntityTicks = 0; ++ } ++ ++ @NotNull ++ Object export() { ++ return createObject( ++ pair("s", startTime), ++ pair("e", endTime), ++ pair("tk", totalTicks), ++ pair("tm", totalTime), ++ pair("w", worlds), ++ pair("h", toArrayMapper(entries, new Function() { ++ @Nullable ++ @Override ++ public Object apply(TimingHistoryEntry entry) { ++ TimingData record = entry.data; ++ if (!record.hasData()) { ++ return null; ++ } ++ return entry.export(); ++ } ++ })), ++ pair("mp", toArrayMapper(minuteReports, new Function() { ++ @NotNull ++ @Override ++ public Object apply(MinuteReport input) { ++ return input.export(); ++ } ++ })) ++ ); ++ } ++ ++ static class MinuteReport { ++ final long time = System.currentTimeMillis() / 1000; ++ ++ final TicksRecord ticksRecord = new TicksRecord(); ++ final PingRecord pingRecord = new PingRecord(); ++ final TimingData fst = TimingsManager.FULL_SERVER_TICK.minuteData.clone(); ++ final double tps = 1E9 / ( System.nanoTime() - lastMinuteTime ) * ticksRecord.timed; ++ final double usedMemory = TimingsManager.FULL_SERVER_TICK.avgUsedMemory; ++ final double freeMemory = TimingsManager.FULL_SERVER_TICK.avgFreeMemory; ++ final double loadAvg = ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage(); ++ ++ @NotNull ++ List export() { ++ return toArray( ++ time, ++ Math.round(tps * 100D) / 100D, ++ Math.round(pingRecord.avg * 100D) / 100D, ++ fst.export(), ++ toArray(ticksRecord.timed, ++ ticksRecord.player, ++ ticksRecord.entity, ++ ticksRecord.activatedEntity, ++ ticksRecord.tileEntity ++ ), ++ usedMemory, ++ freeMemory, ++ loadAvg ++ ); ++ } ++ } ++ ++ private static class TicksRecord { ++ final long timed; ++ final long player; ++ final long entity; ++ final long tileEntity; ++ final long activatedEntity; ++ ++ TicksRecord() { ++ timed = timedTicks - (TimingsManager.MINUTE_REPORTS.size() * 1200); ++ player = playerTicks; ++ entity = entityTicks; ++ tileEntity = tileEntityTicks; ++ activatedEntity = activatedEntityTicks; ++ } ++ ++ } ++ ++ private static class PingRecord { ++ final double avg; ++ ++ PingRecord() { ++ final Collection onlinePlayers = Bukkit.getOnlinePlayers(); ++ int totalPing = 0; ++ for (Player player : onlinePlayers) { ++ totalPing += player.spigot().getPing(); ++ } ++ avg = onlinePlayers.isEmpty() ? 0 : totalPing / onlinePlayers.size(); ++ } ++ } ++ ++ ++ private static class Counter { ++ private int count = 0; ++ public int increment() { ++ return ++count; ++ } ++ public int count() { ++ return count; ++ } ++ } ++} +diff --git a/src/main/java/co/aikar/timings/TimingHistoryEntry.java b/src/main/java/co/aikar/timings/TimingHistoryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..86d5ac6bd0d7d0003688761aceb3f3343575319f +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimingHistoryEntry.java +@@ -0,0 +1,58 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import com.google.common.base.Function; ++ ++import java.util.List; ++import org.jetbrains.annotations.NotNull; ++ ++import static co.aikar.util.JSONUtil.toArrayMapper; ++ ++class TimingHistoryEntry { ++ final TimingData data; ++ private final TimingData[] children; ++ ++ TimingHistoryEntry(@NotNull TimingHandler handler) { ++ this.data = handler.record.clone(); ++ children = handler.cloneChildren(); ++ } ++ ++ @NotNull ++ List export() { ++ List result = data.export(); ++ if (children.length > 0) { ++ result.add( ++ toArrayMapper(children, new Function() { ++ @NotNull ++ @Override ++ public Object apply(TimingData child) { ++ return child.export(); ++ } ++ }) ++ ); ++ } ++ return result; ++ } ++} +diff --git a/src/main/java/co/aikar/timings/TimingIdentifier.java b/src/main/java/co/aikar/timings/TimingIdentifier.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df142a89b8c43acb81eb383eac0ef048a1f49a6e +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimingIdentifier.java +@@ -0,0 +1,116 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import co.aikar.util.LoadingMap; ++ ++import java.util.ArrayList; ++import java.util.Collections; ++import java.util.List; ++import java.util.Map; ++import java.util.Objects; ++import java.util.concurrent.ConcurrentHashMap; ++import java.util.concurrent.atomic.AtomicInteger; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ *

      Used as a basis for fast HashMap key comparisons for the Timing Map.

      ++ * ++ * This class uses interned strings giving us the ability to do an identity check instead of equals() on the strings ++ */ ++final class TimingIdentifier { ++ /** ++ * Holds all groups. Autoloads on request for a group by name. ++ */ ++ static final Map GROUP_MAP = LoadingMap.of(new ConcurrentHashMap<>(64, .5F), TimingGroup::new); ++ private static final TimingGroup DEFAULT_GROUP = getGroup("Minecraft"); ++ final String group; ++ final String name; ++ final TimingHandler groupHandler; ++ private final int hashCode; ++ ++ TimingIdentifier(@Nullable String group, @NotNull String name, @Nullable Timing groupHandler) { ++ this.group = group != null ? group: DEFAULT_GROUP.name; ++ this.name = name; ++ this.groupHandler = groupHandler != null ? groupHandler.getTimingHandler() : null; ++ this.hashCode = (31 * this.group.hashCode()) + this.name.hashCode(); ++ } ++ ++ @NotNull ++ static TimingGroup getGroup(@Nullable String groupName) { ++ if (groupName == null) { ++ //noinspection ConstantConditions ++ return DEFAULT_GROUP; ++ } ++ ++ return GROUP_MAP.get(groupName); ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (o == null) { ++ return false; ++ } ++ ++ TimingIdentifier that = (TimingIdentifier) o; ++ return Objects.equals(group, that.group) && Objects.equals(name, that.name); ++ } ++ ++ @Override ++ public int hashCode() { ++ return hashCode; ++ } ++ ++ @Override ++ public String toString() { ++ return "TimingIdentifier{id=" + group + ":" + name +'}'; ++ } ++ ++ static class TimingGroup { ++ ++ private static AtomicInteger idPool = new AtomicInteger(1); ++ final int id = idPool.getAndIncrement(); ++ ++ final String name; ++ final List handlers = Collections.synchronizedList(new ArrayList<>(64)); ++ ++ private TimingGroup(String name) { ++ this.name = name; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) return true; ++ if (o == null || getClass() != o.getClass()) return false; ++ TimingGroup that = (TimingGroup) o; ++ return id == that.id; ++ } ++ ++ @Override ++ public int hashCode() { ++ return id; ++ } ++ } ++} +diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java +new file mode 100644 +index 0000000000000000000000000000000000000000..95b7cdf0677ef71e6885fa78aa5c75bb500f5f53 +--- /dev/null ++++ b/src/main/java/co/aikar/timings/Timings.java +@@ -0,0 +1,325 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import com.google.common.base.Preconditions; ++import com.google.common.collect.EvictingQueue; ++import com.google.common.collect.Lists; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.event.ClickEvent; ++import net.kyori.adventure.text.format.TextColor; ++import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; ++import org.bukkit.Bukkit; ++import org.bukkit.command.CommandSender; ++import org.bukkit.plugin.Plugin; ++ ++import java.util.List; ++import java.util.Queue; ++import java.util.logging.Level; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++@SuppressWarnings({"UnusedDeclaration", "WeakerAccess", "SameParameterValue"}) ++public final class Timings { ++ ++ final static List requestingReport = Lists.newArrayList(); ++ private static final int MAX_HISTORY_FRAMES = 12; ++ public static final Timing NULL_HANDLER = new NullTimingHandler(); ++ static boolean timingsEnabled = false; ++ static boolean verboseEnabled = false; ++ private static int historyInterval = -1; ++ private static int historyLength = -1; ++ private static boolean warnedAboutDeprecationOnEnable; ++ ++ private Timings() {} ++ ++ /** ++ * Returns a Timing for a plugin corresponding to a name. ++ * ++ * @param plugin Plugin to own the Timing ++ * @param name Name of Timing ++ * @return Handler ++ */ ++ @NotNull ++ public static Timing of(@NotNull Plugin plugin, @NotNull String name) { ++ Timing pluginHandler = null; ++ if (plugin != null) { ++ pluginHandler = ofSafe(plugin.getName(), "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER); ++ } ++ return of(plugin, name, pluginHandler); ++ } ++ ++ /** ++ *

      Returns a handler that has a groupHandler timer handler. Parent timers should not have their ++ * start/stop methods called directly, as the children will call it for you.

      ++ * ++ * Parent Timers are used to group multiple subsections together and get a summary of them combined ++ * Parent Handler can not be changed after first call ++ * ++ * @param plugin Plugin to own the Timing ++ * @param name Name of Timing ++ * @param groupHandler Parent handler to mirror .start/stop calls to ++ * @return Timing Handler ++ */ ++ @NotNull ++ public static Timing of(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) { ++ Preconditions.checkNotNull(plugin, "Plugin can not be null"); ++ Bukkit.getLogger().warning(String.format("Plugin '%s' is creating timing '%s' - this is deprecated behavior, please report it to the authors: %s", plugin.getName(), name, String.join(", ", plugin.getDescription().getAuthors()))); ++ return TimingsManager.getHandler(plugin.getName(), name, groupHandler); ++ } ++ ++ /** ++ * Returns a Timing object after starting it, useful for Java7 try-with-resources. ++ * ++ * try (Timing ignored = Timings.ofStart(plugin, someName)) { ++ * // timed section ++ * } ++ * ++ * @param plugin Plugin to own the Timing ++ * @param name Name of Timing ++ * @return Timing Handler ++ */ ++ @NotNull ++ public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name) { ++ return ofStart(plugin, name, null); ++ } ++ ++ /** ++ * Returns a Timing object after starting it, useful for Java7 try-with-resources. ++ * ++ * try (Timing ignored = Timings.ofStart(plugin, someName, groupHandler)) { ++ * // timed section ++ * } ++ * ++ * @param plugin Plugin to own the Timing ++ * @param name Name of Timing ++ * @param groupHandler Parent handler to mirror .start/stop calls to ++ * @return Timing Handler ++ */ ++ @NotNull ++ public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) { ++ Timing timing = of(plugin, name, groupHandler); ++ timing.startTiming(); ++ return timing; ++ } ++ ++ /** ++ * Gets whether or not the Spigot Timings system is enabled ++ * ++ * @return Enabled or not ++ */ ++ public static boolean isTimingsEnabled() { ++ return timingsEnabled; ++ } ++ ++ /** ++ *

      Sets whether or not the Spigot Timings system should be enabled

      ++ * ++ * Calling this will reset timing data. ++ * ++ * @param enabled Should timings be reported ++ */ ++ public static void setTimingsEnabled(boolean enabled) { ++ if (enabled && !warnedAboutDeprecationOnEnable) { ++ Bukkit.getLogger().severe(PlainTextComponentSerializer.plainText().serialize(deprecationMessage())); ++ warnedAboutDeprecationOnEnable = true; ++ } ++ } ++ ++ public static Component deprecationMessage() { ++ return Component.text() ++ .color(TextColor.color(0xffc93a)) ++ .append(Component.text("[!] The timings profiler is in no-op mode and will be fully removed in a later update.")) ++ .append(Component.newline()) ++ .append(Component.text(" We recommend migrating to the spark profiler.")) ++ .append(Component.newline()) ++ .append( ++ Component.text(" For more information please visit: ") ++ .append( ++ Component.text() ++ .content("https://github.com/PaperMC/Paper/discussions/10565") ++ .clickEvent(ClickEvent.openUrl("https://github.com/PaperMC/Paper/discussions/10565"))) ++ ) ++ .build(); ++ } ++ ++ /** ++ *

      Sets whether or not the Timings should monitor at Verbose level.

      ++ * ++ *

      When Verbose is disabled, high-frequency timings will not be available.

      ++ * ++ * @return Enabled or not ++ */ ++ public static boolean isVerboseTimingsEnabled() { ++ return verboseEnabled; ++ } ++ ++ /** ++ *

      Sets whether or not the Timings should monitor at Verbose level.

      ++ * ++ * When Verbose is disabled, high-frequency timings will not be available. ++ * Calling this will reset timing data. ++ * ++ * @param enabled Should high-frequency timings be reported ++ */ ++ public static void setVerboseTimingsEnabled(boolean enabled) { ++ verboseEnabled = enabled; ++ TimingsManager.needsRecheckEnabled = true; ++ } ++ ++ /** ++ *

      Gets the interval between Timing History report generation.

      ++ * ++ * Defaults to 5 minutes (6000 ticks) ++ * ++ * @return Interval in ticks ++ */ ++ public static int getHistoryInterval() { ++ return historyInterval; ++ } ++ ++ /** ++ *

      Sets the interval between Timing History report generations.

      ++ * ++ *

      Defaults to 5 minutes (6000 ticks)

      ++ * ++ * This will recheck your history length, so lowering this value will lower your ++ * history length if you need more than 60 history windows. ++ * ++ * @param interval Interval in ticks ++ */ ++ public static void setHistoryInterval(int interval) { ++ historyInterval = Math.max(20*60, interval); ++ // Recheck the history length with the new Interval ++ if (historyLength != -1) { ++ setHistoryLength(historyLength); ++ } ++ } ++ ++ /** ++ * Gets how long in ticks Timings history is kept for the server. ++ * ++ * Defaults to 1 hour (72000 ticks) ++ * ++ * @return Duration in Ticks ++ */ ++ public static int getHistoryLength() { ++ return historyLength; ++ } ++ ++ /** ++ * Sets how long Timing History reports are kept for the server. ++ * ++ * Defaults to 1 hours(72000 ticks) ++ * ++ * This value is capped at a maximum of getHistoryInterval() * MAX_HISTORY_FRAMES (12) ++ * ++ * Will not reset Timing Data but may truncate old history if the new length is less than old length. ++ * ++ * @param length Duration in ticks ++ */ ++ public static void setHistoryLength(int length) { ++ // Cap at 12 History Frames, 1 hour at 5 minute frames. ++ int maxLength = historyInterval * MAX_HISTORY_FRAMES; ++ // For special cases of servers with special permission to bypass the max. ++ // This max helps keep data file sizes reasonable for processing on Aikar's Timing parser side. ++ // Setting this will not help you bypass the max unless Aikar has added an exception on the API side. ++ if (System.getProperty("timings.bypassMax") != null) { ++ maxLength = Integer.MAX_VALUE; ++ } ++ historyLength = Math.max(Math.min(maxLength, length), historyInterval); ++ Queue oldQueue = TimingsManager.HISTORY; ++ int frames = (getHistoryLength() / getHistoryInterval()); ++ if (length > maxLength) { ++ Bukkit.getLogger().log(Level.WARNING, "Timings Length too high. Requested " + length + ", max is " + maxLength + ". To get longer history, you must increase your interval. Set Interval to " + Math.ceil(length / MAX_HISTORY_FRAMES) + " to achieve this length."); ++ } ++ TimingsManager.HISTORY = EvictingQueue.create(frames); ++ TimingsManager.HISTORY.addAll(oldQueue); ++ } ++ ++ /** ++ * Resets all Timing Data ++ */ ++ public static void reset() { ++ TimingsManager.reset(); ++ } ++ ++ /** ++ * Generates a report and sends it to the specified command sender. ++ * ++ * If sender is null, ConsoleCommandSender will be used. ++ * @param sender The sender to send to, or null to use the ConsoleCommandSender ++ */ ++ public static void generateReport(@Nullable CommandSender sender) { ++ if (sender == null) { ++ sender = Bukkit.getConsoleSender(); ++ } ++ requestingReport.add(sender); ++ } ++ ++ /** ++ * Generates a report and sends it to the specified listener. ++ * Use with {@link org.bukkit.command.BufferedCommandSender} to get full response when done! ++ * @param sender The listener to send responses too. ++ */ ++ public static void generateReport(@NotNull TimingsReportListener sender) { ++ Preconditions.checkNotNull(sender); ++ requestingReport.add(sender); ++ } ++ ++ /* ++ ================= ++ Protected API: These are for internal use only in Bukkit/CraftBukkit ++ These do not have isPrimaryThread() checks in the startTiming/stopTiming ++ ================= ++ */ ++ @NotNull ++ static TimingHandler ofSafe(@NotNull String name) { ++ return ofSafe(null, name, null); ++ } ++ ++ @NotNull ++ static Timing ofSafe(@Nullable Plugin plugin, @NotNull String name) { ++ Timing pluginHandler = null; ++ if (plugin != null) { ++ pluginHandler = ofSafe(plugin.getName(), "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER); ++ } ++ return ofSafe(plugin != null ? plugin.getName() : "Minecraft - Invalid Plugin", name, pluginHandler); ++ } ++ ++ @NotNull ++ static TimingHandler ofSafe(@NotNull String name, @Nullable Timing groupHandler) { ++ return ofSafe(null, name, groupHandler); ++ } ++ ++ @NotNull ++ static TimingHandler ofSafe(@Nullable String groupName, @NotNull String name, @Nullable Timing groupHandler) { ++ return TimingsManager.getHandler(groupName, name, groupHandler); ++ } ++} ++ +diff --git a/src/main/java/co/aikar/timings/TimingsCommand.java b/src/main/java/co/aikar/timings/TimingsCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b83e5ff7ada8771fdf27ba9807c77ba6a4ce12da +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimingsCommand.java +@@ -0,0 +1,127 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import com.google.common.base.Preconditions; ++import com.google.common.collect.ImmutableList; ++import net.kyori.adventure.text.format.NamedTextColor; ++import org.bukkit.command.CommandSender; ++import org.bukkit.command.defaults.BukkitCommand; ++import org.bukkit.util.StringUtil; ++ ++import java.util.ArrayList; ++import java.util.List; ++import org.jetbrains.annotations.NotNull; ++ ++import static net.kyori.adventure.text.Component.text; ++ ++/** ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++public class TimingsCommand extends BukkitCommand { ++ private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("report", "reset", "on", "off", "paste", "verbon", "verboff"); ++ private long lastResetAttempt = 0; ++ ++ public TimingsCommand(@NotNull String name) { ++ super(name); ++ this.description = "Manages Spigot Timings data to see performance of the server."; ++ this.usageMessage = "/timings "; ++ this.setPermission("bukkit.command.timings"); ++ } ++ ++ @Override ++ public boolean execute(@NotNull CommandSender sender, @NotNull String currentAlias, @NotNull String[] args) { ++ if (!testPermission(sender)) { ++ return true; ++ } ++ if (true) { ++ sender.sendMessage(Timings.deprecationMessage()); ++ return true; ++ } ++ if (args.length < 1) { ++ sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED)); ++ return true; ++ } ++ final String arg = args[0]; ++ if ("on".equalsIgnoreCase(arg)) { ++ Timings.setTimingsEnabled(true); ++ sender.sendMessage(text("Enabled Timings & Reset")); ++ return true; ++ } else if ("off".equalsIgnoreCase(arg)) { ++ Timings.setTimingsEnabled(false); ++ sender.sendMessage(text("Disabled Timings")); ++ return true; ++ } ++ ++ if (!Timings.isTimingsEnabled()) { ++ sender.sendMessage(text("Please enable timings by typing /timings on")); ++ return true; ++ } ++ ++ long now = System.currentTimeMillis(); ++ if ("verbon".equalsIgnoreCase(arg)) { ++ Timings.setVerboseTimingsEnabled(true); ++ sender.sendMessage(text("Enabled Verbose Timings")); ++ return true; ++ } else if ("verboff".equalsIgnoreCase(arg)) { ++ Timings.setVerboseTimingsEnabled(false); ++ sender.sendMessage(text("Disabled Verbose Timings")); ++ return true; ++ } else if ("reset".equalsIgnoreCase(arg)) { ++ if (now - lastResetAttempt < 30000) { ++ TimingsManager.reset(); ++ sender.sendMessage(text("Timings reset. Please wait 5-10 minutes before using /timings report.", NamedTextColor.RED)); ++ } else { ++ lastResetAttempt = now; ++ sender.sendMessage(text("WARNING: Timings v2 should not be reset. If you are experiencing lag, please wait 3 minutes and then issue a report. The best timings will include 10+ minutes, with data before and after your lag period. If you really want to reset, run this command again within 30 seconds.", NamedTextColor.RED)); ++ } ++ } else if ( ++ "paste".equalsIgnoreCase(arg) || ++ "report".equalsIgnoreCase(arg) || ++ "get".equalsIgnoreCase(arg) || ++ "merged".equalsIgnoreCase(arg) || ++ "separate".equalsIgnoreCase(arg) ++ ) { ++ Timings.generateReport(sender); ++ } else { ++ sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED)); ++ } ++ return true; ++ } ++ ++ @NotNull ++ @Override ++ public List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { ++ Preconditions.checkNotNull(sender, "Sender cannot be null"); ++ Preconditions.checkNotNull(args, "Arguments cannot be null"); ++ Preconditions.checkNotNull(alias, "Alias cannot be null"); ++ ++ if (args.length == 1) { ++ return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS, ++ new ArrayList(TIMINGS_SUBCOMMANDS.size())); ++ } ++ return ImmutableList.of(); ++ } ++} +diff --git a/src/main/java/co/aikar/timings/TimingsManager.java b/src/main/java/co/aikar/timings/TimingsManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e72ad05abada04426e32a73d02b21cb69079d268 +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimingsManager.java +@@ -0,0 +1,192 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import co.aikar.util.LoadingMap; ++import com.google.common.collect.EvictingQueue; ++import org.bukkit.Bukkit; ++import org.bukkit.Server; ++import org.bukkit.command.Command; ++import org.bukkit.plugin.Plugin; ++import org.bukkit.plugin.java.PluginClassLoader; ++ ++import java.util.ArrayList; ++import java.util.List; ++import java.util.Map; ++import java.util.concurrent.ConcurrentHashMap; ++import java.util.logging.Level; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++public final class TimingsManager { ++ static final Map TIMING_MAP = LoadingMap.of( ++ new ConcurrentHashMap<>(4096, .5F), TimingHandler::new ++ ); ++ public static final FullServerTickHandler FULL_SERVER_TICK = new FullServerTickHandler(); ++ public static final TimingHandler TIMINGS_TICK = Timings.ofSafe("Timings Tick", FULL_SERVER_TICK); ++ public static final Timing PLUGIN_GROUP_HANDLER = Timings.ofSafe("Plugins"); ++ public static String url = "https://timings.aikar.co/"; ++ public static List hiddenConfigs = new ArrayList(); ++ public static boolean privacy = false; ++ ++ static final List HANDLERS = new ArrayList<>(1024); ++ static final List MINUTE_REPORTS = new ArrayList<>(64); ++ ++ static EvictingQueue HISTORY = EvictingQueue.create(12); ++ static long timingStart = 0; ++ static long historyStart = 0; ++ static boolean needsFullReset = false; ++ static boolean needsRecheckEnabled = false; ++ ++ private TimingsManager() {} ++ ++ /** ++ * Resets all timing data on the next tick ++ */ ++ static void reset() { ++ needsFullReset = true; ++ } ++ ++ /** ++ * Ticked every tick by CraftBukkit to count the number of times a timer ++ * caused TPS loss. ++ */ ++ static void tick() { ++ if (Timings.timingsEnabled) { ++ boolean violated = FULL_SERVER_TICK.isViolated(); ++ ++ for (TimingHandler handler : HANDLERS) { ++ if (handler.isSpecial()) { ++ // We manually call this ++ continue; ++ } ++ handler.processTick(violated); ++ } ++ ++ TimingHistory.playerTicks += Bukkit.getOnlinePlayers().size(); ++ TimingHistory.timedTicks++; ++ // Generate TPS/Ping/Tick reports every minute ++ } ++ } ++ static void stopServer() { ++ Timings.timingsEnabled = false; ++ recheckEnabled(); ++ } ++ static void recheckEnabled() { ++ synchronized (TIMING_MAP) { ++ for (TimingHandler timings : TIMING_MAP.values()) { ++ timings.checkEnabled(); ++ } ++ } ++ needsRecheckEnabled = false; ++ } ++ static void resetTimings() { ++ if (needsFullReset) { ++ // Full resets need to re-check every handlers enabled state ++ // Timing map can be modified from async so we must sync on it. ++ synchronized (TIMING_MAP) { ++ for (TimingHandler timings : TIMING_MAP.values()) { ++ timings.reset(true); ++ } ++ } ++ Bukkit.getLogger().log(Level.INFO, "Timings Reset"); ++ HISTORY.clear(); ++ needsFullReset = false; ++ needsRecheckEnabled = false; ++ timingStart = System.currentTimeMillis(); ++ } else { ++ // Soft resets only need to act on timings that have done something ++ // Handlers can only be modified on main thread. ++ for (TimingHandler timings : HANDLERS) { ++ timings.reset(false); ++ } ++ } ++ ++ HANDLERS.clear(); ++ MINUTE_REPORTS.clear(); ++ ++ TimingHistory.resetTicks(true); ++ historyStart = System.currentTimeMillis(); ++ } ++ ++ @NotNull ++ static TimingHandler getHandler(@Nullable String group, @NotNull String name, @Nullable Timing parent) { ++ return TIMING_MAP.get(new TimingIdentifier(group, name, parent)); ++ } ++ ++ ++ /** ++ *

      Due to access restrictions, we need a helper method to get a Command TimingHandler with String group

      ++ * ++ * Plugins should never call this ++ * ++ * @param pluginName Plugin this command is associated with ++ * @param command Command to get timings for ++ * @return TimingHandler ++ */ ++ @NotNull ++ public static Timing getCommandTiming(@Nullable String pluginName, @NotNull Command command) { ++ Plugin plugin = null; ++ final Server server = Bukkit.getServer(); ++ if (!( server == null || pluginName == null || ++ "minecraft".equals(pluginName) || "bukkit".equals(pluginName) || ++ "spigot".equalsIgnoreCase(pluginName) || "paper".equals(pluginName) ++ )) { ++ plugin = server.getPluginManager().getPlugin(pluginName); ++ } ++ if (plugin == null) { ++ // Plugin is passing custom fallback prefix, try to look up by class loader ++ plugin = getPluginByClassloader(command.getClass()); ++ } ++ if (plugin == null) { ++ return Timings.ofSafe("Command: " + pluginName + ":" + command.getTimingName()); ++ } ++ ++ return Timings.ofSafe(plugin, "Command: " + pluginName + ":" + command.getTimingName()); ++ } ++ ++ /** ++ * Looks up the class loader for the specified class, and if it is a PluginClassLoader, return the ++ * Plugin that created this class. ++ * ++ * @param clazz Class to check ++ * @return Plugin if created by a plugin ++ */ ++ @Nullable ++ public static Plugin getPluginByClassloader(@Nullable Class clazz) { ++ if (clazz == null) { ++ return null; ++ } ++ final ClassLoader classLoader = clazz.getClassLoader(); ++ if (classLoader instanceof PluginClassLoader) { ++ PluginClassLoader pluginClassLoader = (PluginClassLoader) classLoader; ++ return pluginClassLoader.getPlugin(); ++ } ++ return null; ++ } ++} +diff --git a/src/main/java/co/aikar/timings/TimingsReportListener.java b/src/main/java/co/aikar/timings/TimingsReportListener.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df066d6f8d55afbc0c1897c486d638657a5f8df9 +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimingsReportListener.java +@@ -0,0 +1,90 @@ ++package co.aikar.timings; ++ ++import com.google.common.base.Preconditions; ++import com.google.common.collect.Lists; ++import org.bukkit.Bukkit; ++import org.bukkit.command.CommandSender; ++import org.bukkit.command.ConsoleCommandSender; ++import org.bukkit.command.MessageCommandSender; ++import org.bukkit.command.RemoteConsoleCommandSender; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.List; ++ ++/** ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++@SuppressWarnings("WeakerAccess") ++public class TimingsReportListener implements net.kyori.adventure.audience.ForwardingAudience, MessageCommandSender { ++ private final List senders; ++ private final Runnable onDone; ++ private String timingsURL; ++ ++ public TimingsReportListener(@NotNull CommandSender senders) { ++ this(senders, null); ++ } ++ public TimingsReportListener(@NotNull CommandSender sender, @Nullable Runnable onDone) { ++ this(Lists.newArrayList(sender), onDone); ++ } ++ public TimingsReportListener(@NotNull List senders) { ++ this(senders, null); ++ } ++ public TimingsReportListener(@NotNull List senders, @Nullable Runnable onDone) { ++ Preconditions.checkNotNull(senders); ++ Preconditions.checkArgument(!senders.isEmpty(), "senders is empty"); ++ ++ this.senders = Lists.newArrayList(senders); ++ this.onDone = onDone; ++ } ++ ++ @Nullable ++ public String getTimingsURL() { ++ return timingsURL; ++ } ++ ++ public void done() { ++ done(null); ++ } ++ ++ public void done(@Nullable String url) { ++ this.timingsURL = url; ++ if (onDone != null) { ++ onDone.run(); ++ } ++ for (CommandSender sender : senders) { ++ if (sender instanceof TimingsReportListener) { ++ ((TimingsReportListener) sender).done(); ++ } ++ } ++ } ++ ++ @Override ++ public void sendMessage(final @NotNull net.kyori.adventure.identity.Identity source, final @NotNull net.kyori.adventure.text.Component message, final @NotNull net.kyori.adventure.audience.MessageType type) { ++ net.kyori.adventure.audience.ForwardingAudience.super.sendMessage(source, message, type); ++ } ++ ++ @NotNull ++ @Override ++ public Iterable audiences() { ++ return this.senders; ++ } ++ ++ @Override ++ public void sendMessage(@NotNull String message) { ++ senders.forEach((sender) -> sender.sendMessage(message)); ++ } ++ ++ public void addConsoleIfNeeded() { ++ boolean hasConsole = false; ++ for (CommandSender sender : this.senders) { ++ if (sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) { ++ hasConsole = true; ++ } ++ } ++ if (!hasConsole) { ++ this.senders.add(Bukkit.getConsoleSender()); ++ } ++ } ++} +diff --git a/src/main/java/co/aikar/timings/UnsafeTimingHandler.java b/src/main/java/co/aikar/timings/UnsafeTimingHandler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..632c4961515f5052551f841cfa840e60bba7a257 +--- /dev/null ++++ b/src/main/java/co/aikar/timings/UnsafeTimingHandler.java +@@ -0,0 +1,53 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import org.bukkit.Bukkit; ++import org.jetbrains.annotations.NotNull; ++ ++class UnsafeTimingHandler extends TimingHandler { ++ ++ UnsafeTimingHandler(@NotNull TimingIdentifier id) { ++ super(id); ++ } ++ ++ private static void checkThread() { ++ if (!Bukkit.isPrimaryThread()) { ++ throw new IllegalStateException("Calling Timings from Async Operation"); ++ } ++ } ++ ++ @NotNull ++ @Override ++ public Timing startTiming() { ++ checkThread(); ++ return super.startTiming(); ++ } ++ ++ @Override ++ public void stopTiming() { ++ checkThread(); ++ super.stopTiming(); ++ } ++} +diff --git a/src/main/java/co/aikar/util/Counter.java b/src/main/java/co/aikar/util/Counter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..dae84243804b4b076cafb3e1b29bdcf614efc93f +--- /dev/null ++++ b/src/main/java/co/aikar/util/Counter.java +@@ -0,0 +1,39 @@ ++package co.aikar.util; ++ ++import com.google.common.collect.ForwardingMap; ++ ++import java.util.HashMap; ++import java.util.Map; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++@Deprecated(forRemoval = true) ++public class Counter extends ForwardingMap { ++ private final Map counts = new HashMap<>(); ++ ++ public long decrement(@Nullable T key) { ++ return increment(key, -1); ++ } ++ public long increment(@Nullable T key) { ++ return increment(key, 1); ++ } ++ public long decrement(@Nullable T key, long amount) { ++ return increment(key, -amount); ++ } ++ public long increment(@Nullable T key, long amount) { ++ Long count = this.getCount(key); ++ count += amount; ++ this.counts.put(key, count); ++ return count; ++ } ++ ++ public long getCount(@Nullable T key) { ++ return this.counts.getOrDefault(key, 0L); ++ } ++ ++ @NotNull ++ @Override ++ protected Map delegate() { ++ return this.counts; ++ } ++} +diff --git a/src/main/java/co/aikar/util/JSONUtil.java b/src/main/java/co/aikar/util/JSONUtil.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c105a1429ca58b37be265708ec345e00f0d43ed8 +--- /dev/null ++++ b/src/main/java/co/aikar/util/JSONUtil.java +@@ -0,0 +1,141 @@ ++package co.aikar.util; ++ ++import com.google.common.base.Function; ++import com.google.common.collect.Lists; ++import com.google.common.collect.Maps; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++import org.json.simple.JSONArray; ++import org.json.simple.JSONObject; ++ ++import java.util.ArrayList; ++import java.util.LinkedHashMap; ++import java.util.List; ++import java.util.Map; ++ ++/** ++ * Provides Utility methods that assist with generating JSON Objects ++ */ ++@SuppressWarnings({"rawtypes", "SuppressionAnnotation"}) ++@Deprecated(forRemoval = true) ++public final class JSONUtil { ++ private JSONUtil() {} ++ ++ /** ++ * Creates a key/value "JSONPair" object ++ * ++ * @param key Key to use ++ * @param obj Value to use ++ * @return JSONPair ++ */ ++ @NotNull ++ public static JSONPair pair(@NotNull String key, @Nullable Object obj) { ++ return new JSONPair(key, obj); ++ } ++ ++ @NotNull ++ public static JSONPair pair(long key, @Nullable Object obj) { ++ return new JSONPair(String.valueOf(key), obj); ++ } ++ ++ /** ++ * Creates a new JSON object from multiple JSONPair key/value pairs ++ * ++ * @param data JSONPairs ++ * @return Map ++ */ ++ @NotNull ++ public static Map createObject(@NotNull JSONPair... data) { ++ return appendObjectData(new LinkedHashMap(), data); ++ } ++ ++ /** ++ * This appends multiple key/value Obj pairs into a JSON Object ++ * ++ * @param parent Map to be appended to ++ * @param data Data to append ++ * @return Map ++ */ ++ @NotNull ++ public static Map appendObjectData(@NotNull Map parent, @NotNull JSONPair... data) { ++ for (JSONPair JSONPair : data) { ++ parent.put(JSONPair.key, JSONPair.val); ++ } ++ return parent; ++ } ++ ++ /** ++ * This builds a JSON array from a set of data ++ * ++ * @param data Data to build JSON array from ++ * @return List ++ */ ++ @NotNull ++ public static List toArray(@NotNull Object... data) { ++ return Lists.newArrayList(data); ++ } ++ ++ /** ++ * These help build a single JSON array using a mapper function ++ * ++ * @param collection Collection to apply to ++ * @param mapper Mapper to apply ++ * @param Element Type ++ * @return List ++ */ ++ @NotNull ++ public static List toArrayMapper(@NotNull E[] collection, @NotNull Function mapper) { ++ return toArrayMapper(Lists.newArrayList(collection), mapper); ++ } ++ ++ @NotNull ++ public static List toArrayMapper(@NotNull Iterable collection, @NotNull Function mapper) { ++ List array = Lists.newArrayList(); ++ for (E e : collection) { ++ Object object = mapper.apply(e); ++ if (object != null) { ++ array.add(object); ++ } ++ } ++ return array; ++ } ++ ++ /** ++ * These help build a single JSON Object from a collection, using a mapper function ++ * ++ * @param collection Collection to apply to ++ * @param mapper Mapper to apply ++ * @param Element Type ++ * @return Map ++ */ ++ @NotNull ++ public static Map toObjectMapper(@NotNull E[] collection, @NotNull Function mapper) { ++ return toObjectMapper(Lists.newArrayList(collection), mapper); ++ } ++ ++ @NotNull ++ public static Map toObjectMapper(@NotNull Iterable collection, @NotNull Function mapper) { ++ Map object = Maps.newLinkedHashMap(); ++ for (E e : collection) { ++ JSONPair JSONPair = mapper.apply(e); ++ if (JSONPair != null) { ++ object.put(JSONPair.key, JSONPair.val); ++ } ++ } ++ return object; ++ } ++ ++ /** ++ * Simply stores a key and a value, used internally by many methods below. ++ */ ++ @SuppressWarnings("PublicInnerClass") ++ public static class JSONPair { ++ final String key; ++ final Object val; ++ ++ JSONPair(@NotNull String key, @NotNull Object val) { ++ this.key = key; ++ this.val = val; ++ } ++ } ++} +diff --git a/src/main/java/co/aikar/util/LoadingIntMap.java b/src/main/java/co/aikar/util/LoadingIntMap.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5753b9bce89db2ac378ec41f1b61907cc2e23335 +--- /dev/null ++++ b/src/main/java/co/aikar/util/LoadingIntMap.java +@@ -0,0 +1,77 @@ ++/* ++ * Copyright (c) 2015. Starlis LLC / dba Empire Minecraft ++ * ++ * This source code is proprietary software and must not be redistributed without Starlis LLC's approval ++ * ++ */ ++package co.aikar.util; ++ ++ ++import com.google.common.base.Function; ++import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Allows you to pass a Loader function that when a key is accessed that doesn't exist, ++ * automatically loads the entry into the map by calling the loader Function. ++ * ++ * .get() Will only return null if the Loader can return null. ++ * ++ * You may pass any backing Map to use. ++ * ++ * This class is not thread safe and should be wrapped with Collections.synchronizedMap on the OUTSIDE of the LoadingMap if needed. ++ * ++ * Do not wrap the backing map with Collections.synchronizedMap. ++ * ++ * @param Value ++ */ ++@Deprecated(forRemoval = true) ++public class LoadingIntMap extends Int2ObjectOpenHashMap { ++ private final Function loader; ++ ++ public LoadingIntMap(@NotNull Function loader) { ++ super(); ++ this.loader = loader; ++ } ++ ++ public LoadingIntMap(int expectedSize, @NotNull Function loader) { ++ super(expectedSize); ++ this.loader = loader; ++ } ++ ++ public LoadingIntMap(int expectedSize, float loadFactor, @NotNull Function loader) { ++ super(expectedSize, loadFactor); ++ this.loader = loader; ++ } ++ ++ ++ @Nullable ++ @Override ++ public V get(int key) { ++ V res = super.get(key); ++ if (res == null) { ++ res = loader.apply(key); ++ if (res != null) { ++ put(key, res); ++ } ++ } ++ return res; ++ } ++ ++ /** ++ * Due to java stuff, you will need to cast it to (Function) for some cases ++ * ++ * @param Type ++ */ ++ public abstract static class Feeder implements Function { ++ @Nullable ++ @Override ++ public T apply(@Nullable Object input) { ++ return apply(); ++ } ++ ++ @Nullable ++ public abstract T apply(); ++ } ++} +diff --git a/src/main/java/co/aikar/util/LoadingMap.java b/src/main/java/co/aikar/util/LoadingMap.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1786eeb5cbeaad75602c9c5649bbcd9b2af5cf81 +--- /dev/null ++++ b/src/main/java/co/aikar/util/LoadingMap.java +@@ -0,0 +1,369 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.util; ++ ++import com.google.common.base.Preconditions; ++import java.lang.reflect.Constructor; ++import java.util.AbstractMap; ++import java.util.Collection; ++import java.util.HashMap; ++import java.util.IdentityHashMap; ++import java.util.Map; ++import java.util.Set; ++import java.util.function.Function; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Allows you to pass a Loader function that when a key is accessed that doesn't exists, ++ * automatically loads the entry into the map by calling the loader Function. ++ * ++ * .get() Will only return null if the Loader can return null. ++ * ++ * You may pass any backing Map to use. ++ * ++ * This class is not thread safe and should be wrapped with Collections.synchronizedMap on the OUTSIDE of the LoadingMap if needed. ++ * ++ * Do not wrap the backing map with Collections.synchronizedMap. ++ * ++ * @param Key ++ * @param Value ++ */ ++@Deprecated(forRemoval = true) ++public class LoadingMap extends AbstractMap { ++ private final Map backingMap; ++ private final java.util.function.Function loader; ++ ++ /** ++ * Initializes an auto loading map using specified loader and backing map ++ * @param backingMap Map to wrap ++ * @param loader Loader ++ */ ++ public LoadingMap(@NotNull Map backingMap, @NotNull java.util.function.Function loader) { ++ this.backingMap = backingMap; ++ this.loader = loader; ++ } ++ ++ /** ++ * Creates a new LoadingMap with the specified map and loader ++ * ++ * @param backingMap Actual map being used. ++ * @param loader Loader to use ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map ++ */ ++ @NotNull ++ public static Map of(@NotNull Map backingMap, @NotNull Function loader) { ++ return new LoadingMap<>(backingMap, loader); ++ } ++ ++ /** ++ * Creates a LoadingMap with an auto instantiating loader. ++ * ++ * Will auto construct class of of Value when not found ++ * ++ * Since this uses Reflection, It is more effecient to define your own static loader ++ * than using this helper, but if performance is not critical, this is easier. ++ * ++ * @param backingMap Actual map being used. ++ * @param keyClass Class used for the K generic ++ * @param valueClass Class used for the V generic ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map that auto instantiates on .get() ++ */ ++ @NotNull ++ public static Map newAutoMap(@NotNull Map backingMap, @Nullable final Class keyClass, ++ @NotNull final Class valueClass) { ++ return new LoadingMap<>(backingMap, new AutoInstantiatingLoader<>(keyClass, valueClass)); ++ } ++ /** ++ * Creates a LoadingMap with an auto instantiating loader. ++ * ++ * Will auto construct class of of Value when not found ++ * ++ * Since this uses Reflection, It is more effecient to define your own static loader ++ * than using this helper, but if performance is not critical, this is easier. ++ * ++ * @param backingMap Actual map being used. ++ * @param valueClass Class used for the V generic ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map that auto instantiates on .get() ++ */ ++ @NotNull ++ public static Map newAutoMap(@NotNull Map backingMap, ++ @NotNull final Class valueClass) { ++ return newAutoMap(backingMap, null, valueClass); ++ } ++ ++ /** ++ * @see #newAutoMap ++ * ++ * new Auto initializing map using a HashMap. ++ * ++ * @param keyClass Class used for the K generic ++ * @param valueClass Class used for the V generic ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map that auto instantiates on .get() ++ */ ++ @NotNull ++ public static Map newHashAutoMap(@Nullable final Class keyClass, @NotNull final Class valueClass) { ++ return newAutoMap(new HashMap<>(), keyClass, valueClass); ++ } ++ ++ /** ++ * @see #newAutoMap ++ * ++ * new Auto initializing map using a HashMap. ++ * ++ * @param valueClass Class used for the V generic ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map that auto instantiates on .get() ++ */ ++ @NotNull ++ public static Map newHashAutoMap(@NotNull final Class valueClass) { ++ return newHashAutoMap(null, valueClass); ++ } ++ ++ /** ++ * @see #newAutoMap ++ * ++ * new Auto initializing map using a HashMap. ++ * ++ * @param keyClass Class used for the K generic ++ * @param valueClass Class used for the V generic ++ * @param initialCapacity Initial capacity to use ++ * @param loadFactor Load factor to use ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map that auto instantiates on .get() ++ */ ++ @NotNull ++ public static Map newHashAutoMap(@Nullable final Class keyClass, @NotNull final Class valueClass, int initialCapacity, float loadFactor) { ++ return newAutoMap(new HashMap<>(initialCapacity, loadFactor), keyClass, valueClass); ++ } ++ ++ /** ++ * @see #newAutoMap ++ * ++ * new Auto initializing map using a HashMap. ++ * ++ * @param valueClass Class used for the V generic ++ * @param initialCapacity Initial capacity to use ++ * @param loadFactor Load factor to use ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map that auto instantiates on .get() ++ */ ++ @NotNull ++ public static Map newHashAutoMap(@NotNull final Class valueClass, int initialCapacity, float loadFactor) { ++ return newHashAutoMap(null, valueClass, initialCapacity, loadFactor); ++ } ++ ++ /** ++ * Initializes an auto loading map using a HashMap ++ * ++ * @param loader Loader to use ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map ++ */ ++ @NotNull ++ public static Map newHashMap(@NotNull Function loader) { ++ return new LoadingMap<>(new HashMap<>(), loader); ++ } ++ ++ /** ++ * Initializes an auto loading map using a HashMap ++ * ++ * @param loader Loader to use ++ * @param initialCapacity Initial capacity to use ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map ++ */ ++ @NotNull ++ public static Map newHashMap(@NotNull Function loader, int initialCapacity) { ++ return new LoadingMap<>(new HashMap<>(initialCapacity), loader); ++ } ++ /** ++ * Initializes an auto loading map using a HashMap ++ * ++ * @param loader Loader to use ++ * @param initialCapacity Initial capacity to use ++ * @param loadFactor Load factor to use ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map ++ */ ++ @NotNull ++ public static Map newHashMap(@NotNull Function loader, int initialCapacity, float loadFactor) { ++ return new LoadingMap<>(new HashMap<>(initialCapacity, loadFactor), loader); ++ } ++ ++ /** ++ * Initializes an auto loading map using an Identity HashMap ++ * ++ * @param loader Loader to use ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map ++ */ ++ @NotNull ++ public static Map newIdentityHashMap(@NotNull Function loader) { ++ return new LoadingMap<>(new IdentityHashMap<>(), loader); ++ } ++ ++ /** ++ * Initializes an auto loading map using an Identity HashMap ++ * ++ * @param loader Loader to use ++ * @param initialCapacity Initial capacity to use ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map ++ */ ++ @NotNull ++ public static Map newIdentityHashMap(@NotNull Function loader, int initialCapacity) { ++ return new LoadingMap<>(new IdentityHashMap<>(initialCapacity), loader); ++ } ++ ++ @Override ++ public int size() {return backingMap.size();} ++ ++ @Override ++ public boolean isEmpty() {return backingMap.isEmpty();} ++ ++ @Override ++ public boolean containsKey(@Nullable Object key) {return backingMap.containsKey(key);} ++ ++ @Override ++ public boolean containsValue(@Nullable Object value) {return backingMap.containsValue(value);} ++ ++ @Nullable ++ @Override ++ public V get(@Nullable Object key) { ++ V v = backingMap.get(key); ++ if (v != null) { ++ return v; ++ } ++ return backingMap.computeIfAbsent((K) key, loader); ++ } ++ ++ @Nullable ++ public V put(@Nullable K key, @Nullable V value) {return backingMap.put(key, value);} ++ ++ @Nullable ++ @Override ++ public V remove(@Nullable Object key) {return backingMap.remove(key);} ++ ++ public void putAll(@NotNull Map m) {backingMap.putAll(m);} ++ ++ @Override ++ public void clear() {backingMap.clear();} ++ ++ @NotNull ++ @Override ++ public Set keySet() {return backingMap.keySet();} ++ ++ @NotNull ++ @Override ++ public Collection values() {return backingMap.values();} ++ ++ @Override ++ public boolean equals(@Nullable Object o) {return backingMap.equals(o);} ++ ++ @Override ++ public int hashCode() {return backingMap.hashCode();} ++ ++ @NotNull ++ @Override ++ public Set> entrySet() { ++ return backingMap.entrySet(); ++ } ++ ++ @NotNull ++ public LoadingMap clone() { ++ return new LoadingMap<>(backingMap, loader); ++ } ++ ++ private static class AutoInstantiatingLoader implements Function { ++ final Constructor constructor; ++ private final Class valueClass; ++ ++ AutoInstantiatingLoader(@Nullable Class keyClass, @NotNull Class valueClass) { ++ try { ++ this.valueClass = valueClass; ++ if (keyClass != null) { ++ constructor = valueClass.getConstructor(keyClass); ++ } else { ++ constructor = null; ++ } ++ } catch (NoSuchMethodException e) { ++ throw new IllegalStateException( ++ valueClass.getName() + " does not have a constructor for " + (keyClass != null ? keyClass.getName() : null)); ++ } ++ } ++ ++ @NotNull ++ @Override ++ public V apply(@Nullable K input) { ++ try { ++ return (constructor != null ? constructor.newInstance(input) : valueClass.newInstance()); ++ } catch (Exception e) { ++ throw new ExceptionInInitializerError(e); ++ } ++ } ++ ++ @Override ++ public int hashCode() { ++ return super.hashCode(); ++ } ++ ++ @Override ++ public boolean equals(Object object) { ++ return false; ++ } ++ } ++ ++ /** ++ * Due to java stuff, you will need to cast it to (Function) for some cases ++ * ++ * @param Type ++ */ ++ public abstract static class Feeder implements Function { ++ @Nullable ++ @Override ++ public T apply(@Nullable Object input) { ++ return apply(); ++ } ++ ++ @Nullable ++ public abstract T apply(); ++ } ++} +diff --git a/src/main/java/co/aikar/util/MRUMapCache.java b/src/main/java/co/aikar/util/MRUMapCache.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3e61a926620a67daec3af54b72a1b911eaef2ed4 +--- /dev/null ++++ b/src/main/java/co/aikar/util/MRUMapCache.java +@@ -0,0 +1,112 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.util; ++ ++import java.util.AbstractMap; ++import java.util.Collection; ++import java.util.Map; ++import java.util.Set; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Implements a Most Recently Used cache in front of a backing map, to quickly access the last accessed result. ++ * ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ */ ++@Deprecated(forRemoval = true) ++public class MRUMapCache extends AbstractMap { ++ final Map backingMap; ++ Object cacheKey; ++ V cacheValue; ++ public MRUMapCache(@NotNull final Map backingMap) { ++ this.backingMap = backingMap; ++ } ++ ++ public int size() {return backingMap.size();} ++ ++ public boolean isEmpty() {return backingMap.isEmpty();} ++ ++ public boolean containsKey(@Nullable Object key) { ++ return key != null && key.equals(cacheKey) || backingMap.containsKey(key); ++ } ++ ++ public boolean containsValue(@Nullable Object value) { ++ return value != null && value == cacheValue || backingMap.containsValue(value); ++ } ++ ++ @Nullable ++ public V get(@Nullable Object key) { ++ if (cacheKey != null && cacheKey.equals(key)) { ++ return cacheValue; ++ } ++ cacheKey = key; ++ return cacheValue = backingMap.get(key); ++ } ++ ++ @Nullable ++ public V put(@Nullable K key, @Nullable V value) { ++ cacheKey = key; ++ return cacheValue = backingMap.put(key, value); ++ } ++ ++ @Nullable ++ public V remove(@Nullable Object key) { ++ if (key != null && key.equals(cacheKey)) { ++ cacheKey = null; ++ } ++ return backingMap.remove(key); ++ } ++ ++ public void putAll(@NotNull Map m) {backingMap.putAll(m);} ++ ++ public void clear() { ++ cacheKey = null; ++ cacheValue = null; ++ backingMap.clear(); ++ } ++ ++ @NotNull ++ public Set keySet() {return backingMap.keySet();} ++ ++ @NotNull ++ public Collection values() {return backingMap.values();} ++ ++ @NotNull ++ public Set> entrySet() {return backingMap.entrySet();} ++ ++ /** ++ * Wraps the specified map with a most recently used cache ++ * ++ * @param map Map to be wrapped ++ * @param Key Type of the Map ++ * @param Value Type of the Map ++ * @return Map ++ */ ++ @NotNull ++ public static Map of(@NotNull Map map) { ++ return new MRUMapCache(map); ++ } ++} +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 6391011464ac0c95d4da7fb9c698f35c58b40922..a327c71f110fc0330a3a43ab118565d35801eb32 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -870,7 +870,6 @@ public final class Bukkit { + */ + public static void reload() { + server.reload(); +- org.spigotmc.CustomTimingsHandler.reload(); // Spigot + } + + /** +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 01f8e0811f8b337acac31819a85bb44b189b3c21..a1bffe44764fc3e1bb96bf014c56025b0bde7507 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1978,6 +1978,26 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + throw new UnsupportedOperationException("Not supported yet."); + } + ++ // Paper start ++ @NotNull ++ public org.bukkit.configuration.file.YamlConfiguration getBukkitConfig() ++ { ++ throw new UnsupportedOperationException( "Not supported yet." ); ++ } ++ ++ @NotNull ++ public org.bukkit.configuration.file.YamlConfiguration getSpigotConfig() ++ { ++ throw new UnsupportedOperationException("Not supported yet."); ++ } ++ ++ @NotNull ++ public org.bukkit.configuration.file.YamlConfiguration getPaperConfig() ++ { ++ throw new UnsupportedOperationException("Not supported yet."); ++ } ++ // Paper end ++ + /** + * Sends the component to the player + * +diff --git a/src/main/java/org/bukkit/command/BufferedCommandSender.java b/src/main/java/org/bukkit/command/BufferedCommandSender.java +new file mode 100644 +index 0000000000000000000000000000000000000000..45ed63797b13e114bf3795c80a6c3967d8eb2351 +--- /dev/null ++++ b/src/main/java/org/bukkit/command/BufferedCommandSender.java +@@ -0,0 +1,25 @@ ++package org.bukkit.command; ++ ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++public class BufferedCommandSender implements MessageCommandSender { ++ private final StringBuffer buffer = new StringBuffer(); ++ @Override ++ public void sendMessage(@NotNull String message) { ++ buffer.append(message); ++ buffer.append("\n"); ++ } ++ ++ @NotNull ++ public String getBuffer() { ++ return buffer.toString(); ++ } ++ ++ public void reset() { ++ this.buffer.setLength(0); ++ } ++} +diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java +index 6686d025222dc50156347a1757c88da02f882eec..cee16db367907cfa4b432dc6969f403321a855ea 100644 +--- a/src/main/java/org/bukkit/command/Command.java ++++ b/src/main/java/org/bukkit/command/Command.java +@@ -33,7 +33,16 @@ public abstract class Command { + protected String usageMessage; + private String permission; + private net.kyori.adventure.text.Component permissionMessage; // Paper +- public org.spigotmc.CustomTimingsHandler timings; // Spigot ++ /** ++ * @deprecated Timings will be removed in the future ++ */ ++ @Deprecated(forRemoval = true) ++ public co.aikar.timings.Timing timings; // Paper ++ /** ++ * @deprecated Timings will be removed in the future ++ */ ++ @Deprecated(forRemoval = true) ++ @NotNull public String getTimingName() {return getName();} // Paper + + protected Command(@NotNull String name) { + this(name, "", "/" + name, new ArrayList()); +@@ -47,7 +56,6 @@ public abstract class Command { + this.usageMessage = (usageMessage == null) ? "/" + name : usageMessage; + this.aliases = aliases; + this.activeAliases = new ArrayList(aliases); +- this.timings = new org.spigotmc.CustomTimingsHandler("** Command: " + name); // Spigot + } + + /** +@@ -245,7 +253,6 @@ public abstract class Command { + } + this.nextLabel = name; + if (!isRegistered()) { +- this.timings = new org.spigotmc.CustomTimingsHandler("** Command: " + name); // Spigot + this.label = name; + return true; + } +diff --git a/src/main/java/org/bukkit/command/FormattedCommandAlias.java b/src/main/java/org/bukkit/command/FormattedCommandAlias.java +index d6c8938b1e13b63116b7b0e074ea8ef5997f8dc3..a6ad94ef98a1df1d2842635d850bc990b0137849 100644 +--- a/src/main/java/org/bukkit/command/FormattedCommandAlias.java ++++ b/src/main/java/org/bukkit/command/FormattedCommandAlias.java +@@ -9,6 +9,7 @@ public class FormattedCommandAlias extends Command { + + public FormattedCommandAlias(@NotNull String alias, @NotNull String[] formatStrings) { + super(alias); ++ timings = co.aikar.timings.TimingsManager.getCommandTiming("minecraft", this); // Spigot + this.formatStrings = formatStrings; + } + +@@ -113,6 +114,10 @@ public class FormattedCommandAlias extends Command { + return formatString; + } + ++ @NotNull ++ @Override // Paper ++ public String getTimingName() {return "Command Forwarder - " + super.getTimingName();} // Paper ++ + private static boolean inRange(int i, int j, int k) { + return i >= j && i <= k; + } +diff --git a/src/main/java/org/bukkit/command/MessageCommandSender.java b/src/main/java/org/bukkit/command/MessageCommandSender.java +new file mode 100644 +index 0000000000000000000000000000000000000000..946d2f0ef37c6cf895caf8d3c6963c7889e0567b +--- /dev/null ++++ b/src/main/java/org/bukkit/command/MessageCommandSender.java +@@ -0,0 +1,138 @@ ++package org.bukkit.command; ++ ++import org.bukkit.Bukkit; ++import org.bukkit.Server; ++import org.bukkit.permissions.Permission; ++import org.bukkit.permissions.PermissionAttachment; ++import org.bukkit.permissions.PermissionAttachmentInfo; ++import org.bukkit.plugin.Plugin; ++ ++import java.util.Set; ++import java.util.UUID; ++ ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * For when all you care about is just messaging ++ * ++ * @deprecated Timings will be removed in the future ++ */ ++@Deprecated(forRemoval = true) ++public interface MessageCommandSender extends CommandSender { ++ ++ @Override ++ default void sendMessage(@NotNull String[] messages) { ++ for (String message : messages) { ++ sendMessage(message); ++ } ++ } ++ ++ @Override ++ default void sendMessage(@Nullable UUID sender, @NotNull String message) { ++ sendMessage(message); ++ } ++ ++ @Override ++ default void sendMessage(@Nullable UUID sender, @NotNull String[] messages) { ++ for (String message : messages) { ++ sendMessage(message); ++ } ++ } ++ ++ @NotNull ++ @Override ++ default Server getServer() { ++ return Bukkit.getServer(); ++ } ++ ++ // Paper start ++ @Override ++ default net.kyori.adventure.text.@org.jetbrains.annotations.NotNull Component name() { ++ throw new UnsupportedOperationException(); ++ } ++ // Paper end ++ ++ @NotNull ++ @Override ++ default String getName() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ default boolean isOp() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ default void setOp(boolean value) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ default boolean isPermissionSet(@NotNull String name) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ default boolean isPermissionSet(@NotNull Permission perm) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ default boolean hasPermission(@NotNull String name) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ default boolean hasPermission(@NotNull Permission perm) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @NotNull ++ @Override ++ default PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @NotNull ++ @Override ++ default PermissionAttachment addAttachment(@NotNull Plugin plugin) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @NotNull ++ @Override ++ default PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value, int ticks) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @NotNull ++ @Override ++ default PermissionAttachment addAttachment(@NotNull Plugin plugin, int ticks) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ default void removeAttachment(@NotNull PermissionAttachment attachment) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ default void recalculatePermissions() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @NotNull ++ @Override ++ default Set getEffectivePermissions() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @NotNull ++ @Override ++ default Spigot spigot() { ++ throw new UnsupportedOperationException(); ++ } ++ ++} +diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java +index 9207ae900cb4cc8ce41dd4e63d7ad8b35b0ac048..36fc2c35395c72f8b81a2a2f3265fd205384ce26 100644 +--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java ++++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java +@@ -16,7 +16,6 @@ import org.bukkit.command.defaults.BukkitCommand; + import org.bukkit.command.defaults.HelpCommand; + import org.bukkit.command.defaults.PluginsCommand; + import org.bukkit.command.defaults.ReloadCommand; +-import org.bukkit.command.defaults.TimingsCommand; + import org.bukkit.command.defaults.VersionCommand; + import org.bukkit.entity.Player; + import org.bukkit.util.StringUtil; +@@ -36,7 +35,7 @@ public class SimpleCommandMap implements CommandMap { + register("bukkit", new VersionCommand("version")); + register("bukkit", new ReloadCommand("reload")); + //register("bukkit", new PluginsCommand("plugins")); // Paper +- register("bukkit", new TimingsCommand("timings")); ++ register("bukkit", new co.aikar.timings.TimingsCommand("timings")); // Paper + } + + public void setFallbackCommands() { +@@ -68,6 +67,7 @@ public class SimpleCommandMap implements CommandMap { + */ + @Override + public boolean register(@NotNull String label, @NotNull String fallbackPrefix, @NotNull Command command) { ++ command.timings = co.aikar.timings.TimingsManager.getCommandTiming(fallbackPrefix, command); // Paper + label = label.toLowerCase(Locale.ROOT).trim(); + fallbackPrefix = fallbackPrefix.toLowerCase(Locale.ROOT).trim(); + boolean registered = register(label, command, false, fallbackPrefix); +@@ -144,16 +144,22 @@ public class SimpleCommandMap implements CommandMap { + return false; + } + ++ // Paper start - Plugins do weird things to workaround normal registration ++ if (target.timings == null) { ++ target.timings = co.aikar.timings.TimingsManager.getCommandTiming(null, target); ++ } ++ // Paper end ++ + try { +- target.timings.startTiming(); // Spigot ++ try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources + // Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false) + target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length)); +- target.timings.stopTiming(); // Spigot ++ } // target.timings.stopTiming(); // Spigot // Paper + } catch (CommandException ex) { +- target.timings.stopTiming(); // Spigot ++ //target.timings.stopTiming(); // Spigot // Paper + throw ex; + } catch (Throwable ex) { +- target.timings.stopTiming(); // Spigot ++ //target.timings.stopTiming(); // Spigot // Paper + throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex); + } + +diff --git a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java +deleted file mode 100644 +index 516d7fc7812aac343782861d0d567f54aa578c2a..0000000000000000000000000000000000000000 +--- a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java ++++ /dev/null +@@ -1,250 +0,0 @@ +-package org.bukkit.command.defaults; +- +-import com.google.common.base.Preconditions; +-import com.google.common.collect.ImmutableList; +-import java.io.File; +-import java.io.IOException; +-import java.io.PrintStream; +-import java.util.ArrayList; +-import java.util.List; +-import org.bukkit.Bukkit; +-import org.bukkit.ChatColor; +-import org.bukkit.command.CommandSender; +-import org.bukkit.event.Event; +-import org.bukkit.event.HandlerList; +-import org.bukkit.plugin.Plugin; +-import org.bukkit.plugin.RegisteredListener; +-import org.bukkit.plugin.TimedRegisteredListener; +-import org.bukkit.util.StringUtil; +-import org.jetbrains.annotations.NotNull; +- +-// Spigot start +-// CHECKSTYLE:OFF +-import java.io.ByteArrayOutputStream; +-import java.io.OutputStream; +-import java.net.HttpURLConnection; +-import java.net.URL; +-import java.util.logging.Level; +-import org.bukkit.command.RemoteConsoleCommandSender; +-import org.bukkit.plugin.SimplePluginManager; +-import org.spigotmc.CustomTimingsHandler; +-// CHECKSTYLE:ON +-// Spigot end +- +-public class TimingsCommand extends BukkitCommand { +- private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("report", "reset", "on", "off", "paste"); // Spigot +- public static long timingStart = 0; // Spigot +- +- public TimingsCommand(@NotNull String name) { +- super(name); +- this.description = "Manages Spigot Timings data to see performance of the server."; // Spigot +- this.usageMessage = "/timings "; // Spigot +- this.setPermission("bukkit.command.timings"); +- } +- +- // Spigot start - redesigned Timings Command +- public void executeSpigotTimings(@NotNull CommandSender sender, @NotNull String[] args) { +- if ("on".equals(args[0])) { +- ((SimplePluginManager) Bukkit.getPluginManager()).useTimings(true); +- CustomTimingsHandler.reload(); +- sender.sendMessage("Enabled Timings & Reset"); +- return; +- } else if ("off".equals(args[0])) { +- ((SimplePluginManager) Bukkit.getPluginManager()).useTimings(false); +- sender.sendMessage("Disabled Timings"); +- return; +- } +- +- if (!Bukkit.getPluginManager().useTimings()) { +- sender.sendMessage("Please enable timings by typing /timings on"); +- return; +- } +- +- boolean paste = "paste".equals(args[0]); +- if ("reset".equals(args[0])) { +- CustomTimingsHandler.reload(); +- sender.sendMessage("Timings reset"); +- } else if ("merged".equals(args[0]) || "report".equals(args[0]) || paste) { +- long sampleTime = System.nanoTime() - timingStart; +- int index = 0; +- File timingFolder = new File("timings"); +- timingFolder.mkdirs(); +- File timings = new File(timingFolder, "timings.txt"); +- ByteArrayOutputStream bout = (paste) ? new ByteArrayOutputStream() : null; +- while (timings.exists()) timings = new File(timingFolder, "timings" + (++index) + ".txt"); +- PrintStream fileTimings = null; +- try { +- fileTimings = (paste) ? new PrintStream(bout) : new PrintStream(timings); +- +- CustomTimingsHandler.printTimings(fileTimings); +- fileTimings.println("Sample time " + sampleTime + " (" + sampleTime / 1E9 + "s)"); +- +- fileTimings.println(""); +- fileTimings.println(Bukkit.spigot().getConfig().saveToString()); +- fileTimings.println(""); +- +- if (paste) { +- new PasteThread(sender, bout).start(); +- return; +- } +- +- sender.sendMessage("Timings written to " + timings.getPath()); +- sender.sendMessage("Paste contents of file into form at http://www.spigotmc.org/go/timings to read results."); +- +- } catch (IOException e) { +- } finally { +- if (fileTimings != null) { +- fileTimings.close(); +- } +- } +- } +- } +- // Spigot end +- +- @Override +- public boolean execute(@NotNull CommandSender sender, @NotNull String currentAlias, @NotNull String[] args) { +- if (!testPermission(sender)) return true; +- if (args.length < 1) { // Spigot +- sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); +- return false; +- } +- // Spigot start +- if (true) { +- executeSpigotTimings(sender, args); +- return true; +- } +- // Spigot end +- if (!sender.getServer().getPluginManager().useTimings()) { +- sender.sendMessage("Please enable timings by setting \"settings.plugin-profiling\" to true in bukkit.yml"); +- return true; +- } +- +- boolean separate = "separate".equalsIgnoreCase(args[0]); +- if ("reset".equalsIgnoreCase(args[0])) { +- for (HandlerList handlerList : HandlerList.getHandlerLists()) { +- for (RegisteredListener listener : handlerList.getRegisteredListeners()) { +- if (listener instanceof TimedRegisteredListener) { +- ((TimedRegisteredListener) listener).reset(); +- } +- } +- } +- sender.sendMessage("Timings reset"); +- } else if ("merged".equalsIgnoreCase(args[0]) || separate) { +- +- int index = 0; +- int pluginIdx = 0; +- File timingFolder = new File("timings"); +- timingFolder.mkdirs(); +- File timings = new File(timingFolder, "timings.txt"); +- File names = null; +- while (timings.exists()) timings = new File(timingFolder, "timings" + (++index) + ".txt"); +- PrintStream fileTimings = null; +- PrintStream fileNames = null; +- try { +- fileTimings = new PrintStream(timings); +- if (separate) { +- names = new File(timingFolder, "names" + index + ".txt"); +- fileNames = new PrintStream(names); +- } +- for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { +- pluginIdx++; +- long totalTime = 0; +- if (separate) { +- fileNames.println(pluginIdx + " " + plugin.getDescription().getFullName()); +- fileTimings.println("Plugin " + pluginIdx); +- } else { +- fileTimings.println(plugin.getDescription().getFullName()); +- } +- for (RegisteredListener listener : HandlerList.getRegisteredListeners(plugin)) { +- if (listener instanceof TimedRegisteredListener) { +- TimedRegisteredListener trl = (TimedRegisteredListener) listener; +- long time = trl.getTotalTime(); +- int count = trl.getCount(); +- if (count == 0) continue; +- long avg = time / count; +- totalTime += time; +- Class eventClass = trl.getEventClass(); +- if (count > 0 && eventClass != null) { +- fileTimings.println(" " + eventClass.getSimpleName() + (trl.hasMultiple() ? " (and sub-classes)" : "") + " Time: " + time + " Count: " + count + " Avg: " + avg); +- } +- } +- } +- fileTimings.println(" Total time " + totalTime + " (" + totalTime / 1000000000 + "s)"); +- } +- sender.sendMessage("Timings written to " + timings.getPath()); +- if (separate) sender.sendMessage("Names written to " + names.getPath()); +- } catch (IOException e) { +- } finally { +- if (fileTimings != null) { +- fileTimings.close(); +- } +- if (fileNames != null) { +- fileNames.close(); +- } +- } +- } else { +- sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); +- return false; +- } +- return true; +- } +- +- @NotNull +- @Override +- public List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { +- Preconditions.checkArgument(sender != null, "Sender cannot be null"); +- Preconditions.checkArgument(args != null, "Arguments cannot be null"); +- Preconditions.checkArgument(alias != null, "Alias cannot be null"); +- +- if (args.length == 1) { +- return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS, new ArrayList(TIMINGS_SUBCOMMANDS.size())); +- } +- return ImmutableList.of(); +- } +- +- // Spigot start +- private static class PasteThread extends Thread { +- +- private final CommandSender sender; +- private final ByteArrayOutputStream bout; +- +- public PasteThread(@NotNull CommandSender sender, @NotNull ByteArrayOutputStream bout) { +- super("Timings paste thread"); +- this.sender = sender; +- this.bout = bout; +- } +- +- @Override +- public synchronized void start() { +- if (sender instanceof RemoteConsoleCommandSender) { +- run(); +- } else { +- super.start(); +- } +- } +- +- @Override +- public void run() { +- try { +- HttpURLConnection con = (HttpURLConnection) new URL("https://timings.spigotmc.org/paste").openConnection(); +- con.setDoOutput(true); +- con.setRequestMethod("POST"); +- con.setInstanceFollowRedirects(false); +- +- OutputStream out = con.getOutputStream(); +- out.write(bout.toByteArray()); +- out.close(); +- +- com.google.gson.JsonObject location = new com.google.gson.Gson().fromJson(new java.io.InputStreamReader(con.getInputStream()), com.google.gson.JsonObject.class); +- con.getInputStream().close(); +- +- String pasteID = location.get("key").getAsString(); +- sender.sendMessage(ChatColor.GREEN + "Timings results can be viewed at https://www.spigotmc.org/go/timings?url=" + pasteID); +- } catch (IOException ex) { +- sender.sendMessage(ChatColor.RED + "Error pasting timings, check your console for more information"); +- Bukkit.getServer().getLogger().log(Level.WARNING, "Could not paste timings", ex); +- } +- } +- } +- // Spigot end +-} +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 64d32c377d0303ed28011a5f002274de3c16b383..a06daeeee71a5ca58fbc1e13453d9116eadbcac2 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -2771,7 +2771,19 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + @Deprecated // Paper + public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @Nullable java.util.UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { + throw new UnsupportedOperationException("Not supported yet."); ++ ++ } ++ ++ // Paper start ++ /** ++ * @return the player's ping ++ * @deprecated use {@link Player#getPing()} ++ */ ++ @Deprecated ++ public int getPing() { ++ throw new UnsupportedOperationException( "Not supported yet." ); + } ++ // Paper end + } + + @NotNull +diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +index d6f3c8da8bae1f70e0f9bee3e688a04801a3b546..b03f3e0ce9fdb0bb587cf1a1c10b8cfaa2eab09e 100644 +--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java ++++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +@@ -381,7 +381,6 @@ public final class SimplePluginManager implements PluginManager { + } + } + +- org.bukkit.command.defaults.TimingsCommand.timingStart = System.nanoTime(); // Spigot + return result.toArray(new Plugin[result.size()]); + } + +@@ -429,9 +428,9 @@ public final class SimplePluginManager implements PluginManager { + + if (result != null) { + plugins.add(result); +- lookupNames.put(result.getDescription().getName(), result); ++ lookupNames.put(result.getDescription().getName().toLowerCase(java.util.Locale.ENGLISH), result); // Paper + for (String provided : result.getDescription().getProvides()) { +- lookupNames.putIfAbsent(provided, result); ++ lookupNames.putIfAbsent(provided.toLowerCase(java.util.Locale.ENGLISH), result); // Paper + } + } + +@@ -461,7 +460,7 @@ public final class SimplePluginManager implements PluginManager { + @Nullable + public synchronized Plugin getPlugin(@NotNull String name) { + if (true) {return this.paperPluginManager.getPlugin(name);} // Paper +- return lookupNames.get(name.replace(' ', '_')); ++ return lookupNames.get(name.replace(' ', '_').toLowerCase(java.util.Locale.ENGLISH)); // Paper + } + + @Override +@@ -689,7 +688,8 @@ public final class SimplePluginManager implements PluginManager { + throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled"); + } + +- if (useTimings) { ++ executor = new co.aikar.timings.TimedEventExecutor(executor, plugin, null, event); // Paper ++ if (false) { // Spigot - RL handles useTimings check now // Paper + getEventListeners(event).register(new TimedRegisteredListener(listener, executor, priority, plugin, ignoreCancelled)); + } else { + getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled)); +@@ -924,7 +924,7 @@ public final class SimplePluginManager implements PluginManager { + @Override + public boolean useTimings() { + if (true) {return this.paperPluginManager.useTimings();} // Paper +- return useTimings; ++ return co.aikar.timings.Timings.isTimingsEnabled(); // Spigot + } + + /** +@@ -932,8 +932,9 @@ public final class SimplePluginManager implements PluginManager { + * + * @param use True if per event timing code should be used + */ ++ @Deprecated(forRemoval = true) + public void useTimings(boolean use) { +- useTimings = use; ++ co.aikar.timings.Timings.setTimingsEnabled(use); // Paper + } + + // Paper start +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +index 70ac93d420d0a8528428a3d038a2ef6a86d2fddd..2e4a0a66151b358cc89d8eea26002f9fda16ee48 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +@@ -55,7 +55,6 @@ public final class JavaPluginLoader implements PluginLoader { + private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")}; + private final List loaders = new CopyOnWriteArrayList(); + private final LibraryLoader libraryLoader; +- public static final CustomTimingsHandler pluginParentTimer = new CustomTimingsHandler("** Plugins"); // Spigot + + /** + * This class was not meant to be constructed explicitly +@@ -294,27 +293,21 @@ public final class JavaPluginLoader implements PluginLoader { + } + } + +- final CustomTimingsHandler timings = new CustomTimingsHandler("Plugin: " + plugin.getDescription().getFullName() + " Event: " + listener.getClass().getName() + "::" + method.getName() + "(" + eventClass.getSimpleName() + ")", pluginParentTimer); // Spigot +- EventExecutor executor = new EventExecutor() { ++ EventExecutor executor = new co.aikar.timings.TimedEventExecutor(new EventExecutor() { // Paper + @Override +- public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { ++ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { // Paper + try { + if (!eventClass.isAssignableFrom(event.getClass())) { + return; + } +- // Spigot start +- boolean isAsync = event.isAsynchronous(); +- if (!isAsync) timings.startTiming(); + method.invoke(listener, event); +- if (!isAsync) timings.stopTiming(); +- // Spigot end + } catch (InvocationTargetException ex) { + throw new EventException(ex.getCause()); + } catch (Throwable t) { + throw new EventException(t); + } + } +- }; ++ }, plugin, method, eventClass); // Paper + if (false) { // Spigot - RL handles useTimings check now + eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); + } else { +diff --git a/src/main/java/org/bukkit/util/CachedServerIcon.java b/src/main/java/org/bukkit/util/CachedServerIcon.java +index 5ca863b3692b2e1b58e7fb4d82f554a92cc4f01e..612958a331575d1da2715531ebdf6b1168f2e860 100644 +--- a/src/main/java/org/bukkit/util/CachedServerIcon.java ++++ b/src/main/java/org/bukkit/util/CachedServerIcon.java +@@ -2,6 +2,7 @@ package org.bukkit.util; + + import org.bukkit.Server; + import org.bukkit.event.server.ServerListPingEvent; ++import org.jetbrains.annotations.Nullable; + + /** + * This is a cached version of a server-icon. It's internal representation +@@ -12,4 +13,9 @@ import org.bukkit.event.server.ServerListPingEvent; + * @see Server#loadServerIcon(java.io.File) + * @see ServerListPingEvent#setServerIcon(CachedServerIcon) + */ +-public interface CachedServerIcon {} ++public interface CachedServerIcon { ++ ++ @Nullable ++ public String getData(); // Paper ++ ++} +diff --git a/src/main/java/org/spigotmc/CustomTimingsHandler.java b/src/main/java/org/spigotmc/CustomTimingsHandler.java +index 44badfedcc3fdc26bdc293b85d8c781d6f659faa..12946bd55fcf7c40d39081779a7fa30049ee6165 100644 +--- a/src/main/java/org/spigotmc/CustomTimingsHandler.java ++++ b/src/main/java/org/spigotmc/CustomTimingsHandler.java +@@ -1,137 +1,67 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ + package org.spigotmc; + +-import java.io.PrintStream; +-import java.util.Queue; +-import java.util.concurrent.ConcurrentLinkedQueue; + import org.bukkit.Bukkit; +-import org.bukkit.World; +-import org.bukkit.command.defaults.TimingsCommand; + import org.jetbrains.annotations.NotNull; +-import org.jetbrains.annotations.Nullable; ++import org.bukkit.plugin.AuthorNagException; ++import co.aikar.timings.Timing; ++import co.aikar.timings.Timings; ++import co.aikar.timings.TimingsManager; ++ ++import java.lang.reflect.Method; ++import java.util.logging.Level; + + /** +- * Provides custom timing sections for /timings merged. ++ * This is here for legacy purposes incase any plugin used it. ++ * ++ * If you use this, migrate ASAP as this will be removed in the future! ++ * ++ * @deprecated ++ * @see co.aikar.timings.Timings#of + */ +-public class CustomTimingsHandler { +- +- private static Queue HANDLERS = new ConcurrentLinkedQueue(); +- /*========================================================================*/ +- private final String name; +- private final CustomTimingsHandler parent; +- private long count = 0; +- private long start = 0; +- private long timingDepth = 0; +- private long totalTime = 0; +- private long curTickTotal = 0; +- private long violations = 0; ++@Deprecated(forRemoval = true) ++public final class CustomTimingsHandler { ++ private final Timing handler; + + public CustomTimingsHandler(@NotNull String name) { +- this(name, null); +- } +- +- public CustomTimingsHandler(@NotNull String name, @Nullable CustomTimingsHandler parent) { +- this.name = name; +- this.parent = parent; +- HANDLERS.add(this); +- } +- +- /** +- * Prints the timings and extra data to the given stream. +- * +- * @param printStream output stream +- */ +- public static void printTimings(@NotNull PrintStream printStream) { +- printStream.println("Minecraft"); +- for (CustomTimingsHandler timings : HANDLERS) { +- long time = timings.totalTime; +- long count = timings.count; +- if (count == 0) { +- continue; +- } +- long avg = time / count; +- +- printStream.println(" " + timings.name + " Time: " + time + " Count: " + count + " Avg: " + avg + " Violations: " + timings.violations); +- } +- printStream.println("# Version " + Bukkit.getVersion()); +- int entities = 0; +- int livingEntities = 0; +- for (World world : Bukkit.getWorlds()) { +- entities += world.getEntities().size(); +- livingEntities += world.getLivingEntities().size(); +- } +- printStream.println("# Entities " + entities); +- printStream.println("# LivingEntities " + livingEntities); +- } +- +- /** +- * Resets all timings. +- */ +- public static void reload() { +- if (Bukkit.getPluginManager().useTimings()) { +- for (CustomTimingsHandler timings : HANDLERS) { +- timings.reset(); +- } +- } +- TimingsCommand.timingStart = System.nanoTime(); +- } +- +- /** +- * Ticked every tick by CraftBukkit to count the number of times a timer +- * caused TPS loss. +- */ +- public static void tick() { +- if (Bukkit.getPluginManager().useTimings()) { +- for (CustomTimingsHandler timings : HANDLERS) { +- if (timings.curTickTotal > 50000000) { +- timings.violations += Math.ceil(timings.curTickTotal / 50000000); +- } +- timings.curTickTotal = 0; +- timings.timingDepth = 0; // incase reset messes this up +- } +- } +- } ++ Timing timing; + +- /** +- * Starts timing to track a section of code. +- */ +- public void startTiming() { +- // If second condtion fails we are already timing +- if (Bukkit.getPluginManager().useTimings() && ++timingDepth == 1) { +- start = System.nanoTime(); +- if (parent != null && ++parent.timingDepth == 1) { +- parent.start = start; +- } ++ new AuthorNagException("Deprecated use of CustomTimingsHandler. Please Switch to Timings.of ASAP").printStackTrace(); ++ try { ++ final Method ofSafe = TimingsManager.class.getDeclaredMethod("getHandler", String.class, String.class, Timing.class); ++ ofSafe.setAccessible(true); ++ timing = (Timing) ofSafe.invoke(null,"Minecraft", "(Deprecated API) " + name, null); ++ } catch (Exception e) { ++ e.printStackTrace(); ++ Bukkit.getLogger().log(Level.SEVERE, "This handler could not be registered"); ++ timing = Timings.NULL_HANDLER; + } ++ handler = timing; + } + +- /** +- * Stops timing a section of code. +- */ +- public void stopTiming() { +- if (Bukkit.getPluginManager().useTimings()) { +- if (--timingDepth != 0 || start == 0) { +- return; +- } +- long diff = System.nanoTime() - start; +- totalTime += diff; +- curTickTotal += diff; +- count++; +- start = 0; +- if (parent != null) { +- parent.stopTiming(); +- } +- } +- } ++ public void startTiming() { handler.startTiming(); } ++ public void stopTiming() { handler.stopTiming(); } + +- /** +- * Reset this timer, setting all values to zero. +- */ +- public void reset() { +- count = 0; +- violations = 0; +- curTickTotal = 0; +- totalTime = 0; +- start = 0; +- timingDepth = 0; +- } + } diff --git a/patches/api/0011-Version-Command-2.0.patch b/patches/api/0011-Version-Command-2.0.patch deleted file mode 100644 index 50f9cbf8d373..000000000000 --- a/patches/api/0011-Version-Command-2.0.patch +++ /dev/null @@ -1,177 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Mon, 27 May 2019 01:10:06 -0500 -Subject: [PATCH] Version Command 2.0 - - -diff --git a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a736d7bcdc5861a01b66ba36158db1c716339346 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java -@@ -0,0 +1,45 @@ -+package com.destroystokyo.paper.util; -+ -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.format.NamedTextColor; -+import org.bukkit.Bukkit; -+import org.jetbrains.annotations.NotNull; -+ -+public interface VersionFetcher { -+ /** -+ * Amount of time to cache results for in milliseconds -+ *

      -+ * Negative values will never cache. -+ * -+ * @return cache time -+ */ -+ long getCacheTime(); -+ -+ /** -+ * Gets the version message to cache and show to command senders. -+ * -+ *

      NOTE: This is run in a new thread separate from that of the command processing thread

      -+ * -+ * @param serverVersion the current version of the server (will match {@link Bukkit#getVersion()}) -+ * @return the message to show when requesting a version -+ */ -+ @NotNull -+ Component getVersionMessage(@NotNull String serverVersion); -+ -+ class DummyVersionFetcher implements VersionFetcher { -+ -+ @Override -+ public long getCacheTime() { -+ return -1; -+ } -+ -+ @NotNull -+ @Override -+ public Component getVersionMessage(@NotNull String serverVersion) { -+ Bukkit.getLogger().warning("Version provider has not been set, cannot check for updates!"); -+ Bukkit.getLogger().info("Override the default implementation of org.bukkit.UnsafeValues#getVersionFetcher()"); -+ new Throwable().printStackTrace(); -+ return Component.text("Unable to check for updates. No version provider set.", NamedTextColor.RED); -+ } -+ } -+} -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index c9ecd5b1908e05a1b39dadcded27241672adcddf..355c46f1c1f08072446f3cc92c0d22898933a7fc 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -94,5 +94,12 @@ public interface UnsafeValues { - * @return name - */ - String getTimingsServerName(); -+ -+ /** -+ * Called once by the version command on first use, then cached. -+ */ -+ default com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { -+ return new com.destroystokyo.paper.util.VersionFetcher.DummyVersionFetcher(); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java -index 04b4fb6859df0221f8f9f92c5a7ac2dda1073355..b50f614806f4634960d383e8a33f094c2f46935f 100644 ---- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java -+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java -@@ -1,5 +1,6 @@ - package org.bukkit.command.defaults; - -+import com.destroystokyo.paper.util.VersionFetcher; // Paper - version supplier - import com.google.common.base.Charsets; - import com.google.common.base.Preconditions; - import com.google.common.collect.ImmutableList; -@@ -26,6 +27,15 @@ import org.bukkit.util.StringUtil; - import org.jetbrains.annotations.NotNull; - - public class VersionCommand extends BukkitCommand { -+ private VersionFetcher versionFetcher; -+ private VersionFetcher getVersionFetcher() { // lazy load because unsafe isn't available at command registration -+ if (versionFetcher == null) { -+ versionFetcher = Bukkit.getUnsafe().getVersionFetcher(); -+ } -+ -+ return versionFetcher; -+ } -+ - public VersionCommand(@NotNull String name) { - super(name); - -@@ -40,7 +50,7 @@ public class VersionCommand extends BukkitCommand { - if (!testPermission(sender)) return true; - - if (args.length == 0) { -- sender.sendMessage("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")"); -+ //sender.sendMessage("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")"); // Paper - moved to setVersionMessage - sendVersion(sender); - } else { - StringBuilder name = new StringBuilder(); -@@ -146,14 +156,14 @@ public class VersionCommand extends BukkitCommand { - - private final ReentrantLock versionLock = new ReentrantLock(); - private boolean hasVersion = false; -- private String versionMessage = null; -+ private net.kyori.adventure.text.Component versionMessage = null; // Paper - private final Set versionWaiters = new HashSet(); - private boolean versionTaskStarted = false; - private long lastCheck = 0; - - private void sendVersion(@NotNull CommandSender sender) { - if (hasVersion) { -- if (System.currentTimeMillis() - lastCheck > 21600000) { -+ if (System.currentTimeMillis() - lastCheck > getVersionFetcher().getCacheTime()) { // Paper - use version supplier - lastCheck = System.currentTimeMillis(); - hasVersion = false; - } else { -@@ -168,7 +178,7 @@ public class VersionCommand extends BukkitCommand { - return; - } - versionWaiters.add(sender); -- sender.sendMessage("Checking version, please wait..."); -+ sender.sendMessage(net.kyori.adventure.text.Component.text("Checking version, please wait...", net.kyori.adventure.text.format.NamedTextColor.WHITE, net.kyori.adventure.text.format.TextDecoration.ITALIC)); // Paper - if (!versionTaskStarted) { - versionTaskStarted = true; - new Thread(new Runnable() { -@@ -186,6 +196,13 @@ public class VersionCommand extends BukkitCommand { - - private void obtainVersion() { - String version = Bukkit.getVersion(); -+ // Paper start -+ if (version.startsWith("null")) { // running from ide? -+ setVersionMessage(net.kyori.adventure.text.Component.text("Unknown version, custom build?", net.kyori.adventure.text.format.NamedTextColor.YELLOW)); -+ return; -+ } -+ setVersionMessage(getVersionFetcher().getVersionMessage(version)); -+ /* - if (version == null) version = "Custom"; - String[] parts = version.substring(0, version.indexOf(' ')).split("-"); - if (parts.length == 4) { -@@ -215,11 +232,24 @@ public class VersionCommand extends BukkitCommand { - } else { - setVersionMessage("Unknown version, custom build?"); - } -+ */ -+ // Paper end - } - -- private void setVersionMessage(@NotNull String msg) { -+ // Paper start -+ private void setVersionMessage(final @NotNull net.kyori.adventure.text.Component msg) { - lastCheck = System.currentTimeMillis(); -- versionMessage = msg; -+ final net.kyori.adventure.text.Component message = net.kyori.adventure.text.TextComponent.ofChildren( -+ net.kyori.adventure.text.Component.text("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")", net.kyori.adventure.text.format.NamedTextColor.WHITE), -+ net.kyori.adventure.text.Component.newline(), -+ msg -+ ); -+ this.versionMessage = net.kyori.adventure.text.Component.text() -+ .append(message) -+ .hoverEvent(net.kyori.adventure.text.Component.text("Click to copy to clipboard", net.kyori.adventure.text.format.NamedTextColor.WHITE)) -+ .clickEvent(net.kyori.adventure.text.event.ClickEvent.copyToClipboard(net.kyori.adventure.text.serializer.plain.PlainComponentSerializer.plain().serialize(message))) -+ .build(); -+ // Paper end - versionLock.lock(); - try { - hasVersion = true; diff --git a/patches/api/0012-Add-command-line-option-to-load-extra-plugin-jars-no.patch b/patches/api/0012-Add-command-line-option-to-load-extra-plugin-jars-no.patch new file mode 100644 index 000000000000..5a2340eb8fdf --- /dev/null +++ b/patches/api/0012-Add-command-line-option-to-load-extra-plugin-jars-no.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Tue, 18 May 2021 14:42:26 -0700 +Subject: [PATCH] Add command line option to load extra plugin jars not in the + plugins folder + +ex: java -jar paperclip.jar nogui -add-plugin=/path/to/plugin.jar -add-plugin=/path/to/another/plugin_jar.jar + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index a327c71f110fc0330a3a43ab118565d35801eb32..60ad479817c95aef809f73c6688cd6b2a0bb91df 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -83,6 +83,20 @@ public final class Bukkit { + return server; + } + ++ /** ++ * Returns the de facto plugins directory, generally used for storing plugin jars to be loaded, ++ * as well as their {@link org.bukkit.plugin.Plugin#getDataFolder() data folders}. ++ * ++ *

      Plugins should use {@link org.bukkit.plugin.Plugin#getDataFolder()} rather than traversing this ++ * directory manually when determining the location in which to store their data and configuration files.

      ++ * ++ * @return plugins directory ++ */ ++ @NotNull ++ public static File getPluginsFolder() { ++ return server.getPluginsFolder(); ++ } ++ + /** + * Attempts to set the {@link Server} singleton. + *

      +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index a1bffe44764fc3e1bb96bf014c56025b0bde7507..f5005063c33d5e7ac030c4d43cb042c18c799284 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -68,6 +68,18 @@ import org.jetbrains.annotations.Nullable; + */ + public interface Server extends PluginMessageRecipient, net.kyori.adventure.audience.ForwardingAudience { // Paper + ++ /** ++ * Returns the de facto plugins directory, generally used for storing plugin jars to be loaded, ++ * as well as their {@link org.bukkit.plugin.Plugin#getDataFolder() data folders}. ++ * ++ *

      Plugins should use {@link org.bukkit.plugin.Plugin#getDataFolder()} rather than traversing this ++ * directory manually when determining the location in which to store their data and configuration files.

      ++ * ++ * @return plugins directory ++ */ ++ @NotNull ++ File getPluginsFolder(); ++ + /** + * Used for all administrative messages, such as an operator using a + * command. +diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +index b03f3e0ce9fdb0bb587cf1a1c10b8cfaa2eab09e..48b66054913c8b53e6e7fd34615c2ab54727693f 100644 +--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java ++++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +@@ -117,9 +117,22 @@ public final class SimplePluginManager implements PluginManager { + @Override + @NotNull + public Plugin[] loadPlugins(@NotNull File directory) { ++ // Paper start - extra jars ++ return this.loadPlugins(directory, java.util.Collections.emptyList()); ++ } ++ @NotNull ++ public Plugin[] loadPlugins(final @NotNull File directory, final @NotNull List extraPluginJars) { ++ // Paper end + if (true) { + List pluginList = new ArrayList<>(); + java.util.Collections.addAll(pluginList, this.paperPluginManager.loadPlugins(directory)); ++ for (File file : extraPluginJars) { ++ try { ++ pluginList.add(this.paperPluginManager.loadPlugin(file)); ++ } catch (Exception e) { ++ this.server.getLogger().log(Level.SEVERE, "Plugin loading error!", e); ++ } ++ } + return pluginList.toArray(new Plugin[0]); + } + Preconditions.checkArgument(directory != null, "Directory cannot be null"); +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +index 2e4a0a66151b358cc89d8eea26002f9fda16ee48..b412aaf08901d169ac9fc89b36f9d6ccb95c53d3 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +@@ -93,7 +93,7 @@ public final class JavaPluginLoader implements PluginLoader { + throw new InvalidPluginException(ex); + } + +- final File parentFile = file.getParentFile(); ++ final File parentFile = this.server.getPluginsFolder(); // Paper + final File dataFolder = new File(parentFile, description.getName()); + @SuppressWarnings("deprecation") + final File oldDataFolder = new File(parentFile, description.getRawName()); diff --git a/patches/api/0012-Entity-Origin-API.patch b/patches/api/0012-Entity-Origin-API.patch deleted file mode 100644 index c3a843eb0fde..000000000000 --- a/patches/api/0012-Entity-Origin-API.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Byteflux -Date: Mon, 29 Feb 2016 17:50:31 -0600 -Subject: [PATCH] Entity Origin API - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index cd287978c34873c7122794e4f3e762915978a1f0..c315d2494969190f8b53236f905ad5c5cf1bfc39 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -671,5 +671,15 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - default net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { - return net.kyori.adventure.text.event.HoverEvent.showEntity(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowEntity.of(this.getType().getKey(), this.getUniqueId(), this.customName()))); - } -+ -+ /** -+ * Gets the location where this entity originates from. -+ *

      -+ * This value can be null if the entity hasn't yet been added to the world. -+ * -+ * @return Location where entity originates or null if not yet added -+ */ -+ @Nullable -+ Location getOrigin(); - // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/FallingBlock.java b/src/main/java/org/bukkit/entity/FallingBlock.java -index 64f9d3fd870d65afd2ee9a85625b149163eee144..14cb0d770561151570ab4399ca5facff43076819 100644 ---- a/src/main/java/org/bukkit/entity/FallingBlock.java -+++ b/src/main/java/org/bukkit/entity/FallingBlock.java -@@ -54,4 +54,15 @@ public interface FallingBlock extends Entity { - * @param hurtEntities whether entities will be damaged by this block. - */ - void setHurtEntities(boolean hurtEntities); -+ -+ /** -+ * Gets the source block location of the FallingBlock -+ * -+ * @return the source block location the FallingBlock was spawned from -+ * @deprecated replaced by {@link Entity#getOrigin()} -+ */ -+ @Deprecated -+ default org.bukkit.Location getSourceLoc() { -+ return this.getOrigin(); -+ } - } -diff --git a/src/main/java/org/bukkit/entity/TNTPrimed.java b/src/main/java/org/bukkit/entity/TNTPrimed.java -index a23cfdf66877f0a61eae700de084c76e6ee7b431..0813bd913c8fdb2001963ce3e82c07c2af105418 100644 ---- a/src/main/java/org/bukkit/entity/TNTPrimed.java -+++ b/src/main/java/org/bukkit/entity/TNTPrimed.java -@@ -53,4 +53,15 @@ public interface TNTPrimed extends Explosive { - * @param source the source of this primed TNT - */ - public void setSource(@Nullable Entity source); -+ -+ /** -+ * Gets the source block location of the TNTPrimed -+ * -+ * @return the source block location the TNTPrimed was spawned from -+ * @deprecated replaced by {@link Entity#getOrigin()} -+ */ -+ @Deprecated -+ default org.bukkit.Location getSourceLoc() { -+ return this.getOrigin(); -+ } - } diff --git a/patches/api/0013-Add-PlayerLocaleChangeEvent.patch b/patches/api/0013-Add-PlayerLocaleChangeEvent.patch deleted file mode 100644 index 10593168ecec..000000000000 --- a/patches/api/0013-Add-PlayerLocaleChangeEvent.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Isaac Moore -Date: Mon, 29 Feb 2016 18:02:25 -0600 -Subject: [PATCH] Add PlayerLocaleChangeEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerLocaleChangeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerLocaleChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..29dd763a99ce7c6ecb176b9fb346a400369d48a0 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerLocaleChangeEvent.java -@@ -0,0 +1,50 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+ -+/** -+ * Called when the locale of the player is changed. -+ * -+ * @deprecated Replaced by {@link org.bukkit.event.player.PlayerLocaleChangeEvent} upstream -+ */ -+@Deprecated -+public class PlayerLocaleChangeEvent extends PlayerEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ private final String oldLocale; -+ private final String newLocale; -+ -+ public PlayerLocaleChangeEvent(final Player player, final String oldLocale, final String newLocale) { -+ super(player); -+ this.oldLocale = oldLocale; -+ this.newLocale = newLocale; -+ } -+ -+ /** -+ * Gets the locale the player switched from. -+ * -+ * @return player's old locale -+ */ -+ public String getOldLocale() { -+ return oldLocale; -+ } -+ -+ /** -+ * Gets the locale the player is changed to. -+ * -+ * @return player's new locale -+ */ -+ public String getNewLocale() { -+ return newLocale; -+ } -+ -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0013-Player-affects-spawning-API.patch b/patches/api/0013-Player-affects-spawning-API.patch new file mode 100644 index 000000000000..3a62dc90c906 --- /dev/null +++ b/patches/api/0013-Player-affects-spawning-API.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jedediah Smith +Date: Mon, 29 Feb 2016 17:22:34 -0600 +Subject: [PATCH] Player affects spawning API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index a06daeeee71a5ca58fbc1e13453d9116eadbcac2..bc64083c02bce93a22521173c9430eb5469ba8a6 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -2623,6 +2623,22 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + @Deprecated // Paper + public String getLocale(); + ++ // Paper start ++ /** ++ * Get whether the player can affect mob spawning ++ * ++ * @return if the player can affect mob spawning ++ */ ++ public boolean getAffectsSpawning(); ++ ++ /** ++ * Set whether the player can affect mob spawning ++ * ++ * @param affects Whether the player can affect mob spawning ++ */ ++ public void setAffectsSpawning(boolean affects); ++ // Paper end ++ + /** + * Update the list of commands sent to the client. + *
      diff --git a/patches/api/0014-Add-getTPS-method.patch b/patches/api/0014-Add-getTPS-method.patch new file mode 100644 index 000000000000..b97e3f77435e --- /dev/null +++ b/patches/api/0014-Add-getTPS-method.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 29 Feb 2016 17:24:57 -0600 +Subject: [PATCH] Add getTPS method + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 60ad479817c95aef809f73c6688cd6b2a0bb91df..e4f7ff41d7205994fef87989a7955d7b8fe4d7f4 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2132,6 +2132,17 @@ public final class Bukkit { + return server.getEntity(uuid); + } + ++ // Paper start ++ /** ++ * Gets the current server TPS ++ * @return current server TPS (1m, 5m, 15m in Paper-Server) ++ */ ++ @NotNull ++ public static double[] getTPS() { ++ return server.getTPS(); ++ } ++ // Paper end ++ + /** + * Get the advancement specified by this key. + * +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index f5005063c33d5e7ac030c4d43cb042c18c799284..4f15cc4bcc07d3061dd94b20fc77f549ddfcbb6b 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1815,6 +1815,16 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @Nullable + Entity getEntity(@NotNull UUID uuid); + ++ // Paper start ++ /** ++ * Gets the current server TPS ++ * ++ * @return current server TPS (1m, 5m, 15m in Paper-Server) ++ */ ++ @NotNull ++ public double[] getTPS(); ++ // Paper end ++ + /** + * Get the advancement specified by this key. + * diff --git a/patches/api/0014-Add-view-distance-API.patch b/patches/api/0014-Add-view-distance-API.patch deleted file mode 100644 index fee18bd5314c..000000000000 --- a/patches/api/0014-Add-view-distance-API.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Byteflux -Date: Mon, 29 Feb 2016 18:05:37 -0600 -Subject: [PATCH] Add view distance API - -Add per player no-tick, tick, and send view distances. - -Also add send/no-tick view distance to World. - -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 1d3bb553c944f5920e81e295f8cd5b7194d37aac..887b85849803cee22a41a701b43cdc9085ba0dc3 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -2673,6 +2673,62 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - int getSimulationDistance(); - // Spigot end - -+ // Paper start - view distance api -+ /** -+ * Sets the view distance for this world. -+ * @param viewDistance view distance in [2, 32] -+ */ -+ void setViewDistance(int viewDistance); -+ -+ /** -+ * Sets the simulation distance for this world. -+ * @param simulationDistance simulation distance in [2, 32] -+ */ -+ void setSimulationDistance(int simulationDistance); -+ -+ /** -+ * Returns the no-tick view distance for this world. -+ *

      -+ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not -+ * be set to tick. -+ *

      -+ * @return The no-tick view distance for this world. -+ * @deprecated Use {@link #getViewDistance()} -+ */ -+ @Deprecated -+ int getNoTickViewDistance(); -+ -+ /** -+ * Sets the no-tick view distance for this world. -+ *

      -+ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not -+ * be set to tick. -+ *

      -+ * @param viewDistance view distance in [2, 32] -+ * @deprecated Use {@link #setViewDistance(int)} -+ */ -+ @Deprecated -+ void setNoTickViewDistance(int viewDistance); -+ -+ /** -+ * Gets the sending view distance for this world. -+ *

      -+ * Sending view distance is the view distance where chunks will load in for players in this world. -+ *

      -+ * @return The sending view distance for this world. -+ */ -+ int getSendViewDistance(); -+ -+ /** -+ * Sets the sending view distance for this world. -+ *

      -+ * Sending view distance is the view distance where chunks will load in for players in this world. -+ *

      -+ * @param viewDistance view distance in [2, 32] or -1 -+ */ -+ void setSendViewDistance(int viewDistance); -+ // Paper end - view distance api -+ - // Spigot start - public class Spigot { - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index e03ab25cf2add5edbf0d3a28451ac47360fad080..b362a0e3954a2a58b896a9951f3e31c1706959ec 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -1833,6 +1833,78 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @param affects Whether the player can affect mob spawning - */ - public void setAffectsSpawning(boolean affects); -+ -+ /** -+ * Gets the view distance for this player -+ * -+ * @return the player's view distance -+ * @see org.bukkit.World#getViewDistance() -+ */ -+ public int getViewDistance(); -+ -+ /** -+ * Sets the view distance for this player -+ * -+ * @param viewDistance the player's view distance -+ * @see org.bukkit.World#setViewDistance(int) -+ */ -+ public void setViewDistance(int viewDistance); -+ -+ /** -+ * Gets the simulation distance for this player -+ * -+ * @return the player's simulation distance -+ */ -+ public int getSimulationDistance(); -+ -+ /** -+ * Sets the simulation distance for this player -+ * -+ * @param simulationDistance the player's new simulation distance -+ */ -+ public void setSimulationDistance(int simulationDistance); -+ -+ /** -+ * Gets the no-ticking view distance for this player. -+ *

      -+ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not -+ * be set to tick. -+ *

      -+ * @return The no-tick view distance for this player. -+ * @deprecated Use {@link #getViewDistance()} -+ */ -+ @Deprecated -+ public int getNoTickViewDistance(); -+ -+ /** -+ * Sets the no-ticking view distance for this player. -+ *

      -+ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not -+ * be set to tick. -+ *

      -+ * @param viewDistance view distance in [2, 32] or -1 -+ * @deprecated Use {@link #setViewDistance(int)} -+ */ -+ @Deprecated -+ public void setNoTickViewDistance(int viewDistance); -+ -+ /** -+ * Gets the sending view distance for this player. -+ *

      -+ * Sending view distance is the view distance where chunks will load in for players. -+ *

      -+ * @return The sending view distance for this player. -+ */ -+ public int getSendViewDistance(); -+ -+ /** -+ * Sets the sending view distance for this player. -+ *

      -+ * Sending view distance is the view distance where chunks will load in for players. -+ *

      -+ * @param viewDistance view distance in [2, 32] or -1 -+ */ -+ public void setSendViewDistance(int viewDistance); - // Paper end - - /** diff --git a/patches/api/0015-Add-BeaconEffectEvent.patch b/patches/api/0015-Add-BeaconEffectEvent.patch deleted file mode 100644 index 43af3c3828b5..000000000000 --- a/patches/api/0015-Add-BeaconEffectEvent.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Byteflux -Date: Mon, 29 Feb 2016 18:09:40 -0600 -Subject: [PATCH] Add BeaconEffectEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java b/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..978813b94a5eae0afccbd3b38b463091a46b56ac ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java -@@ -0,0 +1,86 @@ -+package com.destroystokyo.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.bukkit.potion.PotionEffect; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a beacon effect is being applied to a player. -+ */ -+public class BeaconEffectEvent extends BlockEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private PotionEffect effect; -+ private Player player; -+ private boolean primary; -+ -+ public BeaconEffectEvent(@NotNull Block block, @NotNull PotionEffect effect, @NotNull Player player, boolean primary) { -+ super(block); -+ this.effect = effect; -+ this.player = player; -+ this.primary = primary; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancelled) { -+ this.cancelled = cancelled; -+ } -+ -+ /** -+ * Gets the potion effect being applied. -+ * -+ * @return Potion effect -+ */ -+ @NotNull -+ public PotionEffect getEffect() { -+ return effect; -+ } -+ -+ /** -+ * Sets the potion effect that will be applied. -+ * -+ * @param effect Potion effect -+ */ -+ public void setEffect(@NotNull PotionEffect effect) { -+ this.effect = effect; -+ } -+ -+ /** -+ * Gets the player who the potion effect is being applied to. -+ * -+ * @return Affected player -+ */ -+ @NotNull -+ public Player getPlayer() { -+ return player; -+ } -+ -+ /** -+ * Gets whether the effect is a primary beacon effect. -+ * -+ * @return true if this event represents a primary effect -+ */ -+ public boolean isPrimary() { -+ return primary; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0015-Expose-server-build-information.patch b/patches/api/0015-Expose-server-build-information.patch new file mode 100644 index 000000000000..a5cae3c9f322 --- /dev/null +++ b/patches/api/0015-Expose-server-build-information.patch @@ -0,0 +1,533 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Mon, 27 May 2019 01:10:06 -0500 +Subject: [PATCH] Expose server build information + +Co-authored-by: Professor Bloodstone +Co-authored-by: Mark Vainomaa +Co-authored-by: masmc05 +Co-authored-by: Riley Park + +diff --git a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java +new file mode 100644 +index 0000000000000000000000000000000000000000..023cc52a9e28e1238c7452c0f3f577f2850fd861 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java +@@ -0,0 +1,47 @@ ++package com.destroystokyo.paper.util; ++ ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.format.NamedTextColor; ++import org.bukkit.Bukkit; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public interface VersionFetcher { ++ ++ /** ++ * Amount of time to cache results for in milliseconds ++ *

      ++ * Negative values will never cache. ++ * ++ * @return cache time ++ */ ++ long getCacheTime(); ++ ++ /** ++ * Gets the version message to cache and show to command senders. ++ * ++ *

      NOTE: This is run in a new thread separate from that of the command processing thread

      ++ * ++ * @param serverVersion the current version of the server (will match {@link Bukkit#getVersion()}) ++ * @return the message to show when requesting a version ++ */ ++ Component getVersionMessage(String serverVersion); ++ ++ @ApiStatus.Internal ++ class DummyVersionFetcher implements VersionFetcher { ++ ++ @Override ++ public long getCacheTime() { ++ return -1; ++ } ++ ++ @Override ++ public Component getVersionMessage(final String serverVersion) { ++ Bukkit.getLogger().warning("Version provider has not been set, cannot check for updates!"); ++ Bukkit.getLogger().info("Override the default implementation of org.bukkit.UnsafeValues#getVersionFetcher()"); ++ new Throwable().printStackTrace(); ++ return Component.text("Unable to check for updates. No version provider set.", NamedTextColor.RED); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java +new file mode 100644 +index 0000000000000000000000000000000000000000..652ff54e7c50412503725d628bfe72ed03059790 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java +@@ -0,0 +1,122 @@ ++package io.papermc.paper; ++ ++import java.time.Instant; ++import java.util.Optional; ++import java.util.OptionalInt; ++import net.kyori.adventure.key.Key; ++import net.kyori.adventure.util.Services; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Information about the current server build. ++ */ ++@NullMarked ++@ApiStatus.NonExtendable ++public interface ServerBuildInfo { ++ /** ++ * The brand id for Paper. ++ */ ++ Key BRAND_PAPER_ID = Key.key("papermc", "paper"); ++ ++ /** ++ * Gets the {@code ServerBuildInfo}. ++ * ++ * @return the {@code ServerBuildInfo} ++ */ ++ static ServerBuildInfo buildInfo() { ++ // ++ final class Holder { ++ static final Optional INSTANCE = Services.service(ServerBuildInfo.class); ++ } ++ // ++ return Holder.INSTANCE.orElseThrow(); ++ } ++ ++ /** ++ * Gets the brand id of the server. ++ * ++ * @return the brand id of the server (e.g. "papermc:paper") ++ */ ++ Key brandId(); ++ ++ /** ++ * Checks if the current server supports the specified brand. ++ * ++ * @param brandId the brand to check (e.g. "papermc:folia") ++ * @return {@code true} if the server supports the specified brand ++ */ ++ @ApiStatus.Experimental ++ boolean isBrandCompatible(final Key brandId); ++ ++ /** ++ * Gets the brand name of the server. ++ * ++ * @return the brand name of the server (e.g. "Paper") ++ */ ++ String brandName(); ++ ++ /** ++ * Gets the Minecraft version id. ++ * ++ * @return the Minecraft version id (e.g. "1.20.4", "1.20.2-pre2", "23w31a") ++ */ ++ String minecraftVersionId(); ++ ++ /** ++ * Gets the Minecraft version name. ++ * ++ * @return the Minecraft version name (e.g. "1.20.4", "1.20.2 Pre-release 2", "23w31a") ++ */ ++ String minecraftVersionName(); ++ ++ /** ++ * Gets the build number. ++ * ++ * @return the build number ++ */ ++ OptionalInt buildNumber(); ++ ++ /** ++ * Gets the build time. ++ * ++ * @return the build time ++ */ ++ Instant buildTime(); ++ ++ /** ++ * Gets the git commit branch. ++ * ++ * @return the git commit branch ++ */ ++ Optional gitBranch(); ++ ++ /** ++ * Gets the git commit hash. ++ * ++ * @return the git commit hash ++ */ ++ Optional gitCommit(); ++ ++ /** ++ * Creates a string representation of the server build information. ++ * ++ * @param representation the type of representation ++ * @return a string ++ */ ++ String asString(final StringRepresentation representation); ++ ++ /** ++ * String representation types. ++ */ ++ enum StringRepresentation { ++ /** ++ * A simple version string, in format {@code --}. ++ */ ++ VERSION_SIMPLE, ++ /** ++ * A simple version string, in format {@code --@ ()}. ++ */ ++ VERSION_FULL, ++ } ++} +diff --git a/src/main/java/io/papermc/paper/util/JarManifests.java b/src/main/java/io/papermc/paper/util/JarManifests.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7915a70d676b1205dcae39259f670af258a1ab9b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/JarManifests.java +@@ -0,0 +1,38 @@ ++package io.papermc.paper.util; ++ ++import java.io.IOException; ++import java.io.InputStream; ++import java.net.URL; ++import java.util.Collections; ++import java.util.Map; ++import java.util.WeakHashMap; ++import java.util.jar.Manifest; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@NullMarked ++@ApiStatus.Internal ++public final class JarManifests { ++ private JarManifests() { ++ } ++ ++ private static final Map MANIFESTS = Collections.synchronizedMap(new WeakHashMap<>()); ++ ++ public static @Nullable Manifest manifest(final Class clazz) { ++ return MANIFESTS.computeIfAbsent(clazz.getClassLoader(), classLoader -> { ++ final String classLocation = "/" + clazz.getName().replace(".", "/") + ".class"; ++ final URL resource = clazz.getResource(classLocation); ++ if (resource == null) { ++ return null; ++ } ++ final String classFilePath = resource.toString().replace("\\", "/"); ++ final String archivePath = classFilePath.substring(0, classFilePath.length() - classLocation.length()); ++ try (final InputStream stream = new URL(archivePath + "/META-INF/MANIFEST.MF").openStream()) { ++ return new Manifest(stream); ++ } catch (final IOException ex) { ++ return null; ++ } ++ }); ++ } ++} +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index e4f7ff41d7205994fef87989a7955d7b8fe4d7f4..75e0c5b884363be03876103e0d66e67de03c4856 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -110,13 +110,26 @@ public final class Bukkit { + } + + Bukkit.server = server; +- server.getLogger().info("This server is running " + getName() + " version " + getVersion() + " (Implementing API version " + getBukkitVersion() + ")"); ++ // Paper start - add git information ++ server.getLogger().info(getVersionMessage()); ++ } ++ /** ++ * Gets message describing the version server is running. ++ * ++ * @return message describing the version server is running ++ */ ++ @NotNull ++ public static String getVersionMessage() { ++ final io.papermc.paper.ServerBuildInfo version = io.papermc.paper.ServerBuildInfo.buildInfo(); ++ return "This server is running " + getName() + " version " + version.asString(io.papermc.paper.ServerBuildInfo.StringRepresentation.VERSION_FULL) + " (Implementing API version " + getBukkitVersion() + ")"; ++ // Paper end + } + + /** + * Gets the name of this server implementation. + * + * @return name of this server implementation ++ * @see io.papermc.paper.ServerBuildInfo#brandName() + */ + @NotNull + public static String getName() { +@@ -127,6 +140,7 @@ public final class Bukkit { + * Gets the version string of this server implementation. + * + * @return version of this server implementation ++ * @see io.papermc.paper.ServerBuildInfo + */ + @NotNull + public static String getVersion() { +@@ -143,6 +157,20 @@ public final class Bukkit { + return server.getBukkitVersion(); + } + ++ // Paper start - expose game version ++ /** ++ * Gets the version of game this server implements ++ * ++ * @return version of game ++ * @see io.papermc.paper.ServerBuildInfo#minecraftVersionId() ++ * @see io.papermc.paper.ServerBuildInfo#minecraftVersionName() ++ */ ++ @NotNull ++ public static String getMinecraftVersion() { ++ return server.getMinecraftVersion(); ++ } ++ // Paper end ++ + /** + * Gets a view of all currently logged in players. This {@linkplain + * Collections#unmodifiableCollection(Collection) view} is a reused +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 4f15cc4bcc07d3061dd94b20fc77f549ddfcbb6b..2ed640d5a0027f7a94a5cf4555741c27c9b1b3a4 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -120,6 +120,16 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @NotNull + public String getBukkitVersion(); + ++ // Paper start - expose game version ++ /** ++ * Gets the version of game this server implements ++ * ++ * @return version of game ++ */ ++ @NotNull ++ String getMinecraftVersion(); ++ // Paper end ++ + /** + * Gets a view of all currently logged in players. This {@linkplain + * Collections#unmodifiableCollection(Collection) view} is a reused +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index aec092e019667d53faf3e7352799772804d5d260..012b46c82d9d06d1d2da8da626fc5cde6e9e2ca4 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -156,4 +156,13 @@ public interface UnsafeValues { + return !Bukkit.getUnsafe().isSupportedApiVersion(plugin.getDescription().getAPIVersion()); + } + // Paper end ++ ++ // Paper start ++ /** ++ * Called once by the version command on first use, then cached. ++ */ ++ default com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { ++ return new com.destroystokyo.paper.util.VersionFetcher.DummyVersionFetcher(); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java +index 263208d3cba36cb80c9ee4e3022ef702ea113df2..e64bb57f74e6d6f78927be228825b3e0bdf41f48 100644 +--- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java ++++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java +@@ -25,8 +25,25 @@ import org.bukkit.plugin.Plugin; + import org.bukkit.plugin.PluginDescriptionFile; + import org.bukkit.util.StringUtil; + import org.jetbrains.annotations.NotNull; ++// Paper start - version command 2.0 ++import com.destroystokyo.paper.util.VersionFetcher; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.event.ClickEvent; ++import net.kyori.adventure.text.format.TextDecoration; ++import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; ++// Paper end - version command 2.0 + + public class VersionCommand extends BukkitCommand { ++ private VersionFetcher versionFetcher; // Paper - version command 2.0 ++ private VersionFetcher getVersionFetcher() { // lazy load because unsafe isn't available at command registration ++ if (versionFetcher == null) { ++ versionFetcher = Bukkit.getUnsafe().getVersionFetcher(); ++ } ++ ++ return versionFetcher; ++ } ++ + public VersionCommand(@NotNull String name) { + super(name); + +@@ -41,7 +58,7 @@ public class VersionCommand extends BukkitCommand { + if (!testPermission(sender)) return true; + + if (args.length == 0) { +- sender.sendMessage("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")"); ++ //sender.sendMessage("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")"); // Paper - moved to setVersionMessage + sendVersion(sender); + } else { + StringBuilder name = new StringBuilder(); +@@ -80,8 +97,17 @@ public class VersionCommand extends BukkitCommand { + + private void describeToSender(@NotNull Plugin plugin, @NotNull CommandSender sender) { + PluginDescriptionFile desc = plugin.getDescription(); +- sender.sendMessage(ChatColor.GREEN + desc.getName() + ChatColor.WHITE + " version " + ChatColor.GREEN + desc.getVersion()); +- ++ // Paper start - version command 2.0 ++ sender.sendMessage( ++ Component.text() ++ .append(Component.text(desc.getName(), NamedTextColor.GREEN)) ++ .append(Component.text(" version ")) ++ .append(Component.text(desc.getVersion(), NamedTextColor.GREEN) ++ .hoverEvent(Component.text("Click to copy to clipboard", NamedTextColor.WHITE)) ++ .clickEvent(ClickEvent.copyToClipboard(desc.getVersion())) ++ ) ++ ); ++ // Paper end - version command 2.0 + if (desc.getDescription() != null) { + sender.sendMessage(desc.getDescription()); + } +@@ -147,14 +173,14 @@ public class VersionCommand extends BukkitCommand { + + private final ReentrantLock versionLock = new ReentrantLock(); + private boolean hasVersion = false; +- private String versionMessage = null; ++ private Component versionMessage = null; // Paper + private final Set versionWaiters = new HashSet(); + private boolean versionTaskStarted = false; + private long lastCheck = 0; + + private void sendVersion(@NotNull CommandSender sender) { + if (hasVersion) { +- if (System.currentTimeMillis() - lastCheck > 21600000) { ++ if (System.currentTimeMillis() - lastCheck > getVersionFetcher().getCacheTime()) { // Paper - use version supplier + lastCheck = System.currentTimeMillis(); + hasVersion = false; + } else { +@@ -169,7 +195,7 @@ public class VersionCommand extends BukkitCommand { + return; + } + versionWaiters.add(sender); +- sender.sendMessage("Checking version, please wait..."); ++ sender.sendMessage(Component.text("Checking version, please wait...", NamedTextColor.WHITE, TextDecoration.ITALIC)); // Paper + if (!versionTaskStarted) { + versionTaskStarted = true; + new Thread(new Runnable() { +@@ -187,6 +213,13 @@ public class VersionCommand extends BukkitCommand { + + private void obtainVersion() { + String version = Bukkit.getVersion(); ++ // Paper start ++ if (version.startsWith("null")) { // running from ide? ++ setVersionMessage(Component.text("Unknown version, custom build?", NamedTextColor.YELLOW)); ++ return; ++ } ++ setVersionMessage(getVersionFetcher().getVersionMessage(version)); ++ /* + if (version == null) version = "Custom"; + String[] parts = version.substring(0, version.indexOf(' ')).split("-"); + if (parts.length == 4) { +@@ -216,11 +249,24 @@ public class VersionCommand extends BukkitCommand { + } else { + setVersionMessage("Unknown version, custom build?"); + } ++ */ ++ // Paper end + } + +- private void setVersionMessage(@NotNull String msg) { ++ // Paper start ++ private void setVersionMessage(final @NotNull Component msg) { + lastCheck = System.currentTimeMillis(); +- versionMessage = msg; ++ final Component message = Component.textOfChildren( ++ Component.text(Bukkit.getVersionMessage(), NamedTextColor.WHITE), ++ Component.newline(), ++ msg ++ ); ++ this.versionMessage = Component.text() ++ .append(message) ++ .hoverEvent(Component.text("Click to copy to clipboard", NamedTextColor.WHITE)) ++ .clickEvent(ClickEvent.copyToClipboard(PlainTextComponentSerializer.plainText().serialize(message))) ++ .build(); ++ // Paper end + versionLock.lock(); + try { + hasVersion = true; +diff --git a/src/test/java/io/papermc/paper/TestServerBuildInfo.java b/src/test/java/io/papermc/paper/TestServerBuildInfo.java +new file mode 100644 +index 0000000000000000000000000000000000000000..17be27a869c1047a7a9440fb8f3717260d4abbd0 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/TestServerBuildInfo.java +@@ -0,0 +1,59 @@ ++package io.papermc.paper; ++ ++import java.time.Instant; ++import java.util.Optional; ++import java.util.OptionalInt; ++import net.kyori.adventure.key.Key; ++import org.jetbrains.annotations.NotNull; ++ ++public class TestServerBuildInfo implements ServerBuildInfo { ++ @Override ++ public @NotNull Key brandId() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean isBrandCompatible(final @NotNull Key brandId) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull String brandName() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull String minecraftVersionId() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull String minecraftVersionName() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull OptionalInt buildNumber() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull Instant buildTime() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull Optional gitBranch() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull Optional gitCommit() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull String asString(final @NotNull StringRepresentation representation) { ++ return ""; ++ } ++} +diff --git a/src/test/resources/META-INF/services/io.papermc.paper.ServerBuildInfo b/src/test/resources/META-INF/services/io.papermc.paper.ServerBuildInfo +new file mode 100644 +index 0000000000000000000000000000000000000000..64e2f8559b9c5a52e0a3229d3d12f65e9af145b3 +--- /dev/null ++++ b/src/test/resources/META-INF/services/io.papermc.paper.ServerBuildInfo +@@ -0,0 +1 @@ ++io.papermc.paper.TestServerBuildInfo diff --git a/patches/api/0016-Add-PlayerInitialSpawnEvent.patch b/patches/api/0016-Add-PlayerInitialSpawnEvent.patch deleted file mode 100644 index 44ff48c323da..000000000000 --- a/patches/api/0016-Add-PlayerInitialSpawnEvent.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Steve Anton -Date: Mon, 29 Feb 2016 18:13:58 -0600 -Subject: [PATCH] Add PlayerInitialSpawnEvent - -For modifying a player's initial spawn location as they join the server - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerInitialSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerInitialSpawnEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..626e97bbcaa19d55475a0fc8770412d437af2733 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerInitialSpawnEvent.java -@@ -0,0 +1,17 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.Location; -+import org.bukkit.entity.Player; -+import org.jetbrains.annotations.NotNull; -+import org.spigotmc.event.player.PlayerSpawnLocationEvent; -+ -+/** -+ * @deprecated Use {@link PlayerSpawnLocationEvent}, Duplicate API -+ */ -+@Deprecated -+public class PlayerInitialSpawnEvent extends PlayerSpawnLocationEvent { -+ -+ public PlayerInitialSpawnEvent(@NotNull Player who, @NotNull Location spawnLocation) { -+ super(who, spawnLocation); -+ } -+} diff --git a/patches/api/0016-Entity-Origin-API.patch b/patches/api/0016-Entity-Origin-API.patch new file mode 100644 index 000000000000..ca30d1d77fb8 --- /dev/null +++ b/patches/api/0016-Entity-Origin-API.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Byteflux +Date: Mon, 29 Feb 2016 17:50:31 -0600 +Subject: [PATCH] Entity Origin API + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index d7f95863922bf332c674d538eb187015fadae9d8..411297f66520774a4072c9e15aa9bdf03a527208 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -791,5 +791,15 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + default net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { + return net.kyori.adventure.text.event.HoverEvent.showEntity(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowEntity.of(this.getType().getKey(), this.getUniqueId(), this.customName()))); + } ++ ++ /** ++ * Gets the location where this entity originates from. ++ *

      ++ * This value can be null if the entity hasn't yet been added to the world. ++ * ++ * @return Location where entity originates or null if not yet added ++ */ ++ @Nullable ++ Location getOrigin(); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/FallingBlock.java b/src/main/java/org/bukkit/entity/FallingBlock.java +index 5d7d940cdad7915efa639b8940a17dc97b60ecd8..315dcf9da29e077a819f602ebf1c76286164b264 100644 +--- a/src/main/java/org/bukkit/entity/FallingBlock.java ++++ b/src/main/java/org/bukkit/entity/FallingBlock.java +@@ -126,4 +126,15 @@ public interface FallingBlock extends Entity { + * @param damage the max damage to set. Must be >= 0 + */ + void setMaxDamage(int damage); ++ ++ /** ++ * Gets the source block location of the FallingBlock ++ * ++ * @return the source block location the FallingBlock was spawned from ++ * @deprecated replaced by {@link Entity#getOrigin()} ++ */ ++ @Deprecated ++ default org.bukkit.Location getSourceLoc() { ++ return this.getOrigin(); ++ } + } +diff --git a/src/main/java/org/bukkit/entity/TNTPrimed.java b/src/main/java/org/bukkit/entity/TNTPrimed.java +index a23cfdf66877f0a61eae700de084c76e6ee7b431..0813bd913c8fdb2001963ce3e82c07c2af105418 100644 +--- a/src/main/java/org/bukkit/entity/TNTPrimed.java ++++ b/src/main/java/org/bukkit/entity/TNTPrimed.java +@@ -53,4 +53,15 @@ public interface TNTPrimed extends Explosive { + * @param source the source of this primed TNT + */ + public void setSource(@Nullable Entity source); ++ ++ /** ++ * Gets the source block location of the TNTPrimed ++ * ++ * @return the source block location the TNTPrimed was spawned from ++ * @deprecated replaced by {@link Entity#getOrigin()} ++ */ ++ @Deprecated ++ default org.bukkit.Location getSourceLoc() { ++ return this.getOrigin(); ++ } + } diff --git a/patches/api/0017-Add-view-distance-API.patch b/patches/api/0017-Add-view-distance-API.patch new file mode 100644 index 000000000000..562b99a9f16a --- /dev/null +++ b/patches/api/0017-Add-view-distance-API.patch @@ -0,0 +1,167 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Byteflux +Date: Mon, 29 Feb 2016 18:05:37 -0600 +Subject: [PATCH] Add view distance API + +Add per player no-tick, tick, and send view distances. + +Also add send/no-tick view distance to World. + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index ed87e82eb0e30bdea6f7760bb80addcb3bbe59cc..683357f685b1d5f52151a5e78fc5265ebf9d32c2 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -2968,6 +2968,66 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @NotNull + public Set getFeatureFlags(); + ++ // Paper start - view distance api ++ /** ++ * Sets the view distance for this world. ++ * @param viewDistance view distance in [2, 32] ++ */ ++ void setViewDistance(int viewDistance); ++ ++ /** ++ * Sets the simulation distance for this world. ++ * @param simulationDistance simulation distance in [2, 32] ++ */ ++ void setSimulationDistance(int simulationDistance); ++ ++ /** ++ * Returns the no-tick view distance for this world. ++ *

      ++ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not ++ * be set to tick. ++ *

      ++ * @return The no-tick view distance for this world. ++ * @deprecated Use {@link #getViewDistance()} ++ */ ++ @Deprecated ++ default int getNoTickViewDistance() { ++ return this.getViewDistance(); ++ } ++ ++ /** ++ * Sets the no-tick view distance for this world. ++ *

      ++ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not ++ * be set to tick. ++ *

      ++ * @param viewDistance view distance in [2, 32] ++ * @deprecated Use {@link #setViewDistance(int)} ++ */ ++ @Deprecated ++ default void setNoTickViewDistance(int viewDistance) { ++ this.setViewDistance(viewDistance); ++ } ++ ++ /** ++ * Gets the sending view distance for this world. ++ *

      ++ * Sending view distance is the view distance where chunks will load in for players in this world. ++ *

      ++ * @return The sending view distance for this world. ++ */ ++ int getSendViewDistance(); ++ ++ /** ++ * Sets the sending view distance for this world. ++ *

      ++ * Sending view distance is the view distance where chunks will load in for players in this world. ++ *

      ++ * @param viewDistance view distance in [2, 32] or -1 ++ */ ++ void setSendViewDistance(int viewDistance); ++ // Paper end - view distance api ++ + /** + * Gets all generated structures that intersect the chunk at the given + * coordinates.
      +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index bc64083c02bce93a22521173c9430eb5469ba8a6..2073aca572a1b751e895373f32fffba0edf026a5 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -2637,6 +2637,82 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param affects Whether the player can affect mob spawning + */ + public void setAffectsSpawning(boolean affects); ++ ++ /** ++ * Gets the view distance for this player ++ * ++ * @return the player's view distance ++ * @see org.bukkit.World#getViewDistance() ++ */ ++ public int getViewDistance(); ++ ++ /** ++ * Sets the view distance for this player ++ * ++ * @param viewDistance the player's view distance ++ * @see org.bukkit.World#setViewDistance(int) ++ */ ++ public void setViewDistance(int viewDistance); ++ ++ /** ++ * Gets the simulation distance for this player ++ * ++ * @return the player's simulation distance ++ */ ++ public int getSimulationDistance(); ++ ++ /** ++ * Sets the simulation distance for this player ++ * ++ * @param simulationDistance the player's new simulation distance ++ */ ++ public void setSimulationDistance(int simulationDistance); ++ ++ /** ++ * Gets the no-ticking view distance for this player. ++ *

      ++ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not ++ * be set to tick. ++ *

      ++ * @return The no-tick view distance for this player. ++ * @deprecated Use {@link #getViewDistance()} ++ */ ++ @Deprecated ++ default int getNoTickViewDistance() { ++ return this.getViewDistance(); ++ } ++ ++ /** ++ * Sets the no-ticking view distance for this player. ++ *

      ++ * No-tick view distance is the view distance where chunks will load, however the chunks and their entities will not ++ * be set to tick. ++ *

      ++ * @param viewDistance view distance in [2, 32] or -1 ++ * @deprecated Use {@link #setViewDistance(int)} ++ */ ++ @Deprecated ++ default void setNoTickViewDistance(int viewDistance) { ++ this.setViewDistance(viewDistance); ++ } ++ ++ /** ++ * Gets the sending view distance for this player. ++ *

      ++ * Sending view distance is the view distance where chunks will load in for players. ++ *

      ++ * @return The sending view distance for this player. ++ */ ++ public int getSendViewDistance(); ++ ++ /** ++ * Sets the sending view distance for this player. ++ *

      ++ * Sending view distance is the view distance where chunks will load in for players. ++ *

      ++ * @param viewDistance view distance in [2, 32] or -1 ++ */ ++ public void setSendViewDistance(int viewDistance); + // Paper end + + /** diff --git a/patches/api/0017-Automatically-disable-plugins-that-fail-to-load.patch b/patches/api/0017-Automatically-disable-plugins-that-fail-to-load.patch deleted file mode 100644 index 61b71bb09373..000000000000 --- a/patches/api/0017-Automatically-disable-plugins-that-fail-to-load.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 29 Feb 2016 19:45:21 -0600 -Subject: [PATCH] Automatically disable plugins that fail to load - - -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index 333c47a1f7e9d7ddf91aad5ec15163427f7b8039..5eb24f38f158d43fb42836b83c108f808c89512e 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -335,6 +335,10 @@ public final class JavaPluginLoader implements PluginLoader { - jPlugin.setEnabled(true); - } catch (Throwable ex) { - server.getLogger().log(Level.SEVERE, "Error occurred while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); -+ // Paper start - Disable plugins that fail to load -+ this.server.getPluginManager().disablePlugin(jPlugin); -+ return; -+ // Paper end - } - - // Perhaps abort here, rather than continue going, but as it stands, diff --git a/patches/api/0018-Add-BeaconEffectEvent.patch b/patches/api/0018-Add-BeaconEffectEvent.patch new file mode 100644 index 000000000000..15619bb49566 --- /dev/null +++ b/patches/api/0018-Add-BeaconEffectEvent.patch @@ -0,0 +1,100 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Byteflux +Date: Mon, 29 Feb 2016 18:09:40 -0600 +Subject: [PATCH] Add BeaconEffectEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java b/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..741d0e73bc635a545c94c4b1254cee8f41ba8925 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/block/BeaconEffectEvent.java +@@ -0,0 +1,88 @@ ++package com.destroystokyo.paper.event.block; ++ ++import org.bukkit.block.Block; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.bukkit.potion.PotionEffect; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a beacon effect is being applied to a player. ++ */ ++@NullMarked ++public class BeaconEffectEvent extends BlockEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Player player; ++ private final boolean primary; ++ private PotionEffect effect; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public BeaconEffectEvent(final Block block, final PotionEffect effect, final Player player, final boolean primary) { ++ super(block); ++ this.effect = effect; ++ this.player = player; ++ this.primary = primary; ++ } ++ ++ /** ++ * Gets the potion effect being applied. ++ * ++ * @return Potion effect ++ */ ++ public PotionEffect getEffect() { ++ return this.effect; ++ } ++ ++ /** ++ * Sets the potion effect that will be applied. ++ * ++ * @param effect Potion effect ++ */ ++ public void setEffect(final PotionEffect effect) { ++ this.effect = effect; ++ } ++ ++ /** ++ * Gets the player who the potion effect is being applied to. ++ * ++ * @return Affected player ++ */ ++ public Player getPlayer() { ++ return this.player; ++ } ++ ++ /** ++ * Gets whether the effect is a primary beacon effect. ++ * ++ * @return {@code true} if this event represents a primary effect ++ */ ++ public boolean isPrimary() { ++ return this.primary; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0018-Expose-server-CommandMap.patch b/patches/api/0018-Expose-server-CommandMap.patch deleted file mode 100644 index 49cd011dd36b..000000000000 --- a/patches/api/0018-Expose-server-CommandMap.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: kashike -Date: Mon, 29 Feb 2016 19:48:59 -0600 -Subject: [PATCH] Expose server CommandMap - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index fcdce3b516821d42327452790cc66663e4677613..d225e4a5587aa76a85a4b56e11d4563bdc97fe3f 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2077,6 +2077,19 @@ public final class Bukkit { - return server.getUnsafe(); - } - -+ -+ // Paper start -+ /** -+ * Gets the active {@link org.bukkit.command.CommandMap} -+ * -+ * @return the active command map -+ */ -+ @NotNull -+ public static org.bukkit.command.CommandMap getCommandMap() { -+ return server.getCommandMap(); -+ } -+ // Paper end -+ - @NotNull - public static Server.Spigot spigot() { - return server.spigot(); -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index f52dd4c4602638bf02f676f6415d7051c0439cce..f6f3297231d3a9e9f142faf992437cc99e241109 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1602,6 +1602,15 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - public double[] getTPS(); - // Paper end - -+ // Paper start -+ /** -+ * Gets the active {@link org.bukkit.command.CommandMap} -+ * -+ * @return the active command map -+ */ -+ @NotNull -+ org.bukkit.command.CommandMap getCommandMap(); -+ - /** - * Get the advancement specified by this key. - * diff --git a/patches/api/0019-Expose-server-CommandMap.patch b/patches/api/0019-Expose-server-CommandMap.patch new file mode 100644 index 000000000000..9fa19450c816 --- /dev/null +++ b/patches/api/0019-Expose-server-CommandMap.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kashike +Date: Mon, 29 Feb 2016 19:48:59 -0600 +Subject: [PATCH] Expose server CommandMap + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 75e0c5b884363be03876103e0d66e67de03c4856..81b3800e86bcd20b47df13e9c9ef3a83abfcb7c6 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2361,6 +2361,19 @@ public final class Bukkit { + return server.getUnsafe(); + } + ++ ++ // Paper start ++ /** ++ * Gets the active {@link org.bukkit.command.CommandMap} ++ * ++ * @return the active command map ++ */ ++ @NotNull ++ public static org.bukkit.command.CommandMap getCommandMap() { ++ return server.getCommandMap(); ++ } ++ // Paper end ++ + @NotNull + public static Server.Spigot spigot() { + return server.spigot(); +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 2ed640d5a0027f7a94a5cf4555741c27c9b1b3a4..1b18d3916f3972675d9371ec5c6e020d70a723f6 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1835,6 +1835,15 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + public double[] getTPS(); + // Paper end + ++ // Paper start ++ /** ++ * Gets the active {@link org.bukkit.command.CommandMap} ++ * ++ * @return the active command map ++ */ ++ @NotNull ++ org.bukkit.command.CommandMap getCommandMap(); ++ + /** + * Get the advancement specified by this key. + * diff --git a/patches/api/0019-Graduate-bungeecord-chat-API-from-spigot-subclasses.patch b/patches/api/0019-Graduate-bungeecord-chat-API-from-spigot-subclasses.patch deleted file mode 100644 index 503595c80dcf..000000000000 --- a/patches/api/0019-Graduate-bungeecord-chat-API-from-spigot-subclasses.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Mon, 29 Feb 2016 19:54:32 -0600 -Subject: [PATCH] Graduate bungeecord chat API from spigot subclasses - -Change Javadoc to be accurate - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index d225e4a5587aa76a85a4b56e11d4563bdc97fe3f..e13ffa85390f2feda49309ba02ccf75856e4c8f2 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -378,6 +378,30 @@ public final class Bukkit { - return server.broadcastMessage(message); - } - -+ // Paper start -+ /** -+ * Sends the component to all online players. -+ * -+ * @param component the component to send -+ * @deprecated use {@code sendMessage} methods on {@link #getServer()} that accept {@link net.kyori.adventure.text.Component} -+ */ -+ @Deprecated -+ public static void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { -+ server.broadcast(component); -+ } -+ -+ /** -+ * Sends an array of components as a single message to all online players. -+ * -+ * @param components the components to send -+ * @deprecated use {@code sendMessage} methods on {@link #getServer()} that accept {@link net.kyori.adventure.text.Component} -+ */ -+ @Deprecated -+ public static void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { -+ server.broadcast(components); -+ } -+ // Paper end -+ - /** - * Gets the name of the update folder. The update folder is used to safely - * update plugins at the right moment on a plugin load. -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index f6f3297231d3a9e9f142faf992437cc99e241109..1dcf90071bae51e6b767ac26eb6624d372acac68 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -311,6 +311,30 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - @Deprecated // Paper - public int broadcastMessage(@NotNull String message); - -+ // Paper start -+ /** -+ * Sends the component to all online players. -+ * -+ * @param component the component to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} -+ */ -+ @Deprecated -+ public default void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { -+ spigot().broadcast(component); -+ } -+ -+ /** -+ * Sends an array of components as a single message to all online players. -+ * -+ * @param components the components to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} -+ */ -+ @Deprecated -+ public default void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { -+ spigot().broadcast(components); -+ } -+ // Paper end -+ - /** - * Gets the name of the update folder. The update folder is used to safely - * update plugins at the right moment on a plugin load. -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index b362a0e3954a2a58b896a9951f3e31c1706959ec..84172c4356dd15e0d7de611d871584d8bb69b974 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -747,6 +747,42 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - */ - public void sendMap(@NotNull MapView map); - -+ // Paper start -+ /** -+ * Sends the component to the player -+ * -+ * @param component the components to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} -+ */ -+ @Override -+ @Deprecated -+ public default void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { -+ spigot().sendMessage(component); -+ } -+ -+ /** -+ * Sends an array of components as a single message to the player -+ * -+ * @param components the components to send -+ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} -+ */ -+ @Override -+ @Deprecated -+ public default void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { -+ spigot().sendMessage(components); -+ } -+ -+ /** -+ * Sends an array of components as a single message to the specified screen position of this player -+ * -+ * @param position the screen position -+ * @param components the components to send -+ */ -+ public default void sendMessage(net.md_5.bungee.api.ChatMessageType position, net.md_5.bungee.api.chat.BaseComponent... components) { -+ spigot().sendMessage(position, components); -+ } -+ // Paper end -+ - /** - * Forces an update of the player's entire inventory. - * diff --git a/patches/api/0020-Add-exception-reporting-event.patch b/patches/api/0020-Add-exception-reporting-event.patch deleted file mode 100644 index 6b6b666c7953..000000000000 --- a/patches/api/0020-Add-exception-reporting-event.patch +++ /dev/null @@ -1,579 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Mon, 29 Feb 2016 20:24:35 -0600 -Subject: [PATCH] Add exception reporting event - - -diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..306dbd975e9380c22dae0dad526725cc47a36f16 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java -@@ -0,0 +1,42 @@ -+package com.destroystokyo.paper.event.server; -+ -+import com.google.common.base.Preconditions; -+import org.bukkit.Bukkit; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import com.destroystokyo.paper.exception.ServerException; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called whenever an exception is thrown in a recoverable section of the server. -+ */ -+public class ServerExceptionEvent extends Event { -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull private ServerException exception; -+ -+ public ServerExceptionEvent(@NotNull ServerException exception) { -+ super(!Bukkit.isPrimaryThread()); -+ this.exception = Preconditions.checkNotNull(exception, "exception"); -+ } -+ -+ /** -+ * Gets the wrapped exception that was thrown. -+ * -+ * @return Exception thrown -+ */ -+ @NotNull -+ public ServerException getException() { -+ return exception; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerCommandException.java b/src/main/java/com/destroystokyo/paper/exception/ServerCommandException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6fb39af0479a818f7f1465bcdfe505ab4ff7da1a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/exception/ServerCommandException.java -@@ -0,0 +1,64 @@ -+package com.destroystokyo.paper.exception; -+ -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+ -+import static com.google.common.base.Preconditions.checkNotNull; -+ -+/** -+ * Thrown when a command throws an exception -+ */ -+public class ServerCommandException extends ServerException { -+ -+ private final Command command; -+ private final CommandSender commandSender; -+ private final String[] arguments; -+ -+ public ServerCommandException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) { -+ super(message, cause); -+ this.commandSender = checkNotNull(commandSender, "commandSender"); -+ this.arguments = checkNotNull(arguments, "arguments"); -+ this.command = checkNotNull(command, "command"); -+ } -+ -+ public ServerCommandException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) { -+ super(cause); -+ this.commandSender = checkNotNull(commandSender, "commandSender"); -+ this.arguments = checkNotNull(arguments, "arguments"); -+ this.command = checkNotNull(command, "command"); -+ } -+ -+ protected ServerCommandException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) { -+ super(message, cause, enableSuppression, writableStackTrace); -+ this.commandSender = checkNotNull(commandSender, "commandSender"); -+ this.arguments = checkNotNull(arguments, "arguments"); -+ this.command = checkNotNull(command, "command"); -+ } -+ -+ /** -+ * Gets the command which threw the exception -+ * -+ * @return exception throwing command -+ */ -+ public Command getCommand() { -+ return command; -+ } -+ -+ /** -+ * Gets the command sender which executed the command request -+ * -+ * @return command sender of exception thrown command request -+ */ -+ public CommandSender getCommandSender() { -+ return commandSender; -+ } -+ -+ /** -+ * Gets the arguments which threw the exception for the command -+ * -+ * @return arguments of exception thrown command request -+ */ -+ public String[] getArguments() { -+ return arguments; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerEventException.java b/src/main/java/com/destroystokyo/paper/exception/ServerEventException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..410b24139535cd5d8439ad581c43c61b5757fbf6 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/exception/ServerEventException.java -@@ -0,0 +1,52 @@ -+package com.destroystokyo.paper.exception; -+ -+import org.bukkit.event.Event; -+import org.bukkit.event.Listener; -+import org.bukkit.plugin.Plugin; -+ -+import static com.google.common.base.Preconditions.*; -+ -+/** -+ * Exception thrown when a server event listener throws an exception -+ */ -+public class ServerEventException extends ServerPluginException { -+ -+ private final Listener listener; -+ private final Event event; -+ -+ public ServerEventException(String message, Throwable cause, Plugin responsiblePlugin, Listener listener, Event event) { -+ super(message, cause, responsiblePlugin); -+ this.listener = checkNotNull(listener, "listener"); -+ this.event = checkNotNull(event, "event"); -+ } -+ -+ public ServerEventException(Throwable cause, Plugin responsiblePlugin, Listener listener, Event event) { -+ super(cause, responsiblePlugin); -+ this.listener = checkNotNull(listener, "listener"); -+ this.event = checkNotNull(event, "event"); -+ } -+ -+ protected ServerEventException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin, Listener listener, Event event) { -+ super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin); -+ this.listener = checkNotNull(listener, "listener"); -+ this.event = checkNotNull(event, "event"); -+ } -+ -+ /** -+ * Gets the listener which threw the exception -+ * -+ * @return event listener -+ */ -+ public Listener getListener() { -+ return listener; -+ } -+ -+ /** -+ * Gets the event which caused the exception -+ * -+ * @return event -+ */ -+ public Event getEvent() { -+ return event; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerException.java b/src/main/java/com/destroystokyo/paper/exception/ServerException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c06ea3942447d4824b83ff839cb449fb818dede1 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/exception/ServerException.java -@@ -0,0 +1,23 @@ -+package com.destroystokyo.paper.exception; -+ -+/** -+ * Wrapper exception for all exceptions that are thrown by the server. -+ */ -+public class ServerException extends Exception { -+ -+ public ServerException(String message) { -+ super(message); -+ } -+ -+ public ServerException(String message, Throwable cause) { -+ super(message, cause); -+ } -+ -+ public ServerException(Throwable cause) { -+ super(cause); -+ } -+ -+ protected ServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { -+ super(message, cause, enableSuppression, writableStackTrace); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerInternalException.java b/src/main/java/com/destroystokyo/paper/exception/ServerInternalException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e762ed0dbad51625e65fef2e1898679108459a36 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/exception/ServerInternalException.java -@@ -0,0 +1,35 @@ -+package com.destroystokyo.paper.exception; -+ -+import org.bukkit.Bukkit; -+import com.destroystokyo.paper.event.server.ServerExceptionEvent; -+ -+/** -+ * Thrown when the internal server throws a recoverable exception. -+ */ -+public class ServerInternalException extends ServerException { -+ -+ public ServerInternalException(String message) { -+ super(message); -+ } -+ -+ public ServerInternalException(String message, Throwable cause) { -+ super(message, cause); -+ } -+ -+ public ServerInternalException(Throwable cause) { -+ super(cause); -+ } -+ -+ protected ServerInternalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { -+ super(message, cause, enableSuppression, writableStackTrace); -+ } -+ -+ public static void reportInternalException(Throwable cause) { -+ try { -+ Bukkit.getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(cause))); -+ ; -+ } catch (Throwable t) { -+ t.printStackTrace(); // Don't want to rethrow! -+ } -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginEnableDisableException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginEnableDisableException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f016ba3b1b62e554a9bacbb9635f2dbe441b3c4e ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginEnableDisableException.java -@@ -0,0 +1,20 @@ -+package com.destroystokyo.paper.exception; -+ -+import org.bukkit.plugin.Plugin; -+ -+/** -+ * Thrown whenever there is an exception with any enabling or disabling of plugins. -+ */ -+public class ServerPluginEnableDisableException extends ServerPluginException { -+ public ServerPluginEnableDisableException(String message, Throwable cause, Plugin responsiblePlugin) { -+ super(message, cause, responsiblePlugin); -+ } -+ -+ public ServerPluginEnableDisableException(Throwable cause, Plugin responsiblePlugin) { -+ super(cause, responsiblePlugin); -+ } -+ -+ protected ServerPluginEnableDisableException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) { -+ super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin); -+ } -+} -\ No newline at end of file -diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..be3f92e3c6bcefe8b78da701b75121275001882e ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginException.java -@@ -0,0 +1,36 @@ -+package com.destroystokyo.paper.exception; -+ -+import org.bukkit.plugin.Plugin; -+ -+import static com.google.common.base.Preconditions.checkNotNull; -+ -+/** -+ * Wrapper exception for all cases to which a plugin can be immediately blamed for -+ */ -+public class ServerPluginException extends ServerException { -+ public ServerPluginException(String message, Throwable cause, Plugin responsiblePlugin) { -+ super(message, cause); -+ this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin"); -+ } -+ -+ public ServerPluginException(Throwable cause, Plugin responsiblePlugin) { -+ super(cause); -+ this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin"); -+ } -+ -+ protected ServerPluginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) { -+ super(message, cause, enableSuppression, writableStackTrace); -+ this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin"); -+ } -+ -+ private final Plugin responsiblePlugin; -+ -+ /** -+ * Gets the plugin which is directly responsible for the exception being thrown -+ * -+ * @return plugin which is responsible for the exception throw -+ */ -+ public Plugin getResponsiblePlugin() { -+ return responsiblePlugin; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..89e132525cfae0ce979e37b3e2793df781e47227 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java -@@ -0,0 +1,64 @@ -+package com.destroystokyo.paper.exception; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.plugin.Plugin; -+ -+import static com.google.common.base.Preconditions.*; -+ -+/** -+ * Thrown when an incoming plugin message channel throws an exception -+ */ -+public class ServerPluginMessageException extends ServerPluginException { -+ -+ private final Player player; -+ private final String channel; -+ private final byte[] data; -+ -+ public ServerPluginMessageException(String message, Throwable cause, Plugin responsiblePlugin, Player player, String channel, byte[] data) { -+ super(message, cause, responsiblePlugin); -+ this.player = checkNotNull(player, "player"); -+ this.channel = checkNotNull(channel, "channel"); -+ this.data = checkNotNull(data, "data"); -+ } -+ -+ public ServerPluginMessageException(Throwable cause, Plugin responsiblePlugin, Player player, String channel, byte[] data) { -+ super(cause, responsiblePlugin); -+ this.player = checkNotNull(player, "player"); -+ this.channel = checkNotNull(channel, "channel"); -+ this.data = checkNotNull(data, "data"); -+ } -+ -+ protected ServerPluginMessageException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin, Player player, String channel, byte[] data) { -+ super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin); -+ this.player = checkNotNull(player, "player"); -+ this.channel = checkNotNull(channel, "channel"); -+ this.data = checkNotNull(data, "data"); -+ } -+ -+ /** -+ * Gets the channel to which the error occurred from recieving data from -+ * -+ * @return exception channel -+ */ -+ public String getChannel() { -+ return channel; -+ } -+ -+ /** -+ * Gets the data to which the error occurred from -+ * -+ * @return exception data -+ */ -+ public byte[] getData() { -+ return data; -+ } -+ -+ /** -+ * Gets the player which the plugin message causing the exception originated from -+ * -+ * @return exception player -+ */ -+ public Player getPlayer() { -+ return player; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerSchedulerException.java b/src/main/java/com/destroystokyo/paper/exception/ServerSchedulerException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2d0b2d4a9b3e5bdeec0e4ea7ab69858d86aa3715 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/exception/ServerSchedulerException.java -@@ -0,0 +1,37 @@ -+package com.destroystokyo.paper.exception; -+ -+import org.bukkit.scheduler.BukkitTask; -+ -+import static com.google.common.base.Preconditions.checkNotNull; -+ -+/** -+ * Thrown when a plugin's scheduler fails with an exception -+ */ -+public class ServerSchedulerException extends ServerPluginException { -+ -+ private final BukkitTask task; -+ -+ public ServerSchedulerException(String message, Throwable cause, BukkitTask task) { -+ super(message, cause, task.getOwner()); -+ this.task = checkNotNull(task, "task"); -+ } -+ -+ public ServerSchedulerException(Throwable cause, BukkitTask task) { -+ super(cause, task.getOwner()); -+ this.task = checkNotNull(task, "task"); -+ } -+ -+ protected ServerSchedulerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, BukkitTask task) { -+ super(message, cause, enableSuppression, writableStackTrace, task.getOwner()); -+ this.task = checkNotNull(task, "task"); -+ } -+ -+ /** -+ * Gets the task which threw the exception -+ * -+ * @return exception throwing task -+ */ -+ public BukkitTask getTask() { -+ return task; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerTabCompleteException.java b/src/main/java/com/destroystokyo/paper/exception/ServerTabCompleteException.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5582999fe94c7a3dac655044ccc6d078cd9521a1 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/exception/ServerTabCompleteException.java -@@ -0,0 +1,22 @@ -+package com.destroystokyo.paper.exception; -+ -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+ -+/** -+ * Called when a tab-complete request throws an exception -+ */ -+public class ServerTabCompleteException extends ServerCommandException { -+ -+ public ServerTabCompleteException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) { -+ super(message, cause, command, commandSender, arguments); -+ } -+ -+ public ServerTabCompleteException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) { -+ super(cause, command, commandSender, arguments); -+ } -+ -+ protected ServerTabCompleteException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) { -+ super(message, cause, enableSuppression, writableStackTrace, command, commandSender, arguments); -+ } -+} -diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java -index f99d71301ceaa3af07ff0525f7d657ac6253d0e6..2e23c124311b38aaea64dd274c33afcd52edcf43 100644 ---- a/src/main/java/org/bukkit/command/SimpleCommandMap.java -+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java -@@ -155,11 +155,14 @@ public class SimpleCommandMap implements CommandMap { - target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length)); - } // target.timings.stopTiming(); // Spigot // Paper - } catch (CommandException ex) { -+ server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper - //target.timings.stopTiming(); // Spigot // Paper - throw ex; - } catch (Throwable ex) { - //target.timings.stopTiming(); // Spigot // Paper -- throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex); -+ String msg = "Unhandled exception executing '" + commandLine + "' in " + target; -+ server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper -+ throw new CommandException(msg, ex); - } - - // return true as command was handled -@@ -238,7 +241,9 @@ public class SimpleCommandMap implements CommandMap { - } catch (CommandException ex) { - throw ex; - } catch (Throwable ex) { -- throw new CommandException("Unhandled exception executing tab-completer for '" + cmdLine + "' in " + target, ex); -+ String msg = "Unhandled exception executing tab-completer for '" + cmdLine + "' in " + target; -+ server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerTabCompleteException(msg, ex, target, sender, args))); // Paper -+ throw new CommandException(msg, ex); - } - } - -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index 50a2e8c138c677c91dad65c850acf840f7517e86..b7cd4b9e4fd5f98aafbc0fe5ad6883eeb50dea56 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -487,7 +487,8 @@ public final class SimplePluginManager implements PluginManager { - try { - plugin.getPluginLoader().enablePlugin(plugin); - } catch (Throwable ex) { -- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); -+ handlePluginException("Error occurred (in the plugin loader) while enabling " -+ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); - } - - HandlerList.bakeAll(); -@@ -508,32 +509,37 @@ public final class SimplePluginManager implements PluginManager { - try { - plugin.getPluginLoader().disablePlugin(plugin); - } catch (Throwable ex) { -- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); -+ handlePluginException("Error occurred (in the plugin loader) while disabling " -+ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper - } - - try { - server.getScheduler().cancelTasks(plugin); - } catch (Throwable ex) { -- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while cancelling tasks for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); -+ handlePluginException("Error occurred (in the plugin loader) while cancelling tasks for " -+ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper - } - - try { - server.getServicesManager().unregisterAll(plugin); - } catch (Throwable ex) { -- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering services for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); -+ handlePluginException("Error occurred (in the plugin loader) while unregistering services for " -+ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper - } - - try { - HandlerList.unregisterAll(plugin); - } catch (Throwable ex) { -- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering events for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); -+ handlePluginException("Error occurred (in the plugin loader) while unregistering events for " -+ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper - } - - try { - server.getMessenger().unregisterIncomingPluginChannel(plugin); - server.getMessenger().unregisterOutgoingPluginChannel(plugin); - } catch (Throwable ex) { -- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering plugin channels for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); -+ handlePluginException("Error occurred (in the plugin loader) while unregistering plugin channels for " -+ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper - } - - try { -@@ -546,6 +552,13 @@ public final class SimplePluginManager implements PluginManager { - } - } - -+ // Paper start -+ private void handlePluginException(String msg, Throwable ex, Plugin plugin) { -+ server.getLogger().log(Level.SEVERE, msg, ex); -+ callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerPluginEnableDisableException(msg, ex, plugin))); -+ } -+ // Paper end -+ - @Override - public void clearPlugins() { - synchronized (this) { -@@ -609,7 +622,13 @@ public final class SimplePluginManager implements PluginManager { - )); - } - } catch (Throwable ex) { -- server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName(), ex); -+ // Paper start - error reporting -+ String msg = "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName(); -+ server.getLogger().log(Level.SEVERE, msg, ex); -+ if (!(event instanceof com.destroystokyo.paper.event.server.ServerExceptionEvent)) { // We don't want to cause an endless event loop -+ callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event))); -+ } -+ // Paper end - } - } - } diff --git a/patches/api/0020-Graduate-bungeecord-chat-API-from-spigot-subclasses.patch b/patches/api/0020-Graduate-bungeecord-chat-API-from-spigot-subclasses.patch new file mode 100644 index 000000000000..9aa815bb7799 --- /dev/null +++ b/patches/api/0020-Graduate-bungeecord-chat-API-from-spigot-subclasses.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Mon, 29 Feb 2016 19:54:32 -0600 +Subject: [PATCH] Graduate bungeecord chat API from spigot subclasses + +Change Javadoc to be accurate + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 81b3800e86bcd20b47df13e9c9ef3a83abfcb7c6..1ada54827acfaacab0a32ae5d55def952547c352 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -472,6 +472,30 @@ public final class Bukkit { + return server.broadcastMessage(message); + } + ++ // Paper start ++ /** ++ * Sends the component to all online players. ++ * ++ * @param component the component to send ++ * @deprecated use {@code sendMessage} methods on {@link #getServer()} that accept {@link net.kyori.adventure.text.Component} ++ */ ++ @Deprecated ++ public static void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { ++ server.broadcast(component); ++ } ++ ++ /** ++ * Sends an array of components as a single message to all online players. ++ * ++ * @param components the components to send ++ * @deprecated use {@code sendMessage} methods on {@link #getServer()} that accept {@link net.kyori.adventure.text.Component} ++ */ ++ @Deprecated ++ public static void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { ++ server.broadcast(components); ++ } ++ // Paper end ++ + /** + * Gets the name of the update folder. The update folder is used to safely + * update plugins at the right moment on a plugin load. +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 1b18d3916f3972675d9371ec5c6e020d70a723f6..93d924c586803161820707af823c352f7c5d40e1 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -383,6 +383,30 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @Deprecated // Paper + public int broadcastMessage(@NotNull String message); + ++ // Paper start ++ /** ++ * Sends the component to all online players. ++ * ++ * @param component the component to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} ++ */ ++ @Deprecated ++ public default void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { ++ spigot().broadcast(component); ++ } ++ ++ /** ++ * Sends an array of components as a single message to all online players. ++ * ++ * @param components the components to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} ++ */ ++ @Deprecated ++ public default void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { ++ spigot().broadcast(components); ++ } ++ // Paper end ++ + /** + * Gets the name of the update folder. The update folder is used to safely + * update plugins at the right moment on a plugin load. +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 2073aca572a1b751e895373f32fffba0edf026a5..17f55697d02d7b9c9b42c4b89a33db9207622a36 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -1254,6 +1254,42 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public void sendMap(@NotNull MapView map); + ++ // Paper start ++ /** ++ * Sends the component to the player ++ * ++ * @param component the components to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} ++ */ ++ @Override ++ @Deprecated ++ public default void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { ++ spigot().sendMessage(component); ++ } ++ ++ /** ++ * Sends an array of components as a single message to the player ++ * ++ * @param components the components to send ++ * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} ++ */ ++ @Override ++ @Deprecated ++ public default void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { ++ spigot().sendMessage(components); ++ } ++ ++ /** ++ * Sends an array of components as a single message to the specified screen position of this player ++ * ++ * @param position the screen position ++ * @param components the components to send ++ */ ++ public default void sendMessage(net.md_5.bungee.api.ChatMessageType position, net.md_5.bungee.api.chat.BaseComponent... components) { ++ spigot().sendMessage(position, components); ++ } ++ // Paper end ++ + /** + * Send a hurt animation. This fakes incoming damage towards the player from + * the given yaw relative to the player's direction. diff --git a/patches/api/0021-Add-BaseComponent-sendMessage-methods-to-CommandSend.patch b/patches/api/0021-Add-BaseComponent-sendMessage-methods-to-CommandSend.patch deleted file mode 100644 index 3e85e8a7ae0c..000000000000 --- a/patches/api/0021-Add-BaseComponent-sendMessage-methods-to-CommandSend.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: kashike -Date: Tue, 8 Mar 2016 13:05:59 -0800 -Subject: [PATCH] Add BaseComponent sendMessage methods to CommandSender - - -diff --git a/src/main/java/org/bukkit/command/CommandSender.java b/src/main/java/org/bukkit/command/CommandSender.java -index ec97093a4410322ad44e111d894a3b1a5c5f7b88..f3cf27e075ea01d9d825aead3782db66cd4f2c3b 100644 ---- a/src/main/java/org/bukkit/command/CommandSender.java -+++ b/src/main/java/org/bukkit/command/CommandSender.java -@@ -1,6 +1,9 @@ - package org.bukkit.command; - - import java.util.UUID; -+import net.kyori.adventure.audience.MessageType; -+import net.kyori.adventure.identity.Identity; -+import net.kyori.adventure.text.Component; - import org.bukkit.Server; - import org.bukkit.permissions.Permissible; - import org.jetbrains.annotations.NotNull; -@@ -145,5 +148,33 @@ public interface CommandSender extends net.kyori.adventure.audience.Audience, Pe - default void sendPlainMessage(final @NotNull String message) { - this.sendMessage(net.kyori.adventure.text.Component.text(message)); - } -+ -+ /** -+ * Sends the component to the sender -+ * -+ *

      If this sender does not support sending full components then -+ * the component will be sent as legacy text.

      -+ * -+ * @param component the component to send -+ * @deprecated use {@link #sendMessage(Identity, Component, MessageType)} instead -+ */ -+ @Deprecated -+ default void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { -+ this.sendMessage(component.toLegacyText()); -+ } -+ -+ /** -+ * Sends an array of components as a single message to the sender -+ * -+ *

      If this sender does not support sending full components then -+ * the components will be sent as legacy text.

      -+ * -+ * @param components the components to send -+ * @deprecated use {@link #sendMessage(Identity, Component, MessageType)} instead -+ */ -+ @Deprecated -+ default void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { -+ this.sendMessage(new net.md_5.bungee.api.chat.TextComponent(components).toLegacyText()); -+ } - // Paper end - } diff --git a/patches/api/0021-Add-exception-reporting-event.patch b/patches/api/0021-Add-exception-reporting-event.patch new file mode 100644 index 000000000000..c446fdb186c3 --- /dev/null +++ b/patches/api/0021-Add-exception-reporting-event.patch @@ -0,0 +1,581 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Mon, 29 Feb 2016 20:24:35 -0600 +Subject: [PATCH] Add exception reporting event + + +diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..95a5a59e6bd88345177fca0b12008ddd689cb448 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/server/ServerExceptionEvent.java +@@ -0,0 +1,43 @@ ++package com.destroystokyo.paper.event.server; ++ ++import com.destroystokyo.paper.exception.ServerException; ++import org.bukkit.Bukkit; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called whenever an exception is thrown in a recoverable section of the server. ++ */ ++@NullMarked ++public class ServerExceptionEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ServerException exception; ++ ++ @ApiStatus.Internal ++ public ServerExceptionEvent(final ServerException exception) { ++ super(!Bukkit.isPrimaryThread()); ++ this.exception = exception; ++ } ++ ++ /** ++ * Gets the wrapped exception that was thrown. ++ * ++ * @return Exception thrown ++ */ ++ public ServerException getException() { ++ return this.exception; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerCommandException.java b/src/main/java/com/destroystokyo/paper/exception/ServerCommandException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6fb39af0479a818f7f1465bcdfe505ab4ff7da1a +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerCommandException.java +@@ -0,0 +1,64 @@ ++package com.destroystokyo.paper.exception; ++ ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandSender; ++ ++import static com.google.common.base.Preconditions.checkNotNull; ++ ++/** ++ * Thrown when a command throws an exception ++ */ ++public class ServerCommandException extends ServerException { ++ ++ private final Command command; ++ private final CommandSender commandSender; ++ private final String[] arguments; ++ ++ public ServerCommandException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) { ++ super(message, cause); ++ this.commandSender = checkNotNull(commandSender, "commandSender"); ++ this.arguments = checkNotNull(arguments, "arguments"); ++ this.command = checkNotNull(command, "command"); ++ } ++ ++ public ServerCommandException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) { ++ super(cause); ++ this.commandSender = checkNotNull(commandSender, "commandSender"); ++ this.arguments = checkNotNull(arguments, "arguments"); ++ this.command = checkNotNull(command, "command"); ++ } ++ ++ protected ServerCommandException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) { ++ super(message, cause, enableSuppression, writableStackTrace); ++ this.commandSender = checkNotNull(commandSender, "commandSender"); ++ this.arguments = checkNotNull(arguments, "arguments"); ++ this.command = checkNotNull(command, "command"); ++ } ++ ++ /** ++ * Gets the command which threw the exception ++ * ++ * @return exception throwing command ++ */ ++ public Command getCommand() { ++ return command; ++ } ++ ++ /** ++ * Gets the command sender which executed the command request ++ * ++ * @return command sender of exception thrown command request ++ */ ++ public CommandSender getCommandSender() { ++ return commandSender; ++ } ++ ++ /** ++ * Gets the arguments which threw the exception for the command ++ * ++ * @return arguments of exception thrown command request ++ */ ++ public String[] getArguments() { ++ return arguments; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerEventException.java b/src/main/java/com/destroystokyo/paper/exception/ServerEventException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..410b24139535cd5d8439ad581c43c61b5757fbf6 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerEventException.java +@@ -0,0 +1,52 @@ ++package com.destroystokyo.paper.exception; ++ ++import org.bukkit.event.Event; ++import org.bukkit.event.Listener; ++import org.bukkit.plugin.Plugin; ++ ++import static com.google.common.base.Preconditions.*; ++ ++/** ++ * Exception thrown when a server event listener throws an exception ++ */ ++public class ServerEventException extends ServerPluginException { ++ ++ private final Listener listener; ++ private final Event event; ++ ++ public ServerEventException(String message, Throwable cause, Plugin responsiblePlugin, Listener listener, Event event) { ++ super(message, cause, responsiblePlugin); ++ this.listener = checkNotNull(listener, "listener"); ++ this.event = checkNotNull(event, "event"); ++ } ++ ++ public ServerEventException(Throwable cause, Plugin responsiblePlugin, Listener listener, Event event) { ++ super(cause, responsiblePlugin); ++ this.listener = checkNotNull(listener, "listener"); ++ this.event = checkNotNull(event, "event"); ++ } ++ ++ protected ServerEventException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin, Listener listener, Event event) { ++ super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin); ++ this.listener = checkNotNull(listener, "listener"); ++ this.event = checkNotNull(event, "event"); ++ } ++ ++ /** ++ * Gets the listener which threw the exception ++ * ++ * @return event listener ++ */ ++ public Listener getListener() { ++ return listener; ++ } ++ ++ /** ++ * Gets the event which caused the exception ++ * ++ * @return event ++ */ ++ public Event getEvent() { ++ return event; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerException.java b/src/main/java/com/destroystokyo/paper/exception/ServerException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c06ea3942447d4824b83ff839cb449fb818dede1 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerException.java +@@ -0,0 +1,23 @@ ++package com.destroystokyo.paper.exception; ++ ++/** ++ * Wrapper exception for all exceptions that are thrown by the server. ++ */ ++public class ServerException extends Exception { ++ ++ public ServerException(String message) { ++ super(message); ++ } ++ ++ public ServerException(String message, Throwable cause) { ++ super(message, cause); ++ } ++ ++ public ServerException(Throwable cause) { ++ super(cause); ++ } ++ ++ protected ServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { ++ super(message, cause, enableSuppression, writableStackTrace); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerInternalException.java b/src/main/java/com/destroystokyo/paper/exception/ServerInternalException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2c3effca7c9d6c904cbe248d312b74e2cd360acf +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerInternalException.java +@@ -0,0 +1,36 @@ ++package com.destroystokyo.paper.exception; ++ ++import java.util.logging.Level; ++import org.bukkit.Bukkit; ++import com.destroystokyo.paper.event.server.ServerExceptionEvent; ++ ++/** ++ * Thrown when the internal server throws a recoverable exception. ++ */ ++public class ServerInternalException extends ServerException { ++ ++ public ServerInternalException(String message) { ++ super(message); ++ } ++ ++ public ServerInternalException(String message, Throwable cause) { ++ super(message, cause); ++ } ++ ++ public ServerInternalException(Throwable cause) { ++ super(cause); ++ } ++ ++ protected ServerInternalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { ++ super(message, cause, enableSuppression, writableStackTrace); ++ } ++ ++ public static void reportInternalException(Throwable cause) { ++ try { ++ Bukkit.getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(cause))); ++ ; ++ } catch (Throwable t) { ++ Bukkit.getLogger().log(Level.WARNING, "Exception posting ServerExceptionEvent", t); // Don't want to rethrow! ++ } ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginEnableDisableException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginEnableDisableException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f016ba3b1b62e554a9bacbb9635f2dbe441b3c4e +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginEnableDisableException.java +@@ -0,0 +1,20 @@ ++package com.destroystokyo.paper.exception; ++ ++import org.bukkit.plugin.Plugin; ++ ++/** ++ * Thrown whenever there is an exception with any enabling or disabling of plugins. ++ */ ++public class ServerPluginEnableDisableException extends ServerPluginException { ++ public ServerPluginEnableDisableException(String message, Throwable cause, Plugin responsiblePlugin) { ++ super(message, cause, responsiblePlugin); ++ } ++ ++ public ServerPluginEnableDisableException(Throwable cause, Plugin responsiblePlugin) { ++ super(cause, responsiblePlugin); ++ } ++ ++ protected ServerPluginEnableDisableException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) { ++ super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin); ++ } ++} +\ No newline at end of file +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..be3f92e3c6bcefe8b78da701b75121275001882e +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginException.java +@@ -0,0 +1,36 @@ ++package com.destroystokyo.paper.exception; ++ ++import org.bukkit.plugin.Plugin; ++ ++import static com.google.common.base.Preconditions.checkNotNull; ++ ++/** ++ * Wrapper exception for all cases to which a plugin can be immediately blamed for ++ */ ++public class ServerPluginException extends ServerException { ++ public ServerPluginException(String message, Throwable cause, Plugin responsiblePlugin) { ++ super(message, cause); ++ this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin"); ++ } ++ ++ public ServerPluginException(Throwable cause, Plugin responsiblePlugin) { ++ super(cause); ++ this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin"); ++ } ++ ++ protected ServerPluginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) { ++ super(message, cause, enableSuppression, writableStackTrace); ++ this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin"); ++ } ++ ++ private final Plugin responsiblePlugin; ++ ++ /** ++ * Gets the plugin which is directly responsible for the exception being thrown ++ * ++ * @return plugin which is responsible for the exception throw ++ */ ++ public Plugin getResponsiblePlugin() { ++ return responsiblePlugin; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2faef4cb358ec65e32a6aba6426f0dd7ddf90d2a +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java +@@ -0,0 +1,64 @@ ++package com.destroystokyo.paper.exception; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.plugin.Plugin; ++ ++import static com.google.common.base.Preconditions.*; ++ ++/** ++ * Thrown when an incoming plugin message channel throws an exception ++ */ ++public class ServerPluginMessageException extends ServerPluginException { ++ ++ private final Player player; ++ private final String channel; ++ private final byte[] data; ++ ++ public ServerPluginMessageException(String message, Throwable cause, Plugin responsiblePlugin, Player player, String channel, byte[] data) { ++ super(message, cause, responsiblePlugin); ++ this.player = checkNotNull(player, "player"); ++ this.channel = checkNotNull(channel, "channel"); ++ this.data = checkNotNull(data, "data"); ++ } ++ ++ public ServerPluginMessageException(Throwable cause, Plugin responsiblePlugin, Player player, String channel, byte[] data) { ++ super(cause, responsiblePlugin); ++ this.player = checkNotNull(player, "player"); ++ this.channel = checkNotNull(channel, "channel"); ++ this.data = checkNotNull(data, "data"); ++ } ++ ++ protected ServerPluginMessageException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin, Player player, String channel, byte[] data) { ++ super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin); ++ this.player = checkNotNull(player, "player"); ++ this.channel = checkNotNull(channel, "channel"); ++ this.data = checkNotNull(data, "data"); ++ } ++ ++ /** ++ * Gets the channel to which the error occurred from receiving data from ++ * ++ * @return exception channel ++ */ ++ public String getChannel() { ++ return channel; ++ } ++ ++ /** ++ * Gets the data to which the error occurred from ++ * ++ * @return exception data ++ */ ++ public byte[] getData() { ++ return data; ++ } ++ ++ /** ++ * Gets the player which the plugin message causing the exception originated from ++ * ++ * @return exception player ++ */ ++ public Player getPlayer() { ++ return player; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerSchedulerException.java b/src/main/java/com/destroystokyo/paper/exception/ServerSchedulerException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2d0b2d4a9b3e5bdeec0e4ea7ab69858d86aa3715 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerSchedulerException.java +@@ -0,0 +1,37 @@ ++package com.destroystokyo.paper.exception; ++ ++import org.bukkit.scheduler.BukkitTask; ++ ++import static com.google.common.base.Preconditions.checkNotNull; ++ ++/** ++ * Thrown when a plugin's scheduler fails with an exception ++ */ ++public class ServerSchedulerException extends ServerPluginException { ++ ++ private final BukkitTask task; ++ ++ public ServerSchedulerException(String message, Throwable cause, BukkitTask task) { ++ super(message, cause, task.getOwner()); ++ this.task = checkNotNull(task, "task"); ++ } ++ ++ public ServerSchedulerException(Throwable cause, BukkitTask task) { ++ super(cause, task.getOwner()); ++ this.task = checkNotNull(task, "task"); ++ } ++ ++ protected ServerSchedulerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, BukkitTask task) { ++ super(message, cause, enableSuppression, writableStackTrace, task.getOwner()); ++ this.task = checkNotNull(task, "task"); ++ } ++ ++ /** ++ * Gets the task which threw the exception ++ * ++ * @return exception throwing task ++ */ ++ public BukkitTask getTask() { ++ return task; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerTabCompleteException.java b/src/main/java/com/destroystokyo/paper/exception/ServerTabCompleteException.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5582999fe94c7a3dac655044ccc6d078cd9521a1 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerTabCompleteException.java +@@ -0,0 +1,22 @@ ++package com.destroystokyo.paper.exception; ++ ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandSender; ++ ++/** ++ * Called when a tab-complete request throws an exception ++ */ ++public class ServerTabCompleteException extends ServerCommandException { ++ ++ public ServerTabCompleteException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) { ++ super(message, cause, command, commandSender, arguments); ++ } ++ ++ public ServerTabCompleteException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) { ++ super(cause, command, commandSender, arguments); ++ } ++ ++ protected ServerTabCompleteException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) { ++ super(message, cause, enableSuppression, writableStackTrace, command, commandSender, arguments); ++ } ++} +diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java +index 36fc2c35395c72f8b81a2a2f3265fd205384ce26..c7fa1d235cea78bda4656ed66b8d42b119cc50fb 100644 +--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java ++++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java +@@ -156,11 +156,14 @@ public class SimpleCommandMap implements CommandMap { + target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length)); + } // target.timings.stopTiming(); // Spigot // Paper + } catch (CommandException ex) { ++ server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper + //target.timings.stopTiming(); // Spigot // Paper + throw ex; + } catch (Throwable ex) { + //target.timings.stopTiming(); // Spigot // Paper +- throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex); ++ String msg = "Unhandled exception executing '" + commandLine + "' in " + target; ++ server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper ++ throw new CommandException(msg, ex); + } + + // return true as command was handled +@@ -239,7 +242,9 @@ public class SimpleCommandMap implements CommandMap { + } catch (CommandException ex) { + throw ex; + } catch (Throwable ex) { +- throw new CommandException("Unhandled exception executing tab-completer for '" + cmdLine + "' in " + target, ex); ++ String msg = "Unhandled exception executing tab-completer for '" + cmdLine + "' in " + target; ++ server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerTabCompleteException(msg, ex, target, sender, args))); // Paper ++ throw new CommandException(msg, ex); + } + } + +diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +index 48b66054913c8b53e6e7fd34615c2ab54727693f..001465eedafa51ac027a4db51cba6223edfe1171 100644 +--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java ++++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java +@@ -528,7 +528,8 @@ public final class SimplePluginManager implements PluginManager { + try { + plugin.getPluginLoader().enablePlugin(plugin); + } catch (Throwable ex) { +- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); ++ handlePluginException("Error occurred (in the plugin loader) while enabling " ++ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); + } + + HandlerList.bakeAll(); +@@ -551,32 +552,37 @@ public final class SimplePluginManager implements PluginManager { + try { + plugin.getPluginLoader().disablePlugin(plugin); + } catch (Throwable ex) { +- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); ++ handlePluginException("Error occurred (in the plugin loader) while disabling " ++ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper + } + + try { + server.getScheduler().cancelTasks(plugin); + } catch (Throwable ex) { +- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while cancelling tasks for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); ++ handlePluginException("Error occurred (in the plugin loader) while cancelling tasks for " ++ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper + } + + try { + server.getServicesManager().unregisterAll(plugin); + } catch (Throwable ex) { +- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering services for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); ++ handlePluginException("Error occurred (in the plugin loader) while unregistering services for " ++ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper + } + + try { + HandlerList.unregisterAll(plugin); + } catch (Throwable ex) { +- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering events for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); ++ handlePluginException("Error occurred (in the plugin loader) while unregistering events for " ++ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper + } + + try { + server.getMessenger().unregisterIncomingPluginChannel(plugin); + server.getMessenger().unregisterOutgoingPluginChannel(plugin); + } catch (Throwable ex) { +- server.getLogger().log(Level.SEVERE, "Error occurred (in the plugin loader) while unregistering plugin channels for " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); ++ handlePluginException("Error occurred (in the plugin loader) while unregistering plugin channels for " ++ + plugin.getDescription().getFullName() + " (Is it up to date?)", ex, plugin); // Paper + } + + try { +@@ -589,6 +595,13 @@ public final class SimplePluginManager implements PluginManager { + } + } + ++ // Paper start ++ private void handlePluginException(String msg, Throwable ex, Plugin plugin) { ++ server.getLogger().log(Level.SEVERE, msg, ex); ++ callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerPluginEnableDisableException(msg, ex, plugin))); ++ } ++ // Paper end ++ + @Override + public void clearPlugins() { + if (true) {this.paperPluginManager.clearPlugins(); return;} // Paper +@@ -654,7 +667,13 @@ public final class SimplePluginManager implements PluginManager { + )); + } + } catch (Throwable ex) { +- server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName(), ex); ++ // Paper start - error reporting ++ String msg = "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName(); ++ server.getLogger().log(Level.SEVERE, msg, ex); ++ if (!(event instanceof com.destroystokyo.paper.event.server.ServerExceptionEvent)) { // We don't want to cause an endless event loop ++ callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event))); ++ } ++ // Paper end + } + } + } diff --git a/patches/api/0022-Add-BaseComponent-sendMessage-methods-to-CommandSend.patch b/patches/api/0022-Add-BaseComponent-sendMessage-methods-to-CommandSend.patch new file mode 100644 index 000000000000..02e7138c1061 --- /dev/null +++ b/patches/api/0022-Add-BaseComponent-sendMessage-methods-to-CommandSend.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kashike +Date: Tue, 8 Mar 2016 13:05:59 -0800 +Subject: [PATCH] Add BaseComponent sendMessage methods to CommandSender + + +diff --git a/src/main/java/org/bukkit/command/CommandSender.java b/src/main/java/org/bukkit/command/CommandSender.java +index 70fec73328227725f519af845ecbdce8be2fa4e2..04e7cd0e4e2d0eb38fb2862ce6688a4470f30d6b 100644 +--- a/src/main/java/org/bukkit/command/CommandSender.java ++++ b/src/main/java/org/bukkit/command/CommandSender.java +@@ -1,6 +1,9 @@ + package org.bukkit.command; + + import java.util.UUID; ++import net.kyori.adventure.audience.MessageType; ++import net.kyori.adventure.identity.Identity; ++import net.kyori.adventure.text.Component; + import org.bukkit.Server; + import org.bukkit.permissions.Permissible; + import org.jetbrains.annotations.NotNull; +@@ -168,5 +171,33 @@ public interface CommandSender extends net.kyori.adventure.audience.Audience, Pe + default void sendPlainMessage(final @NotNull String message) { + this.sendMessage(net.kyori.adventure.text.Component.text(message)); + } ++ ++ /** ++ * Sends the component to the sender ++ * ++ *

      If this sender does not support sending full components then ++ * the component will be sent as legacy text.

      ++ * ++ * @param component the component to send ++ * @deprecated use {@link #sendMessage(Identity, Component, MessageType)} instead ++ */ ++ @Deprecated ++ default void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { ++ this.sendMessage(component.toLegacyText()); ++ } ++ ++ /** ++ * Sends an array of components as a single message to the sender ++ * ++ *

      If this sender does not support sending full components then ++ * the components will be sent as legacy text.

      ++ * ++ * @param components the components to send ++ * @deprecated use {@link #sendMessage(Identity, Component, MessageType)} instead ++ */ ++ @Deprecated ++ default void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { ++ this.sendMessage(new net.md_5.bungee.api.chat.TextComponent(components).toLegacyText()); ++ } + // Paper end + } diff --git a/patches/api/0022-Fix-ServerListPingEvent-flagging-as-Async.patch b/patches/api/0023-Fix-ServerListPingEvent-flagging-as-Async.patch similarity index 100% rename from patches/api/0022-Fix-ServerListPingEvent-flagging-as-Async.patch rename to patches/api/0023-Fix-ServerListPingEvent-flagging-as-Async.patch diff --git a/patches/api/0023-Player-Tab-List-and-Title-APIs.patch b/patches/api/0023-Player-Tab-List-and-Title-APIs.patch deleted file mode 100644 index 7257eb3e8a7f..000000000000 --- a/patches/api/0023-Player-Tab-List-and-Title-APIs.patch +++ /dev/null @@ -1,577 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Techcable -Date: Mon, 29 Feb 2016 20:02:40 -0600 -Subject: [PATCH] Player Tab List and Title APIs - -Co-authored-by: Fruxz - -diff --git a/src/main/java/com/destroystokyo/paper/Title.java b/src/main/java/com/destroystokyo/paper/Title.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9e90c3df567a65b48a0b9341f784eb902cb35d8c ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/Title.java -@@ -0,0 +1,420 @@ -+package com.destroystokyo.paper; -+ -+import net.md_5.bungee.api.chat.BaseComponent; -+import net.md_5.bungee.api.chat.TextComponent; -+ -+import org.bukkit.Bukkit; -+import org.bukkit.entity.Player; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Collection; -+import java.util.List; -+ -+import static com.google.common.base.Preconditions.checkArgument; -+import static com.google.common.base.Preconditions.checkNotNull; -+import static com.google.common.base.Preconditions.checkState; -+ -+/** -+ * Represents a title to may be sent to a {@link Player}. -+ * -+ *

      A title can be sent without subtitle text.

      -+ * -+ * @deprecated use {@link net.kyori.adventure.title.Title} -+ */ -+@Deprecated -+public final class Title { -+ -+ /** -+ * The default number of ticks for the title to fade in. -+ */ -+ public static final int DEFAULT_FADE_IN = 20; -+ /** -+ * The default number of ticks for the title to stay. -+ */ -+ public static final int DEFAULT_STAY = 200; -+ /** -+ * The default number of ticks for the title to fade out. -+ */ -+ public static final int DEFAULT_FADE_OUT = 20; -+ -+ private final BaseComponent[] title; -+ private final BaseComponent[] subtitle; -+ private final int fadeIn; -+ private final int stay; -+ private final int fadeOut; -+ -+ /** -+ * Create a title with the default time values and no subtitle. -+ * -+ *

      Times use default values.

      -+ * -+ * @param title the main text of the title -+ * @throws NullPointerException if the title is null -+ */ -+ public Title(@NotNull BaseComponent title) { -+ this(title, null); -+ } -+ -+ /** -+ * Create a title with the default time values and no subtitle. -+ * -+ *

      Times use default values.

      -+ * -+ * @param title the main text of the title -+ * @throws NullPointerException if the title is null -+ */ -+ public Title(@NotNull BaseComponent[] title) { -+ this(title, null); -+ } -+ -+ /** -+ * Create a title with the default time values and no subtitle. -+ * -+ *

      Times use default values.

      -+ * -+ * @param title the main text of the title -+ * @throws NullPointerException if the title is null -+ */ -+ public Title(@NotNull String title) { -+ this(title, null); -+ } -+ -+ /** -+ * Create a title with the default time values. -+ * -+ *

      Times use default values.

      -+ * -+ * @param title the main text of the title -+ * @param subtitle the secondary text of the title -+ */ -+ public Title(@NotNull BaseComponent title, @Nullable BaseComponent subtitle) { -+ this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT); -+ } -+ -+ /** -+ * Create a title with the default time values. -+ * -+ *

      Times use default values.

      -+ * -+ * @param title the main text of the title -+ * @param subtitle the secondary text of the title -+ */ -+ public Title(@NotNull BaseComponent[] title, @Nullable BaseComponent[] subtitle) { -+ this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT); -+ } -+ -+ /** -+ * Create a title with the default time values. -+ * -+ *

      Times use default values.

      -+ * -+ * @param title the main text of the title -+ * @param subtitle the secondary text of the title -+ */ -+ public Title(@NotNull String title, @Nullable String subtitle) { -+ this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT); -+ } -+ -+ /** -+ * Creates a new title. -+ * -+ * @param title the main text of the title -+ * @param subtitle the secondary text of the title -+ * @param fadeIn the number of ticks for the title to fade in -+ * @param stay the number of ticks for the title to stay on screen -+ * @param fadeOut the number of ticks for the title to fade out -+ * @throws IllegalArgumentException if any of the times are negative -+ */ -+ public Title(@NotNull BaseComponent title, @Nullable BaseComponent subtitle, int fadeIn, int stay, int fadeOut) { -+ this( -+ new BaseComponent[]{checkNotNull(title, "title")}, -+ subtitle == null ? null : new BaseComponent[]{subtitle}, -+ fadeIn, -+ stay, -+ fadeOut -+ ); -+ } -+ -+ /** -+ * Creates a new title. -+ * -+ * @param title the main text of the title -+ * @param subtitle the secondary text of the title -+ * @param fadeIn the number of ticks for the title to fade in -+ * @param stay the number of ticks for the title to stay on screen -+ * @param fadeOut the number of ticks for the title to fade out -+ * @throws IllegalArgumentException if any of the times are negative -+ */ -+ public Title(@Nullable BaseComponent[] title, @NotNull BaseComponent[] subtitle, int fadeIn, int stay, int fadeOut) { -+ checkArgument(fadeIn >= 0, "Negative fadeIn: %s", fadeIn); -+ checkArgument(stay >= 0, "Negative stay: %s", stay); -+ checkArgument(fadeOut >= 0, "Negative fadeOut: %s", fadeOut); -+ this.title = checkNotNull(title, "title"); -+ this.subtitle = subtitle; -+ this.fadeIn = fadeIn; -+ this.stay = stay; -+ this.fadeOut = fadeOut; -+ } -+ -+ /** -+ * Creates a new title. -+ * -+ *

      It is recommended to the {@link BaseComponent} constrctors.

      -+ * -+ * @param title the main text of the title -+ * @param subtitle the secondary text of the title -+ * @param fadeIn the number of ticks for the title to fade in -+ * @param stay the number of ticks for the title to stay on screen -+ * @param fadeOut the number of ticks for the title to fade out -+ */ -+ public Title(@NotNull String title, @Nullable String subtitle, int fadeIn, int stay, int fadeOut) { -+ this( -+ TextComponent.fromLegacyText(checkNotNull(title, "title")), -+ subtitle == null ? null : TextComponent.fromLegacyText(subtitle), -+ fadeIn, -+ stay, -+ fadeOut -+ ); -+ } -+ -+ /** -+ * Gets the text of this title -+ * -+ * @return the text -+ */ -+ @NotNull -+ public BaseComponent[] getTitle() { -+ return this.title; -+ } -+ -+ /** -+ * Gets the text of this title's subtitle -+ * -+ * @return the text -+ */ -+ @Nullable -+ public BaseComponent[] getSubtitle() { -+ return this.subtitle; -+ } -+ -+ /** -+ * Gets the number of ticks to fade in. -+ * -+ *

      The returned value is never negative.

      -+ * -+ * @return the number of ticks to fade in -+ */ -+ public int getFadeIn() { -+ return this.fadeIn; -+ } -+ -+ /** -+ * Gets the number of ticks to stay. -+ * -+ *

      The returned value is never negative.

      -+ * -+ * @return the number of ticks to stay -+ */ -+ public int getStay() { -+ return this.stay; -+ } -+ -+ /** -+ * Gets the number of ticks to fade out. -+ * -+ *

      The returned value is never negative.

      -+ * -+ * @return the number of ticks to fade out -+ */ -+ public int getFadeOut() { -+ return this.fadeOut; -+ } -+ -+ /** -+ * Sends the title directly to an player -+ * -+ * @param player the receiver of the title -+ */ -+ public void send(@NotNull Player player) { -+ player.sendTitle(this); -+ } -+ -+ /** -+ * Sends the title directly to the defined players -+ * -+ * @param players the receivers of the title -+ */ -+ public void send(@NotNull Collection players) { -+ for (Player player : players) { -+ player.sendTitle(this); -+ } -+ } -+ -+ /** -+ * Sends the title directly to the defined players -+ * -+ * @param players the receivers of the title -+ */ -+ public void send(@NotNull Player[] players) { -+ for (Player player : players) { -+ player.sendTitle(this); -+ } -+ } -+ -+ /** -+ * Sends the title directly to all online players -+ */ -+ public void broadcast() { -+ send(Bukkit.getOnlinePlayers()); -+ } -+ -+ @NotNull -+ public static Builder builder() { -+ return new Builder(); -+ } -+ -+ /** -+ * A builder for creating titles -+ */ -+ public static final class Builder { -+ -+ private BaseComponent[] title; -+ private BaseComponent[] subtitle; -+ private int fadeIn = DEFAULT_FADE_IN; -+ private int stay = DEFAULT_STAY; -+ private int fadeOut = DEFAULT_FADE_OUT; -+ -+ /** -+ * Sets the title to the given text. -+ * -+ * @param title the title text -+ * @return this builder instance -+ * @throws NullPointerException if the title is null -+ */ -+ @NotNull -+ public Builder title(@NotNull BaseComponent title) { -+ return this.title(new BaseComponent[]{checkNotNull(title, "title")}); -+ } -+ -+ /** -+ * Sets the title to the given text. -+ * -+ * @param title the title text -+ * @return this builder instance -+ * @throws NullPointerException if the title is null -+ */ -+ @NotNull -+ public Builder title(@NotNull BaseComponent[] title) { -+ this.title = checkNotNull(title, "title"); -+ return this; -+ } -+ -+ /** -+ * Sets the title to the given text. -+ * -+ *

      It is recommended to the {@link BaseComponent} methods.

      -+ * -+ * @param title the title text -+ * @return this builder instance -+ * @throws NullPointerException if the title is null -+ */ -+ @NotNull -+ public Builder title(@NotNull String title) { -+ return this.title(TextComponent.fromLegacyText(checkNotNull(title, "title"))); -+ } -+ -+ /** -+ * Sets the subtitle to the given text. -+ * -+ * @param subtitle the title text -+ * @return this builder instance -+ */ -+ @NotNull -+ public Builder subtitle(@Nullable BaseComponent subtitle) { -+ return this.subtitle(subtitle == null ? null : new BaseComponent[]{subtitle}); -+ } -+ -+ /** -+ * Sets the subtitle to the given text. -+ * -+ * @param subtitle the title text -+ * @return this builder instance -+ */ -+ @NotNull -+ public Builder subtitle(@Nullable BaseComponent[] subtitle) { -+ this.subtitle = subtitle; -+ return this; -+ } -+ -+ /** -+ * Sets the subtitle to the given text. -+ * -+ *

      It is recommended to the {@link BaseComponent} methods.

      -+ * -+ * @param subtitle the title text -+ * @return this builder instance -+ */ -+ @NotNull -+ public Builder subtitle(@Nullable String subtitle) { -+ return this.subtitle(subtitle == null ? null : TextComponent.fromLegacyText(subtitle)); -+ } -+ -+ /** -+ * Sets the number of ticks for the title to fade in -+ * -+ * @param fadeIn the number of ticks to fade in -+ * @return this builder instance -+ * @throws IllegalArgumentException if it is negative -+ */ -+ @NotNull -+ public Builder fadeIn(int fadeIn) { -+ checkArgument(fadeIn >= 0, "Negative fadeIn: %s", fadeIn); -+ this.fadeIn = fadeIn; -+ return this; -+ } -+ -+ -+ /** -+ * Sets the number of ticks for the title to stay. -+ * -+ * @param stay the number of ticks to stay -+ * @return this builder instance -+ * @throws IllegalArgumentException if it is negative -+ */ -+ @NotNull -+ public Builder stay(int stay) { -+ checkArgument(stay >= 0, "Negative stay: %s", stay); -+ this.stay = stay; -+ return this; -+ } -+ -+ /** -+ * Sets the number of ticks for the title to fade out. -+ * -+ * @param fadeOut the number of ticks to fade out -+ * @return this builder instance -+ * @throws IllegalArgumentException if it is negative -+ */ -+ @NotNull -+ public Builder fadeOut(int fadeOut) { -+ checkArgument(fadeOut >= 0, "Negative fadeOut: %s", fadeOut); -+ this.fadeOut = fadeOut; -+ return this; -+ } -+ -+ /** -+ * Create a title based on the values in the builder. -+ * -+ * @return a title from the values in this builder -+ * @throws IllegalStateException if title isn't specified -+ */ -+ @NotNull -+ public Title build() { -+ checkState(title != null, "Title not specified"); -+ return new Title(this.title, this.subtitle, this.fadeIn, this.stay, this.fadeOut); -+ } -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 84172c4356dd15e0d7de611d871584d8bb69b974..0f1f8494443e74d0a3a5326a006be6edfc9b3ce2 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -2,6 +2,7 @@ package org.bukkit.entity; - - import java.net.InetSocketAddress; - import java.util.UUID; -+import com.destroystokyo.paper.Title; // Paper - import org.bukkit.DyeColor; - import org.bukkit.Effect; - import org.bukkit.GameMode; -@@ -781,6 +782,131 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - public default void sendMessage(net.md_5.bungee.api.ChatMessageType position, net.md_5.bungee.api.chat.BaseComponent... components) { - spigot().sendMessage(position, components); - } -+ -+ /** -+ * Set the text displayed in the player list header and footer for this player -+ * -+ * @param header content for the top of the player list -+ * @param footer content for the bottom of the player list -+ * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)} -+ */ -+ @Deprecated -+ public void setPlayerListHeaderFooter(@Nullable net.md_5.bungee.api.chat.BaseComponent[] header, @Nullable net.md_5.bungee.api.chat.BaseComponent[] footer); -+ -+ /** -+ * Set the text displayed in the player list header and footer for this player -+ * -+ * @param header content for the top of the player list -+ * @param footer content for the bottom of the player list -+ * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)} -+ */ -+ @Deprecated -+ public void setPlayerListHeaderFooter(@Nullable net.md_5.bungee.api.chat.BaseComponent header, @Nullable net.md_5.bungee.api.chat.BaseComponent footer); -+ -+ /** -+ * Update the times for titles displayed to the player -+ * -+ * @param fadeInTicks ticks to fade-in -+ * @param stayTicks ticks to stay visible -+ * @param fadeOutTicks ticks to fade-out -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} -+ */ -+ @Deprecated -+ public void setTitleTimes(int fadeInTicks, int stayTicks, int fadeOutTicks); -+ -+ /** -+ * Update the subtitle of titles displayed to the player -+ * -+ * @param subtitle Subtitle to set -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} -+ */ -+ @Deprecated -+ public void setSubtitle(net.md_5.bungee.api.chat.BaseComponent[] subtitle); -+ -+ /** -+ * Update the subtitle of titles displayed to the player -+ * -+ * @param subtitle Subtitle to set -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} -+ */ -+ @Deprecated -+ public void setSubtitle(net.md_5.bungee.api.chat.BaseComponent subtitle); -+ -+ /** -+ * Show the given title to the player, along with the last subtitle set, using the last set times -+ * -+ * @param title Title to set -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} -+ */ -+ @Deprecated -+ public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent[] title); -+ -+ /** -+ * Show the given title to the player, along with the last subtitle set, using the last set times -+ * -+ * @param title Title to set -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} -+ */ -+ @Deprecated -+ public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent title); -+ -+ /** -+ * Show the given title and subtitle to the player using the given times -+ * -+ * @param title big text -+ * @param subtitle little text under it -+ * @param fadeInTicks ticks to fade-in -+ * @param stayTicks ticks to stay visible -+ * @param fadeOutTicks ticks to fade-out -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} -+ */ -+ @Deprecated -+ public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent[] title, @Nullable net.md_5.bungee.api.chat.BaseComponent[] subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks); -+ -+ /** -+ * Show the given title and subtitle to the player using the given times -+ * -+ * @param title big text -+ * @param subtitle little text under it -+ * @param fadeInTicks ticks to fade-in -+ * @param stayTicks ticks to stay visible -+ * @param fadeOutTicks ticks to fade-out -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} -+ */ -+ @Deprecated -+ public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent title, @Nullable net.md_5.bungee.api.chat.BaseComponent subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks); -+ -+ /** -+ * Show the title to the player, overriding any previously displayed title. -+ * -+ *

      This method overrides any previous title, use {@link #updateTitle(Title)} to change the existing one.

      -+ * -+ * @param title the title to send -+ * @throws NullPointerException if the title is null -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} -+ */ -+ @Deprecated -+ void sendTitle(@NotNull Title title); -+ -+ /** -+ * Show the title to the player, overriding any previously displayed title. -+ * -+ *

      This method doesn't override previous titles, but changes their values.

      -+ * -+ * @param title the title to send -+ * @throws NullPointerException if title is null -+ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} -+ */ -+ @Deprecated -+ void updateTitle(@NotNull Title title); -+ -+ /** -+ * Hide any title that is currently visible to the player -+ * -+ * @deprecated use {@link #clearTitle()} -+ */ -+ @Deprecated -+ public void hideTitle(); - // Paper end - - /** diff --git a/patches/api/0024-Add-methods-for-working-with-arrows-stuck-in-living-.patch b/patches/api/0024-Add-methods-for-working-with-arrows-stuck-in-living-.patch deleted file mode 100644 index c2662ea313b0..000000000000 --- a/patches/api/0024-Add-methods-for-working-with-arrows-stuck-in-living-.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: mrapple -Date: Sun, 25 Nov 2012 13:47:27 -0600 -Subject: [PATCH] Add methods for working with arrows stuck in living entities - - -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index 5077ec367a5cba88957c6115be27742974f7deec..b41133f23d25f90fc0993499056c4eeaf003a701 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -612,4 +612,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - * @return Whether the entity is invisible - */ - public boolean isInvisible(); -+ -+ // Paper start -+ /** -+ * Get the number of arrows stuck in this entity -+ * @return Number of arrows stuck -+ */ -+ int getArrowsStuck(); -+ -+ /** -+ * Set the number of arrows stuck in this entity -+ * -+ * @param arrows Number of arrows to stick in this entity -+ */ -+ void setArrowsStuck(int arrows); -+ // Paper end - } diff --git a/patches/api/0024-Player-Tab-List-and-Title-APIs.patch b/patches/api/0024-Player-Tab-List-and-Title-APIs.patch new file mode 100644 index 000000000000..07f2e6f80157 --- /dev/null +++ b/patches/api/0024-Player-Tab-List-and-Title-APIs.patch @@ -0,0 +1,569 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Techcable +Date: Mon, 29 Feb 2016 20:02:40 -0600 +Subject: [PATCH] Player Tab List and Title APIs + +Co-authored-by: Fruxz + +diff --git a/src/main/java/com/destroystokyo/paper/Title.java b/src/main/java/com/destroystokyo/paper/Title.java +new file mode 100644 +index 0000000000000000000000000000000000000000..20a028450667edf102b59b6b50ac6e890f2c34ab +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/Title.java +@@ -0,0 +1,420 @@ ++package com.destroystokyo.paper; ++ ++import net.md_5.bungee.api.chat.BaseComponent; ++import net.md_5.bungee.api.chat.TextComponent; ++ ++import org.bukkit.Bukkit; ++import org.bukkit.entity.Player; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.Collection; ++import java.util.List; ++ ++import static com.google.common.base.Preconditions.checkArgument; ++import static com.google.common.base.Preconditions.checkNotNull; ++import static com.google.common.base.Preconditions.checkState; ++ ++/** ++ * Represents a title to may be sent to a {@link Player}. ++ * ++ *

      A title can be sent without subtitle text.

      ++ * ++ * @deprecated use {@link net.kyori.adventure.title.Title} ++ */ ++@Deprecated(since = "1.16.5") ++public final class Title { ++ ++ /** ++ * The default number of ticks for the title to fade in. ++ */ ++ public static final int DEFAULT_FADE_IN = 20; ++ /** ++ * The default number of ticks for the title to stay. ++ */ ++ public static final int DEFAULT_STAY = 200; ++ /** ++ * The default number of ticks for the title to fade out. ++ */ ++ public static final int DEFAULT_FADE_OUT = 20; ++ ++ private final BaseComponent[] title; ++ private final BaseComponent[] subtitle; ++ private final int fadeIn; ++ private final int stay; ++ private final int fadeOut; ++ ++ /** ++ * Create a title with the default time values and no subtitle. ++ * ++ *

      Times use default values.

      ++ * ++ * @param title the main text of the title ++ * @throws NullPointerException if the title is null ++ */ ++ public Title(@NotNull BaseComponent title) { ++ this(title, null); ++ } ++ ++ /** ++ * Create a title with the default time values and no subtitle. ++ * ++ *

      Times use default values.

      ++ * ++ * @param title the main text of the title ++ * @throws NullPointerException if the title is null ++ */ ++ public Title(@NotNull BaseComponent[] title) { ++ this(title, null); ++ } ++ ++ /** ++ * Create a title with the default time values and no subtitle. ++ * ++ *

      Times use default values.

      ++ * ++ * @param title the main text of the title ++ * @throws NullPointerException if the title is null ++ */ ++ public Title(@NotNull String title) { ++ this(title, null); ++ } ++ ++ /** ++ * Create a title with the default time values. ++ * ++ *

      Times use default values.

      ++ * ++ * @param title the main text of the title ++ * @param subtitle the secondary text of the title ++ */ ++ public Title(@NotNull BaseComponent title, @Nullable BaseComponent subtitle) { ++ this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT); ++ } ++ ++ /** ++ * Create a title with the default time values. ++ * ++ *

      Times use default values.

      ++ * ++ * @param title the main text of the title ++ * @param subtitle the secondary text of the title ++ */ ++ public Title(@NotNull BaseComponent[] title, @Nullable BaseComponent[] subtitle) { ++ this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT); ++ } ++ ++ /** ++ * Create a title with the default time values. ++ * ++ *

      Times use default values.

      ++ * ++ * @param title the main text of the title ++ * @param subtitle the secondary text of the title ++ */ ++ public Title(@NotNull String title, @Nullable String subtitle) { ++ this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT); ++ } ++ ++ /** ++ * Creates a new title. ++ * ++ * @param title the main text of the title ++ * @param subtitle the secondary text of the title ++ * @param fadeIn the number of ticks for the title to fade in ++ * @param stay the number of ticks for the title to stay on screen ++ * @param fadeOut the number of ticks for the title to fade out ++ * @throws IllegalArgumentException if any of the times are negative ++ */ ++ public Title(@NotNull BaseComponent title, @Nullable BaseComponent subtitle, int fadeIn, int stay, int fadeOut) { ++ this( ++ new BaseComponent[]{checkNotNull(title, "title")}, ++ subtitle == null ? null : new BaseComponent[]{subtitle}, ++ fadeIn, ++ stay, ++ fadeOut ++ ); ++ } ++ ++ /** ++ * Creates a new title. ++ * ++ * @param title the main text of the title ++ * @param subtitle the secondary text of the title ++ * @param fadeIn the number of ticks for the title to fade in ++ * @param stay the number of ticks for the title to stay on screen ++ * @param fadeOut the number of ticks for the title to fade out ++ * @throws IllegalArgumentException if any of the times are negative ++ */ ++ public Title(@Nullable BaseComponent[] title, @NotNull BaseComponent[] subtitle, int fadeIn, int stay, int fadeOut) { ++ checkArgument(fadeIn >= 0, "Negative fadeIn: %s", fadeIn); ++ checkArgument(stay >= 0, "Negative stay: %s", stay); ++ checkArgument(fadeOut >= 0, "Negative fadeOut: %s", fadeOut); ++ this.title = checkNotNull(title, "title"); ++ this.subtitle = subtitle; ++ this.fadeIn = fadeIn; ++ this.stay = stay; ++ this.fadeOut = fadeOut; ++ } ++ ++ /** ++ * Creates a new title. ++ * ++ *

      It is recommended to the {@link BaseComponent} constrctors.

      ++ * ++ * @param title the main text of the title ++ * @param subtitle the secondary text of the title ++ * @param fadeIn the number of ticks for the title to fade in ++ * @param stay the number of ticks for the title to stay on screen ++ * @param fadeOut the number of ticks for the title to fade out ++ */ ++ public Title(@NotNull String title, @Nullable String subtitle, int fadeIn, int stay, int fadeOut) { ++ this( ++ TextComponent.fromLegacyText(checkNotNull(title, "title")), ++ subtitle == null ? null : TextComponent.fromLegacyText(subtitle), ++ fadeIn, ++ stay, ++ fadeOut ++ ); ++ } ++ ++ /** ++ * Gets the text of this title ++ * ++ * @return the text ++ */ ++ @NotNull ++ public BaseComponent[] getTitle() { ++ return this.title; ++ } ++ ++ /** ++ * Gets the text of this title's subtitle ++ * ++ * @return the text ++ */ ++ @Nullable ++ public BaseComponent[] getSubtitle() { ++ return this.subtitle; ++ } ++ ++ /** ++ * Gets the number of ticks to fade in. ++ * ++ *

      The returned value is never negative.

      ++ * ++ * @return the number of ticks to fade in ++ */ ++ public int getFadeIn() { ++ return this.fadeIn; ++ } ++ ++ /** ++ * Gets the number of ticks to stay. ++ * ++ *

      The returned value is never negative.

      ++ * ++ * @return the number of ticks to stay ++ */ ++ public int getStay() { ++ return this.stay; ++ } ++ ++ /** ++ * Gets the number of ticks to fade out. ++ * ++ *

      The returned value is never negative.

      ++ * ++ * @return the number of ticks to fade out ++ */ ++ public int getFadeOut() { ++ return this.fadeOut; ++ } ++ ++ /** ++ * Sends the title directly to an player ++ * ++ * @param player the receiver of the title ++ */ ++ public void send(@NotNull Player player) { ++ player.sendTitle(this); ++ } ++ ++ /** ++ * Sends the title directly to the defined players ++ * ++ * @param players the receivers of the title ++ */ ++ public void send(@NotNull Collection players) { ++ for (Player player : players) { ++ player.sendTitle(this); ++ } ++ } ++ ++ /** ++ * Sends the title directly to the defined players ++ * ++ * @param players the receivers of the title ++ */ ++ public void send(@NotNull Player[] players) { ++ for (Player player : players) { ++ player.sendTitle(this); ++ } ++ } ++ ++ /** ++ * Sends the title directly to all online players ++ */ ++ public void broadcast() { ++ send(Bukkit.getOnlinePlayers()); ++ } ++ ++ @NotNull ++ public static Builder builder() { ++ return new Builder(); ++ } ++ ++ /** ++ * A builder for creating titles ++ */ ++ public static final class Builder { ++ ++ private BaseComponent[] title; ++ private BaseComponent[] subtitle; ++ private int fadeIn = DEFAULT_FADE_IN; ++ private int stay = DEFAULT_STAY; ++ private int fadeOut = DEFAULT_FADE_OUT; ++ ++ /** ++ * Sets the title to the given text. ++ * ++ * @param title the title text ++ * @return this builder instance ++ * @throws NullPointerException if the title is null ++ */ ++ @NotNull ++ public Builder title(@NotNull BaseComponent title) { ++ return this.title(new BaseComponent[]{checkNotNull(title, "title")}); ++ } ++ ++ /** ++ * Sets the title to the given text. ++ * ++ * @param title the title text ++ * @return this builder instance ++ * @throws NullPointerException if the title is null ++ */ ++ @NotNull ++ public Builder title(@NotNull BaseComponent[] title) { ++ this.title = checkNotNull(title, "title"); ++ return this; ++ } ++ ++ /** ++ * Sets the title to the given text. ++ * ++ *

      It is recommended to the {@link BaseComponent} methods.

      ++ * ++ * @param title the title text ++ * @return this builder instance ++ * @throws NullPointerException if the title is null ++ */ ++ @NotNull ++ public Builder title(@NotNull String title) { ++ return this.title(TextComponent.fromLegacyText(checkNotNull(title, "title"))); ++ } ++ ++ /** ++ * Sets the subtitle to the given text. ++ * ++ * @param subtitle the title text ++ * @return this builder instance ++ */ ++ @NotNull ++ public Builder subtitle(@Nullable BaseComponent subtitle) { ++ return this.subtitle(subtitle == null ? null : new BaseComponent[]{subtitle}); ++ } ++ ++ /** ++ * Sets the subtitle to the given text. ++ * ++ * @param subtitle the title text ++ * @return this builder instance ++ */ ++ @NotNull ++ public Builder subtitle(@Nullable BaseComponent[] subtitle) { ++ this.subtitle = subtitle; ++ return this; ++ } ++ ++ /** ++ * Sets the subtitle to the given text. ++ * ++ *

      It is recommended to the {@link BaseComponent} methods.

      ++ * ++ * @param subtitle the title text ++ * @return this builder instance ++ */ ++ @NotNull ++ public Builder subtitle(@Nullable String subtitle) { ++ return this.subtitle(subtitle == null ? null : TextComponent.fromLegacyText(subtitle)); ++ } ++ ++ /** ++ * Sets the number of ticks for the title to fade in ++ * ++ * @param fadeIn the number of ticks to fade in ++ * @return this builder instance ++ * @throws IllegalArgumentException if it is negative ++ */ ++ @NotNull ++ public Builder fadeIn(int fadeIn) { ++ checkArgument(fadeIn >= 0, "Negative fadeIn: %s", fadeIn); ++ this.fadeIn = fadeIn; ++ return this; ++ } ++ ++ ++ /** ++ * Sets the number of ticks for the title to stay. ++ * ++ * @param stay the number of ticks to stay ++ * @return this builder instance ++ * @throws IllegalArgumentException if it is negative ++ */ ++ @NotNull ++ public Builder stay(int stay) { ++ checkArgument(stay >= 0, "Negative stay: %s", stay); ++ this.stay = stay; ++ return this; ++ } ++ ++ /** ++ * Sets the number of ticks for the title to fade out. ++ * ++ * @param fadeOut the number of ticks to fade out ++ * @return this builder instance ++ * @throws IllegalArgumentException if it is negative ++ */ ++ @NotNull ++ public Builder fadeOut(int fadeOut) { ++ checkArgument(fadeOut >= 0, "Negative fadeOut: %s", fadeOut); ++ this.fadeOut = fadeOut; ++ return this; ++ } ++ ++ /** ++ * Create a title based on the values in the builder. ++ * ++ * @return a title from the values in this builder ++ * @throws IllegalStateException if title isn't specified ++ */ ++ @NotNull ++ public Title build() { ++ checkState(title != null, "Title not specified"); ++ return new Title(this.title, this.subtitle, this.fadeIn, this.stay, this.fadeOut); ++ } ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 17f55697d02d7b9c9b42c4b89a33db9207622a36..01fcff92daec5d4bf4b2b9213925cd2604cdec98 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -1288,6 +1288,131 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + public default void sendMessage(net.md_5.bungee.api.ChatMessageType position, net.md_5.bungee.api.chat.BaseComponent... components) { + spigot().sendMessage(position, components); + } ++ ++ /** ++ * Set the text displayed in the player list header and footer for this player ++ * ++ * @param header content for the top of the player list ++ * @param footer content for the bottom of the player list ++ * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)} ++ */ ++ @Deprecated ++ public void setPlayerListHeaderFooter(@Nullable net.md_5.bungee.api.chat.BaseComponent[] header, @Nullable net.md_5.bungee.api.chat.BaseComponent[] footer); ++ ++ /** ++ * Set the text displayed in the player list header and footer for this player ++ * ++ * @param header content for the top of the player list ++ * @param footer content for the bottom of the player list ++ * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)} ++ */ ++ @Deprecated ++ public void setPlayerListHeaderFooter(@Nullable net.md_5.bungee.api.chat.BaseComponent header, @Nullable net.md_5.bungee.api.chat.BaseComponent footer); ++ ++ /** ++ * Update the times for titles displayed to the player ++ * ++ * @param fadeInTicks ticks to fade-in ++ * @param stayTicks ticks to stay visible ++ * @param fadeOutTicks ticks to fade-out ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} ++ */ ++ @Deprecated ++ public void setTitleTimes(int fadeInTicks, int stayTicks, int fadeOutTicks); ++ ++ /** ++ * Update the subtitle of titles displayed to the player ++ * ++ * @param subtitle Subtitle to set ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} ++ */ ++ @Deprecated ++ public void setSubtitle(net.md_5.bungee.api.chat.BaseComponent[] subtitle); ++ ++ /** ++ * Update the subtitle of titles displayed to the player ++ * ++ * @param subtitle Subtitle to set ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} ++ */ ++ @Deprecated ++ public void setSubtitle(net.md_5.bungee.api.chat.BaseComponent subtitle); ++ ++ /** ++ * Show the given title to the player, along with the last subtitle set, using the last set times ++ * ++ * @param title Title to set ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} ++ */ ++ @Deprecated ++ public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent[] title); ++ ++ /** ++ * Show the given title to the player, along with the last subtitle set, using the last set times ++ * ++ * @param title Title to set ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} ++ */ ++ @Deprecated ++ public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent title); ++ ++ /** ++ * Show the given title and subtitle to the player using the given times ++ * ++ * @param title big text ++ * @param subtitle little text under it ++ * @param fadeInTicks ticks to fade-in ++ * @param stayTicks ticks to stay visible ++ * @param fadeOutTicks ticks to fade-out ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} ++ */ ++ @Deprecated ++ public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent[] title, @Nullable net.md_5.bungee.api.chat.BaseComponent[] subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks); ++ ++ /** ++ * Show the given title and subtitle to the player using the given times ++ * ++ * @param title big text ++ * @param subtitle little text under it ++ * @param fadeInTicks ticks to fade-in ++ * @param stayTicks ticks to stay visible ++ * @param fadeOutTicks ticks to fade-out ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} ++ */ ++ @Deprecated ++ public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent title, @Nullable net.md_5.bungee.api.chat.BaseComponent subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks); ++ ++ /** ++ * Show the title to the player, overriding any previously displayed title. ++ * ++ *

      This method overrides any previous title, use {@link #updateTitle(com.destroystokyo.paper.Title)} to change the existing one.

      ++ * ++ * @param title the title to send ++ * @throws NullPointerException if the title is null ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} ++ */ ++ @Deprecated ++ void sendTitle(@NotNull com.destroystokyo.paper.Title title); ++ ++ /** ++ * Show the title to the player, overriding any previously displayed title. ++ * ++ *

      This method doesn't override previous titles, but changes their values.

      ++ * ++ * @param title the title to send ++ * @throws NullPointerException if title is null ++ * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} ++ */ ++ @Deprecated ++ void updateTitle(@NotNull com.destroystokyo.paper.Title title); ++ ++ /** ++ * Hide any title that is currently visible to the player ++ * ++ * @deprecated use {@link #clearTitle()} ++ */ ++ @Deprecated ++ public void hideTitle(); + // Paper end + + /** diff --git a/patches/api/0025-Add-methods-for-working-with-arrows-stuck-in-living-.patch b/patches/api/0025-Add-methods-for-working-with-arrows-stuck-in-living-.patch new file mode 100644 index 000000000000..895f0ff60829 --- /dev/null +++ b/patches/api/0025-Add-methods-for-working-with-arrows-stuck-in-living-.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: mrapple +Date: Sun, 25 Nov 2012 13:47:27 -0600 +Subject: [PATCH] Add methods for working with arrows stuck in living entities + +Upstream added methods for this so the original methods +are now deprecated + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 7afa4674a79f24db6344f02038ed9e2310c9cc66..598c88f02a764abe62f9f10833b2c499a0fb00ff 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -243,12 +243,44 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + public int getArrowsInBody(); + ++ // Paper start ++ /** ++ * Set the amount of arrows in the entity's body. ++ *

      ++ * Does not fire the {@link org.bukkit.event.entity.ArrowBodyCountChangeEvent}. ++ * ++ * @param count amount of arrows in entity's body ++ */ ++ default void setArrowsInBody(final int count) { ++ this.setArrowsInBody(count, false); ++ } ++ // Paper end ++ + /** + * Set the amount of arrows in the entity's body. + * + * @param count amount of arrows in entity's body ++ * @param fireEvent whether to fire the {@link org.bukkit.event.entity.ArrowBodyCountChangeEvent} event ++ */ ++ void setArrowsInBody(int count, boolean fireEvent); // Paper ++ ++ // Paper start - Add methods for working with arrows stuck in living entities ++ /** ++ * Sets the amount of ticks before the next arrow gets removed from the entities body. ++ *

      ++ * A value of 0 will cause the server to re-calculate the amount of ticks on the next tick. ++ * ++ * @param ticks Amount of ticks + */ +- public void setArrowsInBody(int count); ++ void setNextArrowRemoval(@org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE) int ticks); ++ ++ /** ++ * Gets the amount of ticks before the next arrow gets removed from the entities body. ++ * ++ * @return ticks Amount of ticks ++ */ ++ int getNextArrowRemoval(); ++ // Paper end - Add methods for working with arrows stuck in living entities + + /** + * Returns the living entity's current maximum no damage ticks. +@@ -787,4 +819,24 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + * @return Whether the entity is invisible + */ + public boolean isInvisible(); ++ ++ // Paper start ++ /** ++ * Get the number of arrows stuck in this entity ++ * @return Number of arrows stuck ++ * @deprecated use {@link #getArrowsInBody()} ++ */ ++ @Deprecated ++ int getArrowsStuck(); ++ ++ /** ++ * Set the number of arrows stuck in this entity ++ * ++ * @param arrows Number of arrows to stick in this entity ++ * @deprecated use {@link #setArrowsInBody(int, boolean)}. This method previously fired {@link org.bukkit.event.entity.ArrowBodyCountChangeEvent} so if ++ * you want to retain exact functionality, pass {@code true} for {@code fireEvent}. ++ */ ++ @Deprecated ++ void setArrowsStuck(int arrows); ++ // Paper end + } diff --git a/patches/api/0025-Complete-resource-pack-API.patch b/patches/api/0025-Complete-resource-pack-API.patch deleted file mode 100644 index ebab3fa62a71..000000000000 --- a/patches/api/0025-Complete-resource-pack-API.patch +++ /dev/null @@ -1,182 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jedediah Smith -Date: Sat, 4 Apr 2015 22:59:54 -0400 -Subject: [PATCH] Complete resource pack API - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 0f1f8494443e74d0a3a5326a006be6edfc9b3ce2..51b9d9a85f6de2add0797c816593b38e35e7cfb4 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -1298,7 +1298,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @throws IllegalArgumentException Thrown if the URL is null. - * @throws IllegalArgumentException Thrown if the URL is too long. The - * length restriction is an implementation specific arbitrary value. -+ * @deprecated use {@link #setResourcePack(String, String)} - */ -+ @Deprecated // Paper - public void setResourcePack(@NotNull String url); - - /** -@@ -2114,6 +2116,124 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - default net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { - return net.kyori.adventure.text.event.HoverEvent.showEntity(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowEntity.of(this.getType().getKey(), this.getUniqueId(), this.displayName()))); - } -+ -+ /** -+ * Request that the player's client download and switch resource packs. -+ *

      -+ * The player's client will download the new resource pack asynchronously -+ * in the background, and will automatically switch to it once the -+ * download is complete. If the client has downloaded and cached the same -+ * resource pack in the past, it will perform a quick timestamp check -+ * over the network to determine if the resource pack has changed and -+ * needs to be downloaded again. When this request is sent for the very -+ * first time from a given server, the client will first display a -+ * confirmation GUI to the player before proceeding with the download. -+ *

      -+ * Notes: -+ *

        -+ *
      • Players can disable server resources on their client, in which -+ * case this method will have no affect on them. -+ *
      • There is no concept of resetting resource packs back to default -+ * within Minecraft, so players will have to relog to do so. -+ *
      -+ * -+ * @param url The URL from which the client will download the resource -+ * pack. The string must contain only US-ASCII characters and should -+ * be encoded as per RFC 1738. -+ * @param hash A 40 character hexadecimal and lowercase SHA-1 digest of -+ * the resource pack file. -+ * @throws IllegalArgumentException Thrown if the URL is null. -+ * @throws IllegalArgumentException Thrown if the URL is too long. The -+ * length restriction is an implementation specific arbitrary value. -+ */ -+ void setResourcePack(@NotNull String url, @NotNull String hash); -+ -+ /** -+ * Request that the player's client download and switch resource packs. -+ *

      -+ * The player's client will download the new resource pack asynchronously -+ * in the background, and will automatically switch to it once the -+ * download is complete. If the client has downloaded and cached the same -+ * resource pack in the past, it will perform a quick timestamp check -+ * over the network to determine if the resource pack has changed and -+ * needs to be downloaded again. When this request is sent for the very -+ * first time from a given server, the client will first display a -+ * confirmation GUI to the player before proceeding with the download. -+ *

      -+ * Notes: -+ *

        -+ *
      • Players can disable server resources on their client, in which -+ * case this method will have no affect on them. -+ *
      • There is no concept of resetting resource packs back to default -+ * within Minecraft, so players will have to relog to do so. -+ *
      -+ * -+ * @param url The URL from which the client will download the resource -+ * pack. The string must contain only US-ASCII characters and should -+ * be encoded as per RFC 1738. -+ * @param hash A 40 character hexadecimal and lowercase SHA-1 digest of -+ * the resource pack file. -+ * @param required Marks if the resource pack should be required by the client -+ * @throws IllegalArgumentException Thrown if the URL is null. -+ * @throws IllegalArgumentException Thrown if the URL is too long. The -+ * length restriction is an implementation specific arbitrary value. -+ */ -+ void setResourcePack(@NotNull String url, @NotNull String hash, boolean required); -+ -+ /** -+ * Request that the player's client download and switch resource packs. -+ *

      -+ * The player's client will download the new resource pack asynchronously -+ * in the background, and will automatically switch to it once the -+ * download is complete. If the client has downloaded and cached the same -+ * resource pack in the past, it will perform a quick timestamp check -+ * over the network to determine if the resource pack has changed and -+ * needs to be downloaded again. When this request is sent for the very -+ * first time from a given server, the client will first display a -+ * confirmation GUI to the player before proceeding with the download. -+ *

      -+ * Notes: -+ *

        -+ *
      • Players can disable server resources on their client, in which -+ * case this method will have no affect on them. -+ *
      • There is no concept of resetting resource packs back to default -+ * within Minecraft, so players will have to relog to do so. -+ *
      -+ * -+ * @param url The URL from which the client will download the resource -+ * pack. The string must contain only US-ASCII characters and should -+ * be encoded as per RFC 1738. -+ * @param hash A 40 character hexadecimal and lowercase SHA-1 digest of -+ * the resource pack file. -+ * @param required Marks if the resource pack should be required by the client -+ * @param resourcePackPrompt A Prompt to be displayed in the client request -+ * @throws IllegalArgumentException Thrown if the URL is null. -+ * @throws IllegalArgumentException Thrown if the URL is too long. The -+ * length restriction is an implementation specific arbitrary value. -+ */ -+ void setResourcePack(@NotNull String url, @NotNull String hash, boolean required, @Nullable net.kyori.adventure.text.Component resourcePackPrompt); -+ /** -+ * @return the most recent resource pack status received from the player, -+ * or null if no status has ever been received from this player. -+ */ -+ @Nullable -+ org.bukkit.event.player.PlayerResourcePackStatusEvent.Status getResourcePackStatus(); -+ -+ /** -+ * @return the most recent resource pack hash received from the player, -+ * or null if no hash has ever been received from this player. -+ * -+ * @deprecated This is no longer sent from the client and will always be null -+ */ -+ @Nullable -+ @Deprecated -+ String getResourcePackHash(); -+ -+ /** -+ * @return true if the last resource pack status received from this player -+ * was {@link org.bukkit.event.player.PlayerResourcePackStatusEvent.Status#SUCCESSFULLY_LOADED} -+ */ -+ boolean hasResourcePack(); - // Paper end - - // Spigot start -diff --git a/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java b/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java -index b98195650d49d78ec35970ca0376b6289b861e4b..4c2102a11c3d682d98f0db4ccafa35231e66bcdd 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java -@@ -11,13 +11,32 @@ import org.jetbrains.annotations.NotNull; - public class PlayerResourcePackStatusEvent extends PlayerEvent { - - private static final HandlerList handlers = new HandlerList(); -+ @Deprecated -+ private final String hash; // Paper - private final Status status; - - public PlayerResourcePackStatusEvent(@NotNull final Player who, @NotNull Status resourcePackStatus) { - super(who); -+ this.hash = null; // Paper - this.status = resourcePackStatus; - } - -+ @Deprecated // Paper -+ public PlayerResourcePackStatusEvent(final Player who, Status resourcePackStatus, String hash) { -+ super(who); -+ this.hash = hash; // Paper -+ this.status = resourcePackStatus; -+ } -+ -+ @Deprecated -+ /** -+ * @deprecated Hash does not seem to ever be set -+ */ -+ public String getHash() { -+ return this.hash; -+ } -+ // Paper end -+ - /** - * Gets the status of this pack. - * diff --git a/patches/api/0026-Complete-resource-pack-API.patch b/patches/api/0026-Complete-resource-pack-API.patch new file mode 100644 index 000000000000..ec794ae5352a --- /dev/null +++ b/patches/api/0026-Complete-resource-pack-API.patch @@ -0,0 +1,212 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jedediah Smith +Date: Sat, 4 Apr 2015 22:59:54 -0400 +Subject: [PATCH] Complete resource pack API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 01fcff92daec5d4bf4b2b9213925cd2604cdec98..cb758b5907aa0c214123550fe14ccfdacbc6b208 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -2252,6 +2252,180 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + void setResourcePack(@NotNull UUID uuid, @NotNull String url, byte @Nullable [] hash, net.kyori.adventure.text.@Nullable Component prompt, boolean force); + // Paper end + ++ // Paper start - more resource pack API ++ /** ++ * Request that the player's client download and switch resource packs. ++ *

      ++ * The player's client will download the new resource pack asynchronously ++ * in the background, and will automatically switch to it once the ++ * download is complete. If the client has downloaded and cached the same ++ * resource pack in the past, it will perform a quick timestamp check ++ * over the network to determine if the resource pack has changed and ++ * needs to be downloaded again. When this request is sent for the very ++ * first time from a given server, the client will first display a ++ * confirmation GUI to the player before proceeding with the download. ++ *

      ++ * Notes: ++ *

        ++ *
      • Players can disable server resources on their client, in which ++ * case this method will have no affect on them. ++ *
      • To remove a resource pack you can use ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. ++ *
      ++ * ++ * @param url The URL from which the client will download the resource ++ * pack. The string must contain only US-ASCII characters and should ++ * be encoded as per RFC 1738. ++ * @param hash A 40 character hexadecimal and lowercase SHA-1 digest of ++ * the resource pack file. ++ * @throws IllegalArgumentException Thrown if the URL is null. ++ * @throws IllegalArgumentException Thrown if the URL is too long. The ++ * length restriction is an implementation specific arbitrary value. ++ */ ++ default void setResourcePack(final @NotNull String url, final @NotNull String hash) { ++ this.setResourcePack(url, hash, false); ++ } ++ ++ /** ++ * Request that the player's client download and switch resource packs. ++ *

      ++ * The player's client will download the new resource pack asynchronously ++ * in the background, and will automatically switch to it once the ++ * download is complete. If the client has downloaded and cached the same ++ * resource pack in the past, it will perform a quick timestamp check ++ * over the network to determine if the resource pack has changed and ++ * needs to be downloaded again. When this request is sent for the very ++ * first time from a given server, the client will first display a ++ * confirmation GUI to the player before proceeding with the download. ++ *

      ++ * Notes: ++ *

        ++ *
      • Players can disable server resources on their client, in which ++ * case this method will have no affect on them. ++ *
      • To remove a resource pack you can use ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. ++ *
      ++ * ++ * @param url The URL from which the client will download the resource ++ * pack. The string must contain only US-ASCII characters and should ++ * be encoded as per RFC 1738. ++ * @param hash A 40 character hexadecimal and lowercase SHA-1 digest of ++ * the resource pack file. ++ * @param required Marks if the resource pack should be required by the client ++ * @throws IllegalArgumentException Thrown if the URL is null. ++ * @throws IllegalArgumentException Thrown if the URL is too long. The ++ * length restriction is an implementation specific arbitrary value. ++ */ ++ default void setResourcePack(final @NotNull String url, final @NotNull String hash, final boolean required) { ++ this.setResourcePack(url, hash, required, null); ++ } ++ ++ /** ++ * Request that the player's client download and switch resource packs. ++ *

      ++ * The player's client will download the new resource pack asynchronously ++ * in the background, and will automatically switch to it once the ++ * download is complete. If the client has downloaded and cached the same ++ * resource pack in the past, it will perform a quick timestamp check ++ * over the network to determine if the resource pack has changed and ++ * needs to be downloaded again. When this request is sent for the very ++ * first time from a given server, the client will first display a ++ * confirmation GUI to the player before proceeding with the download. ++ *

      ++ * Notes: ++ *

        ++ *
      • Players can disable server resources on their client, in which ++ * case this method will have no affect on them. ++ *
      • To remove a resource pack you can use ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. ++ *
      ++ * ++ * @param url The URL from which the client will download the resource ++ * pack. The string must contain only US-ASCII characters and should ++ * be encoded as per RFC 1738. ++ * @param hash A 40 character hexadecimal and lowercase SHA-1 digest of ++ * the resource pack file. ++ * @param required Marks if the resource pack should be required by the client ++ * @param resourcePackPrompt A Prompt to be displayed in the client request ++ * @throws IllegalArgumentException Thrown if the URL is null. ++ * @throws IllegalArgumentException Thrown if the URL is too long. The ++ * length restriction is an implementation specific arbitrary value. ++ */ ++ default void setResourcePack(final @NotNull String url, final @NotNull String hash, final boolean required, final net.kyori.adventure.text.@Nullable Component resourcePackPrompt) { ++ this.setResourcePack(UUID.nameUUIDFromBytes(url.getBytes(java.nio.charset.StandardCharsets.UTF_8)), url, hash, resourcePackPrompt, required); ++ } ++ ++ /** ++ * Request that the player's client download and switch resource packs. ++ *

      ++ * The player's client will download the new resource pack asynchronously ++ * in the background, and will automatically switch to it once the ++ * download is complete. If the client has downloaded and cached the same ++ * resource pack in the past, it will perform a quick timestamp check ++ * over the network to determine if the resource pack has changed and ++ * needs to be downloaded again. When this request is sent for the very ++ * first time from a given server, the client will first display a ++ * confirmation GUI to the player before proceeding with the download. ++ *

      ++ * Notes: ++ *

        ++ *
      • Players can disable server resources on their client, in which ++ * case this method will have no affect on them. ++ *
      • To remove a resource pack you can use ++ * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. ++ *
      ++ * ++ * @param uuid Unique resource pack ID. ++ * @param url The URL from which the client will download the resource ++ * pack. The string must contain only US-ASCII characters and should ++ * be encoded as per RFC 1738. ++ * @param hash A 40 character hexadecimal and lowercase SHA-1 digest of ++ * the resource pack file. ++ * @param resourcePackPrompt A Prompt to be displayed in the client request ++ * @param required Marks if the resource pack should be required by the client ++ * @throws IllegalArgumentException Thrown if the URL is null. ++ * @throws IllegalArgumentException Thrown if the URL is too long. The ++ * length restriction is an implementation specific arbitrary value. ++ */ ++ default void setResourcePack(final @NotNull UUID uuid, final @NotNull String url, final @NotNull String hash, final net.kyori.adventure.text.@Nullable Component resourcePackPrompt, final boolean required) { ++ this.sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest.resourcePackRequest() ++ .required(required) ++ .replace(true) ++ .prompt(resourcePackPrompt) ++ .packs(net.kyori.adventure.resource.ResourcePackInfo.resourcePackInfo(uuid, java.net.URI.create(url), hash)) ++ ); ++ } ++ ++ /** ++ * Gets the most recent resource pack status from the player. ++ * ++ * @return the most recent status or null ++ */ ++ org.bukkit.event.player.PlayerResourcePackStatusEvent.@Nullable Status getResourcePackStatus(); ++ ++ /** ++ * Gets the most recent pack hash from the player. ++ * ++ * @return the most recent hash or null ++ * @deprecated This is no longer sent from the client and will always be null ++ */ ++ @Deprecated(forRemoval = true, since = "1.13.2") ++ @org.jetbrains.annotations.Contract("-> null") ++ default @Nullable String getResourcePackHash() { ++ return null; ++ } ++ ++ /** ++ * Gets if the last resource pack status from the player ++ * was {@link org.bukkit.event.player.PlayerResourcePackStatusEvent.Status#SUCCESSFULLY_LOADED}. ++ * ++ * @return true if last status was successfully loaded ++ */ ++ default boolean hasResourcePack() { ++ return this.getResourcePackStatus() == org.bukkit.event.player.PlayerResourcePackStatusEvent.Status.SUCCESSFULLY_LOADED; ++ } ++ // Paper end - more resource pack API ++ + /** + * Request that the player's client download and include another resource pack. + *

      +diff --git a/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java b/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java +index e2c4f9a0456cef345772d57b4d9c6e7d9598dd53..e4c32b21ab013703a6a1b07a1ad564d914ebe83f 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java +@@ -21,6 +21,16 @@ public class PlayerResourcePackStatusEvent extends PlayerEvent { + this.status = resourcePackStatus; + } + ++ // Paper start - add hash (not used anymore) ++ /** ++ * @deprecated Hash does not seem to ever be set ++ */ ++ @Deprecated(forRemoval = true) ++ public String getHash() { ++ return null; ++ } ++ // Paper end ++ + /** + * Gets the unique ID of this pack. + * diff --git a/patches/api/0026-Use-ASM-for-event-executors.patch b/patches/api/0026-Use-ASM-for-event-executors.patch deleted file mode 100644 index 331aaf5a9829..000000000000 --- a/patches/api/0026-Use-ASM-for-event-executors.patch +++ /dev/null @@ -1,394 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Techcable -Date: Thu, 3 Mar 2016 13:20:33 -0700 -Subject: [PATCH] Use ASM for event executors. - -Uses method handles for private or static methods. - -diff --git a/build.gradle.kts b/build.gradle.kts -index 7b8196db1fd1e283dc9ef71e3fe5137cc5920ba9..f0f8047cb3a43b447dc50b730dab3d0bc471b25a 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -39,6 +39,9 @@ dependencies { - apiAndDocs("net.kyori:adventure-text-serializer-legacy") - apiAndDocs("net.kyori:adventure-text-serializer-plain") - apiAndDocs("net.kyori:adventure-text-logger-slf4j") -+ -+ implementation("org.ow2.asm:asm:9.2") -+ implementation("org.ow2.asm:asm-commons:9.2") - // Paper end - - compileOnly("org.apache.maven:maven-resolver-provider:3.8.5") -diff --git a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5b28e9b1daba7834af67dbc193dd656bedd9a994 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java -@@ -0,0 +1,42 @@ -+package com.destroystokyo.paper.event.executor; -+ -+import java.lang.invoke.MethodHandle; -+import java.lang.invoke.MethodHandles; -+import java.lang.reflect.Method; -+ -+import com.destroystokyo.paper.util.SneakyThrow; -+import org.bukkit.event.Event; -+import org.bukkit.event.EventException; -+import org.bukkit.event.Listener; -+import org.bukkit.plugin.EventExecutor; -+import org.jetbrains.annotations.NotNull; -+ -+public class MethodHandleEventExecutor implements EventExecutor { -+ private final Class eventClass; -+ private final MethodHandle handle; -+ -+ public MethodHandleEventExecutor(@NotNull Class eventClass, @NotNull MethodHandle handle) { -+ this.eventClass = eventClass; -+ this.handle = handle; -+ } -+ -+ public MethodHandleEventExecutor(@NotNull Class eventClass, @NotNull Method m) { -+ this.eventClass = eventClass; -+ try { -+ m.setAccessible(true); -+ this.handle = MethodHandles.lookup().unreflect(m); -+ } catch (IllegalAccessException e) { -+ throw new AssertionError("Unable to set accessible", e); -+ } -+ } -+ -+ @Override -+ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { -+ if (!eventClass.isInstance(event)) return; -+ try { -+ handle.invoke(listener, event); -+ } catch (Throwable t) { -+ SneakyThrow.sneaky(t); -+ } -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c83672427324bd068ed52916f700b68446a226f6 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java -@@ -0,0 +1,43 @@ -+package com.destroystokyo.paper.event.executor; -+ -+import java.lang.invoke.MethodHandle; -+import java.lang.invoke.MethodHandles; -+import java.lang.reflect.Method; -+import java.lang.reflect.Modifier; -+ -+import com.destroystokyo.paper.util.SneakyThrow; -+import com.google.common.base.Preconditions; -+ -+import org.bukkit.Bukkit; -+import org.bukkit.event.Event; -+import org.bukkit.event.EventException; -+import org.bukkit.event.Listener; -+import org.bukkit.plugin.EventExecutor; -+import org.jetbrains.annotations.NotNull; -+ -+public class StaticMethodHandleEventExecutor implements EventExecutor { -+ private final Class eventClass; -+ private final MethodHandle handle; -+ -+ public StaticMethodHandleEventExecutor(@NotNull Class eventClass, @NotNull Method m) { -+ Preconditions.checkArgument(Modifier.isStatic(m.getModifiers()), "Not a static method: %s", m); -+ Preconditions.checkArgument(eventClass != null, "eventClass is null"); -+ this.eventClass = eventClass; -+ try { -+ m.setAccessible(true); -+ this.handle = MethodHandles.lookup().unreflect(m); -+ } catch (IllegalAccessException e) { -+ throw new AssertionError("Unable to set accessible", e); -+ } -+ } -+ -+ @Override -+ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { -+ if (!eventClass.isInstance(event)) return; -+ try { -+ handle.invoke(event); -+ } catch (Throwable throwable) { -+ SneakyThrow.sneaky(throwable); -+ } -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b8d5c13980858dc27fb5383726b7ebcaf14adcb8 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java -@@ -0,0 +1,51 @@ -+package com.destroystokyo.paper.event.executor.asm; -+ -+import java.lang.reflect.Method; -+import java.util.concurrent.atomic.AtomicInteger; -+ -+import org.bukkit.plugin.EventExecutor; -+import org.jetbrains.annotations.NotNull; -+import org.objectweb.asm.ClassWriter; -+import org.objectweb.asm.Type; -+import org.objectweb.asm.commons.GeneratorAdapter; -+ -+import static org.objectweb.asm.Opcodes.*; -+ -+public class ASMEventExecutorGenerator { -+ @NotNull -+ public static byte[] generateEventExecutor(@NotNull Method m, @NotNull String name) { -+ ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); -+ writer.visit(V1_8, ACC_PUBLIC, name.replace('.', '/'), null, Type.getInternalName(Object.class), new String[] {Type.getInternalName(EventExecutor.class)}); -+ // Generate constructor -+ GeneratorAdapter methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "", "()V", null, null), ACC_PUBLIC, "", "()V"); -+ methodGenerator.loadThis(); -+ methodGenerator.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); // Invoke the super class (Object) constructor -+ methodGenerator.returnValue(); -+ methodGenerator.endMethod(); -+ // Generate the execute method -+ methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "execute", "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Event;)V", null, null), ACC_PUBLIC, "execute", "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Listener;)V"); -+ methodGenerator.loadArg(0); -+ methodGenerator.checkCast(Type.getType(m.getDeclaringClass())); -+ methodGenerator.loadArg(1); -+ methodGenerator.checkCast(Type.getType(m.getParameterTypes()[0])); -+ methodGenerator.visitMethodInsn(m.getDeclaringClass().isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, Type.getInternalName(m.getDeclaringClass()), m.getName(), Type.getMethodDescriptor(m), m.getDeclaringClass().isInterface()); -+ // The only purpose of this switch statement is to generate the correct pop instruction, should the event handler method return something other than void. -+ // Non-void event handlers will be unsupported in a future release. -+ switch (Type.getType(m.getReturnType()).getSize()) { -+ // case 0 is omitted because the only type that has size 0 is void - no pop instruction needed. -+ case 1 -> methodGenerator.pop(); // handles reference types and most primitives -+ case 2 -> methodGenerator.pop2(); // handles long and double -+ } -+ methodGenerator.returnValue(); -+ methodGenerator.endMethod(); -+ writer.visitEnd(); -+ return writer.toByteArray(); -+ } -+ -+ public static AtomicInteger NEXT_ID = new AtomicInteger(1); -+ @NotNull -+ public static String generateName() { -+ int id = NEXT_ID.getAndIncrement(); -+ return "com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor" + id; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f79685b48bb581277a6891927988b6f7a4389dc4 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java -@@ -0,0 +1,34 @@ -+package com.destroystokyo.paper.event.executor.asm; -+ -+import org.jetbrains.annotations.NotNull; -+ -+public interface ClassDefiner { -+ -+ /** -+ * Returns if the defined classes can bypass access checks -+ * -+ * @return if classes bypass access checks -+ */ -+ public default boolean isBypassAccessChecks() { -+ return false; -+ } -+ -+ /** -+ * Define a class -+ * -+ * @param parentLoader the parent classloader -+ * @param name the name of the class -+ * @param data the class data to load -+ * @return the defined class -+ * @throws ClassFormatError if the class data is invalid -+ * @throws NullPointerException if any of the arguments are null -+ */ -+ @NotNull -+ public Class defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data); -+ -+ @NotNull -+ public static ClassDefiner getInstance() { -+ return SafeClassDefiner.INSTANCE; -+ } -+ -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ac99477e9f2c08041aeff31abc1d1edee58d0a67 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java -@@ -0,0 +1,66 @@ -+package com.destroystokyo.paper.event.executor.asm; -+ -+import java.util.concurrent.ConcurrentHashMap; -+import java.util.concurrent.ConcurrentMap; -+ -+import com.google.common.base.Preconditions; -+ -+import com.google.common.collect.MapMaker; -+import org.jetbrains.annotations.NotNull; -+import org.objectweb.asm.Type; -+ -+public class SafeClassDefiner implements ClassDefiner { -+ /* default */ static final SafeClassDefiner INSTANCE = new SafeClassDefiner(); -+ -+ private SafeClassDefiner() {} -+ -+ private final ConcurrentMap loaders = new MapMaker().weakKeys().makeMap(); -+ -+ @NotNull -+ @Override -+ public Class defineClass(@NotNull ClassLoader parentLoader, @NotNull String name, @NotNull byte[] data) { -+ GeneratedClassLoader loader = loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new); -+ synchronized (loader.getClassLoadingLock(name)) { -+ Preconditions.checkState(!loader.hasClass(name), "%s already defined", name); -+ Class c = loader.define(name, data); -+ assert c.getName().equals(name); -+ return c; -+ } -+ } -+ -+ private static class GeneratedClassLoader extends ClassLoader { -+ static { -+ ClassLoader.registerAsParallelCapable(); -+ } -+ -+ protected GeneratedClassLoader(@NotNull ClassLoader parent) { -+ super(parent); -+ } -+ -+ private Class define(@NotNull String name, byte[] data) { -+ synchronized (getClassLoadingLock(name)) { -+ assert !hasClass(name); -+ Class c = defineClass(name, data, 0, data.length); -+ resolveClass(c); -+ return c; -+ } -+ } -+ -+ @Override -+ @NotNull -+ public Object getClassLoadingLock(@NotNull String name) { -+ return super.getClassLoadingLock(name); -+ } -+ -+ public boolean hasClass(@NotNull String name) { -+ synchronized (getClassLoadingLock(name)) { -+ try { -+ Class.forName(name); -+ return true; -+ } catch (ClassNotFoundException e) { -+ return false; -+ } -+ } -+ } -+ } -+} -diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java -index a850f0780de05463fc0d3f9e15ff7f19d88b2aed..9026e108ccd3a88aee1267ee275137befa646455 100644 ---- a/src/main/java/org/bukkit/plugin/EventExecutor.java -+++ b/src/main/java/org/bukkit/plugin/EventExecutor.java -@@ -5,9 +5,75 @@ import org.bukkit.event.EventException; - import org.bukkit.event.Listener; - import org.jetbrains.annotations.NotNull; - -+// Paper start -+import java.lang.reflect.Method; -+import java.lang.reflect.Modifier; -+import java.util.concurrent.ConcurrentHashMap; -+import java.util.concurrent.ConcurrentMap; -+import java.util.function.Function; -+ -+import com.destroystokyo.paper.event.executor.MethodHandleEventExecutor; -+import com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor; -+import com.destroystokyo.paper.event.executor.asm.ASMEventExecutorGenerator; -+import com.destroystokyo.paper.event.executor.asm.ClassDefiner; -+import com.google.common.base.Preconditions; -+// Paper end -+ - /** - * Interface which defines the class for event call backs to plugins - */ - public interface EventExecutor { - public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException; -+ -+ // Paper start -+ ConcurrentMap> eventExecutorMap = new ConcurrentHashMap>() { -+ @NotNull -+ @Override -+ public Class computeIfAbsent(@NotNull Method key, @NotNull Function> mappingFunction) { -+ Class executorClass = get(key); -+ if (executorClass != null) -+ return executorClass; -+ -+ //noinspection SynchronizationOnLocalVariableOrMethodParameter -+ synchronized (key) { -+ executorClass = get(key); -+ if (executorClass != null) -+ return executorClass; -+ -+ return super.computeIfAbsent(key, mappingFunction); -+ } -+ } -+ }; -+ -+ @NotNull -+ public static EventExecutor create(@NotNull Method m, @NotNull Class eventClass) { -+ Preconditions.checkNotNull(m, "Null method"); -+ Preconditions.checkArgument(m.getParameterCount() != 0, "Incorrect number of arguments %s", m.getParameterCount()); -+ Preconditions.checkArgument(m.getParameterTypes()[0] == eventClass, "First parameter %s doesn't match event class %s", m.getParameterTypes()[0], eventClass); -+ ClassDefiner definer = ClassDefiner.getInstance(); -+ if (Modifier.isStatic(m.getModifiers())) { -+ return new StaticMethodHandleEventExecutor(eventClass, m); -+ } else if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) { -+ // get the existing generated EventExecutor class for the Method or generate one -+ Class executorClass = eventExecutorMap.computeIfAbsent(m, (__) -> { -+ String name = ASMEventExecutorGenerator.generateName(); -+ byte[] classData = ASMEventExecutorGenerator.generateEventExecutor(m, name); -+ return definer.defineClass(m.getDeclaringClass().getClassLoader(), name, classData).asSubclass(EventExecutor.class); -+ }); -+ -+ try { -+ EventExecutor asmExecutor = executorClass.newInstance(); -+ // Define a wrapper to conform to bukkit stupidity (passing in events that don't match and wrapper exception) -+ return (listener, event) -> { -+ if (!eventClass.isInstance(event)) return; -+ asmExecutor.execute(listener, event); -+ }; -+ } catch (InstantiationException | IllegalAccessException e) { -+ throw new AssertionError("Unable to initialize generated event executor", e); -+ } -+ } else { -+ return new MethodHandleEventExecutor(eventClass, m); -+ } -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index 5eb24f38f158d43fb42836b83c108f808c89512e..5d74fab03a15d7099e5dacb780eade4cdc185797 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -291,21 +291,7 @@ public final class JavaPluginLoader implements PluginLoader { - } - } - -- EventExecutor executor = new co.aikar.timings.TimedEventExecutor(new EventExecutor() { // Paper -- @Override -- public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { // Paper -- try { -- if (!eventClass.isAssignableFrom(event.getClass())) { -- return; -- } -- method.invoke(listener, event); -- } catch (InvocationTargetException ex) { -- throw new EventException(ex.getCause()); -- } catch (Throwable t) { -- throw new EventException(t); -- } -- } -- }, plugin, method, eventClass); // Paper -+ EventExecutor executor = new co.aikar.timings.TimedEventExecutor(EventExecutor.create(method, eventClass), plugin, method, eventClass); // Paper // Paper (Yes.) - Use factory method `EventExecutor.create()` - if (false) { // Spigot - RL handles useTimings check now - eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); - } else { diff --git a/patches/api/0029-Add-command-to-reload-permissions.yml-and-require-co.patch b/patches/api/0029-Add-command-to-reload-permissions.yml-and-require-co.patch index 3b185a563c92..0db1a8a7c050 100644 --- a/patches/api/0029-Add-command-to-reload-permissions.yml-and-require-co.patch +++ b/patches/api/0029-Add-command-to-reload-permissions.yml-and-require-co.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Add command to reload permissions.yml and require confirm to diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index e13ffa85390f2feda49309ba02ccf75856e4c8f2..c015c0b7678a141c84f0c0e339fe7c2a93988685 100644 +index 1ada54827acfaacab0a32ae5d55def952547c352..13fa39ed3d5ffa8a459d68d1e240e869ba42ac32 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2112,6 +2112,13 @@ public final class Bukkit { +@@ -2396,6 +2396,13 @@ public final class Bukkit { public static org.bukkit.command.CommandMap getCommandMap() { return server.getCommandMap(); } @@ -24,10 +24,10 @@ index e13ffa85390f2feda49309ba02ccf75856e4c8f2..c015c0b7678a141c84f0c0e339fe7c2a @NotNull diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 1dcf90071bae51e6b767ac26eb6624d372acac68..7204f8ea6271dbb94406f07bc98ec322f928fcea 100644 +index 93d924c586803161820707af823c352f7c5d40e1..6567d1746f5cf16c9f3518203dd9916ff916ca68 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -1863,4 +1863,6 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2096,4 +2096,6 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi @NotNull Spigot spigot(); // Spigot end @@ -84,21 +84,3 @@ index 50cc311be7904cc8fc6070a21c8e4de3a489fd20..5fa9d648bc780e874f658597f1a24715 + return java.util.Collections.singletonList("permissions"); // Paper } } -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index b7cd4b9e4fd5f98aafbc0fe5ad6883eeb50dea56..efe0e5e6b43c50c6a41ee3baa44beb7d883b551a 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -900,4 +900,13 @@ public final class SimplePluginManager implements PluginManager { - public void useTimings(boolean use) { - co.aikar.timings.Timings.setTimingsEnabled(use); // Paper - } -+ -+ // Paper start -+ public void clearPermissions() { -+ permissions.clear(); -+ defaultPerms.get(true).clear(); -+ defaultPerms.get(false).clear(); -+ } -+ // Paper end -+ - } diff --git a/patches/api/0030-Custom-replacement-for-eaten-items.patch b/patches/api/0030-Custom-replacement-for-eaten-items.patch index 94ff9d88e2aa..90a728214859 100644 --- a/patches/api/0030-Custom-replacement-for-eaten-items.patch +++ b/patches/api/0030-Custom-replacement-for-eaten-items.patch @@ -5,19 +5,19 @@ Subject: [PATCH] Custom replacement for eaten items diff --git a/src/main/java/org/bukkit/event/player/PlayerItemConsumeEvent.java b/src/main/java/org/bukkit/event/player/PlayerItemConsumeEvent.java -index c2793f3ef01c1246c130971c17e1c2bf8f551435..373f4b5b5185aa81ff728da89c9cc4e0ccf87889 100644 +index 36b16b6076321310b6ed60e515064e506b706b58..3208dedfb6769e3e8c2ebeb17c0e02d80adf233a 100644 --- a/src/main/java/org/bukkit/event/player/PlayerItemConsumeEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerItemConsumeEvent.java -@@ -22,6 +22,7 @@ public class PlayerItemConsumeEvent extends PlayerEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); +@@ -24,6 +24,7 @@ public class PlayerItemConsumeEvent extends PlayerEvent implements Cancellable { private boolean isCancelled = false; private ItemStack item; + private final EquipmentSlot hand; + @Nullable private ItemStack replacement; // Paper /** * @param player the player consuming -@@ -58,6 +59,29 @@ public class PlayerItemConsumeEvent extends PlayerEvent implements Cancellable { - } +@@ -82,6 +83,29 @@ public class PlayerItemConsumeEvent extends PlayerEvent implements Cancellable { + return hand; } + // Paper start diff --git a/patches/api/0031-Entity-AddTo-RemoveFrom-World-Events.patch b/patches/api/0031-Entity-AddTo-RemoveFrom-World-Events.patch index 5dc11c88f891..23dad970bc3a 100644 --- a/patches/api/0031-Entity-AddTo-RemoveFrom-World-Events.patch +++ b/patches/api/0031-Entity-AddTo-RemoveFrom-World-Events.patch @@ -6,74 +6,128 @@ Subject: [PATCH] Entity AddTo/RemoveFrom World Events diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityAddToWorldEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityAddToWorldEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..07660202e41ee86f1b66bad3335cf6fe126e7f9c +index 0000000000000000000000000000000000000000..11f8540a4752cf4d2112eff48bcca3b935c9f8b1 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityAddToWorldEvent.java -@@ -0,0 +1,32 @@ +@@ -0,0 +1,44 @@ +package com.destroystokyo.paper.event.entity; + ++import org.bukkit.World; +import org.bukkit.entity.Entity; -+import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; + +/** -+ * Fired any time an entity is being added to the world for any reason. -+ * -+ * Not to be confused with {@link org.bukkit.event.entity.CreatureSpawnEvent} -+ * This will fire anytime a chunk is reloaded too. ++ * Fired any time an entity is being added to the world for any reason (including a chunk loading). ++ *

      ++ * Not to be confused with {@link CreatureSpawnEvent} + */ ++@NullMarked +public class EntityAddToWorldEvent extends EntityEvent { + -+ public EntityAddToWorldEvent(@NotNull Entity entity) { ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final World world; ++ ++ @ApiStatus.Internal ++ public EntityAddToWorldEvent(final Entity entity, final World world) { + super(entity); ++ this.world = world; + } + -+ private static final HandlerList handlers = new HandlerList(); ++ /** ++ * @return The world that the entity is being added to ++ */ ++ public World getWorld() { ++ return this.world; ++ } + -+ @NotNull ++ @Override + public HandlerList getHandlers() { -+ return handlers; ++ return HANDLER_LIST; + } + -+ @NotNull + public static HandlerList getHandlerList() { -+ return handlers; ++ return HANDLER_LIST; + } +} diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityRemoveFromWorldEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityRemoveFromWorldEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..e5dbbd660409bae0d3b96e83390511d3a423a52e +index 0000000000000000000000000000000000000000..5ad5632d4d47d8b42e4f2af19c0fe6cf94ac5643 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityRemoveFromWorldEvent.java -@@ -0,0 +1,29 @@ +@@ -0,0 +1,42 @@ +package com.destroystokyo.paper.event.entity; + ++import org.bukkit.World; +import org.bukkit.entity.Entity; -+import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; + +/** -+ * Fired any time an entity is being removed from a world for any reason ++ * Fired any time an entity is being removed from a world for any reason (including a chunk unloading). ++ * Note: The entity is updated prior to this event being called, as such, the entity's world may not be equal to {@link #getWorld()}. + */ ++@NullMarked +public class EntityRemoveFromWorldEvent extends EntityEvent { + -+ public EntityRemoveFromWorldEvent(@NotNull Entity entity) { ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final World world; ++ ++ @ApiStatus.Internal ++ public EntityRemoveFromWorldEvent(final Entity entity, final World world) { + super(entity); ++ this.world = world; + } + -+ private static final HandlerList handlers = new HandlerList(); ++ /** ++ * @return The world that the entity is being removed from ++ */ ++ public World getWorld() { ++ return this.world; ++ } + -+ @NotNull ++ @Override + public HandlerList getHandlers() { -+ return handlers; ++ return HANDLER_LIST; + } + -+ @NotNull + public static HandlerList getHandlerList() { -+ return handlers; ++ return HANDLER_LIST; + } +} +diff --git a/src/main/java/org/bukkit/event/entity/EntityRemoveEvent.java b/src/main/java/org/bukkit/event/entity/EntityRemoveEvent.java +index e32df91d911bae42c8137c6f952a6ac6a94d27e0..8ed5d1ccc44951089999db360219b556db89b4ba 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityRemoveEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityRemoveEvent.java +@@ -1,5 +1,6 @@ + package org.bukkit.event.entity; + ++import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; + import org.bukkit.entity.Entity; + import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.ApiStatus; +@@ -11,8 +12,9 @@ import org.jetbrains.annotations.NotNull; + * This event should only be used for monitoring. The result + * of modifying the entity during or after this event is unspecified. + * This event is not called for a {@link org.bukkit.entity.Player}. ++ * @deprecated use {@link EntityRemoveFromWorldEvent} instead + */ +-@ApiStatus.Experimental ++@Deprecated(forRemoval = true) + public class EntityRemoveEvent extends EntityEvent { + + private static final HandlerList handlers = new HandlerList(); +@@ -112,5 +114,6 @@ public class EntityRemoveEvent extends EntityEvent { + * When the chunk an entity is in gets unloaded. + */ + UNLOAD, ++ DISCARD + } + } diff --git a/patches/api/0032-EntityPathfindEvent.patch b/patches/api/0032-EntityPathfindEvent.patch index 697b76661aca..5a2e0c0ffaf0 100644 --- a/patches/api/0032-EntityPathfindEvent.patch +++ b/patches/api/0032-EntityPathfindEvent.patch @@ -7,10 +7,10 @@ Fires when an Entity decides to start moving to a location. diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityPathfindEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityPathfindEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..63e46b2fb1b12b36fcb1e98b178cf29dd2e3d1b5 +index 0000000000000000000000000000000000000000..8624e0a528985c9b118f5e8a0f33d3286af2fc36 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityPathfindEvent.java -@@ -0,0 +1,82 @@ +@@ -0,0 +1,84 @@ +package com.destroystokyo.paper.event.entity; + +import org.bukkit.Location; @@ -18,78 +18,80 @@ index 0000000000000000000000000000000000000000..63e46b2fb1b12b36fcb1e98b178cf29d +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; + +/** + * Fired when an Entity decides to start moving towards a location. -+ * ++ *

      + * This event does not fire for the entities actual movement. Only when it + * is choosing to start moving to a location. + */ ++@NullMarked +public class EntityPathfindEvent extends EntityEvent implements Cancellable { -+ @Nullable private final Entity targetEntity; -+ @NotNull private final Location loc; + -+ public EntityPathfindEvent(@NotNull Entity entity, @NotNull Location loc, @Nullable Entity targetEntity) { ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final @Nullable Entity targetEntity; ++ private final Location location; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityPathfindEvent(final Entity entity, final Location location, final @Nullable Entity targetEntity) { + super(entity); + this.targetEntity = targetEntity; -+ this.loc = loc; ++ this.location = location; + } + + /** + * The Entity that is pathfinding. ++ * + * @return The Entity that is pathfinding. + */ -+ @NotNull ++ @Override + public Entity getEntity() { -+ return entity; ++ return this.entity; + } + + /** + * If the Entity is trying to pathfind to an entity, this is the entity in relation. ++ *
      ++ * Otherwise, this will return {@code null}. + * -+ * Otherwise this will return null. -+ * -+ * @return The entity target or null ++ * @return The entity target or {@code null} + */ -+ @Nullable -+ public Entity getTargetEntity() { -+ return targetEntity; ++ public @Nullable Entity getTargetEntity() { ++ return this.targetEntity; + } + + /** + * The Location of where the entity is about to move to. -+ * ++ *
      + * Note that if the target happened to of been an entity ++ * + * @return Location of where the entity is trying to pathfind to. + */ -+ @NotNull + public Location getLoc() { -+ return loc; ++ return this.location.clone(); + } + -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; + } + -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; + } + -+ private boolean cancelled = false; -+ + @Override -+ public boolean isCancelled() { -+ return cancelled; ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; + } + -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; + } +} diff --git a/patches/api/0035-Add-PlayerUseUnknownEntityEvent.patch b/patches/api/0035-Add-PlayerUseUnknownEntityEvent.patch index 8fa59475c298..49715a5255d3 100644 --- a/patches/api/0035-Add-PlayerUseUnknownEntityEvent.patch +++ b/patches/api/0035-Add-PlayerUseUnknownEntityEvent.patch @@ -3,56 +3,99 @@ From: Jedediah Smith Date: Sat, 2 Apr 2016 05:08:36 -0400 Subject: [PATCH] Add PlayerUseUnknownEntityEvent +Adds the PlayerUseUnknownEntityEvent to be used by plugins dealing with +virtual entities/entities that are not actually known to the server. + +Co-authored-by: Nassim Jahnke diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..09cfdf48ead8f03f3497646537292174241b0868 +index 0000000000000000000000000000000000000000..9ff2bbf7f99df45cc626cad60bec4d14a8a04e3e --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java -@@ -0,0 +1,46 @@ +@@ -0,0 +1,85 @@ +package com.destroystokyo.paper.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.inventory.EquipmentSlot; -+import org.jetbrains.annotations.NotNull; ++import org.bukkit.util.Vector; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; + ++/** ++ * Represents an event that is called when a player right-clicks an unknown entity. ++ * Useful for plugins dealing with virtual entities (entities that aren't actually spawned on the server). ++ *
      ++ * This event may be called multiple times per interaction with different interaction hands ++ * and with or without the clicked position. ++ */ ++@NullMarked +public class PlayerUseUnknownEntityEvent extends PlayerEvent { + -+ private static final HandlerList handlers = new HandlerList(); ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ + private final int entityId; + private final boolean attack; -+ @NotNull private final EquipmentSlot hand; ++ private final EquipmentSlot hand; ++ private final @Nullable Vector clickedPosition; + -+ public PlayerUseUnknownEntityEvent(@NotNull Player who, int entityId, boolean attack, @NotNull EquipmentSlot hand) { -+ super(who); ++ @ApiStatus.Internal ++ public PlayerUseUnknownEntityEvent(final Player player, final int entityId, final boolean attack, final EquipmentSlot hand, final @Nullable Vector clickedPosition) { ++ super(player); + this.entityId = entityId; + this.attack = attack; + this.hand = hand; ++ this.clickedPosition = clickedPosition; + } + ++ /** ++ * Returns the entity id of the unknown entity that was interacted with. ++ * ++ * @return the entity id of the entity that was interacted with ++ */ + public int getEntityId() { + return this.entityId; + } + ++ /** ++ * Returns whether the interaction was an attack. ++ * ++ * @return {@code true} if the player is attacking the entity, {@code false} if the player is interacting with the entity ++ */ + public boolean isAttack() { + return this.attack; + } + -+ @NotNull ++ /** ++ * Returns the hand used to perform this interaction. ++ * ++ * @return the hand used to interact ++ */ + public EquipmentSlot getHand() { + return this.hand; + } + -+ @NotNull ++ /** ++ * Returns the position relative to the entity that was clicked, or {@code null} if not available. ++ * See {@link PlayerInteractAtEntityEvent} for more details. ++ * ++ * @return the position relative to the entity that was clicked, or {@code null} if not available ++ * @see PlayerInteractAtEntityEvent ++ */ ++ public @Nullable Vector getClickedRelativePosition() { ++ return this.clickedPosition != null ? this.clickedPosition.clone() : null; ++ } ++ + @Override + public HandlerList getHandlers() { -+ return handlers; ++ return HANDLER_LIST; + } + -+ @NotNull + public static HandlerList getHandlerList() { -+ return handlers; ++ return HANDLER_LIST; + } +} diff --git a/patches/api/0036-Add-handshake-event-to-allow-plugins-to-handle-clien.patch b/patches/api/0036-Add-handshake-event-to-allow-plugins-to-handle-clien.patch index e041c954a7ee..30a767b777a4 100644 --- a/patches/api/0036-Add-handshake-event-to-allow-plugins-to-handle-clien.patch +++ b/patches/api/0036-Add-handshake-event-to-allow-plugins-to-handle-clien.patch @@ -7,66 +7,56 @@ Subject: [PATCH] Add handshake event to allow plugins to handle client diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca682a58e4e3 +index 0000000000000000000000000000000000000000..aea04fb357f5728195fd9c9bdcd6304a0b953c45 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerHandshakeEvent.java -@@ -0,0 +1,277 @@ +@@ -0,0 +1,257 @@ +package com.destroystokyo.paper.event.player; + +import com.google.common.base.Preconditions; ++import java.util.UUID; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.UUID; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; + +/** + * This event is fired during a player handshake. -+ * -+ *

      If there are no listeners listening to this event, the logic default -+ * to your server platform will be ran.

      ++ *

      ++ * If there are no listeners listening to this event, the logic default ++ * to your server platform will be run. + * + *

      WARNING: TAMPERING WITH THIS EVENT CAN BE DANGEROUS

      + */ ++@NullMarked +public class PlayerHandshakeEvent extends Event implements Cancellable { + -+ private static final HandlerList HANDLERS = new HandlerList(); -+ @NotNull private final String originalHandshake; -+ @NotNull private final String originalSocketAddressHostname; -+ private boolean cancelled; -+ @Nullable private String serverHostname; -+ @Nullable private String socketAddressHostname; -+ @Nullable private UUID uniqueId; -+ @Nullable private String propertiesJson; ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final String originalHandshake; ++ private final String originalSocketAddressHostname; ++ private @Nullable String serverHostname; ++ private @Nullable String socketAddressHostname; ++ private @Nullable UUID uniqueId; ++ private @Nullable String propertiesJson; + private boolean failed; + private Component failMessage = Component.text("If you wish to use IP forwarding, please enable it in your BungeeCord config as well!", NamedTextColor.YELLOW); + -+ /** -+ * Creates a new {@link PlayerHandshakeEvent}. -+ * -+ * @param originalHandshake the original handshake string -+ * @param cancelled if this event is enabled -+ * -+ * @deprecated in favour of {@link PlayerHandshakeEvent(String, String, boolean)} -+ */ ++ private boolean cancelled; ++ + @Deprecated -+ public PlayerHandshakeEvent(@NotNull String originalHandshake, boolean cancelled) { ++ @ApiStatus.Internal ++ public PlayerHandshakeEvent(final String originalHandshake, final boolean cancelled) { + this(originalHandshake, "127.0.0.1", cancelled); + } + -+ /** -+ * Creates a new {@link PlayerHandshakeEvent}. -+ * -+ * @param originalHandshake the original handshake string -+ * @param originalSocketAddressHostname the original socket address hostname -+ * @param cancelled if this event is enabled -+ */ -+ public PlayerHandshakeEvent(@NotNull String originalHandshake, @NotNull String originalSocketAddressHostname, boolean cancelled) { ++ @ApiStatus.Internal ++ public PlayerHandshakeEvent(final String originalHandshake, final String originalSocketAddressHostname, final boolean cancelled) { + super(true); + this.originalHandshake = originalHandshake; + this.originalSocketAddressHostname = originalSocketAddressHostname; @@ -75,9 +65,9 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + + /** + * Determines if this event is cancelled. -+ * -+ *

      When this event is cancelled, custom handshake logic will not -+ * be processed.

      ++ *

      ++ * When this event is cancelled, custom handshake logic will not ++ * be processed. + * + * @return {@code true} if this event is cancelled, {@code false} otherwise + */ @@ -88,15 +78,15 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + + /** + * Sets if this event is cancelled. ++ *

      ++ * When this event is cancelled, custom handshake logic will not ++ * be processed. + * -+ *

      When this event is cancelled, custom handshake logic will not -+ * be processed.

      -+ * -+ * @param cancelled {@code true} if this event is cancelled, {@code false} otherwise ++ * @param cancel {@code true} if this event is cancelled, {@code false} otherwise + */ + @Override -+ public void setCancelled(boolean cancelled) { -+ this.cancelled = cancelled; ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; + } + + /** @@ -104,7 +94,6 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @return the original handshake string + */ -+ @NotNull + public String getOriginalHandshake() { + return this.originalHandshake; + } @@ -117,7 +106,6 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @return the original socket address hostname + */ -+ @NotNull + public String getOriginalSocketAddressHostname() { + return this.originalSocketAddressHostname; + } @@ -129,8 +117,7 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @return the server hostname string + */ -+ @Nullable -+ public String getServerHostname() { ++ public @Nullable String getServerHostname() { + return this.serverHostname; + } + @@ -141,7 +128,7 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @param serverHostname the server hostname string + */ -+ public void setServerHostname(@NotNull String serverHostname) { ++ public void setServerHostname(final String serverHostname) { + this.serverHostname = serverHostname; + } + @@ -152,8 +139,7 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @return the socket address hostname string + */ -+ @Nullable -+ public String getSocketAddressHostname() { ++ public @Nullable String getSocketAddressHostname() { + return this.socketAddressHostname; + } + @@ -164,7 +150,7 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @param socketAddressHostname the socket address hostname string + */ -+ public void setSocketAddressHostname(@NotNull String socketAddressHostname) { ++ public void setSocketAddressHostname(final String socketAddressHostname) { + this.socketAddressHostname = socketAddressHostname; + } + @@ -173,8 +159,7 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @return the unique id + */ -+ @Nullable -+ public UUID getUniqueId() { ++ public @Nullable UUID getUniqueId() { + return this.uniqueId; + } + @@ -183,7 +168,7 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @param uniqueId the unique id + */ -+ public void setUniqueId(@NotNull UUID uniqueId) { ++ public void setUniqueId(final UUID uniqueId) { + this.uniqueId = uniqueId; + } + @@ -194,16 +179,15 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @return the profile properties, as JSON + */ -+ @Nullable -+ public String getPropertiesJson() { ++ public @Nullable String getPropertiesJson() { + return this.propertiesJson; + } + + /** + * Determines if authentication failed. -+ * -+ *

      When {@code true}, the client connecting will be disconnected -+ * with the {@link #getFailMessage() fail message}.

      ++ *

      ++ * When {@code true}, the client connecting will be disconnected ++ * with the {@link #getFailMessage() fail message}. + * + * @return {@code true} if authentication failed, {@code false} otherwise + */ @@ -213,13 +197,13 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + + /** + * Sets if authentication failed and the client should be disconnected. -+ * -+ *

      When {@code true}, the client connecting will be disconnected -+ * with the {@link #getFailMessage() fail message}.

      ++ *

      ++ * When {@code true}, the client connecting will be disconnected ++ * with the {@link #getFailMessage() fail message}. + * + * @param failed {@code true} if authentication failed, {@code false} otherwise + */ -+ public void setFailed(boolean failed) { ++ public void setFailed(final boolean failed) { + this.failed = failed; + } + @@ -230,7 +214,7 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @param propertiesJson the profile properties, as JSON + */ -+ public void setPropertiesJson(@NotNull String propertiesJson) { ++ public void setPropertiesJson(final String propertiesJson) { + this.propertiesJson = propertiesJson; + } + @@ -239,7 +223,6 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @return the message to display to the client + */ -+ @NotNull + public Component failMessage() { + return this.failMessage; + } @@ -249,7 +232,7 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * + * @param failMessage the message to display to the client + */ -+ public void failMessage(@NotNull Component failMessage) { ++ public void failMessage(final Component failMessage) { + this.failMessage = failMessage; + } + @@ -259,7 +242,6 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * @return the message to display to the client + * @deprecated use {@link #failMessage()} + */ -+ @NotNull + @Deprecated + public String getFailMessage() { + return LegacyComponentSerializer.legacySection().serialize(this.failMessage()); @@ -272,19 +254,17 @@ index 0000000000000000000000000000000000000000..59ae7bc3a0a2079fe4b3a92d777aca68 + * @deprecated use {@link #failMessage(Component)} + */ + @Deprecated -+ public void setFailMessage(@NotNull String failMessage) { ++ public void setFailMessage(final String failMessage) { + Preconditions.checkArgument(failMessage != null && !failMessage.isEmpty(), "fail message cannot be null or empty"); + this.failMessage(LegacyComponentSerializer.legacySection().deserialize(failMessage)); + } + -+ @NotNull + @Override + public HandlerList getHandlers() { -+ return HANDLERS; ++ return HANDLER_LIST; + } + -+ @NotNull + public static HandlerList getHandlerList() { -+ return HANDLERS; ++ return HANDLER_LIST; + } +} diff --git a/patches/api/0037-Arrow-pickup-rule-API.patch b/patches/api/0037-Arrow-pickup-rule-API.patch index fb3753f0e176..37a434e032c0 100644 --- a/patches/api/0037-Arrow-pickup-rule-API.patch +++ b/patches/api/0037-Arrow-pickup-rule-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Arrow pickup rule API diff --git a/src/main/java/org/bukkit/entity/AbstractArrow.java b/src/main/java/org/bukkit/entity/AbstractArrow.java -index 5b50a4e10e8ace8cc53ad3c8d7c3185f88d5c8db..e8e56e89e32d84af0639fe2e9b0eeabd747b6007 100644 +index 9cebf79b6217063fbce395b655261ee4ab0f4e45..c901990454ec930169b0dc561987bea101f9b6ae 100644 --- a/src/main/java/org/bukkit/entity/AbstractArrow.java +++ b/src/main/java/org/bukkit/entity/AbstractArrow.java -@@ -141,4 +141,38 @@ public interface AbstractArrow extends Projectile { +@@ -186,4 +186,38 @@ public interface AbstractArrow extends Projectile { */ CREATIVE_ONLY } diff --git a/patches/api/0039-LootTable-API.patch b/patches/api/0039-LootTable-API.patch index 8be71089d4bb..75ed22dfb5ff 100644 --- a/patches/api/0039-LootTable-API.patch +++ b/patches/api/0039-LootTable-API.patch @@ -12,105 +12,116 @@ Provides methods to determine players looted state for an object diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/LootableBlockInventory.java new file mode 100644 -index 0000000000000000000000000000000000000000..92d7b853a2ccaae5afa8ac141bead840942944ef +index 0000000000000000000000000000000000000000..6a03252d66a3e13c1960568ea23f6dcc673f34af --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/loottable/LootableBlockInventory.java @@ -0,0 +1,17 @@ +package com.destroystokyo.paper.loottable; + +import org.bukkit.block.Block; -+import org.jetbrains.annotations.NotNull; ++import org.jspecify.annotations.NullMarked; + +/** + * Represents an Inventory that can generate loot, such as Chests inside of Fortresses and Mineshafts + */ ++@NullMarked +public interface LootableBlockInventory extends LootableInventory { + + /** + * Gets the block that is lootable + * @return The Block + */ -+ @NotNull + Block getBlock(); +} diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/LootableEntityInventory.java new file mode 100644 -index 0000000000000000000000000000000000000000..b387894fe8001edb41ad2ad2b70ebabe065b682e +index 0000000000000000000000000000000000000000..31ca54dea65dc0363a0ff7991ba5be3b06533876 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/loottable/LootableEntityInventory.java @@ -0,0 +1,17 @@ +package com.destroystokyo.paper.loottable; + +import org.bukkit.entity.Entity; -+import org.jetbrains.annotations.NotNull; ++import org.jspecify.annotations.NullMarked; + +/** + * Represents an Inventory that can generate loot, such as Minecarts inside of Mineshafts + */ ++@NullMarked +public interface LootableEntityInventory extends LootableInventory { + + /** + * Gets the entity that is lootable + * @return The Entity + */ -+ @NotNull + Entity getEntity(); +} diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java new file mode 100644 -index 0000000000000000000000000000000000000000..97815eeb231cf0706b34fa47a4f7d1bb786305b4 +index 0000000000000000000000000000000000000000..9fb621200fb3969e8e440341e906acc3547b4039 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java -@@ -0,0 +1,116 @@ +@@ -0,0 +1,128 @@ +package com.destroystokyo.paper.loottable; + ++import java.util.UUID; +import org.bukkit.entity.Player; +import org.bukkit.loot.Lootable; -+ -+import java.util.UUID; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; + +/** + * Represents an Inventory that contains a Loot Table associated to it that will + * automatically fill on first open. -+ * ++ *

      + * A new feature and API is provided to support automatically refreshing the contents + * of the inventory based on that Loot Table after a configurable amount of time has passed. -+ * ++ *

      + * The behavior of how the Inventory is filled based on the loot table may vary based + * on Minecraft versions and the Loot Table feature. + */ ++@NullMarked +public interface LootableInventory extends Lootable { + + /** -+ * Server owners have to enable whether or not an object in a world should refill ++ * Server owners have to enable whether an object in a world should refill + * + * @return If the world this inventory is currently in has Replenishable Lootables enabled + */ + boolean isRefillEnabled(); + + /** -+ * Whether or not this object has ever been filled ++ * Whether this object has ever been filled ++ * + * @return Has ever been filled + */ + boolean hasBeenFilled(); + + /** + * Has this player ever looted this block ++ * + * @param player The player to check -+ * @return Whether or not this player has looted this block ++ * @return Whether this player has looted this block + */ -+ default boolean hasPlayerLooted(@NotNull Player player) { -+ return hasPlayerLooted(player.getUniqueId()); ++ default boolean hasPlayerLooted(final Player player) { ++ return this.hasPlayerLooted(player.getUniqueId()); + } + + /** ++ * Checks if this player can loot this block. Takes into account the "restrict player reloot" settings ++ * ++ * @param player the player to check ++ * @return Whether this player can loot this block ++ */ ++ boolean canPlayerLoot(UUID player); ++ ++ /** + * Has this player ever looted this block ++ * + * @param player The player to check -+ * @return Whether or not this player has looted this block ++ * @return Whether this player has looted this block + */ -+ boolean hasPlayerLooted(@NotNull UUID player); ++ boolean hasPlayerLooted(UUID player); + + /** + * Gets the timestamp, in milliseconds, of when the player last looted this object @@ -118,9 +129,8 @@ index 0000000000000000000000000000000000000000..97815eeb231cf0706b34fa47a4f7d1bb + * @param player The player to check + * @return Timestamp last looted, or null if player has not looted this object + */ -+ @Nullable -+ default Long getLastLooted(@NotNull Player player) { -+ return getLastLooted(player.getUniqueId()); ++ default @Nullable Long getLastLooted(final Player player) { ++ return this.getLastLooted(player.getUniqueId()); + } + + /** @@ -129,29 +139,31 @@ index 0000000000000000000000000000000000000000..97815eeb231cf0706b34fa47a4f7d1bb + * @param player The player to check + * @return Timestamp last looted, or null if player has not looted this object + */ -+ @Nullable -+ Long getLastLooted(@NotNull UUID player); ++ @Nullable Long getLastLooted(UUID player); + + /** -+ * Change the state of whether or not a player has looted this block ++ * Change the state of whether a player has looted this block ++ * + * @param player The player to change state for + * @param looted true to add player to looted list, false to remove + * @return The previous state of whether the player had looted this or not + */ -+ default boolean setHasPlayerLooted(@NotNull Player player, boolean looted) { -+ return setHasPlayerLooted(player.getUniqueId(), looted); ++ default boolean setHasPlayerLooted(final Player player, final boolean looted) { ++ return this.setHasPlayerLooted(player.getUniqueId(), looted); + } + + /** -+ * Change the state of whether or not a player has looted this block ++ * Change the state of whether a player has looted this block ++ * + * @param player The player to change state for + * @param looted true to add player to looted list, false to remove + * @return The previous state of whether the player had looted this or not + */ -+ boolean setHasPlayerLooted(@NotNull UUID player, boolean looted); ++ boolean setHasPlayerLooted(UUID player, boolean looted); + + /** -+ * Returns Whether or not this object has been filled and now has a pending refill ++ * Returns Whether this object has been filled and now has a pending refill ++ * + * @return Has pending refill + */ + boolean hasPendingRefill(); @@ -180,55 +192,66 @@ index 0000000000000000000000000000000000000000..97815eeb231cf0706b34fa47a4f7d1bb +} diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java b/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..fd184f13f5e8ee5cf829fff4f44696e1f760430b +index 0000000000000000000000000000000000000000..994c2183db89fc40d5991d5e1906e4bd04db6291 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java -@@ -0,0 +1,45 @@ +@@ -0,0 +1,46 @@ +package com.destroystokyo.paper.loottable; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; + ++@NullMarked +public class LootableInventoryReplenishEvent extends PlayerEvent implements Cancellable { -+ @NotNull private final LootableInventory inventory; + -+ public LootableInventoryReplenishEvent(@NotNull Player player, @NotNull LootableInventory inventory) { ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final LootableInventory inventory; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public LootableInventoryReplenishEvent(final Player player, final LootableInventory inventory) { + super(player); + this.inventory = inventory; + } + -+ @NotNull + public LootableInventory getInventory() { -+ return inventory; ++ return this.inventory; + } + -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; + } + -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; + } + -+ private boolean cancelled = false; -+ + @Override -+ public boolean isCancelled() { -+ return cancelled; ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; + } + -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; + } +} +diff --git a/src/main/java/org/bukkit/block/Barrel.java b/src/main/java/org/bukkit/block/Barrel.java +index aa1bb7a1a1c94b0b029bb60026efbc7f55584dd7..d3789b2b7dd71d7c1872a0d84698d35a1884101b 100644 +--- a/src/main/java/org/bukkit/block/Barrel.java ++++ b/src/main/java/org/bukkit/block/Barrel.java +@@ -5,4 +5,4 @@ import org.bukkit.loot.Lootable; + /** + * Represents a captured state of a Barrel. + */ +-public interface Barrel extends Container, Lootable, Lidded { } ++public interface Barrel extends Container, com.destroystokyo.paper.loottable.LootableBlockInventory, Lidded { } // Paper diff --git a/src/main/java/org/bukkit/block/Chest.java b/src/main/java/org/bukkit/block/Chest.java index b451191312e4fb19f2131c2d0a0c0337953f6c7c..db6affbc78106b2d93b41953b624a0bca0ca1d72 100644 --- a/src/main/java/org/bukkit/block/Chest.java @@ -250,6 +273,19 @@ index b451191312e4fb19f2131c2d0a0c0337953f6c7c..db6affbc78106b2d93b41953b624a0bc /** * Gets the inventory of the chest block represented by this block state. +diff --git a/src/main/java/org/bukkit/block/Crafter.java b/src/main/java/org/bukkit/block/Crafter.java +index e004920ec1e13daaa2f0969a5cf97b6a7de25df9..8d2dd78fc588a6817dfede8040b9909a7d5bde67 100644 +--- a/src/main/java/org/bukkit/block/Crafter.java ++++ b/src/main/java/org/bukkit/block/Crafter.java +@@ -7,7 +7,7 @@ import org.jetbrains.annotations.ApiStatus; + * Represents a captured state of a crafter. + */ + @ApiStatus.Experimental +-public interface Crafter extends Container, Lootable { ++public interface Crafter extends Container, com.destroystokyo.paper.loottable.LootableBlockInventory { // Paper - LootTable API + + /** + * Gets the number of ticks which this block will remain in the crafting diff --git a/src/main/java/org/bukkit/block/Dispenser.java b/src/main/java/org/bukkit/block/Dispenser.java index 74cd194c9a98245dc52e7e352d7d6c046e1e5cf3..07af1a3f011d4b96275f919d302ac367198e923e 100644 --- a/src/main/java/org/bukkit/block/Dispenser.java @@ -334,6 +370,23 @@ index 5b5c3be107fdaa6c55ceb1bca2c223ebc6ab7f43..4ebe1033c55dbd58d0794809435c9352 -public interface ChestBoat extends Boat, InventoryHolder, Lootable { +public interface ChestBoat extends Boat, InventoryHolder, com.destroystokyo.paper.loottable.LootableEntityInventory { // Paper } +diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java +index 2926fa6071bc7640cc10280b5c3962b0ce7686f1..f3f62e13cc1b6172808c52f2d5f520f1f584e6db 100644 +--- a/src/main/java/org/bukkit/entity/Mob.java ++++ b/src/main/java/org/bukkit/entity/Mob.java +@@ -61,4 +61,12 @@ public interface Mob extends LivingEntity, Lootable { + */ + @Nullable + public Sound getAmbientSound(); ++ ++ // Paper start - LootTable API ++ @Override ++ default void setLootTable(final @Nullable org.bukkit.loot.LootTable table, final long seed) { ++ this.setLootTable(table); ++ this.setSeed(seed); ++ } ++ // Paper end - LootTable API + } diff --git a/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java b/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java index 937b99f8734d71b2ad33af142afbc251b81d9745..db69687a7ad4b18d17ab1677cae5d8dd4dcd3678 100644 --- a/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java @@ -373,10 +426,10 @@ index 9ea403e6fd8e960d017660e0aec118abeda2c42b..238d118f7788b13cd86b7e9ea3a0fc38 +public interface StorageMinecart extends Minecart, InventoryHolder, LootableEntityInventory { // Paper } diff --git a/src/main/java/org/bukkit/loot/Lootable.java b/src/main/java/org/bukkit/loot/Lootable.java -index 24a3d989db3bc67e7afe8459a3d4bb132f448ea7..901db852498e0658c79a57582508dab29bf0a798 100644 +index b3e9347496fd60aa4f5d18ff256e8d4d73f2d9cd..649dd959035843604525a637dba639a4fbd34f97 100644 --- a/src/main/java/org/bukkit/loot/Lootable.java +++ b/src/main/java/org/bukkit/loot/Lootable.java -@@ -36,6 +36,34 @@ public interface Lootable { +@@ -35,6 +35,31 @@ public interface Lootable { @Nullable LootTable getLootTable(); @@ -387,24 +440,21 @@ index 24a3d989db3bc67e7afe8459a3d4bb132f448ea7..901db852498e0658c79a57582508dab2 + * @param table the Loot Table this {@link org.bukkit.block.Container} or {@link org.bukkit.entity.Mob} will have. + * @param seed the seed to used to generate loot. Default is 0. + */ -+ default void setLootTable(@Nullable LootTable table, long seed) { -+ setLootTable(table); -+ setSeed(seed); -+ } ++ void setLootTable(final @Nullable LootTable table, final long seed); + + /** + * Returns whether or not this object has a Loot Table + * @return Has a loot table + */ + default boolean hasLootTable() { -+ return getLootTable() != null; ++ return this.getLootTable() != null; + } + + /** + * Clears the associated Loot Table to this object + */ + default void clearLootTable() { -+ setLootTable(null); ++ this.setLootTable(null); + } + // Paper end + diff --git a/patches/api/0040-Add-EntityZapEvent.patch b/patches/api/0040-Add-EntityZapEvent.patch index cb9acafef24b..04fa98d81a3d 100644 --- a/patches/api/0040-Add-EntityZapEvent.patch +++ b/patches/api/0040-Add-EntityZapEvent.patch @@ -6,105 +6,98 @@ Subject: [PATCH] Add EntityZapEvent diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityZapEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityZapEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..1c5fa066c9e5e1b1a06df30842a4c7acc4742df8 +index 0000000000000000000000000000000000000000..af2b1629f845ffe1559e7d580b482636cc6441d9 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityZapEvent.java -@@ -0,0 +1,64 @@ +@@ -0,0 +1,65 @@ +package com.destroystokyo.paper.event.entity; + -+import com.google.common.base.Preconditions; ++import java.util.Collections; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LightningStrike; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityTransformEvent; -+ -+import java.util.Collections; -+import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; + +/** -+ * Fired when lightning strikes an entity ++ * Fired when lightning strikes an entity + */ ++@NullMarked +public class EntityZapEvent extends EntityTransformEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final LightningStrike bolt; + private boolean cancelled; -+ @NotNull private final LightningStrike bolt; + -+ public EntityZapEvent(@NotNull final Entity entity, @NotNull final LightningStrike bolt, @NotNull final Entity replacementEntity) { ++ @ApiStatus.Internal ++ public EntityZapEvent(final Entity entity, final LightningStrike bolt, final Entity replacementEntity) { + super(entity, Collections.singletonList(replacementEntity), TransformReason.LIGHTNING); -+ Preconditions.checkNotNull(bolt); -+ Preconditions.checkNotNull(replacementEntity); + this.bolt = bolt; + } + -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ + /** + * Gets the lightning bolt that is striking the entity. ++ * + * @return The lightning bolt responsible for this event + */ -+ @NotNull + public LightningStrike getBolt() { -+ return bolt; ++ return this.bolt; + } + + /** + * Gets the entity that will replace the struck entity. ++ * + * @return The entity that will replace the struck entity + */ -+ @NotNull + public Entity getReplacementEntity() { -+ return getTransformedEntity(); ++ return super.getTransformedEntity(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; + } + -+ @NotNull + @Override + public HandlerList getHandlers() { -+ return handlers; ++ return HANDLER_LIST; + } + -+ @NotNull + public static HandlerList getHandlerList() { -+ return handlers; ++ return HANDLER_LIST; + } +} diff --git a/src/main/java/org/bukkit/event/entity/PigZapEvent.java b/src/main/java/org/bukkit/event/entity/PigZapEvent.java -index 0e0ed93b568fd2c0d8f6e359c31dc29cb0fa71c2..d3949edfc736b3d67a627ef378748b374769e183 100644 +index c5aa91c68ec24e3d07d7cb18ac8a75c4a8f743ca..7119dc013f087be7e01fc3fedc4361f76b4edae7 100644 --- a/src/main/java/org/bukkit/event/entity/PigZapEvent.java +++ b/src/main/java/org/bukkit/event/entity/PigZapEvent.java -@@ -2,6 +2,7 @@ package org.bukkit.event.entity; - - import java.util.Collections; - import org.bukkit.entity.Entity; -+import com.destroystokyo.paper.event.entity.EntityZapEvent; - import org.bukkit.entity.LightningStrike; - import org.bukkit.entity.Pig; - import org.bukkit.entity.PigZombie; -@@ -12,14 +13,14 @@ import org.jetbrains.annotations.NotNull; +@@ -12,14 +12,14 @@ import org.jetbrains.annotations.NotNull; /** * Stores data for pigs being zapped */ -public class PigZapEvent extends EntityTransformEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); -+public class PigZapEvent extends EntityZapEvent implements Cancellable { -+ //private static final HandlerList handlers = new HandlerList(); ++public class PigZapEvent extends com.destroystokyo.paper.event.entity.EntityZapEvent implements Cancellable { // Paper ++ // private static final HandlerList handlers = new HandlerList(); // Paper - moved in the super class private boolean canceled; private final PigZombie pigzombie; private final LightningStrike bolt; public PigZapEvent(@NotNull final Pig pig, @NotNull final LightningStrike bolt, @NotNull final PigZombie pigzombie) { - super(pig, Collections.singletonList((Entity) pigzombie), TransformReason.LIGHTNING); -+ super(pig, bolt, pigzombie); ++ super(pig, bolt, pigzombie); // Paper this.bolt = bolt; this.pigzombie = pigzombie; } -@@ -63,6 +64,8 @@ public class PigZapEvent extends EntityTransformEvent implements Cancellable { +@@ -63,6 +63,8 @@ public class PigZapEvent extends EntityTransformEvent implements Cancellable { return pigzombie; } @@ -113,7 +106,7 @@ index 0e0ed93b568fd2c0d8f6e359c31dc29cb0fa71c2..d3949edfc736b3d67a627ef378748b37 @NotNull @Override public HandlerList getHandlers() { -@@ -73,4 +76,6 @@ public class PigZapEvent extends EntityTransformEvent implements Cancellable { +@@ -73,4 +75,6 @@ public class PigZapEvent extends EntityTransformEvent implements Cancellable { public static HandlerList getHandlerList() { return handlers; } diff --git a/patches/api/0041-Misc-Utils.patch b/patches/api/0041-Misc-Utils.patch index fac858b16c88..3b0d9dbfd7f7 100644 --- a/patches/api/0041-Misc-Utils.patch +++ b/patches/api/0041-Misc-Utils.patch @@ -6,41 +6,44 @@ Subject: [PATCH] Misc Utils diff --git a/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java b/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java new file mode 100644 -index 0000000000000000000000000000000000000000..5bb677ce585b856b3d3e589e29786a29619c56a7 +index 0000000000000000000000000000000000000000..ebaa12ecacd169f00e184fed95720d047eda8b9d --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java -@@ -0,0 +1,34 @@ +@@ -0,0 +1,37 @@ +package com.destroystokyo.paper.utils; + +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.LongAdder; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; + ++@NullMarked ++@ApiStatus.Internal +public class CachedSizeConcurrentLinkedQueue extends ConcurrentLinkedQueue { ++ + private final LongAdder cachedSize = new LongAdder(); + + @Override -+ public boolean add(@NotNull E e) { -+ boolean result = super.add(e); ++ public boolean add(final E e) { ++ final boolean result = super.add(e); + if (result) { -+ cachedSize.increment(); ++ this.cachedSize.increment(); + } + return result; + } + -+ @Nullable + @Override -+ public E poll() { -+ E result = super.poll(); ++ public @Nullable E poll() { ++ final E result = super.poll(); + if (result != null) { -+ cachedSize.decrement(); ++ this.cachedSize.decrement(); + } + return result; + } + + @Override + public int size() { -+ return cachedSize.intValue(); ++ return this.cachedSize.intValue(); + } +} diff --git a/patches/api/0042-Allow-Reloading-of-Command-Aliases.patch b/patches/api/0042-Allow-Reloading-of-Command-Aliases.patch index c705f46a2355..18a95c3209c1 100644 --- a/patches/api/0042-Allow-Reloading-of-Command-Aliases.patch +++ b/patches/api/0042-Allow-Reloading-of-Command-Aliases.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Allow Reloading of Command Aliases Reload the aliases stored in commands.yml diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index c015c0b7678a141c84f0c0e339fe7c2a93988685..48eb69015cc70b0734f220f95fc0d8ffcd84954a 100644 +index 13fa39ed3d5ffa8a459d68d1e240e869ba42ac32..5660aa59d33ef2387839b9a67637672e6412088e 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2119,6 +2119,15 @@ public final class Bukkit { +@@ -2403,6 +2403,15 @@ public final class Bukkit { public static void reloadPermissions() { server.reloadPermissions(); } @@ -26,10 +26,10 @@ index c015c0b7678a141c84f0c0e339fe7c2a93988685..48eb69015cc70b0734f220f95fc0d8ff @NotNull diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 7204f8ea6271dbb94406f07bc98ec322f928fcea..f7c54fbffe6b39d4f73b45cbc7c23f3508217f74 100644 +index 6567d1746f5cf16c9f3518203dd9916ff916ca68..2c0e3ce1e6bb9602e1af11711b573f0080aa6f4c 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -1865,4 +1865,6 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2098,4 +2098,6 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi // Spigot end void reloadPermissions(); // Paper @@ -56,10 +56,10 @@ index bd2c7a6964722412148fae39e1b4951fc0002b9b..864c263bbd4dd6dd7c37a74b39b1a40a + // Paper end } diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java -index 2e23c124311b38aaea64dd274c33afcd52edcf43..950a2d0b3b583c6b9a703190874bbc4df2783ab7 100644 +index c7fa1d235cea78bda4656ed66b8d42b119cc50fb..27243a1214bc4d7dbb46f0b9b254c8e3f8128419 100644 --- a/src/main/java/org/bukkit/command/SimpleCommandMap.java +++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java -@@ -293,4 +293,11 @@ public class SimpleCommandMap implements CommandMap { +@@ -294,4 +294,11 @@ public class SimpleCommandMap implements CommandMap { } } } diff --git a/patches/api/0044-Add-ProjectileCollideEvent.patch b/patches/api/0044-Add-ProjectileCollideEvent.patch index a5c9df18df3f..9eaf9308b389 100644 --- a/patches/api/0044-Add-ProjectileCollideEvent.patch +++ b/patches/api/0044-Add-ProjectileCollideEvent.patch @@ -3,42 +3,44 @@ From: Techcable Date: Fri, 16 Dec 2016 21:25:39 -0600 Subject: [PATCH] Add ProjectileCollideEvent +Now deprecated and replaced with ProjectileHitEvent diff --git a/src/main/java/com/destroystokyo/paper/event/entity/ProjectileCollideEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/ProjectileCollideEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..453663893021768ae21d4980ce17ffba55d9e129 +index 0000000000000000000000000000000000000000..b7df0e6ca024448784aaf4784930e565b8e5bdb3 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/event/entity/ProjectileCollideEvent.java -@@ -0,0 +1,67 @@ +@@ -0,0 +1,74 @@ +package com.destroystokyo.paper.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Projectile; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** -+ * Called when an projectile collides with an entity ++ * Called when a projectile collides with an entity + *

      -+ * This event is called before {@link org.bukkit.event.entity.EntityDamageByEntityEvent}, and cancelling it will allow the projectile to continue flying ++ * This event is called before {@link EntityDamageByEntityEvent}, and cancelling it will allow the projectile to continue flying ++ * ++ * @deprecated Deprecated, use {@link org.bukkit.event.entity.ProjectileHitEvent} and check if there is a hit entity + */ ++@Deprecated(since = "1.19.3") +public class ProjectileCollideEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ + @NotNull private final Entity collidedWith; + -+ /** -+ * Get the entity the projectile collided with -+ * -+ * @return the entity collided with -+ */ -+ @NotNull -+ public Entity getCollidedWith() { -+ return collidedWith; -+ } ++ private boolean cancelled; + -+ public ProjectileCollideEvent(@NotNull Projectile what, @NotNull Entity collidedWith) { -+ super(what); ++ @ApiStatus.Internal ++ public ProjectileCollideEvent(@NotNull Projectile projectile, @NotNull Entity collidedWith) { ++ super(projectile); + this.collidedWith = collidedWith; + } + @@ -52,28 +54,34 @@ index 0000000000000000000000000000000000000000..453663893021768ae21d4980ce17ffba + return (Projectile) super.getEntity(); + } + -+ private static final HandlerList handlerList = new HandlerList(); -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlerList; -+ } -+ ++ /** ++ * Get the entity the projectile collided with ++ * ++ * @return the entity collided with ++ */ + @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlerList; ++ public Entity getCollidedWith() { ++ return this.collidedWith; + } + -+ private boolean cancelled = false; -+ + @Override + public boolean isCancelled() { -+ return cancelled; ++ return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } +} diff --git a/patches/api/0045-Add-String-based-Action-Bar-API.patch b/patches/api/0045-Add-String-based-Action-Bar-API.patch index 6f0006dda2b0..b96b2f3a312f 100644 --- a/patches/api/0045-Add-String-based-Action-Bar-API.patch +++ b/patches/api/0045-Add-String-based-Action-Bar-API.patch @@ -5,18 +5,10 @@ Subject: [PATCH] Add String based Action Bar API diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 51b9d9a85f6de2add0797c816593b38e35e7cfb4..6e6ec4095ac9d6c17b1ee657133f6521ead35226 100644 +index cb758b5907aa0c214123550fe14ccfdacbc6b208..e014582d73fc821c0b6dcf19ae1f5dfdf510343c 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java -@@ -3,6 +3,7 @@ package org.bukkit.entity; - import java.net.InetSocketAddress; - import java.util.UUID; - import com.destroystokyo.paper.Title; // Paper -+import net.kyori.adventure.text.Component; - import org.bukkit.DyeColor; - import org.bukkit.Effect; - import org.bukkit.GameMode; -@@ -749,6 +750,39 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM +@@ -1255,6 +1255,39 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM public void sendMap(@NotNull MapView map); // Paper start @@ -27,7 +19,7 @@ index 51b9d9a85f6de2add0797c816593b38e35e7cfb4..6e6ec4095ac9d6c17b1ee657133f6521 + * Use Section symbols for legacy color codes to send formatting. + * + * @param message The message to send -+ * @deprecated use {@link #sendActionBar(Component)} ++ * @deprecated use {@link #sendActionBar(net.kyori.adventure.text.Component)} + */ + @Deprecated + public void sendActionBar(@NotNull String message); @@ -39,7 +31,7 @@ index 51b9d9a85f6de2add0797c816593b38e35e7cfb4..6e6ec4095ac9d6c17b1ee657133f6521 + * + * @param alternateChar Alternate symbol such as '&' + * @param message The message to send -+ * @deprecated use {@link #sendActionBar(Component)} ++ * @deprecated use {@link #sendActionBar(net.kyori.adventure.text.Component)} + */ + @Deprecated + public void sendActionBar(char alternateChar, @NotNull String message); @@ -48,7 +40,7 @@ index 51b9d9a85f6de2add0797c816593b38e35e7cfb4..6e6ec4095ac9d6c17b1ee657133f6521 + * Sends an Action Bar message to the client. + * + * @param message The components to send -+ * @deprecated use {@link #sendActionBar(Component)} ++ * @deprecated use {@link #sendActionBar(net.kyori.adventure.text.Component)} + */ + @Deprecated + public void sendActionBar(@NotNull net.md_5.bungee.api.chat.BaseComponent... message); @@ -56,7 +48,7 @@ index 51b9d9a85f6de2add0797c816593b38e35e7cfb4..6e6ec4095ac9d6c17b1ee657133f6521 /** * Sends the component to the player * -@@ -776,9 +810,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM +@@ -1282,9 +1315,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM /** * Sends an array of components as a single message to the specified screen position of this player * @@ -68,19 +60,3 @@ index 51b9d9a85f6de2add0797c816593b38e35e7cfb4..6e6ec4095ac9d6c17b1ee657133f6521 public default void sendMessage(net.md_5.bungee.api.ChatMessageType position, net.md_5.bungee.api.chat.BaseComponent... components) { spigot().sendMessage(position, components); } -@@ -2305,6 +2341,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - /** - * Sends the component to the specified screen position of this player - * -+ * @deprecated This is unlikely the API you want to use. See {@link #sendActionBar(String)} for a more proper Action Bar API. This deprecated API may send unsafe items to the client. - * @param position the screen position - * @param component the components to send - * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} -@@ -2317,6 +2354,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - /** - * Sends an array of components as a single message to the specified screen position of this player - * -+ * @deprecated This is unlikely the API you want to use. See {@link #sendActionBar(String)} for a more proper Action Bar API. This deprecated API may send unsafe items to the client. - * @param position the screen position - * @param components the components to send - * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} diff --git a/patches/api/0046-Add-API-methods-to-control-if-armour-stands-can-move.patch b/patches/api/0046-Add-API-methods-to-control-if-armour-stands-can-move.patch index 5253041ed04e..aad79a70b3d8 100644 --- a/patches/api/0046-Add-API-methods-to-control-if-armour-stands-can-move.patch +++ b/patches/api/0046-Add-API-methods-to-control-if-armour-stands-can-move.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add API methods to control if armour stands can move diff --git a/src/main/java/org/bukkit/entity/ArmorStand.java b/src/main/java/org/bukkit/entity/ArmorStand.java -index dc604d6ab9dcf67fa0791539d18c2f890a814ed8..91fc11dda99de506be83d40df8929bf7cd8e8d85 100644 +index d08c5eb82eab8ad0ca7c8602b4d3d92fb0df02b3..6a1d563d1b7ea7e1060dfacfba98e4e1d4295790 100644 --- a/src/main/java/org/bukkit/entity/ArmorStand.java +++ b/src/main/java/org/bukkit/entity/ArmorStand.java @@ -344,4 +344,21 @@ public interface ArmorStand extends LivingEntity { diff --git a/patches/api/0047-IllegalPacketEvent.patch b/patches/api/0047-IllegalPacketEvent.patch index 7eb8d61aaa15..44c4a8319817 100644 --- a/patches/api/0047-IllegalPacketEvent.patch +++ b/patches/api/0047-IllegalPacketEvent.patch @@ -9,38 +9,42 @@ Lets plugins change the kick message and if it should kick or not. diff --git a/src/main/java/com/destroystokyo/paper/event/player/IllegalPacketEvent.java b/src/main/java/com/destroystokyo/paper/event/player/IllegalPacketEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..8d8e9b16f2a6707d2af7567c7682dfc5db51a737 +index 0000000000000000000000000000000000000000..44637928268c3efa951c340855f7caa63519a115 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/event/player/IllegalPacketEvent.java -@@ -0,0 +1,74 @@ +@@ -0,0 +1,67 @@ +package com.destroystokyo.paper.event.player; + -+import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @deprecated Not used + */ -+@Deprecated ++@Deprecated(since = "1.16.4") +public class IllegalPacketEvent extends PlayerEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ + @Nullable private final String type; -+ @Nullable private final String ex; ++ @Nullable private final String exceptionMessage; + @Nullable private String kickMessage; + private boolean shouldKick = true; + ++ @ApiStatus.Internal + public IllegalPacketEvent(@NotNull Player player, @Nullable String type, @Nullable String kickMessage, @NotNull Exception e) { + super(player); + this.type = type; + this.kickMessage = kickMessage; -+ this.ex = e.getMessage(); ++ this.exceptionMessage = e.getMessage(); + } + + public boolean isShouldKick() { -+ return shouldKick; ++ return this.shouldKick; + } + + public void setShouldKick(boolean shouldKick) { @@ -49,7 +53,7 @@ index 0000000000000000000000000000000000000000..8d8e9b16f2a6707d2af7567c7682dfc5 + + @Nullable + public String getKickMessage() { -+ return kickMessage; ++ return this.kickMessage; + } + + public void setKickMessage(@Nullable String kickMessage) { @@ -58,32 +62,21 @@ index 0000000000000000000000000000000000000000..8d8e9b16f2a6707d2af7567c7682dfc5 + + @Nullable + public String getType() { -+ return type; ++ return this.type; + } + + @Nullable + public String getExceptionMessage() { -+ return ex; ++ return this.exceptionMessage; + } + -+ private static final HandlerList handlers = new HandlerList(); -+ + @NotNull + public HandlerList getHandlers() { -+ return handlers; ++ return HANDLER_LIST; + } + + @NotNull + public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ public static void process(@NotNull Player player, @Nullable String type, @Nullable String kickMessage, @NotNull Exception exception) { -+ IllegalPacketEvent event = new IllegalPacketEvent(player, type, kickMessage, exception); -+ event.callEvent(); -+ if (event.shouldKick) { -+ player.kickPlayer(kickMessage); -+ } -+ Bukkit.getLogger().severe(player.getName() + "/" + type + ": " + exception.getMessage()); ++ return HANDLER_LIST; + } +} diff --git a/patches/api/0048-Fireworks-API-s.patch b/patches/api/0048-Fireworks-API-s.patch index a0ed753ac6c4..126f0b838d9b 100644 --- a/patches/api/0048-Fireworks-API-s.patch +++ b/patches/api/0048-Fireworks-API-s.patch @@ -7,10 +7,10 @@ Get the Entity being boosted Get the firework launcher diff --git a/src/main/java/org/bukkit/entity/Firework.java b/src/main/java/org/bukkit/entity/Firework.java -index 05e86cb9d826cdf14490fa649348d46c51adbfdb..d616d5941b3c7b85e350e845901da798601b9a3c 100644 +index e750b34d7d067a5f2f5587853274b6f479cc4fd6..0d31aa0b22cf1e849572294e2cfe38b48c9210af 100644 --- a/src/main/java/org/bukkit/entity/Firework.java +++ b/src/main/java/org/bukkit/entity/Firework.java -@@ -43,4 +43,15 @@ public interface Firework extends Projectile { +@@ -111,4 +111,20 @@ public interface Firework extends Projectile { * @param shotAtAngle the new shotAtAngle */ void setShotAtAngle(boolean shotAtAngle); @@ -20,9 +20,14 @@ index 05e86cb9d826cdf14490fa649348d46c51adbfdb..d616d5941b3c7b85e350e845901da798 + public java.util.UUID getSpawningEntity(); + /** + * If this firework is boosting an entity, return it ++ * @deprecated use {@link #getAttachedTo()} ++ * @see #setAttachedTo(LivingEntity) + * @return The entity being boosted + */ + @org.jetbrains.annotations.Nullable -+ public LivingEntity getBoostedEntity(); ++ @Deprecated ++ default LivingEntity getBoostedEntity() { ++ return getAttachedTo(); ++ } + // Paper end } diff --git a/patches/api/0049-PlayerTeleportEndGatewayEvent.patch b/patches/api/0049-PlayerTeleportEndGatewayEvent.patch index 664edd24cd69..b52aaaead8d8 100644 --- a/patches/api/0049-PlayerTeleportEndGatewayEvent.patch +++ b/patches/api/0049-PlayerTeleportEndGatewayEvent.patch @@ -7,25 +7,29 @@ Allows you to access the Gateway being used in a teleport event diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerTeleportEndGatewayEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerTeleportEndGatewayEvent.java new file mode 100644 -index 0000000000000000000000000000000000000000..b64ab6eecd8bc4ca9c109b9d83c82861d6260793 +index 0000000000000000000000000000000000000000..4488154d3f99f4281b08eef8a44c13fd896e538f --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerTeleportEndGatewayEvent.java -@@ -0,0 +1,29 @@ +@@ -0,0 +1,32 @@ +package com.destroystokyo.paper.event.player; + +import org.bukkit.Location; +import org.bukkit.block.EndGateway; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent; -+import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; + +/** + * Fired when a teleport is triggered for an End Gateway + */ ++@NullMarked +public class PlayerTeleportEndGatewayEvent extends PlayerTeleportEvent { -+ @NotNull private final EndGateway gateway; + -+ public PlayerTeleportEndGatewayEvent(@NotNull Player player, @NotNull Location from, @NotNull Location to, @NotNull EndGateway gateway) { ++ private final EndGateway gateway; ++ ++ @ApiStatus.Internal ++ public PlayerTeleportEndGatewayEvent(final Player player, final Location from, final Location to, final EndGateway gateway) { + super(player, from, to, PlayerTeleportEvent.TeleportCause.END_GATEWAY); + this.gateway = gateway; + } @@ -35,8 +39,7 @@ index 0000000000000000000000000000000000000000..b64ab6eecd8bc4ca9c109b9d83c82861 + * + * @return EndGateway used + */ -+ @NotNull + public EndGateway getGateway() { -+ return gateway; ++ return this.gateway; + } +} diff --git a/patches/api/0050-Provide-E-TE-Chunk-count-stat-methods.patch b/patches/api/0050-Provide-E-TE-Chunk-count-stat-methods.patch index 91de10f039a3..1913990a637b 100644 --- a/patches/api/0050-Provide-E-TE-Chunk-count-stat-methods.patch +++ b/patches/api/0050-Provide-E-TE-Chunk-count-stat-methods.patch @@ -7,10 +7,10 @@ Provides counts without the ineffeciency of using .getEntities().size() which creates copy of the collections. diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 887b85849803cee22a41a701b43cdc9085ba0dc3..e0683e69029e8ac423bda79521045b06673eabf3 100644 +index 683357f685b1d5f52151a5e78fc5265ebf9d32c2..e5d3ccf6e1bc87db1f5602214371c0e8ed4d5431 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java -@@ -45,6 +45,33 @@ import org.jetbrains.annotations.Nullable; +@@ -49,6 +49,33 @@ import org.jetbrains.annotations.Nullable; */ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, Keyed, net.kyori.adventure.audience.ForwardingAudience { // Paper diff --git a/patches/api/0052-Add-configuration-option-to-prevent-player-names-fro.patch b/patches/api/0052-Add-configuration-option-to-prevent-player-names-fro.patch new file mode 100644 index 000000000000..338c9e637d42 --- /dev/null +++ b/patches/api/0052-Add-configuration-option-to-prevent-player-names-fro.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kashike +Date: Fri, 9 Jun 2017 07:24:24 -0700 +Subject: [PATCH] Add configuration option to prevent player names from being + suggested + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 5660aa59d33ef2387839b9a67637672e6412088e..29e13fd7c94c5c50e81b804e6dffc8721164f1d1 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2412,6 +2412,16 @@ public final class Bukkit { + public static boolean reloadCommandAliases() { + return server.reloadCommandAliases(); + } ++ ++ /** ++ * Checks if player names should be suggested when a command returns {@code null} as ++ * their tab completion result. ++ * ++ * @return true if player names should be suggested ++ */ ++ public static boolean suggestPlayerNamesWhenNullTabCompletions() { ++ return server.suggestPlayerNamesWhenNullTabCompletions(); ++ } + // Paper end + + @NotNull +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 2c0e3ce1e6bb9602e1af11711b573f0080aa6f4c..4225105fef7aee264b34d1687762b5fc8dccbc47 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2100,4 +2100,14 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + void reloadPermissions(); // Paper + + boolean reloadCommandAliases(); // Paper ++ ++ // Paper start - allow preventing player name suggestions by default ++ /** ++ * Checks if player names should be suggested when a command returns {@code null} as ++ * their tab completion result. ++ * ++ * @return true if player names should be suggested ++ */ ++ boolean suggestPlayerNamesWhenNullTabCompletions(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java +index cee16db367907cfa4b432dc6969f403321a855ea..0ee08b6cd80e72ae67e1316ddbb58b7c1d47e5ce 100644 +--- a/src/main/java/org/bukkit/command/Command.java ++++ b/src/main/java/org/bukkit/command/Command.java +@@ -107,7 +107,7 @@ public abstract class Command { + Preconditions.checkArgument(args != null, "Arguments cannot be null"); + Preconditions.checkArgument(alias != null, "Alias cannot be null"); + +- if (args.length == 0) { ++ if (args.length == 0 || !sender.getServer().suggestPlayerNamesWhenNullTabCompletions()) { // Paper - allow preventing player name suggestions by default) { + return ImmutableList.of(); + } + diff --git a/patches/api/0052-Expose-WorldBorder-isInBounds-Location-check.patch b/patches/api/0052-Expose-WorldBorder-isInBounds-Location-check.patch deleted file mode 100644 index 16c0232c1b1b..000000000000 --- a/patches/api/0052-Expose-WorldBorder-isInBounds-Location-check.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Sat, 21 Jan 2017 17:03:10 -0600 -Subject: [PATCH] Expose WorldBorder#isInBounds(Location) check - - -diff --git a/src/main/java/org/bukkit/WorldBorder.java b/src/main/java/org/bukkit/WorldBorder.java -index 95bb16185514e0b894f407028997ce7d4504f8fb..238b9e2309d633623d35a1dbded6edadf20831f3 100644 ---- a/src/main/java/org/bukkit/WorldBorder.java -+++ b/src/main/java/org/bukkit/WorldBorder.java -@@ -127,4 +127,18 @@ public interface WorldBorder { - * @return if this location is inside the border or not - */ - public boolean isInside(@NotNull Location location); -+ -+ // Paper start -+ /** -+ * Checks if the location is within the boundaries of this border. -+ * -+ * @param location specific location to check -+ * @return true if the location is within the bounds of this border, false otherwise. -+ * @deprecated use {@link #isInside(Location)} for an upstream compatible replacement -+ */ -+ @Deprecated -+ public default boolean isInBounds(@NotNull Location location) { -+ return this.isInside(location); -+ } -+ // Paper end - } diff --git a/patches/api/0053-Add-configuration-option-to-prevent-player-names-fro.patch b/patches/api/0053-Add-configuration-option-to-prevent-player-names-fro.patch deleted file mode 100644 index 5cbb798fb23c..000000000000 --- a/patches/api/0053-Add-configuration-option-to-prevent-player-names-fro.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: kashike -Date: Fri, 9 Jun 2017 07:24:24 -0700 -Subject: [PATCH] Add configuration option to prevent player names from being - suggested - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 48eb69015cc70b0734f220f95fc0d8ffcd84954a..aea30cacbf43c4c6d30b0c9e0d59fcd2db444ad8 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2128,6 +2128,16 @@ public final class Bukkit { - public static boolean reloadCommandAliases() { - return server.reloadCommandAliases(); - } -+ -+ /** -+ * Checks if player names should be suggested when a command returns {@code null} as -+ * their tab completion result. -+ * -+ * @return true if player names should be suggested -+ */ -+ public static boolean suggestPlayerNamesWhenNullTabCompletions() { -+ return server.suggestPlayerNamesWhenNullTabCompletions(); -+ } - // Paper end - - @NotNull -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index f7c54fbffe6b39d4f73b45cbc7c23f3508217f74..5e4e6e83ac6b52493cb285561425bed53ffff2b6 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1867,4 +1867,14 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - void reloadPermissions(); // Paper - - boolean reloadCommandAliases(); // Paper -+ -+ // Paper start - allow preventing player name suggestions by default -+ /** -+ * Checks if player names should be suggested when a command returns {@code null} as -+ * their tab completion result. -+ * -+ * @return true if player names should be suggested -+ */ -+ boolean suggestPlayerNamesWhenNullTabCompletions(); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java -index 6fd341482d5250ad814e870360e40b52427f799a..a26df5f6341d22ecd5e71da59b8f091848e627ad 100644 ---- a/src/main/java/org/bukkit/command/Command.java -+++ b/src/main/java/org/bukkit/command/Command.java -@@ -99,7 +99,7 @@ public abstract class Command { - Preconditions.checkArgument(args != null, "Arguments cannot be null"); - Preconditions.checkArgument(alias != null, "Alias cannot be null"); - -- if (args.length == 0) { -+ if (args.length == 0 || !sender.getServer().suggestPlayerNamesWhenNullTabCompletions()) { // Paper - allow preventing player name suggestions by default) { - return ImmutableList.of(); - } - diff --git a/patches/api/0053-Fix-upstream-javadocs.patch b/patches/api/0053-Fix-upstream-javadocs.patch new file mode 100644 index 000000000000..914dbd429384 --- /dev/null +++ b/patches/api/0053-Fix-upstream-javadocs.patch @@ -0,0 +1,1890 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Sat, 10 Jun 2017 16:59:40 -0500 +Subject: [PATCH] Fix upstream javadocs + + +diff --git a/src/main/java/org/bukkit/BanList.java b/src/main/java/org/bukkit/BanList.java +index ac38b4af280cc7f52c70c238a6f4f9cccab1241d..5829aca9e5aa700bd95f19db3ae032100f74d5a3 100644 +--- a/src/main/java/org/bukkit/BanList.java ++++ b/src/main/java/org/bukkit/BanList.java +@@ -38,6 +38,9 @@ public interface BanList { + + /** + * Gets a {@link BanEntry} by target. ++ *

      ++ * Bans by name for ban type {@link Type#NAME NAME} are no longer supported and this method will return ++ * null when trying to request them. The replacement is bans by UUID. + * + * @param target entry parameter to search for + * @return the corresponding entry, or null if none found +@@ -59,6 +62,9 @@ public interface BanList { + /** + * Adds a ban to this list. If a previous ban exists, this will + * update the previous entry. ++ *

      ++ * Bans by name for ban type {@link Type#NAME NAME} are no longer supported and this method will return ++ * null when trying to request them. The replacement is bans by UUID. + * + * @param target the target of the ban + * @param reason reason for the ban, null indicates implementation default +@@ -139,6 +145,9 @@ public interface BanList { + /** + * Gets if a {@link BanEntry} exists for the target, indicating an active + * ban status. ++ *

      ++ * Bans by name for ban type {@link Type#NAME NAME} are no longer supported. ++ * The replacement is bans by UUID. + * + * @param target the target to find + * @return true if a {@link BanEntry} exists for the target, indicating an +@@ -161,6 +170,9 @@ public interface BanList { + /** + * Removes the specified target from this list, therefore indicating a + * "not banned" status. ++ *

      ++ * Bans by name for ban type {@link Type#NAME NAME} are no longer supported. ++ * The replacement is bans by UUID. + * + * @param target the target to remove from this list + */ +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 29e13fd7c94c5c50e81b804e6dffc8721164f1d1..bacdb1742ecb98bb10651b0582500449bf904910 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -1538,6 +1538,8 @@ public final class Bukkit { + + /** + * Gets every player that has ever played on this server. ++ *

      ++ * This method can be expensive as it loads all the player data files from the disk. + * + * @return an array containing all previous players + */ +@@ -2059,7 +2061,7 @@ public final class Bukkit { + * server will pause most functions after this time if there are no players + * online. + *

      +- * A value of less than 0 will disable the setting ++ * A value of less than 1 will disable the setting + * + * @param seconds the pause threshold in seconds + */ +diff --git a/src/main/java/org/bukkit/ChunkSnapshot.java b/src/main/java/org/bukkit/ChunkSnapshot.java +index 8832a2e0907299fb5f379b6938bbbc8e98688478..725d7944ce066ac56ed86b31628f00eb46cdcf64 100644 +--- a/src/main/java/org/bukkit/ChunkSnapshot.java ++++ b/src/main/java/org/bukkit/ChunkSnapshot.java +@@ -136,7 +136,7 @@ public interface ChunkSnapshot { + * Get raw biome temperature at given coordinates + * + * @param x X-coordinate (0-15) +- * @param y Y-coordinate (0-15) ++ * @param y Y-coordinate (world minHeight (inclusive) - world maxHeight (exclusive)) + * @param z Z-coordinate (0-15) + * @return temperature at given coordinate + */ +diff --git a/src/main/java/org/bukkit/HeightMap.java b/src/main/java/org/bukkit/HeightMap.java +index db6fcd635e295e561642d49941fd8e611247d38e..344b2b5d9207d2645bc5417d1ec00dd0a0b95604 100644 +--- a/src/main/java/org/bukkit/HeightMap.java ++++ b/src/main/java/org/bukkit/HeightMap.java +@@ -12,8 +12,7 @@ public enum HeightMap { + */ + MOTION_BLOCKING, + /** +- * The highest block that blocks motion or contains a fluid or is in the +- * {@link Tag#LEAVES}. ++ * The highest block that blocks motion or contains a fluid, excluding leaves. + */ + MOTION_BLOCKING_NO_LEAVES, + /** +diff --git a/src/main/java/org/bukkit/Particle.java b/src/main/java/org/bukkit/Particle.java +index bc23886a62312fc9e222ff2c6e7a7f325397d36a..ecf9f941e618608b98feaac46df3f10ec951c186 100644 +--- a/src/main/java/org/bukkit/Particle.java ++++ b/src/main/java/org/bukkit/Particle.java +@@ -207,7 +207,7 @@ public enum Particle implements Keyed { + } + + /** +- * Options which can be applied to redstone dust particles - a particle ++ * Options which can be applied to dust particles - a particle + * color and size. + */ + public static class DustOptions { +diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java +index 4c9fd558fbf7f57a948fbb7f80f4651048c0fb57..458119a9ef7ce8e1f59bd47caa5b4bc698715440 100644 +--- a/src/main/java/org/bukkit/RegionAccessor.java ++++ b/src/main/java/org/bukkit/RegionAccessor.java +@@ -158,7 +158,7 @@ public interface RegionAccessor { + * Creates a tree at the given {@link Location} + * + * @param location Location to spawn the tree +- * @param random Random to use to generated the tree ++ * @param random Random to use to generate the tree + * @param type Type of the tree to create + * @return true if the tree was created successfully, otherwise false + */ +@@ -170,14 +170,14 @@ public interface RegionAccessor { + * The provided consumer gets called for every block which gets changed + * as a result of the tree generation. When the consumer gets called no + * modifications to the world are done yet. Which means, that calling +- * {@link #getBlockState(Location)} in the consumer while return the state ++ * {@link #getBlockState(Location)} in the consumer will return the state + * of the block before the generation. + *

      + * Modifications done to the {@link BlockState} in the consumer are respected, + * which means that it is not necessary to call {@link BlockState#update()} + * + * @param location Location to spawn the tree +- * @param random Random to use to generated the tree ++ * @param random Random to use to generate the tree + * @param type Type of the tree to create + * @param stateConsumer The consumer which should get called for every block which gets changed + * @return true if the tree was created successfully, otherwise false +@@ -197,7 +197,7 @@ public interface RegionAccessor { + * If it returns {@code false} the block won't get set in the world. + * + * @param location Location to spawn the tree +- * @param random Random to use to generated the tree ++ * @param random Random to use to generate the tree + * @param type Type of the tree to create + * @param statePredicate The predicate which should get used to test if a block should be set or not. + * @return true if the tree was created successfully, otherwise false +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 4225105fef7aee264b34d1687762b5fc8dccbc47..a506e618448c3bf4b56f54f8fe00d7158df29dd7 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -581,13 +581,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * + *

      + * Note: If set to 0, {@link SpawnCategory} mobs spawning will be disabled. +- *

      +- * Minecraft default: 1. +- *
      +- * Note: the {@link SpawnCategory#MISC} are not consider. + * + * @param spawnCategory the category of spawn + * @return the default ticks per {@link SpawnCategory} mobs spawn value ++ * @throws IllegalArgumentException if the category is {@link SpawnCategory#MISC} + */ + public int getTicksPerSpawns(@NotNull SpawnCategory spawnCategory); + +@@ -1298,6 +1295,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + + /** + * Gets every player that has ever played on this server. ++ *

      ++ * This method can be expensive as it loads all the player data files from the disk. + * + * @return an array containing all previous players + */ +@@ -1740,7 +1739,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * Sets the pause when empty threshold seconds. To save resources, the + * pause most functions after this time if there are no players online. + *

      +- * A value of less than 0 will disable the setting ++ * A value of less than 1 will disable the setting + * + * @param seconds the pause threshold in seconds + */ +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index e5d3ccf6e1bc87db1f5602214371c0e8ed4d5431..369e92f2b5e4b8fc7f5bf8a97058e827c91e4c59 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -2766,7 +2766,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + /** + * Find the closest nearby structure of a given {@link StructureType}. + * Finding unexplored structures can, and will, block if the world is +- * looking in chunks that gave not generated yet. This can lead to the world ++ * looking in chunks that have not generated yet. This can lead to the world + * temporarily freezing while locating an unexplored structure. + *

      + * The {@code radius} is not a rigid square radius. Each structure may alter +@@ -2800,7 +2800,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + /** + * Find the closest nearby structure of a given {@link StructureType}. + * Finding unexplored structures can, and will, block if the world is +- * looking in chunks that gave not generated yet. This can lead to the world ++ * looking in chunks that have not generated yet. This can lead to the world + * temporarily freezing while locating an unexplored structure. + *

      + * The {@code radius} is not a rigid square radius. Each structure may alter +@@ -2833,7 +2833,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + /** + * Find the closest nearby structure of a given {@link Structure}. Finding + * unexplored structures can, and will, block if the world is looking in +- * chunks that gave not generated yet. This can lead to the world ++ * chunks that have not generated yet. This can lead to the world + * temporarily freezing while locating an unexplored structure. + *

      + * The {@code radius} is not a rigid square radius. Each structure may alter +diff --git a/src/main/java/org/bukkit/attribute/AttributeModifier.java b/src/main/java/org/bukkit/attribute/AttributeModifier.java +index ecf3897bd2dbdeebfa09a00a692724a013b0186d..b90af00a8eb83d4c1b183fbc4f1e9eae84c9074b 100644 +--- a/src/main/java/org/bukkit/attribute/AttributeModifier.java ++++ b/src/main/java/org/bukkit/attribute/AttributeModifier.java +@@ -129,8 +129,7 @@ public class AttributeModifier implements ConfigurationSerializable, Keyed { + } + + /** +- * Get the {@link EquipmentSlot} this AttributeModifier is active on, +- * or null if this modifier is applicable for any slot. ++ * Get the {@link EquipmentSlotGroup} this AttributeModifier is active on. + * + * @return the slot + */ +diff --git a/src/main/java/org/bukkit/block/Bed.java b/src/main/java/org/bukkit/block/Bed.java +index 20aaa7e15a71eef34ff4c06bad14464e7c9584dd..46778452893de3d8f1765994fb0c1ba62a90b315 100644 +--- a/src/main/java/org/bukkit/block/Bed.java ++++ b/src/main/java/org/bukkit/block/Bed.java +@@ -4,7 +4,22 @@ import org.bukkit.material.Colorable; + + /** + * Represents a captured state of a bed. +- * @deprecated does not provide useful information beyond the material itself + */ +-@Deprecated(since = "1.13") +-public interface Bed extends TileState, Colorable { } ++// Paper start ++// @Deprecated(since = "1.13") ++public interface Bed extends TileState, Colorable { ++ ++ @Override ++ @org.jetbrains.annotations.NotNull org.bukkit.DyeColor getColor(); ++ ++ /** ++ * Unsupported ++ * ++ * @throws UnsupportedOperationException not supported, set the block type ++ */ ++ @Override ++ @org.jetbrains.annotations.Contract("_ -> fail") ++ @Deprecated(forRemoval = true) ++ void setColor(@org.bukkit.UndefinedNullability("not supported") org.bukkit.DyeColor color); ++// Paper end ++} +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index ab65d9769b73780dc126b4f11f2ad4528e6ab0c0..f440da5941e11c30145175cf24162e1ba2b4e3cf 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -357,7 +357,7 @@ public interface Block extends Metadatable, Translatable { + * Gets the temperature of this block. + *

      + * If the raw biome temperature without adjusting for height effects is +- * required then please use {@link World#getTemperature(int, int)}. ++ * required then please use {@link World#getTemperature(int, int, int)}. + * + * @return Temperature of this block + */ +@@ -405,7 +405,10 @@ public interface Block extends Metadatable, Translatable { + boolean applyBoneMeal(@NotNull BlockFace face); + + /** +- * Returns a list of items which would drop by destroying this block ++ * Returns a list of items which could drop by destroying this block. ++ *

      ++ * The items are not guaranteed to be consistent across multiple calls to this ++ * method as this just uses the block type's loot table. + * + * @return a list of dropped items for this type of block + */ +@@ -413,8 +416,11 @@ public interface Block extends Metadatable, Translatable { + Collection getDrops(); + + /** +- * Returns a list of items which would drop by destroying this block with +- * a specific tool ++ * Returns a list of items which could drop by destroying this block with ++ * a specific tool. ++ *

      ++ * The items are not guaranteed to be consistent across multiple calls to this ++ * method as this just uses the block type's loot table. + * + * @param tool The tool or item in hand used for digging + * @return a list of dropped items for this type of block +@@ -423,8 +429,11 @@ public interface Block extends Metadatable, Translatable { + Collection getDrops(@Nullable ItemStack tool); + + /** +- * Returns a list of items which would drop by the entity destroying this +- * block with a specific tool ++ * Returns a list of items which could drop by the entity destroying this ++ * block with a specific tool. ++ *

      ++ * The items are not guaranteed to be consistent across multiple calls to this ++ * method as this just uses the block type's loot table. + * + * @param tool The tool or item in hand used for digging + * @param entity the entity destroying the block +diff --git a/src/main/java/org/bukkit/block/data/BlockData.java b/src/main/java/org/bukkit/block/data/BlockData.java +index 29fd06cb800f9b7cc91a120ccbe2980422ed9653..cd3b3e05cc825cfedec07f9a2a1e0b7b2a8866d6 100644 +--- a/src/main/java/org/bukkit/block/data/BlockData.java ++++ b/src/main/java/org/bukkit/block/data/BlockData.java +@@ -224,7 +224,7 @@ public interface BlockData extends Cloneable { + * {@link Material#REDSTONE_WIRE} -> {@link Material#REDSTONE} + * {@link Material#CARROTS} -> {@link Material#CARROT} + * +- * @return placement material ++ * @return placement material or {@link Material#AIR} if it doesn't have one + */ + @NotNull + Material getPlacementMaterial(); +diff --git a/src/main/java/org/bukkit/block/data/FaceAttachable.java b/src/main/java/org/bukkit/block/data/FaceAttachable.java +index 9599e1237b9717ddbf84c3738bf6c1293e8b3c54..950266b4bb0a2fabeb9539c5676ed58f0b0fe620 100644 +--- a/src/main/java/org/bukkit/block/data/FaceAttachable.java ++++ b/src/main/java/org/bukkit/block/data/FaceAttachable.java +@@ -38,7 +38,7 @@ public interface FaceAttachable extends BlockData { + */ + WALL, + /** +- * The switch is mounted to the ceiling and pointing dowanrds. ++ * The switch is mounted to the ceiling and pointing downwards. + */ + CEILING; + } +diff --git a/src/main/java/org/bukkit/block/data/type/CommandBlock.java b/src/main/java/org/bukkit/block/data/type/CommandBlock.java +index 9a7122c907308e4e0a4d0eab815df16899503c19..3b1dab4c1c38477fbe651382f37fdb042ce67cd1 100644 +--- a/src/main/java/org/bukkit/block/data/type/CommandBlock.java ++++ b/src/main/java/org/bukkit/block/data/type/CommandBlock.java +@@ -4,7 +4,7 @@ import org.bukkit.block.data.Directional; + + /** + * 'conditional' denotes whether this command block is conditional or not, i.e. +- * will only execute if the preceeding command block also executed successfully. ++ * will only execute if the preceding command block also executed successfully. + */ + public interface CommandBlock extends Directional { + +diff --git a/src/main/java/org/bukkit/block/data/type/Gate.java b/src/main/java/org/bukkit/block/data/type/Gate.java +index 494f97d47b52bc99b13748c1b57730fbd37d8f51..ebc98607b93294847f95e793304bc5d2528de2a3 100644 +--- a/src/main/java/org/bukkit/block/data/type/Gate.java ++++ b/src/main/java/org/bukkit/block/data/type/Gate.java +@@ -5,7 +5,7 @@ import org.bukkit.block.data.Openable; + import org.bukkit.block.data.Powerable; + + /** +- * 'in_wall" indicates if the fence gate is attached to a wall, and if true the ++ * 'in_wall' indicates if the fence gate is attached to a wall, and if true the + * texture is lowered by a small amount to blend in better. + */ + public interface Gate extends Directional, Openable, Powerable { +diff --git a/src/main/java/org/bukkit/block/data/type/Switch.java b/src/main/java/org/bukkit/block/data/type/Switch.java +index df8c2d60e7cce0294d3a1b1a6a81367a56602c26..16ced762f498b0dadd22789fa5d121d644bebf3d 100644 +--- a/src/main/java/org/bukkit/block/data/type/Switch.java ++++ b/src/main/java/org/bukkit/block/data/type/Switch.java +@@ -21,7 +21,7 @@ public interface Switch extends Directional, FaceAttachable, Powerable { + * Sets the value of the 'face' property. + * + * @param face the new 'face' value +- * @deprecated use {@link #getAttachedFace()} ++ * @deprecated use {@link #setAttachedFace(AttachedFace)} + */ + @Deprecated(since = "1.15.2") + void setFace(@NotNull Face face); +@@ -42,7 +42,7 @@ public interface Switch extends Directional, FaceAttachable, Powerable { + */ + WALL, + /** +- * The switch is mounted to the ceiling and pointing dowanrds. ++ * The switch is mounted to the ceiling and pointing downwards. + */ + CEILING; + } +diff --git a/src/main/java/org/bukkit/entity/ArmorStand.java b/src/main/java/org/bukkit/entity/ArmorStand.java +index 6a1d563d1b7ea7e1060dfacfba98e4e1d4295790..c727b2d40efae8f08bdd159991afb8992568a58f 100644 +--- a/src/main/java/org/bukkit/entity/ArmorStand.java ++++ b/src/main/java/org/bukkit/entity/ArmorStand.java +@@ -360,5 +360,8 @@ public interface ArmorStand extends LivingEntity { + * @param move {@code true} if this armour stand can move, {@code false} otherwise + */ + void setCanMove(boolean move); ++ ++ @Override ++ org.bukkit.inventory.@NotNull EntityEquipment getEquipment(); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Arrow.java b/src/main/java/org/bukkit/entity/Arrow.java +index a292579c9fa6eeac92fb1a21fa8144fbef307dad..38e6a8dbb248ead98cfb36bfb077d4e9e95b2c77 100644 +--- a/src/main/java/org/bukkit/entity/Arrow.java ++++ b/src/main/java/org/bukkit/entity/Arrow.java +@@ -93,7 +93,7 @@ public interface Arrow extends AbstractArrow { + * Removes a custom potion effect from this arrow. + * + * @param type the potion effect type to remove +- * @return true if the an effect was removed as a result of this call ++ * @return true if the effect was removed as a result of this call + * @throws IllegalArgumentException if this operation would leave the Arrow + * in a state with no Custom Effects and PotionType.UNCRAFTABLE + */ +diff --git a/src/main/java/org/bukkit/entity/EnderDragon.java b/src/main/java/org/bukkit/entity/EnderDragon.java +index 1e56aef9188487d3e9c737e85025f601ab359a72..92cd35c87bad578c2b714761c93a5b72ebf4bc9e 100644 +--- a/src/main/java/org/bukkit/entity/EnderDragon.java ++++ b/src/main/java/org/bukkit/entity/EnderDragon.java +@@ -30,7 +30,7 @@ public interface EnderDragon extends ComplexLivingEntity, Boss, Mob, Enemy { + */ + FLY_TO_PORTAL, + /** +- * The dragon will land on on the portal. If the dragon is not near ++ * The dragon will land on the portal. If the dragon is not near + * the portal, it will fly to it before mounting. + */ + LAND_ON_PORTAL, +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 411297f66520774a4072c9e15aa9bdf03a527208..45d408f519767785b222c409170bbfecbd8d1931 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -180,9 +180,13 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + public List getNearbyEntities(double x, double y, double z); + + /** +- * Returns a unique id for this entity ++ * Returns the network protocol ID for this entity. This is ++ * not to be used as an identifier for the entity except in ++ * network-related operations. Use {@link #getUniqueId()} as ++ * an entity identifier instead. + * +- * @return Entity id ++ * @return the network protocol ID ++ * @see #getUniqueId() + */ + public int getEntityId(); + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index b21f42e653553b6dbd571a1e8fba1e5a04f3bbd1..c90a0a00be78200adf217e2b3a8302b59af3cf7c 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -22,6 +22,11 @@ import org.jetbrains.annotations.Nullable; + */ + public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder { + ++ // Paper start ++ @Override ++ org.bukkit.inventory.@NotNull EntityEquipment getEquipment(); ++ // Paper end ++ + /** + * Returns the name of this player + * +diff --git a/src/main/java/org/bukkit/entity/ItemFrame.java b/src/main/java/org/bukkit/entity/ItemFrame.java +index b688b3856cb3068a539fcecfbfa113f8ab4160a9..c275b881cbd11307a6dcc7190d7a7d4063000ad8 100644 +--- a/src/main/java/org/bukkit/entity/ItemFrame.java ++++ b/src/main/java/org/bukkit/entity/ItemFrame.java +@@ -75,7 +75,7 @@ public interface ItemFrame extends Hanging { + public void setRotation(@NotNull Rotation rotation) throws IllegalArgumentException; + + /** +- * Returns whether the item frame is be visible or not. ++ * Returns whether the item frame is visible or not. + * + * @return whether the item frame is visible or not + */ +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 598c88f02a764abe62f9f10833b2c499a0fb00ff..4b75a5e1ce788bc375d6147422e5bee6ef0c03be 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -502,7 +502,7 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + /** + * Sets the leash on this entity to be held by the supplied entity. + *

      +- * This method has no effect on EnderDragons, Withers, Players, or Bats. ++ * This method has no effect on players. + * Non-living entities excluding leashes will not persist as leash + * holders. + * +diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java +index f3f62e13cc1b6172808c52f2d5f520f1f584e6db..ad5dbf310fe7b34c997bb339f09697222f862005 100644 +--- a/src/main/java/org/bukkit/entity/Mob.java ++++ b/src/main/java/org/bukkit/entity/Mob.java +@@ -9,6 +9,10 @@ import org.jetbrains.annotations.Nullable; + */ + public interface Mob extends LivingEntity, Lootable { + ++ // Paper start ++ @Override ++ org.bukkit.inventory.@org.jetbrains.annotations.NotNull EntityEquipment getEquipment(); ++ // Paper end + /** + * Instructs this Mob to set the specified LivingEntity as its target. + *

      +diff --git a/src/main/java/org/bukkit/entity/PigZombie.java b/src/main/java/org/bukkit/entity/PigZombie.java +index ae9eaaa8e38e1d9dfc459926c7fc51ddb89de84a..b2ec535bb1b0ce0c114ddd7638b90218b05cd835 100644 +--- a/src/main/java/org/bukkit/entity/PigZombie.java ++++ b/src/main/java/org/bukkit/entity/PigZombie.java +@@ -44,8 +44,6 @@ public interface PigZombie extends Zombie { + + /** + * Not applicable to this entity +- * +- * @return UnsuppotedOperationException + */ + @Override + public int getConversionTime(); +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index e014582d73fc821c0b6dcf19ae1f5dfdf510343c..5b12fa8c41a18ddfe08d82c138c0f71106c89d4d 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -492,15 +492,15 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + + /** + * Saves the players current location, health, inventory, motion, and +- * other information into the uuid.dat file, in the <main +- * world>/playerdata folder. ++ * other information into the <uuid>.dat file, in the ++ * <level-name>/playerdata/ folder. + */ + public void saveData(); + + /** + * Loads the players current location, health, inventory, motion, and +- * other information from the uuid.dat file, in the <main +- * world>/playerdata folder. ++ * other information from the <uuid>.dat file, in the ++ * <level-name>/playerdata/ folder. + *

      + * Note: This will overwrite the players current inventory, health, + * motion, etc, with the state from the saved dat file. +@@ -861,7 +861,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + /** + * Plays an effect to just this player. + * +- * @param the data based based on the type of the effect ++ * @param the data based on the type of the effect + * @param loc the location to play the effect at + * @param effect the {@link Effect} + * @param data a data bit needed for some effects +@@ -1272,7 +1272,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * + * Use supplied alternative character to the section symbol to represent legacy color codes. + * +- * @param alternateChar Alternate symbol such as '&' ++ * @param alternateChar Alternate symbol such as '&' + * @param message The message to send + * @deprecated use {@link #sendActionBar(net.kyori.adventure.text.Component)} + */ +@@ -1745,7 +1745,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + + /** + * Allows this player to see a player that was previously hidden. If +- * another another plugin had hidden the player too, then the player will ++ * another plugin had hidden the player too, then the player will + * remain hidden until the other plugin calls this method too. + * + * @param plugin Plugin that wants to show the player +@@ -1772,7 +1772,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + + /** + * Allows this player to see an entity that was previously hidden. If +- * another another plugin had hidden the entity too, then the entity will ++ * another plugin had hidden the entity too, then the entity will + * remain hidden until the other plugin calls this method too. + * + * @param plugin Plugin that wants to show the entity +@@ -1855,9 +1855,6 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * case this method will have no affect on them. Use the + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! +- *

    • There is no concept of resetting texture packs back to default +- * within Minecraft, so players will have to relog to do so or you +- * have to send an empty pack. + *
    • The request is send with "null" as the hash. This might result + * in newer versions not loading the pack correctly. + * +@@ -1891,9 +1888,6 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * case this method will have no affect on them. Use the + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! +- *
    • There is no concept of resetting resource packs back to default +- * within Minecraft, so players will have to relog to do so or you +- * have to send an empty pack. + *
    • The request is send with empty string as the hash. This might result + * in newer versions not loading the pack correctly. + * +@@ -1930,9 +1924,6 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * case this method will have no affect on them. Use the + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! +- *
    • There is no concept of resetting resource packs back to default +- * within Minecraft, so players will have to relog to do so or you +- * have to send an empty pack. + *
    • The request is sent with empty string as the hash when the hash is + * not provided. This might result in newer versions not loading the + * pack correctly. +diff --git a/src/main/java/org/bukkit/entity/Slime.java b/src/main/java/org/bukkit/entity/Slime.java +index a5ad3250cebfeb302c58e0bfd6db1295913c927e..0a2d603bf6a3f60d3fa7d85df6ef2373fc93d848 100644 +--- a/src/main/java/org/bukkit/entity/Slime.java ++++ b/src/main/java/org/bukkit/entity/Slime.java +@@ -11,6 +11,16 @@ public interface Slime extends Mob, Enemy { + public int getSize(); + + /** ++ * Setting the size of the slime (regardless of previous size) ++ * will set the following attributes: ++ *
        ++ *
      • {@link org.bukkit.attribute.Attribute#MAX_HEALTH}
      • ++ *
      • {@link org.bukkit.attribute.Attribute#MOVEMENT_SPEED}
      • ++ *
      • {@link org.bukkit.attribute.Attribute#ATTACK_DAMAGE}
      • ++ *
      ++ * to their per-size defaults and heal the ++ * slime to its max health (assuming it's alive). ++ * + * @param sz The new size of the slime. + */ + public void setSize(int sz); +diff --git a/src/main/java/org/bukkit/entity/Sniffer.java b/src/main/java/org/bukkit/entity/Sniffer.java +index af5110b4160979c39cc1e5de6fa3bd7957b21403..15a0a733b0e5804655b5957cbf20831290d52a08 100644 +--- a/src/main/java/org/bukkit/entity/Sniffer.java ++++ b/src/main/java/org/bukkit/entity/Sniffer.java +@@ -12,8 +12,6 @@ public interface Sniffer extends Animals { + + /** + * Gets the locations explored by the sniffer. +- *
      +- * Note: the returned locations use sniffer's current world. + * + * @return a collection of locations + */ +@@ -22,9 +20,6 @@ public interface Sniffer extends Animals { + + /** + * Remove a location of the explored locations. +- *
      +- * Note: the location must be in the sniffer's current world for this +- * method to have any effect. + * + * @param location the location to remove + * @see #getExploredLocations() +diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java +index c48f13cc8ece0fa9913450e4402e496ce01a03fb..af4582f3e4687933dac6ccd43667a373f8daedb6 100644 +--- a/src/main/java/org/bukkit/entity/Villager.java ++++ b/src/main/java/org/bukkit/entity/Villager.java +@@ -224,7 +224,7 @@ public interface Villager extends AbstractVillager { + */ + Profession NITWIT = getProfession("nitwit"); + /** +- * Sheperd profession. Wears a brown robe. Shepherds primarily trade for ++ * Shepherd profession. Wears a brown robe. Shepherds primarily trade for + * wool items, and shears. + */ + Profession SHEPHERD = getProfession("shepherd"); +diff --git a/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java b/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java +index a0f6f1af304190b4c5db4b284d460f625eeb7801..7e21548cac8515c281ec86853e9272ab7695b24f 100644 +--- a/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java +@@ -10,15 +10,19 @@ import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.NotNull; + + /** +- * Called if a block broken by a player drops an item. ++ * Called after a block is broken by a player and potential drops are computed, even if said blocks loot table ++ * does not define any drops at the point the event is constructed. + * + * If the block break is cancelled, this event won't be called. + * +- * If isDropItems in BlockBreakEvent is set to false, this event won't be ++ * If isDropItems in {@link org.bukkit.event.block.BlockBreakEvent} is set to false, this event won't be + * called. + * ++ * If a block is broken and isDropItems is set to true, this event will be called even if the block does ++ * not drop any items, for example glass broken by hand. In this case, #getItems() will be empty. ++ * + * This event will also be called if the player breaks a multi block structure, +- * for example a torch on top of a stone. Both items will have an event call. ++ * for example a torch on top of a stone. Both items will be included in the #getItems() list. + * + * The Block is already broken as this event is called, so #getBlock() will be + * AIR in most cases. Use #getBlockState() for more Information about the broken +diff --git a/src/main/java/org/bukkit/event/block/BlockExplodeEvent.java b/src/main/java/org/bukkit/event/block/BlockExplodeEvent.java +index 1df172c0bb48de3b143179a3f0c63d6ecc30649e..254d549f956053af4264ca3a52d34a97ede4273d 100644 +--- a/src/main/java/org/bukkit/event/block/BlockExplodeEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockExplodeEvent.java +@@ -14,6 +14,9 @@ import org.jetbrains.annotations.NotNull; + * Note that due to the nature of explosions, {@link #getBlock()} will always be + * an air block. {@link #getExplodedBlockState()} should be used to get + * information about the block state that exploded. ++ *

      ++ * The event isn't called if the {@link org.bukkit.GameRule#MOB_GRIEFING} ++ * is disabled as no block interaction will occur. + */ + public class BlockExplodeEvent extends BlockEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/block/BlockPistonRetractEvent.java b/src/main/java/org/bukkit/event/block/BlockPistonRetractEvent.java +index 0392cc3a00f77a11608bf78cc157a411c7bcd976..23b3f44ab009bd49dac60a4045f12858f12cb2ba 100644 +--- a/src/main/java/org/bukkit/event/block/BlockPistonRetractEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockPistonRetractEvent.java +@@ -34,7 +34,7 @@ public class BlockPistonRetractEvent extends BlockPistonEvent { + + /** + * Get an immutable list of the blocks which will be moved by the +- * extending. ++ * retracting. + * + * @return Immutable list of the moved blocks. + */ +diff --git a/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java b/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java +index 77215c1dd2419104607138c45666ce0d84866670..3bfd0f6edc44d6503988f3c3c7a267f1be2986e3 100644 +--- a/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java +@@ -114,7 +114,7 @@ public class BlockPlaceEvent extends BlockEvent implements Cancellable { + + /** + * Gets the value whether the player would be allowed to build here. +- * Defaults to spawn if the server was going to stop them (such as, the ++ * Defaults to false if the server was going to stop them (such as, the + * player is in Spawn). Note that this is an entirely different check + * than BLOCK_CANBUILD, as this refers to a player, not universe-physics + * rule like cactus on dirt. +diff --git a/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java b/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java +index a722e090e788f5497569e69137923682e2abcbac..4c8f388897ff9ddd077695172622c5550651858b 100644 +--- a/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java ++++ b/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java +@@ -81,7 +81,7 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab + /** + * Get a list of available {@link EnchantmentOffer} for the player. You can + * modify the values to change the available offers for the player. An offer +- * may be null, if there isn't a enchantment offer at a specific slot. There ++ * may be null, if there isn't an enchantment offer at a specific slot. There + * are 3 slots in the enchantment table available to modify. + * + * @return list of available enchantment offers +diff --git a/src/main/java/org/bukkit/event/entity/AreaEffectCloudApplyEvent.java b/src/main/java/org/bukkit/event/entity/AreaEffectCloudApplyEvent.java +index a37febd0d4dd5b733e9ee72628fdf9395fec4367..9cee218b9ee14688356f16b1f58512186286e7e9 100644 +--- a/src/main/java/org/bukkit/event/entity/AreaEffectCloudApplyEvent.java ++++ b/src/main/java/org/bukkit/event/entity/AreaEffectCloudApplyEvent.java +@@ -8,7 +8,7 @@ import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.NotNull; + + /** +- * Called when a lingering potion applies it's effects. Happens ++ * Called when a lingering potion applies its effects. Happens + * once every 5 ticks + */ + public class AreaEffectCloudApplyEvent extends EntityEvent implements Cancellable { +diff --git a/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java b/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java +index c746c2e73ab9c91376ceaeab43423edb8009fe1a..5d2597378d36ccace672db0768267d3499100cf1 100644 +--- a/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java ++++ b/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java +@@ -158,11 +158,12 @@ public class CreatureSpawnEvent extends EntitySpawnEvent { + */ + DROWNED, + /** +- * When an cow is spawned by shearing a mushroom cow ++ * When a cow is spawned by shearing a mushroom cow + */ + SHEARED, + /** +- * When eg an effect cloud is spawned as a result of a creeper exploding ++ * When an entity is spawned as a result of an explosion. Like an area effect cloud from ++ * a creeper or a dragon fireball. + */ + EXPLOSION, + /** +diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java +index 0a3699226be1941c0ad1ff1ad8f80bad3aec42aa..971093bd2500543e680db1c92f781bfd5c35dd83 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java +@@ -12,6 +12,10 @@ import org.jetbrains.annotations.Nullable; + + /** + * Called when an entity is damaged by a block ++ *

      ++ * For explosions, the Block returned by {@link #getDamager()} has ++ * already been cleared. See {@link #getDamagerBlockState()} for a snapshot ++ * of the block if it has already been changed. + */ + public class EntityDamageByBlockEvent extends EntityDamageEvent { + private final Block damager; +@@ -51,6 +55,9 @@ public class EntityDamageByBlockEvent extends EntityDamageEvent { + + /** + * Returns the captured BlockState of the block that damaged the player. ++ *

      ++ * This block state is not placed so {@link org.bukkit.block.BlockState#isPlaced} ++ * will be false. + * + * @return the block state + */ +diff --git a/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java b/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java +index fc2158793aec67310bc8d06ac1f0bac39d2a5c3d..50161d313cfcc9e61441589685c3d0e1f057dd86 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java +@@ -10,7 +10,9 @@ import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.NotNull; + + /** +- * Called when an entity explodes ++ * Called when an entity explodes interacting with blocks. The ++ * event isn't called if the {@link org.bukkit.GameRule#MOB_GRIEFING} ++ * is disabled as no block interaction will occur. + */ + public class EntityExplodeEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/entity/EntityPickupItemEvent.java b/src/main/java/org/bukkit/event/entity/EntityPickupItemEvent.java +index c866df03d66dd8724e12c7353da4cf144c70b2c8..94ee5a3354722aa5d825da727b7b7071fdc6bacc 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityPickupItemEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPickupItemEvent.java +@@ -7,7 +7,7 @@ import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.NotNull; + + /** +- * Thrown when a entity picks an item up from the ground ++ * Thrown when an entity picks an item up from the ground + */ + public class EntityPickupItemEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java b/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java +index 4f116956071148a1a148b94ceb4654d3934e2f7f..a7bd15d51a4ff9142cfb341f65050a88b5f5fa8d 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java +@@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + + /** +- * Triggered when a entity is created in the world by a player "placing" an item ++ * Triggered when an entity is created in the world by a player "placing" an item + * on a block. + *
      + * Note that this event is currently only fired for four specific placements: +diff --git a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java +index 31a5515c08c9454d52a0d946d103a2d526c15e48..d743cc5ee34fd7bc5db92f4b17fed9f3aa5ffbcc 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java +@@ -133,7 +133,7 @@ public class EntityPotionEffectEvent extends EntityEvent implements Cancellable + public enum Action { + + /** +- * When the potion effect is added because the entity didn't have it's ++ * When the potion effect is added because the entity didn't have its + * type. + */ + ADDED, +@@ -237,7 +237,7 @@ public class EntityPotionEffectEvent extends EntityEvent implements Cancellable + */ + SPIDER_SPAWN, + /** +- * When the entity gets effects from a totem item saving it's life. ++ * When the entity gets effects from a totem item saving its life. + */ + TOTEM, + /** +diff --git a/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java b/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java +index d51d2ec1d04d9ea8a25a70d0d856f2355ebfcb4a..7ecff9fcee19fc94be784474fea620e5dd434731 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java +@@ -105,7 +105,7 @@ public class EntityRegainHealthEvent extends EntityEvent implements Cancellable + */ + SATIATED, + /** +- * When a player regains health from eating consumables ++ * When an animal regains health from eating consumables + */ + EATING, + /** +diff --git a/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java b/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java +index 842cfd3e9829c61250e98d1a45602a81549de176..808142232a722cb6466bac78d00dc55c18ebe109 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java +@@ -156,7 +156,7 @@ public class EntityTargetEvent extends EntityEvent implements Cancellable { + FOLLOW_LEADER, + /** + * When another entity tempts this entity by having a desired item such +- * as wheat in it's hand. ++ * as wheat in its hand. + */ + TEMPT, + /** +diff --git a/src/main/java/org/bukkit/event/entity/PiglinBarterEvent.java b/src/main/java/org/bukkit/event/entity/PiglinBarterEvent.java +index c17ff41a688b2cbd877cda25d4ec033ac8ef5524..bd67b7cba78b9bbdd82a5a40048e658a979e3108 100644 +--- a/src/main/java/org/bukkit/event/entity/PiglinBarterEvent.java ++++ b/src/main/java/org/bukkit/event/entity/PiglinBarterEvent.java +@@ -10,8 +10,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Stores all data related to the bartering interaction with a piglin. + * +- * This event can be triggered by a piglin picking up an item that's on its +- * bartering list. ++ * Called when a piglin completes a barter. + */ + public class PiglinBarterEvent extends EntityEvent implements Cancellable { + +diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java +index bc71bc2d3ace0d19d730c09f05f9e0655bcee8f5..24077da8e6a7937f66eafc6779206055cf82e8d2 100644 +--- a/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java +@@ -8,7 +8,9 @@ import org.bukkit.inventory.ItemStack; + import org.jetbrains.annotations.NotNull; + + /** +- * Called when an ItemStack is successfully burned as fuel in a furnace. ++ * Called when an ItemStack is successfully burned as fuel in a furnace-like block such as a ++ * {@link org.bukkit.block.Furnace}, {@link org.bukkit.block.Smoker}, or ++ * {@link org.bukkit.block.BlastFurnace}. + */ + public class FurnaceBurnEvent extends BlockEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java +index 65db4991bd4789991868c0d75fea4034fed487a8..5ffd28fd24b4477a07fc9f6a3f669a6f4da9fa26 100644 +--- a/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java +@@ -9,7 +9,9 @@ import org.bukkit.material.MaterialData; + import org.jetbrains.annotations.NotNull; + + /** +- * This event is called when a player takes items out of the furnace ++ * This event is called when a player takes items out of a furnace-like block such as a ++ * {@link org.bukkit.block.Furnace}, {@link org.bukkit.block.Smoker}, or ++ * {@link org.bukkit.block.BlastFurnace}. + */ + public class FurnaceExtractEvent extends BlockExpEvent { + private final Player player; +diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java +index 066e7dd9a34d35c8b643a5efcf95d6a5ef47c7ee..f8f9b08a0bd82a2667ae4e0c99dae9103f0db3f0 100644 +--- a/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java +@@ -6,7 +6,9 @@ import org.bukkit.inventory.ItemStack; + import org.jetbrains.annotations.NotNull; + + /** +- * Called when an ItemStack is successfully smelted in a furnace. ++ * Called when an ItemStack is successfully smelted in a furnace-like block ++ * such as a {@link org.bukkit.block.Furnace}, {@link org.bukkit.block.Smoker}, ++ * or {@link org.bukkit.block.BlastFurnace}. + */ + public class FurnaceSmeltEvent extends BlockCookEvent { + +diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java +index 1440c6115520d692faf75455df35b92aa8734491..0808e7aeffb69160913344de5b5e21d5e857f1d6 100644 +--- a/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java +@@ -8,7 +8,10 @@ import org.bukkit.inventory.ItemStack; + import org.jetbrains.annotations.NotNull; + + /** +- * Called when a Furnace starts smelting. ++ * Called when any of the furnace-like blocks start smelting. ++ *

      ++ * Furnace-like blocks are {@link org.bukkit.block.Furnace}, ++ * {@link org.bukkit.block.Smoker}, and {@link org.bukkit.block.BlastFurnace}. + */ + public class FurnaceStartSmeltEvent extends InventoryBlockStartEvent { + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java +index e1f0ae392c14b940581ed966da42a58ec5cb005d..5832c610e4fad1372e70dc01bd04ba684a89b492 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java +@@ -16,12 +16,16 @@ import org.jetbrains.annotations.Nullable; + /** + * This event is called when a player clicks in an inventory. + *

      ++ * In case of a drag action within an inventory, InventoryClickEvent is never called. ++ * Instead, {@link InventoryDragEvent} is called at the end of the drag. ++ *

      + * Because InventoryClickEvent occurs within a modification of the Inventory, + * not all Inventory related methods are safe to use. + *

      +- * The following should never be invoked by an EventHandler for +- * InventoryClickEvent using the HumanEntity or InventoryView associated with +- * this event: ++ * Methods that change the view a player is looking at should never be invoked ++ * by an EventHandler for InventoryClickEvent using the HumanEntity or ++ * InventoryView associated with this event. ++ * Examples of these include: + *

        + *
      • {@link HumanEntity#closeInventory()} + *
      • {@link HumanEntity#openInventory(Inventory)} +@@ -92,7 +96,7 @@ public class InventoryClickEvent extends InventoryInteractEvent { + /** + * Gets the ItemStack currently in the clicked slot. + * +- * @return the item in the clicked ++ * @return the item in the clicked slot + */ + @Nullable + public ItemStack getCurrentItem() { +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java +index 5861247c1b8ee4fe2736fd5098e05a2ca9ab78ea..c0cc82d98348e8aae3cb56bafb2fcb590b03094f 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java +@@ -7,7 +7,26 @@ import org.bukkit.inventory.InventoryView; + import org.jetbrains.annotations.NotNull; + + /** +- * Represents a player related inventory event ++ * This event is called when a player closes an inventory. ++ *

        ++ * Because InventoryCloseEvent occurs within a modification of the Inventory, ++ * not all Inventory related methods are safe to use. ++ *

        ++ * Methods that change the view a player is looking at should never be invoked ++ * by an EventHandler for InventoryCloseEvent using the HumanEntity or ++ * InventoryView associated with this event. ++ * Examples of these include: ++ *

          ++ *
        • {@link HumanEntity#closeInventory()} ++ *
        • {@link HumanEntity#openInventory(org.bukkit.inventory.Inventory)} ++ *
        • {@link HumanEntity#openWorkbench(org.bukkit.Location, boolean)} ++ *
        • {@link HumanEntity#openEnchanting(org.bukkit.Location, boolean)} ++ *
        • {@link InventoryView#close()} ++ *
        ++ * To invoke one of these methods, schedule a task using ++ * {@link org.bukkit.scheduler.BukkitScheduler#runTask(org.bukkit.plugin.Plugin, Runnable)}, which will run the task ++ * on the next tick. Also be aware that this is not an exhaustive list, and ++ * other methods could potentially create issues as well. + */ + public class InventoryCloseEvent extends InventoryEvent { + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java +index 9013d043503d175004ad276799e5935b7fa59dc4..ceae092eb782698803c6c3df41267dde20ba62b2 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java +@@ -7,7 +7,7 @@ import org.bukkit.inventory.InventoryView; + import org.jetbrains.annotations.NotNull; + + /** +- * Represents a player related inventory event ++ * Called when a player opens an inventory + */ + public class InventoryOpenEvent extends InventoryEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java b/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java +index 08a7c564fe5d3d232998d1789d4d4723a59c1430..8a5be3f0322ac19aeac3f00df54add0e73bc87ed 100644 +--- a/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java +@@ -24,6 +24,20 @@ public class PrepareAnvilEvent extends PrepareInventoryResultEvent { + return (AnvilInventory) super.getInventory(); + } + ++ /** ++ * {@inheritDoc} ++ * ++ *

        ++ * Note: by default custom recipes in anvil are disabled ++ * you should define a repair cost on the anvil inventory ++ * greater or equals to zero in order to allow that. ++ * ++ * @param result result item ++ */ ++ public void setResult(@Nullable ItemStack result) { ++ super.setResult(result); ++ } ++ + @NotNull + @Override + public AnvilView getView() { +diff --git a/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java b/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java +index c3eb020498121746ac0650522b15f1346bbca5fa..9eb2c2a1fe385d306df8e44476339073a7532f60 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerCommandPreprocessEvent.java +@@ -106,7 +106,9 @@ public class PlayerCommandPreprocessEvent extends PlayerEvent implements Cancell + * + * @param player New player which this event will execute as + * @throws IllegalArgumentException if the player provided is null ++ * @deprecated Only works for sign commands; use {@link Player#performCommand(String)}, including those cases + */ ++ @Deprecated(forRemoval = true) + public void setPlayer(@NotNull final Player player) throws IllegalArgumentException { + Preconditions.checkArgument(player != null, "Player cannot be null"); + this.player = player; +@@ -123,11 +125,10 @@ public class PlayerCommandPreprocessEvent extends PlayerEvent implements Cancell + * unmodifiable set. + * + * @return All Players who will see this chat message +- * @deprecated This method is provided for backward compatibility with no +- * guarantee to the effect of viewing or modifying the set. ++ * @deprecated This is simply the online players. Modifications have no effect + */ + @NotNull +- @Deprecated(since = "1.3.1") ++ @Deprecated(since = "1.3.1", forRemoval = true) + public Set getRecipients() { + return recipients; + } +diff --git a/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java b/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java +index e4c32b21ab013703a6a1b07a1ad564d914ebe83f..e58fecf0fe54db06e0e944027923a352fd8005d8 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerResourcePackStatusEvent.java +@@ -6,8 +6,9 @@ import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.NotNull; + + /** +- * Called when a player takes action on a resource pack request sent via +- * {@link Player#setResourcePack(java.lang.String)}. ++ * Called when a player takes action on a resource pack request. ++ * @see Player#setResourcePack(String, String) ++ * @see Player#setResourcePack(String, String, boolean) + */ + public class PlayerResourcePackStatusEvent extends PlayerEvent { + +diff --git a/src/main/java/org/bukkit/generator/ChunkGenerator.java b/src/main/java/org/bukkit/generator/ChunkGenerator.java +index 4b952b0178de24e0902b48dfceff99ef1c926e43..b4dab4cf521c7fb067e88d985572f12d14a2c8df 100644 +--- a/src/main/java/org/bukkit/generator/ChunkGenerator.java ++++ b/src/main/java/org/bukkit/generator/ChunkGenerator.java +@@ -627,7 +627,7 @@ public abstract class ChunkGenerator { + * Get the biome at x, y, z within chunk being generated + * + * @param x the x location in the chunk from 0-15 inclusive +- * @param y the y location in the chunk from minimum (inclusive) - ++ * @param y the y location in the chunk from minHeight (inclusive) - + * maxHeight (exclusive) + * @param z the z location in the chunk from 0-15 inclusive + * @return Biome value +diff --git a/src/main/java/org/bukkit/inventory/EntityEquipment.java b/src/main/java/org/bukkit/inventory/EntityEquipment.java +index 37298cec0234b6c681d912791c1235fbfc427d93..720038083f8c8ab1f29ac424f2d9dbb5cbc8b533 100644 +--- a/src/main/java/org/bukkit/inventory/EntityEquipment.java ++++ b/src/main/java/org/bukkit/inventory/EntityEquipment.java +@@ -37,9 +37,23 @@ public interface EntityEquipment { + public ItemStack getItem(@NotNull EquipmentSlot slot); + + /** +- * Gets a copy of the item the entity is currently holding ++ * Gets the item the entity is currently holding + * in their main hand. + * ++ *

        ++ * This returns a copy if this equipment instance is from a non-player, ++ * or it's an empty stack (has AIR as its type). ++ * For non-empty stacks from players, this returns a live mirror. You can check if this ++ * will return a mirror with ++ *

        {@code
        ++     * EntityEquipment equipment = entity.getEquipment();
        ++     * if (equipment instanceof PlayerInventory) {
        ++     *     equipment.getItemInMainHand(); // will return a mirror
        ++     * } else {
        ++     *     equipment.getItemInMainHand(); // will return a copy
        ++     * }
        ++     * }
        ++ * + * @return the currently held item + */ + @NotNull +@@ -61,9 +75,23 @@ public interface EntityEquipment { + void setItemInMainHand(@Nullable ItemStack item, boolean silent); + + /** +- * Gets a copy of the item the entity is currently holding ++ * Gets the item the entity is currently holding + * in their off hand. + * ++ *

        ++ * This returns a copy if this equipment instance is from a non-player, ++ * or it's an empty stack (has AIR as its type). ++ * For non-empty stacks from players, this returns a live mirror. You can check if this ++ * will return a mirror with ++ *

        {@code
        ++     * EntityEquipment equipment = entity.getEquipment();
        ++     * if (equipment instanceof PlayerInventory) {
        ++     *     equipment.getItemInOffHand(); // will return a mirror
        ++     * } else {
        ++     *     equipment.getItemInOffHand(); // will return a copy
        ++     * }
        ++     * }
        ++ * + * @return the currently held item + */ + @NotNull +@@ -85,7 +113,21 @@ public interface EntityEquipment { + void setItemInOffHand(@Nullable ItemStack item, boolean silent); + + /** +- * Gets a copy of the item the entity is currently holding ++ * Gets the item the entity is currently holding ++ * ++ *

        ++ * This returns a copy if this equipment instance is from a non-player, ++ * or it's an empty stack (has AIR as its type). ++ * For non-empty stacks from players, this returns a live mirror. You can check if this ++ * will return a mirror with ++ *

        {@code
        ++     * EntityEquipment equipment = entity.getEquipment();
        ++     * if (equipment instanceof PlayerInventory) {
        ++     *     equipment.getItemInHand(); // will return a mirror
        ++     * } else {
        ++     *     equipment.getItemInHand(); // will return a copy
        ++     * }
        ++     * }
        + * + * @return the currently held item + * @see #getItemInMainHand() +@@ -110,11 +152,24 @@ public interface EntityEquipment { + void setItemInHand(@Nullable ItemStack stack); + + /** +- * Gets a copy of the helmet currently being worn by the entity ++ * Gets the helmet currently being worn by the entity ++ * ++ *

        ++ * This returns a copy if this equipment instance is from a non-player. ++ * For stacks from players, this returns a live mirror (or null). You can check if this ++ * will return a mirror with ++ *

        {@code
        ++     * EntityEquipment equipment = entity.getEquipment();
        ++     * if (equipment instanceof PlayerInventory) {
        ++     *     equipment.getHelmet(); // will return a mirror
        ++     * } else {
        ++     *     equipment.getHelmet(); // will return a copy
        ++     * }
        ++     * }
        + * + * @return The helmet being worn + */ +- @Nullable ++ @org.bukkit.UndefinedNullability("not null for entities, nullable for players") // Paper + ItemStack getHelmet(); + + /** +@@ -133,11 +188,24 @@ public interface EntityEquipment { + void setHelmet(@Nullable ItemStack helmet, boolean silent); + + /** +- * Gets a copy of the chest plate currently being worn by the entity ++ * Gets the chest plate currently being worn by the entity ++ * ++ *

        ++ * This returns a copy if this equipment instance is from a non-player. ++ * For stacks from players, this returns a live mirror (or null). You can check if this ++ * will return a mirror with ++ *

        {@code
        ++     * EntityEquipment equipment = entity.getEquipment();
        ++     * if (equipment instanceof PlayerInventory) {
        ++     *     equipment.getChestplate(); // will return a mirror
        ++     * } else {
        ++     *     equipment.getChestplate(); // will return a copy
        ++     * }
        ++     * }
        + * + * @return The chest plate being worn + */ +- @Nullable ++ @org.bukkit.UndefinedNullability("not null for entities, nullable for players") // Paper + ItemStack getChestplate(); + + /** +@@ -156,11 +224,24 @@ public interface EntityEquipment { + void setChestplate(@Nullable ItemStack chestplate, boolean silent); + + /** +- * Gets a copy of the leggings currently being worn by the entity ++ * Gets the leggings currently being worn by the entity ++ * ++ *

        ++ * This returns a copy if this equipment instance is from a non-player. ++ * For stacks from players, this returns a live mirror (or null). You can check if this ++ * will return a mirror with ++ *

        {@code
        ++     * EntityEquipment equipment = entity.getEquipment();
        ++     * if (equipment instanceof PlayerInventory) {
        ++     *     equipment.getLeggings(); // will return a mirror
        ++     * } else {
        ++     *     equipment.getLeggings(); // will return a copy
        ++     * }
        ++     * }
        + * + * @return The leggings being worn + */ +- @Nullable ++ @org.bukkit.UndefinedNullability("not null for entities, nullable for players") // Paper + ItemStack getLeggings(); + + /** +@@ -179,11 +260,24 @@ public interface EntityEquipment { + void setLeggings(@Nullable ItemStack leggings, boolean silent); + + /** +- * Gets a copy of the boots currently being worn by the entity ++ * Gets the boots currently being worn by the entity ++ * ++ *

        ++ * This returns a copy if this equipment instance is from a non-player. ++ * For stacks from players, this returns a live mirror (or null). You can check if this ++ * will return a mirror with ++ *

        {@code
        ++     * EntityEquipment equipment = entity.getEquipment();
        ++     * if (equipment instanceof PlayerInventory) {
        ++     *     equipment.getBoots(); // will return a mirror
        ++     * } else {
        ++     *     equipment.getBoots(); // will return a copy
        ++     * }
        ++     * }
        + * + * @return The boots being worn + */ +- @Nullable ++ @org.bukkit.UndefinedNullability("not null for entities, nullable for players") // Paper + ItemStack getBoots(); + + /** +@@ -204,12 +298,25 @@ public interface EntityEquipment { + /** + * Gets all ItemStacks from the armor slots. + * ++ *

        ++ * This returns a copy if this equipment instance is from a non-player, ++ * or it's an empty stack (has AIR as its type). ++ * For non-empty stacks from players, this returns a live mirror. You can check if this ++ * will return a mirror with ++ *

        {@code
        ++     * EntityEquipment equipment = entity.getEquipment();
        ++     * if (equipment instanceof PlayerInventory) {
        ++     *     equipment.getArmorContents(); // will return an array of mirror
        ++     * } else {
        ++     *     equipment.getArmorContents(); // will return an array of copies
        ++     * }
        ++     * }
        ++ * + * @return all the ItemStacks from the armor slots. Individual items can be + * null and are returned in a fixed order starting from the boots and going + * up to the helmet + */ +- @NotNull +- ItemStack[] getArmorContents(); ++ @org.bukkit.UndefinedNullability("not null elements for entities, nullable elements for players") ItemStack @NotNull [] getArmorContents(); // Paper + + /** + * Sets the entities armor to the provided array of ItemStacks +@@ -249,7 +356,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop killed by anything + *
        + * + * @return chance of the currently held item being dropped (1 for non-{@link Mob}) +@@ -262,7 +370,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @param chance the chance of the main hand item being dropped +@@ -276,7 +385,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @return chance of the off hand item being dropped (1 for non-{@link Mob}) +@@ -289,7 +399,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @param chance the chance of off hand item being dropped +@@ -302,7 +413,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @return the chance of the helmet being dropped (1 for non-{@link Mob}) +@@ -314,7 +426,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @param chance of the helmet being dropped +@@ -328,7 +441,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @return the chance of the chest plate being dropped (1 for non-{@link Mob}) +@@ -341,7 +455,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @param chance of the chest plate being dropped +@@ -355,7 +470,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @return the chance of the leggings being dropped (1 for non-{@link Mob}) +@@ -368,7 +484,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @param chance chance of the leggings being dropped +@@ -381,7 +498,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @return the chance of the boots being dropped (1 for non-{@link Mob}) +@@ -393,7 +511,8 @@ public interface EntityEquipment { + * + *
          + *
        • A drop chance of 0.0F will never drop +- *
        • A drop chance of 1.0F will always drop ++ *
        • A drop chance of exactly 1.0F will always drop if killed by a player ++ *
        • A drop chance of greater than 1.0F will always drop if killed by anything + *
        + * + * @param chance of the boots being dropped +diff --git a/src/main/java/org/bukkit/inventory/ItemFlag.java b/src/main/java/org/bukkit/inventory/ItemFlag.java +index 8453bd058d426c1088b04c55d2448d205f0a104b..1b3580d1861af402396121805715e4087b3bc587 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFlag.java ++++ b/src/main/java/org/bukkit/inventory/ItemFlag.java +@@ -35,7 +35,7 @@ public enum ItemFlag { + */ + HIDE_DYE, + /** +- * Setting to show/hide armor trim from leather armor. ++ * Setting to show/hide armor trim from armor. + */ + HIDE_ARMOR_TRIM; + } +diff --git a/src/main/java/org/bukkit/inventory/PlayerInventory.java b/src/main/java/org/bukkit/inventory/PlayerInventory.java +index 6933fb24ea3e6c2e306a69407ae7fa280101419a..b1f4b8f2666e8012eb8a1e21a2b958fe6e03f74f 100644 +--- a/src/main/java/org/bukkit/inventory/PlayerInventory.java ++++ b/src/main/java/org/bukkit/inventory/PlayerInventory.java +@@ -160,7 +160,7 @@ public interface PlayerInventory extends Inventory { + public void setBoots(@Nullable ItemStack boots); + + /** +- * Gets a copy of the item the player is currently holding ++ * Gets the item the player is currently holding + * in their main hand. + * + * @return the currently held item +@@ -176,7 +176,7 @@ public interface PlayerInventory extends Inventory { + void setItemInMainHand(@Nullable ItemStack item); + + /** +- * Gets a copy of the item the player is currently holding ++ * Gets the item the player is currently holding + * in their off hand. + * + * @return the currently held item +@@ -192,7 +192,7 @@ public interface PlayerInventory extends Inventory { + void setItemInOffHand(@Nullable ItemStack item); + + /** +- * Gets a copy of the item the player is currently holding ++ * Gets the item the player is currently holding + * + * @return the currently held item + * @see #getItemInMainHand() +diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java +index 83b08fa8a42b07a9abc84f30df921a5c2a60adbf..64916d17ee81cf2eaec7fbac1cb071db3b3eb258 100644 +--- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java ++++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java +@@ -24,8 +24,6 @@ public class ShapedRecipe extends CraftingRecipe { + * @param result The item you want the recipe to create. + * @see ShapedRecipe#shape(String...) + * @see ShapedRecipe#setIngredient(char, Material) +- * @see ShapedRecipe#setIngredient(char, Material, int) +- * @see ShapedRecipe#setIngredient(char, MaterialData) + * @see ShapedRecipe#setIngredient(char, RecipeChoice) + * @deprecated Recipes must have keys. Use {@link #ShapedRecipe(NamespacedKey, ItemStack)} + * instead. +@@ -45,8 +43,6 @@ public class ShapedRecipe extends CraftingRecipe { + * @exception IllegalArgumentException if the {@code result} is an empty item (AIR) + * @see ShapedRecipe#shape(String...) + * @see ShapedRecipe#setIngredient(char, Material) +- * @see ShapedRecipe#setIngredient(char, Material, int) +- * @see ShapedRecipe#setIngredient(char, MaterialData) + * @see ShapedRecipe#setIngredient(char, RecipeChoice) + */ + public ShapedRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result) { +diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +index 969710cc69fe4c1265f509915cd6bf78d47a2d78..354af775093fd3a74dac6c64244d8f3464397f72 100644 +--- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java ++++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +@@ -31,11 +31,8 @@ public class ShapelessRecipe extends CraftingRecipe { + * @param result The item you want the recipe to create. + * @exception IllegalArgumentException if the {@code result} is an empty item (AIR) + * @see ShapelessRecipe#addIngredient(Material) +- * @see ShapelessRecipe#addIngredient(MaterialData) +- * @see ShapelessRecipe#addIngredient(Material,int) + * @see ShapelessRecipe#addIngredient(int,Material) +- * @see ShapelessRecipe#addIngredient(int,MaterialData) +- * @see ShapelessRecipe#addIngredient(int,Material,int) ++ * @see ShapelessRecipe#addIngredient(RecipeChoice) + */ + public ShapelessRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result) { + super(key, checkResult(result)); +@@ -175,7 +172,7 @@ public class ShapelessRecipe extends CraftingRecipe { + + /** + * Removes multiple instances of an ingredient from the list. If there are +- * less instances then specified, all will be removed. Only removes exact ++ * fewer instances than specified, all will be removed. Only removes exact + * matches, with a data value of 0. + * + * @param count The number of copies to remove. +diff --git a/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java b/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java +index 07c3dff4d6190ef388d9c1e1c36f67f00a3e8e66..597a18a767b68b47e81454b7d44613c7178c1366 100644 +--- a/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java ++++ b/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java +@@ -28,7 +28,7 @@ public class StonecuttingRecipe implements Recipe, Keyed { + } + + /** +- * Create a cooking recipe to craft the specified ItemStack. ++ * Create a Stonecutting recipe to craft the specified ItemStack. + * + * @param key The unique recipe key + * @param result The item you want the recipe to create. +@@ -42,7 +42,7 @@ public class StonecuttingRecipe implements Recipe, Keyed { + } + + /** +- * Sets the input of this cooking recipe. ++ * Sets the input of this Stonecutting recipe. + * + * @param input The input material. + * @return The changed recipe, so you can chain calls. +@@ -64,7 +64,7 @@ public class StonecuttingRecipe implements Recipe, Keyed { + } + + /** +- * Sets the input of this cooking recipe. ++ * Sets the input of this Stonecutting recipe. + * + * @param input The input choice. + * @return The changed recipe, so you can chain calls. +diff --git a/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java b/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java +index e7d905b1146b2bdd2da5bdeb6bf3541fb181d59e..c7d3041221742f6655155f19ef2addcaf2401015 100644 +--- a/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java +@@ -32,6 +32,11 @@ public interface BlockStateMeta extends ItemMeta { + * @param blockState the block state to attach to the block. + * @throws IllegalArgumentException if the blockState is null + * or invalid for this item. ++ * ++ * @apiNote As of 1.20.5 the block state carries a copy of the item's data deviations. ++ * As such, setting the block state via this method will reset secondary deviations of the item meta. ++ * This can manifest in the addition to an existing lore failing or a change of a previously added display name. ++ * It is hence recommended to first mutate the block state, set it back, and then mutate the item meta. + */ + void setBlockState(@NotNull BlockState blockState); + } +diff --git a/src/main/java/org/bukkit/inventory/meta/CrossbowMeta.java b/src/main/java/org/bukkit/inventory/meta/CrossbowMeta.java +index 35c6594fd1040a1af1029e7260e5e3a9307b107d..d58719ee75bef8bc265bfc81bc5d88a426e01dd9 100644 +--- a/src/main/java/org/bukkit/inventory/meta/CrossbowMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/CrossbowMeta.java +@@ -28,8 +28,7 @@ public interface CrossbowMeta extends ItemMeta { + * Removes all projectiles when given null. + * + * @param projectiles the projectiles to set +- * @throws IllegalArgumentException if one of the projectiles is not an +- * arrow or firework rocket ++ * @throws IllegalArgumentException if one of the projectiles is empty + */ + void setChargedProjectiles(@Nullable List projectiles); + +@@ -37,8 +36,7 @@ public interface CrossbowMeta extends ItemMeta { + * Adds a charged projectile to this item. + * + * @param item projectile +- * @throws IllegalArgumentException if the projectile is not an arrow or +- * firework rocket ++ * @throws IllegalArgumentException if the projectile is empty + */ + void addChargedProjectile(@NotNull ItemStack item); + } +diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +index 753a756525f6afea981dd0c2984e7a747d4d148b..c083ac4344dd1b2b56cbe103ce80daac945defd5 100644 +--- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +@@ -328,7 +328,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + /** + * Gets the enchantable component. Higher values allow higher enchantments. + * +- * @return max_stack_size ++ * @return the enchantable value + */ + int getEnchantable(); + +@@ -661,11 +661,6 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + + /** + * Gets the item which this item will convert to when used. +- *

        +- * The returned component is a snapshot of its current state and does not +- * reflect a live view of what is on an item. After changing any value on +- * this component, it must be set with {@link #setUseRemainder(ItemStack)} +- * to apply the changes. + * + * @return remainder + */ +@@ -802,7 +797,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * The returned component is a snapshot of its current state and does not + * reflect a live view of what is on an item. After changing any value on + * this component, it must be set with +- * {@link #setJukeboxPlayable(org.bukkit.inventory.meta.components.JukeboxComponent)} ++ * {@link #setJukeboxPlayable(org.bukkit.inventory.meta.components.JukeboxPlayableComponent)} + * to apply the changes. + * + * @return component +@@ -811,7 +806,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + JukeboxPlayableComponent getJukeboxPlayable(); + + /** +- * Sets the item tool. ++ * Sets the jukebox playable component. + * + * @param jukeboxPlayable new component + */ +@@ -838,7 +833,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + /** + * Return an immutable copy of all {@link Attribute}s and their + * {@link AttributeModifier}s for a given {@link EquipmentSlot}.
        +- * Any {@link AttributeModifier} that does have have a given ++ * Any {@link AttributeModifier} that does have a given + * {@link EquipmentSlot} will be returned. This is because + * AttributeModifiers without a slot are active in any slot.
        + * If there are no attributes set for the given slot, an empty map +diff --git a/src/main/java/org/bukkit/inventory/meta/LeatherArmorMeta.java b/src/main/java/org/bukkit/inventory/meta/LeatherArmorMeta.java +index c1676991c3cc5f8d6e3f97d8cb356d6e2aa52809..c701d5fbc5fef503f18a3a46fa54c983bf96e895 100644 +--- a/src/main/java/org/bukkit/inventory/meta/LeatherArmorMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/LeatherArmorMeta.java +@@ -8,8 +8,9 @@ import org.jetbrains.annotations.Nullable; + + /** + * Represents leather armor ({@link Material#LEATHER_BOOTS}, {@link +- * Material#LEATHER_CHESTPLATE}, {@link Material#LEATHER_HELMET}, or {@link +- * Material#LEATHER_LEGGINGS}) that can be colored. ++ * Material#LEATHER_LEGGINGS}, {@link Material#LEATHER_CHESTPLATE}, {@link ++ * Material#LEATHER_HELMET}, {@link Material#LEATHER_HORSE_ARMOR} or {@link ++ * Material#WOLF_ARMOR}) that can be colored. + */ + public interface LeatherArmorMeta extends ItemMeta { + +@@ -18,6 +19,9 @@ public interface LeatherArmorMeta extends ItemMeta { + * be {@link ItemFactory#getDefaultLeatherColor()}. + * + * @return the color of the armor, never null ++ * @apiNote The method yielding {@link ItemFactory#getDefaultLeatherColor()} is incorrect ++ * for {@link Material#WOLF_ARMOR} as its default color differs. Generally, it is recommended to check ++ * {@link #isDyed()} to determine if this leather armor is dyed than to compare this color to the default. + */ + @NotNull + Color getColor(); +@@ -25,8 +29,7 @@ public interface LeatherArmorMeta extends ItemMeta { + /** + * Sets the color of the armor. + * +- * @param color the color to set. Setting it to null is equivalent to +- * setting it to {@link ItemFactory#getDefaultLeatherColor()}. ++ * @param color the color to set. + */ + void setColor(@Nullable Color color); + +diff --git a/src/main/java/org/bukkit/inventory/meta/OminousBottleMeta.java b/src/main/java/org/bukkit/inventory/meta/OminousBottleMeta.java +index 43f0df04f3cdff7d7db73321a2886f3a737e3c9f..5c741228b2338a7c4de2fe736eb789511abf4880 100644 +--- a/src/main/java/org/bukkit/inventory/meta/OminousBottleMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/OminousBottleMeta.java +@@ -3,7 +3,7 @@ package org.bukkit.inventory.meta; + import org.jetbrains.annotations.NotNull; + + /** +- * Represents a map that can be scalable. ++ * Represents an ominous bottle with an amplifier of the bad omen effect. + */ + public interface OminousBottleMeta extends ItemMeta { + +diff --git a/src/main/java/org/bukkit/inventory/meta/components/UseCooldownComponent.java b/src/main/java/org/bukkit/inventory/meta/components/UseCooldownComponent.java +index 4086a413895f82b51bf192ceffdfee4a939c6fed..172032e56ee8e4e1b13ec6b41a5122a33b18bc64 100644 +--- a/src/main/java/org/bukkit/inventory/meta/components/UseCooldownComponent.java ++++ b/src/main/java/org/bukkit/inventory/meta/components/UseCooldownComponent.java +@@ -6,8 +6,7 @@ import org.jetbrains.annotations.ApiStatus; + import org.jetbrains.annotations.Nullable; + + /** +- * Represents a component which determines the cooldown applied to use of this +- * item. ++ * Represents a component which determines the cooldown applied when using this item before it is available for use again. + */ + @ApiStatus.Experimental + public interface UseCooldownComponent extends ConfigurationSerializable { +@@ -39,7 +38,7 @@ public interface UseCooldownComponent extends ConfigurationSerializable { + /** + * Sets the custom cooldown group to be used for similar items. + * +- * @param song the cooldown group ++ * @param group the cooldown group + */ +- void setCooldownGroup(@Nullable NamespacedKey song); ++ void setCooldownGroup(@Nullable NamespacedKey group); + } +diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java +index 8c76716249e44ed8bf6be94c1f5c7b6d9bb35be2..68a0ed5f0ed25e98f4ab4d1e482ec2ccfda9cd3a 100644 +--- a/src/main/java/org/bukkit/plugin/Plugin.java ++++ b/src/main/java/org/bukkit/plugin/Plugin.java +@@ -18,7 +18,7 @@ import org.jetbrains.annotations.Nullable; + */ + public interface Plugin extends TabExecutor { + /** +- * Returns the folder that the plugin data's files are located in. The ++ * Returns the folder that the plugin data files are located in. The + * folder may not yet exist. + * + * @return The folder +@@ -27,9 +27,9 @@ public interface Plugin extends TabExecutor { + public File getDataFolder(); + + /** +- * Returns the plugin.yaml file containing the details for this plugin ++ * Returns the plugin.yml file containing the details for this plugin + * +- * @return Contents of the plugin.yaml file ++ * @return Contents of the plugin.yml file + * @deprecated May be inaccurate due to different plugin implementations. + * @see Plugin#getPluginMeta() + */ +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +index 2a14522c484febcd880d00197df4359a0020dddd..7f17337b9f0fb60fa1c91c47af496c03290d1b1c 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +@@ -69,7 +69,7 @@ public abstract class JavaPlugin extends PluginBase { + } + + /** +- * Returns the folder that the plugin data's files are located in. The ++ * Returns the folder that the plugin data files are located in. The + * folder may not yet exist. + * + * @return The folder. +@@ -127,9 +127,9 @@ public abstract class JavaPlugin extends PluginBase { + } + + /** +- * Returns the plugin.yaml file containing the details for this plugin ++ * Returns the plugin.yml file containing the details for this plugin + * +- * @return Contents of the plugin.yaml file ++ * @return Contents of the plugin.yml file + * @deprecated No longer applicable to all types of plugins + */ + @NotNull +diff --git a/src/main/java/org/bukkit/plugin/messaging/PluginMessageRecipient.java b/src/main/java/org/bukkit/plugin/messaging/PluginMessageRecipient.java +index b84b37fe27d84574dc5897285f1d9a1437bd322c..281ae60a6be7e39aab4f27b4c7de3d49ada9a557 100644 +--- a/src/main/java/org/bukkit/plugin/messaging/PluginMessageRecipient.java ++++ b/src/main/java/org/bukkit/plugin/messaging/PluginMessageRecipient.java +@@ -31,7 +31,8 @@ public interface PluginMessageRecipient { + + /** + * Gets a set containing all the Plugin Channels that this client is +- * listening on. ++ * listening on. Does not contain the BungeeCord channel due to its ++ * special status. + * + * @return Set containing all the channels that this client may accept. + */ +diff --git a/src/main/java/org/bukkit/projectiles/ProjectileSource.java b/src/main/java/org/bukkit/projectiles/ProjectileSource.java +index eabd8b926ec1c934cd7e77b7cc6adfae16771021..8557bfefaf02538dec95adb29734ae2cf50f3f8c 100644 +--- a/src/main/java/org/bukkit/projectiles/ProjectileSource.java ++++ b/src/main/java/org/bukkit/projectiles/ProjectileSource.java +@@ -12,6 +12,10 @@ public interface ProjectileSource { + + /** + * Launches a {@link Projectile} from the ProjectileSource. ++ *

        ++ * The family of launchProjectile methods only promise the ability to launch projectile types ++ * that the {@link ProjectileSource} is capable of firing in vanilla. ++ * Any other types of projectiles *may* be implemented but are not part of the method contract. + * + * @param a projectile subclass + * @param projectile class of the projectile to launch +@@ -23,6 +27,10 @@ public interface ProjectileSource { + /** + * Launches a {@link Projectile} from the ProjectileSource with an + * initial velocity. ++ *

        ++ * The family of launchProjectile methods only promise the ability to launch projectile types ++ * that the {@link ProjectileSource} is capable of firing in vanilla. ++ * Any other types of projectiles *may* be implemented but are not part of the method contract. + * + * @param a projectile subclass + * @param projectile class of the projectile to launch +diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java +index d57634dd3796a695aba7623d2b04e35d630887b3..35755c9165c1b48eaacfff86a50a7973476fe04b 100644 +--- a/src/main/java/org/bukkit/scoreboard/Objective.java ++++ b/src/main/java/org/bukkit/scoreboard/Objective.java +@@ -86,7 +86,7 @@ public interface Objective { + * + * @return true if scores are modifiable + * @throws IllegalStateException if this objective has been unregistered +- * @see Criterias#HEALTH ++ * @see Criteria#HEALTH + */ + boolean isModifiable(); + +diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java +index 284468fd3d310a7acdffa31f0f6593f5a98419ba..38deee00cfe2f6803070e98cd9ded95d859bf8e1 100644 +--- a/src/main/java/org/bukkit/scoreboard/Team.java ++++ b/src/main/java/org/bukkit/scoreboard/Team.java +@@ -265,7 +265,7 @@ public interface Team extends net.kyori.adventure.audience.ForwardingAudience { + * Gets the Set of entries on the team + * + * @return entries on the team +- * @throws IllegalStateException if this entries has been unregistered ++ * @throws IllegalStateException if this team has been unregistered + */ + @NotNull + Set getEntries(); +diff --git a/src/main/java/org/bukkit/util/BoundingBox.java b/src/main/java/org/bukkit/util/BoundingBox.java +index 9883983c33fcff0f4c1e23867adafa436e2ed96f..5017b73bcec0d4d5256d89db14201c03829dc981 100644 +--- a/src/main/java/org/bukkit/util/BoundingBox.java ++++ b/src/main/java/org/bukkit/util/BoundingBox.java +@@ -358,7 +358,7 @@ public class BoundingBox implements Cloneable, ConfigurationSerializable { + *

        + * Negative values will shrink the bounding box in the corresponding + * direction. Shrinking will be limited to the point where the affected +- * opposite faces would meet if the they shrank at uniform speeds. ++ * opposite faces would meet if they shrank at uniform speeds. + * + * @param negativeX the amount of expansion in the negative x direction + * @param negativeY the amount of expansion in the negative y direction +diff --git a/src/main/java/org/bukkit/util/CachedServerIcon.java b/src/main/java/org/bukkit/util/CachedServerIcon.java +index 612958a331575d1da2715531ebdf6b1168f2e860..9a7768d41270714d4a1c89b4dcb436cc66f57545 100644 +--- a/src/main/java/org/bukkit/util/CachedServerIcon.java ++++ b/src/main/java/org/bukkit/util/CachedServerIcon.java +@@ -5,7 +5,7 @@ import org.bukkit.event.server.ServerListPingEvent; + import org.jetbrains.annotations.Nullable; + + /** +- * This is a cached version of a server-icon. It's internal representation ++ * This is a cached version of a server-icon. Its internal representation + * and implementation is undefined. + * + * @see Server#getServerIcon() diff --git a/patches/api/0054-Fix-upstream-javadocs.patch b/patches/api/0054-Fix-upstream-javadocs.patch deleted file mode 100644 index 86737f5199ee..000000000000 --- a/patches/api/0054-Fix-upstream-javadocs.patch +++ /dev/null @@ -1,391 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Sat, 10 Jun 2017 16:59:40 -0500 -Subject: [PATCH] Fix upstream javadocs - -Upstream still refuses to use Java 8 with the API so they are likely unaware these are even issues. - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index aea30cacbf43c4c6d30b0c9e0d59fcd2db444ad8..e25a6532deca1df59eff2ab59697b851535ee952 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -1331,6 +1331,8 @@ public final class Bukkit { - - /** - * Gets every player that has ever played on this server. -+ *

        -+ * This method can be expensive as it loads all the player data files from the disk. - * - * @return an array containing all previous players - */ -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 5e4e6e83ac6b52493cb285561425bed53ffff2b6..2bfbb0ce71c8c5f8bd9bbd908488831b94ce583f 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -509,13 +509,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - *

      - *

      - * Note: If set to 0, {@link SpawnCategory} mobs spawning will be disabled. -- *

      -- * Minecraft default: 1. -- *
      -- * Note: the {@link SpawnCategory#MISC} are not consider. - * - * @param spawnCategory the category of spawn - * @return the default ticks per {@link SpawnCategory} mobs spawn value -+ * @throws IllegalArgumentException if the category is {@link SpawnCategory#MISC} - */ - public int getTicksPerSpawns(@NotNull SpawnCategory spawnCategory); - -@@ -1126,6 +1123,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - - /** - * Gets every player that has ever played on this server. -+ *

      -+ * This method can be expensive as it loads all the player data files from the disk. - * - * @return an array containing all previous players - */ -diff --git a/src/main/java/org/bukkit/entity/ArmorStand.java b/src/main/java/org/bukkit/entity/ArmorStand.java -index 91fc11dda99de506be83d40df8929bf7cd8e8d85..7dc631ebd009f5f5c3ac1699c3f3515c47609c05 100644 ---- a/src/main/java/org/bukkit/entity/ArmorStand.java -+++ b/src/main/java/org/bukkit/entity/ArmorStand.java -@@ -360,5 +360,8 @@ public interface ArmorStand extends LivingEntity { - * @param move {@code true} if this armour stand can move, {@code false} otherwise - */ - void setCanMove(boolean move); -+ -+ @Override -+ org.bukkit.inventory.@NotNull EntityEquipment getEquipment(); - // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java -index 2cf43eac30187a43a01c81b3021b2cfec0d4ba8a..864941be2d07de08f63e740ad2becf1dc5790433 100644 ---- a/src/main/java/org/bukkit/entity/HumanEntity.java -+++ b/src/main/java/org/bukkit/entity/HumanEntity.java -@@ -21,6 +21,11 @@ import org.jetbrains.annotations.Nullable; - */ - public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder { - -+ // Paper start -+ @Override -+ org.bukkit.inventory.@NotNull EntityEquipment getEquipment(); -+ // Paper end -+ - /** - * Returns the name of this player - * -diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java -index be9334a8b5fba9181ad63c211697e798be63da25..0514a141cb93a650be38c63d4336d46e4304f4b6 100644 ---- a/src/main/java/org/bukkit/entity/Mob.java -+++ b/src/main/java/org/bukkit/entity/Mob.java -@@ -8,6 +8,10 @@ import org.jetbrains.annotations.Nullable; - */ - public interface Mob extends LivingEntity, Lootable { - -+ // Paper start -+ @Override -+ org.bukkit.inventory.@org.jetbrains.annotations.NotNull EntityEquipment getEquipment(); -+ // Paper end - /** - * Instructs this Mob to set the specified LivingEntity as its target. - *

      -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 6e6ec4095ac9d6c17b1ee657133f6521ead35226..cf4beb02cce7b87facd5465291286f1b5e97db59 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -303,15 +303,15 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - - /** - * Saves the players current location, health, inventory, motion, and -- * other information into the username.dat file, in the world/player -- * folder -+ * other information into the <uuid>.dat file, in the -+ * <level-name>/playerdata/ folder. - */ - public void saveData(); - - /** - * Loads the players current location, health, inventory, motion, and -- * other information from the username.dat file, in the world/player -- * folder. -+ * other information from the <uuid>.dat file, in the -+ * <level-name>/playerdata/ folder. - *

      - * Note: This will overwrite the players current inventory, health, - * motion, etc, with the state from the saved dat file. -@@ -767,7 +767,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * - * Use supplied alternative character to the section symbol to represent legacy color codes. - * -- * @param alternateChar Alternate symbol such as '&' -+ * @param alternateChar Alternate symbol such as '&' - * @param message The message to send - * @deprecated use {@link #sendActionBar(Component)} - */ -diff --git a/src/main/java/org/bukkit/entity/Slime.java b/src/main/java/org/bukkit/entity/Slime.java -index 1119e26e270bb45f517955b19d95a9ec3d113634..4631647c64c89ffdde2d9b63bdab974acfe6cb3d 100644 ---- a/src/main/java/org/bukkit/entity/Slime.java -+++ b/src/main/java/org/bukkit/entity/Slime.java -@@ -11,6 +11,16 @@ public interface Slime extends Mob { - public int getSize(); - - /** -+ * Setting the size of the slime (regardless of previous size) -+ * will set the following attributes: -+ *

        -+ *
      • {@link org.bukkit.attribute.Attribute#GENERIC_MAX_HEALTH}
      • -+ *
      • {@link org.bukkit.attribute.Attribute#GENERIC_MOVEMENT_SPEED}
      • -+ *
      • {@link org.bukkit.attribute.Attribute#GENERIC_ATTACK_DAMAGE}
      • -+ *
      -+ * to their per-size defaults and heal the -+ * slime to its max health (assuming it's alive). -+ * - * @param sz The new size of the slime. - */ - public void setSize(int sz); -diff --git a/src/main/java/org/bukkit/inventory/EntityEquipment.java b/src/main/java/org/bukkit/inventory/EntityEquipment.java -index d5b50a4a954fed35d37f03f1a277cc173ca106df..a91fa5386afd7a1137adb921ad5adb798604772f 100644 ---- a/src/main/java/org/bukkit/inventory/EntityEquipment.java -+++ b/src/main/java/org/bukkit/inventory/EntityEquipment.java -@@ -37,9 +37,23 @@ public interface EntityEquipment { - public ItemStack getItem(@NotNull EquipmentSlot slot); - - /** -- * Gets a copy of the item the entity is currently holding -+ * Gets the item the entity is currently holding - * in their main hand. - * -+ *

      -+ * This returns a copy if this equipment instance is from a non-player, -+ * or it's an empty stack (has AIR as its type). -+ * For non-empty stacks from players, this returns a live mirror. You can check if this -+ * will return a mirror with -+ *

      {@code
      -+     * EntityEquipment equipment = entity.getEquipment();
      -+     * if (equipment instanceof PlayerInventory) {
      -+     *     equipment.getItemInMainHand(); // will return a mirror
      -+     * } else {
      -+     *     equipment.getItemInMainHand(); // will return a copy
      -+     * }
      -+     * }
      -+ * - * @return the currently held item - */ - @NotNull -@@ -61,9 +75,23 @@ public interface EntityEquipment { - void setItemInMainHand(@Nullable ItemStack item, boolean silent); - - /** -- * Gets a copy of the item the entity is currently holding -+ * Gets the item the entity is currently holding - * in their off hand. - * -+ *

      -+ * This returns a copy if this equipment instance is from a non-player, -+ * or it's an empty stack (has AIR as its type). -+ * For non-empty stacks from players, this returns a live mirror. You can check if this -+ * will return a mirror with -+ *

      {@code
      -+     * EntityEquipment equipment = entity.getEquipment();
      -+     * if (equipment instanceof PlayerInventory) {
      -+     *     equipment.getItemInOffHand(); // will return a mirror
      -+     * } else {
      -+     *     equipment.getItemInOffHand(); // will return a copy
      -+     * }
      -+     * }
      -+ * - * @return the currently held item - */ - @NotNull -@@ -85,7 +113,21 @@ public interface EntityEquipment { - void setItemInOffHand(@Nullable ItemStack item, boolean silent); - - /** -- * Gets a copy of the item the entity is currently holding -+ * Gets the item the entity is currently holding -+ * -+ *

      -+ * This returns a copy if this equipment instance is from a non-player, -+ * or it's an empty stack (has AIR as its type). -+ * For non-empty stacks from players, this returns a live mirror. You can check if this -+ * will return a mirror with -+ *

      {@code
      -+     * EntityEquipment equipment = entity.getEquipment();
      -+     * if (equipment instanceof PlayerInventory) {
      -+     *     equipment.getItemInHand(); // will return a mirror
      -+     * } else {
      -+     *     equipment.getItemInHand(); // will return a copy
      -+     * }
      -+     * }
      - * - * @return the currently held item - * @see #getItemInMainHand() -@@ -110,11 +152,24 @@ public interface EntityEquipment { - void setItemInHand(@Nullable ItemStack stack); - - /** -- * Gets a copy of the helmet currently being worn by the entity -+ * Gets the helmet currently being worn by the entity -+ * -+ *

      -+ * This returns a copy if this equipment instance is from a non-player. -+ * For stacks from players, this returns a live mirror (or null). You can check if this -+ * will return a mirror with -+ *

      {@code
      -+     * EntityEquipment equipment = entity.getEquipment();
      -+     * if (equipment instanceof PlayerInventory) {
      -+     *     equipment.getItemInHand(); // will return a mirror
      -+     * } else {
      -+     *     equipment.getItemInHand(); // will return a copy
      -+     * }
      -+     * }
      - * - * @return The helmet being worn - */ -- @Nullable -+ @org.bukkit.UndefinedNullability("not null for entities, nullable for players") // Paper - ItemStack getHelmet(); - - /** -@@ -133,11 +188,24 @@ public interface EntityEquipment { - void setHelmet(@Nullable ItemStack helmet, boolean silent); - - /** -- * Gets a copy of the chest plate currently being worn by the entity -+ * Gets the chest plate currently being worn by the entity -+ * -+ *

      -+ * This returns a copy if this equipment instance is from a non-player. -+ * For stacks from players, this returns a live mirror (or null). You can check if this -+ * will return a mirror with -+ *

      {@code
      -+     * EntityEquipment equipment = entity.getEquipment();
      -+     * if (equipment instanceof PlayerInventory) {
      -+     *     equipment.getChestplate(); // will return a mirror
      -+     * } else {
      -+     *     equipment.getChestplate(); // will return a copy
      -+     * }
      -+     * }
      - * - * @return The chest plate being worn - */ -- @Nullable -+ @org.bukkit.UndefinedNullability("not null for entities, nullable for players") // Paper - ItemStack getChestplate(); - - /** -@@ -156,11 +224,24 @@ public interface EntityEquipment { - void setChestplate(@Nullable ItemStack chestplate, boolean silent); - - /** -- * Gets a copy of the leggings currently being worn by the entity -+ * Gets the leggings currently being worn by the entity -+ * -+ *

      -+ * This returns a copy if this equipment instance is from a non-player. -+ * For stacks from players, this returns a live mirror (or null). You can check if this -+ * will return a mirror with -+ *

      {@code
      -+     * EntityEquipment equipment = entity.getEquipment();
      -+     * if (equipment instanceof PlayerInventory) {
      -+     *     equipment.getLeggings(); // will return a mirror
      -+     * } else {
      -+     *     equipment.getLeggings(); // will return a copy
      -+     * }
      -+     * }
      - * - * @return The leggings being worn - */ -- @Nullable -+ @org.bukkit.UndefinedNullability("not null for entities, nullable for players") // Paper - ItemStack getLeggings(); - - /** -@@ -179,11 +260,24 @@ public interface EntityEquipment { - void setLeggings(@Nullable ItemStack leggings, boolean silent); - - /** -- * Gets a copy of the boots currently being worn by the entity -+ * Gets the boots currently being worn by the entity -+ * -+ *

      -+ * This returns a copy if this equipment instance is from a non-player. -+ * For stacks from players, this returns a live mirror (or null). You can check if this -+ * will return a mirror with -+ *

      {@code
      -+     * EntityEquipment equipment = entity.getEquipment();
      -+     * if (equipment instanceof PlayerInventory) {
      -+     *     equipment.getBoots(); // will return a mirror
      -+     * } else {
      -+     *     equipment.getBoots(); // will return a copy
      -+     * }
      -+     * }
      - * - * @return The boots being worn - */ -- @Nullable -+ @org.bukkit.UndefinedNullability("not null for entities, nullable for players") // Paper - ItemStack getBoots(); - - /** -@@ -202,12 +296,25 @@ public interface EntityEquipment { - void setBoots(@Nullable ItemStack boots, boolean silent); - - /** -- * Gets a copy of all worn armor -+ * Gets all worn armor -+ * -+ *

      -+ * This returns a copy if this equipment instance is from a non-player, -+ * or it's an empty stack (has AIR as its type). -+ * For non-empty stacks from players, this returns a live mirror. You can check if this -+ * will return a mirror with -+ *

      {@code
      -+     * EntityEquipment equipment = entity.getEquipment();
      -+     * if (equipment instanceof PlayerInventory) {
      -+     *     equipment.getArmorContents(); // will return an array of mirror
      -+     * } else {
      -+     *     equipment.getArmorContents(); // will return an array of copies
      -+     * }
      -+     * }
      - * - * @return The array of worn armor. Individual items may be null. - */ -- @NotNull -- ItemStack[] getArmorContents(); -+ @org.bukkit.UndefinedNullability("not null elements for entities, nullable elements for players") ItemStack @NotNull [] getArmorContents(); // Paper - - /** - * Sets the entities armor to the provided array of ItemStacks -diff --git a/src/main/java/org/bukkit/inventory/PlayerInventory.java b/src/main/java/org/bukkit/inventory/PlayerInventory.java -index 62fbd7f6d8195bebcab7f704a0a485a1bbeca26c..5461f7fa75f5a065bb333b4a113640b5fe1e3825 100644 ---- a/src/main/java/org/bukkit/inventory/PlayerInventory.java -+++ b/src/main/java/org/bukkit/inventory/PlayerInventory.java -@@ -158,7 +158,7 @@ public interface PlayerInventory extends Inventory { - public void setBoots(@Nullable ItemStack boots); - - /** -- * Gets a copy of the item the player is currently holding -+ * Gets the item the player is currently holding - * in their main hand. - * - * @return the currently held item -@@ -174,7 +174,7 @@ public interface PlayerInventory extends Inventory { - void setItemInMainHand(@Nullable ItemStack item); - - /** -- * Gets a copy of the item the player is currently holding -+ * Gets the item the player is currently holding - * in their off hand. - * - * @return the currently held item -@@ -190,7 +190,7 @@ public interface PlayerInventory extends Inventory { - void setItemInOffHand(@Nullable ItemStack item); - - /** -- * Gets a copy of the item the player is currently holding -+ * Gets the item the player is currently holding - * - * @return the currently held item - * @see #getItemInMainHand() diff --git a/patches/api/0054-Item-canEntityPickup.patch b/patches/api/0054-Item-canEntityPickup.patch new file mode 100644 index 000000000000..fc22e7407937 --- /dev/null +++ b/patches/api/0054-Item-canEntityPickup.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 5 May 2017 03:57:08 -0500 +Subject: [PATCH] Item#canEntityPickup + + +diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java +index 65dd4554c6cc0801fcbc0ef6809b794dcebd1124..bfecd0633458586c0352eeb1a95bb57b12f9101e 100644 +--- a/src/main/java/org/bukkit/entity/Item.java ++++ b/src/main/java/org/bukkit/entity/Item.java +@@ -89,4 +89,20 @@ public interface Item extends Entity { + */ + @Nullable + public UUID getThrower(); ++ ++ // Paper start ++ /** ++ * Gets if non-player entities can pick this Item up ++ * ++ * @return True if non-player entities can pickup ++ */ ++ public boolean canMobPickup(); ++ ++ /** ++ * Sets if non-player entities can pick this Item up ++ * ++ * @param canMobPickup True to allow non-player entity pickup ++ */ ++ public void setCanMobPickup(boolean canMobPickup); ++ // Paper end + } diff --git a/patches/api/0055-Item-canEntityPickup.patch b/patches/api/0055-Item-canEntityPickup.patch deleted file mode 100644 index 1d18a940a25d..000000000000 --- a/patches/api/0055-Item-canEntityPickup.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 5 May 2017 03:57:08 -0500 -Subject: [PATCH] Item#canEntityPickup - - -diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java -index 65dd4554c6cc0801fcbc0ef6809b794dcebd1124..ab06c640cef1309ab44b0fae8d95df48cdc869a7 100644 ---- a/src/main/java/org/bukkit/entity/Item.java -+++ b/src/main/java/org/bukkit/entity/Item.java -@@ -89,4 +89,20 @@ public interface Item extends Entity { - */ - @Nullable - public UUID getThrower(); -+ -+ // Paper Start -+ /** -+ * Gets if non-player entities can pick this Item up -+ * -+ * @return True if non-player entities can pickup -+ */ -+ public boolean canMobPickup(); -+ -+ /** -+ * Sets if non-player entities can pick this Item up -+ * -+ * @param canMobPickup True to allow non-player entity pickup -+ */ -+ public void setCanMobPickup(boolean canMobPickup); -+ // Paper end - } diff --git a/patches/api/0055-PlayerAttemptPickupItemEvent.patch b/patches/api/0055-PlayerAttemptPickupItemEvent.patch new file mode 100644 index 000000000000..b6059f57571e --- /dev/null +++ b/patches/api/0055-PlayerAttemptPickupItemEvent.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 11 Jun 2017 16:30:37 -0500 +Subject: [PATCH] PlayerAttemptPickupItemEvent + + +diff --git a/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java b/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..eff29875f6282d8bd04a33cb572c90090742d3b2 +--- /dev/null ++++ b/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java +@@ -0,0 +1,94 @@ ++package org.bukkit.event.player; ++ ++import org.bukkit.entity.Item; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Thrown when a player attempts to pick an item up from the ground ++ */ ++@NullMarked ++public class PlayerAttemptPickupItemEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Item item; ++ private final int remaining; ++ private boolean flyAtPlayer = true; ++ ++ private boolean cancelled; ++ ++ @Deprecated // Remove in 1.13 // Remove in 1.14? ++ @ApiStatus.Internal ++ public PlayerAttemptPickupItemEvent(final Player player, final Item item) { ++ this(player, item, 0); ++ } ++ ++ @ApiStatus.Internal ++ public PlayerAttemptPickupItemEvent(final Player player, final Item item, final int remaining) { ++ super(player); ++ this.item = item; ++ this.remaining = remaining; ++ } ++ ++ /** ++ * Gets the Item attempted by the player. ++ * ++ * @return Item ++ */ ++ public Item getItem() { ++ return this.item; ++ } ++ ++ /** ++ * Gets the amount that will remain on the ground, if any ++ * ++ * @return amount that will remain on the ground ++ */ ++ public int getRemaining() { ++ return this.remaining; ++ } ++ ++ /** ++ * Set if the item will fly at the player ++ *

      Cancelling the event will set this value to false.

      ++ * ++ * @param flyAtPlayer {@code true} for item to fly at player ++ */ ++ public void setFlyAtPlayer(boolean flyAtPlayer) { ++ this.flyAtPlayer = flyAtPlayer; ++ } ++ ++ /** ++ * Gets if the item will fly at the player ++ * ++ * @return {@code true} if the item will fly at the player ++ */ ++ public boolean getFlyAtPlayer() { ++ return this.flyAtPlayer; ++ } ++ ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancelled = cancel; ++ this.flyAtPlayer = !cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0056-Add-UnknownCommandEvent.patch b/patches/api/0056-Add-UnknownCommandEvent.patch new file mode 100644 index 000000000000..8c7d30f48d64 --- /dev/null +++ b/patches/api/0056-Add-UnknownCommandEvent.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sweepyoface +Date: Sat, 17 Jun 2017 18:48:06 -0400 +Subject: [PATCH] Add UnknownCommandEvent + + +diff --git a/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java b/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..58fe8f60ad5e7ca0ffddebb7ba5748bbfb129ddd +--- /dev/null ++++ b/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java +@@ -0,0 +1,105 @@ ++package org.bukkit.event.command; ++ ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; ++import org.bukkit.command.CommandSender; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Thrown when a player executes a command that is not defined ++ */ ++@NullMarked ++public class UnknownCommandEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final CommandSender sender; ++ private final String commandLine; ++ private @Nullable Component message; ++ ++ @ApiStatus.Internal ++ public UnknownCommandEvent(final CommandSender sender, final String commandLine, final @Nullable Component message) { ++ super(false); ++ this.sender = sender; ++ this.commandLine = commandLine; ++ this.message = message; ++ } ++ ++ /** ++ * Gets the CommandSender or ConsoleCommandSender ++ * ++ * @return Sender of the command ++ */ ++ public CommandSender getSender() { ++ return this.sender; ++ } ++ ++ /** ++ * Gets the command that was sent ++ * ++ * @return Command sent ++ */ ++ public String getCommandLine() { ++ return this.commandLine; ++ } ++ ++ /** ++ * Gets message that will be returned ++ * ++ * @return Unknown command message ++ * @deprecated use {@link #message()} ++ */ ++ @Deprecated ++ public @Nullable String getMessage() { ++ return this.message == null ? null : LegacyComponentSerializer.legacySection().serialize(this.message); ++ } ++ ++ /** ++ * Sets message that will be returned ++ *

      ++ * Set to {@code null} to avoid any message being sent ++ * ++ * @param message the message to be returned, or {@code null} ++ * @deprecated use {@link #message(Component)} ++ */ ++ @Deprecated ++ public void setMessage(@Nullable String message) { ++ this.message(message == null ? null : LegacyComponentSerializer.legacySection().deserialize(message)); ++ } ++ ++ /** ++ * Gets message that will be returned ++ * ++ * @return Unknown command message ++ */ ++ @Contract(pure = true) ++ public @Nullable Component message() { ++ return this.message; ++ } ++ ++ /** ++ * Sets message that will be returned ++ *

      ++ * Set to {@code null} to avoid any message being sent ++ * ++ * @param message the message to be returned, or {@code null} ++ */ ++ public void message(@Nullable Component message) { ++ this.message = message; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} ++ diff --git a/patches/api/0056-PlayerAttemptPickupItemEvent.patch b/patches/api/0056-PlayerAttemptPickupItemEvent.patch deleted file mode 100644 index 6b504ae68865..000000000000 --- a/patches/api/0056-PlayerAttemptPickupItemEvent.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 11 Jun 2017 16:30:37 -0500 -Subject: [PATCH] PlayerAttemptPickupItemEvent - - -diff --git a/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java b/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0788153a9641e75da565d2e6eee37eeee1cbc61e ---- /dev/null -+++ b/src/main/java/org/bukkit/event/player/PlayerAttemptPickupItemEvent.java -@@ -0,0 +1,90 @@ -+package org.bukkit.event.player; -+ -+import org.bukkit.entity.Item; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Thrown when a player attempts to pick an item up from the ground -+ */ -+public class PlayerAttemptPickupItemEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull private final Item item; -+ private final int remaining; -+ private boolean flyAtPlayer = true; -+ private boolean isCancelled = false; -+ -+ @Deprecated // Remove in 1.13 // Remove in 1.14? -+ public PlayerAttemptPickupItemEvent(@NotNull final Player player, @NotNull final Item item) { -+ this(player, item, 0); -+ } -+ -+ public PlayerAttemptPickupItemEvent(@NotNull final Player player, @NotNull final Item item, final int remaining) { -+ super(player); -+ this.item = item; -+ this.remaining = remaining; -+ } -+ -+ /** -+ * Gets the Item attempted by the player. -+ * -+ * @return Item -+ */ -+ @NotNull -+ public Item getItem() { -+ return item; -+ } -+ -+ /** -+ * Gets the amount that will remain on the ground, if any -+ * -+ * @return amount that will remain on the ground -+ */ -+ public int getRemaining() { -+ return remaining; -+ } -+ -+ /** -+ * Set if the item will fly at the player -+ *

      Cancelling the event will set this value to false.

      -+ * -+ * @param flyAtPlayer True for item to fly at player -+ */ -+ public void setFlyAtPlayer(boolean flyAtPlayer) { -+ this.flyAtPlayer = flyAtPlayer; -+ } -+ -+ /** -+ * Gets if the item will fly at the player -+ * -+ * @return True if the item will fly at the player -+ */ -+ public boolean getFlyAtPlayer() { -+ return this.flyAtPlayer; -+ } -+ -+ -+ @Override -+ public boolean isCancelled() { -+ return this.isCancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.isCancelled = cancel; -+ this.flyAtPlayer = !cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0057-Add-UnknownCommandEvent.patch b/patches/api/0057-Add-UnknownCommandEvent.patch deleted file mode 100644 index 64312ce49a71..000000000000 --- a/patches/api/0057-Add-UnknownCommandEvent.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Sweepyoface -Date: Sat, 17 Jun 2017 18:48:06 -0400 -Subject: [PATCH] Add UnknownCommandEvent - - -diff --git a/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java b/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..57128c780bc73e39d2733cceeb21dc06c2422c3c ---- /dev/null -+++ b/src/main/java/org/bukkit/event/command/UnknownCommandEvent.java -@@ -0,0 +1,113 @@ -+package org.bukkit.event.command; -+ -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -+import org.bukkit.command.CommandSender; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Thrown when a player executes a command that is not defined -+ */ -+public class UnknownCommandEvent extends Event { -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull private CommandSender sender; -+ @NotNull private String commandLine; -+ @Nullable private Component message; -+ -+ @Deprecated -+ public UnknownCommandEvent(@NotNull final CommandSender sender, @NotNull final String commandLine, @Nullable final String message) { -+ this(sender, commandLine, message == null ? null : LegacyComponentSerializer.legacySection().deserialize(message)); -+ } -+ -+ public UnknownCommandEvent(@NotNull final CommandSender sender, @NotNull final String commandLine, @Nullable final Component message) { -+ super(false); -+ this.sender = sender; -+ this.commandLine = commandLine; -+ this.message = message; -+ } -+ -+ /** -+ * Gets the CommandSender or ConsoleCommandSender -+ *

      -+ * -+ * @return Sender of the command -+ */ -+ @NotNull -+ public CommandSender getSender() { -+ return sender; -+ } -+ -+ /** -+ * Gets the command that was send -+ *

      -+ * -+ * @return Command sent -+ */ -+ @NotNull -+ public String getCommandLine() { -+ return commandLine; -+ } -+ -+ /** -+ * Gets message that will be returned -+ *

      -+ * -+ * @return Unknown command message -+ * @deprecated use {@link #message()} -+ */ -+ @Nullable -+ @Deprecated -+ public String getMessage() { -+ return this.message == null ? null : LegacyComponentSerializer.legacySection().serialize(this.message); -+ } -+ -+ /** -+ * Sets message that will be returned -+ *

      -+ * Set to null to avoid any message being sent -+ * -+ * @param message the message to be returned, or null -+ * @deprecated use {@link #message(Component)} -+ */ -+ @Deprecated -+ public void setMessage(@Nullable String message) { -+ this.message(message == null ? null : LegacyComponentSerializer.legacySection().deserialize(message)); -+ } -+ -+ /** -+ * Gets message that will be returned -+ *

      -+ * -+ * @return Unknown command message -+ */ -+ @Nullable -+ public Component message() { -+ return this.message; -+ } -+ -+ /** -+ * Sets message that will be returned -+ *

      -+ * Set to null to avoid any message being sent -+ * -+ * @param message the message to be returned, or null -+ */ -+ public void message(@Nullable Component message) { -+ this.message = message; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -+ diff --git a/patches/api/0057-Basic-PlayerProfile-API.patch b/patches/api/0057-Basic-PlayerProfile-API.patch new file mode 100644 index 000000000000..5363667b4635 --- /dev/null +++ b/patches/api/0057-Basic-PlayerProfile-API.patch @@ -0,0 +1,530 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 15 Jan 2018 21:46:46 -0500 +Subject: [PATCH] Basic PlayerProfile API + +Provides basic elements of a PlayerProfile to be used by future API/events + +diff --git a/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java b/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java +new file mode 100644 +index 0000000000000000000000000000000000000000..324c1cba46c9eef95cc22ffa231b04f9298a5e00 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java +@@ -0,0 +1,246 @@ ++package com.destroystokyo.paper.profile; ++ ++import java.util.Collection; ++import java.util.Set; ++import java.util.UUID; ++import java.util.concurrent.CompletableFuture; ++import org.bukkit.profile.PlayerTextures; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Represents a players profile for the game, such as UUID, Name, and textures. ++ */ ++@NullMarked ++public interface PlayerProfile extends org.bukkit.profile.PlayerProfile { ++ ++ /** ++ * @return The players name, if set ++ */ ++ @Override ++ @Nullable ++ String getName(); ++ ++ /** ++ * Sets this profiles Name ++ * ++ * @param name The new Name ++ * @return The previous Name ++ */ ++ @Deprecated(forRemoval = true, since = "1.18.1") ++ String setName(@Nullable String name); ++ ++ /** ++ * @return The players unique identifier, if set ++ */ ++ @Nullable ++ UUID getId(); ++ ++ /** ++ * Sets this profiles UUID ++ * ++ * @param uuid The new UUID ++ * @return The previous UUID ++ */ ++ @Deprecated(forRemoval = true, since = "1.18.1") ++ @Nullable ++ UUID setId(@Nullable UUID uuid); ++ ++ /** ++ * Gets the {@link PlayerTextures} of this profile. ++ * This will build a snapshot of the current texture data once ++ * requested inside PlayerTextures. ++ * ++ * @return the textures, not null ++ */ ++ @Override ++ PlayerTextures getTextures(); ++ ++ /** ++ * Copies the given textures. ++ * ++ * @param textures the textures to copy, or null to clear the ++ * textures ++ */ ++ @Override ++ void setTextures(@Nullable PlayerTextures textures); ++ ++ /** ++ * @return A Mutable set of this players properties, such as textures. ++ * Values specified here are subject to implementation details. ++ */ ++ Set getProperties(); ++ ++ /** ++ * Check if the Profile has the specified property ++ * ++ * @param property Property name to check ++ * @return If the property is set ++ */ ++ boolean hasProperty(@Nullable String property); ++ ++ /** ++ * Sets a property. If the property already exists, the previous one will be replaced ++ * ++ * @param property Property to set. ++ * @throws IllegalArgumentException if setting the property results in more than 16 properties ++ */ ++ void setProperty(ProfileProperty property); ++ ++ /** ++ * Sets multiple properties. If any of the set properties already exist, it will be replaced ++ * ++ * @param properties The properties to set ++ * @throws IllegalArgumentException if the number of properties exceeds 16 ++ */ ++ void setProperties(Collection properties); ++ ++ /** ++ * Removes a specific property from this profile ++ * ++ * @param property The property to remove ++ * @return If a property was removed ++ */ ++ boolean removeProperty(@Nullable String property); ++ ++ /** ++ * Removes a specific property from this profile ++ * ++ * @param property The property to remove ++ * @return If a property was removed ++ */ ++ default boolean removeProperty(final ProfileProperty property) { ++ return this.removeProperty(property.getName()); ++ } ++ ++ /** ++ * Removes all properties in the collection ++ * ++ * @param properties The properties to remove ++ * @return If any property was removed ++ */ ++ default boolean removeProperties(final Collection properties) { ++ boolean removed = false; ++ for (final ProfileProperty property : properties) { ++ if (this.removeProperty(property)) { ++ removed = true; ++ } ++ } ++ return removed; ++ } ++ ++ /** ++ * Clears all properties on this profile ++ */ ++ void clearProperties(); ++ ++ /** ++ * @return If the profile is now complete (has UUID and Name) ++ */ ++ @Override ++ boolean isComplete(); ++ ++ /** ++ * Like {@link #complete(boolean)} but will try only from cache, and not make network calls ++ * Does not account for textures. ++ * ++ * @return If the profile is now complete (has UUID and Name) ++ */ ++ boolean completeFromCache(); ++ ++ /** ++ * Like {@link #complete(boolean)} but will try only from cache, and not make network calls ++ * Does not account for textures. ++ * ++ * @param onlineMode Treat this as online mode or not ++ * @return If the profile is now complete (has UUID and Name) ++ */ ++ boolean completeFromCache(boolean onlineMode); ++ ++ /** ++ * Like {@link #complete(boolean)} but will try only from cache, and not make network calls ++ * Does not account for textures. ++ * ++ * @param lookupUUID If only name is supplied, should we do a UUID lookup ++ * @param onlineMode Treat this as online mode or not ++ * @return If the profile is now complete (has UUID and Name) ++ */ ++ boolean completeFromCache(boolean lookupUUID, boolean onlineMode); ++ ++ /** ++ * If this profile is not complete, then make the API call to complete it. ++ * This is a blocking operation and should be done asynchronously. ++ *

      ++ * This will also complete textures. If you do not want to load textures, use {{@link #complete(boolean)}} ++ * ++ * @return If the profile is now complete (has UUID and Name) (if you get rate limited, this operation may fail) ++ */ ++ default boolean complete() { ++ return this.complete(true); ++ } ++ ++ /** ++ * If this profile is not complete, then make the API call to complete it. ++ * This is a blocking operation and should be done asynchronously. ++ *

      ++ * Optionally will also fill textures. ++ *

      ++ * Online mode will be automatically determined ++ * ++ * @param textures controls if we should fill the profile with texture properties ++ * @return If the profile is now complete (has UUID and Name) (if you get rate limited, this operation may fail) ++ */ ++ boolean complete(boolean textures); ++ ++ /** ++ * If this profile is not complete, then make the API call to complete it. ++ * This is a blocking operation and should be done asynchronously. ++ *

      ++ * Optionally will also fill textures. ++ * ++ * @param textures controls if we should fill the profile with texture properties ++ * @param onlineMode Treat this server as online mode or not ++ * @return If the profile is now complete (has UUID and Name) (if you get rate limited, this operation may fail) ++ */ ++ boolean complete(boolean textures, boolean onlineMode); ++ ++ /** ++ * Produces an updated player profile based on this profile. ++ *

      ++ * This tries to produce a completed profile by filling in missing ++ * properties (name, unique id, textures, etc.), and updates existing ++ * properties (e.g. name, textures, etc.) to their official and up-to-date ++ * values. This operation does not alter the current profile, but produces a ++ * new updated {@link PlayerProfile}. ++ *

      ++ * If no player exists for the unique id or name of this profile, this ++ * operation yields a profile that is equal to the current profile, which ++ * might not be complete. ++ *

      ++ * This is an asynchronous operation: Updating the profile can result in an ++ * outgoing connection in another thread in order to fetch the latest ++ * profile properties. The returned {@link CompletableFuture} will be ++ * completed once the updated profile is available. In order to not block ++ * the server's main thread, you should not wait for the result of the ++ * returned CompletableFuture on the server's main thread. Instead, if you ++ * want to do something with the updated player profile on the server's main ++ * thread once it is available, you could do something like this: ++ *

      ++     * profile.update().thenAcceptAsync(updatedProfile -> {
      ++     *     // Do something with the updated profile:
      ++     *     // ...
      ++     * }, runnable -> Bukkit.getScheduler().runTask(plugin, runnable));
      ++     * 
      ++ */ ++ @Override ++ CompletableFuture update(); ++ ++ /** ++ * Whether this Profile has textures associated to it ++ * ++ * @return If it has a textures property ++ */ ++ default boolean hasTextures() { ++ return this.hasProperty("textures"); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java b/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java +new file mode 100644 +index 0000000000000000000000000000000000000000..35341d8f1ac2d80f339084ef80d099a545027554 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java +@@ -0,0 +1,73 @@ ++package com.destroystokyo.paper.profile; ++ ++import com.google.common.base.Preconditions; ++import java.util.Objects; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Represents a property on a {@link PlayerProfile} ++ */ ++@NullMarked ++public final class ProfileProperty { ++ ++ private final String name; ++ private final String value; ++ private final @Nullable String signature; ++ ++ public ProfileProperty(final String name, final String value) { ++ this(name, value, null); ++ } ++ ++ public ProfileProperty(final String name, final String value, final @Nullable String signature) { ++ this.name = Preconditions.checkNotNull(name, "ProfileProperty name can not be null"); ++ this.value = Preconditions.checkNotNull(value, "ProfileProperty value can not be null"); ++ this.signature = signature; ++ Preconditions.checkArgument(name.length() <= 64, "ProfileProperty name can not be longer than 64 characters"); ++ Preconditions.checkArgument(value.length() <= Short.MAX_VALUE, "ProfileProperty value can not be longer than 32767 characters"); ++ Preconditions.checkArgument(signature == null || signature.length() <= 1024, "ProfileProperty signature can not be longer than 1024 characters"); ++ } ++ ++ /** ++ * @return The property name, ie "textures" ++ */ ++ public String getName() { ++ return this.name; ++ } ++ ++ /** ++ * @return The property value, likely to be base64 encoded ++ */ ++ public String getValue() { ++ return this.value; ++ } ++ ++ /** ++ * @return A signature from Mojang for signed properties ++ */ ++ public @Nullable String getSignature() { ++ return this.signature; ++ } ++ ++ /** ++ * @return If this property has a signature or not ++ */ ++ public boolean isSigned() { ++ return this.signature != null; ++ } ++ ++ @Override ++ public boolean equals(final @Nullable Object o) { ++ if (this == o) return true; ++ if (o == null || this.getClass() != o.getClass()) return false; ++ final ProfileProperty that = (ProfileProperty) o; ++ return Objects.equals(this.name, that.name) && ++ Objects.equals(this.value, that.value) && ++ Objects.equals(this.signature, that.signature); ++ } ++ ++ @Override ++ public int hashCode() { ++ return Objects.hash(this.name); ++ } ++} +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index bacdb1742ecb98bb10651b0582500449bf904910..c351fb49a8d044312ca77f5cd85d939a95bdae20 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2424,6 +2424,89 @@ public final class Bukkit { + public static boolean suggestPlayerNamesWhenNullTabCompletions() { + return server.suggestPlayerNamesWhenNullTabCompletions(); + } ++ ++ /** ++ * Creates a PlayerProfile for the specified uuid, with name as null. ++ * ++ * If a player with the passed uuid exists on the server at the time of creation, the returned player profile will ++ * be populated with the properties of said player (including their uuid and name). ++ * ++ * @param uuid UUID to create profile for ++ * @return A PlayerProfile object ++ */ ++ @NotNull ++ public static com.destroystokyo.paper.profile.PlayerProfile createProfile(@NotNull UUID uuid) { ++ return server.createProfile(uuid); ++ } ++ ++ /** ++ * Creates a PlayerProfile for the specified name, with UUID as null. ++ * ++ * If a player with the passed name exists on the server at the time of creation, the returned player profile will ++ * be populated with the properties of said player (including their uuid and name). ++ *

      ++ * E.g. if the player 'jeb_' is currently playing on the server, calling {@code createProfile("JEB_")} will ++ * yield a profile with the name 'jeb_', their uuid and their textures. ++ * To bypass this pre-population on a case-insensitive name match, see {@link #createProfileExact(UUID, String)}. ++ *

      ++ * ++ * @param name Name to create profile for ++ * @return A PlayerProfile object ++ * @throws IllegalArgumentException if the name is longer than 16 characters ++ * @throws IllegalArgumentException if the name contains invalid characters ++ */ ++ @NotNull ++ public static com.destroystokyo.paper.profile.PlayerProfile createProfile(@NotNull String name) { ++ return server.createProfile(name); ++ } ++ ++ /** ++ * Creates a PlayerProfile for the specified name/uuid ++ * ++ * Both UUID and Name can not be null at same time. One must be supplied. ++ * If a player with the passed uuid or name exists on the server at the time of creation, the returned player ++ * profile will be populated with the properties of said player (including their uuid and name). ++ *

      ++ * E.g. if the player 'jeb_' is currently playing on the server, calling {@code createProfile(null, "JEB_")} will ++ * yield a profile with the name 'jeb_', their uuid and their textures. ++ * To bypass this pre-population on an case-insensitive name match, see {@link #createProfileExact(UUID, String)}. ++ *

      ++ * ++ * The name comparison will compare the {@link String#toLowerCase()} version of both the passed name parameter and ++ * a players name to honour the case-insensitive nature of a mojang profile lookup. ++ * ++ * @param uuid UUID to create profile for ++ * @param name Name to create profile for ++ * @return A PlayerProfile object ++ * @throws IllegalArgumentException if the name is longer than 16 characters ++ * @throws IllegalArgumentException if the name contains invalid characters ++ */ ++ @NotNull ++ public static com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUID uuid, @Nullable String name) { ++ return server.createProfile(uuid, name); ++ } ++ ++ /** ++ * Creates an exact PlayerProfile for the specified name/uuid ++ * ++ * Both UUID and Name can not be null at same time. One must be supplied. ++ * If a player with the passed uuid or name exists on the server at the time of creation, the returned player ++ * profile will be populated with the properties of said player. ++ *

      ++ * Compared to {@link #createProfile(UUID, String)}, this method will never mutate the passed uuid or name. ++ * If a player with either the same uuid or a matching name (case-insensitive) is found on the server, their ++ * properties, such as textures, will be pre-populated in the profile, however the passed uuid and name stay intact. ++ * ++ * @param uuid UUID to create profile for ++ * @param name Name to create profile for ++ * @return A PlayerProfile object ++ * @throws IllegalArgumentException if the name is longer than 16 characters ++ * @throws IllegalArgumentException if the name contains invalid characters ++ */ ++ @NotNull ++ public static com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name) { ++ return server.createProfileExact(uuid, name); ++ } + // Paper end + + @NotNull +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index a506e618448c3bf4b56f54f8fe00d7158df29dd7..51bed70fdc7221f41035e13af1fba69b492507ac 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2108,5 +2108,80 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @return true if player names should be suggested + */ + boolean suggestPlayerNamesWhenNullTabCompletions(); ++ ++ /** ++ * Creates a PlayerProfile for the specified uuid, with name as null. ++ * ++ * If a player with the passed uuid exists on the server at the time of creation, the returned player profile will ++ * be populated with the properties of said player (including their uuid and name). ++ * ++ * @param uuid UUID to create profile for ++ * @return A PlayerProfile object ++ */ ++ @NotNull ++ com.destroystokyo.paper.profile.PlayerProfile createProfile(@NotNull UUID uuid); ++ ++ /** ++ * Creates a PlayerProfile for the specified name, with UUID as null. ++ * ++ * If a player with the passed name exists on the server at the time of creation, the returned player profile will ++ * be populated with the properties of said player (including their uuid and name). ++ *

      ++ * E.g. if the player 'jeb_' is currently playing on the server, calling {@code createProfile("JEB_")} will ++ * yield a profile with the name 'jeb_', their uuid and their textures. ++ * To bypass this pre-population on a case-insensitive name match, see {@link #createProfileExact(UUID, String)}. ++ *

      ++ * ++ * @param name Name to create profile for ++ * @return A PlayerProfile object ++ * @throws IllegalArgumentException if the name is longer than 16 characters ++ * @throws IllegalArgumentException if the name contains invalid characters ++ */ ++ @NotNull ++ com.destroystokyo.paper.profile.PlayerProfile createProfile(@NotNull String name); ++ ++ /** ++ * Creates a PlayerProfile for the specified name/uuid ++ * ++ * Both UUID and Name can not be null at same time. One must be supplied. ++ * If a player with the passed uuid or name exists on the server at the time of creation, the returned player ++ * profile will be populated with the properties of said player (including their uuid and name). ++ *

      ++ * E.g. if the player 'jeb_' is currently playing on the server, calling {@code createProfile(null, "JEB_")} will ++ * yield a profile with the name 'jeb_', their uuid and their textures. ++ * To bypass this pre-population on an case-insensitive name match, see {@link #createProfileExact(UUID, String)}. ++ *

      ++ * ++ * The name comparison will compare the {@link String#toLowerCase()} version of both the passed name parameter and ++ * a players name to honour the case-insensitive nature of a mojang profile lookup. ++ * ++ * @param uuid UUID to create profile for ++ * @param name Name to create profile for ++ * @return A PlayerProfile object ++ * @throws IllegalArgumentException if the name is longer than 16 characters ++ * @throws IllegalArgumentException if the name contains invalid characters ++ */ ++ @NotNull ++ com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUID uuid, @Nullable String name); ++ ++ /** ++ * Creates an exact PlayerProfile for the specified name/uuid ++ * ++ * Both UUID and Name can not be null at same time. One must be supplied. ++ * If a player with the passed uuid or name exists on the server at the time of creation, the returned player ++ * profile will be populated with the properties of said player. ++ *

      ++ * Compared to {@link #createProfile(UUID, String)}, this method will never mutate the passed uuid or name. ++ * If a player with either the same uuid or a matching name (case-insensitive) is found on the server, their ++ * properties, such as textures, will be pre-populated in the profile, however the passed uuid and name stay intact. ++ * ++ * @param uuid UUID to create profile for ++ * @param name Name to create profile for ++ * @return A PlayerProfile object ++ * @throws IllegalArgumentException if the name is longer than 16 characters ++ * @throws IllegalArgumentException if the name contains invalid characters ++ */ ++ @NotNull ++ com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name); + // Paper end + } +diff --git a/src/main/java/org/bukkit/profile/PlayerProfile.java b/src/main/java/org/bukkit/profile/PlayerProfile.java +index 16ae1282f3178e8873483a25a5d5cce16b2c21a9..fc46add38bf59dc1a04ea566fd230dcd8ae2708c 100644 +--- a/src/main/java/org/bukkit/profile/PlayerProfile.java ++++ b/src/main/java/org/bukkit/profile/PlayerProfile.java +@@ -93,7 +93,7 @@ public interface PlayerProfile extends Cloneable, ConfigurationSerializable { + * PlayerProfile once it is available + */ + @NotNull +- CompletableFuture update(); ++ CompletableFuture update(); // Paper + + @NotNull + PlayerProfile clone(); diff --git a/patches/api/0058-Basic-PlayerProfile-API.patch b/patches/api/0058-Basic-PlayerProfile-API.patch deleted file mode 100644 index 806e90fd4951..000000000000 --- a/patches/api/0058-Basic-PlayerProfile-API.patch +++ /dev/null @@ -1,457 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 15 Jan 2018 21:46:46 -0500 -Subject: [PATCH] Basic PlayerProfile API - -Provides basic elements of a PlayerProfile to be used by future API/events - -diff --git a/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java b/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d4766e2116c2202d84080637a2832bef0ab3f718 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/profile/PlayerProfile.java -@@ -0,0 +1,199 @@ -+package com.destroystokyo.paper.profile; -+ -+import java.util.Collection; -+import java.util.Set; -+import java.util.UUID; -+ -+import org.bukkit.profile.PlayerTextures; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Represents a players profile for the game, such as UUID, Name, and textures. -+ */ -+public interface PlayerProfile extends org.bukkit.profile.PlayerProfile { -+ -+ /** -+ * @return The players name, if set -+ */ -+ @Nullable -+ String getName(); -+ -+ /** -+ * Sets this profiles Name -+ * -+ * @param name The new Name -+ * @return The previous Name -+ */ -+ @NotNull -+ @Deprecated(forRemoval = true) -+ String setName(@Nullable String name); -+ -+ /** -+ * @return The players unique identifier, if set -+ */ -+ @Nullable UUID getId(); -+ -+ /** -+ * Sets this profiles UUID -+ * -+ * @param uuid The new UUID -+ * @return The previous UUID -+ */ -+ @Nullable -+ @Deprecated(forRemoval = true) -+ UUID setId(@Nullable UUID uuid); -+ -+ /** -+ * Gets the {@link PlayerTextures} of this profile. -+ * This will build a snapshot of the current texture data once -+ * requested inside PlayerTextures. -+ * -+ * @return the textures, not null -+ */ -+ @NotNull -+ PlayerTextures getTextures(); -+ -+ /** -+ * Copies the given textures. -+ * -+ * @param textures the textures to copy, or null to clear the -+ * textures -+ */ -+ void setTextures(@Nullable PlayerTextures textures); -+ -+ /** -+ * @return A Mutable set of this players properties, such as textures. -+ * Values specified here are subject to implementation details. -+ */ -+ @NotNull Set getProperties(); -+ -+ /** -+ * Check if the Profile has the specified property -+ * @param property Property name to check -+ * @return If the property is set -+ */ -+ boolean hasProperty(@Nullable String property); -+ -+ /** -+ * Sets a property. If the property already exists, the previous one will be replaced -+ * @param property Property to set. -+ */ -+ void setProperty(@NotNull ProfileProperty property); -+ -+ /** -+ * Sets multiple properties. If any of the set properties already exist, it will be replaced -+ * @param properties The properties to set -+ */ -+ void setProperties(@NotNull Collection properties); -+ -+ /** -+ * Removes a specific property from this profile -+ * @param property The property to remove -+ * @return If a property was removed -+ */ -+ boolean removeProperty(@Nullable String property); -+ -+ /** -+ * Removes a specific property from this profile -+ * @param property The property to remove -+ * @return If a property was removed -+ */ -+ default boolean removeProperty(@NotNull ProfileProperty property) { -+ return removeProperty(property.getName()); -+ } -+ -+ /** -+ * Removes all properties in the collection -+ * @param properties The properties to remove -+ * @return If any property was removed -+ */ -+ default boolean removeProperties(@NotNull Collection properties) { -+ boolean removed = false; -+ for (ProfileProperty property : properties) { -+ if (removeProperty(property)) { -+ removed = true; -+ } -+ } -+ return removed; -+ } -+ -+ /** -+ * Clears all properties on this profile -+ */ -+ void clearProperties(); -+ -+ /** -+ * @return If the profile is now complete (has UUID and Name) -+ */ -+ boolean isComplete(); -+ -+ /** -+ * Like {@link #complete(boolean)} but will try only from cache, and not make network calls -+ * Does not account for textures. -+ * -+ * @return If the profile is now complete (has UUID and Name) -+ */ -+ boolean completeFromCache(); -+ -+ /** -+ * Like {@link #complete(boolean)} but will try only from cache, and not make network calls -+ * Does not account for textures. -+ * -+ * @param onlineMode Treat this as online mode or not -+ * @return If the profile is now complete (has UUID and Name) -+ */ -+ boolean completeFromCache(boolean onlineMode); -+ -+ /** -+ * Like {@link #complete(boolean)} but will try only from cache, and not make network calls -+ * Does not account for textures. -+ * -+ * @param lookupUUID If only name is supplied, should we do a UUID lookup -+ * @param onlineMode Treat this as online mode or not -+ * @return If the profile is now complete (has UUID and Name) -+ */ -+ boolean completeFromCache(boolean lookupUUID, boolean onlineMode); -+ -+ /** -+ * If this profile is not complete, then make the API call to complete it. -+ * This is a blocking operation and should be done asynchronously. -+ * -+ * This will also complete textures. If you do not want to load textures, use {{@link #complete(boolean)}} -+ * @return If the profile is now complete (has UUID and Name) (if you get rate limited, this operation may fail) -+ */ -+ default boolean complete() { -+ return complete(true); -+ } -+ -+ /** -+ * If this profile is not complete, then make the API call to complete it. -+ * This is a blocking operation and should be done asynchronously. -+ * -+ * Optionally will also fill textures. -+ * -+ * Online mode will be automatically determined -+ * @param textures controls if we should fill the profile with texture properties -+ * @return If the profile is now complete (has UUID and Name) (if you get rate limited, this operation may fail) -+ */ -+ boolean complete(boolean textures); -+ -+ /** -+ * If this profile is not complete, then make the API call to complete it. -+ * This is a blocking operation and should be done asynchronously. -+ * -+ * Optionally will also fill textures. -+ * @param textures controls if we should fill the profile with texture properties -+ * @param onlineMode Treat this server as online mode or not -+ * @return If the profile is now complete (has UUID and Name) (if you get rate limited, this operation may fail) -+ */ -+ boolean complete(boolean textures, boolean onlineMode); -+ -+ /** -+ * Whether or not this Profile has textures associated to it -+ * @return If has a textures property -+ */ -+ default boolean hasTextures() { -+ return hasProperty("textures"); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java b/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7b3b6ef533d32169fbeca389bd61cfc6b0e0faee ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/profile/ProfileProperty.java -@@ -0,0 +1,72 @@ -+package com.destroystokyo.paper.profile; -+ -+import com.google.common.base.Preconditions; -+ -+import java.util.Objects; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Represents a property on a {@link PlayerProfile} -+ */ -+public class ProfileProperty { -+ private final String name; -+ private final String value; -+ private final String signature; -+ -+ public ProfileProperty(@NotNull String name, @NotNull String value) { -+ this(name, value, null); -+ } -+ -+ public ProfileProperty(@NotNull String name, @NotNull String value, @Nullable String signature) { -+ this.name = Preconditions.checkNotNull(name, "ProfileProperty name can not be null"); -+ this.value = Preconditions.checkNotNull(value, "ProfileProperty value can not be null"); -+ this.signature = signature; -+ } -+ -+ /** -+ * @return The property name, ie "textures" -+ */ -+ @NotNull -+ public String getName() { -+ return name; -+ } -+ -+ /** -+ * @return The property value, likely to be base64 encoded -+ */ -+ @NotNull -+ public String getValue() { -+ return value; -+ } -+ -+ /** -+ * @return A signature from Mojang for signed properties -+ */ -+ @Nullable -+ public String getSignature() { -+ return signature; -+ } -+ -+ /** -+ * @return If this property has a signature or not -+ */ -+ public boolean isSigned() { -+ return this.signature != null; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (this == o) return true; -+ if (o == null || getClass() != o.getClass()) return false; -+ ProfileProperty that = (ProfileProperty) o; -+ return Objects.equals(name, that.name) && -+ Objects.equals(value, that.value) && -+ Objects.equals(signature, that.signature); -+ } -+ -+ @Override -+ public int hashCode() { -+ return Objects.hash(name); -+ } -+} -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index e25a6532deca1df59eff2ab59697b851535ee952..be46b7aa492226d2c943b9a15f0e009878be422c 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2140,6 +2140,83 @@ public final class Bukkit { - public static boolean suggestPlayerNamesWhenNullTabCompletions() { - return server.suggestPlayerNamesWhenNullTabCompletions(); - } -+ -+ /** -+ * Creates a PlayerProfile for the specified uuid, with name as null. -+ * -+ * If a player with the passed uuid exists on the server at the time of creation, the returned player profile will -+ * be populated with the properties of said player (including their uuid and name). -+ * -+ * @param uuid UUID to create profile for -+ * @return A PlayerProfile object -+ */ -+ @NotNull -+ public static com.destroystokyo.paper.profile.PlayerProfile createProfile(@NotNull UUID uuid) { -+ return server.createProfile(uuid); -+ } -+ -+ /** -+ * Creates a PlayerProfile for the specified name, with UUID as null. -+ * -+ * If a player with the passed name exists on the server at the time of creation, the returned player profile will -+ * be populated with the properties of said player (including their uuid and name). -+ *

      -+ * E.g. if the player 'jeb_' is currently playing on the server, calling {@code createProfile("JEB_")} will -+ * yield a profile with the name 'jeb_', their uuid and their textures. -+ * To bypass this pre-population on a case-insensitive name match, see {@link #createProfileExact(UUID, String)}. -+ *

      -+ * -+ * @param name Name to create profile for -+ * @return A PlayerProfile object -+ */ -+ @NotNull -+ public static com.destroystokyo.paper.profile.PlayerProfile createProfile(@NotNull String name) { -+ return server.createProfile(name); -+ } -+ -+ /** -+ * Creates a PlayerProfile for the specified name/uuid -+ * -+ * Both UUID and Name can not be null at same time. One must be supplied. -+ * If a player with the passed uuid or name exists on the server at the time of creation, the returned player -+ * profile will be populated with the properties of said player (including their uuid and name). -+ *

      -+ * E.g. if the player 'jeb_' is currently playing on the server, calling {@code createProfile(null, "JEB_")} will -+ * yield a profile with the name 'jeb_', their uuid and their textures. -+ * To bypass this pre-population on an case-insensitive name match, see {@link #createProfileExact(UUID, String)}. -+ *

      -+ * -+ * The name comparison will compare the {@link String#toLowerCase()} version of both the passed name parameter and -+ * a players name to honour the case-insensitive nature of a mojang profile lookup. -+ * -+ * @param uuid UUID to create profile for -+ * @param name Name to create profile for -+ * @return A PlayerProfile object -+ */ -+ @NotNull -+ public static com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUID uuid, @Nullable String name) { -+ return server.createProfile(uuid, name); -+ } -+ -+ /** -+ * Creates an exact PlayerProfile for the specified name/uuid -+ * -+ * Both UUID and Name can not be null at same time. One must be supplied. -+ * If a player with the passed uuid or name exists on the server at the time of creation, the returned player -+ * profile will be populated with the properties of said player. -+ *

      -+ * Compared to {@link #createProfile(UUID, String)}, this method will never mutate the passed uuid or name. -+ * If a player with either the same uuid or a matching name (case-insensitive) is found on the server, their -+ * properties, such as textures, will be pre-populated in the profile, however the passed uuid and name stay intact. -+ * -+ * @param uuid UUID to create profile for -+ * @param name Name to create profile for -+ * @return A PlayerProfile object -+ */ -+ @NotNull -+ public static com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name) { -+ return server.createProfileExact(uuid, name); -+ } - // Paper end - - @NotNull -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 2bfbb0ce71c8c5f8bd9bbd908488831b94ce583f..04752eebe9df1138207a969fb1492a1f55b0b753 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1875,5 +1875,74 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * @return true if player names should be suggested - */ - boolean suggestPlayerNamesWhenNullTabCompletions(); -+ -+ /** -+ * Creates a PlayerProfile for the specified uuid, with name as null. -+ * -+ * If a player with the passed uuid exists on the server at the time of creation, the returned player profile will -+ * be populated with the properties of said player (including their uuid and name). -+ * -+ * @param uuid UUID to create profile for -+ * @return A PlayerProfile object -+ */ -+ @NotNull -+ com.destroystokyo.paper.profile.PlayerProfile createProfile(@NotNull UUID uuid); -+ -+ /** -+ * Creates a PlayerProfile for the specified name, with UUID as null. -+ * -+ * If a player with the passed name exists on the server at the time of creation, the returned player profile will -+ * be populated with the properties of said player (including their uuid and name). -+ *

      -+ * E.g. if the player 'jeb_' is currently playing on the server, calling {@code createProfile("JEB_")} will -+ * yield a profile with the name 'jeb_', their uuid and their textures. -+ * To bypass this pre-population on a case-insensitive name match, see {@link #createProfileExact(UUID, String)}. -+ *

      -+ * -+ * @param name Name to create profile for -+ * @return A PlayerProfile object -+ */ -+ @NotNull -+ com.destroystokyo.paper.profile.PlayerProfile createProfile(@NotNull String name); -+ -+ /** -+ * Creates a PlayerProfile for the specified name/uuid -+ * -+ * Both UUID and Name can not be null at same time. One must be supplied. -+ * If a player with the passed uuid or name exists on the server at the time of creation, the returned player -+ * profile will be populated with the properties of said player (including their uuid and name). -+ *

      -+ * E.g. if the player 'jeb_' is currently playing on the server, calling {@code createProfile(null, "JEB_")} will -+ * yield a profile with the name 'jeb_', their uuid and their textures. -+ * To bypass this pre-population on an case-insensitive name match, see {@link #createProfileExact(UUID, String)}. -+ *

      -+ * -+ * The name comparison will compare the {@link String#toLowerCase()} version of both the passed name parameter and -+ * a players name to honour the case-insensitive nature of a mojang profile lookup. -+ * -+ * @param uuid UUID to create profile for -+ * @param name Name to create profile for -+ * @return A PlayerProfile object -+ */ -+ @NotNull -+ com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUID uuid, @Nullable String name); -+ -+ /** -+ * Creates an exact PlayerProfile for the specified name/uuid -+ * -+ * Both UUID and Name can not be null at same time. One must be supplied. -+ * If a player with the passed uuid or name exists on the server at the time of creation, the returned player -+ * profile will be populated with the properties of said player. -+ *

      -+ * Compared to {@link #createProfile(UUID, String)}, this method will never mutate the passed uuid or name. -+ * If a player with either the same uuid or a matching name (case-insensitive) is found on the server, their -+ * properties, such as textures, will be pre-populated in the profile, however the passed uuid and name stay intact. -+ * -+ * @param uuid UUID to create profile for -+ * @param name Name to create profile for -+ * @return A PlayerProfile object -+ */ -+ @NotNull -+ com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name); - // Paper end - } diff --git a/patches/api/0058-PlayerPickupItemEvent-setFlyAtPlayer.patch b/patches/api/0058-PlayerPickupItemEvent-setFlyAtPlayer.patch new file mode 100644 index 000000000000..6620dcd7924b --- /dev/null +++ b/patches/api/0058-PlayerPickupItemEvent-setFlyAtPlayer.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 7 May 2017 06:26:01 -0500 +Subject: [PATCH] PlayerPickupItemEvent#setFlyAtPlayer + + +diff --git a/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java b/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java +index a73d1b9717bb6d745f909317474cf3b4380d5cb3..f5166bbf94d5fc24c10888a384003a5f8181ac69 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java +@@ -17,6 +17,7 @@ import org.jetbrains.annotations.NotNull; + public class PlayerPickupItemEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private final Item item; ++ private boolean flyAtPlayer = true; // Paper + private boolean cancel = false; + private final int remaining; + +@@ -45,6 +46,28 @@ public class PlayerPickupItemEvent extends PlayerEvent implements Cancellable { + return remaining; + } + ++ // Paper start ++ /** ++ * Set if the item will fly at the player ++ *

      ++ * Cancelling the event will set this value to false. ++ * ++ * @param flyAtPlayer true for item to fly at player ++ */ ++ public void setFlyAtPlayer(boolean flyAtPlayer) { ++ this.flyAtPlayer = flyAtPlayer; ++ } ++ ++ /** ++ * Gets if the item will fly at the player ++ * ++ * @return true if the item will fly at the player ++ */ ++ public boolean getFlyAtPlayer() { ++ return flyAtPlayer; ++ } ++ // Paper end ++ + @Override + public boolean isCancelled() { + return cancel; +@@ -53,6 +76,7 @@ public class PlayerPickupItemEvent extends PlayerEvent implements Cancellable { + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; ++ this.flyAtPlayer = !cancel; // Paper + } + + @NotNull diff --git a/patches/api/0059-PlayerPickupItemEvent-setFlyAtPlayer.patch b/patches/api/0059-PlayerPickupItemEvent-setFlyAtPlayer.patch deleted file mode 100644 index 353d39591191..000000000000 --- a/patches/api/0059-PlayerPickupItemEvent-setFlyAtPlayer.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 7 May 2017 06:26:01 -0500 -Subject: [PATCH] PlayerPickupItemEvent#setFlyAtPlayer - - -diff --git a/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java b/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java -index 951ea2cc763973655beedcba3c75332d3f297313..18d82c111f30e0279c10a174a51bac018185cd38 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerPickupItemEvent.java -@@ -17,6 +17,7 @@ import org.jetbrains.annotations.NotNull; - public class PlayerPickupItemEvent extends PlayerEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); - private final Item item; -+ private boolean flyAtPlayer = true; // Paper - private boolean cancel = false; - private final int remaining; - -@@ -45,6 +46,27 @@ public class PlayerPickupItemEvent extends PlayerEvent implements Cancellable { - return remaining; - } - -+ // Paper Start -+ /** -+ * Set if the item will fly at the player -+ *

      Cancelling the event will set this value to false.

      -+ * -+ * @param flyAtPlayer True for item to fly at player -+ */ -+ public void setFlyAtPlayer(boolean flyAtPlayer) { -+ this.flyAtPlayer = flyAtPlayer; -+ } -+ -+ /** -+ * Gets if the item will fly at the player -+ * -+ * @return True if the item will fly at the player -+ */ -+ public boolean getFlyAtPlayer() { -+ return flyAtPlayer; -+ } -+ // Paper End -+ - @Override - public boolean isCancelled() { - return cancel; -@@ -53,6 +75,7 @@ public class PlayerPickupItemEvent extends PlayerEvent implements Cancellable { - @Override - public void setCancelled(boolean cancel) { - this.cancel = cancel; -+ this.flyAtPlayer = !cancel; // Paper - } - - @NotNull diff --git a/patches/api/0059-Shoulder-Entities-Release-API.patch b/patches/api/0059-Shoulder-Entities-Release-API.patch new file mode 100644 index 000000000000..47ca7ce75087 --- /dev/null +++ b/patches/api/0059-Shoulder-Entities-Release-API.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 17 Jun 2017 15:04:51 -0400 +Subject: [PATCH] Shoulder Entities Release API + + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index c90a0a00be78200adf217e2b3a8302b59af3cf7c..b4452d18a530c4c4a9bc10f368aeced9430b42a2 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -377,6 +377,26 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder + */ + public int getExpToLevel(); + ++ // Paper start ++ /** ++ * If there is an Entity on this entities left shoulder, it will be released to the world and returned. ++ * If no Entity is released, null will be returned. ++ * ++ * @return The released entity, or null ++ */ ++ @Nullable ++ public Entity releaseLeftShoulderEntity(); ++ ++ /** ++ * If there is an Entity on this entities left shoulder, it will be released to the world and returned. ++ * If no Entity is released, null will be returned. ++ * ++ * @return The released entity, or null ++ */ ++ @Nullable ++ public Entity releaseRightShoulderEntity(); ++ // Paper end ++ + /** + * Gets the current cooldown for a player's attack. + * diff --git a/patches/api/0060-Entity-fromMobSpawner.patch b/patches/api/0060-Entity-fromMobSpawner.patch new file mode 100644 index 000000000000..368746d28a99 --- /dev/null +++ b/patches/api/0060-Entity-fromMobSpawner.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 18 Jun 2017 18:17:05 -0500 +Subject: [PATCH] Entity#fromMobSpawner() + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 45d408f519767785b222c409170bbfecbd8d1931..ca81360956276047602958949148b6a70cc3e954 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -805,5 +805,12 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + @Nullable + Location getOrigin(); ++ ++ /** ++ * Returns whether this entity was spawned from a mob spawner. ++ * ++ * @return True if entity spawned from a mob spawner ++ */ ++ boolean fromMobSpawner(); + // Paper end + } diff --git a/patches/api/0060-Shoulder-Entities-Release-API.patch b/patches/api/0060-Shoulder-Entities-Release-API.patch deleted file mode 100644 index 54e172b458d8..000000000000 --- a/patches/api/0060-Shoulder-Entities-Release-API.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 17 Jun 2017 15:04:51 -0400 -Subject: [PATCH] Shoulder Entities Release API - - -diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java -index f607c57275958bf1cbf8e77b4d7efa936064c228..8a479c7dfd3825fab8bb057d8afa5ae0cb01b071 100644 ---- a/src/main/java/org/bukkit/entity/HumanEntity.java -+++ b/src/main/java/org/bukkit/entity/HumanEntity.java -@@ -318,6 +318,26 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder - */ - public int getExpToLevel(); - -+ // Paper start -+ /** -+ * If there is an Entity on this entities left shoulder, it will be released to the world and returned. -+ * If no Entity is released, null will be returned. -+ * -+ * @return The released entity, or null -+ */ -+ @Nullable -+ public Entity releaseLeftShoulderEntity(); -+ -+ /** -+ * If there is an Entity on this entities left shoulder, it will be released to the world and returned. -+ * If no Entity is released, null will be returned. -+ * -+ * @return The released entity, or null -+ */ -+ @Nullable -+ public Entity releaseRightShoulderEntity(); -+ // Paper end -+ - /** - * Gets the current cooldown for a player's attack. - * diff --git a/patches/api/0061-Entity-fromMobSpawner.patch b/patches/api/0061-Entity-fromMobSpawner.patch deleted file mode 100644 index 03b16193dfe4..000000000000 --- a/patches/api/0061-Entity-fromMobSpawner.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 18 Jun 2017 18:17:05 -0500 -Subject: [PATCH] Entity#fromMobSpawner() - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index c315d2494969190f8b53236f905ad5c5cf1bfc39..b9a61d06d72831dc0c591e129553453a537d3785 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -681,5 +681,12 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - */ - @Nullable - Location getOrigin(); -+ -+ /** -+ * Returns whether this entity was spawned from a mob spawner. -+ * -+ * @return True if entity spawned from a mob spawner -+ */ -+ boolean fromMobSpawner(); - // Paper end - } diff --git a/patches/api/0061-Profile-Lookup-Events.patch b/patches/api/0061-Profile-Lookup-Events.patch new file mode 100644 index 000000000000..e55a9e329e6f --- /dev/null +++ b/patches/api/0061-Profile-Lookup-Events.patch @@ -0,0 +1,172 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 17 Jun 2017 16:30:44 -0400 +Subject: [PATCH] Profile Lookup Events + +Adds a Pre Lookup Event and a Post Lookup Event so that plugins may prefill in profile data, and cache the responses from +profiles that had to be looked up. + +diff --git a/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9e8ae0ab13cac9a260c9959eb6bf5b93a3c15018 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java +@@ -0,0 +1,45 @@ ++package com.destroystokyo.paper.event.profile; ++ ++import com.destroystokyo.paper.profile.PlayerProfile; ++import org.bukkit.Bukkit; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Allows a plugin to be notified anytime AFTER a Profile has been looked up from the Mojang API ++ * This is an opportunity to view the response and potentially cache things. ++ *

      ++ * No guarantees are made about thread execution context for this event. If you need to know, check ++ * {@link Event#isAsynchronous()} ++ */ ++@NullMarked ++public class LookupProfileEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final PlayerProfile profile; ++ ++ @ApiStatus.Internal ++ public LookupProfileEvent(final PlayerProfile profile) { ++ super(!Bukkit.isPrimaryThread()); ++ this.profile = profile; ++ } ++ ++ /** ++ * @return The profile that was recently looked up. This profile can be mutated ++ */ ++ public PlayerProfile getPlayerProfile() { ++ return this.profile; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..07416cc9e2b8156be2cc92d6d974b881b427fd99 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java +@@ -0,0 +1,107 @@ ++package com.destroystokyo.paper.event.profile; ++ ++import com.destroystokyo.paper.profile.ProfileProperty; ++import java.util.HashSet; ++import java.util.Set; ++import java.util.UUID; ++import org.bukkit.Bukkit; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Allows a plugin to intercept a Profile Lookup for a Profile by name ++ *

      ++ * At the point of event fire, the UUID and properties are unset. ++ *

      ++ * If a plugin sets the UUID, and optionally the properties, the API call to look up the profile may be skipped. ++ *

      ++ * No guarantees are made about thread execution context for this event. If you need to know, check ++ * {@link Event#isAsynchronous()} ++ */ ++@NullMarked ++public class PreLookupProfileEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final String name; ++ ++ private @Nullable UUID uuid; ++ private Set properties = new HashSet<>(); ++ ++ @ApiStatus.Internal ++ public PreLookupProfileEvent(final String name) { ++ super(!Bukkit.isPrimaryThread()); ++ this.name = name; ++ } ++ ++ /** ++ * @return Name of the profile ++ */ ++ public String getName() { ++ return this.name; ++ } ++ ++ /** ++ * If this value is left {@code null} by the completion of the event call, then the server will ++ * trigger a call to the Mojang API to look up the UUID (Network Request), and subsequently, fire a ++ * {@link LookupProfileEvent} ++ * ++ * @return The UUID of the profile if it has already been provided by a plugin ++ */ ++ public @Nullable UUID getUUID() { ++ return this.uuid; ++ } ++ ++ /** ++ * Sets the UUID for this player name. This will skip the initial API call to find the players UUID. ++ *

      ++ * However, if Profile Properties are needed by the server, you must also set them or else an API call might still be made. ++ * ++ * @param uuid the UUID to set for the profile or {@code null} to reset ++ */ ++ public void setUUID(final @Nullable UUID uuid) { ++ this.uuid = uuid; ++ } ++ ++ /** ++ * @return The currently pending pre-populated properties. ++ * Any property in this Set will be automatically prefilled on this Profile ++ */ ++ public Set getProfileProperties() { ++ return this.properties; ++ } ++ ++ /** ++ * Clears any existing pre-populated properties and uses the supplied properties ++ * Any property in this Set will be automatically prefilled on this Profile ++ * ++ * @param properties The properties to add ++ */ ++ public void setProfileProperties(final Set properties) { ++ this.properties = new HashSet<>(); ++ this.properties.addAll(properties); ++ } ++ ++ /** ++ * Adds any properties currently missing to the pre-populated properties set, replacing any that already were set. ++ * Any property in this Set will be automatically prefilled on this Profile ++ * ++ * @param properties The properties to add ++ */ ++ public void addProfileProperties(final Set properties) { ++ this.properties.addAll(properties); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++} diff --git a/patches/api/0062-Improve-the-Saddle-API-for-Horses.patch b/patches/api/0062-Improve-the-Saddle-API-for-Horses.patch new file mode 100644 index 000000000000..033f539a9bbe --- /dev/null +++ b/patches/api/0062-Improve-the-Saddle-API-for-Horses.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 10 Dec 2016 16:12:48 -0500 +Subject: [PATCH] Improve the Saddle API for Horses + +Not all horses with Saddles have armor. This lets us break up the horses with saddles +and access their saddle state separately from an interface shared with Armor. + +diff --git a/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java b/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java +new file mode 100644 +index 0000000000000000000000000000000000000000..994f34ac2062c092c2b4e5ff364067482d19588c +--- /dev/null ++++ b/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java +@@ -0,0 +1,22 @@ ++package org.bukkit.inventory; ++ ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@NullMarked ++public interface ArmoredHorseInventory extends AbstractHorseInventory { ++ ++ /** ++ * Gets the item in the horse's armor slot. ++ * ++ * @return the armor item ++ */ ++ @Nullable ItemStack getArmor(); ++ ++ /** ++ * Sets the item in the horse's armor slot. ++ * ++ * @param stack the new item ++ */ ++ void setArmor(@Nullable ItemStack stack); ++} +diff --git a/src/main/java/org/bukkit/inventory/HorseInventory.java b/src/main/java/org/bukkit/inventory/HorseInventory.java +index 608e99c4207405bf9dd88d44ad8e82eefa19e45c..53498debe4cfb80592ef3025270bc8e5df4a5fec 100644 +--- a/src/main/java/org/bukkit/inventory/HorseInventory.java ++++ b/src/main/java/org/bukkit/inventory/HorseInventory.java +@@ -5,20 +5,4 @@ import org.jetbrains.annotations.Nullable; + /** + * An interface to the inventory of a Horse. + */ +-public interface HorseInventory extends AbstractHorseInventory { +- +- /** +- * Gets the item in the horse's armor slot. +- * +- * @return the armor item +- */ +- @Nullable +- ItemStack getArmor(); +- +- /** +- * Sets the item in the horse's armor slot. +- * +- * @param stack the new item +- */ +- void setArmor(@Nullable ItemStack stack); +-} ++public interface HorseInventory extends AbstractHorseInventory, ArmoredHorseInventory {} +diff --git a/src/main/java/org/bukkit/inventory/LlamaInventory.java b/src/main/java/org/bukkit/inventory/LlamaInventory.java +index 2fa2c9d07ecbafaf2396d913af90f1f4d432b238..5ac1afb8a213fa0fe344db4730ecbc5de6eed445 100644 +--- a/src/main/java/org/bukkit/inventory/LlamaInventory.java ++++ b/src/main/java/org/bukkit/inventory/LlamaInventory.java +@@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable; + /** + * An interface to the inventory of a {@link Llama}. + */ +-public interface LlamaInventory extends AbstractHorseInventory { ++public interface LlamaInventory extends SaddledHorseInventory { + + /** + * Gets the item in the llama's decor slot. +diff --git a/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java b/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0f508a8df87f1e23764152d00e02a3da5131f034 +--- /dev/null ++++ b/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java +@@ -0,0 +1,7 @@ ++package org.bukkit.inventory; ++ ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public interface SaddledHorseInventory extends AbstractHorseInventory { ++} diff --git a/patches/api/0062-Profile-Lookup-Events.patch b/patches/api/0062-Profile-Lookup-Events.patch deleted file mode 100644 index 1cdb35476d74..000000000000 --- a/patches/api/0062-Profile-Lookup-Events.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 17 Jun 2017 16:30:44 -0400 -Subject: [PATCH] Profile Lookup Events - -Adds a Pre Lookup Event and a Post Lookup Event so that plugins may prefill in profile data, and cache the responses from -profiles that had to be looked up. - -diff --git a/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8df37c07cd55ddf110d1dd68183d7b697f7a6756 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/profile/LookupProfileEvent.java -@@ -0,0 +1,46 @@ -+package com.destroystokyo.paper.event.profile; -+ -+import com.destroystokyo.paper.profile.PlayerProfile; -+import org.bukkit.Bukkit; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+ -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Allows a plugin to be notified anytime AFTER a Profile has been looked up from the Mojang API -+ * This is an opportunity to view the response and potentially cache things. -+ * -+ * No guarantees are made about thread execution context for this event. If you need to know, check -+ * event.isAsync() -+ */ -+public class LookupProfileEvent extends Event { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull private final PlayerProfile profile; -+ -+ public LookupProfileEvent(@NotNull PlayerProfile profile) { -+ super(!Bukkit.isPrimaryThread()); -+ this.profile = profile; -+ } -+ -+ /** -+ * @return The profile that was recently looked up. This profile can be mutated -+ */ -+ @NotNull -+ public PlayerProfile getPlayerProfile() { -+ return profile; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4dcf6242c9acc62d030a94f67b78729ed29f8c85 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java -@@ -0,0 +1,108 @@ -+package com.destroystokyo.paper.event.profile; -+ -+import com.destroystokyo.paper.profile.PlayerProfile; -+import com.destroystokyo.paper.profile.ProfileProperty; -+import com.google.common.collect.ArrayListMultimap; -+import org.bukkit.Bukkit; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+ -+import java.util.HashSet; -+import java.util.Set; -+import java.util.UUID; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Allows a plugin to intercept a Profile Lookup for a Profile by name -+ * -+ * At the point of event fire, the UUID and properties are unset. -+ * -+ * If a plugin sets the UUID, and optionally the properties, the API call to look up the profile may be skipped. -+ * -+ * No guarantees are made about thread execution context for this event. If you need to know, check -+ * event.isAsync() -+ */ -+public class PreLookupProfileEvent extends Event { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull private final String name; -+ private UUID uuid; -+ @NotNull private Set properties = new HashSet<>(); -+ -+ public PreLookupProfileEvent(@NotNull String name) { -+ super(!Bukkit.isPrimaryThread()); -+ this.name = name; -+ } -+ -+ /** -+ * @return Name of the profile -+ */ -+ @NotNull -+ public String getName() { -+ return name; -+ } -+ -+ /** -+ * If this value is left null by the completion of the event call, then the server will -+ * trigger a call to the Mojang API to look up the UUID (Network Request), and subsequently, fire a -+ * {@link LookupProfileEvent} -+ * -+ * @return The UUID of the profile if it has already been provided by a plugin -+ */ -+ @Nullable -+ public UUID getUUID() { -+ return uuid; -+ } -+ -+ /** -+ * Sets the UUID for this player name. This will skip the initial API call to find the players UUID. -+ * -+ * However, if Profile Properties are needed by the server, you must also set them or else an API call might still be made. -+ * -+ * @param uuid the UUID to set for the profile or null to reset -+ */ -+ public void setUUID(@Nullable UUID uuid) { -+ this.uuid = uuid; -+ } -+ -+ /** -+ * @return The currently pending prepopulated properties. -+ * Any property in this Set will be automatically prefilled on this Profile -+ */ -+ @NotNull -+ public Set getProfileProperties() { -+ return this.properties; -+ } -+ -+ /** -+ * Clears any existing prepopulated properties and uses the supplied properties -+ * Any property in this Set will be automatically prefilled on this Profile -+ * @param properties The properties to add -+ */ -+ public void setProfileProperties(@NotNull Set properties) { -+ this.properties = new HashSet<>(); -+ this.properties.addAll(properties); -+ } -+ -+ /** -+ * Adds any properties currently missing to the prepopulated properties set, replacing any that already were set. -+ * Any property in this Set will be automatically prefilled on this Profile -+ * @param properties The properties to add -+ */ -+ public void addProfileProperties(@NotNull Set properties) { -+ this.properties.addAll(properties); -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+} diff --git a/patches/api/0063-Add-getI18NDisplayName-API.patch b/patches/api/0063-Add-getI18NDisplayName-API.patch new file mode 100644 index 000000000000..967541c44a3f --- /dev/null +++ b/patches/api/0063-Add-getI18NDisplayName-API.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 4 May 2016 23:55:48 -0400 +Subject: [PATCH] Add getI18NDisplayName API + +Gets the Display name as seen in the Client. +Currently the server only supports the English language. To override this, +You must replace the language file embedded in the server jar. + +diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java +index d5342258086066d3b9ef404916bad8440f0cf0cd..333884bc8fe45c66d37a1bbcebc10ea655d2055f 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFactory.java ++++ b/src/main/java/org/bukkit/inventory/ItemFactory.java +@@ -220,4 +220,20 @@ public interface ItemFactory { + @NotNull + net.kyori.adventure.text.Component displayName(@NotNull ItemStack itemStack); + // Paper end - Adventure ++ ++ // Paper start - add getI18NDisplayName ++ /** ++ * Gets the Display name as seen in the Client. ++ * Currently, the server only supports the English language. To override this, ++ * You must replace the language file embedded in the server jar. ++ * ++ * @param item Item to return Display name of ++ * @return Display name of Item ++ * @deprecated {@link ItemStack} implements {@link net.kyori.adventure.translation.Translatable}; use that and ++ * {@link net.kyori.adventure.text.Component#translatable(net.kyori.adventure.translation.Translatable)} instead. ++ */ ++ @Nullable ++ @Deprecated(since = "1.18.1", forRemoval = true) ++ String getI18NDisplayName(@Nullable ItemStack item); ++ // Paper end - add getI18NDisplayName + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index a71a37e3833b6a339c4df8939768c2bd46a816a5..e2cc1ea49f5b7fa06ef388c922184835a84f9440 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -642,5 +642,20 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + public net.kyori.adventure.text.@NotNull Component displayName() { + return Bukkit.getServer().getItemFactory().displayName(this); + } ++ ++ /** ++ * Gets the Display name as seen in the Client. ++ * Currently the server only supports the English language. To override this, ++ * You must replace the language file embedded in the server jar. ++ * ++ * @return Display name of Item ++ * @deprecated {@link ItemStack} implements {@link net.kyori.adventure.translation.Translatable}; use that and ++ * {@link net.kyori.adventure.text.Component#translatable(net.kyori.adventure.translation.Translatable)} instead. ++ */ ++ @Nullable ++ @Deprecated ++ public String getI18NDisplayName() { ++ return Bukkit.getServer().getItemFactory().getI18NDisplayName(this); ++ } + // Paper end + } diff --git a/patches/api/0063-Improve-the-Saddle-API-for-Horses.patch b/patches/api/0063-Improve-the-Saddle-API-for-Horses.patch deleted file mode 100644 index 85814456bf48..000000000000 --- a/patches/api/0063-Improve-the-Saddle-API-for-Horses.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 10 Dec 2016 16:12:48 -0500 -Subject: [PATCH] Improve the Saddle API for Horses - -Not all horses with Saddles have armor. This lets us break up the horses with saddles -and access their saddle state separately from an interface shared with Armor. - -diff --git a/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java b/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java -new file mode 100644 -index 0000000000000000000000000000000000000000..163ffe8ff76ded6265d865901d5110fb6a56950d ---- /dev/null -+++ b/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java -@@ -0,0 +1,21 @@ -+package org.bukkit.inventory; -+ -+import org.jetbrains.annotations.Nullable; -+ -+public interface ArmoredHorseInventory extends AbstractHorseInventory { -+ -+ /** -+ * Gets the item in the horse's armor slot. -+ * -+ * @return the armor item -+ */ -+ @Nullable -+ ItemStack getArmor(); -+ -+ /** -+ * Sets the item in the horse's armor slot. -+ * -+ * @param stack the new item -+ */ -+ void setArmor(@Nullable ItemStack stack); -+} -diff --git a/src/main/java/org/bukkit/inventory/HorseInventory.java b/src/main/java/org/bukkit/inventory/HorseInventory.java -index 608e99c4207405bf9dd88d44ad8e82eefa19e45c..53498debe4cfb80592ef3025270bc8e5df4a5fec 100644 ---- a/src/main/java/org/bukkit/inventory/HorseInventory.java -+++ b/src/main/java/org/bukkit/inventory/HorseInventory.java -@@ -5,20 +5,4 @@ import org.jetbrains.annotations.Nullable; - /** - * An interface to the inventory of a Horse. - */ --public interface HorseInventory extends AbstractHorseInventory { -- -- /** -- * Gets the item in the horse's armor slot. -- * -- * @return the armor item -- */ -- @Nullable -- ItemStack getArmor(); -- -- /** -- * Sets the item in the horse's armor slot. -- * -- * @param stack the new item -- */ -- void setArmor(@Nullable ItemStack stack); --} -+public interface HorseInventory extends AbstractHorseInventory, ArmoredHorseInventory {} -diff --git a/src/main/java/org/bukkit/inventory/LlamaInventory.java b/src/main/java/org/bukkit/inventory/LlamaInventory.java -index 2fa2c9d07ecbafaf2396d913af90f1f4d432b238..5ac1afb8a213fa0fe344db4730ecbc5de6eed445 100644 ---- a/src/main/java/org/bukkit/inventory/LlamaInventory.java -+++ b/src/main/java/org/bukkit/inventory/LlamaInventory.java -@@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable; - /** - * An interface to the inventory of a {@link Llama}. - */ --public interface LlamaInventory extends AbstractHorseInventory { -+public interface LlamaInventory extends SaddledHorseInventory { - - /** - * Gets the item in the llama's decor slot. -diff --git a/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java b/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7944f26a3e2a92601c3be0e55c00c39cc16cf177 ---- /dev/null -+++ b/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java -@@ -0,0 +1,3 @@ -+package org.bukkit.inventory; -+ -+public interface SaddledHorseInventory extends AbstractHorseInventory {} diff --git a/patches/api/0064-Add-getI18NDisplayName-API.patch b/patches/api/0064-Add-getI18NDisplayName-API.patch deleted file mode 100644 index ea4187110ad5..000000000000 --- a/patches/api/0064-Add-getI18NDisplayName-API.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 4 May 2016 23:55:48 -0400 -Subject: [PATCH] Add getI18NDisplayName API - -Gets the Display name as seen in the Client. -Currently the server only supports the English language. To override this, -You must replace the language file embedded in the server jar. - -diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java -index af4a7ce37eb10bab06eadb6583c7894b3ec55ae6..159e5a908b35b84b7fabc36581e093d9aa4c4b67 100644 ---- a/src/main/java/org/bukkit/inventory/ItemFactory.java -+++ b/src/main/java/org/bukkit/inventory/ItemFactory.java -@@ -178,5 +178,19 @@ public interface ItemFactory { - */ - @NotNull - net.kyori.adventure.text.Component displayName(@NotNull ItemStack itemStack); -+ -+ /** -+ * Gets the Display name as seen in the Client. -+ * Currently the server only supports the English language. To override this, -+ * You must replace the language file embedded in the server jar. -+ * -+ * @param item Item to return Display name of -+ * @return Display name of Item -+ * @deprecated {@link ItemStack} implements {@link net.kyori.adventure.translation.Translatable}; use that and -+ * {@link net.kyori.adventure.text.Component#translatable(net.kyori.adventure.translation.Translatable)} instead. -+ */ -+ @Nullable -+ @Deprecated -+ String getI18NDisplayName(@Nullable ItemStack item); - // Paper end - } -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index d168a836d655b369f67200d7afe101b56ff815b1..edf5cd3734011de9130139e542ebc44bcc67f396 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -611,5 +611,20 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - public @NotNull net.kyori.adventure.text.Component displayName() { - return Bukkit.getServer().getItemFactory().displayName(this); - } -+ -+ /** -+ * Gets the Display name as seen in the Client. -+ * Currently the server only supports the English language. To override this, -+ * You must replace the language file embedded in the server jar. -+ * -+ * @return Display name of Item -+ * @deprecated {@link ItemStack} implements {@link net.kyori.adventure.translation.Translatable}; use that and -+ * {@link net.kyori.adventure.text.Component#translatable(net.kyori.adventure.translation.Translatable)} instead. -+ */ -+ @Nullable -+ @Deprecated -+ public String getI18NDisplayName() { -+ return Bukkit.getServer().getItemFactory().getI18NDisplayName(this); -+ } - // Paper end - } diff --git a/patches/api/0064-ensureServerConversions-API.patch b/patches/api/0064-ensureServerConversions-API.patch new file mode 100644 index 000000000000..1e727d00dfdf --- /dev/null +++ b/patches/api/0064-ensureServerConversions-API.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 4 May 2016 23:55:48 -0400 +Subject: [PATCH] ensureServerConversions API + +This will take a Bukkit ItemStack and run it through any conversions a server process would perform on it, +to ensure it meets latest minecraft expectations. + +diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java +index 333884bc8fe45c66d37a1bbcebc10ea655d2055f..c1ec8efffd5ff2a4dcb1d761be9a431a62284607 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFactory.java ++++ b/src/main/java/org/bukkit/inventory/ItemFactory.java +@@ -236,4 +236,18 @@ public interface ItemFactory { + @Deprecated(since = "1.18.1", forRemoval = true) + String getI18NDisplayName(@Nullable ItemStack item); + // Paper end - add getI18NDisplayName ++ ++ // Paper start - ensure server conversions API ++ /** ++ * Minecraft's updates are converting simple item stacks into more complex NBT oriented Item Stacks. ++ * ++ * Use this method to ensure any desired data conversions are processed. ++ * The input itemstack will not be the same as the returned itemstack. ++ * ++ * @param item The item to process conversions on ++ * @return A potentially Data-Converted-ItemStack ++ */ ++ @NotNull ++ ItemStack ensureServerConversions(@NotNull ItemStack item); ++ // Paper end - ensure server conversions API + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index e2cc1ea49f5b7fa06ef388c922184835a84f9440..e66a958bc36ac774081d5e71966f312ebb8228d9 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -566,7 +566,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + } + } + +- return result; ++ return result.ensureServerConversions(); // Paper + } + + /** +@@ -643,6 +643,19 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + return Bukkit.getServer().getItemFactory().displayName(this); + } + ++ /** ++ * Minecraft updates are converting simple item stacks into more complex NBT oriented Item Stacks. ++ * ++ * Use this method to ensure any desired data conversions are processed. ++ * The input itemstack will not be the same as the returned itemstack. ++ * ++ * @return A potentially Data Converted ItemStack ++ */ ++ @NotNull ++ public ItemStack ensureServerConversions() { ++ return Bukkit.getServer().getItemFactory().ensureServerConversions(this); ++ } ++ + /** + * Gets the Display name as seen in the Client. + * Currently the server only supports the English language. To override this, diff --git a/patches/api/0065-LivingEntity-setKiller.patch b/patches/api/0065-LivingEntity-setKiller.patch new file mode 100644 index 000000000000..a1106238d334 --- /dev/null +++ b/patches/api/0065-LivingEntity-setKiller.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 31 Jul 2017 01:49:43 -0500 +Subject: [PATCH] LivingEntity#setKiller + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 4b75a5e1ce788bc375d6147422e5bee6ef0c03be..055ba78f61dfa2d791361ae3b74611131e95dda7 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -365,6 +365,15 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + @Nullable + public Player getKiller(); + ++ // Paper start ++ /** ++ * Sets the player identified as the killer of the living entity. ++ * ++ * @param killer player ++ */ ++ public void setKiller(@Nullable Player killer); ++ // Paper end ++ + /** + * Adds the given {@link PotionEffect} to the living entity. + * diff --git a/patches/api/0065-ensureServerConversions-API.patch b/patches/api/0065-ensureServerConversions-API.patch deleted file mode 100644 index 95f19337565c..000000000000 --- a/patches/api/0065-ensureServerConversions-API.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 4 May 2016 23:55:48 -0400 -Subject: [PATCH] ensureServerConversions API - -This will take a Bukkit ItemStack and run it through any conversions a server process would perform on it, -to ensure it meets latest minecraft expectations. - -diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java -index 159e5a908b35b84b7fabc36581e093d9aa4c4b67..66ffc658dba85942f179760dc6c50258e24ab903 100644 ---- a/src/main/java/org/bukkit/inventory/ItemFactory.java -+++ b/src/main/java/org/bukkit/inventory/ItemFactory.java -@@ -192,5 +192,17 @@ public interface ItemFactory { - @Nullable - @Deprecated - String getI18NDisplayName(@Nullable ItemStack item); -+ -+ /** -+ * Minecraft updates are converting simple item stacks into more complex NBT oriented Item Stacks. -+ * -+ * Use this method to to ensure any desired data conversions are processed. -+ * The input itemstack will not be the same as the returned itemstack. -+ * -+ * @param item The item to process conversions on -+ * @return A potentially Data Converted ItemStack -+ */ -+ @NotNull -+ ItemStack ensureServerConversions(@NotNull ItemStack item); - // Paper end - } -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index edf5cd3734011de9130139e542ebc44bcc67f396..8b76d7ca596ea261c0ca3b9fe2fbf5507c3883e3 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -536,7 +536,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - } - } - -- return result; -+ return result.ensureServerConversions(); // Paper - } - - /** -@@ -612,6 +612,19 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - return Bukkit.getServer().getItemFactory().displayName(this); - } - -+ /** -+ * Minecraft updates are converting simple item stacks into more complex NBT oriented Item Stacks. -+ * -+ * Use this method to to ensure any desired data conversions are processed. -+ * The input itemstack will not be the same as the returned itemstack. -+ * -+ * @return A potentially Data Converted ItemStack -+ */ -+ @NotNull -+ public ItemStack ensureServerConversions() { -+ return Bukkit.getServer().getItemFactory().ensureServerConversions(this); -+ } -+ - /** - * Gets the Display name as seen in the Client. - * Currently the server only supports the English language. To override this, diff --git a/patches/api/0066-Make-plugins-list-alphabetical.patch b/patches/api/0066-Make-plugins-list-alphabetical.patch deleted file mode 100644 index ec1fc9814a94..000000000000 --- a/patches/api/0066-Make-plugins-list-alphabetical.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 31 Jul 2017 02:08:55 -0500 -Subject: [PATCH] Make /plugins list alphabetical - - -diff --git a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java -index bcb576a4271b1ec7b1cfe6f83cf161b7d89ed2e5..4de959bbd1270d7d6ea8e5e69521bcca6abe2138 100644 ---- a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java -+++ b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java -@@ -3,6 +3,9 @@ package org.bukkit.command.defaults; - import java.util.Arrays; - import java.util.Collections; - import java.util.List; -+import java.util.Map; -+import java.util.TreeMap; -+ - import org.bukkit.Bukkit; - import org.bukkit.ChatColor; - import org.bukkit.command.CommandSender; -@@ -34,15 +37,22 @@ public class PluginsCommand extends BukkitCommand { - - @NotNull - private String getPluginList() { -- StringBuilder pluginList = new StringBuilder(); -- Plugin[] plugins = Bukkit.getPluginManager().getPlugins(); -+ // Paper start -+ TreeMap plugins = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); -+ -+ for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { -+ plugins.put(plugin.getDescription().getName(), plugin); -+ } - -- for (Plugin plugin : plugins) { -+ StringBuilder pluginList = new StringBuilder(); -+ for (Map.Entry entry : plugins.entrySet()) { - if (pluginList.length() > 0) { - pluginList.append(ChatColor.WHITE); - pluginList.append(", "); - } - -+ Plugin plugin = entry.getValue(); -+ - pluginList.append(plugin.isEnabled() ? ChatColor.GREEN : ChatColor.RED); - pluginList.append(plugin.getDescription().getName()); - -@@ -51,6 +61,8 @@ public class PluginsCommand extends BukkitCommand { - } - } - -- return "(" + plugins.length + "): " + pluginList.toString(); -+ return "(" + plugins.size() + "): " + pluginList.toString(); -+ // Paper end - } -+ - } diff --git a/patches/api/0066-ProfileWhitelistVerifyEvent.patch b/patches/api/0066-ProfileWhitelistVerifyEvent.patch new file mode 100644 index 000000000000..8f81cecfd649 --- /dev/null +++ b/patches/api/0066-ProfileWhitelistVerifyEvent.patch @@ -0,0 +1,161 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 3 Jul 2017 18:11:34 -0500 +Subject: [PATCH] ProfileWhitelistVerifyEvent + +Fires when the server is validating if a player is whitelisted. + +Allows you to do dynamic whitelisting and change of kick message + +diff --git a/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..901efb61fdc02b3228cc25649926d691c4617512 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java +@@ -0,0 +1,146 @@ ++/* ++ * Copyright (c) 2017 - Daniel Ennis (Aikar) - MIT License ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++package com.destroystokyo.paper.event.profile; ++ ++import com.destroystokyo.paper.profile.PlayerProfile; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Fires when the server needs to verify if a player is whitelisted. ++ *

      ++ * Plugins may override/control the servers whitelist with this event, ++ * and dynamically change the kick message. ++ */ ++@NullMarked ++public class ProfileWhitelistVerifyEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final PlayerProfile profile; ++ private final boolean whitelistEnabled; ++ private final boolean isOp; ++ private boolean whitelisted; ++ private @Nullable Component kickMessage; ++ ++ @Deprecated ++ @ApiStatus.Internal ++ public ProfileWhitelistVerifyEvent(final PlayerProfile profile, final boolean whitelistEnabled, final boolean whitelisted, final boolean isOp, final @Nullable String kickMessage) { ++ this(profile, whitelistEnabled, whitelisted, isOp, kickMessage == null ? null : LegacyComponentSerializer.legacySection().deserialize(kickMessage)); ++ } ++ ++ @ApiStatus.Internal ++ public ProfileWhitelistVerifyEvent(final PlayerProfile profile, final boolean whitelistEnabled, final boolean whitelisted, final boolean isOp, final @Nullable Component kickMessage) { ++ this.profile = profile; ++ this.whitelistEnabled = whitelistEnabled; ++ this.whitelisted = whitelisted; ++ this.isOp = isOp; ++ this.kickMessage = kickMessage; ++ } ++ ++ /** ++ * @return the currently planned message to send to the user if they are not whitelisted ++ * @deprecated use {@link #kickMessage()} ++ */ ++ @Deprecated ++ public @Nullable String getKickMessage() { ++ return this.kickMessage == null ? null : LegacyComponentSerializer.legacySection().serialize(this.kickMessage); ++ } ++ ++ /** ++ * @param kickMessage The message to send to the player on kick if not whitelisted. May set to {@code null} to use the server configured default ++ * @deprecated Use {@link #kickMessage(Component)} ++ */ ++ @Deprecated ++ public void setKickMessage(final @Nullable String kickMessage) { ++ this.kickMessage(kickMessage == null ? null : LegacyComponentSerializer.legacySection().deserialize(kickMessage)); ++ } ++ ++ /** ++ * @return the currently planned message to send to the user if they are not whitelisted ++ */ ++ @Contract(pure = true) ++ public @Nullable Component kickMessage() { ++ return this.kickMessage; ++ } ++ ++ /** ++ * @param kickMessage The message to send to the player on kick if not whitelisted. May set to {@code null} to use the server configured default ++ */ ++ public void kickMessage(final @Nullable Component kickMessage) { ++ this.kickMessage = kickMessage; ++ } ++ ++ /** ++ * @return The profile of the player trying to connect ++ */ ++ public PlayerProfile getPlayerProfile() { ++ return this.profile; ++ } ++ ++ /** ++ * @return Whether the player is whitelisted to play on this server (whitelist may be off is why it's true) ++ */ ++ public boolean isWhitelisted() { ++ return this.whitelisted; ++ } ++ ++ /** ++ * Changes the players whitelisted state. {@code false} will deny the login ++ * ++ * @param whitelisted The new whitelisted state ++ */ ++ public void setWhitelisted(final boolean whitelisted) { ++ this.whitelisted = whitelisted; ++ } ++ ++ /** ++ * @return if the player obtained whitelist status by having op ++ */ ++ public boolean isOp() { ++ return this.isOp; ++ } ++ ++ /** ++ * @return if the server even has whitelist on ++ */ ++ public boolean isWhitelistEnabled() { ++ return this.whitelistEnabled; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0067-Allow-plugins-to-use-SLF4J-for-logging.patch b/patches/api/0067-Allow-plugins-to-use-SLF4J-for-logging.patch new file mode 100644 index 000000000000..1a33aeb2ba42 --- /dev/null +++ b/patches/api/0067-Allow-plugins-to-use-SLF4J-for-logging.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Minecrell +Date: Thu, 21 Sep 2017 16:33:12 +0200 +Subject: [PATCH] Allow plugins to use SLF4J for logging + +SLF4J is a commonly used abstraction for various logging frameworks +such as java.util.logging (JUL) or Log4j. Currently, plugins are +required to do all their logging using the provided JUL logger. +This is annoying for plugins that target multiple platforms or when +using libraries that log messages using SLF4J. + +Expose SLF4J as optional logging API for plugins, so they can use +it without having to shade it in the plugin and going through +several layers of logging abstraction. + +diff --git a/build.gradle.kts b/build.gradle.kts +index 305c2f3226f59e36ab1059b52e111178790aa6e8..2b489adc50d45facd347f79c34224d347dc20a75 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -12,6 +12,8 @@ java { + val annotationsVersion = "24.1.0" + val bungeeCordChatVersion = "1.20-R0.2" + val adventureVersion = "4.17.0" ++val slf4jVersion = "2.0.9" ++val log4jVersion = "2.17.1" + val apiAndDocs: Configuration by configurations.creating { + attributes { + attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION)) +@@ -61,6 +63,8 @@ dependencies { + apiAndDocs("net.kyori:adventure-text-serializer-legacy") + apiAndDocs("net.kyori:adventure-text-serializer-plain") + apiAndDocs("net.kyori:adventure-text-logger-slf4j") ++ api("org.apache.logging.log4j:log4j-api:$log4jVersion") ++ api("org.slf4j:slf4j-api:$slf4jVersion") + + implementation("org.ow2.asm:asm:9.7.1") + implementation("org.ow2.asm:asm-commons:9.7.1") +@@ -155,6 +159,8 @@ tasks.withType { + "https://jd.advntr.dev/text-serializer-legacy/$adventureVersion/", + "https://jd.advntr.dev/text-serializer-plain/$adventureVersion/", + "https://jd.advntr.dev/text-logger-slf4j/$adventureVersion/", ++ "https://javadoc.io/doc/org.slf4j/slf4j-api/$slf4jVersion/", ++ "https://javadoc.io/doc/org.apache.logging.log4j/log4j-api/$log4jVersion/", + // Paper end + "https://javadoc.io/doc/org.apache.maven.resolver/maven-resolver-api/1.7.3", // Paper + ) +diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java +index 68a0ed5f0ed25e98f4ab4d1e482ec2ccfda9cd3a..46fc37a36403c8fbc4c0c9f863d4d57eb3896bd4 100644 +--- a/src/main/java/org/bukkit/plugin/Plugin.java ++++ b/src/main/java/org/bukkit/plugin/Plugin.java +@@ -198,6 +198,22 @@ public interface Plugin extends TabExecutor { + } + // Paper end + ++ // Paper start - Add SLF4J/Log4J loggers ++ @NotNull ++ default org.slf4j.Logger getSLF4JLogger() { ++ return org.slf4j.LoggerFactory.getLogger(getLogger().getName()); ++ } ++ ++ /** ++ * @deprecated use {@link #getSLF4JLogger()} ++ */ ++ @Deprecated ++ @NotNull ++ default org.apache.logging.log4j.Logger getLog4JLogger() { ++ return org.apache.logging.log4j.LogManager.getLogger(getLogger().getName()); ++ } ++ // Paper end ++ + /** + * Returns the name of the plugin. + *

      diff --git a/patches/api/0067-LivingEntity-setKiller.patch b/patches/api/0067-LivingEntity-setKiller.patch deleted file mode 100644 index 37cb713a6ebb..000000000000 --- a/patches/api/0067-LivingEntity-setKiller.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 31 Jul 2017 01:49:43 -0500 -Subject: [PATCH] LivingEntity#setKiller - - -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index b41133f23d25f90fc0993499056c4eeaf003a701..bfc90a3569abc717f37c064e3068c55ef323edab 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -279,6 +279,15 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - @Nullable - public Player getKiller(); - -+ // Paper start -+ /** -+ * Sets the player identified as the killer of the living entity. -+ * -+ * @param killer player -+ */ -+ public void setKiller(@Nullable Player killer); -+ // Paper end -+ - /** - * Adds the given {@link PotionEffect} to the living entity. - * diff --git a/patches/api/0068-Handle-plugin-prefixes-in-implementation-logging-con.patch b/patches/api/0068-Handle-plugin-prefixes-in-implementation-logging-con.patch new file mode 100644 index 000000000000..74e02036c1a7 --- /dev/null +++ b/patches/api/0068-Handle-plugin-prefixes-in-implementation-logging-con.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Minecrell +Date: Thu, 21 Sep 2017 16:14:13 +0200 +Subject: [PATCH] Handle plugin prefixes in implementation logging + configuration + +Currently, plugin prefixes are prepended to the log message in +the PluginLogger before passing the message to the underlying +logging framework. This is bad design because they need to be +stripped manually when using custom appenders to log messages +in a different format. + +Additionally, it makes integration of alternative logging APIs hard +because all logging must go through the PluginLogger. Avoid using +PluginLogger and create a regular logger using the plugin name. +The implementation should handle plugin prefixes by displaying +logger names when appropriate. + +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +index 7f17337b9f0fb60fa1c91c47af496c03290d1b1c..801578de8599d6b546cde63b3f2655fab48eee03 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +@@ -47,7 +47,7 @@ public abstract class JavaPlugin extends PluginBase { + private boolean naggable = true; + private FileConfiguration newConfig = null; + private File configFile = null; +- private PluginLogger logger = null; ++ private Logger logger = null; // Paper - PluginLogger -> Logger + + public JavaPlugin() { + // Paper start +@@ -304,8 +304,8 @@ public abstract class JavaPlugin extends PluginBase { + this.dataFolder = dataFolder; + this.classLoader = classLoader; + this.configFile = new File(dataFolder, "config.yml"); +- this.logger = new PluginLogger(this); + this.pluginMeta = configuration; // Paper ++ this.logger = Logger.getLogger(description.getPrefix() != null ? description.getPrefix() : description.getName()); // Paper - Handle plugin prefix in implementation + } + + /** diff --git a/patches/api/0068-ProfileWhitelistVerifyEvent.patch b/patches/api/0068-ProfileWhitelistVerifyEvent.patch deleted file mode 100644 index 9bf74b4d3edc..000000000000 --- a/patches/api/0068-ProfileWhitelistVerifyEvent.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 3 Jul 2017 18:11:34 -0500 -Subject: [PATCH] ProfileWhitelistVerifyEvent - -Fires when the server is validating if a player is whitelisted. - -Allows you to do dynamic whitelisting and change of kick message - -diff --git a/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c6f5e2b5459368ad1e4db9929ca14568a25793fa ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/profile/ProfileWhitelistVerifyEvent.java -@@ -0,0 +1,142 @@ -+/* -+ * Copyright (c) 2017 - Daniel Ennis (Aikar) - MIT License -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be -+ * included in all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+package com.destroystokyo.paper.event.profile; -+ -+import com.destroystokyo.paper.profile.PlayerProfile; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Fires when the server needs to verify if a player is whitelisted. -+ * -+ * Plugins may override/control the servers whitelist with this event, -+ * and dynamically change the kick message. -+ */ -+public class ProfileWhitelistVerifyEvent extends Event { -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull private final PlayerProfile profile; -+ private final boolean whitelistEnabled; -+ private boolean whitelisted; -+ private final boolean isOp; -+ @Nullable private Component kickMessage; -+ -+ @Deprecated -+ public ProfileWhitelistVerifyEvent(@NotNull final PlayerProfile profile, boolean whitelistEnabled, boolean whitelisted, boolean isOp, @Nullable String kickMessage) { -+ this(profile, whitelistEnabled, whitelisted, isOp, kickMessage == null ? null : LegacyComponentSerializer.legacySection().deserialize(kickMessage)); -+ } -+ -+ public ProfileWhitelistVerifyEvent(@NotNull final PlayerProfile profile, boolean whitelistEnabled, boolean whitelisted, boolean isOp, @Nullable Component kickMessage) { -+ this.profile = profile; -+ this.whitelistEnabled = whitelistEnabled; -+ this.whitelisted = whitelisted; -+ this.isOp = isOp; -+ this.kickMessage = kickMessage; -+ } -+ -+ /** -+ * @return the currently planned message to send to the user if they are not whitelisted -+ * @deprecated use {@link #kickMessage()} -+ */ -+ @Deprecated -+ @Nullable -+ public String getKickMessage() { -+ return this.kickMessage == null ? null : LegacyComponentSerializer.legacySection().serialize(kickMessage); -+ } -+ -+ /** -+ * @param kickMessage The message to send to the player on kick if not whitelisted. May set to null to use the server configured default -+ * @deprecated Use {@link #kickMessage(Component)} -+ */ -+ @Deprecated -+ public void setKickMessage(@Nullable String kickMessage) { -+ this.kickMessage(kickMessage == null ? null : LegacyComponentSerializer.legacySection().deserialize(kickMessage)); -+ } -+ -+ /** -+ * @return the currently planned message to send to the user if they are not whitelisted -+ */ -+ @Nullable -+ public Component kickMessage() { -+ return this.kickMessage; -+ } -+ -+ /** -+ * @param kickMessage The message to send to the player on kick if not whitelisted. May set to null to use the server configured default -+ */ -+ public void kickMessage(@Nullable Component kickMessage) { -+ this.kickMessage = kickMessage; -+ } -+ -+ /** -+ * @return The profile of the player trying to connect -+ */ -+ @NotNull -+ public PlayerProfile getPlayerProfile() { -+ return profile; -+ } -+ -+ /** -+ * @return Whether the player is whitelisted to play on this server (whitelist may be off is why its true) -+ */ -+ public boolean isWhitelisted() { -+ return whitelisted; -+ } -+ -+ /** -+ * Changes the players whitelisted state. false will deny the login -+ * @param whitelisted The new whitelisted state -+ */ -+ public void setWhitelisted(boolean whitelisted) { -+ this.whitelisted = whitelisted; -+ } -+ -+ /** -+ * @return if the player obtained whitelist status by having op -+ */ -+ public boolean isOp() { -+ return isOp; -+ } -+ -+ /** -+ * @return if the server even has whitelist on -+ */ -+ public boolean isWhitelistEnabled() { -+ return whitelistEnabled; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0069-Add-PlayerJumpEvent.patch b/patches/api/0069-Add-PlayerJumpEvent.patch new file mode 100644 index 000000000000..f43b25a51fb9 --- /dev/null +++ b/patches/api/0069-Add-PlayerJumpEvent.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Thu, 28 Sep 2017 17:21:32 -0400 +Subject: [PATCH] Add PlayerJumpEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1d07c3d6bf3b9283371ca45698178979113085fa +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java +@@ -0,0 +1,105 @@ ++package com.destroystokyo.paper.event.player; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.Location; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.event.player.PlayerMoveEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when the server detects the player is jumping. ++ *

      ++ * Added to avoid the overhead and special case logic that many plugins use ++ * when checking for jumps via {@link PlayerMoveEvent}, this event is fired whenever ++ * the server detects that the player is jumping. ++ */ ++@NullMarked ++public class PlayerJumpEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Location to; ++ private Location from; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerJumpEvent(final Player player, final Location from, final Location to) { ++ super(player); ++ this.from = from; ++ this.to = to; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * If a jump event is cancelled, the player will be moved or ++ * teleported back to the Location as defined by {@link #getFrom()}. This will not ++ * fire an event ++ * ++ * @return {@code true} if this event is cancelled ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * If a jump event is cancelled, the player will be moved or ++ * teleported back to the Location as defined by {@link #getFrom()}. This will not ++ * fire an event ++ * ++ * @param cancel {@code true} if you wish to cancel this event ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ /** ++ * Gets the location this player jumped from ++ * ++ * @return Location the player jumped from ++ */ ++ public Location getFrom() { ++ return this.from; ++ } ++ ++ /** ++ * Sets the location to mark as where the player jumped from ++ * ++ * @param from New location to mark as the players previous location ++ */ ++ public void setFrom(final Location from) { ++ Preconditions.checkArgument(from != null, "Cannot use null from location!"); ++ Preconditions.checkArgument(from.getWorld() != null, "Cannot use from location with null world!"); ++ this.from = from; ++ } ++ ++ /** ++ * Gets the location this player jumped to ++ *

      ++ * This information is based on what the client sends, it typically ++ * has little relation to the arc of the jump at any given point. ++ * ++ * @return Location the player jumped to ++ */ ++ public Location getTo() { ++ return this.to.clone(); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0069-Allow-plugins-to-use-SLF4J-for-logging.patch b/patches/api/0069-Allow-plugins-to-use-SLF4J-for-logging.patch deleted file mode 100644 index 1baed8390d96..000000000000 --- a/patches/api/0069-Allow-plugins-to-use-SLF4J-for-logging.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Minecrell -Date: Thu, 21 Sep 2017 16:33:12 +0200 -Subject: [PATCH] Allow plugins to use SLF4J for logging - -SLF4J is a commonly used abstraction for various logging frameworks -such as java.util.logging (JUL) or Log4j. Currently, plugins are -required to do all their logging using the provided JUL logger. -This is annoying for plugins that target multiple platforms or when -using libraries that log messages using SLF4J. - -Expose SLF4J as optional logging API for plugins, so they can use -it without having to shade it in the plugin and going through -several layers of logging abstraction. - -diff --git a/build.gradle.kts b/build.gradle.kts -index f0f8047cb3a43b447dc50b730dab3d0bc471b25a..435db1ffe47476bcb7067802faad7aee7e4c3f54 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -39,6 +39,8 @@ dependencies { - apiAndDocs("net.kyori:adventure-text-serializer-legacy") - apiAndDocs("net.kyori:adventure-text-serializer-plain") - apiAndDocs("net.kyori:adventure-text-logger-slf4j") -+ api("org.apache.logging.log4j:log4j-api:2.17.1") -+ api("org.slf4j:slf4j-api:1.8.0-beta4") - - implementation("org.ow2.asm:asm:9.2") - implementation("org.ow2.asm:asm-commons:9.2") -diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java -index b37938745f916b5f0111b07b1a1c97527f026e9d..08aef59d8443038771704d9587e31f299e587307 100644 ---- a/src/main/java/org/bukkit/plugin/Plugin.java -+++ b/src/main/java/org/bukkit/plugin/Plugin.java -@@ -186,6 +186,22 @@ public interface Plugin extends TabExecutor { - } - // Paper end - -+ // Paper start - Add SLF4J/Log4J loggers -+ @NotNull -+ default org.slf4j.Logger getSLF4JLogger() { -+ return org.slf4j.LoggerFactory.getLogger(getLogger().getName()); -+ } -+ -+ /** -+ * @deprecated use {@link #getSLF4JLogger()} -+ */ -+ @Deprecated -+ @NotNull -+ default org.apache.logging.log4j.Logger getLog4JLogger() { -+ return org.apache.logging.log4j.LogManager.getLogger(getLogger().getName()); -+ } -+ // Paper end -+ - /** - * Returns the name of the plugin. - *

      diff --git a/patches/api/0070-Add-workaround-for-plugins-modifying-the-parent-of-t.patch b/patches/api/0070-Add-workaround-for-plugins-modifying-the-parent-of-t.patch new file mode 100644 index 000000000000..9afdf0a360f7 --- /dev/null +++ b/patches/api/0070-Add-workaround-for-plugins-modifying-the-parent-of-t.patch @@ -0,0 +1,113 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Minecrell +Date: Thu, 21 Sep 2017 19:41:20 +0200 +Subject: [PATCH] Add workaround for plugins modifying the parent of the plugin + logger + +Essentials uses a custom logger name ("Essentials") instead of the +plugin logger. Log messages are redirected to the plugin logger by +setting the parent of the "Essentials" logger to the plugin logger. + +With our changes, the plugin logger is now also called "Essentials", +resulting in an infinite loop. Make sure plugins can't change the +parent of the plugin logger to avoid this. + +diff --git a/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java b/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c78a359566a11904d2dd41098ced556a91a7fa36 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java +@@ -0,0 +1,46 @@ ++package com.destroystokyo.paper.utils; ++ ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import java.util.logging.Level; ++import java.util.logging.LogManager; ++import java.util.logging.Logger; ++import org.bukkit.plugin.PluginDescriptionFile; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Prevents plugins (e.g. Essentials) from changing the parent of the plugin logger. ++ */ ++@NullMarked ++public class PaperPluginLogger extends Logger { ++ ++ @Deprecated(forRemoval = true) ++ public static Logger getLogger(final PluginDescriptionFile description) { ++ return getLogger((PluginMeta) description); ++ } ++ ++ public static Logger getLogger(final PluginMeta meta) { ++ Logger logger = new PaperPluginLogger(meta); ++ if (!LogManager.getLogManager().addLogger(logger)) { ++ // Disable this if it's going to happen across reloads anyways... ++ //logger.log(Level.WARNING, "Could not insert plugin logger - one was already found: {}", LogManager.getLogManager().getLogger(this.getName())); ++ logger = LogManager.getLogManager().getLogger(meta.getLoggerPrefix() != null ? meta.getLoggerPrefix() : meta.getName()); ++ } ++ ++ return logger; ++ } ++ ++ private PaperPluginLogger(final PluginMeta meta) { ++ super(meta.getLoggerPrefix() != null ? meta.getLoggerPrefix() : meta.getName(), null); ++ } ++ ++ @Override ++ public void setParent(final Logger parent) { ++ if (this.getParent() != null) { ++ this.warning("Ignoring attempt to change parent of plugin logger"); ++ } else { ++ this.log(Level.FINE, "Setting plugin logger parent to {0}", parent); ++ super.setParent(parent); ++ } ++ } ++ ++} +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +index 801578de8599d6b546cde63b3f2655fab48eee03..2d64fc065d53dcd8c01d05215c3e63aaf4428177 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +@@ -292,10 +292,10 @@ public abstract class JavaPlugin extends PluginBase { + .orElseThrow(); + } + public final void init(@NotNull PluginLoader loader, @NotNull Server server, @NotNull PluginDescriptionFile description, @NotNull File dataFolder, @NotNull File file, @NotNull ClassLoader classLoader) { +- init(server, description, dataFolder, file, classLoader, description); ++ init(server, description, dataFolder, file, classLoader, description, com.destroystokyo.paper.utils.PaperPluginLogger.getLogger(description)); + this.pluginMeta = description; + } +- public final void init(@NotNull Server server, @NotNull PluginDescriptionFile description, @NotNull File dataFolder, @NotNull File file, @NotNull ClassLoader classLoader, @Nullable io.papermc.paper.plugin.configuration.PluginMeta configuration) { ++ public final void init(@NotNull Server server, @NotNull PluginDescriptionFile description, @NotNull File dataFolder, @NotNull File file, @NotNull ClassLoader classLoader, @Nullable io.papermc.paper.plugin.configuration.PluginMeta configuration, @NotNull Logger logger) { + // Paper end + this.loader = DummyPluginLoaderImplHolder.INSTANCE; // Paper + this.server = server; +@@ -305,7 +305,7 @@ public abstract class JavaPlugin extends PluginBase { + this.classLoader = classLoader; + this.configFile = new File(dataFolder, "config.yml"); + this.pluginMeta = configuration; // Paper +- this.logger = Logger.getLogger(description.getPrefix() != null ? description.getPrefix() : description.getName()); // Paper - Handle plugin prefix in implementation ++ this.logger = logger; // Paper + } + + /** +diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +index 58d20eff7e0da2d7fcb1609d55e4284715355634..8c5597e02d71c8db66e9cd11f0a41776eb471c46 100644 +--- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +@@ -67,6 +67,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm + this.url = file.toURI().toURL(); + this.libraryLoader = libraryLoader; + ++ this.logger = com.destroystokyo.paper.utils.PaperPluginLogger.getLogger(description); // Paper - Register logger early + // Paper start + this.dependencyContext = dependencyContext; + this.classLoaderGroup = io.papermc.paper.plugin.provider.classloader.PaperClassLoaderStorage.instance().registerSpigotGroup(this); +@@ -262,7 +263,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm + pluginState = new IllegalStateException("Initial initialization"); + this.pluginInit = javaPlugin; + +- javaPlugin.init(null, org.bukkit.Bukkit.getServer(), description, dataFolder, file, this); // Paper ++ javaPlugin.init(org.bukkit.Bukkit.getServer(), description, dataFolder, file, this, description, this.logger); // Paper + } + + // Paper start diff --git a/patches/api/0070-Handle-plugin-prefixes-in-implementation-logging-con.patch b/patches/api/0070-Handle-plugin-prefixes-in-implementation-logging-con.patch deleted file mode 100644 index e8b752d9a73e..000000000000 --- a/patches/api/0070-Handle-plugin-prefixes-in-implementation-logging-con.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Minecrell -Date: Thu, 21 Sep 2017 16:14:13 +0200 -Subject: [PATCH] Handle plugin prefixes in implementation logging - configuration - -Currently, plugin prefixes are prepended to the log message in -the PluginLogger before passing the message to the underlying -logging framework. This is bad design because they need to be -stripped manually when using custom appenders to log messages -in a different format. - -Additionally, it makes integration of alternative logging APIs hard -because all logging must go through the PluginLogger. Avoid using -PluginLogger and create a regular logger using the plugin name. -The implementation should handle plugin prefixes by displaying -logger names when appropriate. - -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java -index 669a70faa95d0d6525a731d73499ed6fb0b48320..1ff0e0ef1aebec5bbb0a8a09af11d07b2a3220e8 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java -@@ -43,7 +43,7 @@ public abstract class JavaPlugin extends PluginBase { - private boolean naggable = true; - private FileConfiguration newConfig = null; - private File configFile = null; -- private PluginLogger logger = null; -+ private Logger logger = null; // Paper - PluginLogger -> Logger - - public JavaPlugin() { - final ClassLoader classLoader = this.getClass().getClassLoader(); -@@ -277,7 +277,8 @@ public abstract class JavaPlugin extends PluginBase { - this.dataFolder = dataFolder; - this.classLoader = classLoader; - this.configFile = new File(dataFolder, "config.yml"); -- this.logger = new PluginLogger(this); -+ // Paper - Handle plugin prefix in implementation -+ this.logger = Logger.getLogger(description.getPrefix() != null ? description.getPrefix() : description.getName()); - } - - /** diff --git a/patches/api/0071-Add-PlayerArmorChangeEvent.patch b/patches/api/0071-Add-PlayerArmorChangeEvent.patch new file mode 100644 index 000000000000..9b30ad2abc48 --- /dev/null +++ b/patches/api/0071-Add-PlayerArmorChangeEvent.patch @@ -0,0 +1,132 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: pkt77 +Date: Fri, 10 Nov 2017 23:45:59 -0500 +Subject: [PATCH] Add PlayerArmorChangeEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c7cc612ec81b0c7da6ee6676167e047e69347966 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java +@@ -0,0 +1,120 @@ ++package com.destroystokyo.paper.event.player; ++ ++import java.util.Set; ++import org.bukkit.Material; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++import static org.bukkit.Material.*; ++ ++/** ++ * Called when the player themselves change their armor items ++ *

      ++ * Not currently called for environmental factors though it MAY BE IN THE FUTURE ++ */ ++@NullMarked ++public class PlayerArmorChangeEvent extends PlayerEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final SlotType slotType; ++ private final ItemStack oldItem; ++ private final ItemStack newItem; ++ ++ @ApiStatus.Internal ++ public PlayerArmorChangeEvent(final Player player, final SlotType slotType, final ItemStack oldItem, final ItemStack newItem) { ++ super(player); ++ this.slotType = slotType; ++ this.oldItem = oldItem; ++ this.newItem = newItem; ++ } ++ ++ /** ++ * Gets the type of slot being altered. ++ * ++ * @return type of slot being altered ++ */ ++ public SlotType getSlotType() { ++ return this.slotType; ++ } ++ ++ /** ++ * Gets the existing item that's being replaced ++ * ++ * @return old item ++ */ ++ public ItemStack getOldItem() { ++ return this.oldItem; ++ } ++ ++ /** ++ * Gets the new item that's replacing the old ++ * ++ * @return new item ++ */ ++ public ItemStack getNewItem() { ++ return this.newItem; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum SlotType { ++ HEAD(NETHERITE_HELMET, DIAMOND_HELMET, GOLDEN_HELMET, IRON_HELMET, CHAINMAIL_HELMET, LEATHER_HELMET, CARVED_PUMPKIN, PLAYER_HEAD, SKELETON_SKULL, ZOMBIE_HEAD, CREEPER_HEAD, WITHER_SKELETON_SKULL, TURTLE_HELMET, DRAGON_HEAD, PIGLIN_HEAD), ++ CHEST(NETHERITE_CHESTPLATE, DIAMOND_CHESTPLATE, GOLDEN_CHESTPLATE, IRON_CHESTPLATE, CHAINMAIL_CHESTPLATE, LEATHER_CHESTPLATE, ELYTRA), ++ LEGS(NETHERITE_LEGGINGS, DIAMOND_LEGGINGS, GOLDEN_LEGGINGS, IRON_LEGGINGS, CHAINMAIL_LEGGINGS, LEATHER_LEGGINGS), ++ FEET(NETHERITE_BOOTS, DIAMOND_BOOTS, GOLDEN_BOOTS, IRON_BOOTS, CHAINMAIL_BOOTS, LEATHER_BOOTS); ++ ++ private final Set types; ++ ++ SlotType(final Material... types) { ++ this.types = Set.of(types); ++ } ++ ++ /** ++ * Gets an immutable set of all allowed material types that can be placed in an ++ * armor slot. ++ * ++ * @return immutable set of material types ++ */ ++ public Set getTypes() { ++ return this.types; ++ } ++ ++ /** ++ * Gets the type of slot via the specified material ++ * ++ * @param material material to get slot by ++ * @return slot type the material will go in, or {@code null} if it won't ++ */ ++ public static @Nullable SlotType getByMaterial(final Material material) { ++ for (final SlotType slotType : values()) { ++ if (slotType.getTypes().contains(material)) { ++ return slotType; ++ } ++ } ++ return null; ++ } ++ ++ /** ++ * Gets whether this material can be equipped to a slot ++ * ++ * @param material material to check ++ * @return whether this material can be equipped ++ */ ++ public static boolean isEquipable(final Material material) { ++ return getByMaterial(material) != null; ++ } ++ } ++} diff --git a/patches/api/0071-Add-PlayerJumpEvent.patch b/patches/api/0071-Add-PlayerJumpEvent.patch deleted file mode 100644 index 18f2c35b4dd5..000000000000 --- a/patches/api/0071-Add-PlayerJumpEvent.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Thu, 28 Sep 2017 17:21:32 -0400 -Subject: [PATCH] Add PlayerJumpEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..289a0d784a3c74caf8a7231b4dd166096b1849a1 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerJumpEvent.java -@@ -0,0 +1,106 @@ -+package com.destroystokyo.paper.event.player; -+ -+import com.google.common.base.Preconditions; -+import org.bukkit.Location; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when the server detects the player is jumping. -+ *

      -+ * Added to avoid the overhead and special case logic that many plugins use -+ * when checking for jumps via PlayerMoveEvent, this event is fired whenever -+ * the server detects that the player is jumping. -+ */ -+public class PlayerJumpEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancel = false; -+ @NotNull private Location from; -+ @NotNull private Location to; -+ -+ public PlayerJumpEvent(@NotNull final Player player, @NotNull final Location from, @NotNull final Location to) { -+ super(player); -+ this.from = from; -+ this.to = to; -+ } -+ -+ /** -+ * Gets the cancellation state of this event. A cancelled event will not -+ * be executed in the server, but will still pass to other plugins -+ *

      -+ * If a jump event is cancelled, the player will be moved or -+ * teleported back to the Location as defined by getFrom(). This will not -+ * fire an event -+ * -+ * @return true if this event is cancelled -+ */ -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ /** -+ * Sets the cancellation state of this event. A cancelled event will not -+ * be executed in the server, but will still pass to other plugins -+ *

      -+ * If a jump event is cancelled, the player will be moved or -+ * teleported back to the Location as defined by getFrom(). This will not -+ * fire an event -+ * -+ * @param cancel true if you wish to cancel this event -+ */ -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ /** -+ * Gets the location this player jumped from -+ * -+ * @return Location the player jumped from -+ */ -+ @NotNull -+ public Location getFrom() { -+ return from; -+ } -+ -+ /** -+ * Sets the location to mark as where the player jumped from -+ * -+ * @param from New location to mark as the players previous location -+ */ -+ public void setFrom(@NotNull Location from) { -+ validateLocation(from); -+ this.from = from; -+ } -+ -+ /** -+ * Gets the location this player jumped to -+ * -+ * This information is based on what the client sends, it typically -+ * has little relation to the arc of the jump at any given point. -+ * -+ * @return Location the player jumped to -+ */ -+ @NotNull -+ public Location getTo() { -+ return to; -+ } -+ -+ private void validateLocation(Location loc) { -+ Preconditions.checkArgument(loc != null, "Cannot use null location!"); -+ Preconditions.checkArgument(loc.getWorld() != null, "Cannot use location with null world!"); -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0072-API-to-get-a-BlockState-without-a-snapshot.patch b/patches/api/0072-API-to-get-a-BlockState-without-a-snapshot.patch new file mode 100644 index 000000000000..e37dca393f28 --- /dev/null +++ b/patches/api/0072-API-to-get-a-BlockState-without-a-snapshot.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 6 Nov 2017 21:10:01 -0500 +Subject: [PATCH] API to get a BlockState without a snapshot + +This allows you to get a BlockState without creating a snapshot, operating +on the real tile entity. + +This is useful for where performance is needed + +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index f440da5941e11c30145175cf24162e1ba2b4e3cf..69d97a14715040263afec77d0ba623c2ac84062a 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -272,6 +272,16 @@ public interface Block extends Metadatable, Translatable { + @NotNull + BlockState getState(); + ++ // Paper start ++ /** ++ * @see #getState() optionally disables use of snapshot, to operate on real block data ++ * @param useSnapshot if this block is a TE, should we create a fully copy of the TileEntity ++ * @return BlockState with the current state of this block ++ */ ++ @NotNull ++ BlockState getState(boolean useSnapshot); ++ // Paper end ++ + /** + * Returns the biome that this block resides in + * +diff --git a/src/main/java/org/bukkit/block/TileState.java b/src/main/java/org/bukkit/block/TileState.java +index 3b10fcc13893403b29f0260b8605144679e89b82..5c8517c5bcae10161952c104b6a4ff7c713bcdbd 100644 +--- a/src/main/java/org/bukkit/block/TileState.java ++++ b/src/main/java/org/bukkit/block/TileState.java +@@ -36,4 +36,18 @@ public interface TileState extends BlockState, PersistentDataHolder { + @NotNull + @Override + PersistentDataContainer getPersistentDataContainer(); ++ ++ // Paper start ++ /** ++ * Checks if this TileState is a snapshot or a live ++ * representation of the underlying tile entity. ++ *

      ++ * NOTE: You may still have to call {@link BlockState#update()} on ++ * live representations to update any visuals on the block. ++ * ++ * @return true if this is a snapshot ++ * @see Block#getState(boolean) ++ */ ++ boolean isSnapshot(); ++ // Paper end + } diff --git a/patches/api/0072-Add-workaround-for-plugins-modifying-the-parent-of-t.patch b/patches/api/0072-Add-workaround-for-plugins-modifying-the-parent-of-t.patch deleted file mode 100644 index 4b8543b4f9cb..000000000000 --- a/patches/api/0072-Add-workaround-for-plugins-modifying-the-parent-of-t.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Minecrell -Date: Thu, 21 Sep 2017 19:41:20 +0200 -Subject: [PATCH] Add workaround for plugins modifying the parent of the plugin - logger - -Essentials uses a custom logger name ("Essentials") instead of the -plugin logger. Log messages are redirected to the plugin logger by -setting the parent of the "Essentials" logger to the plugin logger. - -With our changes, the plugin logger is now also called "Essentials", -resulting in an infinite loop. Make sure plugins can't change the -parent of the plugin logger to avoid this. - -diff --git a/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java b/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java -new file mode 100644 -index 0000000000000000000000000000000000000000..76f2cb9cd99cad2a9484eab2becd8c36f1dd91b3 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/utils/PaperPluginLogger.java -@@ -0,0 +1,41 @@ -+package com.destroystokyo.paper.utils; -+ -+import org.bukkit.plugin.PluginDescriptionFile; -+ -+import java.util.logging.Level; -+import java.util.logging.LogManager; -+import java.util.logging.Logger; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Prevents plugins (e.g. Essentials) from changing the parent of the plugin logger. -+ */ -+public class PaperPluginLogger extends Logger { -+ -+ @NotNull -+ public static Logger getLogger(@NotNull PluginDescriptionFile description) { -+ Logger logger = new PaperPluginLogger(description); -+ if (!LogManager.getLogManager().addLogger(logger)) { -+ // Disable this if it's going to happen across reloads anyways... -+ //logger.log(Level.WARNING, "Could not insert plugin logger - one was already found: {}", LogManager.getLogManager().getLogger(this.getName())); -+ logger = LogManager.getLogManager().getLogger(description.getPrefix() != null ? description.getPrefix() : description.getName()); -+ } -+ -+ return logger; -+ } -+ -+ private PaperPluginLogger(@NotNull PluginDescriptionFile description) { -+ super(description.getPrefix() != null ? description.getPrefix() : description.getName(), null); -+ } -+ -+ @Override -+ public void setParent(@NotNull Logger parent) { -+ if (getParent() != null) { -+ warning("Ignoring attempt to change parent of plugin logger"); -+ } else { -+ this.log(Level.FINE, "Setting plugin logger parent to {0}", parent); -+ super.setParent(parent); -+ } -+ } -+ -+} -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java -index 1ff0e0ef1aebec5bbb0a8a09af11d07b2a3220e8..3bea5dd67ad0393160ccede4ac99a3c7baa1803b 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java -@@ -43,7 +43,7 @@ public abstract class JavaPlugin extends PluginBase { - private boolean naggable = true; - private FileConfiguration newConfig = null; - private File configFile = null; -- private Logger logger = null; // Paper - PluginLogger -> Logger -+ Logger logger = null; // Paper - PluginLogger -> Logger, package-private - - public JavaPlugin() { - final ClassLoader classLoader = this.getClass().getClassLoader(); -@@ -277,8 +277,11 @@ public abstract class JavaPlugin extends PluginBase { - this.dataFolder = dataFolder; - this.classLoader = classLoader; - this.configFile = new File(dataFolder, "config.yml"); -- // Paper - Handle plugin prefix in implementation -- this.logger = Logger.getLogger(description.getPrefix() != null ? description.getPrefix() : description.getName()); -+ // Paper start -+ if (this.logger == null) { -+ this.logger = com.destroystokyo.paper.utils.PaperPluginLogger.getLogger(this.description); -+ } -+ // Paper end - } - - /** -diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -index 6148b69af39344f758b05a28c7c572befa9b8f3f..0db641f5d5e1293b236ad0d2e3a156802ffed839 100644 ---- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -@@ -44,6 +44,7 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot - private JavaPlugin pluginInit; - private IllegalStateException pluginState; - private final Set seenIllegalAccess = Collections.newSetFromMap(new ConcurrentHashMap<>()); -+ private java.util.logging.Logger logger; // Paper - add field - - static { - ClassLoader.registerAsParallelCapable(); -@@ -62,6 +63,8 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot - this.url = file.toURI().toURL(); - this.libraryLoader = libraryLoader; - -+ this.logger = com.destroystokyo.paper.utils.PaperPluginLogger.getLogger(description); // Paper - Register logger early -+ - try { - Class jarClass; - try { -@@ -229,6 +232,7 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot - pluginState = new IllegalStateException("Initial initialization"); - this.pluginInit = javaPlugin; - -+ javaPlugin.logger = this.logger; // Paper - set logger - javaPlugin.init(loader, loader.server, description, dataFolder, file, this); - } - } diff --git a/patches/api/0073-Add-PlayerArmorChangeEvent.patch b/patches/api/0073-Add-PlayerArmorChangeEvent.patch deleted file mode 100644 index 4e9d795db36e..000000000000 --- a/patches/api/0073-Add-PlayerArmorChangeEvent.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: pkt77 -Date: Fri, 10 Nov 2017 23:45:59 -0500 -Subject: [PATCH] Add PlayerArmorChangeEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e406ce639a2e88b78f82f25e71678a669d0a958b ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java -@@ -0,0 +1,137 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.Material; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.ItemStack; -+ -+import java.util.Arrays; -+import java.util.Collections; -+import java.util.HashSet; -+import java.util.Set; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import static org.bukkit.Material.*; -+ -+/** -+ * Called when the player themselves change their armor items -+ *

      -+ * Not currently called for environmental factors though it MAY BE IN THE FUTURE -+ */ -+public class PlayerArmorChangeEvent extends PlayerEvent { -+ private static final HandlerList HANDLERS = new HandlerList(); -+ -+ @NotNull private final SlotType slotType; -+ @Nullable private final ItemStack oldItem; -+ @Nullable private final ItemStack newItem; -+ -+ public PlayerArmorChangeEvent(@NotNull Player player, @NotNull SlotType slotType, @Nullable ItemStack oldItem, @Nullable ItemStack newItem) { -+ super(player); -+ this.slotType = slotType; -+ this.oldItem = oldItem; -+ this.newItem = newItem; -+ } -+ -+ /** -+ * Gets the type of slot being altered. -+ * -+ * @return type of slot being altered -+ */ -+ @NotNull -+ public SlotType getSlotType() { -+ return this.slotType; -+ } -+ -+ /** -+ * Gets the existing item that's being replaced -+ * -+ * @return old item -+ */ -+ @Nullable -+ public ItemStack getOldItem() { -+ return this.oldItem; -+ } -+ -+ /** -+ * Gets the new item that's replacing the old -+ * -+ * @return new item -+ */ -+ @Nullable -+ public ItemStack getNewItem() { -+ return this.newItem; -+ } -+ -+ @Override -+ public String toString() { -+ return "ArmorChangeEvent{" + "player=" + player + ", slotType=" + slotType + ", oldItem=" + oldItem + ", newItem=" + newItem + '}'; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLERS; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLERS; -+ } -+ -+ public enum SlotType { -+ HEAD(NETHERITE_HELMET, DIAMOND_HELMET, GOLDEN_HELMET, IRON_HELMET, CHAINMAIL_HELMET, LEATHER_HELMET, CARVED_PUMPKIN, PLAYER_HEAD, SKELETON_SKULL, ZOMBIE_HEAD, CREEPER_HEAD, WITHER_SKELETON_SKULL, TURTLE_HELMET), -+ CHEST(NETHERITE_CHESTPLATE, DIAMOND_CHESTPLATE, GOLDEN_CHESTPLATE, IRON_CHESTPLATE, CHAINMAIL_CHESTPLATE, LEATHER_CHESTPLATE, ELYTRA), -+ LEGS(NETHERITE_LEGGINGS, DIAMOND_LEGGINGS, GOLDEN_LEGGINGS, IRON_LEGGINGS, CHAINMAIL_LEGGINGS, LEATHER_LEGGINGS), -+ FEET(NETHERITE_BOOTS, DIAMOND_BOOTS, GOLDEN_BOOTS, IRON_BOOTS, CHAINMAIL_BOOTS, LEATHER_BOOTS); -+ -+ private final Set mutableTypes = new HashSet<>(); -+ private Set immutableTypes; -+ -+ SlotType(Material... types) { -+ this.mutableTypes.addAll(Arrays.asList(types)); -+ } -+ -+ /** -+ * Gets an immutable set of all allowed material types that can be placed in an -+ * armor slot. -+ * -+ * @return immutable set of material types -+ */ -+ @NotNull -+ public Set getTypes() { -+ if (immutableTypes == null) { -+ immutableTypes = Collections.unmodifiableSet(mutableTypes); -+ } -+ -+ return immutableTypes; -+ } -+ -+ /** -+ * Gets the type of slot via the specified material -+ * -+ * @param material material to get slot by -+ * @return slot type the material will go in, or null if it won't -+ */ -+ @Nullable -+ public static SlotType getByMaterial(@NotNull Material material) { -+ for (SlotType slotType : values()) { -+ if (slotType.getTypes().contains(material)) { -+ return slotType; -+ } -+ } -+ return null; -+ } -+ -+ /** -+ * Gets whether or not this material can be equipped to a slot -+ * -+ * @param material material to check -+ * @return whether or not this material can be equipped -+ */ -+ public static boolean isEquipable(@NotNull Material material) { -+ return getByMaterial(material) != null; -+ } -+ } -+} diff --git a/patches/api/0073-AsyncTabCompleteEvent.patch b/patches/api/0073-AsyncTabCompleteEvent.patch new file mode 100644 index 000000000000..a48195bf9fc6 --- /dev/null +++ b/patches/api/0073-AsyncTabCompleteEvent.patch @@ -0,0 +1,610 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Sun, 26 Nov 2017 13:17:09 -0500 +Subject: [PATCH] AsyncTabCompleteEvent + +Let plugins be able to control tab completion of commands and chat async. + +This will be useful for frameworks like ACF so we can define async safe completion handlers, +and avoid going to main for tab completions. + +Especially useful if you need to query a database in order to obtain the results for tab +completion, such as offline players. + +Also Enforces mutability of the existing TabCompleteEvent. + +Co-authored-by: Aikar + +diff --git a/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0482ecf5b84ba8e0260679049f384f3449bbe7b5 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java +@@ -0,0 +1,333 @@ ++/* ++ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++package com.destroystokyo.paper.event.server; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.util.TransformingRandomAccessList; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.Objects; ++import java.util.stream.Stream; ++import net.kyori.adventure.text.Component; ++import net.kyori.examination.Examinable; ++import net.kyori.examination.ExaminableProperty; ++import net.kyori.examination.string.StringExaminer; ++import org.bukkit.Location; ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandSender; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Allows plugins to compute tab completion results asynchronously. ++ *

      ++ * If this event provides completions, then the standard synchronous process ++ * will not be fired to populate the results. ++ * However, the synchronous TabCompleteEvent will fire with the Async results. ++ *

      ++ * Only 1 process will be allowed to provide completions, the Async Event, or the standard process. ++ */ ++@NullMarked ++public class AsyncTabCompleteEvent extends Event implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final CommandSender sender; ++ private final String buffer; ++ private final boolean isCommand; ++ private final @Nullable Location location; ++ private final List completions = new ArrayList<>(); ++ private final List stringCompletions = new TransformingRandomAccessList<>( ++ this.completions, ++ Completion::suggestion, ++ Completion::completion ++ ); ++ private boolean handled; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public AsyncTabCompleteEvent(final CommandSender sender, final String buffer, final boolean isCommand, final @Nullable Location loc) { ++ super(true); ++ this.sender = sender; ++ this.buffer = buffer; ++ this.isCommand = isCommand; ++ this.location = loc; ++ } ++ ++ @Deprecated ++ @ApiStatus.Internal ++ public AsyncTabCompleteEvent(final CommandSender sender, final List completions, final String buffer, final boolean isCommand, final @Nullable Location loc) { ++ super(true); ++ this.sender = sender; ++ this.completions.addAll(fromStrings(completions)); ++ this.buffer = buffer; ++ this.isCommand = isCommand; ++ this.location = loc; ++ } ++ ++ /** ++ * Get the sender completing this command. ++ * ++ * @return the {@link CommandSender} instance ++ */ ++ public CommandSender getSender() { ++ return this.sender; ++ } ++ ++ /** ++ * The list of completions which will be offered to the sender, in order. ++ * This list is mutable and reflects what will be offered. ++ *

      ++ * If this collection is not empty after the event is fired, then ++ * the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} ++ * or current player names will not be called. ++ * ++ * @return a list of offered completions ++ */ ++ public List getCompletions() { ++ return this.stringCompletions; ++ } ++ ++ /** ++ * Set the completions offered, overriding any already set. ++ * If this collection is not empty after the event is fired, then ++ * the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} ++ * or current player names will not be called. ++ *

      ++ * The passed collection will be cloned to a new {@code List}. You must call {{@link #getCompletions()}} to mutate from here ++ * ++ * @param completions the new completions ++ */ ++ public void setCompletions(final List completions) { ++ Preconditions.checkArgument(completions != null, "Completions list cannot be null"); ++ if (completions == this.stringCompletions) { ++ return; ++ } ++ this.completions.clear(); ++ this.completions.addAll(fromStrings(completions)); ++ } ++ ++ /** ++ * The list of {@link Completion completions} which will be offered to the sender, in order. ++ * This list is mutable and reflects what will be offered. ++ *

      ++ * If this collection is not empty after the event is fired, then ++ * the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} ++ * or current player names will not be called. ++ * ++ * @return a list of offered completions ++ */ ++ public List completions() { ++ return this.completions; ++ } ++ ++ /** ++ * Set the {@link Completion completions} offered, overriding any already set. ++ * If this collection is not empty after the event is fired, then ++ * the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} ++ * or current player names will not be called. ++ *

      ++ * The passed collection will be cloned to a new {@code List}. You must call {@link #completions()} to mutate from here ++ * ++ * @param newCompletions the new completions ++ */ ++ public void completions(final List newCompletions) { ++ Preconditions.checkArgument(newCompletions != null, "new completions cannot be null"); ++ this.completions.clear(); ++ this.completions.addAll(newCompletions); ++ } ++ ++ /** ++ * Return the entire buffer which formed the basis of this completion. ++ * ++ * @return command buffer, as entered ++ */ ++ public String getBuffer() { ++ return this.buffer; ++ } ++ ++ /** ++ * @return {@code true} if it is a command being tab completed, {@code false} if it is a chat message. ++ */ ++ public boolean isCommand() { ++ return this.isCommand; ++ } ++ ++ /** ++ * @return The position looked at by the sender, or {@code null} if none ++ */ ++ public @Nullable Location getLocation() { ++ return this.location != null ? this.location.clone() : null; ++ } ++ ++ /** ++ * If {@code true}, the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} ++ * or current player names will not be called. ++ * ++ * @return Is completions considered handled. Always {@code true} if completions is not empty. ++ */ ++ public boolean isHandled() { ++ return !this.completions.isEmpty() || this.handled; ++ } ++ ++ /** ++ * Sets whether to consider the completion request handled. ++ * If {@code true}, the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} ++ * or current player names will not be called. ++ * ++ * @param handled if this completion should be marked as being handled ++ */ ++ public void setHandled(final boolean handled) { ++ this.handled = handled; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *
      ++ * Will provide no completions, and will not fire the synchronous process ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ private static List fromStrings(final List suggestions) { ++ final List list = new ArrayList<>(suggestions.size()); ++ for (final String suggestion : suggestions) { ++ list.add(new CompletionImpl(suggestion, null)); ++ } ++ return list; ++ } ++ ++ /** ++ * A rich tab completion, consisting of a string suggestion, and a nullable {@link Component} tooltip. ++ */ ++ public interface Completion extends Examinable { ++ ++ /** ++ * Get the suggestion string for this {@link Completion}. ++ * ++ * @return suggestion string ++ */ ++ String suggestion(); ++ ++ /** ++ * Get the suggestion tooltip for this {@link Completion}. ++ * ++ * @return tooltip component ++ */ ++ @Nullable Component tooltip(); ++ ++ @Override ++ default Stream examinableProperties() { ++ return Stream.of(ExaminableProperty.of("suggestion", this.suggestion()), ExaminableProperty.of("tooltip", this.tooltip())); ++ } ++ ++ /** ++ * Create a new {@link Completion} from a suggestion string. ++ * ++ * @param suggestion suggestion string ++ * @return new completion instance ++ */ ++ static Completion completion(final String suggestion) { ++ return new CompletionImpl(suggestion, null); ++ } ++ ++ /** ++ * Create a new {@link Completion} from a suggestion string and a tooltip {@link Component}. ++ *

      ++ * If the provided component is {@code null}, the suggestion will not have a tooltip. ++ * ++ * @param suggestion suggestion string ++ * @param tooltip tooltip component, or {@code null} ++ * @return new completion instance ++ */ ++ static Completion completion(final String suggestion, final @Nullable Component tooltip) { ++ return new CompletionImpl(suggestion, tooltip); ++ } ++ } ++ ++ @ApiStatus.Internal ++ static final class CompletionImpl implements Completion { ++ ++ private final String suggestion; ++ private final @Nullable Component tooltip; ++ ++ CompletionImpl(final String suggestion, final @Nullable Component tooltip) { ++ this.suggestion = suggestion; ++ this.tooltip = tooltip; ++ } ++ ++ @Override ++ public String suggestion() { ++ return this.suggestion; ++ } ++ ++ @Override ++ public @Nullable Component tooltip() { ++ return this.tooltip; ++ } ++ ++ @Override ++ public boolean equals(final @Nullable Object o) { ++ if (this == o) { ++ return true; ++ } ++ if (o == null || this.getClass() != o.getClass()) { ++ return false; ++ } ++ final CompletionImpl that = (CompletionImpl) o; ++ return this.suggestion.equals(that.suggestion) ++ && Objects.equals(this.tooltip, that.tooltip); ++ } ++ ++ @Override ++ public int hashCode() { ++ return Objects.hash(this.suggestion, this.tooltip); ++ } ++ ++ @Override ++ public String toString() { ++ return StringExaminer.simpleEscaping().examine(this); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java b/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java +new file mode 100644 +index 0000000000000000000000000000000000000000..488250fdcdc93ca1aba5042f63fb6286db518014 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java +@@ -0,0 +1,172 @@ ++package io.papermc.paper.util; ++ ++import java.util.AbstractList; ++import java.util.Iterator; ++import java.util.List; ++import java.util.ListIterator; ++import java.util.RandomAccess; ++import java.util.function.Function; ++import java.util.function.Predicate; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++import static com.google.common.base.Preconditions.checkNotNull; ++ ++/** ++ * Modified version of the Guava class with the same name to support add operations. ++ * ++ * @param backing list element type ++ * @param transformed list element type ++ */ ++@NullMarked ++@ApiStatus.Internal ++public final class TransformingRandomAccessList extends AbstractList implements RandomAccess { ++ ++ final List fromList; ++ final Function toFunction; ++ final Function fromFunction; ++ ++ /** ++ * Create a new {@link TransformingRandomAccessList}. ++ * ++ * @param fromList backing list ++ * @param toFunction function mapping backing list element type to transformed list element type ++ * @param fromFunction function mapping transformed list element type to backing list element type ++ */ ++ public TransformingRandomAccessList( ++ final List fromList, ++ final Function toFunction, ++ final Function fromFunction ++ ) { ++ this.fromList = checkNotNull(fromList); ++ this.toFunction = checkNotNull(toFunction); ++ this.fromFunction = checkNotNull(fromFunction); ++ } ++ ++ @Override ++ public void clear() { ++ this.fromList.clear(); ++ } ++ ++ @Override ++ public T get(final int index) { ++ return this.toFunction.apply(this.fromList.get(index)); ++ } ++ ++ @Override ++ public Iterator iterator() { ++ return this.listIterator(); ++ } ++ ++ @Override ++ public ListIterator listIterator(final int index) { ++ return new TransformedListIterator<>(this.fromList.listIterator(index)) { ++ @Override ++ T transform(final F from) { ++ return TransformingRandomAccessList.this.toFunction.apply(from); ++ } ++ ++ @Override ++ F transformBack(final T from) { ++ return TransformingRandomAccessList.this.fromFunction.apply(from); ++ } ++ }; ++ } ++ ++ @Override ++ public boolean isEmpty() { ++ return this.fromList.isEmpty(); ++ } ++ ++ @Override ++ public boolean removeIf(final Predicate filter) { ++ checkNotNull(filter); ++ return this.fromList.removeIf(element -> filter.test(this.toFunction.apply(element))); ++ } ++ ++ @Override ++ public T remove(final int index) { ++ return this.toFunction.apply(this.fromList.remove(index)); ++ } ++ ++ @Override ++ public int size() { ++ return this.fromList.size(); ++ } ++ ++ @Override ++ public T set(final int i, final T t) { ++ return this.toFunction.apply(this.fromList.set(i, this.fromFunction.apply(t))); ++ } ++ ++ @Override ++ public void add(final int i, final T t) { ++ this.fromList.add(i, this.fromFunction.apply(t)); ++ } ++ ++ abstract static class TransformedListIterator implements ListIterator, Iterator { ++ ++ final Iterator backingIterator; ++ ++ TransformedListIterator(final ListIterator backingIterator) { ++ this.backingIterator = checkNotNull((Iterator) backingIterator); ++ } ++ ++ private ListIterator backingIterator() { ++ return cast(this.backingIterator); ++ } ++ ++ static ListIterator cast(final Iterator iterator) { ++ return (ListIterator) iterator; ++ } ++ ++ @Override ++ public final boolean hasPrevious() { ++ return this.backingIterator().hasPrevious(); ++ } ++ ++ @Override ++ public final T previous() { ++ return this.transform(this.backingIterator().previous()); ++ } ++ ++ @Override ++ public final int nextIndex() { ++ return this.backingIterator().nextIndex(); ++ } ++ ++ @Override ++ public final int previousIndex() { ++ return this.backingIterator().previousIndex(); ++ } ++ ++ @Override ++ public void set(final T element) { ++ this.backingIterator().set(this.transformBack(element)); ++ } ++ ++ @Override ++ public void add(final T element) { ++ this.backingIterator().add(this.transformBack(element)); ++ } ++ ++ abstract T transform(F from); ++ ++ abstract F transformBack(T to); ++ ++ @Override ++ public final boolean hasNext() { ++ return this.backingIterator.hasNext(); ++ } ++ ++ @Override ++ public final T next() { ++ return this.transform(this.backingIterator.next()); ++ } ++ ++ @Override ++ public final void remove() { ++ this.backingIterator.remove(); ++ } ++ } ++} +diff --git a/src/main/java/org/bukkit/event/server/TabCompleteEvent.java b/src/main/java/org/bukkit/event/server/TabCompleteEvent.java +index 270e6d8ad4358baa256cee5f16cff281f063ce3b..6465e290c090d82986352d5ab7ba5dc65bd3dc17 100644 +--- a/src/main/java/org/bukkit/event/server/TabCompleteEvent.java ++++ b/src/main/java/org/bukkit/event/server/TabCompleteEvent.java +@@ -29,13 +29,20 @@ public class TabCompleteEvent extends Event implements Cancellable { + private boolean cancelled; + + public TabCompleteEvent(@NotNull CommandSender sender, @NotNull String buffer, @NotNull List completions) { ++ // Paper start ++ this(sender, buffer, completions, sender instanceof org.bukkit.command.ConsoleCommandSender || buffer.startsWith("/"), null); ++ } ++ public TabCompleteEvent(@NotNull CommandSender sender, @NotNull String buffer, @NotNull List completions, boolean isCommand, @org.jetbrains.annotations.Nullable org.bukkit.Location location) { ++ this.isCommand = isCommand; ++ this.loc = location; ++ // Paper end + Preconditions.checkArgument(sender != null, "sender"); + Preconditions.checkArgument(buffer != null, "buffer"); + Preconditions.checkArgument(completions != null, "completions"); + + this.sender = sender; + this.buffer = buffer; +- this.completions = completions; ++ this.completions = new java.util.ArrayList<>(completions); // Paper - Completions must be mutable + } + + /** +@@ -69,14 +76,35 @@ public class TabCompleteEvent extends Event implements Cancellable { + return completions; + } + ++ // Paper start ++ private final boolean isCommand; ++ private final org.bukkit.Location loc; ++ /** ++ * @return True if it is a command being tab completed, false if it is a chat message. ++ */ ++ public boolean isCommand() { ++ return isCommand; ++ } ++ ++ /** ++ * @return The position looked at by the sender, or null if none ++ */ ++ @org.jetbrains.annotations.Nullable ++ public org.bukkit.Location getLocation() { ++ return this.loc != null ? this.loc.clone() : null; ++ } ++ // Paper end ++ + /** + * Set the completions offered, overriding any already set. + * ++ * The passed collection will be cloned to a new List. You must call {{@link #getCompletions()}} to mutate from here ++ * + * @param completions the new completions + */ + public void setCompletions(@NotNull List completions) { + Preconditions.checkArgument(completions != null); +- this.completions = completions; ++ this.completions = new java.util.ArrayList<>(completions); // Paper - completions must be mutable + } + + @Override +diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java +index f8b8969ee7a0b6f7b3224ff081e35c14a398c9d0..f9e4b16a21d6cc6c9cbbe06d20c8af25e72e3ddb 100644 +--- a/src/test/java/org/bukkit/AnnotationTest.java ++++ b/src/test/java/org/bukkit/AnnotationTest.java +@@ -48,6 +48,8 @@ public class AnnotationTest { + // Generic functional interface + "org/bukkit/util/Consumer", + // Paper start ++ "io/papermc/paper/util/TransformingRandomAccessList", ++ "io/papermc/paper/util/TransformingRandomAccessList$TransformedListIterator", + // Timings history is broken in terms of nullability due to guavas Function defining that the param is NonNull + "co/aikar/timings/TimingHistory$2", + "co/aikar/timings/TimingHistory$2$1", diff --git a/patches/api/0074-API-to-get-a-BlockState-without-a-snapshot.patch b/patches/api/0074-API-to-get-a-BlockState-without-a-snapshot.patch deleted file mode 100644 index 41c8e70b83bd..000000000000 --- a/patches/api/0074-API-to-get-a-BlockState-without-a-snapshot.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 6 Nov 2017 21:10:01 -0500 -Subject: [PATCH] API to get a BlockState without a snapshot - -This allows you to get a BlockState without creating a snapshot, operating -on the real tile entity. - -This is useful for where performance is needed - -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index b4094e042c1619cfcdd68c27f82979a7562ddf55..d29bdc125dba0128d93d57e8d9393b970e6c00a9 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -271,6 +271,16 @@ public interface Block extends Metadatable { - @NotNull - BlockState getState(); - -+ // Paper start -+ /** -+ * @see #getState() optionally disables use of snapshot, to operate on real block data -+ * @param useSnapshot if this block is a TE, should we create a fully copy of the TileEntity -+ * @return BlockState with the current state of this block -+ */ -+ @NotNull -+ BlockState getState(boolean useSnapshot); -+ // Paper end -+ - /** - * Returns the biome that this block resides in - * -diff --git a/src/main/java/org/bukkit/block/TileState.java b/src/main/java/org/bukkit/block/TileState.java -index 3b10fcc13893403b29f0260b8605144679e89b82..5c8517c5bcae10161952c104b6a4ff7c713bcdbd 100644 ---- a/src/main/java/org/bukkit/block/TileState.java -+++ b/src/main/java/org/bukkit/block/TileState.java -@@ -36,4 +36,18 @@ public interface TileState extends BlockState, PersistentDataHolder { - @NotNull - @Override - PersistentDataContainer getPersistentDataContainer(); -+ -+ // Paper start -+ /** -+ * Checks if this TileState is a snapshot or a live -+ * representation of the underlying tile entity. -+ *

      -+ * NOTE: You may still have to call {@link BlockState#update()} on -+ * live representations to update any visuals on the block. -+ * -+ * @return true if this is a snapshot -+ * @see Block#getState(boolean) -+ */ -+ boolean isSnapshot(); -+ // Paper end - } diff --git a/patches/api/0074-Expose-client-protocol-version-and-virtual-host.patch b/patches/api/0074-Expose-client-protocol-version-and-virtual-host.patch new file mode 100644 index 000000000000..beac3b204c75 --- /dev/null +++ b/patches/api/0074-Expose-client-protocol-version-and-virtual-host.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Minecrell +Date: Tue, 10 Oct 2017 18:44:42 +0200 +Subject: [PATCH] Expose client protocol version and virtual host + +Add a NetworkClient interface that provides access to: + - The socket address + - The protocol version + - The virtual host (the hostname/port the client used to connect + to the server) + +diff --git a/src/main/java/com/destroystokyo/paper/network/NetworkClient.java b/src/main/java/com/destroystokyo/paper/network/NetworkClient.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c84ce3fc874eea3d8f0b1cf5273996d9b4af6225 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/network/NetworkClient.java +@@ -0,0 +1,39 @@ ++package com.destroystokyo.paper.network; ++ ++import java.net.InetSocketAddress; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Represents a client connected to the server. ++ */ ++@NullMarked ++public interface NetworkClient { ++ ++ /** ++ * Returns the socket address of the client. ++ * ++ * @return The client's socket address ++ */ ++ InetSocketAddress getAddress(); ++ ++ /** ++ * Returns the protocol version of the client. ++ * ++ * @return The client's protocol version, or {@code -1} if unknown ++ * @see List of protocol ++ * version numbers ++ */ ++ int getProtocolVersion(); ++ ++ /** ++ * Returns the virtual host the client is connected to. ++ * ++ *

      The virtual host refers to the hostname/port the client used to ++ * connect to the server.

      ++ * ++ * @return The client's virtual host, or {@code null} if unknown ++ */ ++ @Nullable InetSocketAddress getVirtualHost(); ++ ++} +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 5b12fa8c41a18ddfe08d82c138c0f71106c89d4d..2c9a1378ec8da80e95f2e9e1f3a464ea7b17da93 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -58,7 +58,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a player, connected or not + */ +-public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, net.kyori.adventure.bossbar.BossBarViewer { // Paper ++public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, net.kyori.adventure.bossbar.BossBarViewer, com.destroystokyo.paper.network.NetworkClient { // Paper + + // Paper start + @Override diff --git a/patches/api/0075-AsyncTabCompleteEvent.patch b/patches/api/0075-AsyncTabCompleteEvent.patch deleted file mode 100644 index c6d6dc4ba483..000000000000 --- a/patches/api/0075-AsyncTabCompleteEvent.patch +++ /dev/null @@ -1,250 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 26 Nov 2017 13:17:09 -0500 -Subject: [PATCH] AsyncTabCompleteEvent - -Let plugins be able to control tab completion of commands and chat async. - -This will be useful for frameworks like ACF so we can define async safe completion handlers, -and avoid going to main for tab completions. - -Especially useful if you need to query a database in order to obtain the results for tab -completion, such as offline players. - -diff --git a/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a135a9bfb2ccc8842baa9d5760fa05b7b1a529b1 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java -@@ -0,0 +1,176 @@ -+/* -+ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be -+ * included in all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+package com.destroystokyo.paper.event.server; -+ -+import com.google.common.base.Preconditions; -+import org.bukkit.Location; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+ -+import java.util.ArrayList; -+import java.util.List; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Allows plugins to compute tab completion results asynchronously. If this event provides completions, then the standard synchronous process will not be fired to populate the results. However, the synchronous TabCompleteEvent will fire with the Async results. -+ * -+ * Only 1 process will be allowed to provide completions, the Async Event, or the standard process. -+ */ -+public class AsyncTabCompleteEvent extends Event implements Cancellable { -+ @NotNull private final CommandSender sender; -+ @NotNull private final String buffer; -+ private final boolean isCommand; -+ @Nullable -+ private final Location loc; -+ @NotNull private List completions; -+ private boolean cancelled; -+ private boolean handled = false; -+ private boolean fireSyncHandler = true; -+ -+ public AsyncTabCompleteEvent(@NotNull CommandSender sender, @NotNull List completions, @NotNull String buffer, boolean isCommand, @Nullable Location loc) { -+ super(true); -+ this.sender = sender; -+ this.completions = completions; -+ this.buffer = buffer; -+ this.isCommand = isCommand; -+ this.loc = loc; -+ } -+ -+ /** -+ * Get the sender completing this command. -+ * -+ * @return the {@link CommandSender} instance -+ */ -+ @NotNull -+ public CommandSender getSender() { -+ return sender; -+ } -+ -+ /** -+ * The list of completions which will be offered to the sender, in order. -+ * This list is mutable and reflects what will be offered. -+ * -+ * If this collection is not empty after the event is fired, then -+ * the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} -+ * or current player names will not be called. -+ * -+ * @return a list of offered completions -+ */ -+ @NotNull -+ public List getCompletions() { -+ return completions; -+ } -+ -+ /** -+ * Set the completions offered, overriding any already set. -+ * If this collection is not empty after the event is fired, then -+ * the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} -+ * or current player names will not be called. -+ * -+ * The passed collection will be cloned to a new List. You must call {{@link #getCompletions()}} to mutate from here -+ * -+ * @param completions the new completions -+ */ -+ public void setCompletions(@NotNull List completions) { -+ Preconditions.checkNotNull(completions); -+ this.completions = new ArrayList<>(completions); -+ } -+ -+ /** -+ * Return the entire buffer which formed the basis of this completion. -+ * -+ * @return command buffer, as entered -+ */ -+ @NotNull -+ public String getBuffer() { -+ return buffer; -+ } -+ -+ /** -+ * @return True if it is a command being tab completed, false if it is a chat message. -+ */ -+ public boolean isCommand() { -+ return isCommand; -+ } -+ -+ /** -+ * @return The position looked at by the sender, or null if none -+ */ -+ @Nullable -+ public Location getLocation() { -+ return loc; -+ } -+ -+ /** -+ * If true, the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} -+ * or current player names will not be called. -+ * -+ * @return Is completions considered handled. Always true if completions is not empty. -+ */ -+ public boolean isHandled() { -+ return !completions.isEmpty() || handled; -+ } -+ -+ /** -+ * Sets whether or not to consider the completion request handled. -+ * If true, the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} -+ * or current player names will not be called. -+ * -+ * @param handled if this completion should be marked as being handled -+ */ -+ public void setHandled(boolean handled) { -+ this.handled = handled; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * Will provide no completions, and will not fire the synchronous process -+ * @param cancelled true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancelled) { -+ this.cancelled = cancelled; -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/bukkit/event/server/TabCompleteEvent.java b/src/main/java/org/bukkit/event/server/TabCompleteEvent.java -index 270e6d8ad4358baa256cee5f16cff281f063ce3b..4a3451af454295ac3e1b688e6665cad9fc594c82 100644 ---- a/src/main/java/org/bukkit/event/server/TabCompleteEvent.java -+++ b/src/main/java/org/bukkit/event/server/TabCompleteEvent.java -@@ -29,6 +29,13 @@ public class TabCompleteEvent extends Event implements Cancellable { - private boolean cancelled; - - public TabCompleteEvent(@NotNull CommandSender sender, @NotNull String buffer, @NotNull List completions) { -+ // Paper start -+ this(sender, buffer, completions, sender instanceof org.bukkit.command.ConsoleCommandSender || buffer.startsWith("/"), null); -+ } -+ public TabCompleteEvent(@NotNull CommandSender sender, @NotNull String buffer, @NotNull List completions, boolean isCommand, @org.jetbrains.annotations.Nullable org.bukkit.Location location) { -+ this.isCommand = isCommand; -+ this.loc = location; -+ // Paper end - Preconditions.checkArgument(sender != null, "sender"); - Preconditions.checkArgument(buffer != null, "buffer"); - Preconditions.checkArgument(completions != null, "completions"); -@@ -69,14 +76,35 @@ public class TabCompleteEvent extends Event implements Cancellable { - return completions; - } - -+ // Paper start -+ private final boolean isCommand; -+ private final org.bukkit.Location loc; -+ /** -+ * @return True if it is a command being tab completed, false if it is a chat message. -+ */ -+ public boolean isCommand() { -+ return isCommand; -+ } -+ -+ /** -+ * @return The position looked at by the sender, or null if none -+ */ -+ @org.jetbrains.annotations.Nullable -+ public org.bukkit.Location getLocation() { -+ return loc; -+ } -+ // Paper end -+ - /** - * Set the completions offered, overriding any already set. - * -+ * The passed collection will be cloned to a new List. You must call {{@link #getCompletions()}} to mutate from here -+ * - * @param completions the new completions - */ - public void setCompletions(@NotNull List completions) { - Preconditions.checkArgument(completions != null); -- this.completions = completions; -+ this.completions = new java.util.ArrayList<>(completions); // Paper - } - - @Override diff --git a/patches/api/0075-Display-warning-on-deprecated-recipe-API.patch b/patches/api/0075-Display-warning-on-deprecated-recipe-API.patch new file mode 100644 index 000000000000..4811a851cf20 --- /dev/null +++ b/patches/api/0075-Display-warning-on-deprecated-recipe-API.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 9 Dec 2017 12:40:25 -0500 +Subject: [PATCH] Display warning on deprecated recipe API + +Any plugin still using this API will result in the server saving an inconsistent UUID to player data files, +which then triggers warnings such as "Tried to load unrecognized recipe: bukkit:9e5b92f5-e549-4f47-b0a8-9f89390ed77b removed now." +on the players login. + +Plugin authors need to define a key to keep it consistent between server restarts. + +diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java +index 64916d17ee81cf2eaec7fbac1cb071db3b3eb258..55f4a6efa7dfb64f131f735f92356d01e7cc775a 100644 +--- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java ++++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java +@@ -31,6 +31,7 @@ public class ShapedRecipe extends CraftingRecipe { + @Deprecated(since = "1.12") + public ShapedRecipe(@NotNull ItemStack result) { + this(NamespacedKey.randomKey(), result); ++ new Throwable("Warning: A plugin is creating a recipe using a Deprecated method. This will cause you to receive warnings stating 'Tried to load unrecognized recipe: bukkit:'. Please ask the author to give their recipe a static key using NamespacedKey.").printStackTrace(); // Paper + } + + /** +diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +index 354af775093fd3a74dac6c64244d8f3464397f72..a9d1f9fc129f757353b879fc5946c4b9299833ea 100644 +--- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java ++++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +@@ -20,6 +20,7 @@ public class ShapelessRecipe extends CraftingRecipe { + @Deprecated(since = "1.12") + public ShapelessRecipe(@NotNull ItemStack result) { + this(NamespacedKey.randomKey(), result); ++ new Throwable("Warning: A plugin is creating a recipe using a Deprecated method. This will cause you to receive warnings stating 'Tried to load unrecognized recipe: bukkit:'. Please ask the author to give their recipe a static key using NamespacedKey.").printStackTrace(); // Paper + } + + /** diff --git a/patches/api/0076-Expose-client-protocol-version-and-virtual-host.patch b/patches/api/0076-Expose-client-protocol-version-and-virtual-host.patch deleted file mode 100644 index 34c3a7348610..000000000000 --- a/patches/api/0076-Expose-client-protocol-version-and-virtual-host.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Minecrell -Date: Tue, 10 Oct 2017 18:44:42 +0200 -Subject: [PATCH] Expose client protocol version and virtual host - -Add a NetworkClient interface that provides access to: - - The socket address - - The protocol version - - The virtual host (the hostname/port the client used to connect - to the server) - -diff --git a/src/main/java/com/destroystokyo/paper/network/NetworkClient.java b/src/main/java/com/destroystokyo/paper/network/NetworkClient.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7b2af1bd72dfbcf4e962a982940fc49b851aa04f ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/network/NetworkClient.java -@@ -0,0 +1,41 @@ -+package com.destroystokyo.paper.network; -+ -+import java.net.InetSocketAddress; -+ -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Represents a client connected to the server. -+ */ -+public interface NetworkClient { -+ -+ /** -+ * Returns the socket address of the client. -+ * -+ * @return The client's socket address -+ */ -+ @NotNull -+ InetSocketAddress getAddress(); -+ -+ /** -+ * Returns the protocol version of the client. -+ * -+ * @return The client's protocol version, or {@code -1} if unknown -+ * @see List of protocol -+ * version numbers -+ */ -+ int getProtocolVersion(); -+ -+ /** -+ * Returns the virtual host the client is connected to. -+ * -+ *

      The virtual host refers to the hostname/port the client used to -+ * connect to the server.

      -+ * -+ * @return The client's virtual host, or {@code null} if unknown -+ */ -+ @Nullable -+ InetSocketAddress getVirtualHost(); -+ -+} -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 9d23a4019814f4662f4ab9a47b3fceff656c5245..f9f708bda24751353dd61951418731a2eea5abb0 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -39,7 +39,7 @@ import org.jetbrains.annotations.Nullable; - /** - * Represents a player, connected or not - */ --public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified { // Paper -+public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, com.destroystokyo.paper.network.NetworkClient { // Paper - - // Paper start - @Override diff --git a/patches/api/0076-PlayerPickupExperienceEvent.patch b/patches/api/0076-PlayerPickupExperienceEvent.patch new file mode 100644 index 000000000000..0f6ff806cdfd --- /dev/null +++ b/patches/api/0076-PlayerPickupExperienceEvent.patch @@ -0,0 +1,94 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 19 Dec 2017 22:00:41 -0500 +Subject: [PATCH] PlayerPickupExperienceEvent + +Allows plugins to cancel a player picking up an experience orb + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0c6ddf0724780245ad01a3b5a5b0e477c25fc62e +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.entity.ExperienceOrb; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a player is attempting to pick up an experience orb ++ */ ++@NullMarked ++public class PlayerPickupExperienceEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ExperienceOrb experienceOrb; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerPickupExperienceEvent(final Player player, final ExperienceOrb experienceOrb) { ++ super(player); ++ this.experienceOrb = experienceOrb; ++ } ++ ++ /** ++ * @return Returns the Orb that the player is picking up ++ */ ++ public ExperienceOrb getExperienceOrb() { ++ return this.experienceOrb; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *
      ++ * If {@code true}, cancels picking up the experience orb, leaving it in the world ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0077-Display-warning-on-deprecated-recipe-API.patch b/patches/api/0077-Display-warning-on-deprecated-recipe-API.patch deleted file mode 100644 index 48352336bf35..000000000000 --- a/patches/api/0077-Display-warning-on-deprecated-recipe-API.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 9 Dec 2017 12:40:25 -0500 -Subject: [PATCH] Display warning on deprecated recipe API - -Any plugin still using this API will result in the server saving an inconsistent UUID to player data files, -which then triggers warnings such as "Tried to load unrecognized recipe: bukkit:9e5b92f5-e549-4f47-b0a8-9f89390ed77b removed now." -on the players login. - -Plugin authors need to define a key to keep it consistent between server restarts. - -diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java -index fde34da0f7a13dee06e479fd6c5350a69beb3c95..ad2ab6e97ccf6900d19f8bfbe08181d4c7743a99 100644 ---- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java -+++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java -@@ -24,6 +24,7 @@ public class ShapedRecipe implements Recipe, Keyed { - public ShapedRecipe(@NotNull ItemStack result) { - Preconditions.checkArgument(result.getType() != Material.AIR, "Recipe must have non-AIR result."); - this.key = NamespacedKey.randomKey(); -+ new Throwable("Warning: A plugin is creating a recipe using a Deprecated method. This will cause you to receive warnings stating 'Tried to load unrecognized recipe: bukkit:'. Please ask the author to give their recipe a static key using NamespacedKey.").printStackTrace(); - this.output = new ItemStack(result); - } - -diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java -index cc3f7cccfa06a92f3ca192cb88f30f8929c02dfd..75b47c608d0a902e4ea5f03c395667f47dec8980 100644 ---- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java -+++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java -@@ -25,6 +25,7 @@ public class ShapelessRecipe implements Recipe, Keyed { - public ShapelessRecipe(@NotNull ItemStack result) { - Preconditions.checkArgument(result.getType() != Material.AIR, "Recipe must have non-AIR result."); - this.key = NamespacedKey.randomKey(); -+ new Throwable("Warning: A plugin is creating a recipe using a Deprecated method. This will cause you to receive warnings stating 'Tried to load unrecognized recipe: bukkit:'. Please ask the author to give their recipe a static key using NamespacedKey.").printStackTrace(); - this.output = new ItemStack(result); - } - diff --git a/patches/api/0077-ExperienceOrb-merging-stacking-API.patch b/patches/api/0077-ExperienceOrb-merging-stacking-API.patch new file mode 100644 index 000000000000..aab6f1a751e9 --- /dev/null +++ b/patches/api/0077-ExperienceOrb-merging-stacking-API.patch @@ -0,0 +1,133 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 19 Dec 2017 22:56:24 -0500 +Subject: [PATCH] ExperienceOrb merging/stacking API + +Adds ExperienceOrbMergeEvent +Fired when the server is about to merge 2 experience orbs +Plugins can cancel this if they want to ensure experience orbs do not lose important +metadata such as spawn reason, or conditionally move data from source to target. + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5902e6d6c0516a1249c72b405a49dfc5cc490e0e +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.ExperienceOrb; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired anytime the server is about to merge 2 experience orbs into one ++ */ ++@NullMarked ++public class ExperienceOrbMergeEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ExperienceOrb mergeTarget; ++ private final ExperienceOrb mergeSource; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public ExperienceOrbMergeEvent(final ExperienceOrb mergeTarget, final ExperienceOrb mergeSource) { ++ super(mergeTarget); ++ this.mergeTarget = mergeTarget; ++ this.mergeSource = mergeSource; ++ } ++ ++ /** ++ * @return The orb that will absorb the other experience orb ++ */ ++ public ExperienceOrb getMergeTarget() { ++ return this.mergeTarget; ++ } ++ ++ /** ++ * @return The orb that is subject to being removed and merged into the target orb ++ */ ++ public ExperienceOrb getMergeSource() { ++ return this.mergeSource; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * @param cancel {@code true} if you wish to cancel this event, and prevent the orbs from merging ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/ExperienceOrb.java b/src/main/java/org/bukkit/entity/ExperienceOrb.java +index dec70bbfaf73a9d525b2c45682b804c684e1645b..0fe4a7f300287f38dbe15862787f387aba74397b 100644 +--- a/src/main/java/org/bukkit/entity/ExperienceOrb.java ++++ b/src/main/java/org/bukkit/entity/ExperienceOrb.java +@@ -21,6 +21,22 @@ public interface ExperienceOrb extends Entity { + * @param value Amount of experience + */ + public void setExperience(int value); ++ ++ // Paper start - expose count ++ /** ++ * Get the stacked count for this experience orb. ++ * ++ * @return the count ++ */ ++ int getCount(); ++ ++ /** ++ * Sets the stacked count for this experience orb. ++ * ++ * @param count the new count ++ */ ++ void setCount(int count); ++ // Paper end + + // Paper start + /** diff --git a/patches/api/0078-Ability-to-apply-mending-to-XP-API.patch b/patches/api/0078-Ability-to-apply-mending-to-XP-API.patch new file mode 100644 index 000000000000..b319f2402961 --- /dev/null +++ b/patches/api/0078-Ability-to-apply-mending-to-XP-API.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 20 Dec 2017 17:38:07 -0500 +Subject: [PATCH] Ability to apply mending to XP API + +This allows plugins that give players the ability to apply the experience +points to the Item Mending formula, which will repair an item instead +of giving the player experience points. + +Both an API To standalone mend, and apply mending logic to .giveExp has been added. + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 2c9a1378ec8da80e95f2e9e1f3a464ea7b17da93..fcb83800bc4cbaa96e5f190e0cf618542d8bb637 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -1588,6 +1588,15 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public void resetPlayerWeather(); + ++ // Paper start ++ /** ++ * Gives the player the amount of experience specified. ++ * ++ * @param amount Exp amount to give ++ */ ++ public default void giveExp(int amount) { ++ giveExp(amount, false); ++ } + /** + * Gets the player's cooldown between picking up experience orbs. + * +@@ -1613,8 +1622,20 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * Gives the player the amount of experience specified. + * + * @param amount Exp amount to give ++ * @param applyMending Mend players items with mending, with same behavior as picking up orbs. calls {@link #applyMending(int)} + */ +- public void giveExp(int amount); ++ public void giveExp(int amount, boolean applyMending); ++ ++ /** ++ * Applies the mending effect to any items just as picking up an orb would. ++ * ++ * Can also be called with {@link #giveExp(int, boolean)} by passing true to applyMending ++ * ++ * @param amount Exp to apply ++ * @return the remaining experience ++ */ ++ public int applyMending(int amount); ++ // Paper end + + /** + * Gives the player the amount of experience levels specified. Levels can diff --git a/patches/api/0078-PlayerPickupExperienceEvent.patch b/patches/api/0078-PlayerPickupExperienceEvent.patch deleted file mode 100644 index 906a8ec7c359..000000000000 --- a/patches/api/0078-PlayerPickupExperienceEvent.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 19 Dec 2017 22:00:41 -0500 -Subject: [PATCH] PlayerPickupExperienceEvent - -Allows plugins to cancel a player picking up an experience orb - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f7beb22d5105157940b39efe594ace9d4cb153f5 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerPickupExperienceEvent.java -@@ -0,0 +1,80 @@ -+/* -+ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be -+ * included in all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.entity.ExperienceOrb; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a player is attempting to pick up an experience orb -+ */ -+public class PlayerPickupExperienceEvent extends PlayerEvent implements Cancellable { -+ @NotNull private final ExperienceOrb experienceOrb; -+ -+ public PlayerPickupExperienceEvent(@NotNull Player player, @NotNull ExperienceOrb experienceOrb) { -+ super(player); -+ this.experienceOrb = experienceOrb; -+ } -+ -+ /** -+ * @return Returns the Orb that the player is picking up -+ */ -+ @NotNull -+ public ExperienceOrb getExperienceOrb() { -+ return experienceOrb; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * If true, Cancels picking up the experience orb, leaving it in the world -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0079-ExperienceOrbMergeEvent.patch b/patches/api/0079-ExperienceOrbMergeEvent.patch deleted file mode 100644 index 3a4722a77635..000000000000 --- a/patches/api/0079-ExperienceOrbMergeEvent.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 19 Dec 2017 22:56:24 -0500 -Subject: [PATCH] ExperienceOrbMergeEvent - -Fired when the server is about to merge 2 experience orbs -Plugins can cancel this if they want to ensure experience orbs do not lose important -metadata such as spawn reason, or conditionally move data from source to target. - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0ce3e397716c28c30ed05e153babd0bfb9dd354a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/ExperienceOrbMergeEvent.java -@@ -0,0 +1,87 @@ -+/* -+ * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be -+ * included in all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.ExperienceOrb; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired anytime the server is about to merge 2 experience orbs into one -+ */ -+public class ExperienceOrbMergeEvent extends EntityEvent implements Cancellable { -+ @NotNull private final ExperienceOrb mergeTarget; -+ @NotNull private final ExperienceOrb mergeSource; -+ -+ public ExperienceOrbMergeEvent(@NotNull ExperienceOrb mergeTarget, @NotNull ExperienceOrb mergeSource) { -+ super(mergeTarget); -+ this.mergeTarget = mergeTarget; -+ this.mergeSource = mergeSource; -+ } -+ -+ /** -+ * @return The orb that will absorb the other experience orb -+ */ -+ @NotNull -+ public ExperienceOrb getMergeTarget() { -+ return mergeTarget; -+ } -+ -+ /** -+ * @return The orb that is subject to being removed and merged into the target orb -+ */ -+ @NotNull -+ public ExperienceOrb getMergeSource() { -+ return mergeSource; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * @param cancel true if you wish to cancel this event, and prevent the orbs from merging -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0079-PreCreatureSpawnEvent.patch b/patches/api/0079-PreCreatureSpawnEvent.patch new file mode 100644 index 000000000000..f746a461e5ba --- /dev/null +++ b/patches/api/0079-PreCreatureSpawnEvent.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 14 Jan 2018 16:59:43 -0500 +Subject: [PATCH] PreCreatureSpawnEvent + +Adds an event to fire before an Entity is created, so that plugins that need to cancel +CreatureSpawnEvent can do so from this event instead. + +Cancelling CreatureSpawnEvent rapidly causes a lot of garbage collection and CPU waste +as it's done after the Entity object has been fully created. + +Mob Limiting plugins and blanket "ban this type of monster" plugins should use this event +instead and save a lot of server resources. + +See: https://github.com/PaperMC/Paper/issues/917 + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c1c96f93a4a5450381cb5bdb198b056a37ba0fbe +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java +@@ -0,0 +1,105 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.Location; ++import org.bukkit.entity.EntityType; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * WARNING: This event only fires for a limited number of cases, and not for every case that {@link CreatureSpawnEvent} does. ++ *

      ++ * You should still listen to {@link CreatureSpawnEvent} as a backup, and only use this event as an "enhancement". ++ * The intent of this event is to improve server performance, so it fires even if the spawning might fail later, for ++ * example when the entity would be unable to spawn due to limited space or lighting. ++ *

      ++ * Currently: NATURAL and SPAWNER based reasons. ++ * Also, Plugins that replace Entity Registrations with their own custom entities might not fire this event. ++ */ ++@NullMarked ++public class PreCreatureSpawnEvent extends Event implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Location location; ++ private final EntityType type; ++ private final CreatureSpawnEvent.SpawnReason reason; ++ private boolean shouldAbortSpawn; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PreCreatureSpawnEvent(final Location location, final EntityType type, final CreatureSpawnEvent.SpawnReason reason) { ++ this.location = location; ++ this.type = type; ++ this.reason = reason; ++ } ++ ++ /** ++ * @return The location this creature is being spawned at ++ */ ++ public Location getSpawnLocation() { ++ return this.location.clone(); ++ } ++ ++ /** ++ * @return The type of creature being spawned ++ */ ++ public EntityType getType() { ++ return this.type; ++ } ++ ++ /** ++ * @return Reason this creature is spawning (ie, NATURAL vs SPAWNER) ++ */ ++ public CreatureSpawnEvent.SpawnReason getReason() { ++ return this.reason; ++ } ++ ++ /** ++ * @return If the spawn process should be aborted vs trying more attempts ++ */ ++ public boolean shouldAbortSpawn() { ++ return this.shouldAbortSpawn; ++ } ++ ++ /** ++ * Set this if you are more blanket blocking all types of these spawns, and wish to abort the spawn process from ++ * trying more attempts after this cancellation. ++ * ++ * @param shouldAbortSpawn Set if the spawn process should be aborted vs trying more attempts ++ */ ++ public void setShouldAbortSpawn(final boolean shouldAbortSpawn) { ++ this.shouldAbortSpawn = shouldAbortSpawn; ++ } ++ ++ /** ++ * @return If the spawn of this creature is cancelled or not ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * Cancelling this event is more efficient than cancelling {@link CreatureSpawnEvent} ++ * ++ * @param cancel {@code true} if you wish to cancel this event, and abort the spawn of this creature ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0080-Ability-to-apply-mending-to-XP-API.patch b/patches/api/0080-Ability-to-apply-mending-to-XP-API.patch deleted file mode 100644 index 99f6eff47dff..000000000000 --- a/patches/api/0080-Ability-to-apply-mending-to-XP-API.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 20 Dec 2017 17:38:07 -0500 -Subject: [PATCH] Ability to apply mending to XP API - -This allows plugins that give players the ability to apply the experience -points to the Item Mending formula, which will repair an item instead -of giving the player experience points. - -Both an API To standalone mend, and apply mending logic to .giveExp has been added. - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 7f29fd1891b0b0c2037dc6fb7620e6de29083feb..dc8740d5410aebaa17e014d43b7d9fb29ae2a3d0 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -1033,12 +1033,33 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - */ - public void resetPlayerWeather(); - -+ // Paper start -+ /** -+ * Gives the player the amount of experience specified. -+ * -+ * @param amount Exp amount to give -+ */ -+ public default void giveExp(int amount) { -+ giveExp(amount, false); -+ } - /** - * Gives the player the amount of experience specified. - * - * @param amount Exp amount to give -+ * @param applyMending Mend players items with mending, with same behavior as picking up orbs. calls {@link #applyMending(int)} - */ -- public void giveExp(int amount); -+ public void giveExp(int amount, boolean applyMending); -+ -+ /** -+ * Applies the mending effect to any items just as picking up an orb would. -+ * -+ * Can also be called with {@link #giveExp(int, boolean)} by passing true to applyMending -+ * -+ * @param amount Exp to apply -+ * @return the remaining experience -+ */ -+ public int applyMending(int amount); -+ // Paper end - - /** - * Gives the player the amount of experience levels specified. Levels can diff --git a/patches/api/0080-PlayerNaturallySpawnCreaturesEvent.patch b/patches/api/0080-PlayerNaturallySpawnCreaturesEvent.patch new file mode 100644 index 000000000000..4cf38c237e62 --- /dev/null +++ b/patches/api/0080-PlayerNaturallySpawnCreaturesEvent.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 14 Jan 2018 17:31:37 -0500 +Subject: [PATCH] PlayerNaturallySpawnCreaturesEvent + +This event can be used for when you want to exclude a certain player +from triggering monster spawns on a server. + +Also a highly more effecient way to blanket block spawns in a world + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a3267a283b39e8db1e9b7e5338d2909320f1421c +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java +@@ -0,0 +1,65 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when the server is calculating what chunks to try to spawn monsters in every Monster Spawn Tick event ++ */ ++@NullMarked ++public class PlayerNaturallySpawnCreaturesEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private byte radius; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerNaturallySpawnCreaturesEvent(final Player player, final byte radius) { ++ super(player); ++ this.radius = radius; ++ } ++ ++ /** ++ * @return The radius of chunks around this player to be included in natural spawn selection ++ */ ++ public byte getSpawnRadius() { ++ return this.radius; ++ } ++ ++ /** ++ * @param radius The radius of chunks around this player to be included in natural spawn selection ++ */ ++ public void setSpawnRadius(final byte radius) { ++ this.radius = radius; ++ } ++ ++ /** ++ * @return If this player's chunks will be excluded from natural spawns ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * @param cancel {@code true} if you wish to cancel this event, and not include this player's chunks for natural spawning ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0081-Add-setPlayerProfile-API-for-Skulls.patch b/patches/api/0081-Add-setPlayerProfile-API-for-Skulls.patch new file mode 100644 index 000000000000..213a9ad3b639 --- /dev/null +++ b/patches/api/0081-Add-setPlayerProfile-API-for-Skulls.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 19 Jan 2018 00:29:28 -0500 +Subject: [PATCH] Add setPlayerProfile API for Skulls + +This allows you to create already filled textures on Skulls to avoid texture lookups +which commonly cause rate limit issues with Mojang API + +diff --git a/src/main/java/org/bukkit/block/Skull.java b/src/main/java/org/bukkit/block/Skull.java +index bf2d1b300f1370b33b7a066817074e27b0a86212..6cb7791e97e27812ec816acd709237d4e4f805e4 100644 +--- a/src/main/java/org/bukkit/block/Skull.java ++++ b/src/main/java/org/bukkit/block/Skull.java +@@ -63,6 +63,20 @@ public interface Skull extends TileState { + */ + public void setOwningPlayer(@NotNull OfflinePlayer player); + ++ // Paper start ++ /** ++ * Sets this skull to use the supplied Player Profile, which can include textures already prefilled. ++ * @param profile The profile to set this Skull to use, may not be null ++ */ ++ void setPlayerProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile); ++ ++ /** ++ * If the skull has an owner, per {@link #hasOwner()}, return the owners {@link com.destroystokyo.paper.profile.PlayerProfile} ++ * @return The profile of the owner, if set ++ */ ++ @Nullable com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile(); ++ // Paper end ++ + /** + * Gets the profile of the player who owns the skull. This player profile + * may appear as the texture depending on skull type. +@@ -70,6 +84,7 @@ public interface Skull extends TileState { + * @return the profile of the owning player + */ + @Nullable ++ @Deprecated // Paper + PlayerProfile getOwnerProfile(); + + /** +@@ -84,6 +99,7 @@ public interface Skull extends TileState { + * @throws IllegalArgumentException if the profile does not contain the + * necessary information + */ ++ @Deprecated // Paper + void setOwnerProfile(@Nullable PlayerProfile profile); + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/SkullMeta.java b/src/main/java/org/bukkit/inventory/meta/SkullMeta.java +index 5af814d3cf87d44f69a20dd867716b5b17046a83..a478b6939d61b5d21628dc894bed9e1eb1de5460 100644 +--- a/src/main/java/org/bukkit/inventory/meta/SkullMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/SkullMeta.java +@@ -38,6 +38,20 @@ public interface SkullMeta extends ItemMeta { + @Deprecated(since = "1.12.1") + boolean setOwner(@Nullable String owner); + ++ // Paper start ++ /** ++ * Sets this skull to use the supplied Player Profile, which can include textures already prefilled. ++ * @param profile The profile to set this Skull to use, or null to clear owner ++ */ ++ void setPlayerProfile(@Nullable com.destroystokyo.paper.profile.PlayerProfile profile); ++ ++ /** ++ * If the skull has an owner, per {@link #hasOwner()}, return the owners {@link com.destroystokyo.paper.profile.PlayerProfile} ++ * @return The profile of the owner, if set ++ */ ++ @Nullable com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile(); ++ // Paper end ++ + /** + * Gets the owner of the skull. + * +@@ -64,6 +78,7 @@ public interface SkullMeta extends ItemMeta { + * @return the profile of the owning player + */ + @Nullable ++ @Deprecated // Paper + PlayerProfile getOwnerProfile(); + + /** +@@ -78,6 +93,7 @@ public interface SkullMeta extends ItemMeta { + * @throws IllegalArgumentException if the profile does not contain the + * necessary information + */ ++ @Deprecated // Paper + void setOwnerProfile(@Nullable PlayerProfile profile); + + /** diff --git a/patches/api/0081-PreCreatureSpawnEvent.patch b/patches/api/0081-PreCreatureSpawnEvent.patch deleted file mode 100644 index 0090330de9e3..000000000000 --- a/patches/api/0081-PreCreatureSpawnEvent.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 14 Jan 2018 16:59:43 -0500 -Subject: [PATCH] PreCreatureSpawnEvent - -Adds an event to fire before an Entity is created, so that plugins that need to cancel -CreatureSpawnEvent can do so from this event instead. - -Cancelling CreatureSpawnEvent rapidly causes a lot of garbage collection and CPU waste -as it's done after the Entity object has been fully created. - -Mob Limiting plugins and blanket "ban this type of monster" plugins should use this event -instead and save a lot of server resources. - -See: https://github.com/PaperMC/Paper/issues/917 - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3ad231aa3206c8cfd5ec995249584cebab5d11f3 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/PreCreatureSpawnEvent.java -@@ -0,0 +1,105 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import com.google.common.base.Preconditions; -+import org.bukkit.Location; -+import org.bukkit.entity.EntityType; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.CreatureSpawnEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * WARNING: This event only fires for a limited number of cases, and not for every case that CreatureSpawnEvent does. -+ * -+ * You should still listen to CreatureSpawnEvent as a backup, and only use this event as an "enhancement". -+ * The intent of this event is to improve server performance, so it fires even if the spawning might fail later, for -+ * example when the entity would be unable to spawn due to limited space or lighting. -+ * -+ * Currently: NATURAL and SPAWNER based reasons. Please submit a Pull Request for future additions. -+ * Also, Plugins that replace Entity Registrations with their own custom entities might not fire this event. -+ */ -+public class PreCreatureSpawnEvent extends Event implements Cancellable { -+ @NotNull private final Location location; -+ @NotNull private final EntityType type; -+ @NotNull private final CreatureSpawnEvent.SpawnReason reason; -+ private boolean shouldAbortSpawn; -+ -+ public PreCreatureSpawnEvent(@NotNull Location location, @NotNull EntityType type, @NotNull CreatureSpawnEvent.SpawnReason reason) { -+ this.location = Preconditions.checkNotNull(location, "Location may not be null").clone(); -+ this.type = Preconditions.checkNotNull(type, "Type may not be null"); -+ this.reason = Preconditions.checkNotNull(reason, "Reason may not be null"); -+ } -+ -+ /** -+ * @return The location this creature is being spawned at -+ */ -+ @NotNull -+ public Location getSpawnLocation() { -+ return location; -+ } -+ -+ /** -+ * @return The type of creature being spawned -+ */ -+ @NotNull -+ public EntityType getType() { -+ return type; -+ } -+ -+ /** -+ * @return Reason this creature is spawning (ie, NATURAL vs SPAWNER) -+ */ -+ @NotNull -+ public CreatureSpawnEvent.SpawnReason getReason() { -+ return reason; -+ } -+ -+ /** -+ * @return If the spawn process should be aborted vs trying more attempts -+ */ -+ public boolean shouldAbortSpawn() { -+ return shouldAbortSpawn; -+ } -+ -+ /** -+ * Set this if you are more blanket blocking all types of these spawns, and wish to abort the spawn process from -+ * trying more attempts after this cancellation. -+ * -+ * @param shouldAbortSpawn Set if the spawn process should be aborted vs trying more attempts -+ */ -+ public void setShouldAbortSpawn(boolean shouldAbortSpawn) { -+ this.shouldAbortSpawn = shouldAbortSpawn; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ /** -+ * @return If the spawn of this creature is cancelled or not -+ */ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * Cancelling this event is more effecient than cancelling CreatureSpawnEvent -+ * @param cancel true if you wish to cancel this event, and abort the spawn of this creature -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0082-Add-PlayerAdvancementCriterionGrantEvent.patch b/patches/api/0082-Add-PlayerAdvancementCriterionGrantEvent.patch new file mode 100644 index 000000000000..852e4d9d1e07 --- /dev/null +++ b/patches/api/0082-Add-PlayerAdvancementCriterionGrantEvent.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 19 Jan 2018 08:15:14 -0600 +Subject: [PATCH] Add PlayerAdvancementCriterionGrantEvent + +Co-authored-by: The456gamer + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0fb316e34ec9728610237a08f37fffb61fd5afa8 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java +@@ -0,0 +1,80 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.advancement.Advancement; ++import org.bukkit.advancement.AdvancementProgress; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called after a player is granted a criteria in an advancement. ++ * If cancelled the criteria will be revoked. ++ */ ++@NullMarked ++public class PlayerAdvancementCriterionGrantEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Advancement advancement; ++ private final String criterion; ++ private final AdvancementProgress advancementProgress; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerAdvancementCriterionGrantEvent(final Player player, final Advancement advancement, final String criterion) { ++ super(player); ++ this.advancement = advancement; ++ this.criterion = criterion; ++ this.advancementProgress = player.getAdvancementProgress(advancement); ++ } ++ ++ /** ++ * Get the advancement which has been affected. ++ * ++ * @return affected advancement ++ */ ++ public Advancement getAdvancement() { ++ return this.advancement; ++ } ++ ++ /** ++ * Get the criterion which has been granted. ++ * ++ * @return granted criterion ++ */ ++ public String getCriterion() { ++ return this.criterion; ++ } ++ ++ /** ++ * Gets the current AdvancementProgress. ++ * ++ * @return advancement progress ++ */ ++ public AdvancementProgress getAdvancementProgress() { ++ return this.advancementProgress; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0082-PlayerNaturallySpawnCreaturesEvent.patch b/patches/api/0082-PlayerNaturallySpawnCreaturesEvent.patch deleted file mode 100644 index a6fa8a9b726b..000000000000 --- a/patches/api/0082-PlayerNaturallySpawnCreaturesEvent.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 14 Jan 2018 17:31:37 -0500 -Subject: [PATCH] PlayerNaturallySpawnCreaturesEvent - -This event can be used for when you want to exclude a certain player -from triggering monster spawns on a server. - -Also a highly more effecient way to blanket block spawns in a world - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..112a0dbf522b8e74ce882678434923814e6b187f ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/PlayerNaturallySpawnCreaturesEvent.java -@@ -0,0 +1,64 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when the server is calculating what chunks to try to spawn monsters in every Monster Spawn Tick event -+ */ -+public class PlayerNaturallySpawnCreaturesEvent extends PlayerEvent implements Cancellable { -+ private byte radius; -+ -+ public PlayerNaturallySpawnCreaturesEvent(@NotNull Player player, byte radius) { -+ super(player); -+ this.radius = radius; -+ } -+ -+ /** -+ * @return The radius of chunks around this player to be included in natural spawn selection -+ */ -+ public byte getSpawnRadius() { -+ return radius; -+ } -+ -+ /** -+ * @param radius The radius of chunks around this player to be included in natural spawn selection -+ */ -+ public void setSpawnRadius(byte radius) { -+ this.radius = radius; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ /** -+ * @return If this players chunks will be excluded from natural spawns -+ */ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * @param cancel true if you wish to cancel this event, and not include this players chunks for natural spawning -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0083-Add-setPlayerProfile-API-for-Skulls.patch b/patches/api/0083-Add-setPlayerProfile-API-for-Skulls.patch deleted file mode 100644 index d78a2673400b..000000000000 --- a/patches/api/0083-Add-setPlayerProfile-API-for-Skulls.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 19 Jan 2018 00:29:28 -0500 -Subject: [PATCH] Add setPlayerProfile API for Skulls - -This allows you to create already filled textures on Skulls to avoid texture lookups -which commonly cause rate limit issues with Mojang API - -diff --git a/src/main/java/org/bukkit/block/Skull.java b/src/main/java/org/bukkit/block/Skull.java -index 83ca284e02f0c2229126d8f40cb33b18f44524d3..d89da5e370d95cfbc4dac776a64e402c5c1f5fc1 100644 ---- a/src/main/java/org/bukkit/block/Skull.java -+++ b/src/main/java/org/bukkit/block/Skull.java -@@ -62,6 +62,20 @@ public interface Skull extends TileState { - */ - public void setOwningPlayer(@NotNull OfflinePlayer player); - -+ // Paper start -+ /** -+ * Sets this skull to use the supplied Player Profile, which can include textures already prefilled. -+ * @param profile The profile to set this Skull to use, may not be null -+ */ -+ void setPlayerProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile); -+ -+ /** -+ * If the skull has an owner, per {@link #hasOwner()}, return the owners {@link com.destroystokyo.paper.profile.PlayerProfile} -+ * @return The profile of the owner, if set -+ */ -+ @Nullable com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile(); -+ // Paper end -+ - /** - * Gets the profile of the player who owns the skull. This player profile - * may appear as the texture depending on skull type. -@@ -69,6 +83,7 @@ public interface Skull extends TileState { - * @return the profile of the owning player - */ - @Nullable -+ @Deprecated // Paper - PlayerProfile getOwnerProfile(); - - /** -@@ -83,6 +98,7 @@ public interface Skull extends TileState { - * @throws IllegalArgumentException if the profile does not contain the - * necessary information - */ -+ @Deprecated // Paper - void setOwnerProfile(@Nullable PlayerProfile profile); - - /** -diff --git a/src/main/java/org/bukkit/inventory/meta/SkullMeta.java b/src/main/java/org/bukkit/inventory/meta/SkullMeta.java -index dcefd0eea9461441c4209d587896d704389487d0..9ad062968335ee02bff5353d8c63c330d9338cd7 100644 ---- a/src/main/java/org/bukkit/inventory/meta/SkullMeta.java -+++ b/src/main/java/org/bukkit/inventory/meta/SkullMeta.java -@@ -37,6 +37,20 @@ public interface SkullMeta extends ItemMeta { - @Deprecated - boolean setOwner(@Nullable String owner); - -+ // Paper start -+ /** -+ * Sets this skull to use the supplied Player Profile, which can include textures already prefilled. -+ * @param profile The profile to set this Skull to use, or null to clear owner -+ */ -+ void setPlayerProfile(@Nullable com.destroystokyo.paper.profile.PlayerProfile profile); -+ -+ /** -+ * If the skull has an owner, per {@link #hasOwner()}, return the owners {@link com.destroystokyo.paper.profile.PlayerProfile} -+ * @return The profile of the owner, if set -+ */ -+ @Nullable com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile(); -+ // Paper end -+ - /** - * Gets the owner of the skull. - * -@@ -63,6 +77,7 @@ public interface SkullMeta extends ItemMeta { - * @return the profile of the owning player - */ - @Nullable -+ @Deprecated // Paper - PlayerProfile getOwnerProfile(); - - /** -@@ -77,6 +92,7 @@ public interface SkullMeta extends ItemMeta { - * @throws IllegalArgumentException if the profile does not contain the - * necessary information - */ -+ @Deprecated // Paper - void setOwnerProfile(@Nullable PlayerProfile profile); - - @Override diff --git a/patches/api/0083-Fill-Profile-Property-Events.patch b/patches/api/0083-Fill-Profile-Property-Events.patch new file mode 100644 index 000000000000..137c383e9e75 --- /dev/null +++ b/patches/api/0083-Fill-Profile-Property-Events.patch @@ -0,0 +1,177 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 2 Jan 2018 00:31:08 -0500 +Subject: [PATCH] Fill Profile Property Events + +Allows plugins to populate profile properties from local sources to avoid calls out to Mojang API +to fill in textures for example. + +If Mojang API does need to be hit, event fire so you can get the results. + +This is useful for implementing a ProfileCache for Player Skulls + +diff --git a/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8625d60eb822f39140152f2f74ec5bfe5ecd0039 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java +@@ -0,0 +1,75 @@ ++/* ++ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++package com.destroystokyo.paper.event.profile; ++ ++import com.destroystokyo.paper.profile.PlayerProfile; ++import com.destroystokyo.paper.profile.ProfileProperty; ++import java.util.Set; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired once a profiles additional properties (such as textures) has been filled ++ */ ++@NullMarked ++public class FillProfileEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final PlayerProfile profile; ++ ++ @ApiStatus.Internal ++ public FillProfileEvent(final PlayerProfile profile) { ++ super(!org.bukkit.Bukkit.isPrimaryThread()); ++ this.profile = profile; ++ } ++ ++ /** ++ * @return The Profile that had properties filled ++ */ ++ public PlayerProfile getPlayerProfile() { ++ return this.profile; ++ } ++ ++ /** ++ * Same as .getPlayerProfile().getProperties() ++ * ++ * @return The new properties on the profile. ++ * @see PlayerProfile#getProperties() ++ */ ++ public Set getProperties() { ++ return this.profile.getProperties(); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..177c23274d6dad709b05706117303b70ae8b4c7b +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java +@@ -0,0 +1,78 @@ ++/* ++ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++package com.destroystokyo.paper.event.profile; ++ ++import com.destroystokyo.paper.profile.PlayerProfile; ++import com.destroystokyo.paper.profile.ProfileProperty; ++import java.util.Collection; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when the server is requesting to fill in properties of an incomplete profile, such as textures. ++ *

      ++ * Allows plugins to pre-populate cached properties and avoid a call to the Mojang API ++ */ ++@NullMarked ++public class PreFillProfileEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final PlayerProfile profile; ++ ++ @ApiStatus.Internal ++ public PreFillProfileEvent(final PlayerProfile profile) { ++ super(!org.bukkit.Bukkit.isPrimaryThread()); ++ this.profile = profile; ++ } ++ ++ /** ++ * @return The profile that needs its properties filled ++ */ ++ public PlayerProfile getPlayerProfile() { ++ return this.profile; ++ } ++ ++ /** ++ * Sets the properties on the profile, avoiding the call to the Mojang API ++ * Same as .getPlayerProfile().setProperties(properties); ++ * ++ * @param properties The properties to set/append ++ * @see PlayerProfile#setProperties(Collection) ++ */ ++ public void setProperties(final Collection properties) { ++ this.profile.setProperties(properties); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0084-Add-ArmorStand-Item-Meta.patch b/patches/api/0084-Add-ArmorStand-Item-Meta.patch new file mode 100644 index 000000000000..db847081ce8c --- /dev/null +++ b/patches/api/0084-Add-ArmorStand-Item-Meta.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Sat, 27 Jan 2018 17:06:24 -0500 +Subject: [PATCH] Add ArmorStand Item Meta + +This is adds basic item meta for armor stands. It does not add all +possible metadata however. + +There are armor, hand, and equipment types, as well as position data +that can also be added here. This initial addition should serve a +starting point for future additions in this area. + +diff --git a/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java b/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7e4acfff16db80a75e1ff2fee1972b16955b0918 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java +@@ -0,0 +1,78 @@ ++package com.destroystokyo.paper.inventory.meta; ++ ++import org.bukkit.inventory.meta.ItemMeta; ++ ++public interface ArmorStandMeta extends ItemMeta { ++ ++ /** ++ * Gets whether the ArmorStand should be invisible when spawned ++ * ++ * @return true if this should be invisible ++ */ ++ boolean isInvisible(); ++ ++ /** ++ * Gets whether this ArmorStand should have no base plate when spawned ++ * ++ * @return true if it will not have a base plate ++ */ ++ boolean hasNoBasePlate(); ++ ++ /** ++ * Gets whether this ArmorStand should show arms when spawned ++ * ++ * @return true if it will show arms ++ */ ++ boolean shouldShowArms(); ++ ++ /** ++ * Gets whether this ArmorStand will be small when spawned ++ * ++ * @return true if it will be small ++ */ ++ boolean isSmall(); ++ ++ /** ++ * Gets whether this ArmorStand will be a marker when spawned ++ * The exact details of this flag are an implementation detail ++ * ++ * @return true if it will be a marker ++ */ ++ boolean isMarker(); ++ ++ /** ++ * Sets that this ArmorStand should be invisible when spawned ++ * ++ * @param invisible true if set invisible ++ */ ++ void setInvisible(boolean invisible); ++ ++ /** ++ * Sets that this ArmorStand should have no base plate when spawned ++ * ++ * @param noBasePlate true if no base plate ++ */ ++ void setNoBasePlate(boolean noBasePlate); ++ ++ /** ++ * Sets that this ArmorStand should show arms when spawned ++ * ++ * @param showArms true if show arms ++ */ ++ void setShowArms(boolean showArms); ++ ++ /** ++ * Sets that this ArmorStand should be small when spawned ++ * ++ * @param small true if small ++ */ ++ void setSmall(boolean small); ++ ++ /** ++ * Sets that this ArmorStand should be a marker when spawned ++ * The exact details of this flag are an implementation detail ++ * ++ * @param marker true if a marker ++ */ ++ void setMarker(boolean marker); ++} +diff --git a/src/main/java/org/bukkit/inventory/ItemType.java b/src/main/java/org/bukkit/inventory/ItemType.java +index 4f3579253e56bd868a084767854192863961d7c9..71c4f2cbf8310941b316357d0c799b1e31418d0f 100644 +--- a/src/main/java/org/bukkit/inventory/ItemType.java ++++ b/src/main/java/org/bukkit/inventory/ItemType.java +@@ -1903,7 +1903,7 @@ public interface ItemType extends Keyed, Translatable { + ItemType.Typed RABBIT_STEW = getItemType("rabbit_stew"); + ItemType.Typed RABBIT_FOOT = getItemType("rabbit_foot"); + ItemType.Typed RABBIT_HIDE = getItemType("rabbit_hide"); +- ItemType.Typed ARMOR_STAND = getItemType("armor_stand"); ++ ItemType.Typed ARMOR_STAND = getItemType("armor_stand"); + ItemType.Typed IRON_HORSE_ARMOR = getItemType("iron_horse_armor"); + ItemType.Typed GOLDEN_HORSE_ARMOR = getItemType("golden_horse_armor"); + ItemType.Typed DIAMOND_HORSE_ARMOR = getItemType("diamond_horse_armor"); diff --git a/patches/api/0084-Fill-Profile-Property-Events.patch b/patches/api/0084-Fill-Profile-Property-Events.patch deleted file mode 100644 index 5511f6449a8e..000000000000 --- a/patches/api/0084-Fill-Profile-Property-Events.patch +++ /dev/null @@ -1,176 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 2 Jan 2018 00:31:08 -0500 -Subject: [PATCH] Fill Profile Property Events - -Allows plugins to populate profile properties from local sources to avoid calls out to Mojang API -to fill in textures for example. - -If Mojang API does need to be hit, event fire so you can get the results. - -This is useful for implementing a ProfileCache for Player Skulls - -diff --git a/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..71f36e9cae209ec6861835a5e76e018de959040a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/profile/FillProfileEvent.java -@@ -0,0 +1,75 @@ -+/* -+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be -+ * included in all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+package com.destroystokyo.paper.event.profile; -+ -+import com.destroystokyo.paper.profile.PlayerProfile; -+import com.destroystokyo.paper.profile.ProfileProperty; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+ -+import java.util.Set; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired once a profiles additional properties (such as textures) has been filled -+ */ -+public class FillProfileEvent extends Event { -+ @NotNull private final PlayerProfile profile; -+ -+ public FillProfileEvent(@NotNull PlayerProfile profile) { -+ super(!org.bukkit.Bukkit.isPrimaryThread()); -+ this.profile = profile; -+ } -+ -+ /** -+ * @return The Profile that had properties filled -+ */ -+ @NotNull -+ public PlayerProfile getPlayerProfile() { -+ return profile; -+ } -+ -+ /** -+ * Same as .getPlayerProfile().getProperties() -+ * -+ * @see PlayerProfile#getProperties() -+ * @return The new properties on the profile. -+ */ -+ @NotNull -+ public Set getProperties() { -+ return profile.getProperties(); -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..021bc86310a06f84b39459e0eb8927802726399c ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/profile/PreFillProfileEvent.java -@@ -0,0 +1,77 @@ -+/* -+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be -+ * included in all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+package com.destroystokyo.paper.event.profile; -+ -+import com.destroystokyo.paper.profile.PlayerProfile; -+import com.destroystokyo.paper.profile.ProfileProperty; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+ -+import java.util.Collection; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when the server is requesting to fill in properties of an incomplete profile, such as textures. -+ * -+ * Allows plugins to pre populate cached properties and avoid a call to the Mojang API -+ */ -+public class PreFillProfileEvent extends Event { -+ @NotNull private final PlayerProfile profile; -+ -+ public PreFillProfileEvent(@NotNull PlayerProfile profile) { -+ super(!org.bukkit.Bukkit.isPrimaryThread()); -+ this.profile = profile; -+ } -+ -+ /** -+ * @return The profile that needs its properties filled -+ */ -+ @NotNull -+ public PlayerProfile getPlayerProfile() { -+ return profile; -+ } -+ -+ /** -+ * Sets the properties on the profile, avoiding the call to the Mojang API -+ * Same as .getPlayerProfile().setProperties(properties); -+ * -+ * @see PlayerProfile#setProperties(Collection) -+ * @param properties The properties to set/append -+ */ -+ public void setProperties(@NotNull Collection properties) { -+ profile.setProperties(properties); -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0085-Optimize-Hoppers.patch b/patches/api/0085-Optimize-Hoppers.patch new file mode 100644 index 000000000000..3cf0268664dd --- /dev/null +++ b/patches/api/0085-Optimize-Hoppers.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 18 Jan 2018 01:00:27 -0500 +Subject: [PATCH] Optimize Hoppers + + +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryMoveItemEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryMoveItemEvent.java +index 919cc993e3cb1c14e2a3aebf90e6cc0fa6fbc17f..0161b8a94c7e8774fec3ed9c36d9c37221525928 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryMoveItemEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryMoveItemEvent.java +@@ -58,7 +58,7 @@ public class InventoryMoveItemEvent extends Event implements Cancellable { + */ + @NotNull + public ItemStack getItem() { +- return itemStack.clone(); ++ return itemStack; // Paper - Removed clone, handled better in Server + } + + /** diff --git a/patches/api/0085-PlayerAdvancementCriterionGrantEvent.patch b/patches/api/0085-PlayerAdvancementCriterionGrantEvent.patch deleted file mode 100644 index 5e8eaca58afc..000000000000 --- a/patches/api/0085-PlayerAdvancementCriterionGrantEvent.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 19 Jan 2018 08:15:14 -0600 -Subject: [PATCH] PlayerAdvancementCriterionGrantEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bb8d7c959cdea4b66455a49e74804ea4b126620d ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerAdvancementCriterionGrantEvent.java -@@ -0,0 +1,63 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.advancement.Advancement; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player is granted a criteria in an advancement. -+ */ -+public class PlayerAdvancementCriterionGrantEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull private final Advancement advancement; -+ @NotNull private final String criterion; -+ private boolean cancel = false; -+ -+ public PlayerAdvancementCriterionGrantEvent(@NotNull Player who, @NotNull Advancement advancement, @NotNull String criterion) { -+ super(who); -+ this.advancement = advancement; -+ this.criterion = criterion; -+ } -+ -+ /** -+ * Get the advancement which has been affected. -+ * -+ * @return affected advancement -+ */ -+ @NotNull -+ public Advancement getAdvancement() { -+ return advancement; -+ } -+ -+ /** -+ * Get the criterion which has been granted. -+ * -+ * @return granted criterion -+ */ -+ @NotNull -+ public String getCriterion() { -+ return criterion; -+ } -+ -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0086-Add-ArmorStand-Item-Meta.patch b/patches/api/0086-Add-ArmorStand-Item-Meta.patch deleted file mode 100644 index 6287ef49e76f..000000000000 --- a/patches/api/0086-Add-ArmorStand-Item-Meta.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Sat, 27 Jan 2018 17:06:24 -0500 -Subject: [PATCH] Add ArmorStand Item Meta - -This is adds basic item meta for armor stands. It does not add all -possible metadata however. - -There are armor, hand, and equipment types, as well as position data -that can also be added here. This initial addition should serve a -starting point for future additions in this area. - -diff --git a/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java b/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7e4acfff16db80a75e1ff2fee1972b16955b0918 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java -@@ -0,0 +1,78 @@ -+package com.destroystokyo.paper.inventory.meta; -+ -+import org.bukkit.inventory.meta.ItemMeta; -+ -+public interface ArmorStandMeta extends ItemMeta { -+ -+ /** -+ * Gets whether the ArmorStand should be invisible when spawned -+ * -+ * @return true if this should be invisible -+ */ -+ boolean isInvisible(); -+ -+ /** -+ * Gets whether this ArmorStand should have no base plate when spawned -+ * -+ * @return true if it will not have a base plate -+ */ -+ boolean hasNoBasePlate(); -+ -+ /** -+ * Gets whether this ArmorStand should show arms when spawned -+ * -+ * @return true if it will show arms -+ */ -+ boolean shouldShowArms(); -+ -+ /** -+ * Gets whether this ArmorStand will be small when spawned -+ * -+ * @return true if it will be small -+ */ -+ boolean isSmall(); -+ -+ /** -+ * Gets whether this ArmorStand will be a marker when spawned -+ * The exact details of this flag are an implementation detail -+ * -+ * @return true if it will be a marker -+ */ -+ boolean isMarker(); -+ -+ /** -+ * Sets that this ArmorStand should be invisible when spawned -+ * -+ * @param invisible true if set invisible -+ */ -+ void setInvisible(boolean invisible); -+ -+ /** -+ * Sets that this ArmorStand should have no base plate when spawned -+ * -+ * @param noBasePlate true if no base plate -+ */ -+ void setNoBasePlate(boolean noBasePlate); -+ -+ /** -+ * Sets that this ArmorStand should show arms when spawned -+ * -+ * @param showArms true if show arms -+ */ -+ void setShowArms(boolean showArms); -+ -+ /** -+ * Sets that this ArmorStand should be small when spawned -+ * -+ * @param small true if small -+ */ -+ void setSmall(boolean small); -+ -+ /** -+ * Sets that this ArmorStand should be a marker when spawned -+ * The exact details of this flag are an implementation detail -+ * -+ * @param marker true if a marker -+ */ -+ void setMarker(boolean marker); -+} diff --git a/patches/api/0088-Tameable-getOwnerUniqueId-API.patch b/patches/api/0086-Tameable-getOwnerUniqueId-API.patch similarity index 100% rename from patches/api/0088-Tameable-getOwnerUniqueId-API.patch rename to patches/api/0086-Tameable-getOwnerUniqueId-API.patch diff --git a/patches/api/0087-Add-more-fields-to-AsyncPreLoginEvent.patch b/patches/api/0087-Add-more-fields-to-AsyncPreLoginEvent.patch new file mode 100644 index 000000000000..f853276de2a7 --- /dev/null +++ b/patches/api/0087-Add-more-fields-to-AsyncPreLoginEvent.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 18 Mar 2018 11:43:30 -0400 +Subject: [PATCH] Add more fields to AsyncPreLoginEvent + +Co-authored-by: Connor Linfoot +Co-authored-by: MCMDEV + +diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +index b2f32debd32f78e7df4851866a47da3ff0d1f015..ff5cca4a7e75274b4b278a48ae1544ff42a9836a 100644 +--- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +@@ -22,9 +22,10 @@ public class AsyncPlayerPreLoginEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private Result result; + private net.kyori.adventure.text.Component message; // Paper +- private final String name; + private final InetAddress ipAddress; +- private final UUID uniqueId; ++ private com.destroystokyo.paper.profile.PlayerProfile profile; // Paper ++ private final InetAddress rawAddress; // Paper ++ private final String hostname; // Paper + private final boolean transferred; + + @Deprecated(since = "1.7.5") +@@ -38,12 +39,30 @@ public class AsyncPlayerPreLoginEvent extends Event { + } + + public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId, boolean transferred) { ++ // Paper start ++ this(name, ipAddress, uniqueId, transferred, org.bukkit.Bukkit.createProfile(uniqueId, name)); ++ } ++ ++ @Deprecated(forRemoval = true) ++ public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile) { ++ this(name, ipAddress, ipAddress, uniqueId, transferred, profile); ++ } ++ ++ @Deprecated(forRemoval = true) ++ public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile) { ++ this(name, ipAddress, rawAddress, uniqueId, transferred, profile, ""); ++ } ++ ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile, @NotNull String hostname) { ++ // Paper end + super(true); + this.result = Result.ALLOWED; + this.message = net.kyori.adventure.text.Component.empty(); // Paper +- this.name = name; ++ this.profile = profile; + this.ipAddress = ipAddress; +- this.uniqueId = uniqueId; ++ this.rawAddress = rawAddress; // Paper ++ this.hostname = hostname; // Paper + this.transferred = transferred; + } + +@@ -207,7 +226,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + */ + @NotNull + public String getName() { +- return name; ++ return profile.getName(); // Paper + } + + /** +@@ -227,9 +246,48 @@ public class AsyncPlayerPreLoginEvent extends Event { + */ + @NotNull + public UUID getUniqueId() { +- return uniqueId; ++ return profile.getId(); // Paper ++ } ++ ++ // Paper start ++ /** ++ * Gets the PlayerProfile of the player logging in ++ * @return The Profile ++ */ ++ @NotNull ++ public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() { ++ return profile; ++ } ++ ++ /** ++ * Changes the PlayerProfile the player will login as ++ * @param profile The profile to use ++ */ ++ public void setPlayerProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile) { ++ this.profile = profile; ++ } ++ ++ /** ++ * Gets the raw address of the player logging in ++ * @return The address ++ */ ++ @NotNull ++ public InetAddress getRawAddress() { ++ return rawAddress; + } + ++ /** ++ * Gets the hostname that the player used to connect to the server, or ++ * blank if unknown ++ * ++ * @return The hostname ++ */ ++ @NotNull ++ public String getHostname() { ++ return hostname; ++ } ++ // Paper end ++ + /** + * Gets if this connection has been transferred from another server. + * diff --git a/patches/api/0087-Optimize-Hoppers.patch b/patches/api/0087-Optimize-Hoppers.patch deleted file mode 100644 index 75e6ad8e03c5..000000000000 --- a/patches/api/0087-Optimize-Hoppers.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 18 Jan 2018 01:00:27 -0500 -Subject: [PATCH] Optimize Hoppers - -Adds data about what Item related methods were used in InventoryMoveItem event -so that the server can improve the performance of this event. - -diff --git a/src/main/java/org/bukkit/event/inventory/InventoryMoveItemEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryMoveItemEvent.java -index 919cc993e3cb1c14e2a3aebf90e6cc0fa6fbc17f..95e51bcf5dfd27cc9012d7542c4ed1bceca29626 100644 ---- a/src/main/java/org/bukkit/event/inventory/InventoryMoveItemEvent.java -+++ b/src/main/java/org/bukkit/event/inventory/InventoryMoveItemEvent.java -@@ -31,6 +31,8 @@ public class InventoryMoveItemEvent extends Event implements Cancellable { - private final Inventory destinationInventory; - private ItemStack itemStack; - private final boolean didSourceInitiate; -+ public boolean calledGetItem; // Paper -+ public boolean calledSetItem; // Paper - - public InventoryMoveItemEvent(@NotNull final Inventory sourceInventory, @NotNull final ItemStack itemStack, @NotNull final Inventory destinationInventory, final boolean didSourceInitiate) { - Preconditions.checkArgument(itemStack != null, "ItemStack cannot be null"); -@@ -58,7 +60,8 @@ public class InventoryMoveItemEvent extends Event implements Cancellable { - */ - @NotNull - public ItemStack getItem() { -- return itemStack.clone(); -+ calledGetItem = true; // Paper - record this method was used for auto detection of mode -+ return itemStack; // Paper - Removed clone, handled better in Server - } - - /** -@@ -70,6 +73,7 @@ public class InventoryMoveItemEvent extends Event implements Cancellable { - */ - public void setItem(@NotNull ItemStack itemStack) { - Preconditions.checkArgument(itemStack != null, "ItemStack cannot be null. Cancel the event if you want nothing to be transferred."); -+ calledSetItem = true; // Paper - record this method was used for auto detection of mode - this.itemStack = itemStack.clone(); - } - diff --git a/patches/api/0088-Add-extended-PaperServerListPingEvent.patch b/patches/api/0088-Add-extended-PaperServerListPingEvent.patch new file mode 100644 index 000000000000..e1dce47f5b69 --- /dev/null +++ b/patches/api/0088-Add-extended-PaperServerListPingEvent.patch @@ -0,0 +1,565 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Minecrell +Date: Wed, 11 Oct 2017 15:55:38 +0200 +Subject: [PATCH] Add extended PaperServerListPingEvent + +Add a new event that extends the original ServerListPingEvent +and allows full control of the response sent to the client. + +diff --git a/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java b/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..acff2ff570f8419ffa4dfefe890795c63d75325d +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java +@@ -0,0 +1,502 @@ ++package com.destroystokyo.paper.event.server; ++ ++import static java.util.Objects.requireNonNull; ++ ++import com.destroystokyo.paper.network.StatusClient; ++import com.destroystokyo.paper.profile.PlayerProfile; ++import com.destroystokyo.paper.profile.ProfileProperty; ++import com.google.common.base.Preconditions; ++import io.papermc.paper.util.TransformingRandomAccessList; ++import java.util.Collection; ++import java.util.Map; ++import java.util.Set; ++import java.util.concurrent.CompletableFuture; ++import org.bukkit.Bukkit; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.server.ServerListPingEvent; ++import org.bukkit.profile.PlayerTextures; ++import org.bukkit.util.CachedServerIcon; ++ ++import java.util.ArrayList; ++import java.util.Iterator; ++import java.util.List; ++import java.util.NoSuchElementException; ++import java.util.UUID; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Extended version of {@link ServerListPingEvent} that allows full control ++ * of the response sent to the client. ++ */ ++public class PaperServerListPingEvent extends ServerListPingEvent implements Cancellable { ++ ++ @NotNull private final StatusClient client; ++ ++ private int numPlayers; ++ private boolean hidePlayers; ++ @NotNull private final List listedPlayers = new ArrayList<>(); ++ @NotNull private final TransformingRandomAccessList playerSample = new TransformingRandomAccessList<>( ++ listedPlayers, ++ info -> new UncheckedPlayerProfile(info.name(), info.id()), ++ profile -> new ListedPlayerInfo(profile.getName(), profile.getId()) ++ ); ++ ++ @NotNull private String version; ++ private int protocolVersion; ++ ++ @Nullable private CachedServerIcon favicon; ++ ++ private boolean cancelled; ++ ++ private boolean originalPlayerCount = true; ++ private Object[] players; ++ ++ @Deprecated ++ @ApiStatus.Internal ++ public PaperServerListPingEvent(@NotNull StatusClient client, @NotNull String motd, int numPlayers, int maxPlayers, ++ @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon) { ++ super("", client.getAddress().getAddress(), motd, numPlayers, maxPlayers); ++ this.client = client; ++ this.numPlayers = numPlayers; ++ this.version = version; ++ this.protocolVersion = protocolVersion; ++ setServerIcon(favicon); ++ } ++ ++ @ApiStatus.Internal ++ public PaperServerListPingEvent(@NotNull StatusClient client, @NotNull net.kyori.adventure.text.Component motd, int numPlayers, int maxPlayers, ++ @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon) { ++ super("", client.getAddress().getAddress(), motd, numPlayers, maxPlayers); ++ this.client = client; ++ this.numPlayers = numPlayers; ++ this.version = version; ++ this.protocolVersion = protocolVersion; ++ setServerIcon(favicon); ++ } ++ ++ /** ++ * Returns the {@link StatusClient} pinging the server. ++ * ++ * @return The client ++ */ ++ @NotNull ++ public StatusClient getClient() { ++ return this.client; ++ } ++ ++ /** ++ * {@inheritDoc} ++ * ++ *

      Returns {@code -1} if players are hidden using ++ * {@link #shouldHidePlayers()}.

      ++ */ ++ @Override ++ public int getNumPlayers() { ++ if (this.hidePlayers) { ++ return -1; ++ } ++ ++ return this.numPlayers; ++ } ++ ++ /** ++ * Sets the number of players displayed in the server list. ++ *

      ++ * Note that this won't have any effect if {@link #shouldHidePlayers()} ++ * is enabled. ++ * ++ * @param numPlayers The number of online players ++ */ ++ public void setNumPlayers(int numPlayers) { ++ if (this.numPlayers != numPlayers) { ++ this.numPlayers = numPlayers; ++ this.originalPlayerCount = false; ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * Returns {@code -1} if players are hidden using ++ * {@link #shouldHidePlayers()}. ++ */ ++ @Override ++ public int getMaxPlayers() { ++ if (this.hidePlayers) { ++ return -1; ++ } ++ ++ return super.getMaxPlayers(); ++ } ++ ++ /** ++ * Returns whether all player related information is hidden in the server ++ * list. This will cause {@link #getNumPlayers()}, {@link #getMaxPlayers()} ++ * and {@link #getPlayerSample()} to be skipped in the response. ++ *

      ++ * The Vanilla Minecraft client will display the player count as {@code ???} ++ * when this option is enabled. ++ * ++ * @return {@code true} if the player count is hidden ++ */ ++ public boolean shouldHidePlayers() { ++ return this.hidePlayers; ++ } ++ ++ /** ++ * Sets whether all player related information is hidden in the server ++ * list. This will cause {@link #getNumPlayers()}, {@link #getMaxPlayers()} ++ * and {@link #getPlayerSample()} to be skipped in the response. ++ *

      ++ * The Vanilla Minecraft client will display the player count as {@code ???} ++ * when this option is enabled. ++ * ++ * @param hidePlayers {@code true} if the player count should be hidden ++ */ ++ public void setHidePlayers(boolean hidePlayers) { ++ this.hidePlayers = hidePlayers; ++ } ++ ++ /** ++ * Returns a mutable list of {@link ListedPlayerInfo} that will be displayed ++ * as online players on the client. ++ *

      ++ * The Vanilla Minecraft client will display them when hovering the ++ * player count with the mouse. ++ * ++ * @return The mutable player sample list ++ */ ++ @NotNull ++ public List getListedPlayers() { ++ return this.listedPlayers; ++ } ++ ++ /** ++ * Returns a mutable list of {@link PlayerProfile} that will be displayed ++ * as online players on the client. ++ *

      ++ * The Vanilla Minecraft client will display them when hovering the ++ * player count with the mouse. ++ * ++ * @return The mutable player sample list ++ * @deprecated Use {@link #getListedPlayers()}, as this does not contain real player profiles ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ public List getPlayerSample() { ++ return this.playerSample; ++ } ++ ++ /** ++ * Returns the version that will be sent as server version on the client. ++ * ++ * @return The server version ++ */ ++ @NotNull ++ public String getVersion() { ++ return this.version; ++ } ++ ++ /** ++ * Sets the version that will be sent as server version to the client. ++ * ++ * @param version The server version ++ */ ++ public void setVersion(@NotNull String version) { ++ this.version = requireNonNull(version, "version"); ++ } ++ ++ /** ++ * Returns the protocol version that will be sent as the protocol version ++ * of the server to the client. ++ * ++ * @return The protocol version of the server, or {@code -1} if the server ++ * has not finished initialization yet ++ */ ++ public int getProtocolVersion() { ++ return this.protocolVersion; ++ } ++ ++ /** ++ * Sets the protocol version that will be sent as the protocol version ++ * of the server to the client. ++ * ++ * @param protocolVersion The protocol version of the server ++ */ ++ public void setProtocolVersion(int protocolVersion) { ++ this.protocolVersion = protocolVersion; ++ } ++ ++ /** ++ * Gets the server icon sent to the client. ++ * ++ * @return The icon to send to the client, or {@code null} for none ++ */ ++ @Nullable ++ public CachedServerIcon getServerIcon() { ++ return this.favicon; ++ } ++ ++ /** ++ * Sets the server icon sent to the client. ++ * ++ * @param icon The icon to send to the client, or {@code null} for none ++ */ ++ @Override ++ public void setServerIcon(@Nullable CachedServerIcon icon) { ++ if (icon != null && icon.isEmpty()) { ++ // Represent empty icons as null ++ icon = null; ++ } ++ ++ this.favicon = icon; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * Cancelling this event will cause the connection to be closed immediately, ++ * without sending a response to the client. ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * Cancelling this event will cause the connection to be closed immediately, ++ * without sending a response to the client. ++ */ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * Note: For compatibility reasons, this method will return all ++ * online players, not just the ones referenced in {@link #getPlayerSample()}. ++ * Removing a player will: ++ * ++ *

        ++ *
      • Decrement the online player count (if and only if) the player ++ * count wasn't changed by another plugin before.
      • ++ *
      • Remove all entries from {@link #getPlayerSample()} that refer to ++ * the removed player (based on their {@link UUID}).
      • ++ *
      ++ * @deprecated the Iterable interface will be removed at some point ++ */ ++ @NotNull ++ @Override ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ public Iterator iterator() { ++ if (this.players == null) { ++ this.players = getOnlinePlayers(); ++ } ++ ++ return new PlayerIterator(); ++ } ++ ++ @NotNull ++ protected Object[] getOnlinePlayers() { ++ return Bukkit.getOnlinePlayers().toArray(); ++ } ++ ++ @NotNull ++ protected Player getBukkitPlayer(@NotNull Object player) { ++ return (Player) player; ++ } ++ ++ @ApiStatus.Internal ++ private final class PlayerIterator implements Iterator { ++ ++ private int next; ++ private int current; ++ @Nullable private Player player; ++ ++ @Override ++ public boolean hasNext() { ++ for (; this.next < players.length; this.next++) { ++ if (players[this.next] != null) { ++ return true; ++ } ++ } ++ ++ return false; ++ } ++ ++ @NotNull ++ @Override ++ public Player next() { ++ if (!hasNext()) { ++ this.player = null; ++ throw new NoSuchElementException(); ++ } ++ ++ this.current = this.next++; ++ return this.player = getBukkitPlayer(players[this.current]); ++ } ++ ++ @Override ++ public void remove() { ++ if (this.player == null) { ++ throw new IllegalStateException(); ++ } ++ ++ UUID uniqueId = this.player.getUniqueId(); ++ this.player = null; ++ ++ // Remove player from iterator ++ players[this.current] = null; ++ ++ // Remove player from sample ++ getPlayerSample().removeIf(p -> uniqueId.equals(p.getId())); ++ ++ // Decrement player count ++ if (originalPlayerCount) { ++ numPlayers--; ++ } ++ } ++ } ++ ++ /** ++ * Represents a player that will be displayed in the player sample of the server list. ++ * ++ * @param name name of the listed player ++ * @param id UUID of the listed player ++ */ ++ public record ListedPlayerInfo(@NotNull String name, @NotNull UUID id) { ++ } ++ ++ @ApiStatus.Internal ++ private static final class UncheckedPlayerProfile implements PlayerProfile { ++ private String name; ++ private UUID uuid; ++ ++ public UncheckedPlayerProfile(final @NotNull String name, final @NotNull UUID uuid) { ++ Preconditions.checkNotNull(name, "name cannot be null"); ++ Preconditions.checkNotNull(uuid, "uuid cannot be null"); ++ this.name = name; ++ this.uuid = uuid; ++ } ++ ++ @Override ++ public @Nullable UUID getUniqueId() { ++ return uuid; ++ } ++ ++ @Override ++ public @Nullable String getName() { ++ return name; ++ } ++ ++ @Override ++ public @NotNull String setName(@Nullable final String name) { ++ Preconditions.checkNotNull(name, "name cannot be null"); ++ return this.name = name; ++ } ++ ++ @Override ++ public @Nullable UUID getId() { ++ return uuid; ++ } ++ ++ @Override ++ public @Nullable UUID setId(@Nullable final UUID uuid) { ++ Preconditions.checkNotNull(uuid, "uuid cannot be null"); ++ return this.uuid = uuid; ++ } ++ ++ @Override ++ public @NotNull PlayerTextures getTextures() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public void setTextures(@Nullable final PlayerTextures textures) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull Set getProperties() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean hasProperty(@Nullable final String property) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public void setProperty(@NotNull final ProfileProperty property) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public void setProperties(@NotNull final Collection properties) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean removeProperty(@Nullable final String property) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public void clearProperties() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean isComplete() { ++ return false; ++ } ++ ++ @Override ++ public boolean completeFromCache() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean completeFromCache(final boolean onlineMode) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean completeFromCache(final boolean lookupUUID, final boolean onlineMode) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean complete(final boolean textures) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public boolean complete(final boolean textures, final boolean onlineMode) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull CompletableFuture update() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public org.bukkit.profile.@NotNull PlayerProfile clone() { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull Map serialize() { ++ throw new UnsupportedOperationException(); ++ } ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/network/StatusClient.java b/src/main/java/com/destroystokyo/paper/network/StatusClient.java +new file mode 100644 +index 0000000000000000000000000000000000000000..517d15238ed117f38bbd39f570874014cecf7bb5 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/network/StatusClient.java +@@ -0,0 +1,13 @@ ++package com.destroystokyo.paper.network; ++ ++import com.destroystokyo.paper.event.server.PaperServerListPingEvent; ++ ++/** ++ * Represents a client requesting the current status from the server (e.g. from ++ * the server list). ++ * ++ * @see PaperServerListPingEvent ++ */ ++public interface StatusClient extends NetworkClient { ++ ++} +diff --git a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java +index 1cc5a0abce39c939398ce945dd916dc086888b13..e11b81e711093b1851449c0532bc5103abb1b81c 100644 +--- a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java ++++ b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java +@@ -248,9 +248,11 @@ public class ServerListPingEvent extends ServerEvent implements Iterable + * + * @throws UnsupportedOperationException if the caller of this event does + * not support removing players ++ * @deprecated the Iterable interface will be removed at some point + */ + @NotNull + @Override ++ @Deprecated(forRemoval = true, since = "1.20.6") + public Iterator iterator() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } +diff --git a/src/main/java/org/bukkit/util/CachedServerIcon.java b/src/main/java/org/bukkit/util/CachedServerIcon.java +index 9a7768d41270714d4a1c89b4dcb436cc66f57545..b74b21a1ac7798e847b6d34ff45026e1c9cfed14 100644 +--- a/src/main/java/org/bukkit/util/CachedServerIcon.java ++++ b/src/main/java/org/bukkit/util/CachedServerIcon.java +@@ -18,4 +18,9 @@ public interface CachedServerIcon { + @Nullable + public String getData(); // Paper + ++ // Paper start ++ default boolean isEmpty() { ++ return getData() == null; ++ } ++ // Paper end + } diff --git a/patches/api/0089-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch b/patches/api/0089-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch deleted file mode 100644 index 178267a089c6..000000000000 --- a/patches/api/0089-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 18 Mar 2018 11:43:30 -0400 -Subject: [PATCH] Ability to change PlayerProfile in AsyncPreLoginEvent - -This will allow you to change the players name or skin on login. - -diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -index c7c45e2de8cca1bf8b8e12752e08db62403efa6a..c30b44ff26f8f253902754452a0816f07c7fd035 100644 ---- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -+++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -@@ -2,6 +2,9 @@ package org.bukkit.event.player; - - import java.net.InetAddress; - import java.util.UUID; -+ -+import com.destroystokyo.paper.profile.PlayerProfile; -+import org.bukkit.Bukkit; - import org.bukkit.event.Event; - import org.bukkit.event.HandlerList; - import org.jetbrains.annotations.NotNull; -@@ -15,9 +18,9 @@ public class AsyncPlayerPreLoginEvent extends Event { - private static final HandlerList handlers = new HandlerList(); - private Result result; - private net.kyori.adventure.text.Component message; // Paper -- private final String name; -+ //private String name; // Paper - Not used anymore - private final InetAddress ipAddress; -- private final UUID uniqueId; -+ //private UUID uniqueId; // Paper - Not used anymore - - @Deprecated - public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress) { -@@ -25,12 +28,37 @@ public class AsyncPlayerPreLoginEvent extends Event { - } - - public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId) { -+ // Paper start -+ this(name, ipAddress, uniqueId, Bukkit.createProfile(uniqueId, name)); -+ } -+ private PlayerProfile profile; -+ -+ /** -+ * Gets the PlayerProfile of the player logging in -+ * @return The Profile -+ */ -+ @NotNull -+ public PlayerProfile getPlayerProfile() { -+ return profile; -+ } -+ -+ /** -+ * Changes the PlayerProfile the player will login as -+ * @param profile The profile to use -+ */ -+ public void setPlayerProfile(@NotNull PlayerProfile profile) { -+ this.profile = profile; -+ } -+ -+ public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId, @NotNull PlayerProfile profile) { - super(true); -+ this.profile = profile; -+ // Paper end - this.result = Result.ALLOWED; - this.message = net.kyori.adventure.text.Component.empty(); // Paper -- this.name = name; -+ //this.name = name; // Paper - Not used anymore - this.ipAddress = ipAddress; -- this.uniqueId = uniqueId; -+ //this.uniqueId = uniqueId; // Paper - Not used anymore - } - - /** -@@ -193,7 +221,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - */ - @NotNull - public String getName() { -- return name; -+ return profile.getName(); // Paper - } - - /** -@@ -213,7 +241,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - */ - @NotNull - public UUID getUniqueId() { -- return uniqueId; -+ return profile.getId(); // Paper - } - - @NotNull diff --git a/patches/api/0089-Player.setPlayerProfile-API.patch b/patches/api/0089-Player.setPlayerProfile-API.patch new file mode 100644 index 000000000000..e24c398eea1c --- /dev/null +++ b/patches/api/0089-Player.setPlayerProfile-API.patch @@ -0,0 +1,147 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 18 Mar 2018 12:28:55 -0400 +Subject: [PATCH] Player.setPlayerProfile API + +This can be useful for changing name or skins after a player has logged in. + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index c351fb49a8d044312ca77f5cd85d939a95bdae20..c50b69ace8c7e92d0bb141b301c541ec1e382324 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -1380,8 +1380,10 @@ public final class Bukkit { + * @return the new PlayerProfile + * @throws IllegalArgumentException if both the unique id is + * null and the name is null or blank ++ * @deprecated use {@link #createProfile(UUID, String)} + */ + @NotNull ++ @Deprecated(since = "1.18.1") // Paper + public static PlayerProfile createPlayerProfile(@Nullable UUID uniqueId, @Nullable String name) { + return server.createPlayerProfile(uniqueId, name); + } +@@ -1392,8 +1394,10 @@ public final class Bukkit { + * @param uniqueId the unique id + * @return the new PlayerProfile + * @throws IllegalArgumentException if the unique id is null ++ * @deprecated use {@link #createProfile(UUID)} + */ + @NotNull ++ @Deprecated(since = "1.18.1") // Paper + public static PlayerProfile createPlayerProfile(@NotNull UUID uniqueId) { + return server.createPlayerProfile(uniqueId); + } +@@ -1405,8 +1409,10 @@ public final class Bukkit { + * @return the new PlayerProfile + * @throws IllegalArgumentException if the name is null or + * blank ++ * @deprecated use {@link #createProfile(String)} + */ + @NotNull ++ @Deprecated(since = "1.18.1") // Paper + public static PlayerProfile createPlayerProfile(@NotNull String name) { + return server.createPlayerProfile(name); + } +diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java +index 9f599e44c9519d8eaaedf2a11cce1637b0f23aec..2f404c6cefbbd842932620aa62750b343e90e41c 100644 +--- a/src/main/java/org/bukkit/OfflinePlayer.java ++++ b/src/main/java/org/bukkit/OfflinePlayer.java +@@ -59,7 +59,7 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio + * @return the player's profile + */ + @NotNull +- PlayerProfile getPlayerProfile(); ++ com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile(); // Paper + + /** + * Checks if this player has had their profile banned. +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 51bed70fdc7221f41035e13af1fba69b492507ac..4c10cc9524c3001777c520a32c498108449980fb 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1167,8 +1167,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @return the new PlayerProfile + * @throws IllegalArgumentException if both the unique id is + * null and the name is null or blank ++ * @deprecated use {@link #createProfile(UUID, String)} + */ + @NotNull ++ @Deprecated(since = "1.18.1") // Paper + PlayerProfile createPlayerProfile(@Nullable UUID uniqueId, @Nullable String name); + + /** +@@ -1177,8 +1179,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @param uniqueId the unique id + * @return the new PlayerProfile + * @throws IllegalArgumentException if the unique id is null ++ * @deprecated use {@link #createProfile(UUID)} + */ + @NotNull ++ @Deprecated(since = "1.18.1") // Paper + PlayerProfile createPlayerProfile(@NotNull UUID uniqueId); + + /** +@@ -1188,8 +1192,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @return the new PlayerProfile + * @throws IllegalArgumentException if the name is null or + * blank ++ * @deprecated use {@link #createProfile(String)} + */ + @NotNull ++ @Deprecated(since = "1.18.1") // Paper + PlayerProfile createPlayerProfile(@NotNull String name); + + /** +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index fcb83800bc4cbaa96e5f190e0cf618542d8bb637..3611ef03abe9c81cfb956c9957c57e7df05faf32 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3154,6 +3154,26 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + } + // Paper end + ++ // Paper start - Player Profile API ++ /** ++ * Gets a copy of this players profile ++ * ++ * @return The players profile object ++ */ ++ com.destroystokyo.paper.profile.@NotNull PlayerProfile getPlayerProfile(); ++ ++ /** ++ * Changes the PlayerProfile for this player. This will cause this player ++ * to be re-registered to all clients that can currently see this player. ++ *

      ++ * After executing this method, the player {@link java.util.UUID} won't ++ * be swapped, only their name and profile properties. ++ * ++ * @param profile The new profile to use ++ */ ++ void setPlayerProfile(com.destroystokyo.paper.profile.@NotNull PlayerProfile profile); ++ // Paper end - Player Profile API ++ + // Spigot start + public class Spigot extends Entity.Spigot { + +diff --git a/src/main/java/org/bukkit/profile/PlayerProfile.java b/src/main/java/org/bukkit/profile/PlayerProfile.java +index fc46add38bf59dc1a04ea566fd230dcd8ae2708c..f4ab961647826b8717466be0d8c202b12749e9b4 100644 +--- a/src/main/java/org/bukkit/profile/PlayerProfile.java ++++ b/src/main/java/org/bukkit/profile/PlayerProfile.java +@@ -16,7 +16,9 @@ import org.jetbrains.annotations.Nullable; + *

      + * New profiles can be created via + * {@link Server#createPlayerProfile(UUID, String)}. ++ * @deprecated see {@link com.destroystokyo.paper.profile.PlayerProfile} + */ ++@Deprecated(since = "1.18.1") // Paper + public interface PlayerProfile extends Cloneable, ConfigurationSerializable { + + /** +@@ -25,6 +27,7 @@ public interface PlayerProfile extends Cloneable, ConfigurationSerializable { + * @return the player's unique id, or null if not available + */ + @Nullable ++ @Deprecated(since = "1.18.1") // Paper + UUID getUniqueId(); + + /** diff --git a/patches/api/0090-Add-extended-PaperServerListPingEvent.patch b/patches/api/0090-Add-extended-PaperServerListPingEvent.patch deleted file mode 100644 index 7c18476a847d..000000000000 --- a/patches/api/0090-Add-extended-PaperServerListPingEvent.patch +++ /dev/null @@ -1,381 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Minecrell -Date: Wed, 11 Oct 2017 15:55:38 +0200 -Subject: [PATCH] Add extended PaperServerListPingEvent - -Add a new event that extends the original ServerListPingEvent -and allows full control of the response sent to the client. - -diff --git a/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java b/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5bacbd0df66953d3c8fdfde5af1338a74339cfda ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java -@@ -0,0 +1,334 @@ -+package com.destroystokyo.paper.event.server; -+ -+import static java.util.Objects.requireNonNull; -+ -+import com.destroystokyo.paper.network.StatusClient; -+import com.destroystokyo.paper.profile.PlayerProfile; -+import org.bukkit.Bukkit; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.server.ServerListPingEvent; -+import org.bukkit.util.CachedServerIcon; -+ -+import java.util.ArrayList; -+import java.util.Iterator; -+import java.util.List; -+import java.util.NoSuchElementException; -+import java.util.UUID; -+ -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Extended version of {@link ServerListPingEvent} that allows full control -+ * of the response sent to the client. -+ */ -+public class PaperServerListPingEvent extends ServerListPingEvent implements Cancellable { -+ -+ @NotNull private final StatusClient client; -+ -+ private int numPlayers; -+ private boolean hidePlayers; -+ @NotNull private final List playerSample = new ArrayList<>(); -+ -+ @NotNull private String version; -+ private int protocolVersion; -+ -+ @Nullable private CachedServerIcon favicon; -+ -+ private boolean cancelled; -+ -+ private boolean originalPlayerCount = true; -+ private Object[] players; -+ -+ @Deprecated -+ public PaperServerListPingEvent(@NotNull StatusClient client, @NotNull String motd, boolean shouldSendChatPreviews, int numPlayers, int maxPlayers, -+ @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon) { -+ super(client.getAddress().getAddress(), motd, shouldSendChatPreviews, numPlayers, maxPlayers); -+ this.client = client; -+ this.numPlayers = numPlayers; -+ this.version = version; -+ this.protocolVersion = protocolVersion; -+ setServerIcon(favicon); -+ } -+ -+ public PaperServerListPingEvent(@NotNull StatusClient client, @NotNull net.kyori.adventure.text.Component motd, boolean shouldSendChatPreviews, int numPlayers, int maxPlayers, -+ @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon) { -+ super(client.getAddress().getAddress(), motd, shouldSendChatPreviews, numPlayers, maxPlayers); -+ this.client = client; -+ this.numPlayers = numPlayers; -+ this.version = version; -+ this.protocolVersion = protocolVersion; -+ setServerIcon(favicon); -+ } -+ -+ /** -+ * Returns the {@link StatusClient} pinging the server. -+ * -+ * @return The client -+ */ -+ @NotNull -+ public StatusClient getClient() { -+ return this.client; -+ } -+ -+ /** -+ * {@inheritDoc} -+ * -+ *

      Returns {@code -1} if players are hidden using -+ * {@link #shouldHidePlayers()}.

      -+ */ -+ @Override -+ public int getNumPlayers() { -+ if (this.hidePlayers) { -+ return -1; -+ } -+ -+ return this.numPlayers; -+ } -+ -+ /** -+ * Sets the number of players displayed in the server list. -+ * -+ *

      Note that this won't have any effect if {@link #shouldHidePlayers()} -+ * is enabled.

      -+ * -+ * @param numPlayers The number of online players -+ */ -+ public void setNumPlayers(int numPlayers) { -+ if (this.numPlayers != numPlayers) { -+ this.numPlayers = numPlayers; -+ this.originalPlayerCount = false; -+ } -+ } -+ -+ /** -+ * {@inheritDoc} -+ * -+ *

      Returns {@code -1} if players are hidden using -+ * {@link #shouldHidePlayers()}.

      -+ */ -+ @Override -+ public int getMaxPlayers() { -+ if (this.hidePlayers) { -+ return -1; -+ } -+ -+ return super.getMaxPlayers(); -+ } -+ -+ /** -+ * Returns whether all player related information is hidden in the server -+ * list. This will cause {@link #getNumPlayers()}, {@link #getMaxPlayers()} -+ * and {@link #getPlayerSample()} to be skipped in the response. -+ * -+ *

      The Vanilla Minecraft client will display the player count as {@code ???} -+ * when this option is enabled.

      -+ * -+ * @return {@code true} if the player count is hidden -+ */ -+ public boolean shouldHidePlayers() { -+ return hidePlayers; -+ } -+ -+ /** -+ * Sets whether all player related information is hidden in the server -+ * list. This will cause {@link #getNumPlayers()}, {@link #getMaxPlayers()} -+ * and {@link #getPlayerSample()} to be skipped in the response. -+ * -+ *

      The Vanilla Minecraft client will display the player count as {@code ???} -+ * when this option is enabled.

      -+ * -+ * @param hidePlayers {@code true} if the player count should be hidden -+ */ -+ public void setHidePlayers(boolean hidePlayers) { -+ this.hidePlayers = hidePlayers; -+ } -+ -+ /** -+ * Returns a mutable list of {@link PlayerProfile} that will be displayed -+ * as online players on the client. -+ * -+ *

      The Vanilla Minecraft client will display them when hovering the -+ * player count with the mouse.

      -+ * -+ * @return The mutable player sample list -+ */ -+ @NotNull -+ public List getPlayerSample() { -+ return this.playerSample; -+ } -+ -+ /** -+ * Returns the version that will be sent as server version on the client. -+ * -+ * @return The server version -+ */ -+ @NotNull -+ public String getVersion() { -+ return version; -+ } -+ -+ /** -+ * Sets the version that will be sent as server version to the client. -+ * -+ * @param version The server version -+ */ -+ public void setVersion(@NotNull String version) { -+ this.version = requireNonNull(version, "version"); -+ } -+ -+ /** -+ * Returns the protocol version that will be sent as the protocol version -+ * of the server to the client. -+ * -+ * @return The protocol version of the server, or {@code -1} if the server -+ * has not finished initialization yet -+ */ -+ public int getProtocolVersion() { -+ return protocolVersion; -+ } -+ -+ /** -+ * Sets the protocol version that will be sent as the protocol version -+ * of the server to the client. -+ * -+ * @param protocolVersion The protocol version of the server -+ */ -+ public void setProtocolVersion(int protocolVersion) { -+ this.protocolVersion = protocolVersion; -+ } -+ -+ /** -+ * Gets the server icon sent to the client. -+ * -+ * @return The icon to send to the client, or {@code null} for none -+ */ -+ @Nullable -+ public CachedServerIcon getServerIcon() { -+ return this.favicon; -+ } -+ -+ /** -+ * Sets the server icon sent to the client. -+ * -+ * @param icon The icon to send to the client, or {@code null} for none -+ */ -+ @Override -+ public void setServerIcon(@Nullable CachedServerIcon icon) { -+ if (icon != null && icon.isEmpty()) { -+ // Represent empty icons as null -+ icon = null; -+ } -+ -+ this.favicon = icon; -+ } -+ -+ /** -+ * {@inheritDoc} -+ * -+ *

      Cancelling this event will cause the connection to be closed immediately, -+ * without sending a response to the client.

      -+ */ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ /** -+ * {@inheritDoc} -+ * -+ *

      Cancelling this event will cause the connection to be closed immediately, -+ * without sending a response to the client.

      -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ /** -+ * {@inheritDoc} -+ * -+ *

      Note: For compatibility reasons, this method will return all -+ * online players, not just the ones referenced in {@link #getPlayerSample()}. -+ * Removing a player will:

      -+ * -+ *
        -+ *
      • Decrement the online player count (if and only if) the player -+ * count wasn't changed by another plugin before.
      • -+ *
      • Remove all entries from {@link #getPlayerSample()} that refer to -+ * the removed player (based on their {@link UUID}).
      • -+ *
      -+ */ -+ @NotNull -+ @Override -+ public Iterator iterator() { -+ if (this.players == null) { -+ this.players = getOnlinePlayers(); -+ } -+ -+ return new PlayerIterator(); -+ } -+ -+ @NotNull -+ protected Object[] getOnlinePlayers() { -+ return Bukkit.getOnlinePlayers().toArray(); -+ } -+ -+ @NotNull -+ protected Player getBukkitPlayer(@NotNull Object player) { -+ return (Player) player; -+ } -+ -+ private final class PlayerIterator implements Iterator { -+ -+ private int next; -+ private int current; -+ @Nullable private Player player; -+ -+ @Override -+ public boolean hasNext() { -+ for (; this.next < players.length; this.next++) { -+ if (players[this.next] != null) { -+ return true; -+ } -+ } -+ -+ return false; -+ } -+ -+ @NotNull -+ @Override -+ public Player next() { -+ if (!hasNext()) { -+ this.player = null; -+ throw new NoSuchElementException(); -+ } -+ -+ this.current = this.next++; -+ return this.player = getBukkitPlayer(players[this.current]); -+ } -+ -+ @Override -+ public void remove() { -+ if (this.player == null) { -+ throw new IllegalStateException(); -+ } -+ -+ UUID uniqueId = this.player.getUniqueId(); -+ this.player = null; -+ -+ // Remove player from iterator -+ players[this.current] = null; -+ -+ // Remove player from sample -+ getPlayerSample().removeIf(p -> uniqueId.equals(p.getId())); -+ -+ // Decrement player count -+ if (originalPlayerCount) { -+ numPlayers--; -+ } -+ } -+ } -+ -+} -diff --git a/src/main/java/com/destroystokyo/paper/network/StatusClient.java b/src/main/java/com/destroystokyo/paper/network/StatusClient.java -new file mode 100644 -index 0000000000000000000000000000000000000000..517d15238ed117f38bbd39f570874014cecf7bb5 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/network/StatusClient.java -@@ -0,0 +1,13 @@ -+package com.destroystokyo.paper.network; -+ -+import com.destroystokyo.paper.event.server.PaperServerListPingEvent; -+ -+/** -+ * Represents a client requesting the current status from the server (e.g. from -+ * the server list). -+ * -+ * @see PaperServerListPingEvent -+ */ -+public interface StatusClient extends NetworkClient { -+ -+} -diff --git a/src/main/java/org/bukkit/util/CachedServerIcon.java b/src/main/java/org/bukkit/util/CachedServerIcon.java -index 612958a331575d1da2715531ebdf6b1168f2e860..bb4f7702ced0baf0670a7a21d48ad528b7249361 100644 ---- a/src/main/java/org/bukkit/util/CachedServerIcon.java -+++ b/src/main/java/org/bukkit/util/CachedServerIcon.java -@@ -18,4 +18,9 @@ public interface CachedServerIcon { - @Nullable - public String getData(); // Paper - -+ // Paper start -+ default boolean isEmpty() { -+ return getData() == null; -+ } -+ // Paper end - } diff --git a/patches/api/0090-getPlayerUniqueId-API.patch b/patches/api/0090-getPlayerUniqueId-API.patch new file mode 100644 index 000000000000..18e98ba4927b --- /dev/null +++ b/patches/api/0090-getPlayerUniqueId-API.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 22 Mar 2018 01:39:28 -0400 +Subject: [PATCH] getPlayerUniqueId API + +Gets the unique ID of the player currently known as the specified player name +In Offline Mode, will return an Offline UUID + +This is a more performant way to obtain a UUID for a name than loading an OfflinePlayer + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index c50b69ace8c7e92d0bb141b301c541ec1e382324..4cdbcb96b358bc678255ae3852cef047a2df2457 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -753,6 +753,20 @@ public final class Bukkit { + return server.getPlayer(id); + } + ++ // Paper start ++ /** ++ * Gets the unique ID of the player currently known as the specified player name ++ * In Offline Mode, will return an Offline UUID ++ * ++ * @param playerName the player name to look up the unique ID for ++ * @return A UUID, or null if that player name is not registered with Minecraft and the server is in online mode ++ */ ++ @Nullable ++ public static UUID getPlayerUniqueId(@NotNull String playerName) { ++ return server.getPlayerUniqueId(playerName); ++ } ++ // Paper end ++ + /** + * Gets the plugin manager for interfacing with plugins. + * +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 4c10cc9524c3001777c520a32c498108449980fb..957bc4c3e4c1eb6a4d89b5e559f95b604ecf59c4 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -633,6 +633,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @Nullable + public Player getPlayer(@NotNull UUID id); + ++ // Paper start ++ /** ++ * Gets the unique ID of the player currently known as the specified player name ++ * In Offline Mode, will return an Offline UUID ++ * ++ * @param playerName the player name to look up the unique ID for ++ * @return A UUID, or null if that player name is not registered with Minecraft and the server is in online mode ++ */ ++ @Nullable ++ public UUID getPlayerUniqueId(@NotNull String playerName); ++ // Paper end ++ + /** + * Gets the plugin manager for interfacing with plugins. + * diff --git a/patches/api/0091-Add-legacy-ping-support-to-PaperServerListPingEvent.patch b/patches/api/0091-Add-legacy-ping-support-to-PaperServerListPingEvent.patch new file mode 100644 index 000000000000..96ed5420a29f --- /dev/null +++ b/patches/api/0091-Add-legacy-ping-support-to-PaperServerListPingEvent.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Minecrell +Date: Wed, 11 Oct 2017 19:30:20 +0200 +Subject: [PATCH] Add legacy ping support to PaperServerListPingEvent + +Add a new method to StatusClient check if the client is a legacy +client that does not support all of the features provided in the +event. + +diff --git a/src/main/java/com/destroystokyo/paper/network/StatusClient.java b/src/main/java/com/destroystokyo/paper/network/StatusClient.java +index 517d15238ed117f38bbd39f570874014cecf7bb5..a8437bbd80b3a20772352a3b1797990ea13806ad 100644 +--- a/src/main/java/com/destroystokyo/paper/network/StatusClient.java ++++ b/src/main/java/com/destroystokyo/paper/network/StatusClient.java +@@ -10,4 +10,16 @@ import com.destroystokyo.paper.event.server.PaperServerListPingEvent; + */ + public interface StatusClient extends NetworkClient { + ++ /** ++ * Returns whether the client is using an older version that doesn't ++ * support all the features in {@link PaperServerListPingEvent}. ++ * ++ *

      For Vanilla, this returns {@code true} for all clients older than 1.7.

      ++ * ++ * @return {@code true} if the client is using legacy ping ++ */ ++ default boolean isLegacy() { ++ return false; ++ } ++ + } diff --git a/patches/api/0091-Player.setPlayerProfile-API.patch b/patches/api/0091-Player.setPlayerProfile-API.patch deleted file mode 100644 index cd273731b2ca..000000000000 --- a/patches/api/0091-Player.setPlayerProfile-API.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 18 Mar 2018 12:28:55 -0400 -Subject: [PATCH] Player.setPlayerProfile API - -This can be useful for changing name or skins after a player has logged in. - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index be46b7aa492226d2c943b9a15f0e009878be422c..edbe7363b2da4f89cc31cbf9521c9a6271060ccd 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -1196,8 +1196,10 @@ public final class Bukkit { - * @return the new PlayerProfile - * @throws IllegalArgumentException if both the unique id is - * null and the name is null or blank -+ * @deprecated use {@link #createProfile(UUID, String)} - */ - @NotNull -+ @Deprecated // Paper - public static PlayerProfile createPlayerProfile(@Nullable UUID uniqueId, @Nullable String name) { - return server.createPlayerProfile(uniqueId, name); - } -@@ -1208,8 +1210,10 @@ public final class Bukkit { - * @param uniqueId the unique id - * @return the new PlayerProfile - * @throws IllegalArgumentException if the unique id is null -+ * @deprecated use {@link #createProfile(UUID)} - */ - @NotNull -+ @Deprecated // Paper - public static PlayerProfile createPlayerProfile(@NotNull UUID uniqueId) { - return server.createPlayerProfile(uniqueId); - } -@@ -1221,8 +1225,10 @@ public final class Bukkit { - * @return the new PlayerProfile - * @throws IllegalArgumentException if the name is null or - * blank -+ * @deprecated use {@link #createProfile(String)} - */ - @NotNull -+ @Deprecated // Paper - public static PlayerProfile createPlayerProfile(@NotNull String name) { - return server.createPlayerProfile(name); - } -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 04752eebe9df1138207a969fb1492a1f55b0b753..ca784abeb7f31c65e87df7750ae19aa9a8b65d72 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1014,8 +1014,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * @return the new PlayerProfile - * @throws IllegalArgumentException if both the unique id is - * null and the name is null or blank -+ * @deprecated use {@link #createProfile(UUID, String)} - */ - @NotNull -+ @Deprecated // Paper - PlayerProfile createPlayerProfile(@Nullable UUID uniqueId, @Nullable String name); - - /** -@@ -1024,8 +1026,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * @param uniqueId the unique id - * @return the new PlayerProfile - * @throws IllegalArgumentException if the unique id is null -+ * @deprecated use {@link #createProfile(UUID)} - */ - @NotNull -+ @Deprecated // Paper - PlayerProfile createPlayerProfile(@NotNull UUID uniqueId); - - /** -@@ -1035,8 +1039,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * @return the new PlayerProfile - * @throws IllegalArgumentException if the name is null or - * blank -+ * @deprecated use {@link #createProfile(String)} - */ - @NotNull -+ @Deprecated - PlayerProfile createPlayerProfile(@NotNull String name); - - /** -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index dc8740d5410aebaa17e014d43b7d9fb29ae2a3d0..6768ab96fa14d3e297c37fb899943b9f3fd0cc1d 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -2291,6 +2291,20 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * was {@link org.bukkit.event.player.PlayerResourcePackStatusEvent.Status#SUCCESSFULLY_LOADED} - */ - boolean hasResourcePack(); -+ -+ /** -+ * Gets a copy of this players profile -+ * @return The players profile object -+ */ -+ @NotNull -+ com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile(); -+ -+ /** -+ * Changes the PlayerProfile for this player. This will cause this player -+ * to be reregistered to all clients that can currently see this player -+ * @param profile The new profile to use -+ */ -+ void setPlayerProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile); - // Paper end - - // Spigot start -diff --git a/src/main/java/org/bukkit/profile/PlayerProfile.java b/src/main/java/org/bukkit/profile/PlayerProfile.java -index 16ae1282f3178e8873483a25a5d5cce16b2c21a9..c4aa20fbb0865a0b43ece475ee115ad6a7c65a48 100644 ---- a/src/main/java/org/bukkit/profile/PlayerProfile.java -+++ b/src/main/java/org/bukkit/profile/PlayerProfile.java -@@ -16,7 +16,9 @@ import org.jetbrains.annotations.Nullable; - *

      - * New profiles can be created via - * {@link Server#createPlayerProfile(UUID, String)}. -+ * @deprecated see {@link com.destroystokyo.paper.profile.PlayerProfile} - */ -+@Deprecated // Paper - public interface PlayerProfile extends Cloneable, ConfigurationSerializable { - - /** -@@ -25,6 +27,7 @@ public interface PlayerProfile extends Cloneable, ConfigurationSerializable { - * @return the player's unique id, or null if not available - */ - @Nullable -+ @Deprecated // Paper - UUID getUniqueId(); - - /** diff --git a/patches/api/0092-Add-openSign-method-to-HumanEntity.patch b/patches/api/0092-Add-openSign-method-to-HumanEntity.patch new file mode 100644 index 000000000000..8824804e016e --- /dev/null +++ b/patches/api/0092-Add-openSign-method-to-HumanEntity.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Vainomaa +Date: Sun, 1 Apr 2018 02:28:43 +0300 +Subject: [PATCH] Add openSign method to HumanEntity + + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index b4452d18a530c4c4a9bc10f368aeced9430b42a2..35d72d8ab78ca4095545fab54d6b440c040223eb 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -538,6 +538,26 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder + */ + @Deprecated(since = "1.12") + public void setShoulderEntityRight(@Nullable Entity entity); ++ // Paper start - Add method to open already placed sign ++ /** ++ * Opens an editor window for the specified sign ++ * ++ * @param sign The sign to open ++ * @deprecated use {@link #openSign(org.bukkit.block.Sign, org.bukkit.block.sign.Side)} ++ */ ++ @Deprecated ++ default void openSign(@NotNull org.bukkit.block.Sign sign) { ++ this.openSign(sign, org.bukkit.block.sign.Side.FRONT); ++ } ++ ++ /** ++ * Opens an editor window for the specified sign ++ * ++ * @param sign The sign to open ++ * @param side The side of the sign to open ++ */ ++ void openSign(org.bukkit.block.@NotNull Sign sign, org.bukkit.block.sign.@NotNull Side side); ++ // Paper end + + /** + * Make the entity drop the item in their hand. +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 3611ef03abe9c81cfb956c9957c57e7df05faf32..949b34e9c9f8b4be48c09f80d78d9453f0ff0ee3 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3115,10 +3115,12 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + /** + * Open a Sign for editing by the Player. + * +- * The Sign must be placed in the same world as the player. ++ * The Sign must be in the same world as the player. + * + * @param sign The sign to edit ++ * @deprecated use {@link #openSign(Sign, Side)} + */ ++ @Deprecated + public void openSign(@NotNull Sign sign); + + /** diff --git a/patches/api/0092-getPlayerUniqueId-API.patch b/patches/api/0092-getPlayerUniqueId-API.patch deleted file mode 100644 index 1731d9e28202..000000000000 --- a/patches/api/0092-getPlayerUniqueId-API.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 22 Mar 2018 01:39:28 -0400 -Subject: [PATCH] getPlayerUniqueId API - -Gets the unique ID of the player currently known as the specified player name -In Offline Mode, will return an Offline UUID - -This is a more performant way to obtain a UUID for a name than loading an OfflinePlayer - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 39f97dac6af70b45101a7de776009c4fa3874868..098a09baa481f76e63991268d3dfabc413626fcf 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -656,6 +656,20 @@ public final class Bukkit { - return server.getPlayer(id); - } - -+ // Paper start -+ /** -+ * Gets the unique ID of the player currently known as the specified player name -+ * In Offline Mode, will return an Offline UUID -+ * -+ * @param playerName the player name to look up the unique ID for -+ * @return A UUID, or null if that player name is not registered with Minecraft and the server is in online mode -+ */ -+ @Nullable -+ public static UUID getPlayerUniqueId(@NotNull String playerName) { -+ return server.getPlayerUniqueId(playerName); -+ } -+ // Paper end -+ - /** - * Gets the plugin manager for interfacing with plugins. - * -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 4597c9b2e4691495b54333711141b83926af193d..2042f4963c53d5a903f0de1fec6a9af3a7b2bba4 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -558,6 +558,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - @Nullable - public Player getPlayer(@NotNull UUID id); - -+ // Paper start -+ /** -+ * Gets the unique ID of the player currently known as the specified player name -+ * In Offline Mode, will return an Offline UUID -+ * -+ * @param playerName the player name to look up the unique ID for -+ * @return A UUID, or null if that player name is not registered with Minecraft and the server is in online mode -+ */ -+ @Nullable -+ public UUID getPlayerUniqueId(@NotNull String playerName); -+ // Paper end -+ - /** - * Gets the plugin manager for interfacing with plugins. - * diff --git a/patches/api/0093-Add-Ban-Methods-to-Player-Objects.patch b/patches/api/0093-Add-Ban-Methods-to-Player-Objects.patch new file mode 100644 index 000000000000..403efbcaefe3 --- /dev/null +++ b/patches/api/0093-Add-Ban-Methods-to-Player-Objects.patch @@ -0,0 +1,278 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 28 Apr 2018 10:28:50 -0400 +Subject: [PATCH] Add Ban Methods to Player Objects + +Allows a more logical API for banning players. + +player.banPlayer("Breaking the rules"); + +diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java +index 2f404c6cefbbd842932620aa62750b343e90e41c..11b470b07a8b5d9e7f87df5abe9bd4f5bf9f86ef 100644 +--- a/src/main/java/org/bukkit/OfflinePlayer.java ++++ b/src/main/java/org/bukkit/OfflinePlayer.java +@@ -67,6 +67,73 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio + * @return true if banned, otherwise false + */ + public boolean isBanned(); ++ // Paper start ++ /** ++ * Permanently Bans this player from the server ++ * ++ * @param reason Reason for Ban ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} ++ */ ++ @NotNull ++ @Deprecated(since = "1.20.4") ++ public default BanEntry banPlayer(@Nullable String reason) { ++ return banPlayer(reason, null, null); ++ } ++ ++ /** ++ * Permanently Bans this player from the server ++ * @param reason Reason for Ban ++ * @param source Source of the ban, or null for default ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} ++ */ ++ @NotNull ++ @Deprecated(since = "1.20.4") ++ public default BanEntry banPlayer(@Nullable String reason, @Nullable String source) { ++ return banPlayer(reason, null, source); ++ } ++ ++ /** ++ * Bans this player from the server ++ * @param reason Reason for Ban ++ * @param expires When to expire the ban ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} ++ */ ++ @NotNull ++ @Deprecated(since = "1.20.4") ++ public default BanEntry banPlayer(@Nullable String reason, @Nullable java.util.Date expires) { ++ return banPlayer(reason, expires, null); ++ } ++ ++ /** ++ * Bans this player from the server ++ * @param reason Reason for Ban ++ * @param expires When to expire the ban ++ * @param source Source of the ban or null for default ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} ++ */ ++ @NotNull ++ @Deprecated(since = "1.20.4") ++ public default BanEntry banPlayer(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source) { ++ return banPlayer(reason, expires, source, true); ++ } ++ ++ /** ++ * @deprecated use {@link #ban(String, Date, String)} ++ */ ++ @NotNull ++ @Deprecated(since = "1.20.4") ++ public default BanEntry banPlayer(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source, boolean kickIfOnline) { ++ BanEntry banEntry = Bukkit.getServer().getBanList(BanList.Type.NAME).addBan(getName(), reason, expires, source); ++ if (kickIfOnline && isOnline()) { ++ getPlayer().kickPlayer(reason); ++ } ++ return banEntry; ++ } ++ // Paper end + + /** + * Adds this user to the {@link ProfileBanList}. If a previous ban exists, this will +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 949b34e9c9f8b4be48c09f80d78d9453f0ff0ee3..c65a1204c948df81664357524d9d1e6abafb7776 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -1255,6 +1255,186 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + public void sendMap(@NotNull MapView map); + + // Paper start ++ /** ++ * Permanently Bans the Profile and IP address currently used by the player. ++ * ++ * @param reason Reason for ban ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ // For reference, Bukkit defines this as nullable, while they impl isn't, we'll follow API. ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerFull(@Nullable String reason) { ++ return banPlayerFull(reason, null, null); ++ } ++ ++ /** ++ * Permanently Bans the Profile and IP address currently used by the player. ++ * ++ * @param reason Reason for ban ++ * @param source Source of ban, or null for default ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerFull(@Nullable String reason, @Nullable String source) { ++ return banPlayerFull(reason, null, source); ++ } ++ ++ /** ++ * Bans the Profile and IP address currently used by the player. ++ * ++ * @param reason Reason for Ban ++ * @param expires When to expire the ban ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerFull(@Nullable String reason, @Nullable java.util.Date expires) { ++ return banPlayerFull(reason, expires, null); ++ } ++ ++ /** ++ * Bans the Profile and IP address currently used by the player. ++ * ++ * @param reason Reason for Ban ++ * @param expires When to expire the ban ++ * @param source Source of the ban, or null for default ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerFull(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source) { ++ banPlayer(reason, expires, source); ++ return banPlayerIP(reason, expires, source, true); ++ } ++ ++ /** ++ * Permanently Bans the IP address currently used by the player. ++ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} ++ * ++ * @param reason Reason for ban ++ * @param kickPlayer Whether or not to kick the player afterwards ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, boolean kickPlayer) { ++ return banPlayerIP(reason, null, null, kickPlayer); ++ } ++ ++ /** ++ * Permanently Bans the IP address currently used by the player. ++ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} ++ * @param reason Reason for ban ++ * @param source Source of ban, or null for default ++ * @param kickPlayer Whether or not to kick the player afterwards ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable String source, boolean kickPlayer) { ++ return banPlayerIP(reason, null, source, kickPlayer); ++ } ++ ++ /** ++ * Bans the IP address currently used by the player. ++ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} ++ * @param reason Reason for Ban ++ * @param expires When to expire the ban ++ * @param kickPlayer Whether or not to kick the player afterwards ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable java.util.Date expires, boolean kickPlayer) { ++ return banPlayerIP(reason, expires, null, kickPlayer); ++ } ++ ++ /** ++ * Permanently Bans the IP address currently used by the player. ++ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} ++ * ++ * @param reason Reason for ban ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason) { ++ return banPlayerIP(reason, null, null); ++ } ++ ++ /** ++ * Permanently Bans the IP address currently used by the player. ++ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} ++ * @param reason Reason for ban ++ * @param source Source of ban, or null for default ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable String source) { ++ return banPlayerIP(reason, null, source); ++ } ++ ++ /** ++ * Bans the IP address currently used by the player. ++ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} ++ * @param reason Reason for Ban ++ * @param expires When to expire the ban ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable java.util.Date expires) { ++ return banPlayerIP(reason, expires, null); ++ } ++ ++ /** ++ * Bans the IP address currently used by the player. ++ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} ++ * @param reason Reason for Ban ++ * @param expires When to expire the ban ++ * @param source Source of the ban or null for default ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source) { ++ return banPlayerIP(reason, expires, source, true); ++ } ++ ++ /** ++ * Bans the IP address currently used by the player. ++ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} ++ * @param reason Reason for Ban ++ * @param expires When to expire the ban ++ * @param source Source of the ban or null for default ++ * @param kickPlayer if the targeted player should be kicked ++ * @return Ban Entry ++ * @deprecated use {@link #ban(String, Date, String)} and {@link #banIp(String, Date, String, boolean)} ++ */ ++ @Nullable ++ @Deprecated(since = "1.20.4") ++ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source, boolean kickPlayer) { ++ org.bukkit.BanEntry banEntry = org.bukkit.Bukkit.getServer().getBanList(org.bukkit.BanList.Type.IP).addBan(getAddress().getAddress().getHostAddress(), reason, expires, source); ++ if (kickPlayer && isOnline()) { ++ getPlayer().kickPlayer(reason); ++ } ++ ++ return banEntry; ++ } + + /** + * Sends an Action Bar message to the client. diff --git a/patches/api/0093-Add-legacy-ping-support-to-PaperServerListPingEvent.patch b/patches/api/0093-Add-legacy-ping-support-to-PaperServerListPingEvent.patch deleted file mode 100644 index f21c766148fe..000000000000 --- a/patches/api/0093-Add-legacy-ping-support-to-PaperServerListPingEvent.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Minecrell -Date: Wed, 11 Oct 2017 19:30:20 +0200 -Subject: [PATCH] Add legacy ping support to PaperServerListPingEvent - -Add a new method to StatusClient check if the client is a legacy -client that does not support all of the features provided in the -event. - -diff --git a/src/main/java/com/destroystokyo/paper/network/StatusClient.java b/src/main/java/com/destroystokyo/paper/network/StatusClient.java -index 517d15238ed117f38bbd39f570874014cecf7bb5..ffda9f6a8b094942009aa78b331d22d9dcca2802 100644 ---- a/src/main/java/com/destroystokyo/paper/network/StatusClient.java -+++ b/src/main/java/com/destroystokyo/paper/network/StatusClient.java -@@ -10,4 +10,16 @@ import com.destroystokyo.paper.event.server.PaperServerListPingEvent; - */ - public interface StatusClient extends NetworkClient { - -+ /** -+ * Returns whether the client is using an older version that doesn't -+ * support all of the features in {@link PaperServerListPingEvent}. -+ * -+ *

      For Vanilla, this returns {@code true} for all clients older than 1.7.

      -+ * -+ * @return {@code true} if the client is using legacy ping -+ */ -+ default boolean isLegacy() { -+ return false; -+ } -+ - } diff --git a/patches/api/0094-Add-openSign-method-to-HumanEntity.patch b/patches/api/0094-Add-openSign-method-to-HumanEntity.patch deleted file mode 100644 index a4fe0d32ff70..000000000000 --- a/patches/api/0094-Add-openSign-method-to-HumanEntity.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Sun, 1 Apr 2018 02:28:43 +0300 -Subject: [PATCH] Add openSign method to HumanEntity - - -diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java -index bcdf267485f1d68ccc7ea105d5d40bc9bc9db2a2..bd9222b9b5e7ec1f3aebe37838775f345e868150 100644 ---- a/src/main/java/org/bukkit/entity/HumanEntity.java -+++ b/src/main/java/org/bukkit/entity/HumanEntity.java -@@ -479,6 +479,14 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder - */ - @Deprecated - public void setShoulderEntityRight(@Nullable Entity entity); -+ // Paper start - Add method to open already placed sign -+ /** -+ * Opens an editor window for the specified sign -+ * -+ * @param sign The sign to open -+ */ -+ void openSign(@NotNull org.bukkit.block.Sign sign); -+ // Paper end - - /** - * Make the entity drop the item in their hand. -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 6768ab96fa14d3e297c37fb899943b9f3fd0cc1d..2eb9b5b2f7449e381914be26aec4e0236c368f47 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -2146,7 +2146,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - /** - * Open a Sign for editing by the Player. - * -- * The Sign must be placed in the same world as the player. -+ * The Sign must be in the same world as the player. - * - * @param sign The sign to edit - */ diff --git a/patches/api/0094-EndermanEscapeEvent.patch b/patches/api/0094-EndermanEscapeEvent.patch new file mode 100644 index 000000000000..f81f62b72a9f --- /dev/null +++ b/patches/api/0094-EndermanEscapeEvent.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 30 Apr 2018 13:14:30 -0400 +Subject: [PATCH] EndermanEscapeEvent + +Fires an event anytime an enderman intends to teleport away from the player + +You may cancel this, enabling ranged attacks to damage the enderman for example. + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ae72916972dbe86bfbca499eb7b6f97b1a6eae25 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java +@@ -0,0 +1,83 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Enderman; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public class EndermanEscapeEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Reason reason; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EndermanEscapeEvent(final Enderman entity, final Reason reason) { ++ super(entity); ++ this.reason = reason; ++ } ++ ++ @Override ++ public Enderman getEntity() { ++ return (Enderman) super.getEntity(); ++ } ++ ++ /** ++ * @return The reason the enderman is trying to escape ++ */ ++ public Reason getReason() { ++ return this.reason; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * Cancels the escape. ++ *

      ++ * If this escape normally had resulted in damage avoidance such as indirect, ++ * the enderman will now take damage. ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum Reason { ++ /** ++ * The enderman has stopped attacking and ran away ++ */ ++ RUNAWAY, ++ /** ++ * The enderman has teleported away due to indirect damage (ranged) ++ */ ++ INDIRECT, ++ /** ++ * The enderman has teleported away due to a critical hit ++ */ ++ CRITICAL_HIT, ++ /** ++ * The enderman has teleported away due to the player staring at it during combat ++ */ ++ STARE, ++ /** ++ * Specific case for {@link #CRITICAL_HIT} where the enderman is taking rain damage ++ */ ++ DROWN ++ } ++} diff --git a/patches/api/0095-Add-Ban-Methods-to-Player-Objects.patch b/patches/api/0095-Add-Ban-Methods-to-Player-Objects.patch deleted file mode 100644 index 86284e6483a1..000000000000 --- a/patches/api/0095-Add-Ban-Methods-to-Player-Objects.patch +++ /dev/null @@ -1,242 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 28 Apr 2018 10:28:50 -0400 -Subject: [PATCH] Add Ban Methods to Player Objects - -Allows a more logical API for banning players. - -player.banPlayer("Breaking the rules"); - -diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java -index c5eed3234a8c04bfa9d707685746fc2b40ec8bfc..93f86bb30725dff5dbfcccf15012ffd1cee237bf 100644 ---- a/src/main/java/org/bukkit/OfflinePlayer.java -+++ b/src/main/java/org/bukkit/OfflinePlayer.java -@@ -58,6 +58,61 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio - * @return true if banned, otherwise false - */ - public boolean isBanned(); -+ // Paper start -+ -+ /** -+ * Permanently Bans this player from the server -+ * -+ * @param reason Reason for Ban -+ * @return Ban Entry -+ */ -+ @NotNull -+ public default BanEntry banPlayer(@Nullable String reason) { -+ return banPlayer(reason, null, null); -+ } -+ -+ /** -+ * Permanently Bans this player from the server -+ * @param reason Reason for Ban -+ * @param source Source of the ban, or null for default -+ * @return Ban Entry -+ */ -+ @NotNull -+ public default BanEntry banPlayer(@Nullable String reason, @Nullable String source) { -+ return banPlayer(reason, null, source); -+ } -+ -+ /** -+ * Bans this player from the server -+ * @param reason Reason for Ban -+ * @param expires When to expire the ban -+ * @return Ban Entry -+ */ -+ @NotNull -+ public default BanEntry banPlayer(@Nullable String reason, @Nullable java.util.Date expires) { -+ return banPlayer(reason, expires, null); -+ } -+ -+ /** -+ * Bans this player from the server -+ * @param reason Reason for Ban -+ * @param expires When to expire the ban -+ * @param source Source of the ban or null for default -+ * @return Ban Entry -+ */ -+ @NotNull -+ public default BanEntry banPlayer(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source) { -+ return banPlayer(reason, expires, source, true); -+ } -+ @NotNull -+ public default BanEntry banPlayer(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source, boolean kickIfOnline) { -+ BanEntry banEntry = Bukkit.getServer().getBanList(BanList.Type.NAME).addBan(getName(), reason, expires, source); -+ if (kickIfOnline && isOnline()) { -+ getPlayer().kickPlayer(reason); -+ } -+ return banEntry; -+ } -+ // Paper end - - /** - * Checks if this player is whitelisted or not -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 2eb9b5b2f7449e381914be26aec4e0236c368f47..5093a978dd44f0e6e14af7d8e12b50b602f0b2bd 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -750,6 +750,162 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - public void sendMap(@NotNull MapView map); - - // Paper start -+ /** -+ * Permanently Bans the Profile and IP address currently used by the player. -+ * -+ * @param reason Reason for ban -+ * @return Ban Entry -+ */ -+ // For reference, Bukkit defines this as nullable, while they impl isn't, we'll follow API. -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerFull(@Nullable String reason) { -+ return banPlayerFull(reason, null, null); -+ } -+ -+ /** -+ * Permanently Bans the Profile and IP address currently used by the player. -+ * -+ * @param reason Reason for ban -+ * @param source Source of ban, or null for default -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerFull(@Nullable String reason, @Nullable String source) { -+ return banPlayerFull(reason, null, source); -+ } -+ -+ /** -+ * Bans the Profile and IP address currently used by the player. -+ * -+ * @param reason Reason for Ban -+ * @param expires When to expire the ban -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerFull(@Nullable String reason, @Nullable java.util.Date expires) { -+ return banPlayerFull(reason, expires, null); -+ } -+ -+ /** -+ * Bans the Profile and IP address currently used by the player. -+ * -+ * @param reason Reason for Ban -+ * @param expires When to expire the ban -+ * @param source Source of the ban, or null for default -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerFull(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source) { -+ banPlayer(reason, expires, source); -+ return banPlayerIP(reason, expires, source, true); -+ } -+ -+ /** -+ * Permanently Bans the IP address currently used by the player. -+ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} -+ * -+ * @param reason Reason for ban -+ * @param kickPlayer Whether or not to kick the player afterwards -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, boolean kickPlayer) { -+ return banPlayerIP(reason, null, null, kickPlayer); -+ } -+ -+ /** -+ * Permanently Bans the IP address currently used by the player. -+ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} -+ * @param reason Reason for ban -+ * @param source Source of ban, or null for default -+ * @param kickPlayer Whether or not to kick the player afterwards -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable String source, boolean kickPlayer) { -+ return banPlayerIP(reason, null, source, kickPlayer); -+ } -+ -+ /** -+ * Bans the IP address currently used by the player. -+ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} -+ * @param reason Reason for Ban -+ * @param expires When to expire the ban -+ * @param kickPlayer Whether or not to kick the player afterwards -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable java.util.Date expires, boolean kickPlayer) { -+ return banPlayerIP(reason, expires, null, kickPlayer); -+ } -+ -+ /** -+ * Permanently Bans the IP address currently used by the player. -+ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} -+ * -+ * @param reason Reason for ban -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason) { -+ return banPlayerIP(reason, null, null); -+ } -+ -+ /** -+ * Permanently Bans the IP address currently used by the player. -+ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} -+ * @param reason Reason for ban -+ * @param source Source of ban, or null for default -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable String source) { -+ return banPlayerIP(reason, null, source); -+ } -+ -+ /** -+ * Bans the IP address currently used by the player. -+ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} -+ * @param reason Reason for Ban -+ * @param expires When to expire the ban -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable java.util.Date expires) { -+ return banPlayerIP(reason, expires, null); -+ } -+ -+ /** -+ * Bans the IP address currently used by the player. -+ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} -+ * @param reason Reason for Ban -+ * @param expires When to expire the ban -+ * @param source Source of the banm or null for default -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source) { -+ return banPlayerIP(reason, expires, source, true); -+ } -+ -+ /** -+ * Bans the IP address currently used by the player. -+ * Does not ban the Profile, use {@link #banPlayerFull(String, java.util.Date, String)} -+ * @param reason Reason for Ban -+ * @param expires When to expire the ban -+ * @param source Source of the banm or null for default -+ * @param kickPlayer if the targeted player should be kicked -+ * @return Ban Entry -+ */ -+ @Nullable -+ public default org.bukkit.BanEntry banPlayerIP(@Nullable String reason, @Nullable java.util.Date expires, @Nullable String source, boolean kickPlayer) { -+ org.bukkit.BanEntry banEntry = org.bukkit.Bukkit.getServer().getBanList(org.bukkit.BanList.Type.IP).addBan(getAddress().getAddress().getHostAddress(), reason, expires, source); -+ if (kickPlayer && isOnline()) { -+ getPlayer().kickPlayer(reason); -+ } -+ -+ return banEntry; -+ } - - /** - * Sends an Action Bar message to the client. diff --git a/patches/api/0095-Enderman.teleportRandomly.patch b/patches/api/0095-Enderman.teleportRandomly.patch new file mode 100644 index 000000000000..5fedcbb7461c --- /dev/null +++ b/patches/api/0095-Enderman.teleportRandomly.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 30 Apr 2018 13:29:15 -0400 +Subject: [PATCH] Enderman.teleportRandomly() + +Ability to trigger the vanilla "teleport randomly" mechanic of an enderman. + +diff --git a/src/main/java/org/bukkit/entity/Enderman.java b/src/main/java/org/bukkit/entity/Enderman.java +index cc4648528c08980e6191e2fbdd7ba366617491b5..3afe2787de576f7190d87c796bea0ab34dc30248 100644 +--- a/src/main/java/org/bukkit/entity/Enderman.java ++++ b/src/main/java/org/bukkit/entity/Enderman.java +@@ -10,6 +10,17 @@ import org.jetbrains.annotations.Nullable; + */ + public interface Enderman extends Monster { + ++ // Paper start ++ /** ++ * Try to teleport the enderman to a random nearby location. ++ * ++ * May conditionally fail if the random location was not valid ++ * @return If the enderman teleported successfully or not ++ */ ++ ++ public boolean teleportRandomly(); ++ // Paper end ++ + /** + * Gets the id and data of the block that the Enderman is carrying. + * diff --git a/patches/api/0096-Additional-world.getNearbyEntities-API-s.patch b/patches/api/0096-Additional-world.getNearbyEntities-API-s.patch new file mode 100644 index 000000000000..fc6396519e52 --- /dev/null +++ b/patches/api/0096-Additional-world.getNearbyEntities-API-s.patch @@ -0,0 +1,260 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 30 Apr 2018 17:55:28 -0400 +Subject: [PATCH] Additional world.getNearbyEntities API's + +Provides more methods to get nearby entities, and filter by types and predicates + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 369e92f2b5e4b8fc7f5bf8a97058e827c91e4c59..79e5b429fe5660695e9fa603f8bc1fc1352b8950 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -1,6 +1,9 @@ + package org.bukkit; + + import java.io.File; ++import org.bukkit.generator.ChunkGenerator; ++ ++import java.util.ArrayList; + import java.util.Collection; + import java.util.HashMap; + import java.util.List; +@@ -663,6 +666,238 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @NotNull + public Collection getEntitiesByClasses(@NotNull Class... classes); + ++ // Paper start - additional getNearbyEntities API ++ /** ++ * Gets nearby LivingEntities within the specified radius (bounding box) ++ * @param loc Center location ++ * @param radius Radius ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyLivingEntities(final @NotNull Location loc, final double radius) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, loc, radius, radius, radius); ++ } ++ ++ /** ++ * Gets nearby LivingEntities within the specified radius (bounding box) ++ * @param loc Center location ++ * @param xzRadius X/Z Radius ++ * @param yRadius Y Radius ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyLivingEntities(final @NotNull Location loc, final double xzRadius, final double yRadius) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, loc, xzRadius, yRadius, xzRadius); ++ } ++ ++ /** ++ * Gets nearby LivingEntities within the specified radius (bounding box) ++ * @param loc Center location ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z radius ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyLivingEntities(final @NotNull Location loc, final double xRadius, final double yRadius, final double zRadius) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, loc, xRadius, yRadius, zRadius); ++ } ++ ++ /** ++ * Gets nearby LivingEntities within the specified radius (bounding box) ++ * @param loc Center location ++ * @param radius X Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of living entities near location. This will always be a non-null collection ++ */ ++ default @NotNull Collection getNearbyLivingEntities(final @NotNull Location loc, final double radius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, loc, radius, radius, radius, predicate); ++ } ++ ++ /** ++ * Gets nearby LivingEntities within the specified radius (bounding box) ++ * @param loc Center location ++ * @param xzRadius X/Z Radius ++ * @param yRadius Y Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of living entities near location. This will always be a non-null collection ++ */ ++ default @NotNull Collection getNearbyLivingEntities(final @NotNull Location loc, final double xzRadius, final double yRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, loc, xzRadius, yRadius, xzRadius, predicate); ++ } ++ ++ /** ++ * Gets nearby LivingEntities within the specified radius (bounding box) ++ * @param loc Center location ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of living entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyLivingEntities(final @NotNull Location loc, final double xRadius, final double yRadius, final double zRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, loc, xRadius, yRadius, zRadius, predicate); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param loc Center location ++ * @param radius X/Y/Z Radius ++ * @return the collection of living entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyPlayers(final @NotNull Location loc, final double radius) { ++ return this.getNearbyEntitiesByType(Player.class, loc, radius, radius, radius); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param loc Center location ++ * @param xzRadius X/Z Radius ++ * @param yRadius Y Radius ++ * @return the collection of living entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyPlayers(final @NotNull Location loc, final double xzRadius, final double yRadius) { ++ return this.getNearbyEntitiesByType(Player.class, loc, xzRadius, yRadius, xzRadius); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param loc Center location ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z Radius ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyPlayers(final @NotNull Location loc, final double xRadius, final double yRadius, final double zRadius) { ++ return this.getNearbyEntitiesByType(Player.class, loc, xRadius, yRadius, zRadius); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param loc Center location ++ * @param radius X/Y/Z Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyPlayers(final @NotNull Location loc, final double radius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(Player.class, loc, radius, radius, radius, predicate); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param loc Center location ++ * @param xzRadius X/Z Radius ++ * @param yRadius Y Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyPlayers(final @NotNull Location loc, final double xzRadius, final double yRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(Player.class, loc, xzRadius, yRadius, xzRadius, predicate); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param loc Center location ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyPlayers(final @NotNull Location loc, final double xRadius, final double yRadius, final double zRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(Player.class, loc, xRadius, yRadius, zRadius, predicate); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius (bounding box) ++ * @param clazz Type to filter by ++ * @param loc Center location ++ * @param radius X/Y/Z radius to search within ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final @NotNull Location loc, final double radius) { ++ return this.getNearbyEntitiesByType(clazz, loc, radius, radius, radius, null); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius, with x and x radius matching (bounding box) ++ * @param clazz Type to filter by ++ * @param loc Center location ++ * @param xzRadius X/Z radius to search within ++ * @param yRadius Y radius to search within ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final @NotNull Location loc, final double xzRadius, final double yRadius) { ++ return this.getNearbyEntitiesByType(clazz, loc, xzRadius, yRadius, xzRadius, null); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius (bounding box) ++ * @param clazz Type to filter by ++ * @param loc Center location ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z Radius ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final @NotNull Location loc, final double xRadius, final double yRadius, final double zRadius) { ++ return this.getNearbyEntitiesByType(clazz, loc, xRadius, yRadius, zRadius, null); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius (bounding box) ++ * @param clazz Type to filter by ++ * @param loc Center location ++ * @param radius X/Y/Z radius to search within ++ * @param predicate a predicate used to filter results ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final @NotNull Location loc, final double radius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(clazz, loc, radius, radius, radius, predicate); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius, with x and x radius matching (bounding box) ++ * @param clazz Type to filter by ++ * @param loc Center location ++ * @param xzRadius X/Z radius to search within ++ * @param yRadius Y radius to search within ++ * @param predicate a predicate used to filter results ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final @NotNull Location loc, final double xzRadius, final double yRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(clazz, loc, xzRadius, yRadius, xzRadius, predicate); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius (bounding box) ++ * @param clazz Type to filter by ++ * @param loc Center location ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z Radius ++ * @param predicate a predicate used to filter results ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ default @NotNull Collection getNearbyEntitiesByType(@Nullable Class clazz, final @NotNull Location loc, final double xRadius, final double yRadius, final double zRadius, final @Nullable Predicate predicate) { ++ if (clazz == null) { ++ clazz = Entity.class; ++ } ++ final List nearby = new ArrayList<>(); ++ for (final Entity bukkitEntity : this.getNearbyEntities(loc, xRadius, yRadius, zRadius)) { ++ //noinspection unchecked ++ if (clazz.isAssignableFrom(bukkitEntity.getClass()) && (predicate == null || predicate.test((T) bukkitEntity))) { ++ //noinspection unchecked ++ nearby.add((T) bukkitEntity); ++ } ++ } ++ return nearby; ++ } ++ // Paper end - additional getNearbyEntities API ++ + /** + * Get a list of all players in this World + * diff --git a/patches/api/0096-EndermanEscapeEvent.patch b/patches/api/0096-EndermanEscapeEvent.patch deleted file mode 100644 index 82d22fd0ea26..000000000000 --- a/patches/api/0096-EndermanEscapeEvent.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 30 Apr 2018 13:14:30 -0400 -Subject: [PATCH] EndermanEscapeEvent - -Fires an event anytime an enderman intends to teleport away from the player - -You may cancel this, enabling ranged attacks to damage the enderman for example. - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..806112a8b5a7ce31166675f5b074ceaf42e364b6 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java -@@ -0,0 +1,87 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Enderman; -+import org.bukkit.entity.Entity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+public class EndermanEscapeEvent extends EntityEvent implements Cancellable { -+ @NotNull private final Reason reason; -+ -+ public EndermanEscapeEvent(@NotNull Enderman entity, @NotNull Reason reason) { -+ super(entity); -+ this.reason = reason; -+ } -+ -+ @NotNull -+ @Override -+ public Enderman getEntity() { -+ return (Enderman) super.getEntity(); -+ } -+ -+ /** -+ * @return The reason the enderman is trying to escape -+ */ -+ @NotNull -+ public Reason getReason() { -+ return reason; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * Cancels the escape. -+ * -+ * If this escape normally would of resulted in damage avoidance such as indirect, -+ * the enderman will now take damage. -+ * -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ public enum Reason { -+ /** -+ * The enderman has stopped attacking and ran away -+ */ -+ RUNAWAY, -+ /** -+ * The enderman has teleported away due to indirect damage (ranged) -+ */ -+ INDIRECT, -+ /** -+ * The enderman has teleported away due to a critical hit -+ */ -+ CRITICAL_HIT, -+ /** -+ * The enderman has teleported away due to the player staring at it during combat -+ */ -+ STARE, -+ /** -+ * Specific case for CRITICAL_HIT where the enderman is taking rain damage -+ */ -+ DROWN -+ } -+} diff --git a/patches/api/0097-Enderman.teleportRandomly.patch b/patches/api/0097-Enderman.teleportRandomly.patch deleted file mode 100644 index 9c226d009ced..000000000000 --- a/patches/api/0097-Enderman.teleportRandomly.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 30 Apr 2018 13:29:15 -0400 -Subject: [PATCH] Enderman.teleportRandomly() - -Ability to trigger the vanilla "teleport randomly" mechanic of an enderman. - -diff --git a/src/main/java/org/bukkit/entity/Enderman.java b/src/main/java/org/bukkit/entity/Enderman.java -index bb325d9c802e33431530bbccdcf5de5839e5fe68..821c690f8a32918bdb284ffec4af98f411f76ccc 100644 ---- a/src/main/java/org/bukkit/entity/Enderman.java -+++ b/src/main/java/org/bukkit/entity/Enderman.java -@@ -10,6 +10,17 @@ import org.jetbrains.annotations.Nullable; - */ - public interface Enderman extends Monster { - -+ // Paper start -+ /** -+ * Try to teleport the enderman to a random nearby location. -+ * -+ * May conditionally fail if the random location was not valid -+ * @return If the enderman teleported successfully or not -+ */ -+ -+ public boolean teleportRandomly(); -+ // Paper end -+ - /** - * Gets the id and data of the block that the Enderman is carrying. - * diff --git a/patches/api/0097-Location.isChunkLoaded-API.patch b/patches/api/0097-Location.isChunkLoaded-API.patch new file mode 100644 index 000000000000..c865422539dd --- /dev/null +++ b/patches/api/0097-Location.isChunkLoaded-API.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 30 Apr 2018 19:27:31 -0400 +Subject: [PATCH] Location.isChunkLoaded() API + + +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index bc8a64d54e001eae6ef4520a49e261b96c5ae9f3..7c7d2b2dc082fd3b5681a15a600422ae3937e2e1 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -533,6 +533,7 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + return this; + } + ++ public boolean isChunkLoaded() { return this.getWorld().isChunkLoaded(locToBlock(x) >> 4, locToBlock(z) >> 4); } // Paper + @Override + public boolean equals(Object obj) { + if (obj == null) { diff --git a/patches/api/0098-Additional-world.getNearbyEntities-API-s.patch b/patches/api/0098-Additional-world.getNearbyEntities-API-s.patch deleted file mode 100644 index 8b9cd24e5b49..000000000000 --- a/patches/api/0098-Additional-world.getNearbyEntities-API-s.patch +++ /dev/null @@ -1,292 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 30 Apr 2018 17:55:28 -0400 -Subject: [PATCH] Additional world.getNearbyEntities API's - -Provides more methods to get nearby entities, and filter by types and predicates - -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index e0683e69029e8ac423bda79521045b06673eabf3..cf7baa9cd691b02aeaa4d94d5e999e661e003a44 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -1,6 +1,9 @@ - package org.bukkit; - - import java.io.File; -+import org.bukkit.generator.ChunkGenerator; -+ -+import java.util.ArrayList; - import java.util.Collection; - import java.util.HashMap; - import java.util.List; -@@ -657,6 +660,256 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - @NotNull - public Collection getEntitiesByClasses(@NotNull Class... classes); - -+ // Paper start -+ /** -+ * Gets nearby LivingEntities within the specified radius (bounding box) -+ * @param loc Center location -+ * @param radius Radius -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyLivingEntities(@NotNull Location loc, double radius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, loc, radius, radius, radius); -+ } -+ -+ /** -+ * Gets nearby LivingEntities within the specified radius (bounding box) -+ * @param loc Center location -+ * @param xzRadius X/Z Radius -+ * @param yRadius Y Radius -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyLivingEntities(@NotNull Location loc, double xzRadius, double yRadius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, loc, xzRadius, yRadius, xzRadius); -+ } -+ -+ /** -+ * Gets nearby LivingEntities within the specified radius (bounding box) -+ * @param loc Center location -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z radius -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyLivingEntities(@NotNull Location loc, double xRadius, double yRadius, double zRadius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, loc, xRadius, yRadius, zRadius); -+ } -+ -+ /** -+ * Gets nearby LivingEntities within the specified radius (bounding box) -+ * @param loc Center location -+ * @param radius X Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of living entities near location. This will always be a non-null collection -+ */ -+ @NotNull -+ public default Collection getNearbyLivingEntities(@NotNull Location loc, double radius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, loc, radius, radius, radius, predicate); -+ } -+ -+ /** -+ * Gets nearby LivingEntities within the specified radius (bounding box) -+ * @param loc Center location -+ * @param xzRadius X/Z Radius -+ * @param yRadius Y Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of living entities near location. This will always be a non-null collection -+ */ -+ @NotNull -+ public default Collection getNearbyLivingEntities(@NotNull Location loc, double xzRadius, double yRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, loc, xzRadius, yRadius, xzRadius, predicate); -+ } -+ -+ /** -+ * Gets nearby LivingEntities within the specified radius (bounding box) -+ * @param loc Center location -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of living entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyLivingEntities(@NotNull Location loc, double xRadius, double yRadius, double zRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, loc, xRadius, yRadius, zRadius, predicate); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param loc Center location -+ * @param radius X/Y/Z Radius -+ * @return the collection of living entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyPlayers(@NotNull Location loc, double radius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, loc, radius, radius, radius); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param loc Center location -+ * @param xzRadius X/Z Radius -+ * @param yRadius Y Radius -+ * @return the collection of living entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyPlayers(@NotNull Location loc, double xzRadius, double yRadius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, loc, xzRadius, yRadius, xzRadius); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param loc Center location -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z Radius -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyPlayers(@NotNull Location loc, double xRadius, double yRadius, double zRadius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, loc, xRadius, yRadius, zRadius); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param loc Center location -+ * @param radius X/Y/Z Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyPlayers(@NotNull Location loc, double radius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, loc, radius, radius, radius, predicate); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param loc Center location -+ * @param xzRadius X/Z Radius -+ * @param yRadius Y Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyPlayers(@NotNull Location loc, double xzRadius, double yRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, loc, xzRadius, yRadius, xzRadius, predicate); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param loc Center location -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyPlayers(@NotNull Location loc, double xRadius, double yRadius, double zRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, loc, xRadius, yRadius, zRadius, predicate); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius (bounding box) -+ * @param clazz Type to filter by -+ * @param loc Center location -+ * @param radius X/Y/Z radius to search within -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyEntitiesByType(@Nullable Class clazz, @NotNull Location loc, double radius) { -+ return getNearbyEntitiesByType(clazz, loc, radius, radius, radius, null); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius, with x and x radius matching (bounding box) -+ * @param clazz Type to filter by -+ * @param loc Center location -+ * @param xzRadius X/Z radius to search within -+ * @param yRadius Y radius to search within -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyEntitiesByType(@Nullable Class clazz, @NotNull Location loc, double xzRadius, double yRadius) { -+ return getNearbyEntitiesByType(clazz, loc, xzRadius, yRadius, xzRadius, null); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius (bounding box) -+ * @param clazz Type to filter by -+ * @param loc Center location -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z Radius -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyEntitiesByType(@Nullable Class clazz, @NotNull Location loc, double xRadius, double yRadius, double zRadius) { -+ return getNearbyEntitiesByType(clazz, loc, xRadius, yRadius, zRadius, null); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius (bounding box) -+ * @param clazz Type to filter by -+ * @param loc Center location -+ * @param radius X/Y/Z radius to search within -+ * @param predicate a predicate used to filter results -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyEntitiesByType(@Nullable Class clazz, @NotNull Location loc, double radius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(clazz, loc, radius, radius, radius, predicate); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius, with x and x radius matching (bounding box) -+ * @param clazz Type to filter by -+ * @param loc Center location -+ * @param xzRadius X/Z radius to search within -+ * @param yRadius Y radius to search within -+ * @param predicate a predicate used to filter results -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyEntitiesByType(@Nullable Class clazz, @NotNull Location loc, double xzRadius, double yRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(clazz, loc, xzRadius, yRadius, xzRadius, predicate); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius (bounding box) -+ * @param clazz Type to filter by -+ * @param loc Center location -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z Radius -+ * @param predicate a predicate used to filter results -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public default Collection getNearbyEntitiesByType(@Nullable Class clazz, @NotNull Location loc, double xRadius, double yRadius, double zRadius, @Nullable Predicate predicate) { -+ if (clazz == null) { -+ clazz = Entity.class; -+ } -+ List nearby = new ArrayList<>(); -+ for (Entity bukkitEntity : getNearbyEntities(loc, xRadius, yRadius, zRadius)) { -+ //noinspection unchecked -+ if (clazz.isAssignableFrom(bukkitEntity.getClass()) && (predicate == null || predicate.test((T) bukkitEntity))) { -+ //noinspection unchecked -+ nearby.add((T) bukkitEntity); -+ } -+ } -+ return nearby; -+ } -+ // Paper end -+ - /** - * Get a list of all players in this World - * -diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -index c30b44ff26f8f253902754452a0816f07c7fd035..9acf1fb404ccf9b3bc06a448c3099ca2e838facf 100644 ---- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -+++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -@@ -42,8 +42,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - return profile; - } - -- /** -- * Changes the PlayerProfile the player will login as -+ /* * Changes the PlayerProfile the player will login as - * @param profile The profile to use - */ - public void setPlayerProfile(@NotNull PlayerProfile profile) { diff --git a/patches/api/0098-Expand-World.spawnParticle-API-and-add-Builder.patch b/patches/api/0098-Expand-World.spawnParticle-API-and-add-Builder.patch new file mode 100644 index 000000000000..c88ced9f4322 --- /dev/null +++ b/patches/api/0098-Expand-World.spawnParticle-API-and-add-Builder.patch @@ -0,0 +1,684 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 29 Aug 2017 23:58:48 -0400 +Subject: [PATCH] Expand World.spawnParticle API and add Builder + +Adds ability to control who receives it and who is the source/sender (vanish API) +the standard API is to send the packet to everyone in the world, which is ineffecient. + +This adds a new Builder API which is much friendlier to use. + +diff --git a/src/main/java/com/destroystokyo/paper/ParticleBuilder.java b/src/main/java/com/destroystokyo/paper/ParticleBuilder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6c405755f4507d6fbc6c3877c611a7191206f3ff +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/ParticleBuilder.java +@@ -0,0 +1,582 @@ ++package com.destroystokyo.paper; ++ ++import com.google.common.base.Preconditions; ++import com.google.common.collect.Lists; ++import it.unimi.dsi.fastutil.objects.ObjectArrayList; ++import java.util.Collection; ++import java.util.List; ++import org.bukkit.Color; ++import org.bukkit.Location; ++import org.bukkit.Particle; ++import org.bukkit.World; ++import org.bukkit.entity.Player; ++import org.bukkit.util.NumberConversions; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Helps prepare a particle to be sent to players. ++ *

      ++ * Usage of the builder is preferred over the super long {@link World#spawnParticle(Particle, Location, int, double, double, double, double, Object)} API ++ */ ++@NullMarked ++public class ParticleBuilder implements Cloneable { ++ ++ private Particle particle; ++ private @Nullable List receivers; ++ private @Nullable Player source; ++ private @Nullable Location location; ++ private int count = 1; ++ private double offsetX = 0, offsetY = 0, offsetZ = 0; ++ private double extra = 1; ++ private @Nullable Object data; ++ private boolean force = true; ++ ++ public ParticleBuilder(final Particle particle) { ++ this.particle = particle; ++ } ++ ++ /** ++ * Sends the particle to all receiving players (or all). This method is safe to use ++ * Asynchronously ++ * ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder spawn() { ++ if (this.location == null) { ++ throw new IllegalStateException("Please specify location for this particle"); ++ } ++ this.location.getWorld().spawnParticle( ++ this.particle, this.receivers, this.source, ++ this.location.getX(), this.location.getY(), this.location.getZ(), ++ this.count, this.offsetX, this.offsetY, this.offsetZ, this.extra, this.data, this.force ++ ); ++ return this; ++ } ++ ++ /** ++ * @return The particle going to be sent ++ */ ++ public Particle particle() { ++ return this.particle; ++ } ++ ++ /** ++ * Changes what particle will be sent ++ * ++ * @param particle The particle ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder particle(final Particle particle) { ++ this.particle = particle; ++ return this; ++ } ++ ++ /** ++ * @return List of players who will receive the particle, or null for all in world ++ */ ++ public @Nullable List receivers() { ++ return this.receivers; ++ } ++ ++ /** ++ * Example use: ++ *

      ++ * builder.receivers(16); if (builder.hasReceivers()) { sendParticleAsync(builder); } ++ * ++ * @return If this particle is going to be sent to someone ++ */ ++ public boolean hasReceivers() { ++ return (this.receivers == null && this.location != null && !this.location.getWorld().getPlayers().isEmpty()) || ( ++ this.receivers != null && !this.receivers.isEmpty()); ++ } ++ ++ /** ++ * Sends this particle to all players in the world. This is rather silly, and you should likely not ++ * be doing this. ++ *

      ++ * Just be a logical person and use receivers by radius or collection. ++ * ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder allPlayers() { ++ this.receivers = null; ++ return this; ++ } ++ ++ /** ++ * @param receivers List of players to receive this particle, or null for all players in the ++ * world ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder receivers(final @Nullable List receivers) { ++ // Had to keep this as we first made API List<> and not Collection, but removing this may break plugins compiled on older jars ++ // TODO: deprecate? ++ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null; ++ return this; ++ } ++ ++ /** ++ * @param receivers List of players to receive this particle, or null for all players in the ++ * world ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder receivers(final @Nullable Collection receivers) { ++ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null; ++ return this; ++ } ++ ++ /** ++ * @param receivers List of players to receive this particle, or null for all players in the ++ * world ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder receivers(final Player @Nullable... receivers) { ++ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null; ++ return this; ++ } ++ ++ /** ++ * Selects all players within a cuboid selection around the particle location, within the ++ * specified bounding box. If you want a more spherical check, see {@link #receivers(int, ++ * boolean)} ++ * ++ * @param radius amount to add on all axis ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder receivers(final int radius) { ++ return this.receivers(radius, radius); ++ } ++ ++ /** ++ * Selects all players within the specified radius around the particle location. If byDistance is ++ * false, behavior uses cuboid selection the same as {@link #receivers(int, int)} If byDistance is ++ * true, radius is tested by distance in a spherical shape ++ * ++ * @param radius amount to add on each axis ++ * @param byDistance true to use a spherical radius, false to use a cuboid ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder receivers(final int radius, final boolean byDistance) { ++ if (!byDistance) { ++ return this.receivers(radius, radius, radius); ++ } else { ++ if (this.location == null) { ++ throw new IllegalStateException("Please set location first"); ++ } ++ this.receivers = Lists.newArrayList(); ++ for (final Player nearbyPlayer : this.location.getWorld() ++ .getNearbyPlayers(this.location, radius, radius, radius)) { ++ final Location loc = nearbyPlayer.getLocation(); ++ final double x = NumberConversions.square(this.location.getX() - loc.getX()); ++ final double y = NumberConversions.square(this.location.getY() - loc.getY()); ++ final double z = NumberConversions.square(this.location.getZ() - loc.getZ()); ++ if (Math.sqrt(x + y + z) > radius) { ++ continue; ++ } ++ this.receivers.add(nearbyPlayer); ++ } ++ return this; ++ } ++ } ++ ++ /** ++ * Selects all players within a cuboid selection around the particle location, within the ++ * specified bounding box. Allows specifying a different Y size than X and Z If you want a more ++ * cylinder check, see {@link #receivers(int, int, boolean)} If you want a more spherical check, ++ * see {@link #receivers(int, boolean)} ++ * ++ * @param xzRadius amount to add on the x/z axis ++ * @param yRadius amount to add on the y axis ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder receivers(final int xzRadius, final int yRadius) { ++ return this.receivers(xzRadius, yRadius, xzRadius); ++ } ++ ++ /** ++ * Selects all players within the specified radius around the particle location. If byDistance is ++ * false, behavior uses cuboid selection the same as {@link #receivers(int, int)} If byDistance is ++ * true, radius is tested by distance on the y plane and on the x/z plane, in a cylinder shape. ++ * ++ * @param xzRadius amount to add on the x/z axis ++ * @param yRadius amount to add on the y axis ++ * @param byDistance true to use a cylinder shape, false to use cuboid ++ * @return a reference to this object. ++ * @throws IllegalStateException if a location hasn't been specified yet ++ */ ++ public ParticleBuilder receivers(final int xzRadius, final int yRadius, final boolean byDistance) { ++ if (!byDistance) { ++ return this.receivers(xzRadius, yRadius, xzRadius); ++ } else { ++ if (this.location == null) { ++ throw new IllegalStateException("Please set location first"); ++ } ++ this.receivers = Lists.newArrayList(); ++ for (final Player nearbyPlayer : this.location.getWorld() ++ .getNearbyPlayers(this.location, xzRadius, yRadius, xzRadius)) { ++ final Location loc = nearbyPlayer.getLocation(); ++ if (Math.abs(loc.getY() - this.location.getY()) > yRadius) { ++ continue; ++ } ++ final double x = NumberConversions.square(this.location.getX() - loc.getX()); ++ final double z = NumberConversions.square(this.location.getZ() - loc.getZ()); ++ if (x + z > NumberConversions.square(xzRadius)) { ++ continue; ++ } ++ this.receivers.add(nearbyPlayer); ++ } ++ return this; ++ } ++ } ++ ++ /** ++ * Selects all players within a cuboid selection around the particle location, within the ++ * specified bounding box. If you want a more cylinder check, see {@link #receivers(int, int, ++ * boolean)} If you want a more spherical check, see {@link #receivers(int, boolean)} ++ * ++ * @param xRadius amount to add on the x axis ++ * @param yRadius amount to add on the y axis ++ * @param zRadius amount to add on the z axis ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder receivers(final int xRadius, final int yRadius, final int zRadius) { ++ if (this.location == null) { ++ throw new IllegalStateException("Please set location first"); ++ } ++ return this.receivers(this.location.getWorld().getNearbyPlayers(this.location, xRadius, yRadius, zRadius)); ++ } ++ ++ /** ++ * @return The player considered the source of this particle (for Visibility concerns), or null ++ */ ++ public @Nullable Player source() { ++ return this.source; ++ } ++ ++ /** ++ * Sets the source of this particle for visibility concerns (Vanish API) ++ * ++ * @param source The player who is considered the source ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder source(final @Nullable Player source) { ++ this.source = source; ++ return this; ++ } ++ ++ /** ++ * @return Location of where the particle will spawn ++ */ ++ public @Nullable Location location() { ++ return this.location; ++ } ++ ++ /** ++ * Sets the location of where to spawn the particle ++ * ++ * @param location The location of the particle ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder location(final Location location) { ++ this.location = location.clone(); ++ return this; ++ } ++ ++ /** ++ * Sets the location of where to spawn the particle ++ * ++ * @param world World to spawn particle in ++ * @param x X location ++ * @param y Y location ++ * @param z Z location ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder location(final World world, final double x, final double y, final double z) { ++ this.location = new Location(world, x, y, z); ++ return this; ++ } ++ ++ /** ++ * @return Number of particles to spawn ++ */ ++ public int count() { ++ return this.count; ++ } ++ ++ /** ++ * Sets the number of particles to spawn ++ * ++ * @param count Number of particles ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder count(final int count) { ++ this.count = count; ++ return this; ++ } ++ ++ /** ++ * Particle offset X. Varies by particle on how this is used ++ * ++ * @return Particle offset X. ++ */ ++ public double offsetX() { ++ return this.offsetX; ++ } ++ ++ /** ++ * Particle offset Y. Varies by particle on how this is used ++ * ++ * @return Particle offset Y. ++ */ ++ public double offsetY() { ++ return this.offsetY; ++ } ++ ++ /** ++ * Particle offset Z. Varies by particle on how this is used ++ * ++ * @return Particle offset Z. ++ */ ++ public double offsetZ() { ++ return this.offsetZ; ++ } ++ ++ /** ++ * Sets the particle offset. Varies by particle on how this is used ++ * ++ * @param offsetX Particle offset X ++ * @param offsetY Particle offset Y ++ * @param offsetZ Particle offset Z ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder offset(final double offsetX, final double offsetY, final double offsetZ) { ++ this.offsetX = offsetX; ++ this.offsetY = offsetY; ++ this.offsetZ = offsetZ; ++ return this; ++ } ++ ++ /** ++ * Gets the Particle extra data. Varies by particle on how this is used ++ * ++ * @return the extra particle data ++ */ ++ public double extra() { ++ return this.extra; ++ } ++ ++ /** ++ * Sets the particle extra data. Varies by particle on how this is used ++ * ++ * @param extra the extra particle data ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder extra(final double extra) { ++ this.extra = extra; ++ return this; ++ } ++ ++ /** ++ * Gets the particle custom data. Varies by particle on how this is used ++ * ++ * @param The Particle data type ++ * @return the ParticleData for this particle ++ */ ++ public @Nullable T data() { ++ //noinspection unchecked ++ return (T) this.data; ++ } ++ ++ /** ++ * Sets the particle custom data. Varies by particle on how this is used ++ * ++ * @param data The new particle data ++ * @param The Particle data type ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder data(final @Nullable T data) { ++ this.data = data; ++ return this; ++ } ++ ++ /** ++ * @return whether the particle is forcefully shown to players. ++ */ ++ public boolean force() { ++ return this.force; ++ } ++ ++ /** ++ * Sets whether the particle is forcefully shown to the player. If forced, the particle will show ++ * faraway, as far as the player's view distance allows. If false, the particle will show ++ * according to the client's particle settings. ++ * ++ * @param force true to force, false for normal ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder force(final boolean force) { ++ this.force = force; ++ return this; ++ } ++ ++ /** ++ * Sets the particle Color. ++ * Only valid for particles with a data type of {@link Color} or {@link Particle.DustOptions}. ++ * ++ * @param color the new particle color ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder color(final @Nullable Color color) { ++ if (this.particle.getDataType() == Color.class) { ++ return this.data(color); ++ } ++ return this.color(color, 1); ++ } ++ ++ /** ++ * Sets the particle Color and size. ++ * Only valid for particles with a data type of {@link Particle.DustOptions}. ++ * ++ * @param color the new particle color ++ * @param size the size of the particle ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder color(final @Nullable Color color, final float size) { ++ if (this.particle.getDataType() != Particle.DustOptions.class && color != null) { ++ throw new IllegalStateException("The combination of Color and size cannot be set on this particle type."); ++ } ++ ++ // We don't officially support reusing these objects, but here we go ++ if (color == null) { ++ if (this.data instanceof Particle.DustOptions) { ++ return this.data(null); ++ } else { ++ return this; ++ } ++ } ++ ++ return this.data(new Particle.DustOptions(color, size)); ++ } ++ ++ /** ++ * Sets the particle Color. ++ * Only valid for particles with a data type of {@link Color} or {@link Particle.DustOptions}. ++ * ++ * @param r red color component ++ * @param g green color component ++ * @param b blue color component ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder color(final int r, final int g, final int b) { ++ return this.color(Color.fromRGB(r, g, b)); ++ } ++ ++ /** ++ * Sets the particle Color. ++ * Only valid for particles with a data type of {@link Color} or {@link Particle.DustOptions}. ++ *

      ++ * This method detects if the provided color integer is in RGB or ARGB format. ++ * If the alpha channel is zero, it treats the color as RGB. Otherwise, it treats it as ARGB. ++ * ++ * @param color an integer representing the color components. If the highest byte (alpha channel) is zero, ++ * the color is treated as RGB. Otherwise, it is treated as ARGB. ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder color(final int color) { ++ final int alpha = (color >> 24) & 0xFF; ++ if (alpha == 0) { ++ return this.color(Color.fromRGB(color)); ++ } ++ return this.color(Color.fromARGB(color)); ++ } ++ ++ /** ++ * Sets the particle Color. ++ * Only valid for particles with a data type of {@link Color} or {@link Particle.DustOptions}. ++ * ++ * @param a alpha color component ++ * @param r red color component ++ * @param g green color component ++ * @param b blue color component ++ * @return a reference to this object. ++ */ ++ public ParticleBuilder color(final int a, final int r, final int g, final int b) { ++ return this.color(Color.fromARGB(a, r, g, b)); ++ } ++ ++ /** ++ * Sets the particle Color Transition. ++ * Only valid for {@link Particle#DUST_COLOR_TRANSITION}. ++ * ++ * @param fromColor the new particle from color ++ * @param toColor the new particle to color ++ * @return a reference to this object. ++ * @throws IllegalArgumentException if the particle builder's {@link #particle()} isn't {@link Particle#DUST_COLOR_TRANSITION}. ++ */ ++ public ParticleBuilder colorTransition(final Color fromColor, final Color toColor) { ++ return this.colorTransition(fromColor, toColor, 1); ++ } ++ ++ /** ++ * Sets the particle Color Transition. ++ * Only valid for {@link Particle#DUST_COLOR_TRANSITION}. ++ * ++ * @param fromRed red color component for the "from" color ++ * @param fromGreen green color component for the "from" color ++ * @param fromBlue blue color component for the "from" color ++ * @param toRed red color component for the to color ++ * @param toGreen green color component for the to color ++ * @param toBlue blue color component for the to color ++ * @return a reference to this object. ++ * @throws IllegalArgumentException if the particle builder's {@link #particle()} isn't {@link Particle#DUST_COLOR_TRANSITION}. ++ */ ++ public ParticleBuilder colorTransition( ++ final int fromRed, final int fromGreen, final int fromBlue, ++ final int toRed, final int toGreen, final int toBlue ++ ) { ++ return this.colorTransition(Color.fromRGB(fromRed, fromGreen, fromBlue), Color.fromRGB(toRed, toGreen, toBlue)); ++ } ++ ++ /** ++ * Sets the particle Color Transition. ++ * Only valid for {@link Particle#DUST_COLOR_TRANSITION}. ++ * ++ * @param fromRgb an integer representing the red, green, and blue color components for the "from" color ++ * @param toRgb an integer representing the red, green, and blue color components for the "to" color ++ * @return a reference to this object. ++ * @throws IllegalArgumentException if the particle builder's {@link #particle()} isn't {@link Particle#DUST_COLOR_TRANSITION}. ++ */ ++ public ParticleBuilder colorTransition(final int fromRgb, final int toRgb) { ++ return this.colorTransition(Color.fromRGB(fromRgb), Color.fromRGB(toRgb)); ++ } ++ ++ /** ++ * Sets the particle Color Transition and size. ++ * Only valid for {@link Particle#DUST_COLOR_TRANSITION}. ++ * ++ * @param fromColor the new particle color for the "from" color. ++ * @param toColor the new particle color for the "to" color. ++ * @param size the size of the particle ++ * @return a reference to this object. ++ * @throws IllegalArgumentException if the particle builder's {@link #particle()} isn't {@link Particle#DUST_COLOR_TRANSITION}. ++ */ ++ public ParticleBuilder colorTransition(final Color fromColor, final Color toColor, final float size) { ++ Preconditions.checkArgument(fromColor != null, "Cannot define color transition with null fromColor."); ++ Preconditions.checkArgument(toColor != null, "Cannot define color transition with null toColor."); ++ Preconditions.checkArgument(this.particle() == Particle.DUST_COLOR_TRANSITION, "Can only define a color transition on particle DUST_COLOR_TRANSITION."); ++ return this.data(new Particle.DustTransition(fromColor, toColor, size)); ++ } ++ ++ @Override ++ public ParticleBuilder clone() { ++ try { ++ final ParticleBuilder builder = (ParticleBuilder) super.clone(); ++ if (this.location != null) builder.location = this.location.clone(); ++ if (this.receivers != null) builder.receivers = new ObjectArrayList<>(this.receivers); ++ return builder; ++ } catch (final CloneNotSupportedException e) { ++ throw new AssertionError(); ++ } ++ } ++} +diff --git a/src/main/java/org/bukkit/Particle.java b/src/main/java/org/bukkit/Particle.java +index ecf9f941e618608b98feaac46df3f10ec951c186..605588eb0613dedec9cba696503a85abf1a8b280 100644 +--- a/src/main/java/org/bukkit/Particle.java ++++ b/src/main/java/org/bukkit/Particle.java +@@ -206,6 +206,18 @@ public enum Particle implements Keyed { + return key; + } + ++ // Paper start - Particle API expansion ++ /** ++ * Creates a {@link com.destroystokyo.paper.ParticleBuilder} ++ * ++ * @return a {@link com.destroystokyo.paper.ParticleBuilder} for the particle ++ */ ++ @NotNull ++ public com.destroystokyo.paper.ParticleBuilder builder() { ++ return new com.destroystokyo.paper.ParticleBuilder(this); ++ } ++ // Paper end ++ + /** + * Options which can be applied to dust particles - a particle + * color and size. +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 79e5b429fe5660695e9fa603f8bc1fc1352b8950..f1d59d22d805cfe5ac2707c88a917bf17ae38b96 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -2948,7 +2948,57 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + * @param data the data to use for the particle or null, + * the type of this depends on {@link Particle#getDataType()} + */ +- public void spawnParticle(@NotNull Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data); ++ public default void spawnParticle(@NotNull Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data) { spawnParticle(particle, null, null, x, y, z, count, offsetX, offsetY, offsetZ, extra, data, true); }// Paper start - Expand Particle API ++ /** ++ * Spawns the particle (the number of times specified by count) ++ * at the target location. The position of each particle will be ++ * randomized positively and negatively by the offset parameters ++ * on each axis. ++ * ++ * @param particle the particle to spawn ++ * @param receivers List of players to receive the particles, or null for all in world ++ * @param source Source of the particles to be used in visibility checks, or null if no player source ++ * @param x the position on the x axis to spawn at ++ * @param y the position on the y axis to spawn at ++ * @param z the position on the z axis to spawn at ++ * @param count the number of particles ++ * @param offsetX the maximum random offset on the X axis ++ * @param offsetY the maximum random offset on the Y axis ++ * @param offsetZ the maximum random offset on the Z axis ++ * @param extra the extra data for this particle, depends on the ++ * particle used (normally speed) ++ * @param data the data to use for the particle or null, ++ * the type of this depends on {@link Particle#getDataType()} ++ * @param Type ++ */ ++ public default void spawnParticle(@NotNull Particle particle, @Nullable List receivers, @NotNull Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data) { spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data, true); } ++ /** ++ * Spawns the particle (the number of times specified by count) ++ * at the target location. The position of each particle will be ++ * randomized positively and negatively by the offset parameters ++ * on each axis. ++ * ++ * @param particle the particle to spawn ++ * @param receivers List of players to receive the particles, or null for all in world ++ * @param source Source of the particles to be used in visibility checks, or null if no player source ++ * @param x the position on the x axis to spawn at ++ * @param y the position on the y axis to spawn at ++ * @param z the position on the z axis to spawn at ++ * @param count the number of particles ++ * @param offsetX the maximum random offset on the X axis ++ * @param offsetY the maximum random offset on the Y axis ++ * @param offsetZ the maximum random offset on the Z axis ++ * @param extra the extra data for this particle, depends on the ++ * particle used (normally speed) ++ * @param data the data to use for the particle or null, ++ * the type of this depends on {@link Particle#getDataType()} ++ * @param Type ++ * @param force allows the particle to be seen further away from the player ++ * and shows to players using any vanilla client particle settings ++ */ ++ public void spawnParticle(@NotNull Particle particle, @Nullable List receivers, @Nullable Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data, boolean force); ++ // Paper end ++ + + /** + * Spawns the particle (the number of times specified by count) diff --git a/patches/api/0099-EndermanAttackPlayerEvent.patch b/patches/api/0099-EndermanAttackPlayerEvent.patch new file mode 100644 index 000000000000..f3abe83e89e9 --- /dev/null +++ b/patches/api/0099-EndermanAttackPlayerEvent.patch @@ -0,0 +1,114 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 1 May 2018 20:17:44 -0400 +Subject: [PATCH] EndermanAttackPlayerEvent + +Allow control over whether or not an enderman aggros a player. + +This allows you to override/extend the pumpkin/stare logic. + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..34adc77de2d1f06b2b10cc26b60240c6a3ef259c +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java +@@ -0,0 +1,99 @@ ++/* ++ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Enderman; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when an Enderman determines if it should attack a player or not. ++ *

      ++ * Starts off cancelled if the player is wearing a pumpkin head or is not looking ++ * at the Enderman, according to Vanilla rules. ++ */ ++@NullMarked ++public class EndermanAttackPlayerEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Player player; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EndermanAttackPlayerEvent(final Enderman entity, final Player player) { ++ super(entity); ++ this.player = player; ++ } ++ ++ /** ++ * The enderman considering attacking ++ * ++ * @return The enderman considering attacking ++ */ ++ @Override ++ public Enderman getEntity() { ++ return (Enderman) super.getEntity(); ++ } ++ ++ /** ++ * The player the Enderman is considering attacking ++ * ++ * @return The player the Enderman is considering attacking ++ */ ++ public Player getPlayer() { ++ return this.player; ++ } ++ ++ /** ++ * @return If cancelled, the enderman will not attack ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *
      ++ * Cancels if the Enderman will attack this player ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0099-Location.isChunkLoaded-API.patch b/patches/api/0099-Location.isChunkLoaded-API.patch deleted file mode 100644 index 426944c4f99c..000000000000 --- a/patches/api/0099-Location.isChunkLoaded-API.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 30 Apr 2018 19:27:31 -0400 -Subject: [PATCH] Location.isChunkLoaded() API - - -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index 7c4db051472fb6a6c6d24092dc6f75487356690a..3be91f6c9b355c9e8562796d719f5a6ce566d85a 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -533,6 +533,7 @@ public class Location implements Cloneable, ConfigurationSerializable { - return this; - } - -+ public boolean isChunkLoaded() { return this.getWorld().isChunkLoaded(locToBlock(x) >> 4, locToBlock(z) >> 4); } // Paper - @Override - public boolean equals(Object obj) { - if (obj == null) { diff --git a/patches/api/0100-Expand-World.spawnParticle-API-and-add-Builder.patch b/patches/api/0100-Expand-World.spawnParticle-API-and-add-Builder.patch deleted file mode 100644 index bd90d2165d15..000000000000 --- a/patches/api/0100-Expand-World.spawnParticle-API-and-add-Builder.patch +++ /dev/null @@ -1,586 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 29 Aug 2017 23:58:48 -0400 -Subject: [PATCH] Expand World.spawnParticle API and add Builder - -Adds ability to control who receives it and who is the source/sender (vanish API) -the standard API is to send the packet to everyone in the world, which is ineffecient. - -This adds a new Builder API which is much friendlier to use. - -diff --git a/src/main/java/com/destroystokyo/paper/ParticleBuilder.java b/src/main/java/com/destroystokyo/paper/ParticleBuilder.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f45b8cfd1611345e8d81ecb8297a586f05eb5dc6 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/ParticleBuilder.java -@@ -0,0 +1,485 @@ -+package com.destroystokyo.paper; -+ -+import com.google.common.collect.Lists; -+import org.bukkit.Color; -+import org.bukkit.Location; -+import org.bukkit.Particle; -+import org.bukkit.World; -+import org.bukkit.entity.Player; -+import org.bukkit.util.NumberConversions; -+ -+import java.util.Collection; -+import java.util.List; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Helps prepare a particle to be sent to players. -+ * -+ * Usage of the builder is preferred over the super long {@link World#spawnParticle(Particle, Location, int, double, double, double, double, Object)} API -+ */ -+public class ParticleBuilder { -+ -+ private Particle particle; -+ private List receivers; -+ private Player source; -+ private Location location; -+ private int count = 1; -+ private double offsetX = 0, offsetY = 0, offsetZ = 0; -+ private double extra = 1; -+ private Object data; -+ private boolean force = true; -+ -+ public ParticleBuilder(@NotNull Particle particle) { -+ this.particle = particle; -+ } -+ -+ /** -+ * Sends the particle to all receiving players (or all). This method is safe to use -+ * Asynchronously -+ * -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder spawn() { -+ if (this.location == null) { -+ throw new IllegalStateException("Please specify location for this particle"); -+ } -+ location.getWorld().spawnParticle(particle, receivers, source, -+ location.getX(), location.getY(), location.getZ(), -+ count, offsetX, offsetY, offsetZ, extra, data, force -+ ); -+ return this; -+ } -+ -+ /** -+ * @return The particle going to be sent -+ */ -+ @NotNull -+ public Particle particle() { -+ return particle; -+ } -+ -+ /** -+ * Changes what particle will be sent -+ * -+ * @param particle The particle -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder particle(@NotNull Particle particle) { -+ this.particle = particle; -+ return this; -+ } -+ -+ /** -+ * @return List of players who will receive the particle, or null for all in world -+ */ -+ @Nullable -+ public List receivers() { -+ return receivers; -+ } -+ -+ /** -+ * Example use: -+ * -+ * builder.receivers(16); if (builder.hasReceivers()) { sendParticleAsync(builder); } -+ * -+ * @return If this particle is going to be sent to someone -+ */ -+ public boolean hasReceivers() { -+ return (receivers == null && !location.getWorld().getPlayers().isEmpty()) || ( -+ receivers != null && !receivers.isEmpty()); -+ } -+ -+ /** -+ * Sends this particle to all players in the world. This is rather silly and you should likely not -+ * be doing this. -+ * -+ * Just be a logical person and use receivers by radius or collection. -+ * -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder allPlayers() { -+ this.receivers = null; -+ return this; -+ } -+ -+ /** -+ * @param receivers List of players to receive this particle, or null for all players in the -+ * world -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder receivers(@Nullable List receivers) { -+ // Had to keep this as we first made API List<> and not Collection, but removing this may break plugins compiled on older jars -+ // TODO: deprecate? -+ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null; -+ return this; -+ } -+ -+ /** -+ * @param receivers List of players to receive this particle, or null for all players in the -+ * world -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder receivers(@Nullable Collection receivers) { -+ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null; -+ return this; -+ } -+ -+ /** -+ * @param receivers List of players to be receive this particle, or null for all players in the -+ * world -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder receivers(@Nullable Player... receivers) { -+ this.receivers = receivers != null ? Lists.newArrayList(receivers) : null; -+ return this; -+ } -+ -+ /** -+ * Selects all players within a cuboid selection around the particle location, within the -+ * specified bounding box. If you want a more spherical check, see {@link #receivers(int, -+ * boolean)} -+ * -+ * @param radius amount to add on all axis -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder receivers(int radius) { -+ return receivers(radius, radius); -+ } -+ -+ /** -+ * Selects all players within the specified radius around the particle location. If byDistance is -+ * false, behavior uses cuboid selection the same as {@link #receivers(int, int)} If byDistance is -+ * true, radius is tested by distance in a spherical shape -+ * -+ * @param radius amount to add on each axis -+ * @param byDistance true to use a spherical radius, false to use a cuboid -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder receivers(int radius, boolean byDistance) { -+ if (!byDistance) { -+ return receivers(radius, radius, radius); -+ } else { -+ this.receivers = Lists.newArrayList(); -+ for (Player nearbyPlayer : location.getWorld() -+ .getNearbyPlayers(location, radius, radius, radius)) { -+ Location loc = nearbyPlayer.getLocation(); -+ double x = NumberConversions.square(location.getX() - loc.getX()); -+ double y = NumberConversions.square(location.getY() - loc.getY()); -+ double z = NumberConversions.square(location.getZ() - loc.getZ()); -+ if (Math.sqrt(x + y + z) > radius) { -+ continue; -+ } -+ this.receivers.add(nearbyPlayer); -+ } -+ return this; -+ } -+ } -+ -+ /** -+ * Selects all players within a cuboid selection around the particle location, within the -+ * specified bounding box. Allows specifying a different Y size than X and Z If you want a more -+ * cylinder check, see {@link #receivers(int, int, boolean)} If you want a more spherical check, -+ * see {@link #receivers(int, boolean)} -+ * -+ * @param xzRadius amount to add on the x/z axis -+ * @param yRadius amount to add on the y axis -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder receivers(int xzRadius, int yRadius) { -+ return receivers(xzRadius, yRadius, xzRadius); -+ } -+ -+ /** -+ * Selects all players within the specified radius around the particle location. If byDistance is -+ * false, behavior uses cuboid selection the same as {@link #receivers(int, int)} If byDistance is -+ * true, radius is tested by distance on the y plane and on the x/z plane, in a cylinder shape. -+ * -+ * @param xzRadius amount to add on the x/z axis -+ * @param yRadius amount to add on the y axis -+ * @param byDistance true to use a cylinder shape, false to use cuboid -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder receivers(int xzRadius, int yRadius, boolean byDistance) { -+ if (!byDistance) { -+ return receivers(xzRadius, yRadius, xzRadius); -+ } else { -+ this.receivers = Lists.newArrayList(); -+ for (Player nearbyPlayer : location.getWorld() -+ .getNearbyPlayers(location, xzRadius, yRadius, xzRadius)) { -+ Location loc = nearbyPlayer.getLocation(); -+ if (Math.abs(loc.getY() - this.location.getY()) > yRadius) { -+ continue; -+ } -+ double x = NumberConversions.square(location.getX() - loc.getX()); -+ double z = NumberConversions.square(location.getZ() - loc.getZ()); -+ if (x + z > NumberConversions.square(xzRadius)) { -+ continue; -+ } -+ this.receivers.add(nearbyPlayer); -+ } -+ return this; -+ } -+ } -+ -+ /** -+ * Selects all players within a cuboid selection around the particle location, within the -+ * specified bounding box. If you want a more cylinder check, see {@link #receivers(int, int, -+ * boolean)} If you want a more spherical check, see {@link #receivers(int, boolean)} -+ * -+ * @param xRadius amount to add on the x axis -+ * @param yRadius amount to add on the y axis -+ * @param zRadius amount to add on the z axis -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder receivers(int xRadius, int yRadius, int zRadius) { -+ if (location == null) { -+ throw new IllegalStateException("Please set location first"); -+ } -+ return receivers(location.getWorld().getNearbyPlayers(location, xRadius, yRadius, zRadius)); -+ } -+ -+ /** -+ * @return The player considered the source of this particle (for Visibility concerns), or null -+ */ -+ @Nullable -+ public Player source() { -+ return source; -+ } -+ -+ /** -+ * Sets the source of this particle for visibility concerns (Vanish API) -+ * -+ * @param source The player who is considered the source -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder source(@Nullable Player source) { -+ this.source = source; -+ return this; -+ } -+ -+ /** -+ * @return Location of where the particle will spawn -+ */ -+ @Nullable -+ public Location location() { -+ return location; -+ } -+ -+ /** -+ * Sets the location of where to spawn the particle -+ * -+ * @param location The location of the particle -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder location(@NotNull Location location) { -+ this.location = location.clone(); -+ return this; -+ } -+ -+ /** -+ * Sets the location of where to spawn the particle -+ * -+ * @param world World to spawn particle in -+ * @param x X location -+ * @param y Y location -+ * @param z Z location -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder location(@NotNull World world, double x, double y, double z) { -+ this.location = new Location(world, x, y, z); -+ return this; -+ } -+ -+ /** -+ * @return Number of particles to spawn -+ */ -+ public int count() { -+ return count; -+ } -+ -+ /** -+ * Sets the number of particles to spawn -+ * -+ * @param count Number of particles -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder count(int count) { -+ this.count = count; -+ return this; -+ } -+ -+ /** -+ * Particle offset X. Varies by particle on how this is used -+ * -+ * @return Particle offset X. -+ */ -+ public double offsetX() { -+ return offsetX; -+ } -+ -+ /** -+ * Particle offset Y. Varies by particle on how this is used -+ * -+ * @return Particle offset Y. -+ */ -+ public double offsetY() { -+ return offsetY; -+ } -+ -+ /** -+ * Particle offset Z. Varies by particle on how this is used -+ * -+ * @return Particle offset Z. -+ */ -+ public double offsetZ() { -+ return offsetZ; -+ } -+ -+ /** -+ * Sets the particle offset. Varies by particle on how this is used -+ * -+ * @param offsetX Particle offset X -+ * @param offsetY Particle offset Y -+ * @param offsetZ Particle offset Z -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder offset(double offsetX, double offsetY, double offsetZ) { -+ this.offsetX = offsetX; -+ this.offsetY = offsetY; -+ this.offsetZ = offsetZ; -+ return this; -+ } -+ -+ /** -+ * Gets the Particle extra data. Varies by particle on how this is used -+ * -+ * @return the extra particle data -+ */ -+ public double extra() { -+ return extra; -+ } -+ -+ /** -+ * Sets the particle extra data. Varies by particle on how this is used -+ * -+ * @param extra the extra particle data -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder extra(double extra) { -+ this.extra = extra; -+ return this; -+ } -+ -+ /** -+ * Gets the particle custom data. Varies by particle on how this is used -+ * -+ * @param The Particle data type -+ * @return the ParticleData for this particle -+ */ -+ @Nullable -+ public T data() { -+ //noinspection unchecked -+ return (T) data; -+ } -+ -+ /** -+ * Sets the particle custom data. Varies by particle on how this is used -+ * -+ * @param data The new particle data -+ * @param The Particle data type -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder data(@Nullable T data) { -+ this.data = data; -+ return this; -+ } -+ -+ /** -+ * @return whether the particle is forcefully shown to players. -+ */ -+ public boolean force() { -+ return force; -+ } -+ -+ /** -+ * Sets whether the particle is forcefully shown to the player. If forced, the particle will show -+ * faraway, as far as the player's view distance allows. If false, the particle will show -+ * according to the client's particle settings. -+ * -+ * @param force true to force, false for normal -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder force(boolean force) { -+ this.force = force; -+ return this; -+ } -+ -+ /** -+ * Sets the particle Color. Only valid for REDSTONE. -+ * -+ * @param color the new particle color -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder color(@Nullable Color color) { -+ return color(color, 1); -+ } -+ -+ /** -+ * Sets the particle Color and size. Only valid for REDSTONE. -+ * -+ * @param color the new particle color -+ * @param size the size of the particle -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder color(@Nullable Color color, float size) { -+ if (particle != Particle.REDSTONE && color != null) { -+ throw new IllegalStateException("Color may only be set on REDSTONE"); -+ } -+ -+ // We don't officially support reusing these objects, but here we go -+ if (color == null) { -+ if (data instanceof Particle.DustOptions) { -+ return data(null); -+ } else { -+ return this; -+ } -+ } -+ -+ return data(new Particle.DustOptions(color, size)); -+ } -+ -+ /** -+ * Sets the particle Color. -+ * Only valid for REDSTONE. -+ * @param r red color component -+ * @param g green color component -+ * @param b blue color component -+ * @return a reference to this object. -+ */ -+ @NotNull -+ public ParticleBuilder color(int r, int g, int b) { -+ return color(Color.fromRGB(r, g, b)); -+ } -+} -diff --git a/src/main/java/org/bukkit/Particle.java b/src/main/java/org/bukkit/Particle.java -index 9f646171b3ac617fb5217d5ab9c106c3100a8c8d..2315fffc4a1a5bebc50a703e9df59df8121c2200 100644 ---- a/src/main/java/org/bukkit/Particle.java -+++ b/src/main/java/org/bukkit/Particle.java -@@ -160,6 +160,17 @@ public enum Particle { - return dataType; - } - -+ // Paper start - Particle API expansion -+ /** -+ * Creates a {@link com.destroystokyo.paper.ParticleBuilder} -+ * -+ * @return a {@link com.destroystokyo.paper.ParticleBuilder} for the particle -+ */ -+ @NotNull -+ public com.destroystokyo.paper.ParticleBuilder builder() { -+ return new com.destroystokyo.paper.ParticleBuilder(this); -+ } -+ // Paper end - /** - * Options which can be applied to redstone dust particles - a particle - * color and size. -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index cf7baa9cd691b02aeaa4d94d5e999e661e003a44..9ffe69abd0aa706d56e4eff3587cb453a437ba26 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -2787,7 +2787,57 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - * @param data the data to use for the particle or null, - * the type of this depends on {@link Particle#getDataType()} - */ -- public void spawnParticle(@NotNull Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data); -+ public default void spawnParticle(@NotNull Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data) { spawnParticle(particle, null, null, x, y, z, count, offsetX, offsetY, offsetZ, extra, data, true); }// Paper start - Expand Particle API -+ /** -+ * Spawns the particle (the number of times specified by count) -+ * at the target location. The position of each particle will be -+ * randomized positively and negatively by the offset parameters -+ * on each axis. -+ * -+ * @param particle the particle to spawn -+ * @param receivers List of players to receive the particles, or null for all in world -+ * @param source Source of the particles to be used in visibility checks, or null if no player source -+ * @param x the position on the x axis to spawn at -+ * @param y the position on the y axis to spawn at -+ * @param z the position on the z axis to spawn at -+ * @param count the number of particles -+ * @param offsetX the maximum random offset on the X axis -+ * @param offsetY the maximum random offset on the Y axis -+ * @param offsetZ the maximum random offset on the Z axis -+ * @param extra the extra data for this particle, depends on the -+ * particle used (normally speed) -+ * @param data the data to use for the particle or null, -+ * the type of this depends on {@link Particle#getDataType()} -+ * @param Type -+ */ -+ public default void spawnParticle(@NotNull Particle particle, @Nullable List receivers, @NotNull Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data) { spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data, true); } -+ /** -+ * Spawns the particle (the number of times specified by count) -+ * at the target location. The position of each particle will be -+ * randomized positively and negatively by the offset parameters -+ * on each axis. -+ * -+ * @param particle the particle to spawn -+ * @param receivers List of players to receive the particles, or null for all in world -+ * @param source Source of the particles to be used in visibility checks, or null if no player source -+ * @param x the position on the x axis to spawn at -+ * @param y the position on the y axis to spawn at -+ * @param z the position on the z axis to spawn at -+ * @param count the number of particles -+ * @param offsetX the maximum random offset on the X axis -+ * @param offsetY the maximum random offset on the Y axis -+ * @param offsetZ the maximum random offset on the Z axis -+ * @param extra the extra data for this particle, depends on the -+ * particle used (normally speed) -+ * @param data the data to use for the particle or null, -+ * the type of this depends on {@link Particle#getDataType()} -+ * @param Type -+ * @param force allows the particle to be seen further away from the player -+ * and shows to players using any vanilla client particle settings -+ */ -+ public void spawnParticle(@NotNull Particle particle, @Nullable List receivers, @Nullable Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data, boolean force); -+ // Paper end -+ - - /** - * Spawns the particle (the number of times specified by count) diff --git a/patches/api/0100-WitchConsumePotionEvent.patch b/patches/api/0100-WitchConsumePotionEvent.patch new file mode 100644 index 000000000000..3dd9e13caeb3 --- /dev/null +++ b/patches/api/0100-WitchConsumePotionEvent.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 16 May 2018 20:26:16 -0400 +Subject: [PATCH] WitchConsumePotionEvent + +Fires when a witch consumes the potion in their hand + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..43ee765dedf5001fadf1af317b6ab323fde34851 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java +@@ -0,0 +1,71 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Witch; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Fired when a witch consumes the potion in their hand to buff themselves. ++ */ ++@NullMarked ++public class WitchConsumePotionEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private @Nullable ItemStack potion; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public WitchConsumePotionEvent(final Witch witch, final @Nullable ItemStack potion) { ++ super(witch); ++ this.potion = potion; ++ } ++ ++ @Override ++ public Witch getEntity() { ++ return (Witch) super.getEntity(); ++ } ++ ++ /** ++ * @return the potion the witch will consume and have the effects applied. ++ */ ++ public @Nullable ItemStack getPotion() { ++ return this.potion; ++ } ++ ++ /** ++ * Sets the potion to be consumed and applied to the witch. ++ * ++ * @param potion The potion ++ */ ++ public void setPotion(final @Nullable ItemStack potion) { ++ this.potion = potion != null ? potion.clone() : null; ++ } ++ ++ /** ++ * @return Event was cancelled or potion was {@code null} ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled || this.potion == null; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0101-EndermanAttackPlayerEvent.patch b/patches/api/0101-EndermanAttackPlayerEvent.patch deleted file mode 100644 index 9f3e105c9d17..000000000000 --- a/patches/api/0101-EndermanAttackPlayerEvent.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 1 May 2018 20:17:44 -0400 -Subject: [PATCH] EndermanAttackPlayerEvent - -Allow control over whether or not an enderman aggros a player. - -This allows you to override/extend the pumpkin/stare logic. - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f530a3d9314e17d1da896cac633f6a422258d9a9 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EndermanAttackPlayerEvent.java -@@ -0,0 +1,101 @@ -+/* -+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be -+ * included in all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Enderman; -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when an Enderman determines if it should attack a player or not. -+ * Starts off cancelled if the player is wearing a pumpkin head or is not looking -+ * at the Enderman, according to Vanilla rules. -+ * -+ */ -+public class EndermanAttackPlayerEvent extends EntityEvent implements Cancellable { -+ @NotNull private final Player player; -+ -+ public EndermanAttackPlayerEvent(@NotNull Enderman entity, @NotNull Player player) { -+ super(entity); -+ this.player = player; -+ } -+ -+ /** -+ * The enderman considering attacking -+ * -+ * @return The enderman considering attacking -+ */ -+ @NotNull -+ @Override -+ public Enderman getEntity() { -+ return (Enderman) super.getEntity(); -+ } -+ -+ /** -+ * The player the Enderman is considering attacking -+ * -+ * @return The player the Enderman is considering attacking -+ */ -+ @NotNull -+ public Player getPlayer() { -+ return player; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ /** -+ * -+ * @return If cancelled, the enderman will not attack -+ */ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * Cancels if the Enderman will attack this player -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0101-WitchThrowPotionEvent.patch b/patches/api/0101-WitchThrowPotionEvent.patch new file mode 100644 index 000000000000..0ffef49ae498 --- /dev/null +++ b/patches/api/0101-WitchThrowPotionEvent.patch @@ -0,0 +1,94 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 16 May 2018 20:39:09 -0400 +Subject: [PATCH] WitchThrowPotionEvent + +Fired when a witch throws a potion at a player + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..02395582b680f4baa3dc2251a8a79f41241b96ec +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java +@@ -0,0 +1,81 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.entity.Witch; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Fired when a witch throws a potion at a player ++ */ ++@NullMarked ++public class WitchThrowPotionEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final LivingEntity target; ++ private @Nullable ItemStack potion; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public WitchThrowPotionEvent(final Witch witch, final LivingEntity target, final @Nullable ItemStack potion) { ++ super(witch); ++ this.target = target; ++ this.potion = potion; ++ } ++ ++ @Override ++ public Witch getEntity() { ++ return (Witch) super.getEntity(); ++ } ++ ++ /** ++ * @return The target of the potion ++ */ ++ public LivingEntity getTarget() { ++ return this.target; ++ } ++ ++ /** ++ * @return The potion the witch will throw at a player ++ */ ++ public @Nullable ItemStack getPotion() { ++ return this.potion; ++ } ++ ++ /** ++ * Sets the potion to be thrown at a player ++ * ++ * @param potion The potion ++ */ ++ public void setPotion(final @Nullable ItemStack potion) { ++ this.potion = potion != null ? potion.clone() : null; ++ } ++ ++ /** ++ * @return Event was cancelled or potion was {@code null} ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled || this.potion == null; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0102-Close-Plugin-Class-Loaders-on-Disable.patch b/patches/api/0102-Close-Plugin-Class-Loaders-on-Disable.patch deleted file mode 100644 index c37902cb6a8b..000000000000 --- a/patches/api/0102-Close-Plugin-Class-Loaders-on-Disable.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 1 May 2018 21:33:35 -0400 -Subject: [PATCH] Close Plugin Class Loaders on Disable - -This should close more memory leaks from /reload and disabling plugins, -by closing the class loader and the jar file. - -Note: This patch is no longer necessary as upstream now also closes -PluginClassLoaders on disable. This patch is now only to keep around -API methods it previously added, and to add back the log message when a -PluginClassLoader fails to disable, as upstream decided to ignore the -exception. - -diff --git a/src/main/java/org/bukkit/plugin/PluginLoader.java b/src/main/java/org/bukkit/plugin/PluginLoader.java -index a88733f1cd1ddb5d85ab1b0e6af4fd5b80bbc1c6..256e440e699942e3c9da4205bb964bdc10ec92c4 100644 ---- a/src/main/java/org/bukkit/plugin/PluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/PluginLoader.java -@@ -77,4 +77,21 @@ public interface PluginLoader { - * @param plugin Plugin to disable - */ - public void disablePlugin(@NotNull Plugin plugin); -+ -+ // Paper start - close Classloader on disable -+ /** -+ * This method is no longer useful as upstream has -+ * made it so plugin classloaders are always closed on disable. -+ * Use {@link #disablePlugin(Plugin)} instead. -+ * -+ * @param plugin Plugin to disable -+ * @param closeClassloader unused -+ * @deprecated Classloader is always closed by upstream now. -+ */ -+ @Deprecated(forRemoval = true) -+ // provide default to allow other PluginLoader implementations to work -+ default public void disablePlugin(@NotNull Plugin plugin, boolean closeClassloader) { -+ disablePlugin(plugin); -+ } -+ // Paper end - close Classloader on disable - } -diff --git a/src/main/java/org/bukkit/plugin/PluginManager.java b/src/main/java/org/bukkit/plugin/PluginManager.java -index 41e26451fe12d8e6e0ef73c85731b24b4e3f200c..0d1b20f2b5580ea5505ccc2f003925dbcee67199 100644 ---- a/src/main/java/org/bukkit/plugin/PluginManager.java -+++ b/src/main/java/org/bukkit/plugin/PluginManager.java -@@ -161,6 +161,22 @@ public interface PluginManager { - */ - public void disablePlugin(@NotNull Plugin plugin); - -+ // Paper start - close Classloader on disable -+ /** -+ * This method is no longer useful as upstream has -+ * made it so plugin classloaders are always closed on disable. -+ * Use {@link #disablePlugin(Plugin)} instead. -+ * -+ * @param plugin Plugin to disable -+ * @param closeClassloader unused -+ * @deprecated Classloader is always closed by upstream now. -+ */ -+ @Deprecated(forRemoval = true) -+ public default void disablePlugin(@NotNull Plugin plugin, boolean closeClassloader) { -+ this.disablePlugin(plugin); -+ } -+ // Paper end - close Classloader on disable -+ - /** - * Gets a {@link Permission} from its fully qualified name - * -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index efe0e5e6b43c50c6a41ee3baa44beb7d883b551a..6b38b14bfd73f3b7d06b6f747d60373cedf1fa6f 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -503,6 +503,21 @@ public final class SimplePluginManager implements PluginManager { - } - } - -+ // Paper start -+ /** -+ * This method is no longer useful as upstream has -+ * made it so plugin classloaders are always closed on disable. -+ * Use {@link #disablePlugins()} instead. -+ * -+ * @param closeClassloaders unused -+ * @deprecated Classloader is always closed by upstream now. -+ */ -+ @Deprecated(forRemoval = true) -+ public void disablePlugins(boolean closeClassloaders) { -+ this.disablePlugins(); -+ } -+ // Paper end -+ - @Override - public void disablePlugin(@NotNull final Plugin plugin) { - if (plugin.isEnabled()) { -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index 5d74fab03a15d7099e5dacb780eade4cdc185797..032ed2aba7d47144d241d616ba27489ce22d6fea 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -366,6 +366,7 @@ public final class JavaPluginLoader implements PluginLoader { - loader.close(); - } catch (IOException ex) { - // -+ this.server.getLogger().log(Level.WARNING, "Error closing the PluginClassLoader for '" + plugin.getDescription().getFullName() + "'", ex); // Paper - log exception - } - } - } diff --git a/patches/api/0102-Location.toBlockLocation-toCenterLocation.patch b/patches/api/0102-Location.toBlockLocation-toCenterLocation.patch new file mode 100644 index 000000000000..890edb723c04 --- /dev/null +++ b/patches/api/0102-Location.toBlockLocation-toCenterLocation.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 24 May 2018 21:01:13 -0400 +Subject: [PATCH] Location.toBlockLocation/toCenterLocation() + +Convert location objects to their block coordinates, or the center of the block + +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index 7c7d2b2dc082fd3b5681a15a600422ae3937e2e1..3bcc8266d6b1de3c3f964ffad9820bf1b94bbd00 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -534,6 +534,32 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + } + + public boolean isChunkLoaded() { return this.getWorld().isChunkLoaded(locToBlock(x) >> 4, locToBlock(z) >> 4); } // Paper ++ ++ // Paper start - expand Location API ++ /** ++ * @return A new location where X/Y/Z are on the Block location (integer value of X/Y/Z) ++ */ ++ @NotNull ++ public Location toBlockLocation() { ++ Location blockLoc = clone(); ++ blockLoc.setX(getBlockX()); ++ blockLoc.setY(getBlockY()); ++ blockLoc.setZ(getBlockZ()); ++ return blockLoc; ++ } ++ /** ++ * @return A new location where X/Y/Z are the center of the block ++ */ ++ @NotNull ++ public Location toCenterLocation() { ++ Location centerLoc = clone(); ++ centerLoc.setX(getBlockX() + 0.5); ++ centerLoc.setY(getBlockY() + 0.5); ++ centerLoc.setZ(getBlockZ() + 0.5); ++ return centerLoc; ++ } ++ // Paper end - expand Location API ++ + @Override + public boolean equals(Object obj) { + if (obj == null) { diff --git a/patches/api/0103-PotionEffect-clone-methods.patch b/patches/api/0103-PotionEffect-clone-methods.patch new file mode 100644 index 000000000000..a59479b404a1 --- /dev/null +++ b/patches/api/0103-PotionEffect-clone-methods.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 3 Jun 2018 04:10:13 -0400 +Subject: [PATCH] PotionEffect clone methods + + +diff --git a/src/main/java/org/bukkit/potion/PotionEffect.java b/src/main/java/org/bukkit/potion/PotionEffect.java +index 6478faee913d9a3bee0beb83a2cc4ecfa4f8df90..0d60a1b740199783d3fcb775f190ee85bd84696b 100644 +--- a/src/main/java/org/bukkit/potion/PotionEffect.java ++++ b/src/main/java/org/bukkit/potion/PotionEffect.java +@@ -109,6 +109,33 @@ public class PotionEffect implements ConfigurationSerializable { + this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true))); + } + ++ // Paper start ++ @NotNull ++ public PotionEffect withType(@NotNull PotionEffectType type) { ++ return new PotionEffect(type, duration, amplifier, ambient, particles, icon); ++ } ++ @NotNull ++ public PotionEffect withDuration(int duration) { ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ } ++ @NotNull ++ public PotionEffect withAmplifier(int amplifier) { ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ } ++ @NotNull ++ public PotionEffect withAmbient(boolean ambient) { ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ } ++ @NotNull ++ public PotionEffect withParticles(boolean particles) { ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ } ++ @NotNull ++ public PotionEffect withIcon(boolean icon) { ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ } ++ // Paper end ++ + @NotNull + private static PotionEffectType getEffectType(@NotNull Map map) { + PotionEffectType effect; diff --git a/patches/api/0103-WitchConsumePotionEvent.patch b/patches/api/0103-WitchConsumePotionEvent.patch deleted file mode 100644 index fab6106411a2..000000000000 --- a/patches/api/0103-WitchConsumePotionEvent.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 16 May 2018 20:26:16 -0400 -Subject: [PATCH] WitchConsumePotionEvent - -Fires when a witch consumes the potion in their hand - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fbbace36d69373046a7f3618ed5c1c1318b489b9 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchConsumePotionEvent.java -@@ -0,0 +1,70 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Witch; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Fired when a witch consumes the potion in their hand to buff themselves. -+ */ -+public class WitchConsumePotionEvent extends EntityEvent implements Cancellable { -+ @Nullable private ItemStack potion; -+ -+ public WitchConsumePotionEvent(@NotNull Witch witch, @Nullable ItemStack potion) { -+ super(witch); -+ this.potion = potion; -+ } -+ -+ @NotNull -+ @Override -+ public Witch getEntity() { -+ return (Witch) super.getEntity(); -+ } -+ -+ /** -+ * @return the potion the witch will consume and have the effects applied. -+ */ -+ @Nullable -+ public ItemStack getPotion() { -+ return potion; -+ } -+ -+ /** -+ * Sets the potion to be consumed and applied to the witch. -+ * @param potion The potion -+ */ -+ public void setPotion(@Nullable ItemStack potion) { -+ this.potion = potion != null ? potion.clone() : null; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ /** -+ * @return Event was cancelled or potion was null -+ */ -+ @Override -+ public boolean isCancelled() { -+ return cancelled || potion == null; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6ef6367b67261c2b653a97322b9703a9409b3499 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java -@@ -0,0 +1,33 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+ -+public class WitchThrowPotionEvent extends Event implements Cancellable { -+ public WitchThrowPotionEvent() { -+ } -+ -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0104-WitchReadyPotionEvent.patch b/patches/api/0104-WitchReadyPotionEvent.patch new file mode 100644 index 000000000000..ee212c20f564 --- /dev/null +++ b/patches/api/0104-WitchReadyPotionEvent.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 5 Jun 2018 22:47:08 -0400 +Subject: [PATCH] WitchReadyPotionEvent + +Control what potion the witch readies to use + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bda48563cc9e00bd9a537ddec0c730b5e784c9a4 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java +@@ -0,0 +1,65 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Witch; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@NullMarked ++public class WitchReadyPotionEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private @Nullable ItemStack potion; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public WitchReadyPotionEvent(final Witch witch, final @Nullable ItemStack potion) { ++ super(witch); ++ this.potion = potion; ++ } ++ ++ @Override ++ public Witch getEntity() { ++ return (Witch) super.getEntity(); ++ } ++ ++ /** ++ * @return the potion the witch is readying to use ++ */ ++ public @Nullable ItemStack getPotion() { ++ return this.potion; ++ } ++ ++ /** ++ * Sets the potion the which is going to hold and use ++ * ++ * @param potion The potion ++ */ ++ public void setPotion(final @Nullable ItemStack potion) { ++ this.potion = potion != null ? potion.clone() : null; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0104-WitchThrowPotionEvent.patch b/patches/api/0104-WitchThrowPotionEvent.patch deleted file mode 100644 index a5dfe42f3569..000000000000 --- a/patches/api/0104-WitchThrowPotionEvent.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 16 May 2018 20:39:09 -0400 -Subject: [PATCH] WitchThrowPotionEvent - -Fired when a witch throws a potion at a player - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java -index 6ef6367b67261c2b653a97322b9703a9409b3499..688a596aa2b925651a92bf092e1ef4d77a47258c 100644 ---- a/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java -+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchThrowPotionEvent.java -@@ -1,29 +1,77 @@ - package com.destroystokyo.paper.event.entity; - -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.entity.Witch; - import org.bukkit.event.Cancellable; --import org.bukkit.event.Event; - import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; - --public class WitchThrowPotionEvent extends Event implements Cancellable { -- public WitchThrowPotionEvent() { -+/** -+ * Fired when a witch throws a potion at a player -+ */ -+public class WitchThrowPotionEvent extends EntityEvent implements Cancellable { -+ @NotNull private final LivingEntity target; -+ @Nullable private ItemStack potion; -+ -+ public WitchThrowPotionEvent(@NotNull Witch witch, @NotNull LivingEntity target, @Nullable ItemStack potion) { -+ super(witch); -+ this.target = target; -+ this.potion = potion; - } - -+ @NotNull -+ @Override -+ public Witch getEntity() { -+ return (Witch) super.getEntity(); -+ } -+ -+ /** -+ * @return The target of the potion -+ */ -+ @NotNull -+ public LivingEntity getTarget() { -+ return target; -+ } -+ -+ /** -+ * @return The potion the witch will throw at a player -+ */ -+ @Nullable -+ public ItemStack getPotion() { -+ return potion; -+ } -+ -+ /** -+ * Sets the potion to be thrown at a player -+ * @param potion The potion -+ */ -+ public void setPotion(@Nullable ItemStack potion) { -+ this.potion = potion != null ? potion.clone() : null; -+ } - - private static final HandlerList handlers = new HandlerList(); - -+ @NotNull - public HandlerList getHandlers() { - return handlers; - } - -+ @NotNull - public static HandlerList getHandlerList() { - return handlers; - } - - private boolean cancelled = false; - -+ /** -+ * @return Event was cancelled or potion was null -+ */ - @Override - public boolean isCancelled() { -- return cancelled; -+ return cancelled || potion == null; - } - - @Override diff --git a/patches/api/0105-ItemStack-getMaxItemUseDuration.patch b/patches/api/0105-ItemStack-getMaxItemUseDuration.patch new file mode 100644 index 000000000000..4b354180a6ec --- /dev/null +++ b/patches/api/0105-ItemStack-getMaxItemUseDuration.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 5 Jun 2018 22:59:50 -0400 +Subject: [PATCH] ItemStack#getMaxItemUseDuration + +Allows you to determine how long it takes to use a usable/consumable item + +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index e66a958bc36ac774081d5e71966f312ebb8228d9..a3de566c8f0ea4dcdb158f9ef0876a3b14429140 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -670,5 +670,21 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + public String getI18NDisplayName() { + return Bukkit.getServer().getItemFactory().getI18NDisplayName(this); + } ++ ++ /** ++ * @deprecated use {@link #getMaxItemUseDuration(org.bukkit.entity.LivingEntity)}; crossbows, later possibly more items require an entity parameter ++ */ ++ @Deprecated(forRemoval = true) ++ public int getMaxItemUseDuration() { ++ return getMaxItemUseDuration(null); ++ } ++ ++ public int getMaxItemUseDuration(@NotNull final org.bukkit.entity.LivingEntity entity) { ++ if (type == null || type == Material.AIR || !type.isItem()) { ++ return 0; ++ } ++ // Requires access to NMS ++ return ensureServerConversions().getMaxItemUseDuration(entity); ++ } + // Paper end + } diff --git a/patches/api/0105-Location.toBlockLocation-toCenterLocation.patch b/patches/api/0105-Location.toBlockLocation-toCenterLocation.patch deleted file mode 100644 index 03e2f6215b28..000000000000 --- a/patches/api/0105-Location.toBlockLocation-toCenterLocation.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 24 May 2018 21:01:13 -0400 -Subject: [PATCH] Location.toBlockLocation/toCenterLocation() - -Convert location objects to their block coordinates, or the center of the block - -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index 3be91f6c9b355c9e8562796d719f5a6ce566d85a..a90010fea189c5ac9a59a0e6d04c0457243a3280 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -534,6 +534,31 @@ public class Location implements Cloneable, ConfigurationSerializable { - } - - public boolean isChunkLoaded() { return this.getWorld().isChunkLoaded(locToBlock(x) >> 4, locToBlock(z) >> 4); } // Paper -+ -+ // Paper start -+ /** -+ * @return A new location where X/Y/Z are on the Block location (integer value of X/Y/Z) -+ */ -+ @NotNull -+ public Location toBlockLocation() { -+ Location blockLoc = clone(); -+ blockLoc.setX(getBlockX()); -+ blockLoc.setY(getBlockY()); -+ blockLoc.setZ(getBlockZ()); -+ return blockLoc; -+ } -+ /** -+ * @return A new location where X/Y/Z are the center of the block -+ */ -+ @NotNull -+ public Location toCenterLocation() { -+ Location centerLoc = clone(); -+ centerLoc.setX(getBlockX() + 0.5); -+ centerLoc.setY(getBlockY() + 0.5); -+ centerLoc.setZ(getBlockZ() + 0.5); -+ return centerLoc; -+ } -+ // Paper end - @Override - public boolean equals(Object obj) { - if (obj == null) { diff --git a/patches/api/0106-Add-EntityTeleportEndGatewayEvent.patch b/patches/api/0106-Add-EntityTeleportEndGatewayEvent.patch new file mode 100644 index 000000000000..7676b998d8f8 --- /dev/null +++ b/patches/api/0106-Add-EntityTeleportEndGatewayEvent.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sat, 9 Jun 2018 13:08:21 +0100 +Subject: [PATCH] Add EntityTeleportEndGatewayEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cea029bfbd526d21509dee69bbfad44323107cf2 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java +@@ -0,0 +1,33 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.Location; ++import org.bukkit.block.EndGateway; ++import org.bukkit.entity.Entity; ++import org.bukkit.event.entity.EntityTeleportEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired any time an entity attempts to teleport in an end gateway ++ */ ++@NullMarked ++public class EntityTeleportEndGatewayEvent extends EntityTeleportEvent { ++ ++ private final EndGateway gateway; ++ ++ @ApiStatus.Internal ++ public EntityTeleportEndGatewayEvent(final Entity entity, final Location from, final Location to, final EndGateway gateway) { ++ super(entity, from, to); ++ this.gateway = gateway; ++ } ++ ++ /** ++ * The gateway triggering the teleport ++ * ++ * @return EndGateway used ++ */ ++ public EndGateway getGateway() { ++ return this.gateway; ++ } ++ ++} diff --git a/patches/api/0106-PotionEffect-clone-methods.patch b/patches/api/0106-PotionEffect-clone-methods.patch deleted file mode 100644 index 7be547b08c1d..000000000000 --- a/patches/api/0106-PotionEffect-clone-methods.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 3 Jun 2018 04:10:13 -0400 -Subject: [PATCH] PotionEffect clone methods - - -diff --git a/src/main/java/org/bukkit/potion/PotionEffect.java b/src/main/java/org/bukkit/potion/PotionEffect.java -index 1f0faf16071f0be44c87248582ba173e51aafb52..24e36cdf580da885ac64002673a786b9c5a3f787 100644 ---- a/src/main/java/org/bukkit/potion/PotionEffect.java -+++ b/src/main/java/org/bukkit/potion/PotionEffect.java -@@ -101,6 +101,33 @@ public class PotionEffect implements ConfigurationSerializable { - this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true))); - } - -+ // Paper start -+ @NotNull -+ public PotionEffect withType(@NotNull PotionEffectType type) { -+ return new PotionEffect(type, duration, amplifier, ambient, particles, icon); -+ } -+ @NotNull -+ public PotionEffect withDuration(int duration) { -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ } -+ @NotNull -+ public PotionEffect withAmplifier(int amplifier) { -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ } -+ @NotNull -+ public PotionEffect withAmbient(boolean ambient) { -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ } -+ @NotNull -+ public PotionEffect withParticles(boolean particles) { -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ } -+ @NotNull -+ public PotionEffect withIcon(boolean icon) { -+ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); -+ } -+ // Paper end -+ - @NotNull - private static PotionEffectType getEffectType(@NotNull Map map) { - int type = getInt(map, TYPE); diff --git a/patches/api/0107-Make-shield-blocking-delay-configurable.patch b/patches/api/0107-Make-shield-blocking-delay-configurable.patch new file mode 100644 index 000000000000..e76852fc1e8b --- /dev/null +++ b/patches/api/0107-Make-shield-blocking-delay-configurable.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 16 Jun 2018 01:17:39 -0500 +Subject: [PATCH] Make shield blocking delay configurable + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 055ba78f61dfa2d791361ae3b74611131e95dda7..d71fa7359619bca9fab4ecfb05af04b292416217 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -847,5 +847,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + @Deprecated + void setArrowsStuck(int arrows); ++ ++ /** ++ * Get the delay (in ticks) before blocking is effective for this entity ++ * ++ * @return Delay in ticks ++ */ ++ int getShieldBlockingDelay(); ++ ++ /** ++ * Set the delay (in ticks) before blocking is effective for this entity ++ * ++ * @param delay Delay in ticks ++ */ ++ void setShieldBlockingDelay(int delay); + // Paper end + } diff --git a/patches/api/0107-WitchReadyPotionEvent.patch b/patches/api/0107-WitchReadyPotionEvent.patch deleted file mode 100644 index 572242604930..000000000000 --- a/patches/api/0107-WitchReadyPotionEvent.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 5 Jun 2018 22:47:08 -0400 -Subject: [PATCH] WitchReadyPotionEvent - -Control what potion the witch readies to use - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5351b523defa054ba56ae3fb591029283ca7510d ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java -@@ -0,0 +1,80 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.Material; -+import org.bukkit.entity.Witch; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class WitchReadyPotionEvent extends EntityEvent implements Cancellable { -+ private ItemStack potion; -+ -+ public WitchReadyPotionEvent(@NotNull Witch witch, @Nullable ItemStack potion) { -+ super(witch); -+ this.potion = potion; -+ } -+ -+ /** -+ * Fires thee event, returning the desired potion, or air of cancelled -+ * @param witch the witch whom is readying to use a potion -+ * @param potion the potion to be used -+ * @return The ItemStack to be used -+ */ -+ @Nullable -+ public static ItemStack process(@NotNull Witch witch, @Nullable ItemStack potion) { -+ WitchReadyPotionEvent event = new WitchReadyPotionEvent(witch, potion); -+ if (!event.callEvent() || event.getPotion() == null) { -+ return new ItemStack(Material.AIR); -+ } -+ return event.getPotion(); -+ } -+ -+ @NotNull -+ @Override -+ public Witch getEntity() { -+ return (Witch) super.getEntity(); -+ } -+ -+ /** -+ * @return the potion the witch is readying to use -+ */ -+ @Nullable -+ public ItemStack getPotion() { -+ return potion; -+ } -+ -+ /** -+ * Sets the potion the which is going to hold and use -+ * @param potion The potion -+ */ -+ public void setPotion(@Nullable ItemStack potion) { -+ this.potion = potion != null ? potion.clone() : null; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0108-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch b/patches/api/0108-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch new file mode 100644 index 000000000000..31d676c17b04 --- /dev/null +++ b/patches/api/0108-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 15 Jun 2013 19:52:04 -0400 +Subject: [PATCH] EntityShootBowEvent consumeArrow and getArrowItem API + +Adds ability to get what arrow was shot, and control if it should be consumed. + +diff --git a/src/main/java/org/bukkit/event/entity/EntityShootBowEvent.java b/src/main/java/org/bukkit/event/entity/EntityShootBowEvent.java +index 8200ac4e2990d8751f9c5fb02bc5e173d59d7d94..85e2277efa62d8610979003b6d37bda4352e732e 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityShootBowEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityShootBowEvent.java +@@ -22,7 +22,32 @@ public class EntityShootBowEvent extends EntityEvent implements Cancellable { + private final float force; + private boolean consumeItem; + private boolean cancelled; ++ // Paper start ++ @Deprecated ++ public void setConsumeArrow(boolean consumeArrow) { ++ this.setConsumeItem(consumeArrow); ++ } ++ ++ @Deprecated ++ public boolean getConsumeArrow() { ++ return this.shouldConsumeItem(); ++ } ++ ++ @Nullable @Deprecated ++ public ItemStack getArrowItem() { ++ return this.getConsumable(); ++ } ++ ++ @Deprecated ++ public EntityShootBowEvent(@NotNull final LivingEntity shooter, @Nullable final ItemStack bow, @NotNull final Entity projectile, final float force) { ++ this(shooter, bow, new ItemStack(org.bukkit.Material.AIR), projectile, force); ++ } + ++ @Deprecated ++ public EntityShootBowEvent(@NotNull final LivingEntity shooter, @Nullable final ItemStack bow, @NotNull ItemStack arrowItem, @NotNull final Entity projectile, final float force) { ++ this(shooter, bow, arrowItem, projectile, EquipmentSlot.HAND, force, true); ++ } ++ // Paper end + public EntityShootBowEvent(@NotNull final LivingEntity shooter, @Nullable final ItemStack bow, @Nullable final ItemStack consumable, @NotNull final Entity projectile, @NotNull final EquipmentSlot hand, final float force, final boolean consumeItem) { + super(shooter); + this.bow = bow; diff --git a/patches/api/0108-ItemStack-getMaxItemUseDuration.patch b/patches/api/0108-ItemStack-getMaxItemUseDuration.patch deleted file mode 100644 index 2335189f4539..000000000000 --- a/patches/api/0108-ItemStack-getMaxItemUseDuration.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 5 Jun 2018 22:59:50 -0400 -Subject: [PATCH] ItemStack#getMaxItemUseDuration - -Allows you to determine how long it takes to use a usable/consumable item - -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 8b76d7ca596ea261c0ca3b9fe2fbf5507c3883e3..54d7c4b78f7fb01d8c11c19f038642b155334770 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -639,5 +639,13 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - public String getI18NDisplayName() { - return Bukkit.getServer().getItemFactory().getI18NDisplayName(this); - } -+ -+ public int getMaxItemUseDuration() { -+ if (type == null || type == Material.AIR || !type.isItem()) { -+ return 0; -+ } -+ // Requires access to NMS -+ return ensureServerConversions().getMaxItemUseDuration(); -+ } - // Paper end - } diff --git a/patches/api/0109-Add-EntityTeleportEndGatewayEvent.patch b/patches/api/0109-Add-EntityTeleportEndGatewayEvent.patch deleted file mode 100644 index 0422ec9858a7..000000000000 --- a/patches/api/0109-Add-EntityTeleportEndGatewayEvent.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sat, 9 Jun 2018 13:08:21 +0100 -Subject: [PATCH] Add EntityTeleportEndGatewayEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bfc69a43c291fbed91b9d0387e4ef18b0ed1b9de ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityTeleportEndGatewayEvent.java -@@ -0,0 +1,31 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.block.EndGateway; -+import org.bukkit.entity.Entity; -+import org.bukkit.event.entity.EntityTeleportEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired any time an entity attempts to teleport in an end gateway -+ */ -+public class EntityTeleportEndGatewayEvent extends EntityTeleportEvent { -+ -+ @NotNull private final EndGateway gateway; -+ -+ public EntityTeleportEndGatewayEvent(@NotNull Entity what, @NotNull Location from, @NotNull Location to, @NotNull EndGateway gateway) { -+ super(what, from, to); -+ this.gateway = gateway; -+ } -+ -+ /** -+ * The gateway triggering the teleport -+ * -+ * @return EndGateway used -+ */ -+ @NotNull -+ public EndGateway getGateway() { -+ return gateway; -+ } -+ -+} diff --git a/patches/api/0109-Add-getNearbyXXX-methods-to-Location.patch b/patches/api/0109-Add-getNearbyXXX-methods-to-Location.patch new file mode 100644 index 000000000000..63749fbc2588 --- /dev/null +++ b/patches/api/0109-Add-getNearbyXXX-methods-to-Location.patch @@ -0,0 +1,258 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 18 Jun 2018 00:41:46 -0500 +Subject: [PATCH] Add "getNearbyXXX" methods to Location + + +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index 3bcc8266d6b1de3c3f964ffad9820bf1b94bbd00..df88bc77a3fa2506adf17eddc6300ac65774df6f 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -12,6 +12,15 @@ import org.bukkit.util.Vector; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++// Paper start ++import java.util.Collection; ++import java.util.Collections; ++import java.util.function.Predicate; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.entity.Player; ++// Paper end ++ + /** + * Represents a 3-dimensional position in a world. + *
      +@@ -560,6 +569,231 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + } + // Paper end - expand Location API + ++ // Paper start - additional getNearbyEntities API ++ /** ++ * Returns a list of entities within a bounding box centered around a Location. ++ *

      ++ * Some implementations may impose artificial restrictions on the size of the search bounding box. ++ * ++ * @param x 1/2 the size of the box along the x-axis ++ * @param y 1/2 the size of the box along the y-axis ++ * @param z 1/2 the size of the box along the z-axis ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyEntities(final double x, final double y, final double z) { ++ final World world = this.getWorld(); ++ if (world == null) { ++ throw new IllegalArgumentException("Location has no world"); ++ } ++ return world.getNearbyEntities(this, x, y, z); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param radius X Radius ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyLivingEntities(final double radius) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, radius, radius, radius); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param xzRadius X/Z Radius ++ * @param yRadius Y Radius ++ * @return the collection of living entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyLivingEntities(final double xzRadius, final double yRadius) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, xzRadius, yRadius, xzRadius); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z radius ++ * @return the collection of living entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyLivingEntities(final double xRadius, final double yRadius, final double zRadius) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, xRadius, yRadius, zRadius); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param radius Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of living entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyLivingEntities(final double radius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, radius, radius, radius, predicate); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param xzRadius X/Z Radius ++ * @param yRadius Y Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of living entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyLivingEntities(final double xzRadius, final double yRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, xzRadius, yRadius, xzRadius, predicate); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of living entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyLivingEntities(final double xRadius, final double yRadius, final double zRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(LivingEntity.class, xRadius, yRadius, zRadius, predicate); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param radius X/Y/Z Radius ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyPlayers(final double radius) { ++ return this.getNearbyEntitiesByType(Player.class, radius, radius, radius); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param xzRadius X/Z Radius ++ * @param yRadius Y Radius ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyPlayers(final double xzRadius, final double yRadius) { ++ return this.getNearbyEntitiesByType(Player.class, xzRadius, yRadius, xzRadius); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z Radius ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyPlayers(final double xRadius, final double yRadius, final double zRadius) { ++ return this.getNearbyEntitiesByType(Player.class, xRadius, yRadius, zRadius); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param radius X/Y/Z Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyPlayers(final double radius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(Player.class, radius, radius, radius, predicate); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param xzRadius X/Z Radius ++ * @param yRadius Y Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyPlayers(final double xzRadius, final double yRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(Player.class, xzRadius, yRadius, xzRadius, predicate); ++ } ++ ++ /** ++ * Gets nearby players within the specified radius (bounding box) ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z Radius ++ * @param predicate a predicate used to filter results ++ * @return the collection of players near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyPlayers(final double xRadius, final double yRadius, final double zRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(Player.class, xRadius, yRadius, zRadius, predicate); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius (bounding box) ++ * @param clazz Type to filter by ++ * @param radius X/Y/Z radius to search within ++ * @param the entity type ++ * @return the collection of entities of type clazz near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final double radius) { ++ return this.getNearbyEntitiesByType(clazz, radius, radius, radius, null); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius, with x and x radius matching (bounding box) ++ * @param clazz Type to filter by ++ * @param xzRadius X/Z radius to search within ++ * @param yRadius Y radius to search within ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final double xzRadius, final double yRadius) { ++ return this.getNearbyEntitiesByType(clazz, xzRadius, yRadius, xzRadius, null); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius (bounding box) ++ * @param clazz Type to filter by ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z Radius ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final double xRadius, final double yRadius, final double zRadius) { ++ return this.getNearbyEntitiesByType(clazz, xRadius, yRadius, zRadius, null); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius (bounding box) ++ * @param clazz Type to filter by ++ * @param radius X/Y/Z radius to search within ++ * @param predicate a predicate used to filter results ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final double radius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(clazz, radius, radius, radius, predicate); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius, with x and x radius matching (bounding box) ++ * @param clazz Type to filter by ++ * @param xzRadius X/Z radius to search within ++ * @param yRadius Y radius to search within ++ * @param predicate a predicate used to filter results ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final double xzRadius, final double yRadius, final @Nullable Predicate predicate) { ++ return this.getNearbyEntitiesByType(clazz, xzRadius, yRadius, xzRadius, predicate); ++ } ++ ++ /** ++ * Gets all nearby entities of the specified type, within the specified radius (bounding box) ++ * @param clazz Type to filter by ++ * @param xRadius X Radius ++ * @param yRadius Y Radius ++ * @param zRadius Z Radius ++ * @param predicate a predicate used to filter results ++ * @param the entity type ++ * @return the collection of entities near location. This will always be a non-null collection. ++ */ ++ public @NotNull Collection getNearbyEntitiesByType(final @Nullable Class clazz, final double xRadius, final double yRadius, final double zRadius, final @Nullable Predicate predicate) { ++ final World world = this.getWorld(); ++ if (world == null) { ++ throw new IllegalArgumentException("Location has no world"); ++ } ++ return world.getNearbyEntitiesByType(clazz, this, xRadius, yRadius, zRadius, predicate); ++ } ++ // Paper end - additional getNearbyEntities API ++ + @Override + public boolean equals(Object obj) { + if (obj == null) { diff --git a/patches/api/0110-Make-shield-blocking-delay-configurable.patch b/patches/api/0110-Make-shield-blocking-delay-configurable.patch deleted file mode 100644 index 7b6e95c4e82c..000000000000 --- a/patches/api/0110-Make-shield-blocking-delay-configurable.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 16 Jun 2018 01:17:39 -0500 -Subject: [PATCH] Make shield blocking delay configurable - - -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index bfc90a3569abc717f37c064e3068c55ef323edab..588ad09a764236cf858a4e6689cf4ee5246e6f08 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -635,5 +635,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - * @param arrows Number of arrows to stick in this entity - */ - void setArrowsStuck(int arrows); -+ -+ /** -+ * Get the delay (in ticks) before blocking is effective for this entity -+ * -+ * @return Delay in ticks -+ */ -+ int getShieldBlockingDelay(); -+ -+ /** -+ * Set the delay (in ticks) before blocking is effective for this entity -+ * -+ * @param delay Delay in ticks -+ */ -+ void setShieldBlockingDelay(int delay); - // Paper end - } diff --git a/patches/api/0110-PlayerReadyArrowEvent.patch b/patches/api/0110-PlayerReadyArrowEvent.patch new file mode 100644 index 000000000000..3c432ede0a5c --- /dev/null +++ b/patches/api/0110-PlayerReadyArrowEvent.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 18 Jun 2018 01:09:27 -0400 +Subject: [PATCH] PlayerReadyArrowEvent + +Called when a player is firing a bow and the server is choosing an arrow to use. +Plugins can skip selection of certain arrows and control which is used. + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3eadfae8860a4f6cde107cc3c7048368ade29d28 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player is firing a bow and the server is choosing an arrow to use. ++ */ ++@NullMarked ++public class PlayerReadyArrowEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ItemStack bow; ++ private final ItemStack arrow; ++ ++ private boolean cancelled; ++ ++ public PlayerReadyArrowEvent(final Player player, final ItemStack bow, final ItemStack arrow) { ++ super(player); ++ this.bow = bow; ++ this.arrow = arrow; ++ } ++ ++ /** ++ * @return the player is using to fire the arrow ++ */ ++ public ItemStack getBow() { ++ return this.bow; ++ } ++ ++ /** ++ * @return the arrow that is attempting to be used ++ */ ++ public ItemStack getArrow() { ++ return this.arrow; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *
      ++ * Whether use of this arrow is cancelled. On cancel, the server will try the next arrow available and fire another event. ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * Cancel use of this arrow. On cancel, the server will try the next arrow available and fire another event. ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0111-Add-entity-knockback-events.patch b/patches/api/0111-Add-entity-knockback-events.patch new file mode 100644 index 000000000000..046eb6ef3716 --- /dev/null +++ b/patches/api/0111-Add-entity-knockback-events.patch @@ -0,0 +1,296 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brokkonaut +Date: Mon, 18 Jun 2018 15:40:39 +0200 +Subject: [PATCH] Add entity knockback events + +- EntityKnockbackEvent +- EntityPushedByEntityAttackEvent +- EntityKnockbackByEntityEvent + +Co-authored-by: aerulion +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6f376e1ac0f2f44255993b3d5b144f5559d13cc3 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java +@@ -0,0 +1,52 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import io.papermc.paper.event.entity.EntityKnockbackEvent; ++import io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.util.Vector; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when an Entity is knocked back by the hit of another Entity. The acceleration ++ * vector can be modified. If this event is cancelled, the entity is not knocked back. ++ */ ++@NullMarked ++public class EntityKnockbackByEntityEvent extends EntityPushedByEntityAttackEvent { ++ ++ private final float knockbackStrength; ++ ++ @ApiStatus.Internal ++ public EntityKnockbackByEntityEvent(final LivingEntity entity, final Entity hitBy, final EntityKnockbackEvent.Cause cause, final float knockbackStrength, final Vector knockback) { ++ super(entity, cause, hitBy, knockback); ++ this.knockbackStrength = knockbackStrength; ++ } ++ ++ /** ++ * @return the entity which was knocked back ++ */ ++ @Override ++ public LivingEntity getEntity() { ++ return (LivingEntity) super.getEntity(); ++ } ++ ++ /** ++ * @return the original knockback strength. ++ * @apiNote this value doesn't necessarily relate to {@link #getKnockback()}. ++ */ ++ @ApiStatus.Obsolete(since = "1.20.6") ++ public float getKnockbackStrength() { ++ return this.knockbackStrength; ++ } ++ ++ /** ++ * Gets the causing entity. Same as {@link #getPushedBy()}. ++ * ++ * @return the Entity which hit ++ */ ++ public Entity getHitBy() { ++ return super.getPushedBy(); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bc120d4928dc41ea827e2a06f7d30d0e3d484ce0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityKnockbackEvent.java +@@ -0,0 +1,117 @@ ++package io.papermc.paper.event.entity; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.util.Vector; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when an entity receives knockback. ++ * @see EntityPushedByEntityAttackEvent ++ * @see com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent ++ */ ++@NullMarked ++public class EntityKnockbackEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Cause cause; ++ protected Vector knockback; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityKnockbackEvent(final Entity entity, final EntityKnockbackEvent.Cause cause, final Vector knockback) { ++ super(entity); ++ this.cause = cause; ++ this.knockback = knockback; ++ } ++ ++ /** ++ * Gets the cause of the knockback. ++ * ++ * @return the cause of the knockback ++ */ ++ public EntityKnockbackEvent.Cause getCause() { ++ return this.cause; ++ } ++ ++ /** ++ * Gets the knockback force that will be applied to the entity.
      ++ * This value is read-only, changes made to it will not have any ++ * effect on the final knockback received. Use {@link #setKnockback(Vector)} ++ * to make changes. ++ * ++ * @return the knockback ++ */ ++ public Vector getKnockback() { ++ return this.knockback.clone(); ++ } ++ ++ /** ++ * Sets the knockback force that will be applied to the entity. ++ * ++ * @param knockback the knockback ++ */ ++ public void setKnockback(final Vector knockback) { ++ Preconditions.checkArgument(knockback != null, "knockback"); ++ this.knockback = knockback.clone(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ /** ++ * An enum to specify the cause of the knockback. ++ */ ++ public enum Cause { ++ ++ /** ++ * Knockback caused by non-entity damage. ++ */ ++ DAMAGE, ++ /** ++ * Knockback caused by an attacking entity. ++ */ ++ ENTITY_ATTACK, ++ /** ++ * Knockback caused by an explosion. ++ */ ++ EXPLOSION, ++ /** ++ * Knockback caused by the target blocking with a shield. ++ */ ++ SHIELD_BLOCK, ++ /** ++ * Knockback caused by a sweeping attack. ++ */ ++ SWEEP_ATTACK, ++ /** ++ * A generic push. ++ */ ++ PUSH, ++ /** ++ * Knockback with an unknown cause. ++ */ ++ UNKNOWN ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7655c3694b9d6b37206fc46bf892004686e0a7dd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityPushedByEntityAttackEvent.java +@@ -0,0 +1,67 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.util.Vector; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when an entity is pushed by another entity's attack. The acceleration vector can be ++ * modified. If this event is cancelled, the entity will not get pushed. ++ *

      ++ * Note: Some entities might trigger this multiple times on the same entity ++ * as multiple acceleration calculations are done. ++ */ ++@NullMarked ++public class EntityPushedByEntityAttackEvent extends EntityKnockbackEvent implements Cancellable { ++ ++ private final Entity pushedBy; ++ ++ @ApiStatus.Internal ++ public EntityPushedByEntityAttackEvent(final Entity entity, final EntityKnockbackEvent.Cause cause, final Entity pushedBy, final Vector knockback) { ++ super(entity, cause, knockback); ++ this.pushedBy = pushedBy; ++ } ++ ++ /** ++ * Gets the entity which pushed the affected entity. ++ * ++ * @return the pushing entity ++ */ ++ public Entity getPushedBy() { ++ return this.pushedBy; ++ } ++ ++ /** ++ * Gets the acceleration that will be applied to the affected entity. ++ * ++ * @return the acceleration vector ++ * @deprecated use {@link #getKnockback()} ++ */ ++ @Deprecated(since = "1.20.6", forRemoval = true) ++ public Vector getAcceleration() { ++ return this.knockback; // TODO Clone in 1.21 to not instantly break what was technically already modifiable (call super.getKnockback()) ++ } ++ ++ /** ++ * Sets the relative acceleration that will be applied to the affected entity. ++ * ++ * @param acceleration the new acceleration vector ++ * @deprecated use {@link #setKnockback(Vector)} ++ */ ++ @Deprecated(since = "1.20.6", forRemoval = true) ++ public void setAcceleration(final Vector acceleration) { ++ super.setKnockback(acceleration); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return super.isCancelled(); ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ super.setCancelled(cancel); ++ } ++} +diff --git a/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java +index 3f17290c0863cc1d452bb50c524c18b6ab255d70..bd44bc5ed9e20148f9b2ab3d2049187280f3eb18 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityKnockbackByEntityEvent.java +@@ -7,7 +7,10 @@ import org.jetbrains.annotations.NotNull; + + /** + * Called when an entity receives knockback from another entity. ++ * ++ * @deprecated use {@link com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent} + */ ++@Deprecated(forRemoval = true) // Paper + public class EntityKnockbackByEntityEvent extends EntityKnockbackEvent { + + private final Entity source; +diff --git a/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java b/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java +index 692c6010198b06dc56c31e0392a60dcc6cfe5800..0d465629ecd86ba796e99d35c0492597535cb258 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityKnockbackEvent.java +@@ -11,7 +11,10 @@ import org.jetbrains.annotations.NotNull; + + /** + * Called when a living entity receives knockback. ++ * ++ * @deprecated use {@link io.papermc.paper.event.entity.EntityKnockbackEvent} + */ ++@Deprecated(forRemoval = true) // Paper + public class EntityKnockbackEvent extends EntityEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); diff --git a/patches/api/0111-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch b/patches/api/0111-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch deleted file mode 100644 index 71a82a8eaec5..000000000000 --- a/patches/api/0111-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 15 Jun 2013 19:52:04 -0400 -Subject: [PATCH] EntityShootBowEvent consumeArrow and getArrowItem API - -Adds ability to get what arrow was shot, and control if it should be consumed. - -diff --git a/src/main/java/org/bukkit/event/entity/EntityShootBowEvent.java b/src/main/java/org/bukkit/event/entity/EntityShootBowEvent.java -index d4d7ad9c3c953680342c121f39ddaef476549047..719d0d878320c1903b44076053989ba99fa0e92a 100644 ---- a/src/main/java/org/bukkit/event/entity/EntityShootBowEvent.java -+++ b/src/main/java/org/bukkit/event/entity/EntityShootBowEvent.java -@@ -22,7 +22,32 @@ public class EntityShootBowEvent extends EntityEvent implements Cancellable { - private final float force; - private boolean consumeItem; - private boolean cancelled; -+ // Paper start -+ @Deprecated -+ public void setConsumeArrow(boolean consumeArrow) { -+ this.setConsumeItem(consumeArrow); -+ } -+ -+ @Deprecated -+ public boolean getConsumeArrow() { -+ return this.shouldConsumeItem(); -+ } -+ -+ @NotNull @Deprecated -+ public ItemStack getArrowItem() { -+ return this.getConsumable(); -+ } -+ -+ @Deprecated -+ public EntityShootBowEvent(@NotNull final LivingEntity shooter, @Nullable final ItemStack bow, @NotNull final Entity projectile, final float force) { -+ this(shooter, bow, new ItemStack(org.bukkit.Material.AIR), projectile, force); -+ } - -+ @Deprecated -+ public EntityShootBowEvent(@NotNull final LivingEntity shooter, @Nullable final ItemStack bow, @NotNull ItemStack arrowItem, @NotNull final Entity projectile, final float force) { -+ this(shooter, bow, arrowItem, projectile, EquipmentSlot.HAND, force, true); -+ } -+ // Paper end - public EntityShootBowEvent(@NotNull final LivingEntity shooter, @Nullable final ItemStack bow, @Nullable final ItemStack consumable, @NotNull final Entity projectile, @NotNull final EquipmentSlot hand, final float force, final boolean consumeItem) { - super(shooter); - this.bow = bow; diff --git a/patches/api/0112-Add-getNearbyXXX-methods-to-Location.patch b/patches/api/0112-Add-getNearbyXXX-methods-to-Location.patch deleted file mode 100644 index 7c85a03490e4..000000000000 --- a/patches/api/0112-Add-getNearbyXXX-methods-to-Location.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 18 Jun 2018 00:41:46 -0500 -Subject: [PATCH] Add "getNearbyXXX" methods to Location - - -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index a90010fea189c5ac9a59a0e6d04c0457243a3280..bbc636baef2e2b0586c7d517be428438ca26ab66 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -12,6 +12,15 @@ import org.bukkit.util.Vector; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; - -+// Paper start -+import java.util.Collection; -+import java.util.Collections; -+import java.util.function.Predicate; -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.entity.Player; -+// Paper end -+ - /** - * Represents a 3-dimensional position in a world. - *
      -@@ -558,6 +567,248 @@ public class Location implements Cloneable, ConfigurationSerializable { - centerLoc.setZ(getBlockZ() + 0.5); - return centerLoc; - } -+ -+ /** -+ * Returns a list of entities within a bounding box centered around a Location. -+ * -+ * Some implementations may impose artificial restrictions on the size of the search bounding box. -+ * -+ * @param x 1/2 the size of the box along x axis -+ * @param y 1/2 the size of the box along y axis -+ * @param z 1/2 the size of the box along z axis -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyEntities(double x, double y, double z) { -+ World world = this.getWorld(); -+ if (world == null) { -+ throw new IllegalArgumentException("Location has no world"); -+ } -+ return world.getNearbyEntities(this, x, y, z); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param radius X Radius -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyLivingEntities(double radius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, radius, radius, radius); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param xzRadius X/Z Radius -+ * @param yRadius Y Radius -+ * @return the collection of living entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyLivingEntities(double xzRadius, double yRadius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, xzRadius, yRadius, xzRadius); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z radius -+ * @return the collection of living entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyLivingEntities(double xRadius, double yRadius, double zRadius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, xRadius, yRadius, zRadius); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param radius Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of living entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyLivingEntities(double radius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, radius, radius, radius, predicate); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param xzRadius X/Z Radius -+ * @param yRadius Y Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of living entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyLivingEntities(double xzRadius, double yRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, xzRadius, yRadius, xzRadius, predicate); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of living entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyLivingEntities(double xRadius, double yRadius, double zRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.LivingEntity.class, xRadius, yRadius, zRadius, predicate); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param radius X/Y/Z Radius -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyPlayers(double radius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, radius, radius, radius); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param xzRadius X/Z Radius -+ * @param yRadius Y Radius -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyPlayers(double xzRadius, double yRadius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, xzRadius, yRadius, xzRadius); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z Radius -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyPlayers(double xRadius, double yRadius, double zRadius) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, xRadius, yRadius, zRadius); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param radius X/Y/Z Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyPlayers(double radius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, radius, radius, radius, predicate); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param xzRadius X/Z Radius -+ * @param yRadius Y Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyPlayers(double xzRadius, double yRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, xzRadius, yRadius, xzRadius, predicate); -+ } -+ -+ /** -+ * Gets nearby players within the specified radius (bounding box) -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z Radius -+ * @param predicate a predicate used to filter results -+ * @return the collection of players near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyPlayers(double xRadius, double yRadius, double zRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(org.bukkit.entity.Player.class, xRadius, yRadius, zRadius, predicate); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius (bounding box) -+ * @param clazz Type to filter by -+ * @param radius X/Y/Z radius to search within -+ * @param the entity type -+ * @return the collection of entities of type clazz near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyEntitiesByType(@Nullable Class clazz, double radius) { -+ return getNearbyEntitiesByType(clazz, radius, radius, radius, null); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius, with x and x radius matching (bounding box) -+ * @param clazz Type to filter by -+ * @param xzRadius X/Z radius to search within -+ * @param yRadius Y radius to search within -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyEntitiesByType(@Nullable Class clazz, double xzRadius, double yRadius) { -+ return getNearbyEntitiesByType(clazz, xzRadius, yRadius, xzRadius, null); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius (bounding box) -+ * @param clazz Type to filter by -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z Radius -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyEntitiesByType(@Nullable Class clazz, double xRadius, double yRadius, double zRadius) { -+ return getNearbyEntitiesByType(clazz, xRadius, yRadius, zRadius, null); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius (bounding box) -+ * @param clazz Type to filter by -+ * @param radius X/Y/Z radius to search within -+ * @param predicate a predicate used to filter results -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyEntitiesByType(@Nullable Class clazz, double radius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(clazz, radius, radius, radius, predicate); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius, with x and x radius matching (bounding box) -+ * @param clazz Type to filter by -+ * @param xzRadius X/Z radius to search within -+ * @param yRadius Y radius to search within -+ * @param predicate a predicate used to filter results -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyEntitiesByType(@Nullable Class clazz, double xzRadius, double yRadius, @Nullable Predicate predicate) { -+ return getNearbyEntitiesByType(clazz, xzRadius, yRadius, xzRadius, predicate); -+ } -+ -+ /** -+ * Gets all nearby entities of the specified type, within the specified radius (bounding box) -+ * @param clazz Type to filter by -+ * @param xRadius X Radius -+ * @param yRadius Y Radius -+ * @param zRadius Z Radius -+ * @param predicate a predicate used to filter results -+ * @param the entity type -+ * @return the collection of entities near location. This will always be a non-null collection. -+ */ -+ @NotNull -+ public Collection getNearbyEntitiesByType(@Nullable Class clazz, double xRadius, double yRadius, double zRadius, @Nullable Predicate predicate) { -+ World world = this.getWorld(); -+ if (world == null) { -+ throw new IllegalArgumentException("Location has no world"); -+ } -+ return world.getNearbyEntitiesByType(clazz, this, xRadius, yRadius, zRadius, predicate); -+ } - // Paper end - @Override - public boolean equals(Object obj) { diff --git a/patches/api/0112-Expand-Explosions-API.patch b/patches/api/0112-Expand-Explosions-API.patch new file mode 100644 index 000000000000..6523f665b289 --- /dev/null +++ b/patches/api/0112-Expand-Explosions-API.patch @@ -0,0 +1,221 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 19 Dec 2017 16:24:42 -0500 +Subject: [PATCH] Expand Explosions API + +Add Entity as a Source capability, and add more API choices, and on Location. + +Co-authored-by: Esoteric Enderman <90862990+EsotericEnderman@users.noreply.github.com> +Co-authored-by: Bjarne Koll + +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index df88bc77a3fa2506adf17eddc6300ac65774df6f..fe2e0939df61b1f59d12adf3f760f1d619bb3de3 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -7,6 +7,7 @@ import java.util.HashMap; + import java.util.Map; + import org.bukkit.block.Block; + import org.bukkit.configuration.serialization.ConfigurationSerializable; ++import org.bukkit.entity.Entity; // Paper + import org.bukkit.util.NumberConversions; + import org.bukkit.util.Vector; + import org.jetbrains.annotations.NotNull; +@@ -569,6 +570,89 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + } + // Paper end - expand Location API + ++ // Paper start - Expand Explosions API ++ /** ++ * Creates explosion at this location with given power ++ *

      ++ * Will break blocks and ignite blocks on fire. ++ * ++ * @param power The power of explosion, where 4F is TNT ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public boolean createExplosion(float power) { ++ return this.getWorld().createExplosion(this, power); ++ } ++ ++ /** ++ * Creates explosion at this location with given power and optionally ++ * setting blocks on fire. ++ *

      ++ * Will break blocks. ++ * ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether to set blocks on fire ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public boolean createExplosion(float power, boolean setFire) { ++ return this.getWorld().createExplosion(this, power, setFire); ++ } ++ ++ /** ++ * Creates explosion at this location with given power and optionally ++ * setting blocks on fire. ++ * ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether to set blocks on fire ++ * @param breakBlocks Whether to have blocks be destroyed ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public boolean createExplosion(float power, boolean setFire, boolean breakBlocks) { ++ return this.getWorld().createExplosion(this, power, setFire, breakBlocks); ++ } ++ ++ /** ++ * Creates explosion at this location with given power, with the specified entity as the source. ++ *

      ++ * Will break blocks and ignite blocks on fire. ++ * ++ * @param source The source entity of the explosion ++ * @param power The power of explosion, where 4F is TNT ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public boolean createExplosion(@Nullable Entity source, float power) { ++ return this.getWorld().createExplosion(source, this, power, true, true); ++ } ++ ++ /** ++ * Creates explosion at this location with given power and optionally ++ * setting blocks on fire, with the specified entity as the source. ++ *

      ++ * Will break blocks. ++ * ++ * @param source The source entity of the explosion ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether to set blocks on fire ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public boolean createExplosion(@Nullable Entity source, float power, boolean setFire) { ++ return this.getWorld().createExplosion(source, this, power, setFire, true); ++ } ++ ++ /** ++ * Creates explosion at this location with given power and optionally ++ * setting blocks on fire, with the specified entity as the source. ++ * ++ * @param source The source entity of the explosion ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether to set blocks on fire ++ * @param breakBlocks Whether to have blocks be destroyed ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public boolean createExplosion(@Nullable Entity source, float power, boolean setFire, boolean breakBlocks) { ++ return this.getWorld().createExplosion(source, this, power, setFire, breakBlocks); ++ } ++ // Paper end - Expand Explosions API ++ + // Paper start - additional getNearbyEntities API + /** + * Returns a list of entities within a bounding box centered around a Location. +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index f1d59d22d805cfe5ac2707c88a917bf17ae38b96..62a0e6efcc33f56b26fa917276ac09737d4bf362 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -1424,6 +1424,104 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + */ + public boolean createExplosion(@NotNull Location loc, float power, boolean setFire); + ++ // Paper start ++ /** ++ * Creates explosion at given location with given power and optionally ++ * setting blocks on fire, with the specified entity as the source. ++ * ++ * @param source The source entity of the explosion ++ * @param loc Location to blow up ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether or not to set blocks on fire ++ * @param breakBlocks Whether or not to have blocks be destroyed ++ * @param excludeSourceFromDamage whether the explosion should exclude the passed source from taking damage like vanilla explosions do. ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks, boolean excludeSourceFromDamage); ++ ++ /** ++ * Creates explosion at given location with given power and optionally ++ * setting blocks on fire, with the specified entity as the source. ++ * ++ * @param source The source entity of the explosion ++ * @param loc Location to blow up ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether or not to set blocks on fire ++ * @param breakBlocks Whether or not to have blocks be destroyed ++ * @return false if explosion was canceled, otherwise true ++ */ ++ default boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks) { ++ return createExplosion(source, loc, power, setFire, breakBlocks, true); ++ } ++ ++ /** ++ * Creates explosion at given location with given power and optionally ++ * setting blocks on fire, with the specified entity as the source. ++ * ++ * Will destroy other blocks ++ * ++ * @param source The source entity of the explosion ++ * @param loc Location to blow up ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether or not to set blocks on fire ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public default boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire) { ++ return createExplosion(source, loc, power, setFire, true); ++ } ++ /** ++ * Creates explosion at given location with given power, with the specified entity as the source. ++ * Will set blocks on fire and destroy blocks. ++ * ++ * @param source The source entity of the explosion ++ * @param loc Location to blow up ++ * @param power The power of explosion, where 4F is TNT ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public default boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power) { ++ return createExplosion(source, loc, power, true, true); ++ } ++ /** ++ * Creates explosion at given entities location with given power and optionally ++ * setting blocks on fire, with the specified entity as the source. ++ * ++ * @param source The source entity of the explosion ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether or not to set blocks on fire ++ * @param breakBlocks Whether or not to have blocks be destroyed ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public default boolean createExplosion(@NotNull Entity source, float power, boolean setFire, boolean breakBlocks) { ++ return createExplosion(source, source.getLocation(), power, setFire, breakBlocks); ++ } ++ /** ++ * Creates explosion at given entities location with given power and optionally ++ * setting blocks on fire, with the specified entity as the source. ++ * ++ * Will destroy blocks. ++ * ++ * @param source The source entity of the explosion ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether or not to set blocks on fire ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public default boolean createExplosion(@NotNull Entity source, float power, boolean setFire) { ++ return createExplosion(source, source.getLocation(), power, setFire, true); ++ } ++ ++ /** ++ * Creates explosion at given entities location with given power and optionally ++ * setting blocks on fire, with the specified entity as the source. ++ * ++ * @param source The source entity of the explosion ++ * @param power The power of explosion, where 4F is TNT ++ * @return false if explosion was canceled, otherwise true ++ */ ++ public default boolean createExplosion(@NotNull Entity source, float power) { ++ return createExplosion(source, source.getLocation(), power, true, true); ++ } ++ // Paper end ++ + /** + * Creates explosion at given coordinates with given power and optionally + * setting blocks on fire or breaking blocks. diff --git a/patches/api/0113-ItemStack-API-additions-for-quantity-flags-lore.patch b/patches/api/0113-ItemStack-API-additions-for-quantity-flags-lore.patch new file mode 100644 index 000000000000..82dcd40cad17 --- /dev/null +++ b/patches/api/0113-ItemStack-API-additions-for-quantity-flags-lore.patch @@ -0,0 +1,196 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 22 Jun 2018 22:59:18 -0400 +Subject: [PATCH] ItemStack API additions for quantity/flags/lore + + +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index a3de566c8f0ea4dcdb158f9ef0876a3b14429140..080d9a9e26131eb43649104c3d59691308f79fe7 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -686,5 +686,185 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + // Requires access to NMS + return ensureServerConversions().getMaxItemUseDuration(entity); + } ++ ++ /** ++ * Clones the itemstack and returns it a single quantity. ++ * @return The new itemstack with 1 quantity ++ */ ++ @NotNull ++ public ItemStack asOne() { ++ return asQuantity(1); ++ } ++ ++ /** ++ * Clones the itemstack and returns it as the specified quantity ++ * @param qty The quantity of the cloned item ++ * @return The new itemstack with specified quantity ++ */ ++ @NotNull ++ public ItemStack asQuantity(int qty) { ++ ItemStack clone = clone(); ++ clone.setAmount(qty); ++ return clone; ++ } ++ ++ /** ++ * Adds 1 to this itemstack. Will not go over the items max stack size. ++ * @return The same item (not a clone) ++ */ ++ @NotNull ++ public ItemStack add() { ++ return add(1); ++ } ++ ++ /** ++ * Adds quantity to this itemstack. Will not go over the items max stack size. ++ * ++ * @param qty The amount to add ++ * @return The same item (not a clone) ++ */ ++ @NotNull ++ public ItemStack add(int qty) { ++ setAmount(Math.min(getMaxStackSize(), getAmount() + qty)); ++ return this; ++ } ++ ++ /** ++ * Subtracts 1 to this itemstack. Going to 0 or less will invalidate the item. ++ * @return The same item (not a clone) ++ */ ++ @NotNull ++ public ItemStack subtract() { ++ return subtract(1); ++ } ++ ++ /** ++ * Subtracts quantity to this itemstack. Going to 0 or less will invalidate the item. ++ * ++ * @param qty The amount to add ++ * @return The same item (not a clone) ++ */ ++ @NotNull ++ public ItemStack subtract(int qty) { ++ setAmount(Math.max(0, getAmount() - qty)); ++ return this; ++ } ++ ++ /** ++ * If the item has lore, returns it, else it will return null ++ * @return The lore, or null ++ * @deprecated in favor of {@link #lore()} ++ */ ++ @Deprecated ++ public @Nullable java.util.List getLore() { ++ if (!hasItemMeta()) { ++ return null; ++ } ++ ItemMeta itemMeta = getItemMeta(); ++ if (!itemMeta.hasLore()) { ++ return null; ++ } ++ return itemMeta.getLore(); ++ } ++ ++ /** ++ * If the item has lore, returns it, else it will return null ++ * @return The lore, or null ++ */ ++ public @Nullable java.util.List lore() { ++ if (!this.hasItemMeta()) { ++ return null; ++ } ++ final ItemMeta itemMeta = getItemMeta(); ++ if (!itemMeta.hasLore()) { ++ return null; ++ } ++ return itemMeta.lore(); ++ } ++ ++ /** ++ * Sets the lore for this item. ++ * Removes lore when given null. ++ * ++ * @param lore the lore that will be set ++ * @deprecated in favour of {@link #lore(java.util.List)} ++ */ ++ @Deprecated ++ public void setLore(@Nullable java.util.List lore) { ++ ItemMeta itemMeta = getItemMeta(); ++ if (itemMeta == null) { ++ throw new IllegalStateException("Cannot set lore on " + getType()); ++ } ++ itemMeta.setLore(lore); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Sets the lore for this item. ++ * Removes lore when given null. ++ * ++ * @param lore the lore that will be set ++ */ ++ public void lore(@Nullable java.util.List lore) { ++ ItemMeta itemMeta = getItemMeta(); ++ if (itemMeta == null) { ++ throw new IllegalStateException("Cannot set lore on " + getType()); ++ } ++ itemMeta.lore(lore); ++ this.setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Set itemflags which should be ignored when rendering a ItemStack in the Client. This Method does silently ignore double set itemFlags. ++ * ++ * @param itemFlags The hideflags which shouldn't be rendered ++ */ ++ public void addItemFlags(@NotNull ItemFlag... itemFlags) { ++ ItemMeta itemMeta = getItemMeta(); ++ if (itemMeta == null) { ++ throw new IllegalStateException("Cannot add flags on " + getType()); ++ } ++ itemMeta.addItemFlags(itemFlags); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Remove specific set of itemFlags. This tells the Client it should render it again. This Method does silently ignore double removed itemFlags. ++ * ++ * @param itemFlags Hideflags which should be removed ++ */ ++ public void removeItemFlags(@NotNull ItemFlag... itemFlags) { ++ ItemMeta itemMeta = getItemMeta(); ++ if (itemMeta == null) { ++ throw new IllegalStateException("Cannot remove flags on " + getType()); ++ } ++ itemMeta.removeItemFlags(itemFlags); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Get current set itemFlags. The collection returned is unmodifiable. ++ * ++ * @return A set of all itemFlags set ++ */ ++ @NotNull ++ public java.util.Set getItemFlags() { ++ ItemMeta itemMeta = getItemMeta(); ++ if (itemMeta == null) { ++ return java.util.Collections.emptySet(); ++ } ++ return itemMeta.getItemFlags(); ++ } ++ ++ /** ++ * Check if the specified flag is present on this item. ++ * ++ * @param flag the flag to check ++ * @return if it is present ++ */ ++ public boolean hasItemFlag(@NotNull ItemFlag flag) { ++ ItemMeta itemMeta = getItemMeta(); ++ return itemMeta != null && itemMeta.hasItemFlag(flag); ++ } + // Paper end + } diff --git a/patches/api/0113-PlayerReadyArrowEvent.patch b/patches/api/0113-PlayerReadyArrowEvent.patch deleted file mode 100644 index 7ea174058102..000000000000 --- a/patches/api/0113-PlayerReadyArrowEvent.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 18 Jun 2018 01:09:27 -0400 -Subject: [PATCH] PlayerReadyArrowEvent - -Called when a player is firing a bow and the server is choosing an arrow to use. -Plugins can skip selection of certain arrows and control which is used. - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5d04a22fd6964d8d44a2aa069c9629722893b1f4 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerReadyArrowEvent.java -@@ -0,0 +1,93 @@ -+/* -+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be -+ * included in all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player is firing a bow and the server is choosing an arrow to use. -+ */ -+public class PlayerReadyArrowEvent extends PlayerEvent implements Cancellable { -+ @NotNull private final ItemStack bow; -+ @NotNull private final ItemStack arrow; -+ -+ public PlayerReadyArrowEvent(@NotNull Player player, @NotNull ItemStack bow, @NotNull ItemStack arrow) { -+ super(player); -+ this.bow = bow; -+ this.arrow = arrow; -+ } -+ -+ /** -+ * @return the player is using to fire the arrow -+ */ -+ @NotNull -+ public ItemStack getBow() { -+ return bow; -+ } -+ -+ /** -+ * @return the arrow that is attempting to be used -+ */ -+ @NotNull -+ public ItemStack getArrow() { -+ return arrow; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ /** -+ * Whether or not use of this arrow is cancelled. On cancel, the server will try the next arrow available and fire another event. -+ */ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * Cancel use of this arrow. On cancel, the server will try the next arrow available and fire another event. -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0114-Add-EntityKnockbackByEntityEvent.patch b/patches/api/0114-Add-EntityKnockbackByEntityEvent.patch deleted file mode 100644 index 1620ab68a616..000000000000 --- a/patches/api/0114-Add-EntityKnockbackByEntityEvent.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brokkonaut -Date: Mon, 18 Jun 2018 15:40:39 +0200 -Subject: [PATCH] Add EntityKnockbackByEntityEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9efecabab813f575bb447a356e5e7e952d110f30 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityKnockbackByEntityEvent.java -@@ -0,0 +1,82 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.util.Vector; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when an Entity is knocked back by the hit of another Entity. The acceleration -+ * vector can be modified. If this event is cancelled, the entity is not knocked back. -+ * -+ */ -+public class EntityKnockbackByEntityEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull private final Entity hitBy; -+ private final float knockbackStrength; -+ @NotNull private final Vector acceleration; -+ private boolean cancelled = false; -+ -+ public EntityKnockbackByEntityEvent(@NotNull LivingEntity entity, @NotNull Entity hitBy, float knockbackStrength, @NotNull Vector acceleration) { -+ super(entity); -+ this.hitBy = hitBy; -+ this.knockbackStrength = knockbackStrength; -+ this.acceleration = acceleration; -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ /** -+ * @return the entity which was knocked back -+ */ -+ @NotNull -+ @Override -+ public LivingEntity getEntity() { -+ return (LivingEntity) super.getEntity(); -+ } -+ -+ /** -+ * @return the original knockback strength. -+ */ -+ public float getKnockbackStrength() { -+ return knockbackStrength; -+ } -+ -+ /** -+ * @return the Entity which hit -+ */ -+ @NotNull -+ public Entity getHitBy() { -+ return hitBy; -+ } -+ -+ /** -+ * @return the acceleration that will be applied -+ */ -+ @NotNull -+ public Vector getAcceleration() { -+ return acceleration; -+ } -+} diff --git a/patches/api/0114-LivingEntity-Active-Item-API.patch b/patches/api/0114-LivingEntity-Active-Item-API.patch new file mode 100644 index 000000000000..f7f8f2748374 --- /dev/null +++ b/patches/api/0114-LivingEntity-Active-Item-API.patch @@ -0,0 +1,189 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 29 Jun 2018 00:19:19 -0400 +Subject: [PATCH] LivingEntity Active Item API + +API relating to items being actively used by a LivingEntity +such as a bow or eating food. + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index 35d72d8ab78ca4095545fab54d6b440c040223eb..4d72da8b04c72f296bc3f8e00e54f4d79e531d44 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -367,7 +367,9 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder + * blocking). + * + * @return Whether their hand is raised ++ * @see LivingEntity#hasActiveItem() + */ ++ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.20.4") // Paper - active item API + public boolean isHandRaised(); + + /** +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index d71fa7359619bca9fab4ecfb05af04b292416217..f8eb5527b4e0520712f4d8c329ba9d5dc4a4d206 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -202,15 +202,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + * + * @return the item being used by the player, or null if they are not using + * an item ++ * @deprecated Use {@link #getActiveItem()} + */ + @Nullable ++ @Deprecated(forRemoval = true, since = "1.20.4") // Paper + public ItemStack getItemInUse(); + + /** + * Gets the number of ticks remaining for the current item's usage. + * + * @return The number of ticks remaining ++ * @deprecated use {@link #getActiveItemRemainingTime()} + */ ++ @Deprecated(forRemoval = true, since = "1.20.4") // Paper + public int getItemInUseTicks(); + + /** +@@ -219,7 +223,9 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + * or throwing a trident. + * + * @param ticks The number of ticks remaining ++ * @deprecated use {@link #setActiveItemRemainingTime(int)} + */ ++ @Deprecated(forRemoval = true, since = "1.20.4") // Paper + public void setItemInUseTicks(int ticks); + + /** +@@ -862,4 +868,130 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + void setShieldBlockingDelay(int delay); + // Paper end ++ ++ // Paper start - active item API ++ /** ++ * Starts using the item in the specified hand, making it the ++ * currently active item. When, for example, called on a skeleton, ++ * this will cause it to start drawing its bow. ++ *

      ++ * Only HAND or OFF_HAND may be used for the hand parameter. ++ *

      ++ * When used on a player, the client will stop using the item ++ * if right click is held down. ++ *

      ++ * This method does not make any guarantees about the effect of this method ++ * as such depends on the entity and its state. ++ * ++ * @param hand the hand that contains the item to be used ++ */ ++ @org.jetbrains.annotations.ApiStatus.Experimental ++ void startUsingItem(@NotNull org.bukkit.inventory.EquipmentSlot hand); ++ ++ /** ++ * Finishes using the currently active item. When, for example, a ++ * skeleton is drawing its bow, this will cause it to release and ++ * fire the arrow. ++ *

      ++ * This method does not make any guarantees about the effect of this method ++ * as such depends on the entity and its state. ++ */ ++ @org.jetbrains.annotations.ApiStatus.Experimental ++ void completeUsingActiveItem(); ++ ++ /** ++ * Gets the item being actively "used" or consumed. ++ * ++ * @return the item ++ */ ++ org.bukkit.inventory.@NotNull ItemStack getActiveItem(); ++ ++ /** ++ * Gets the remaining number of ticks for {@link #getActiveItem()}'s usage. ++ * ++ * @return remaining ticks to use {@link #getActiveItem()} ++ */ ++ int getActiveItemRemainingTime(); ++ ++ /** ++ * Sets the number of ticks that remain for {@link #getActiveItem()}'s ++ * usage. ++ *

      ++ * Valid values are between 0 and the max item use duration for ++ * the specific item type. ++ * ++ * @param ticks time in ticks remaining ++ */ ++ void setActiveItemRemainingTime(@org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE) int ticks); ++ ++ /** ++ * Gets if the entity is using an item (eating, drinking, etc). ++ * ++ * @return true if using an item ++ */ ++ boolean hasActiveItem(); ++ ++ /** ++ * Get how long the {@link #getActiveItem()} has been in use for. ++ * ++ * @return time used in ticks ++ */ ++ int getActiveItemUsedTime(); ++ ++ /** ++ * Get the hand using the active item. Will be either ++ * {@link org.bukkit.inventory.EquipmentSlot#HAND} or ++ * {@link org.bukkit.inventory.EquipmentSlot#OFF_HAND}. ++ * ++ * @return the hand being used ++ */ ++ org.bukkit.inventory.@NotNull EquipmentSlot getActiveItemHand(); ++ ++ /** ++ * Gets remaining time a player needs to keep hands raised with an item to finish using it. ++ * ++ * @return remaining ticks to use the item ++ * @see #getActiveItemRemainingTime() ++ */ ++ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.20.4") ++ default int getItemUseRemainingTime() { ++ return this.getActiveItemRemainingTime(); ++ } ++ ++ /** ++ * Get how long the entity's hands have been raised (Charging Bow attack, using a potion, etc) ++ * ++ * @return Get how long the players hands have been raised (Charging Bow attack, using a potion, etc) ++ * @see #getActiveItemUsedTime() ++ */ ++ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.20.4") ++ default int getHandRaisedTime() { ++ return this.getActiveItemUsedTime(); ++ } ++ ++ /** ++ * Whether this entity is using or charging an attack (Bow pulled back, drinking potion, eating food) ++ * ++ * @return whether this entity is using or charging an attack (Bow pulled back, drinking potion, eating food) ++ * @see #hasActiveItem() ++ */ ++ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.20.4") ++ default boolean isHandRaised() { ++ return this.hasActiveItem(); ++ } ++ ++ /** ++ * Gets the hand raised by this living entity. Will be either ++ * {@link org.bukkit.inventory.EquipmentSlot#HAND} or ++ * {@link org.bukkit.inventory.EquipmentSlot#OFF_HAND}. ++ * ++ * @return the hand raised ++ * @see #getActiveItemHand() ++ */ ++ @NotNull ++ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.20.4") ++ default org.bukkit.inventory.EquipmentSlot getHandRaised() { ++ return this.getActiveItemHand(); ++ } ++ // Paper end - active item API + } diff --git a/patches/api/0115-Expand-Explosions-API.patch b/patches/api/0115-Expand-Explosions-API.patch deleted file mode 100644 index fee2c850bb52..000000000000 --- a/patches/api/0115-Expand-Explosions-API.patch +++ /dev/null @@ -1,200 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 19 Dec 2017 16:24:42 -0500 -Subject: [PATCH] Expand Explosions API - -Add Entity as a Source capability, and add more API choices, and on Location. - -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index bbc636baef2e2b0586c7d517be428438ca26ab66..a8d4f7972d07ddde171b4a1ec470a4c616e02b2e 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -7,6 +7,7 @@ import java.util.HashMap; - import java.util.Map; - import org.bukkit.block.Block; - import org.bukkit.configuration.serialization.ConfigurationSerializable; -+import org.bukkit.entity.Entity; // Paper - import org.bukkit.util.NumberConversions; - import org.bukkit.util.Vector; - import org.jetbrains.annotations.NotNull; -@@ -568,6 +569,87 @@ public class Location implements Cloneable, ConfigurationSerializable { - return centerLoc; - } - -+ /** -+ * Creates explosion at this location with given power -+ * -+ * Will break blocks and ignite blocks on fire. -+ * -+ * @param power The power of explosion, where 4F is TNT -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public boolean createExplosion(float power) { -+ return this.getWorld().createExplosion(this, power); -+ } -+ -+ /** -+ * Creates explosion at this location with given power and optionally -+ * setting blocks on fire. -+ * -+ * Will break blocks. -+ * -+ * @param power The power of explosion, where 4F is TNT -+ * @param setFire Whether or not to set blocks on fire -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public boolean createExplosion(float power, boolean setFire) { -+ return this.getWorld().createExplosion(this, power, setFire); -+ } -+ -+ /** -+ * Creates explosion at this location with given power and optionally -+ * setting blocks on fire. -+ * -+ * @param power The power of explosion, where 4F is TNT -+ * @param setFire Whether or not to set blocks on fire -+ * @param breakBlocks Whether or not to have blocks be destroyed -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public boolean createExplosion(float power, boolean setFire, boolean breakBlocks) { -+ return this.getWorld().createExplosion(this, power, setFire, breakBlocks); -+ } -+ -+ /** -+ * Creates explosion at this location with given power, with the specified entity as the source. -+ * -+ * Will break blocks and ignite blocks on fire. -+ * -+ * @param source The source entity of the explosion -+ * @param power The power of explosion, where 4F is TNT -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public boolean createExplosion(@Nullable Entity source, float power) { -+ return this.getWorld().createExplosion(source, this, power, true, true); -+ } -+ -+ /** -+ * Creates explosion at this location with given power and optionally -+ * setting blocks on fire, with the specified entity as the source. -+ * -+ * Will break blocks. -+ * -+ * @param source The source entity of the explosion -+ * @param power The power of explosion, where 4F is TNT -+ * @param setFire Whether or not to set blocks on fire -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public boolean createExplosion(@Nullable Entity source, float power, boolean setFire) { -+ return this.getWorld().createExplosion(source, this, power, setFire, true); -+ } -+ -+ /** -+ * Creates explosion at this location with given power and optionally -+ * setting blocks on fire, with the specified entity as the source. -+ * -+ * @param source The source entity of the explosion -+ * @param power The power of explosion, where 4F is TNT -+ * @param setFire Whether or not to set blocks on fire -+ * @param breakBlocks Whether or not to have blocks be destroyed -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public boolean createExplosion(@NotNull Entity source, float power, boolean setFire, boolean breakBlocks) { -+ return this.getWorld().createExplosion(source, this, power, setFire, breakBlocks); -+ } -+ - /** - * Returns a list of entities within a bounding box centered around a Location. - * -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 9ffe69abd0aa706d56e4eff3587cb453a437ba26..147fa28678f09ebc0fdaf3f26ba0693a74a683f2 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -1424,6 +1424,88 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - */ - public boolean createExplosion(@NotNull Location loc, float power, boolean setFire); - -+ // Paper start -+ /** -+ * Creates explosion at given location with given power and optionally -+ * setting blocks on fire, with the specified entity as the source. -+ * -+ * @param source The source entity of the explosion -+ * @param loc Location to blow up -+ * @param power The power of explosion, where 4F is TNT -+ * @param setFire Whether or not to set blocks on fire -+ * @param breakBlocks Whether or not to have blocks be destroyed -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks); -+ -+ /** -+ * Creates explosion at given location with given power and optionally -+ * setting blocks on fire, with the specified entity as the source. -+ * -+ * Will destroy other blocks -+ * -+ * @param source The source entity of the explosion -+ * @param loc Location to blow up -+ * @param power The power of explosion, where 4F is TNT -+ * @param setFire Whether or not to set blocks on fire -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public default boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire) { -+ return createExplosion(source, loc, power, setFire, true); -+ } -+ /** -+ * Creates explosion at given location with given power, with the specified entity as the source. -+ * Will set blocks on fire and destroy blocks. -+ * -+ * @param source The source entity of the explosion -+ * @param loc Location to blow up -+ * @param power The power of explosion, where 4F is TNT -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public default boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power) { -+ return createExplosion(source, loc, power, true, true); -+ } -+ /** -+ * Creates explosion at given entities location with given power and optionally -+ * setting blocks on fire, with the specified entity as the source. -+ * -+ * @param source The source entity of the explosion -+ * @param power The power of explosion, where 4F is TNT -+ * @param setFire Whether or not to set blocks on fire -+ * @param breakBlocks Whether or not to have blocks be destroyed -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public default boolean createExplosion(@NotNull Entity source, float power, boolean setFire, boolean breakBlocks) { -+ return createExplosion(source, source.getLocation(), power, setFire, breakBlocks); -+ } -+ /** -+ * Creates explosion at given entities location with given power and optionally -+ * setting blocks on fire, with the specified entity as the source. -+ * -+ * Will destroy blocks. -+ * -+ * @param source The source entity of the explosion -+ * @param power The power of explosion, where 4F is TNT -+ * @param setFire Whether or not to set blocks on fire -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public default boolean createExplosion(@NotNull Entity source, float power, boolean setFire) { -+ return createExplosion(source, source.getLocation(), power, setFire, true); -+ } -+ -+ /** -+ * Creates explosion at given entities location with given power and optionally -+ * setting blocks on fire, with the specified entity as the source. -+ * -+ * @param source The source entity of the explosion -+ * @param power The power of explosion, where 4F is TNT -+ * @return false if explosion was canceled, otherwise true -+ */ -+ public default boolean createExplosion(@NotNull Entity source, float power) { -+ return createExplosion(source, source.getLocation(), power, true, true); -+ } -+ // Paper end -+ - /** - * Creates explosion at given coordinates with given power and optionally - * setting blocks on fire or breaking blocks. diff --git a/patches/api/0115-RangedEntity-API.patch b/patches/api/0115-RangedEntity-API.patch new file mode 100644 index 000000000000..abc8685ede5b --- /dev/null +++ b/patches/api/0115-RangedEntity-API.patch @@ -0,0 +1,188 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 26 Jun 2018 21:34:40 -0400 +Subject: [PATCH] RangedEntity API + +Allows you to determine if an entity is capable of ranged attacks, +and to perform an attack. + +diff --git a/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java b/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java +new file mode 100644 +index 0000000000000000000000000000000000000000..09c82908f63233febfe1e07fe756f1c39d23d44f +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java +@@ -0,0 +1,36 @@ ++package com.destroystokyo.paper.entity; ++ ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.entity.Mob; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public interface RangedEntity extends Mob { ++ /** ++ * Attack the specified entity using a ranged attack. ++ * ++ * @param target the entity to target ++ * @param charge How "charged" the attack is (how far back the bow was pulled for Bow attacks). ++ * This should be a value between 0 and 1, represented as targetDistance/maxDistance. ++ */ ++ void rangedAttack(LivingEntity target, float charge); ++ ++ /** ++ * Sets that the Entity is "charging" up an attack, by raising its hands ++ * ++ * @param raiseHands Whether the entities hands are raised to charge attack ++ * @deprecated use {@link #setAggressive(boolean)} ++ */ ++ @Deprecated(since = "1.19.2") ++ void setChargingAttack(boolean raiseHands); ++ ++ /** ++ * Alias to {@link LivingEntity#isHandRaised()}, if the entity is charging an attack ++ * @return If entities hands are raised ++ * @deprecated use {@link #isHandRaised()} ++ */ ++ @Deprecated(since = "1.19.2") ++ default boolean isChargingAttack() { ++ return this.isHandRaised(); ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/AbstractSkeleton.java b/src/main/java/org/bukkit/entity/AbstractSkeleton.java +index 6ffacd3af2b03a403d80fa9a141a819cbde34fc6..2d81d077015fff47c5a5b64e2e1c74f962b4ceee 100644 +--- a/src/main/java/org/bukkit/entity/AbstractSkeleton.java ++++ b/src/main/java/org/bukkit/entity/AbstractSkeleton.java +@@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull; + * of this type, instanceOf checks against the specific subtypes listed prior + * are recommended. + */ +-public interface AbstractSkeleton extends Monster { ++public interface AbstractSkeleton extends Monster, com.destroystokyo.paper.entity.RangedEntity { // Paper + + /** + * Gets the current type of this skeleton. +diff --git a/src/main/java/org/bukkit/entity/Drowned.java b/src/main/java/org/bukkit/entity/Drowned.java +index 1dee177ae6e21da000607dc8dd8fd76857f323b9..8d1ad9ef757cb1e8d72b145262df73612a76c746 100644 +--- a/src/main/java/org/bukkit/entity/Drowned.java ++++ b/src/main/java/org/bukkit/entity/Drowned.java +@@ -1,6 +1,8 @@ + package org.bukkit.entity; + ++import com.destroystokyo.paper.entity.RangedEntity; ++ + /** + * Drowned zombie. + */ +-public interface Drowned extends Zombie { } ++public interface Drowned extends Zombie, RangedEntity { } // Paper +diff --git a/src/main/java/org/bukkit/entity/Illusioner.java b/src/main/java/org/bukkit/entity/Illusioner.java +index 7c92c431b32754dca12b4d584bd6fa93ff73badf..14e6c5ee06ece3d1bbc1239afa67c847a479948f 100644 +--- a/src/main/java/org/bukkit/entity/Illusioner.java ++++ b/src/main/java/org/bukkit/entity/Illusioner.java +@@ -1,6 +1,10 @@ + package org.bukkit.entity; + ++import com.destroystokyo.paper.entity.RangedEntity; ++ + /** + * Represents an Illusioner "Illager". + */ +-public interface Illusioner extends Spellcaster { } ++public interface Illusioner extends Spellcaster, RangedEntity { // Paper ++ ++} +diff --git a/src/main/java/org/bukkit/entity/Llama.java b/src/main/java/org/bukkit/entity/Llama.java +index c43854298548391679c1d280bd42edbeed7759b9..d23226ccb0f6c25028f000ce31346cd0a8898e6a 100644 +--- a/src/main/java/org/bukkit/entity/Llama.java ++++ b/src/main/java/org/bukkit/entity/Llama.java +@@ -1,12 +1,13 @@ + package org.bukkit.entity; + ++import com.destroystokyo.paper.entity.RangedEntity; + import org.bukkit.inventory.LlamaInventory; + import org.jetbrains.annotations.NotNull; + + /** + * Represents a Llama. + */ +-public interface Llama extends ChestedHorse { ++public interface Llama extends ChestedHorse, RangedEntity { // Paper + + /** + * Represents the base color that the llama has. +diff --git a/src/main/java/org/bukkit/entity/Piglin.java b/src/main/java/org/bukkit/entity/Piglin.java +index b96e57552245e2c6d452755d4227c572266fcec7..6fdc0e0bb62189dbf3cf9ce7a87b7fbb995956a3 100644 +--- a/src/main/java/org/bukkit/entity/Piglin.java ++++ b/src/main/java/org/bukkit/entity/Piglin.java +@@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents a Piglin. + */ +-public interface Piglin extends PiglinAbstract, InventoryHolder { ++public interface Piglin extends PiglinAbstract, InventoryHolder, com.destroystokyo.paper.entity.RangedEntity { // Paper + + /** + * Get whether the piglin is able to hunt hoglins. +diff --git a/src/main/java/org/bukkit/entity/Pillager.java b/src/main/java/org/bukkit/entity/Pillager.java +index 9a2252fef56be1ed3ae2169aea46cb567e965c6c..11f38187fca830d974be01fea2966a31936184cb 100644 +--- a/src/main/java/org/bukkit/entity/Pillager.java ++++ b/src/main/java/org/bukkit/entity/Pillager.java +@@ -1,8 +1,10 @@ + package org.bukkit.entity; + ++import com.destroystokyo.paper.entity.RangedEntity; // Paper ++ + import org.bukkit.inventory.InventoryHolder; + + /** + * Illager entity. + */ +-public interface Pillager extends Illager, InventoryHolder { } ++public interface Pillager extends Illager, InventoryHolder, RangedEntity { } // Paper +diff --git a/src/main/java/org/bukkit/entity/Snowman.java b/src/main/java/org/bukkit/entity/Snowman.java +index 818efe2a4d1ac0c4d8dca6c757850d99cdc2cb4b..10f8f6d45ae9280651c3ebddd1f90acbd7d6ff29 100644 +--- a/src/main/java/org/bukkit/entity/Snowman.java ++++ b/src/main/java/org/bukkit/entity/Snowman.java +@@ -1,9 +1,11 @@ + package org.bukkit.entity; + ++import com.destroystokyo.paper.entity.RangedEntity; ++ + /** + * Represents a snowman entity + */ +-public interface Snowman extends Golem { ++public interface Snowman extends Golem, RangedEntity { // Paper + + /** + * Gets whether this snowman is in "derp mode", meaning it is not wearing a +diff --git a/src/main/java/org/bukkit/entity/Witch.java b/src/main/java/org/bukkit/entity/Witch.java +index 0ebd54df0bb072df25a6ebcf137a39829cf71bf9..6618f2129e108c0a6cd15f6d0e86426021b6ff0d 100644 +--- a/src/main/java/org/bukkit/entity/Witch.java ++++ b/src/main/java/org/bukkit/entity/Witch.java +@@ -1,9 +1,11 @@ + package org.bukkit.entity; + ++import com.destroystokyo.paper.entity.RangedEntity; ++ + /** + * Represents a Witch + */ +-public interface Witch extends Raider { ++public interface Witch extends Raider, RangedEntity { // Paper + + /** + * Gets whether the witch is drinking a potion +diff --git a/src/main/java/org/bukkit/entity/Wither.java b/src/main/java/org/bukkit/entity/Wither.java +index b3a5d7a91e483b9fd569dd3c8cec989498a50104..87a814f63c3f35be35bfa210c9248ad211c0dd8f 100644 +--- a/src/main/java/org/bukkit/entity/Wither.java ++++ b/src/main/java/org/bukkit/entity/Wither.java +@@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a Wither boss + */ +-public interface Wither extends Monster, Boss { ++public interface Wither extends Monster, Boss, com.destroystokyo.paper.entity.RangedEntity { // Paper + + /** + * {@inheritDoc} diff --git a/patches/api/0116-Add-World.getEntity-UUID-API.patch b/patches/api/0116-Add-World.getEntity-UUID-API.patch new file mode 100644 index 000000000000..148debac203c --- /dev/null +++ b/patches/api/0116-Add-World.getEntity-UUID-API.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brokkonaut +Date: Tue, 3 Jul 2018 16:07:16 +0200 +Subject: [PATCH] Add World.getEntity(UUID) API + + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 62a0e6efcc33f56b26fa917276ac09737d4bf362..002bfadfd4efa3d376a0a7bc5c752e8a02494eec 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -932,6 +932,17 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @NotNull + public Collection getNearbyEntities(@NotNull Location location, double x, double y, double z); + ++ // Paper start - getEntity by UUID API ++ /** ++ * Gets an entity in this world by its UUID ++ * ++ * @param uuid the UUID of the entity ++ * @return the entity with the given UUID, or null if it isn't found ++ */ ++ @Nullable ++ public Entity getEntity(@NotNull java.util.UUID uuid); ++ // Paper end ++ + /** + * Returns a list of entities within a bounding box centered around a + * Location. diff --git a/patches/api/0116-ItemStack-API-additions-for-quantity-flags-lore.patch b/patches/api/0116-ItemStack-API-additions-for-quantity-flags-lore.patch deleted file mode 100644 index d8bba965f18e..000000000000 --- a/patches/api/0116-ItemStack-API-additions-for-quantity-flags-lore.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 22 Jun 2018 22:59:18 -0400 -Subject: [PATCH] ItemStack API additions for quantity/flags/lore - - -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 54d7c4b78f7fb01d8c11c19f038642b155334770..7559f75dcc6665fa3d19d6e53a141a214407d1c5 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -3,6 +3,7 @@ package org.bukkit.inventory; - import com.google.common.base.Preconditions; - import com.google.common.collect.ImmutableMap; - import java.util.LinkedHashMap; -+import java.util.List; // Paper - import java.util.Map; - import org.bukkit.Bukkit; - import org.bukkit.Material; -@@ -647,5 +648,185 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - // Requires access to NMS - return ensureServerConversions().getMaxItemUseDuration(); - } -+ -+ /** -+ * Clones the itemstack and returns it a single quantity. -+ * @return The new itemstack with 1 quantity -+ */ -+ @NotNull -+ public ItemStack asOne() { -+ return asQuantity(1); -+ } -+ -+ /** -+ * Clones the itemstack and returns it as the specified quantity -+ * @param qty The quantity of the cloned item -+ * @return The new itemstack with specified quantity -+ */ -+ @NotNull -+ public ItemStack asQuantity(int qty) { -+ ItemStack clone = clone(); -+ clone.setAmount(qty); -+ return clone; -+ } -+ -+ /** -+ * Adds 1 to this itemstack. Will not go over the items max stack size. -+ * @return The same item (not a clone) -+ */ -+ @NotNull -+ public ItemStack add() { -+ return add(1); -+ } -+ -+ /** -+ * Adds quantity to this itemstack. Will not go over the items max stack size. -+ * -+ * @param qty The amount to add -+ * @return The same item (not a clone) -+ */ -+ @NotNull -+ public ItemStack add(int qty) { -+ setAmount(Math.min(getMaxStackSize(), getAmount() + qty)); -+ return this; -+ } -+ -+ /** -+ * Subtracts 1 to this itemstack. Going to 0 or less will invalidate the item. -+ * @return The same item (not a clone) -+ */ -+ @NotNull -+ public ItemStack subtract() { -+ return subtract(1); -+ } -+ -+ /** -+ * Subtracts quantity to this itemstack. Going to 0 or less will invalidate the item. -+ * -+ * @param qty The amount to add -+ * @return The same item (not a clone) -+ */ -+ @NotNull -+ public ItemStack subtract(int qty) { -+ setAmount(Math.max(0, getAmount() - qty)); -+ return this; -+ } -+ -+ /** -+ * If the item has lore, returns it, else it will return null -+ * @return The lore, or null -+ * @deprecated in favor of {@link #lore()} -+ */ -+ @Deprecated -+ public @Nullable List getLore() { -+ if (!hasItemMeta()) { -+ return null; -+ } -+ ItemMeta itemMeta = getItemMeta(); -+ if (!itemMeta.hasLore()) { -+ return null; -+ } -+ return itemMeta.getLore(); -+ } -+ -+ /** -+ * If the item has lore, returns it, else it will return null -+ * @return The lore, or null -+ */ -+ public @Nullable List lore() { -+ if (!this.hasItemMeta()) { -+ return null; -+ } -+ final ItemMeta itemMeta = getItemMeta(); -+ if (!itemMeta.hasLore()) { -+ return null; -+ } -+ return itemMeta.lore(); -+ } -+ -+ /** -+ * Sets the lore for this item. -+ * Removes lore when given null. -+ * -+ * @param lore the lore that will be set -+ * @deprecated in favour of {@link #lore(List)} -+ */ -+ @Deprecated -+ public void setLore(@Nullable List lore) { -+ ItemMeta itemMeta = getItemMeta(); -+ if (itemMeta == null) { -+ throw new IllegalStateException("Cannot set lore on " + getType()); -+ } -+ itemMeta.setLore(lore); -+ setItemMeta(itemMeta); -+ } -+ -+ /** -+ * Sets the lore for this item. -+ * Removes lore when given null. -+ * -+ * @param lore the lore that will be set -+ */ -+ public void lore(@Nullable List lore) { -+ ItemMeta itemMeta = getItemMeta(); -+ if (itemMeta == null) { -+ throw new IllegalStateException("Cannot set lore on " + getType()); -+ } -+ itemMeta.lore(lore); -+ this.setItemMeta(itemMeta); -+ } -+ -+ /** -+ * Set itemflags which should be ignored when rendering a ItemStack in the Client. This Method does silently ignore double set itemFlags. -+ * -+ * @param itemFlags The hideflags which shouldn't be rendered -+ */ -+ public void addItemFlags(@NotNull ItemFlag... itemFlags) { -+ ItemMeta itemMeta = getItemMeta(); -+ if (itemMeta == null) { -+ throw new IllegalStateException("Cannot add flags on " + getType()); -+ } -+ itemMeta.addItemFlags(itemFlags); -+ setItemMeta(itemMeta); -+ } -+ -+ /** -+ * Remove specific set of itemFlags. This tells the Client it should render it again. This Method does silently ignore double removed itemFlags. -+ * -+ * @param itemFlags Hideflags which should be removed -+ */ -+ public void removeItemFlags(@NotNull ItemFlag... itemFlags) { -+ ItemMeta itemMeta = getItemMeta(); -+ if (itemMeta == null) { -+ throw new IllegalStateException("Cannot remove flags on " + getType()); -+ } -+ itemMeta.removeItemFlags(itemFlags); -+ setItemMeta(itemMeta); -+ } -+ -+ /** -+ * Get current set itemFlags. The collection returned is unmodifiable. -+ * -+ * @return A set of all itemFlags set -+ */ -+ @NotNull -+ public java.util.Set getItemFlags() { -+ ItemMeta itemMeta = getItemMeta(); -+ if (itemMeta == null) { -+ return java.util.Collections.emptySet(); -+ } -+ return itemMeta.getItemFlags(); -+ } -+ -+ /** -+ * Check if the specified flag is present on this item. -+ * -+ * @param flag the flag to check -+ * @return if it is present -+ */ -+ public boolean hasItemFlag(@NotNull ItemFlag flag) { -+ ItemMeta itemMeta = getItemMeta(); -+ return itemMeta != null && itemMeta.hasItemFlag(flag); -+ } - // Paper end - } diff --git a/patches/api/0117-InventoryCloseEvent-Reason-API.patch b/patches/api/0117-InventoryCloseEvent-Reason-API.patch new file mode 100644 index 000000000000..524199660efa --- /dev/null +++ b/patches/api/0117-InventoryCloseEvent-Reason-API.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 3 Jul 2018 21:52:52 -0400 +Subject: [PATCH] InventoryCloseEvent Reason API + +Allows you to determine why an inventory was closed, enabling plugin developers +to "confirm" things based on if it was player triggered close or not. + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index 4d72da8b04c72f296bc3f8e00e54f4d79e531d44..a7824c9f133f433cb9f98326348b4b6ae725a39d 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -187,6 +187,15 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder + */ + public void closeInventory(); + ++ // Paper start ++ /** ++ * Force-closes the currently open inventory view for this player, if any. ++ * ++ * @param reason why the inventory is closing ++ */ ++ public void closeInventory(@NotNull org.bukkit.event.inventory.InventoryCloseEvent.Reason reason); ++ // Paper end ++ + /** + * Returns the ItemStack currently in your hand, can be empty. + * +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java +index c0cc82d98348e8aae3cb56bafb2fcb590b03094f..4db0a07db156c61867644f50c185e63b695e2462 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java +@@ -30,9 +30,60 @@ import org.jetbrains.annotations.NotNull; + */ + public class InventoryCloseEvent extends InventoryEvent { + private static final HandlerList handlers = new HandlerList(); ++ // Paper start ++ private final Reason reason; ++ @NotNull ++ public Reason getReason() { ++ return reason; ++ } ++ ++ public enum Reason { ++ /** ++ * Unknown reason ++ */ ++ UNKNOWN, ++ /** ++ * Player is teleporting ++ */ ++ TELEPORT, ++ /** ++ * Player is no longer permitted to use this inventory ++ */ ++ CANT_USE, ++ /** ++ * The chunk the inventory was in was unloaded ++ */ ++ UNLOADED, ++ /** ++ * Opening new inventory instead ++ */ ++ OPEN_NEW, ++ /** ++ * Closed ++ */ ++ PLAYER, ++ /** ++ * Closed due to disconnect ++ */ ++ DISCONNECT, ++ /** ++ * The player died ++ */ ++ DEATH, ++ /** ++ * Closed by Bukkit API ++ */ ++ PLUGIN, ++ } + + public InventoryCloseEvent(@NotNull InventoryView transaction) { ++ this(transaction, Reason.UNKNOWN); ++ } ++ ++ public InventoryCloseEvent(@NotNull InventoryView transaction, @NotNull Reason reason) { + super(transaction); ++ this.reason = reason; ++ // Paper end + } + + /** diff --git a/patches/api/0117-LivingEntity-Hand-Raised-Item-Use-API.patch b/patches/api/0117-LivingEntity-Hand-Raised-Item-Use-API.patch deleted file mode 100644 index 8bebf5140ba7..000000000000 --- a/patches/api/0117-LivingEntity-Hand-Raised-Item-Use-API.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 29 Jun 2018 00:19:19 -0400 -Subject: [PATCH] LivingEntity Hand Raised/Item Use API - -How long an entity has raised hands to charge an attack or use an item - -diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java -index bd9222b9b5e7ec1f3aebe37838775f345e868150..34c2ae10e2a230ef88a756cf2024edcda2429fbf 100644 ---- a/src/main/java/org/bukkit/entity/HumanEntity.java -+++ b/src/main/java/org/bukkit/entity/HumanEntity.java -@@ -307,7 +307,9 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder - * - * @return the item being used by the player, or null if they are not using - * an item -+ * @deprecated Deprecated in favor of {@link LivingEntity#getActiveItem()} - */ -+ @Deprecated // Paper - @Nullable - public ItemStack getItemInUse(); - -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index 588ad09a764236cf858a4e6689cf4ee5246e6f08..1dd9f7ac1f26c253b8181519aa1873784bc54a07 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -649,5 +649,42 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - * @param delay Delay in ticks - */ - void setShieldBlockingDelay(int delay); -+ -+ /** -+ * Get's the item being actively "used" or consumed. -+ * @return The item -+ */ -+ @NotNull -+ org.bukkit.inventory.ItemStack getActiveItem(); -+ -+ /** -+ * Get's remaining time a player needs to keep hands raised with an item to finish using it. -+ * @return Remaining ticks to use the item -+ */ -+ int getItemUseRemainingTime(); -+ -+ /** -+ * Get how long the players hands have been raised (Charging Bow attack, using a potion, etc) -+ * -+ * @return Get how long the players hands have been raised (Charging Bow attack, using a potion, etc) -+ */ -+ int getHandRaisedTime(); -+ -+ /** -+ * Whether or not this entity is using or charging an attack (Bow pulled back, drinking potion, eating food) -+ * -+ * @return Whether or not this entity is using or charging an attack (Bow pulled back, drinking potion, eating food) -+ */ -+ boolean isHandRaised(); -+ -+ /** -+ * Gets the hand raised by this living entity. Will be either -+ * {@link org.bukkit.inventory.EquipmentSlot#HAND} or -+ * {@link org.bukkit.inventory.EquipmentSlot#OFF_HAND}. -+ * -+ * @return the hand raised -+ */ -+ @NotNull -+ org.bukkit.inventory.EquipmentSlot getHandRaised(); - // Paper end - } diff --git a/patches/api/0121-Allow-setting-the-vex-s-summoner.patch b/patches/api/0118-Allow-setting-the-vex-s-summoner.patch similarity index 100% rename from patches/api/0121-Allow-setting-the-vex-s-summoner.patch rename to patches/api/0118-Allow-setting-the-vex-s-summoner.patch diff --git a/patches/api/0118-RangedEntity-API.patch b/patches/api/0118-RangedEntity-API.patch deleted file mode 100644 index 983f1d2d53e3..000000000000 --- a/patches/api/0118-RangedEntity-API.patch +++ /dev/null @@ -1,181 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 26 Jun 2018 21:34:40 -0400 -Subject: [PATCH] RangedEntity API - -Allows you to determine if an entity is capable of ranged attacks, -and to perform an attack. - -diff --git a/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java b/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f2e3233a3d1744e32fb76d3731b9858ef0067e30 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java -@@ -0,0 +1,31 @@ -+package com.destroystokyo.paper.entity; -+ -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.entity.Mob; -+import org.jetbrains.annotations.NotNull; -+ -+public interface RangedEntity extends Mob { -+ /** -+ * Attack the specified entity using a ranged attack. -+ * -+ * @param target the entity to target -+ * @param charge How "charged" the attack is (how far back the bow was pulled for Bow attacks). -+ * This should be a value between 0 and 1, represented as targetDistance/maxDistance. -+ */ -+ void rangedAttack(@NotNull LivingEntity target, float charge); -+ -+ /** -+ * Sets that the Entity is "charging" up an attack, by raising its hands -+ * -+ * @param raiseHands Whether the entities hands are raised to charge attack -+ */ -+ void setChargingAttack(boolean raiseHands); -+ -+ /** -+ * Alias to {@link LivingEntity#isHandRaised()}, if the entity is charging an attack -+ * @return If entities hands are raised -+ */ -+ default boolean isChargingAttack() { -+ return isHandRaised(); -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/AbstractSkeleton.java b/src/main/java/org/bukkit/entity/AbstractSkeleton.java -index e2fce218c6623b3c932c2782a66dea73dccd33f1..4f4f1e48cdaee0d845f60666569e48731be3fbb9 100644 ---- a/src/main/java/org/bukkit/entity/AbstractSkeleton.java -+++ b/src/main/java/org/bukkit/entity/AbstractSkeleton.java -@@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull; - * of this type, instanceOf checks against the specific subtypes listed prior - * are recommended. - */ --public interface AbstractSkeleton extends Monster { -+public interface AbstractSkeleton extends Monster, com.destroystokyo.paper.entity.RangedEntity { // Paper - - /** - * Gets the current type of this skeleton. -diff --git a/src/main/java/org/bukkit/entity/Drowned.java b/src/main/java/org/bukkit/entity/Drowned.java -index 1dee177ae6e21da000607dc8dd8fd76857f323b9..8d1ad9ef757cb1e8d72b145262df73612a76c746 100644 ---- a/src/main/java/org/bukkit/entity/Drowned.java -+++ b/src/main/java/org/bukkit/entity/Drowned.java -@@ -1,6 +1,8 @@ - package org.bukkit.entity; - -+import com.destroystokyo.paper.entity.RangedEntity; -+ - /** - * Drowned zombie. - */ --public interface Drowned extends Zombie { } -+public interface Drowned extends Zombie, RangedEntity { } // Paper -diff --git a/src/main/java/org/bukkit/entity/Illusioner.java b/src/main/java/org/bukkit/entity/Illusioner.java -index 7c92c431b32754dca12b4d584bd6fa93ff73badf..14e6c5ee06ece3d1bbc1239afa67c847a479948f 100644 ---- a/src/main/java/org/bukkit/entity/Illusioner.java -+++ b/src/main/java/org/bukkit/entity/Illusioner.java -@@ -1,6 +1,10 @@ - package org.bukkit.entity; - -+import com.destroystokyo.paper.entity.RangedEntity; -+ - /** - * Represents an Illusioner "Illager". - */ --public interface Illusioner extends Spellcaster { } -+public interface Illusioner extends Spellcaster, RangedEntity { // Paper -+ -+} -diff --git a/src/main/java/org/bukkit/entity/Llama.java b/src/main/java/org/bukkit/entity/Llama.java -index c43854298548391679c1d280bd42edbeed7759b9..d23226ccb0f6c25028f000ce31346cd0a8898e6a 100644 ---- a/src/main/java/org/bukkit/entity/Llama.java -+++ b/src/main/java/org/bukkit/entity/Llama.java -@@ -1,12 +1,13 @@ - package org.bukkit.entity; - -+import com.destroystokyo.paper.entity.RangedEntity; - import org.bukkit.inventory.LlamaInventory; - import org.jetbrains.annotations.NotNull; - - /** - * Represents a Llama. - */ --public interface Llama extends ChestedHorse { -+public interface Llama extends ChestedHorse, RangedEntity { // Paper - - /** - * Represents the base color that the llama has. -diff --git a/src/main/java/org/bukkit/entity/Piglin.java b/src/main/java/org/bukkit/entity/Piglin.java -index b96e57552245e2c6d452755d4227c572266fcec7..6fdc0e0bb62189dbf3cf9ce7a87b7fbb995956a3 100644 ---- a/src/main/java/org/bukkit/entity/Piglin.java -+++ b/src/main/java/org/bukkit/entity/Piglin.java -@@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; - /** - * Represents a Piglin. - */ --public interface Piglin extends PiglinAbstract, InventoryHolder { -+public interface Piglin extends PiglinAbstract, InventoryHolder, com.destroystokyo.paper.entity.RangedEntity { // Paper - - /** - * Get whether the piglin is able to hunt hoglins. -diff --git a/src/main/java/org/bukkit/entity/Pillager.java b/src/main/java/org/bukkit/entity/Pillager.java -index 9a2252fef56be1ed3ae2169aea46cb567e965c6c..11f38187fca830d974be01fea2966a31936184cb 100644 ---- a/src/main/java/org/bukkit/entity/Pillager.java -+++ b/src/main/java/org/bukkit/entity/Pillager.java -@@ -1,8 +1,10 @@ - package org.bukkit.entity; - -+import com.destroystokyo.paper.entity.RangedEntity; // Paper -+ - import org.bukkit.inventory.InventoryHolder; - - /** - * Illager entity. - */ --public interface Pillager extends Illager, InventoryHolder { } -+public interface Pillager extends Illager, InventoryHolder, RangedEntity { } // Paper -diff --git a/src/main/java/org/bukkit/entity/Snowman.java b/src/main/java/org/bukkit/entity/Snowman.java -index 818efe2a4d1ac0c4d8dca6c757850d99cdc2cb4b..10f8f6d45ae9280651c3ebddd1f90acbd7d6ff29 100644 ---- a/src/main/java/org/bukkit/entity/Snowman.java -+++ b/src/main/java/org/bukkit/entity/Snowman.java -@@ -1,9 +1,11 @@ - package org.bukkit.entity; - -+import com.destroystokyo.paper.entity.RangedEntity; -+ - /** - * Represents a snowman entity - */ --public interface Snowman extends Golem { -+public interface Snowman extends Golem, RangedEntity { // Paper - - /** - * Gets whether this snowman is in "derp mode", meaning it is not wearing a -diff --git a/src/main/java/org/bukkit/entity/Witch.java b/src/main/java/org/bukkit/entity/Witch.java -index b4343903b66a7fb5250c1da2e09c9e5863c20daf..aa88aede6c4e66a608a63d07bc66d60357b0bee9 100644 ---- a/src/main/java/org/bukkit/entity/Witch.java -+++ b/src/main/java/org/bukkit/entity/Witch.java -@@ -1,7 +1,9 @@ - package org.bukkit.entity; - -+import com.destroystokyo.paper.entity.RangedEntity; -+ - /** - * Represents a Witch - */ --public interface Witch extends Raider { -+public interface Witch extends Raider, RangedEntity { // Paper - } -diff --git a/src/main/java/org/bukkit/entity/Wither.java b/src/main/java/org/bukkit/entity/Wither.java -index 225c65a20a3e33dfb14e108a36f2f4bc60f7920c..b86f0196e6eb8070830f63a94f732522c2a6c2f1 100644 ---- a/src/main/java/org/bukkit/entity/Wither.java -+++ b/src/main/java/org/bukkit/entity/Wither.java -@@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable; - /** - * Represents a Wither boss - */ --public interface Wither extends Monster, Boss { -+public interface Wither extends Monster, Boss, com.destroystokyo.paper.entity.RangedEntity { // Paper - - /** - * {@inheritDoc} diff --git a/patches/api/0119-Add-World.getEntity-UUID-API.patch b/patches/api/0119-Add-World.getEntity-UUID-API.patch deleted file mode 100644 index 7fbb9ef9d676..000000000000 --- a/patches/api/0119-Add-World.getEntity-UUID-API.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brokkonaut -Date: Tue, 3 Jul 2018 16:07:16 +0200 -Subject: [PATCH] Add World.getEntity(UUID) API - - -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 147fa28678f09ebc0fdaf3f26ba0693a74a683f2..f46032ac8d48ba172e6a9157dd6b477ddf2cd4cb 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -944,6 +944,17 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - @NotNull - public Collection getNearbyEntities(@NotNull Location location, double x, double y, double z); - -+ // Paper start - getEntity by UUID API -+ /** -+ * Gets an entity in this world by its UUID -+ * -+ * @param uuid the UUID of the entity -+ * @return the entity with the given UUID, or null if it isn't found -+ */ -+ @Nullable -+ public Entity getEntity(@NotNull java.util.UUID uuid); -+ // Paper end -+ - /** - * Returns a list of entities within a bounding box centered around a - * Location. diff --git a/patches/api/0119-Entity-getChunk-API.patch b/patches/api/0119-Entity-getChunk-API.patch new file mode 100644 index 000000000000..939fdeba04ce --- /dev/null +++ b/patches/api/0119-Entity-getChunk-API.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 4 Jul 2018 02:25:48 -0400 +Subject: [PATCH] Entity#getChunk API + +Get the chunk the entity is currently registered to + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index ca81360956276047602958949148b6a70cc3e954..45f06224d476551267e9b083985051ae9954d756 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -3,6 +3,7 @@ package org.bukkit.entity; + import java.util.List; + import java.util.Set; + import java.util.UUID; ++import org.bukkit.Chunk; // Paper + import org.bukkit.EntityEffect; + import org.bukkit.Location; + import org.bukkit.Nameable; +@@ -812,5 +813,16 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + * @return True if entity spawned from a mob spawner + */ + boolean fromMobSpawner(); ++ ++ /** ++ * Gets the latest chunk an entity is currently or was in. ++ * ++ * @return The current, or most recent chunk if the entity is invalid (which may load the chunk) ++ */ ++ @NotNull ++ default Chunk getChunk() { ++ // TODO remove impl here ++ return getLocation().getChunk(); ++ } + // Paper end + } diff --git a/patches/api/0120-EnderDragon-Events.patch b/patches/api/0120-EnderDragon-Events.patch new file mode 100644 index 000000000000..510edc18b91f --- /dev/null +++ b/patches/api/0120-EnderDragon-Events.patch @@ -0,0 +1,220 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 21 Jul 2018 01:51:05 -0500 +Subject: [PATCH] EnderDragon Events + + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..242eb9c07866365568c036819be2b4f882319aa1 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java +@@ -0,0 +1,74 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import java.util.Collection; ++import org.bukkit.entity.AreaEffectCloud; ++import org.bukkit.entity.DragonFireball; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a DragonFireball collides with a block/entity and spawns an AreaEffectCloud ++ */ ++@NullMarked ++public class EnderDragonFireballHitEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Collection targets; ++ private final AreaEffectCloud areaEffectCloud; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EnderDragonFireballHitEvent(final DragonFireball fireball, final Collection targets, final AreaEffectCloud areaEffectCloud) { ++ super(fireball); ++ this.targets = targets; ++ this.areaEffectCloud = areaEffectCloud; ++ } ++ ++ /** ++ * The fireball involved in this event ++ */ ++ @Override ++ public DragonFireball getEntity() { ++ return (DragonFireball) super.getEntity(); ++ } ++ ++ /** ++ * The living entities hit by fireball ++ * ++ * @return the targets ++ */ ++ public Collection getTargets() { ++ return this.targets; ++ } ++ ++ /** ++ * @return The area effect cloud spawned in this collision ++ */ ++ public AreaEffectCloud getAreaEffectCloud() { ++ return this.areaEffectCloud; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..47cf33ef97ce1b92bc13c4d3a6c49d050e344eb1 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java +@@ -0,0 +1,61 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.AreaEffectCloud; ++import org.bukkit.entity.EnderDragon; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when an EnderDragon spawns an AreaEffectCloud by shooting flames ++ */ ++@NullMarked ++public class EnderDragonFlameEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final AreaEffectCloud areaEffectCloud; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EnderDragonFlameEvent(final EnderDragon enderDragon, final AreaEffectCloud areaEffectCloud) { ++ super(enderDragon); ++ this.areaEffectCloud = areaEffectCloud; ++ } ++ ++ /** ++ * The enderdragon involved in this event ++ */ ++ @Override ++ public EnderDragon getEntity() { ++ return (EnderDragon) super.getEntity(); ++ } ++ ++ /** ++ * @return The area effect cloud spawned in this collision ++ */ ++ public AreaEffectCloud getAreaEffectCloud() { ++ return this.areaEffectCloud; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7dd6e17b648868cf5d549f1e779e5d92439751dd +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java +@@ -0,0 +1,61 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.DragonFireball; ++import org.bukkit.entity.EnderDragon; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when an EnderDragon shoots a fireball ++ */ ++@NullMarked ++public class EnderDragonShootFireballEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final DragonFireball fireball; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EnderDragonShootFireballEvent(final EnderDragon entity, final DragonFireball fireball) { ++ super(entity); ++ this.fireball = fireball; ++ } ++ ++ /** ++ * The enderdragon shooting the fireball ++ */ ++ @Override ++ public EnderDragon getEntity() { ++ return (EnderDragon) super.getEntity(); ++ } ++ ++ /** ++ * @return The fireball being shot ++ */ ++ public DragonFireball getFireball() { ++ return this.fireball; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0120-InventoryCloseEvent-Reason-API.patch b/patches/api/0120-InventoryCloseEvent-Reason-API.patch deleted file mode 100644 index 2205a173d479..000000000000 --- a/patches/api/0120-InventoryCloseEvent-Reason-API.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 3 Jul 2018 21:52:52 -0400 -Subject: [PATCH] InventoryCloseEvent Reason API - -Allows you to determine why an inventory was closed, enabling plugin developers -to "confirm" things based on if it was player triggered close or not. - -diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java -index 6ef0d7f3dcb779fb7dc5786e7433262092908eaa..b007b582d344b79ee67751fd1e21f6cef6a1a950 100644 ---- a/src/main/java/org/bukkit/entity/HumanEntity.java -+++ b/src/main/java/org/bukkit/entity/HumanEntity.java -@@ -158,6 +158,15 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder - */ - public void closeInventory(); - -+ // Paper start -+ /** -+ * Force-closes the currently open inventory view for this player, if any. -+ * -+ * @param reason why the inventory is closing -+ */ -+ public void closeInventory(@NotNull org.bukkit.event.inventory.InventoryCloseEvent.Reason reason); -+ // Paper end -+ - /** - * Returns the ItemStack currently in your hand, can be empty. - * -diff --git a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java -index 5861247c1b8ee4fe2736fd5098e05a2ca9ab78ea..21ad8888c0e403bfc63518502577d651c02dda05 100644 ---- a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java -+++ b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java -@@ -11,9 +11,60 @@ import org.jetbrains.annotations.NotNull; - */ - public class InventoryCloseEvent extends InventoryEvent { - private static final HandlerList handlers = new HandlerList(); -+ // Paper start -+ private final Reason reason; -+ @NotNull -+ public Reason getReason() { -+ return reason; -+ } -+ -+ public enum Reason { -+ /** -+ * Unknown reason -+ */ -+ UNKNOWN, -+ /** -+ * Player is teleporting -+ */ -+ TELEPORT, -+ /** -+ * Player is no longer permitted to use this inventory -+ */ -+ CANT_USE, -+ /** -+ * The chunk the inventory was in was unloaded -+ */ -+ UNLOADED, -+ /** -+ * Opening new inventory instead -+ */ -+ OPEN_NEW, -+ /** -+ * Closed -+ */ -+ PLAYER, -+ /** -+ * Closed due to disconnect -+ */ -+ DISCONNECT, -+ /** -+ * The player died -+ */ -+ DEATH, -+ /** -+ * Closed by Bukkit API -+ */ -+ PLUGIN, -+ } - - public InventoryCloseEvent(@NotNull InventoryView transaction) { -+ this(transaction, Reason.UNKNOWN); -+ } -+ -+ public InventoryCloseEvent(@NotNull InventoryView transaction, @NotNull Reason reason) { - super(transaction); -+ this.reason = reason; -+ // Paper end - } - - /** diff --git a/patches/api/0121-PlayerElytraBoostEvent.patch b/patches/api/0121-PlayerElytraBoostEvent.patch new file mode 100644 index 000000000000..b17cf589acb0 --- /dev/null +++ b/patches/api/0121-PlayerElytraBoostEvent.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 21 Jul 2018 01:59:53 -0500 +Subject: [PATCH] PlayerElytraBoostEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7d41a5c2dc6ca659bfad41e70cbeac2349c2b0f3 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java +@@ -0,0 +1,99 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.entity.Firework; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.EquipmentSlot; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a player boosts elytra flight with a firework ++ */ ++@NullMarked ++public class PlayerElytraBoostEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ItemStack itemStack; ++ private final Firework firework; ++ private boolean consume = true; ++ private final EquipmentSlot hand; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerElytraBoostEvent(final Player player, final ItemStack itemStack, final Firework firework, final EquipmentSlot hand) { ++ super(player); ++ this.itemStack = itemStack; ++ this.firework = firework; ++ this.hand = hand; ++ } ++ ++ /** ++ * Get the firework itemstack used ++ * ++ * @return ItemStack of firework ++ */ ++ public ItemStack getItemStack() { ++ return this.itemStack; ++ } ++ ++ /** ++ * Get the firework entity that was spawned ++ * ++ * @return Firework entity ++ */ ++ public Firework getFirework() { ++ return this.firework; ++ } ++ ++ /** ++ * Get whether to consume the firework or not ++ * ++ * @return {@code true} to consume ++ */ ++ public boolean shouldConsume() { ++ return this.consume; ++ } ++ ++ /** ++ * Set whether to consume the firework or not ++ * ++ * @param consume {@code true} to consume ++ */ ++ public void setShouldConsume(final boolean consume) { ++ this.consume = consume; ++ } ++ ++ /** ++ * Gets the hand holding the firework used for boosting this player. ++ * ++ * @return interaction hand ++ */ ++ public EquipmentSlot getHand() { ++ return this.hand; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0122-Entity-getChunk-API.patch b/patches/api/0122-Entity-getChunk-API.patch deleted file mode 100644 index 78f10f07323c..000000000000 --- a/patches/api/0122-Entity-getChunk-API.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 4 Jul 2018 02:25:48 -0400 -Subject: [PATCH] Entity#getChunk API - -Get the chunk the entity is currently registered to - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index b9a61d06d72831dc0c591e129553453a537d3785..df07eb07896790a09d1022daef5cffc6a435f739 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -3,6 +3,7 @@ package org.bukkit.entity; - import java.util.List; - import java.util.Set; - import java.util.UUID; -+import org.bukkit.Chunk; // Paper - import org.bukkit.EntityEffect; - import org.bukkit.Location; - import org.bukkit.Nameable; -@@ -688,5 +689,16 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - * @return True if entity spawned from a mob spawner - */ - boolean fromMobSpawner(); -+ -+ /** -+ * Gets the latest chunk an entity is currently or was in. -+ * -+ * @return The current, or most recent chunk if the entity is invalid (which may load the chunk) -+ */ -+ @NotNull -+ default Chunk getChunk() { -+ // TODO remove impl here -+ return getLocation().getChunk(); -+ } - // Paper end - } diff --git a/patches/api/0122-PlayerLaunchProjectileEvent.patch b/patches/api/0122-PlayerLaunchProjectileEvent.patch new file mode 100644 index 000000000000..9078e566ca06 --- /dev/null +++ b/patches/api/0122-PlayerLaunchProjectileEvent.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 21 Jul 2018 03:10:50 -0500 +Subject: [PATCH] PlayerLaunchProjectileEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a6d483e6be8b8527d7cfd676f6056179e8e9bf33 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java +@@ -0,0 +1,92 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.entity.Projectile; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityShootBowEvent; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player shoots a projectile. ++ *

      ++ * Notably this event is not called for arrows as the player does not launch them, rather shoots them with the help ++ * of a bow or crossbow. A plugin may listen to {@link EntityShootBowEvent} ++ * for these actions instead. ++ */ ++@NullMarked ++public class PlayerLaunchProjectileEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Projectile projectile; ++ private final ItemStack itemStack; ++ private boolean consumeItem = true; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerLaunchProjectileEvent(final Player shooter, final ItemStack itemStack, final Projectile projectile) { ++ super(shooter); ++ this.itemStack = itemStack; ++ this.projectile = projectile; ++ } ++ ++ /** ++ * Gets the projectile which will be launched by this event ++ * ++ * @return the launched projectile ++ */ ++ public Projectile getProjectile() { ++ return this.projectile; ++ } ++ ++ /** ++ * Get the ItemStack used to fire the projectile ++ * ++ * @return The ItemStack used ++ */ ++ public ItemStack getItemStack() { ++ return this.itemStack; ++ } ++ ++ /** ++ * Get whether to consume the ItemStack or not ++ * ++ * @return {@code true} to consume ++ */ ++ public boolean shouldConsume() { ++ return this.consumeItem; ++ } ++ ++ /** ++ * Set whether to consume the ItemStack or not ++ * ++ * @param consumeItem {@code true} to consume ++ */ ++ public void setShouldConsume(final boolean consumeItem) { ++ this.consumeItem = consumeItem; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0123-Add-an-asterisk-to-legacy-API-plugins.patch b/patches/api/0123-Add-an-asterisk-to-legacy-API-plugins.patch deleted file mode 100644 index 847f6fcfb6f7..000000000000 --- a/patches/api/0123-Add-an-asterisk-to-legacy-API-plugins.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Tue, 1 Dec 2020 14:57:02 +0100 -Subject: [PATCH] Add an asterisk to legacy API plugins - -Not here to name and shame, only so server admins can be aware of which -plugins have and haven't been updated. - -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 355c46f1c1f08072446f3cc92c0d22898933a7fc..cbf7df30a7ec8445c8492e3b9f108747dbe1717b 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -101,5 +101,11 @@ public interface UnsafeValues { - default com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { - return new com.destroystokyo.paper.util.VersionFetcher.DummyVersionFetcher(); - } -+ -+ boolean isSupportedApiVersion(String apiVersion); -+ -+ static boolean isLegacyPlugin(org.bukkit.plugin.Plugin plugin) { -+ return !Bukkit.getUnsafe().isSupportedApiVersion(plugin.getDescription().getAPIVersion()); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java -index 4de959bbd1270d7d6ea8e5e69521bcca6abe2138..1aa58c59e1e8738bbdc77752885ff3b18b29de42 100644 ---- a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java -+++ b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java -@@ -52,9 +52,15 @@ public class PluginsCommand extends BukkitCommand { - } - - Plugin plugin = entry.getValue(); -- -+ - pluginList.append(plugin.isEnabled() ? ChatColor.GREEN : ChatColor.RED); -- pluginList.append(plugin.getDescription().getName()); -+ // Paper start - Add an asterisk to legacy plugins (so admins are aware) -+ String pluginName = plugin.getDescription().getName(); -+ if (org.bukkit.UnsafeValues.isLegacyPlugin(plugin)) { -+ pluginName += "*"; -+ } -+ pluginList.append(pluginName); -+ // Paper end - - if (plugin.getDescription().getProvides().size() > 0) { - pluginList.append(" (").append(String.join(", ", plugin.getDescription().getProvides())).append(")"); -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index 032ed2aba7d47144d241d616ba27489ce22d6fea..e98934d32b8dac88b3c3fd14ea5d726872212807 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -306,7 +306,14 @@ public final class JavaPluginLoader implements PluginLoader { - Preconditions.checkArgument(plugin instanceof JavaPlugin, "Plugin is not associated with this PluginLoader"); - - if (!plugin.isEnabled()) { -- plugin.getLogger().info("Enabling " + plugin.getDescription().getFullName()); -+ // Paper start - Add an asterisk to legacy plugins (so admins are aware) -+ String enableMsg = "Enabling " + plugin.getDescription().getFullName(); -+ if (org.bukkit.UnsafeValues.isLegacyPlugin(plugin)) { -+ enableMsg += "*"; -+ } -+ -+ plugin.getLogger().info(enableMsg); -+ // Paper end - - JavaPlugin jPlugin = (JavaPlugin) plugin; - diff --git a/patches/api/0123-Allow-disabling-armour-stand-ticking.patch b/patches/api/0123-Allow-disabling-armour-stand-ticking.patch new file mode 100644 index 000000000000..d8e4a5f002cf --- /dev/null +++ b/patches/api/0123-Allow-disabling-armour-stand-ticking.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kashike +Date: Wed, 15 Aug 2018 01:26:03 -0700 +Subject: [PATCH] Allow disabling armour stand ticking + + +diff --git a/src/main/java/org/bukkit/entity/ArmorStand.java b/src/main/java/org/bukkit/entity/ArmorStand.java +index c727b2d40efae8f08bdd159991afb8992568a58f..38538ad590f33c67cf63ed3bfb177e172f4dc43c 100644 +--- a/src/main/java/org/bukkit/entity/ArmorStand.java ++++ b/src/main/java/org/bukkit/entity/ArmorStand.java +@@ -363,5 +363,21 @@ public interface ArmorStand extends LivingEntity { + + @Override + org.bukkit.inventory.@NotNull EntityEquipment getEquipment(); ++ ++ /** ++ * Tests if this armor stand can tick. ++ * ++ *

      The default value is defined in {@code paper.yml}.

      ++ * ++ * @return {@code true} if this armour stand can tick, {@code false} otherwise ++ */ ++ boolean canTick(); ++ ++ /** ++ * Sets if this armor stand can tick. ++ * ++ * @param tick {@code true} if this armour stand can tick, {@code false} otherwise ++ */ ++ void setCanTick(final boolean tick); + // Paper end + } diff --git a/patches/api/0124-EnderDragon-Events.patch b/patches/api/0124-EnderDragon-Events.patch deleted file mode 100644 index 68ed791382ba..000000000000 --- a/patches/api/0124-EnderDragon-Events.patch +++ /dev/null @@ -1,225 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 21 Jul 2018 01:51:05 -0500 -Subject: [PATCH] EnderDragon Events - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..118c7b6772a52c250649af2a9286f483f43da385 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFireballHitEvent.java -@@ -0,0 +1,79 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.AreaEffectCloud; -+import org.bukkit.entity.DragonFireball; -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+ -+import java.util.Collection; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Fired when a DragonFireball collides with a block/entity and spawns an AreaEffectCloud -+ */ -+public class EnderDragonFireballHitEvent extends EntityEvent implements Cancellable { -+ @Nullable private final Collection targets; -+ @NotNull private final AreaEffectCloud areaEffectCloud; -+ -+ public EnderDragonFireballHitEvent(@NotNull DragonFireball fireball, @Nullable Collection targets, @NotNull AreaEffectCloud areaEffectCloud) { -+ super(fireball); -+ this.targets = targets; -+ this.areaEffectCloud = areaEffectCloud; -+ } -+ -+ /** -+ * The fireball involved in this event -+ */ -+ @NotNull -+ @Override -+ public DragonFireball getEntity() { -+ return (DragonFireball) super.getEntity(); -+ } -+ -+ /** -+ * The living entities hit by fireball -+ * -+ * May be null if no entities were hit -+ * -+ * @return the targets -+ */ -+ @Nullable -+ public Collection getTargets() { -+ return targets; -+ } -+ -+ /** -+ * @return The area effect cloud spawned in this collision -+ */ -+ @NotNull -+ public AreaEffectCloud getAreaEffectCloud() { -+ return areaEffectCloud; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1915177f4b8f8013656fbdb41240f6c5c88f95d7 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonFlameEvent.java -@@ -0,0 +1,61 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.AreaEffectCloud; -+import org.bukkit.entity.EnderDragon; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when an EnderDragon spawns an AreaEffectCloud by shooting flames -+ */ -+public class EnderDragonFlameEvent extends EntityEvent implements Cancellable { -+ @NotNull private final AreaEffectCloud areaEffectCloud; -+ -+ public EnderDragonFlameEvent(@NotNull EnderDragon enderDragon, @NotNull AreaEffectCloud areaEffectCloud) { -+ super(enderDragon); -+ this.areaEffectCloud = areaEffectCloud; -+ } -+ -+ /** -+ * The enderdragon involved in this event -+ */ -+ @NotNull -+ @Override -+ public EnderDragon getEntity() { -+ return (EnderDragon) super.getEntity(); -+ } -+ -+ /** -+ * @return The area effect cloud spawned in this collision -+ */ -+ @NotNull -+ public AreaEffectCloud getAreaEffectCloud() { -+ return areaEffectCloud; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8414bd805ec68d7b305fbf645c59f8d5b762c9ce ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EnderDragonShootFireballEvent.java -@@ -0,0 +1,61 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.DragonFireball; -+import org.bukkit.entity.EnderDragon; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when an EnderDragon shoots a fireball -+ */ -+public class EnderDragonShootFireballEvent extends EntityEvent implements Cancellable { -+ @NotNull private final DragonFireball fireball; -+ -+ public EnderDragonShootFireballEvent(@NotNull EnderDragon entity, @NotNull DragonFireball fireball) { -+ super(entity); -+ this.fireball = fireball; -+ } -+ -+ /** -+ * The enderdragon shooting the fireball -+ */ -+ @NotNull -+ @Override -+ public EnderDragon getEntity() { -+ return (EnderDragon) super.getEntity(); -+ } -+ -+ /** -+ * @return The fireball being shot -+ */ -+ @NotNull -+ public DragonFireball getFireball() { -+ return fireball; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0124-SkeletonHorse-Additions.patch b/patches/api/0124-SkeletonHorse-Additions.patch new file mode 100644 index 000000000000..c3c88038f576 --- /dev/null +++ b/patches/api/0124-SkeletonHorse-Additions.patch @@ -0,0 +1,99 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 27 Jul 2018 22:36:17 -0500 +Subject: [PATCH] SkeletonHorse Additions + + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a70f4972a012f955b45a91fe20ca5df7e2123528 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java +@@ -0,0 +1,64 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import com.google.common.collect.ImmutableList; ++import java.util.List; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.entity.SkeletonHorse; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Event called when a player gets close to a skeleton horse and triggers the lightning trap ++ */ ++@NullMarked ++public class SkeletonHorseTrapEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final List eligibleHumans; ++ private boolean cancelled; ++ ++ @Deprecated ++ @ApiStatus.Internal ++ public SkeletonHorseTrapEvent(final SkeletonHorse horse) { ++ this(horse, ImmutableList.of()); ++ } ++ ++ @ApiStatus.Internal ++ public SkeletonHorseTrapEvent(final SkeletonHorse horse, final List eligibleHumans) { ++ super(horse); ++ this.eligibleHumans = eligibleHumans; ++ } ++ ++ @Override ++ public SkeletonHorse getEntity() { ++ return (SkeletonHorse) super.getEntity(); ++ } ++ ++ public List getEligibleHumans() { ++ return this.eligibleHumans; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} ++ +diff --git a/src/main/java/org/bukkit/entity/SkeletonHorse.java b/src/main/java/org/bukkit/entity/SkeletonHorse.java +index a34ad28fc43bde224c39253e8479bf7bb7e8df1c..38539d5b77e06865aa65b8db0c1a3b6eaa914d03 100644 +--- a/src/main/java/org/bukkit/entity/SkeletonHorse.java ++++ b/src/main/java/org/bukkit/entity/SkeletonHorse.java +@@ -43,4 +43,18 @@ public interface SkeletonHorse extends AbstractHorse { + * @param trapTime new trap time + */ + void setTrapTime(int trapTime); ++ ++ // Paper start ++ /** ++ * @deprecated use {@link #isTrapped()} ++ */ ++ @Deprecated ++ boolean isTrap(); ++ ++ /** ++ * @deprecated use {@link #setTrapped(boolean)} ++ */ ++ @Deprecated ++ void setTrap(boolean trap); ++ // Paper end + } diff --git a/patches/api/0125-Expand-Location-Manipulation-API.patch b/patches/api/0125-Expand-Location-Manipulation-API.patch new file mode 100644 index 000000000000..ff5737313417 --- /dev/null +++ b/patches/api/0125-Expand-Location-Manipulation-API.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 25 Jul 2018 01:36:07 -0400 +Subject: [PATCH] Expand Location Manipulation API + +Adds set(x, y, z), add(base, x, y, z), subtract(base, x, y, z); + +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index fe2e0939df61b1f59d12adf3f760f1d619bb3de3..56fd66a3fb5f6e33812d2981cd192d317453a0f5 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -545,6 +545,59 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + + public boolean isChunkLoaded() { return this.getWorld().isChunkLoaded(locToBlock(x) >> 4, locToBlock(z) >> 4); } // Paper + ++ // Paper start - expand location manipulation API ++ ++ /** ++ * Sets the position of this Location and returns itself ++ *

      ++ * This mutates this object, clone first. ++ * ++ * @param x X coordinate ++ * @param y Y coordinate ++ * @param z Z coordinate ++ * @return self (not cloned) ++ */ ++ @NotNull ++ public Location set(double x, double y, double z) { ++ this.x = x; ++ this.y = y; ++ this.z = z; ++ return this; ++ } ++ ++ /** ++ * Takes the x/y/z from base and adds the specified x/y/z to it and returns self ++ *

      ++ * This mutates this object, clone first. ++ * ++ * @param base The base coordinate to modify ++ * @param x X coordinate to add to base ++ * @param y Y coordinate to add to base ++ * @param z Z coordinate to add to base ++ * @return self (not cloned) ++ */ ++ @NotNull ++ public Location add(@NotNull Location base, double x, double y, double z) { ++ return this.set(base.x + x, base.y + y, base.z + z); ++ } ++ ++ /** ++ * Takes the x/y/z from base and subtracts the specified x/y/z to it and returns self ++ *

      ++ * This mutates this object, clone first. ++ * ++ * @param base The base coordinate to modify ++ * @param x X coordinate to subtract from base ++ * @param y Y coordinate to subtract from base ++ * @param z Z coordinate to subtract from base ++ * @return self (not cloned) ++ */ ++ @NotNull ++ public Location subtract(@NotNull Location base, double x, double y, double z) { ++ return this.set(base.x - x, base.y - y, base.z - z); ++ } ++ // Paper end - expand location manipulation API ++ + // Paper start - expand Location API + /** + * @return A new location where X/Y/Z are on the Block location (integer value of X/Y/Z) diff --git a/patches/api/0125-PlayerElytraBoostEvent.patch b/patches/api/0125-PlayerElytraBoostEvent.patch deleted file mode 100644 index c5d8e5ddf3fc..000000000000 --- a/patches/api/0125-PlayerElytraBoostEvent.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 21 Jul 2018 01:59:53 -0500 -Subject: [PATCH] PlayerElytraBoostEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e9a76a25fa5445905a09dbc2fd5b35bff56d80b3 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerElytraBoostEvent.java -@@ -0,0 +1,85 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.entity.Firework; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a player boosts elytra flight with a firework -+ */ -+public class PlayerElytraBoostEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled = false; -+ @NotNull private final ItemStack itemStack; -+ @NotNull private Firework firework; -+ private boolean consume = true; -+ -+ public PlayerElytraBoostEvent(@NotNull Player player, @NotNull ItemStack itemStack, @NotNull Firework firework) { -+ super(player); -+ this.itemStack = itemStack; -+ this.firework = firework; -+ } -+ -+ /** -+ * Get the firework itemstack used -+ * -+ * @return ItemStack of firework -+ */ -+ @NotNull -+ public ItemStack getItemStack() { -+ return itemStack; -+ } -+ -+ /** -+ * Get the firework entity that was spawned -+ * -+ * @return Firework entity -+ */ -+ @NotNull -+ public Firework getFirework() { -+ return firework; -+ } -+ -+ /** -+ * Get whether to consume the firework or not -+ * -+ * @return True to consume -+ */ -+ public boolean shouldConsume() { -+ return consume; -+ } -+ -+ /** -+ * Set whether to consume the firework or not -+ * -+ * @param consume True to consume -+ */ -+ public void setShouldConsume(boolean consume) { -+ this.consume = consume; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} diff --git a/patches/api/0126-Expand-ArmorStand-API.patch b/patches/api/0126-Expand-ArmorStand-API.patch new file mode 100644 index 000000000000..f6088304aabc --- /dev/null +++ b/patches/api/0126-Expand-ArmorStand-API.patch @@ -0,0 +1,345 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: willies952002 +Date: Thu, 26 Jul 2018 02:22:44 -0400 +Subject: [PATCH] Expand ArmorStand API + +Adds the following: +- Add proper methods for getting and setting items in both hands. Deprecates old methods +- Enable/Disable slot interactions +- Allow using degrees for ArmorStand rotations (via new Rotations class) + +Co-authored-by: SoSeDiK + +diff --git a/src/main/java/io/papermc/paper/math/Rotations.java b/src/main/java/io/papermc/paper/math/Rotations.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2a8e1aa29ab87c69a02f72615fbf1374714f54cf +--- /dev/null ++++ b/src/main/java/io/papermc/paper/math/Rotations.java +@@ -0,0 +1,101 @@ ++package io.papermc.paper.math; ++ ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Rotations is an immutable object that stores rotations ++ * in degrees on each axis (X, Y, Z). ++ */ ++@NullMarked ++public interface Rotations { ++ ++ /** ++ * Rotations instance with every axis set to 0 ++ */ ++ Rotations ZERO = ofDegrees(0, 0, 0); ++ ++ /** ++ * Creates a new Rotations instance holding the provided rotations ++ * ++ * @param x the angle for the X axis in degrees ++ * @param y the angle for the Y axis in degrees ++ * @param z the angle for the Z axis in degrees ++ * @return Rotations instance holding the provided rotations ++ */ ++ static Rotations ofDegrees(final double x, final double y, final double z) { ++ return new RotationsImpl(x, y, z); ++ } ++ ++ /** ++ * Returns the angle on the X axis in degrees ++ * ++ * @return the angle in degrees ++ */ ++ double x(); ++ ++ /** ++ * Returns the angle on the Y axis in degrees ++ * ++ * @return the angle in degrees ++ */ ++ double y(); ++ ++ /** ++ * Returns the angle on the Z axis in degrees ++ * ++ * @return the angle in degrees ++ */ ++ double z(); ++ ++ /** ++ * Returns a new Rotations instance which is the result ++ * of changing the X axis to the passed angle ++ * ++ * @param x the angle in degrees ++ * @return the resultant Rotations ++ */ ++ Rotations withX(double x); ++ ++ /** ++ * Returns a new Rotations instance which is the result ++ * of changing the Y axis to the passed angle ++ * ++ * @param y the angle in degrees ++ * @return the resultant Rotations ++ */ ++ Rotations withY(double y); ++ ++ /** ++ * Returns a new Rotations instance which is the result ++ * of changing the Z axis to the passed angle ++ * ++ * @param z the angle in degrees ++ * @return the resultant Rotations ++ */ ++ Rotations withZ(double z); ++ ++ /** ++ * Returns a new Rotations instance which is the result of adding ++ * the x, y, z components to this Rotations ++ * ++ * @param x the angle to add to the X axis in degrees ++ * @param y the angle to add to the Y axis in degrees ++ * @param z the angle to add to the Z axis in degrees ++ * @return the resultant Rotations ++ */ ++ Rotations add(double x, double y, double z); ++ ++ /** ++ * Returns a new Rotations instance which is the result of subtracting ++ * the x, y, z components from this Rotations ++ * ++ * @param x the angle to subtract from the X axis in degrees ++ * @param y the angle to subtract from the Y axis in degrees ++ * @param z the angle to subtract from the Z axis in degrees ++ * @return the resultant Rotations ++ */ ++ default Rotations subtract(final double x, final double y, final double z) { ++ return this.add(-x, -y, -z); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/math/RotationsImpl.java b/src/main/java/io/papermc/paper/math/RotationsImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..35b493b870240f2cb142ea0c3bc2a5b2a89af25b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/math/RotationsImpl.java +@@ -0,0 +1,28 @@ ++package io.papermc.paper.math; ++ ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++record RotationsImpl(double x, double y, double z) implements Rotations { ++ ++ @Override ++ public RotationsImpl withX(final double x) { ++ return new RotationsImpl(x, this.y, this.z); ++ } ++ ++ @Override ++ public RotationsImpl withY(final double y) { ++ return new RotationsImpl(this.x, y, this.z); ++ } ++ ++ @Override ++ public RotationsImpl withZ(final double z) { ++ return new RotationsImpl(this.x, this.y, z); ++ } ++ ++ @Override ++ public RotationsImpl add(final double x, final double y, final double z) { ++ return new RotationsImpl(this.x + x, this.y + y, this.z + z); ++ } ++ ++} +diff --git a/src/main/java/org/bukkit/entity/ArmorStand.java b/src/main/java/org/bukkit/entity/ArmorStand.java +index 38538ad590f33c67cf63ed3bfb177e172f4dc43c..6303eb0836f55dd2e80f84a91568699f2f6f3b6c 100644 +--- a/src/main/java/org/bukkit/entity/ArmorStand.java ++++ b/src/main/java/org/bukkit/entity/ArmorStand.java +@@ -14,7 +14,7 @@ public interface ArmorStand extends LivingEntity { + * + * @return the held item + * @see #getEquipment() +- * @deprecated prefer {@link EntityEquipment#getItemInHand()} ++ * @deprecated prefer {@link ArmorStand#getItem(EquipmentSlot)} // Paper + */ + @NotNull + @Deprecated(since = "1.15.2") +@@ -26,7 +26,7 @@ public interface ArmorStand extends LivingEntity { + * @param item the item to hold + * @see #getEquipment() + * @deprecated prefer +- * {@link EntityEquipment#setItemInHand(org.bukkit.inventory.ItemStack)} ++ * {@link ArmorStand#setItem(EquipmentSlot, ItemStack)} // Paper + */ + @Deprecated(since = "1.15.2") + void setItemInHand(@Nullable ItemStack item); +@@ -379,5 +379,169 @@ public interface ArmorStand extends LivingEntity { + * @param tick {@code true} if this armour stand can tick, {@code false} otherwise + */ + void setCanTick(final boolean tick); ++ ++ /** ++ * Returns the item the armor stand has ++ * equip in the given equipment slot ++ * ++ * @param slot the equipment slot to get ++ * @return the ItemStack in the equipment slot ++ * @throws IllegalArgumentException if the slot is invalid for the entity ++ */ ++ @NotNull ++ ItemStack getItem(@NotNull final org.bukkit.inventory.EquipmentSlot slot); ++ ++ /** ++ * Sets the item the armor stand has ++ * equip in the given equipment slot ++ * ++ * @param slot the equipment slot to set ++ * @param item the item to hold ++ * @throws IllegalArgumentException if the slot is invalid for the entity ++ */ ++ void setItem(@NotNull final org.bukkit.inventory.EquipmentSlot slot, @Nullable final ItemStack item); ++ ++ /** ++ * Get the list of disabled slots ++ * ++ * @return list of disabled slots ++ */ ++ @NotNull ++ java.util.Set getDisabledSlots(); ++ ++ /** ++ * Set the disabled slots ++ * ++ * This makes it so a player is unable to interact with the Armor Stand to place, remove, or replace an item in the given slot(s) ++ * Note: Once a slot is disabled, the only way to get an item back it to break the armor stand. ++ * ++ * @param slots var-arg array of slots to lock ++ */ ++ void setDisabledSlots(@NotNull org.bukkit.inventory.EquipmentSlot... slots); ++ ++ /** ++ * Disable specific slots, adding them ++ * to the currently disabled slots ++ * ++ * This makes it so a player is unable to interact with the Armor Stand to place, remove, or replace an item in the given slot(s) ++ * Note: Once a slot is disabled, the only way to get an item back it to break the armor stand. ++ * ++ * @param slots var-arg array of slots to lock ++ */ ++ void addDisabledSlots(@NotNull final org.bukkit.inventory.EquipmentSlot... slots); ++ ++ /** ++ * Remove the given slots from the disabled ++ * slots list, enabling them. ++ * ++ * This makes it so a player is able to interact with the Armor Stand to place, remove, or replace an item in the given slot(s) ++ * ++ * @param slots var-arg array of slots to unlock ++ */ ++ void removeDisabledSlots(@NotNull final org.bukkit.inventory.EquipmentSlot... slots); ++ ++ /** ++ * Check if a specific slot is disabled ++ * ++ * @param slot The slot to check ++ * @return {@code true} if the slot is disabled, else {@code false}. ++ */ ++ boolean isSlotDisabled(@NotNull org.bukkit.inventory.EquipmentSlot slot); ++ ++ /** ++ * Returns the ArmorStand's body rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @return the current rotations ++ */ ++ @NotNull io.papermc.paper.math.Rotations getBodyRotations(); ++ ++ /** ++ * Sets the ArmorStand's body rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @param rotations the current rotations ++ */ ++ void setBodyRotations(@NotNull io.papermc.paper.math.Rotations rotations); ++ ++ /** ++ * Returns the ArmorStand's left arm rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @return the current rotations ++ */ ++ @NotNull io.papermc.paper.math.Rotations getLeftArmRotations(); ++ ++ /** ++ * Sets the ArmorStand's left arm rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @param rotations the current rotations ++ */ ++ void setLeftArmRotations(@NotNull io.papermc.paper.math.Rotations rotations); ++ ++ /** ++ * Returns the ArmorStand's right arm rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @return the current rotations ++ */ ++ @NotNull io.papermc.paper.math.Rotations getRightArmRotations(); ++ ++ /** ++ * Sets the ArmorStand's right arm rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @param rotations the current rotations ++ */ ++ void setRightArmRotations(@NotNull io.papermc.paper.math.Rotations rotations); ++ ++ /** ++ * Returns the ArmorStand's left leg rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @return the current rotations ++ */ ++ @NotNull io.papermc.paper.math.Rotations getLeftLegRotations(); ++ ++ /** ++ * Sets the ArmorStand's left leg rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @param rotations the current rotations ++ */ ++ void setLeftLegRotations(@NotNull io.papermc.paper.math.Rotations rotations); ++ ++ /** ++ * Returns the ArmorStand's right leg rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @return the current rotations ++ */ ++ @NotNull io.papermc.paper.math.Rotations getRightLegRotations(); ++ ++ /** ++ * Sets the ArmorStand's right leg rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @param rotations the current rotations ++ */ ++ void setRightLegRotations(@NotNull io.papermc.paper.math.Rotations rotations); ++ ++ /** ++ * Returns the ArmorStand's head rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @return the current rotations ++ */ ++ @NotNull io.papermc.paper.math.Rotations getHeadRotations(); ++ ++ /** ++ * Sets the ArmorStand's head rotations as ++ * {@link io.papermc.paper.math.Rotations}. ++ * ++ * @param rotations the current rotations ++ */ ++ void setHeadRotations(@NotNull io.papermc.paper.math.Rotations rotations); + // Paper end + } diff --git a/patches/api/0126-PlayerLaunchProjectileEvent.patch b/patches/api/0126-PlayerLaunchProjectileEvent.patch deleted file mode 100644 index 7524daea9282..000000000000 --- a/patches/api/0126-PlayerLaunchProjectileEvent.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 21 Jul 2018 03:10:50 -0500 -Subject: [PATCH] PlayerLaunchProjectileEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9074b2ede01f76c0560e5318246382163cc91591 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java -@@ -0,0 +1,83 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.entity.Projectile; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player shoots a projectile -+ */ -+public class PlayerLaunchProjectileEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull private final Projectile projectile; -+ @NotNull private final ItemStack itemStack; -+ private boolean consumeItem = true; -+ private boolean cancelled; -+ -+ public PlayerLaunchProjectileEvent(@NotNull Player shooter, @NotNull ItemStack itemStack, @NotNull Projectile projectile) { -+ super(shooter); -+ this.itemStack = itemStack; -+ this.projectile = projectile; -+ } -+ -+ /** -+ * Gets the projectile which will be launched by this event -+ * -+ * @return the launched projectile -+ */ -+ @NotNull -+ public Projectile getProjectile() { -+ return projectile; -+ } -+ -+ /** -+ * Get the ItemStack used to fire the projectile -+ * -+ * @return The ItemStack used -+ */ -+ @NotNull -+ public ItemStack getItemStack() { -+ return itemStack; -+ } -+ -+ /** -+ * Get whether to consume the ItemStack or not -+ * -+ * @return True to consume -+ */ -+ public boolean shouldConsume() { -+ return consumeItem; -+ } -+ -+ /** -+ * Set whether to consume the ItemStack or not -+ * -+ * @param consumeItem True to consume -+ */ -+ public void setShouldConsume(boolean consumeItem) { -+ this.consumeItem = consumeItem; -+ } -+ -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0127-AnvilDamageEvent.patch b/patches/api/0127-AnvilDamageEvent.patch new file mode 100644 index 000000000000..2d984e06e66c --- /dev/null +++ b/patches/api/0127-AnvilDamageEvent.patch @@ -0,0 +1,161 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 20 Jul 2018 23:36:55 -0500 +Subject: [PATCH] AnvilDamageEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java b/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1472ecef11627d82f72911d86d579ad3bb365dca +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java +@@ -0,0 +1,149 @@ ++package com.destroystokyo.paper.event.block; ++ ++import org.bukkit.Material; ++import org.bukkit.block.data.BlockData; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.inventory.InventoryEvent; ++import org.bukkit.inventory.AnvilInventory; ++import org.bukkit.inventory.InventoryView; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when an anvil is damaged from being used ++ */ ++@NullMarked ++public class AnvilDamagedEvent extends InventoryEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private DamageState damageState; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public AnvilDamagedEvent(final InventoryView inventory, final @Nullable BlockData blockData) { ++ super(inventory); ++ this.damageState = DamageState.getState(blockData); ++ } ++ ++ @Override ++ public AnvilInventory getInventory() { ++ return (AnvilInventory) super.getInventory(); ++ } ++ ++ /** ++ * Gets the new state of damage on the anvil ++ * ++ * @return Damage state ++ */ ++ public DamageState getDamageState() { ++ return this.damageState; ++ } ++ ++ /** ++ * Sets the new state of damage on the anvil ++ * ++ * @param damageState Damage state ++ */ ++ public void setDamageState(final DamageState damageState) { ++ this.damageState = damageState; ++ } ++ ++ /** ++ * Gets if anvil is breaking on this use ++ * ++ * @return {@code true} if breaking ++ */ ++ public boolean isBreaking() { ++ return this.damageState == DamageState.BROKEN; ++ } ++ ++ /** ++ * Sets if anvil is breaking on this use ++ * ++ * @param breaking {@code true} if breaking ++ */ ++ public void setBreaking(final boolean breaking) { ++ if (breaking) { ++ this.damageState = DamageState.BROKEN; ++ } else if (this.damageState == DamageState.BROKEN) { ++ this.damageState = DamageState.DAMAGED; ++ } ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ /** ++ * Represents the amount of damage on an anvil block ++ */ ++ public enum DamageState { ++ FULL(Material.ANVIL), ++ CHIPPED(Material.CHIPPED_ANVIL), ++ DAMAGED(Material.DAMAGED_ANVIL), ++ BROKEN(Material.AIR); ++ ++ private final Material material; ++ ++ DamageState(final Material material) { ++ this.material = material; ++ } ++ ++ /** ++ * Get block material of this state ++ * ++ * @return Material ++ */ ++ public Material getMaterial() { ++ return this.material; ++ } ++ ++ /** ++ * Get damaged state by block data ++ * ++ * @param blockData Block data ++ * @return DamageState ++ * @throws IllegalArgumentException If non anvil block data is given ++ */ ++ public static DamageState getState(final @Nullable BlockData blockData) { ++ return blockData == null ? BROKEN : getState(blockData.getMaterial()); ++ } ++ ++ /** ++ * Get damaged state by block material ++ * ++ * @param material Block material ++ * @return DamageState ++ * @throws IllegalArgumentException If non anvil material is given ++ */ ++ public static DamageState getState(final @Nullable Material material) { ++ if (material == null) { ++ return BROKEN; ++ } ++ for (final DamageState state : values()) { ++ if (state.getMaterial() == material) { ++ return state; ++ } ++ } ++ throw new IllegalArgumentException("Material is not an anvil state"); ++ } ++ } ++} diff --git a/patches/api/0127-EntityTransformedEvent.patch b/patches/api/0127-EntityTransformedEvent.patch deleted file mode 100644 index c77c4a8ba626..000000000000 --- a/patches/api/0127-EntityTransformedEvent.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Anthony MacAllister -Date: Thu, 26 Jul 2018 15:28:53 -0400 -Subject: [PATCH] EntityTransformedEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityTransformedEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityTransformedEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..12194f1fc7f03ca6785904b6187b3dfd03b16461 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityTransformedEvent.java -@@ -0,0 +1,92 @@ -+package com.destroystokyo.paper.event.entity; -+ -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.event.entity.EntityTransformEvent; -+ -+/** -+ * Fired when an entity transforms into another entity -+ *

      -+ * If the event is cancelled, the entity will not transform -+ * @deprecated Bukkit has added {@link EntityTransformEvent}, you should start using that -+ */ -+@Deprecated -+public class EntityTransformedEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private final Entity transformed; -+ private final TransformedReason reason; -+ -+ public EntityTransformedEvent(Entity entity, Entity transformed, TransformedReason reason) { -+ super(entity); -+ this.transformed = transformed; -+ this.reason = reason; -+ } -+ -+ /** -+ * The entity after it has transformed -+ * -+ * @return Transformed entity -+ * @deprecated see {@link EntityTransformEvent#getTransformedEntity()} -+ */ -+ @Deprecated -+ public Entity getTransformed() { -+ return transformed; -+ } -+ -+ /** -+ * @return The reason for the transformation -+ * @deprecated see {@link EntityTransformEvent#getTransformReason()} -+ */ -+ @Deprecated -+ public TransformedReason getReason() { -+ return reason; -+ } -+ -+ -+ @Override -+ public HandlerList getHandlers(){ -+ return handlers; -+ } -+ -+ public static HandlerList getHandlerList(){ -+ return handlers; -+ } -+ -+ @Override -+ public boolean isCancelled(){ -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel){ -+ cancelled = cancel; -+ } -+ -+ public enum TransformedReason { -+ /** -+ * When a zombie drowns -+ */ -+ DROWNED, -+ /** -+ * When a zombie villager is cured -+ */ -+ CURED, -+ /** -+ * When a villager turns to a zombie villager -+ */ -+ INFECTED, -+ /** -+ * When a mooshroom turns to a cow -+ */ -+ SHEARED, -+ /** -+ * When a pig turns to a zombiepigman -+ */ -+ LIGHTNING -+ -+ } -+} diff --git a/patches/api/0128-Add-TNTPrimeEvent.patch b/patches/api/0128-Add-TNTPrimeEvent.patch new file mode 100644 index 000000000000..20d4d46dccc1 --- /dev/null +++ b/patches/api/0128-Add-TNTPrimeEvent.patch @@ -0,0 +1,137 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Vainomaa +Date: Sun, 15 Jul 2018 22:17:55 +0300 +Subject: [PATCH] Add TNTPrimeEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java b/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b17bdd323c25e956a3e851fc44aefa8b1b1d2965 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java +@@ -0,0 +1,125 @@ ++package com.destroystokyo.paper.event.block; ++ ++import org.bukkit.Material; ++import org.bukkit.block.Block; ++import org.bukkit.enchantments.Enchantment; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.entity.TNTPrimed; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Called when TNT block is about to turn into {@link TNTPrimed} ++ *

      ++ * Cancelling it won't turn TNT into {@link TNTPrimed} and leaves ++ * the TNT block as-is ++ * ++ * @author Mark Vainomaa ++ * @deprecated use {@link org.bukkit.event.block.TNTPrimeEvent} ++ */ ++@Deprecated(forRemoval = true, since = "1.19.4") ++public class TNTPrimeEvent extends BlockEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ @NotNull private final PrimeReason reason; ++ @Nullable private final Entity primerEntity; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public TNTPrimeEvent(@NotNull Block theBlock, @NotNull PrimeReason reason, @Nullable Entity primerEntity) { ++ super(theBlock); ++ this.reason = reason; ++ this.primerEntity = primerEntity; ++ } ++ ++ /** ++ * Gets the TNT prime reason ++ * ++ * @return Prime reason ++ */ ++ @NotNull ++ public PrimeReason getReason() { ++ return this.reason; ++ } ++ ++ /** ++ * Gets the TNT primer {@link Entity}. ++ *

      ++ * It's {@code null} if {@link #getReason()} is {@link PrimeReason#REDSTONE} or {@link PrimeReason#FIRE}. ++ * It's not {@code null} if {@link #getReason()} is {@link PrimeReason#ITEM} or {@link PrimeReason#PROJECTILE} ++ * It might be {@code null} if {@link #getReason()} is {@link PrimeReason#EXPLOSION} ++ * ++ * @return The {@link Entity} who primed the TNT ++ */ ++ @Nullable ++ public Entity getPrimerEntity() { ++ return this.primerEntity; ++ } ++ ++ /** ++ * Gets whether spawning {@link TNTPrimed} should be cancelled or not ++ * ++ * @return Whether spawning {@link TNTPrimed} should be cancelled or not ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * Sets whether to cancel spawning {@link TNTPrimed} or not ++ * ++ * @param cancel whether spawning {@link TNTPrimed} should be cancelled or not ++ */ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum PrimeReason { ++ /** ++ * When TNT prime was caused by other explosion (chain reaction) ++ */ ++ EXPLOSION, ++ ++ /** ++ * When TNT prime was caused by fire ++ */ ++ FIRE, ++ ++ /** ++ * When {@link Player} used {@link Material#FLINT_AND_STEEL} or ++ * {@link Material#FIRE_CHARGE} on given TNT block ++ */ ++ ITEM, ++ ++ /** ++ * When TNT prime was caused by an {@link Entity} shooting TNT ++ * using a bow with {@link Enchantment#FLAME} enchantment ++ */ ++ PROJECTILE, ++ ++ /** ++ * When redstone power triggered the TNT prime ++ */ ++ REDSTONE ++ } ++} diff --git a/patches/api/0128-Allow-disabling-armour-stand-ticking.patch b/patches/api/0128-Allow-disabling-armour-stand-ticking.patch deleted file mode 100644 index 1bb68e268b17..000000000000 --- a/patches/api/0128-Allow-disabling-armour-stand-ticking.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: kashike -Date: Wed, 15 Aug 2018 01:26:03 -0700 -Subject: [PATCH] Allow disabling armour stand ticking - - -diff --git a/src/main/java/org/bukkit/entity/ArmorStand.java b/src/main/java/org/bukkit/entity/ArmorStand.java -index 7dc631ebd009f5f5c3ac1699c3f3515c47609c05..2ee3814a52945f541e049b621b9552f8ae9e261d 100644 ---- a/src/main/java/org/bukkit/entity/ArmorStand.java -+++ b/src/main/java/org/bukkit/entity/ArmorStand.java -@@ -363,5 +363,21 @@ public interface ArmorStand extends LivingEntity { - - @Override - org.bukkit.inventory.@NotNull EntityEquipment getEquipment(); -+ -+ /** -+ * Tests if this armor stand can tick. -+ * -+ *

      The default value is defined in {@code paper.yml}.

      -+ * -+ * @return {@code true} if this armour stand can tick, {@code false} otherwise -+ */ -+ boolean canTick(); -+ -+ /** -+ * Sets if this armor stand can tick. -+ * -+ * @param tick {@code true} if this armour stand can tick, {@code false} otherwise -+ */ -+ void setCanTick(final boolean tick); - // Paper end - } diff --git a/patches/api/0129-Provide-Chunk-Coordinates-as-a-Long-API.patch b/patches/api/0129-Provide-Chunk-Coordinates-as-a-Long-API.patch new file mode 100644 index 000000000000..1743caa3473d --- /dev/null +++ b/patches/api/0129-Provide-Chunk-Coordinates-as-a-Long-API.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 4 Aug 2018 19:37:35 -0400 +Subject: [PATCH] Provide Chunk Coordinates as a Long API + +Allows you to easily access the chunks X/z as a long, and a method +to look up by the long key too. + +diff --git a/src/main/java/org/bukkit/Chunk.java b/src/main/java/org/bukkit/Chunk.java +index 20ed1c40437cbf8449dd4d7876086ccb6407b470..8764441ec1bae67a029b13c4c98246574ba32ef5 100644 +--- a/src/main/java/org/bukkit/Chunk.java ++++ b/src/main/java/org/bukkit/Chunk.java +@@ -36,6 +36,32 @@ public interface Chunk extends PersistentDataHolder { + */ + int getZ(); + ++ // Paper start ++ /** ++ * @return The Chunks X and Z coordinates packed into a long ++ */ ++ default long getChunkKey() { ++ return getChunkKey(getX(), getZ()); ++ } ++ ++ /** ++ * @param loc Location to get chunk key ++ * @return Location's chunk coordinates packed into a long ++ */ ++ static long getChunkKey(@NotNull Location loc) { ++ return getChunkKey((int) Math.floor(loc.getX()) >> 4, (int) Math.floor(loc.getZ()) >> 4); ++ } ++ ++ /** ++ * @param x X Coordinate ++ * @param z Z Coordinate ++ * @return Chunk coordinates packed into a long ++ */ ++ static long getChunkKey(int x, int z) { ++ return (long) x & 0xffffffffL | ((long) z & 0xffffffffL) << 32; ++ } ++ // Paper end ++ + /** + * Gets the world containing this chunk + * +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 002bfadfd4efa3d376a0a7bc5c752e8a02494eec..3dc2e420d8a6cf02fc4215d4d8056c44e829157f 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -182,6 +182,37 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @NotNull + public Chunk getChunkAt(@NotNull Block block); + ++ // Paper start - chunk long key API ++ /** ++ * Gets the chunk at the specified chunk key, which is the X and Z packed into a long. ++ *

      ++ * See {@link Chunk#getChunkKey()} for easy access to the key, or you may calculate it as: ++ * long chunkKey = (long) chunkX & 0xffffffffL | ((long) chunkZ & 0xffffffffL) >> 32; ++ * ++ * @param chunkKey The Chunk Key to look up the chunk by ++ * @return The chunk at the specified key ++ */ ++ @NotNull ++ default Chunk getChunkAt(long chunkKey) { ++ return getChunkAt(chunkKey, true); ++ } ++ ++ /** ++ * Gets the chunk at the specified chunk key, which is the X and Z packed into a long. ++ *

      ++ * See {@link Chunk#getChunkKey()} for easy access to the key, or you may calculate it as: ++ * long chunkKey = (long) chunkX & 0xffffffffL | ((long) chunkZ & 0xffffffffL) >> 32; ++ * ++ * @param chunkKey The Chunk Key to look up the chunk by ++ * @param generate Whether the chunk should be fully generated or not ++ * @return The chunk at the specified key ++ */ ++ @NotNull ++ default Chunk getChunkAt(long chunkKey, boolean generate) { ++ return getChunkAt((int) chunkKey, (int) (chunkKey >> 32), generate); ++ } ++ // Paper end - chunk long key API ++ + /** + * Checks if the specified {@link Chunk} is loaded + * diff --git a/patches/api/0129-SkeletonHorse-Additions.patch b/patches/api/0129-SkeletonHorse-Additions.patch deleted file mode 100644 index d50767241a4a..000000000000 --- a/patches/api/0129-SkeletonHorse-Additions.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 27 Jul 2018 22:36:17 -0500 -Subject: [PATCH] SkeletonHorse Additions - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9ce2948dfaa56d0adf53fe9b6117a90d7773b771 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/SkeletonHorseTrapEvent.java -@@ -0,0 +1,62 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import com.google.common.collect.ImmutableList; -+import org.bukkit.entity.HumanEntity; -+import org.bukkit.entity.SkeletonHorse; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.List; -+ -+/** -+ * Event called when a player gets close to a skeleton horse and triggers the lightning trap -+ */ -+public class SkeletonHorseTrapEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private final List eligibleHumans; -+ -+ public SkeletonHorseTrapEvent(@NotNull SkeletonHorse horse) { -+ this(horse, ImmutableList.of()); -+ } -+ -+ public SkeletonHorseTrapEvent(@NotNull SkeletonHorse horse, @NotNull List eligibleHumans) { -+ super(horse); -+ this.eligibleHumans = eligibleHumans; -+ } -+ -+ @NotNull -+ @Override -+ public SkeletonHorse getEntity() { -+ return (SkeletonHorse) super.getEntity(); -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ public List getEligibleHumans() { -+ return eligibleHumans; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -+ -diff --git a/src/main/java/org/bukkit/entity/SkeletonHorse.java b/src/main/java/org/bukkit/entity/SkeletonHorse.java -index a34ad28fc43bde224c39253e8479bf7bb7e8df1c..38539d5b77e06865aa65b8db0c1a3b6eaa914d03 100644 ---- a/src/main/java/org/bukkit/entity/SkeletonHorse.java -+++ b/src/main/java/org/bukkit/entity/SkeletonHorse.java -@@ -43,4 +43,18 @@ public interface SkeletonHorse extends AbstractHorse { - * @param trapTime new trap time - */ - void setTrapTime(int trapTime); -+ -+ // Paper start -+ /** -+ * @deprecated use {@link #isTrapped()} -+ */ -+ @Deprecated -+ boolean isTrap(); -+ -+ /** -+ * @deprecated use {@link #setTrapped(boolean)} -+ */ -+ @Deprecated -+ void setTrap(boolean trap); -+ // Paper end - } diff --git a/patches/api/0130-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch b/patches/api/0130-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch new file mode 100644 index 000000000000..d229aad879bf --- /dev/null +++ b/patches/api/0130-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 15 Aug 2018 01:04:58 -0400 +Subject: [PATCH] Ability to get Tile Entities from a chunk without snapshots + + +diff --git a/src/main/java/org/bukkit/Chunk.java b/src/main/java/org/bukkit/Chunk.java +index 8764441ec1bae67a029b13c4c98246574ba32ef5..c2eb2edd87b4087bfcdffd98f0f8904fbfd4e657 100644 +--- a/src/main/java/org/bukkit/Chunk.java ++++ b/src/main/java/org/bukkit/Chunk.java +@@ -125,7 +125,30 @@ public interface Chunk extends PersistentDataHolder { + * @return The tile entities. + */ + @NotNull +- BlockState[] getTileEntities(); ++ // Paper start ++ default BlockState[] getTileEntities() { ++ return getTileEntities(true); ++ } ++ ++ /** ++ * Get a list of all tile entities in the chunk. ++ * ++ * @param useSnapshot Take snapshots or direct references ++ * @return The tile entities. ++ */ ++ @NotNull ++ BlockState[] getTileEntities(boolean useSnapshot); ++ ++ /** ++ * Get a list of all tile entities that match a given predicate in the chunk. ++ * ++ * @param blockPredicate The predicate of blocks to return tile entities for ++ * @param useSnapshot Take snapshots or direct references ++ * @return The tile entities. ++ */ ++ @NotNull ++ Collection getTileEntities(java.util.function.@NotNull Predicate blockPredicate, boolean useSnapshot); ++ // Paper end + + /** + * Checks if the chunk is fully generated. diff --git a/patches/api/0130-Expand-Location-Manipulation-API.patch b/patches/api/0130-Expand-Location-Manipulation-API.patch deleted file mode 100644 index 2251a2d78ddb..000000000000 --- a/patches/api/0130-Expand-Location-Manipulation-API.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 25 Jul 2018 01:36:07 -0400 -Subject: [PATCH] Expand Location Manipulation API - -Adds set(x, y, z), add(base, x, y, z), subtract(base, x, y, z); - -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index a8d4f7972d07ddde171b4a1ec470a4c616e02b2e..36ed248f0716f2cc465c08ab851b7d83d4c7c0a7 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -546,6 +546,54 @@ public class Location implements Cloneable, ConfigurationSerializable { - public boolean isChunkLoaded() { return this.getWorld().isChunkLoaded(locToBlock(x) >> 4, locToBlock(z) >> 4); } // Paper - - // Paper start -+ -+ /** -+ * Sets the position of this Location and returns itself -+ * -+ * This mutates this object, clone first. -+ * @param x X coordinate -+ * @param y Y coordinate -+ * @param z Z coordinate -+ * @return self (not cloned) -+ */ -+ @NotNull -+ public Location set(double x, double y, double z) { -+ this.x = x; -+ this.y = y; -+ this.z = z; -+ return this; -+ } -+ -+ /** -+ * Takes the x/y/z from base and adds the specified x/y/z to it and returns self -+ * -+ * This mutates this object, clone first. -+ * @param base The base coordinate to modify -+ * @param x X coordinate to add to base -+ * @param y Y coordinate to add to base -+ * @param z Z coordinate to add to base -+ * @return self (not cloned) -+ */ -+ @NotNull -+ public Location add(@NotNull Location base, double x, double y, double z) { -+ return this.set(base.x + x, base.y + y, base.z + z); -+ } -+ -+ /** -+ * Takes the x/y/z from base and subtracts the specified x/y/z to it and returns self -+ * -+ * This mutates this object, clone first. -+ * @param base The base coordinate to modify -+ * @param x X coordinate to subtract from base -+ * @param y Y coordinate to subtract from base -+ * @param z Z coordinate to subtract from base -+ * @return self (not cloned) -+ */ -+ @NotNull -+ public Location subtract(@NotNull Location base, double x, double y, double z) { -+ return this.set(base.x - x, base.y - y, base.z - z); -+ } -+ - /** - * @return A new location where X/Y/Z are on the Block location (integer value of X/Y/Z) - */ diff --git a/patches/api/0131-Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch b/patches/api/0131-Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch new file mode 100644 index 000000000000..90a70c0e5c9a --- /dev/null +++ b/patches/api/0131-Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 15 Aug 2018 01:19:37 -0400 +Subject: [PATCH] Don't use snapshots for Timings Tile Entity reports + + +diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java +index 3d4390f263e52aafa24b306b1fd20d088a4ffcd7..6f6eb1a2e6c8d49014a7ae44540ee282bae5200e 100644 +--- a/src/main/java/co/aikar/timings/TimingHistory.java ++++ b/src/main/java/co/aikar/timings/TimingHistory.java +@@ -125,7 +125,7 @@ public class TimingHistory { + data.entityCounts.get(entity.getType()).increment(); + } + +- for (BlockState tileEntity : chunk.getTileEntities()) { ++ for (BlockState tileEntity : chunk.getTileEntities(false)) { + if (tileEntity == null) { + Bukkit.getLogger().warning("Null tileentity detected in chunk at position x: " + chunk.getX() + ", z: " + chunk.getZ()); + continue; diff --git a/patches/api/0131-Expand-ArmorStand-API.patch b/patches/api/0131-Expand-ArmorStand-API.patch deleted file mode 100644 index a05dd67b88e5..000000000000 --- a/patches/api/0131-Expand-ArmorStand-API.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: willies952002 -Date: Thu, 26 Jul 2018 02:22:44 -0400 -Subject: [PATCH] Expand ArmorStand API - -Add the following: -- Add proper methods for getting and setting items in both hands. Deprecates old methods -- Enable/Disable slot interactions - -diff --git a/src/main/java/org/bukkit/entity/ArmorStand.java b/src/main/java/org/bukkit/entity/ArmorStand.java -index 2ee3814a52945f541e049b621b9552f8ae9e261d..707639096657f995cc812c7b50108eeed48e8181 100644 ---- a/src/main/java/org/bukkit/entity/ArmorStand.java -+++ b/src/main/java/org/bukkit/entity/ArmorStand.java -@@ -14,7 +14,7 @@ public interface ArmorStand extends LivingEntity { - * - * @return the held item - * @see #getEquipment() -- * @deprecated prefer {@link EntityEquipment#getItemInHand()} -+ * @deprecated prefer {@link ArmorStand#getItem(EquipmentSlot)} // Paper - */ - @NotNull - @Deprecated -@@ -26,7 +26,7 @@ public interface ArmorStand extends LivingEntity { - * @param item the item to hold - * @see #getEquipment() - * @deprecated prefer -- * {@link EntityEquipment#setItemInHand(org.bukkit.inventory.ItemStack)} -+ * {@link ArmorStand#setItem(EquipmentSlot, ItemStack)} // Paper - */ - @Deprecated - void setItemInHand(@Nullable ItemStack item); -@@ -379,5 +379,71 @@ public interface ArmorStand extends LivingEntity { - * @param tick {@code true} if this armour stand can tick, {@code false} otherwise - */ - void setCanTick(final boolean tick); -+ -+ /** -+ * Returns the item the armor stand has -+ * equip in the given equipment slot -+ * -+ * @param slot the equipment slot to get -+ * @return the ItemStack in the equipment slot -+ */ -+ @NotNull -+ ItemStack getItem(@NotNull final org.bukkit.inventory.EquipmentSlot slot); -+ -+ /** -+ * Sets the item the armor stand has -+ * equip in the given equipment slot -+ * -+ * @param slot the equipment slot to set -+ * @param item the item to hold -+ */ -+ void setItem(@NotNull final org.bukkit.inventory.EquipmentSlot slot, @Nullable final ItemStack item); -+ -+ /** -+ * Get the list of disabled slots -+ * -+ * @return list of disabled slots -+ */ -+ @NotNull -+ java.util.Set getDisabledSlots(); -+ -+ /** -+ * Set the disabled slots -+ * -+ * This makes it so a player is unable to interact with the Armor Stand to place, remove, or replace an item in the given slot(s) -+ * Note: Once a slot is disabled, the only way to get an item back it to break the armor stand. -+ * -+ * @param slots var-arg array of slots to lock -+ */ -+ void setDisabledSlots(@NotNull org.bukkit.inventory.EquipmentSlot... slots); -+ -+ /** -+ * Disable specific slots, adding them -+ * to the currently disabled slots -+ * -+ * This makes it so a player is unable to interact with the Armor Stand to place, remove, or replace an item in the given slot(s) -+ * Note: Once a slot is disabled, the only way to get an item back it to break the armor stand. -+ * -+ * @param slots var-arg array of slots to lock -+ */ -+ void addDisabledSlots(@NotNull final org.bukkit.inventory.EquipmentSlot... slots); -+ -+ /** -+ * Remove the given slots from the disabled -+ * slots list, enabling them. -+ * -+ * This makes it so a player is able to interact with the Armor Stand to place, remove, or replace an item in the given slot(s) -+ * -+ * @param slots var-arg array of slots to unlock -+ */ -+ void removeDisabledSlots(@NotNull final org.bukkit.inventory.EquipmentSlot... slots); -+ -+ /** -+ * Check if a specific slot is disabled -+ * -+ * @param slot The slot to check -+ * @return {@code true} if the slot is disabled, else {@code false}. -+ */ -+ boolean isSlotDisabled(@NotNull org.bukkit.inventory.EquipmentSlot slot); - // Paper end - } diff --git a/patches/api/0132-Allow-Blocks-to-be-accessed-via-a-long-key.patch b/patches/api/0132-Allow-Blocks-to-be-accessed-via-a-long-key.patch new file mode 100644 index 000000000000..66c02b2da072 --- /dev/null +++ b/patches/api/0132-Allow-Blocks-to-be-accessed-via-a-long-key.patch @@ -0,0 +1,184 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Tue, 14 Aug 2018 21:42:10 -0700 +Subject: [PATCH] Allow Blocks to be accessed via a long key + +The key can be retrieved via methods Location#toBlockKey() and +Block#getBlockKey() + +World provides lookup for blocks by long key via method World#getBlockAtKey(long) + +The formatting for the key is as follows: + +10 bit y|27 bit z|27 bit x + +The y value is considered unsigned while z and x are considered two's complement + +Y range: [0, 1023] +X, Z range: [-67 108 864, 67 108 863] + +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index 56fd66a3fb5f6e33812d2981cd192d317453a0f5..12e1733d06471d0c2253ae846ee93a09140843cc 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -15,7 +15,6 @@ import org.jetbrains.annotations.Nullable; + + // Paper start + import java.util.Collection; +-import java.util.Collections; + import java.util.function.Predicate; + import org.bukkit.entity.Entity; + import org.bukkit.entity.LivingEntity; +@@ -610,6 +609,19 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + blockLoc.setZ(getBlockZ()); + return blockLoc; + } ++ ++ // Paper start ++ /** ++ * @return The block key for this location's block location. ++ * @see Block#getBlockKey(int, int, int) ++ * @deprecated only encodes y block ranges from -512 to 511 and represents an already changed implementation detail ++ */ ++ @Deprecated(since = "1.18.1") ++ public long toBlockKey() { ++ return Block.getBlockKey(getBlockX(), getBlockY(), getBlockZ()); ++ } ++ // Paper end ++ + /** + * @return A new location where X/Y/Z are the center of the block + */ +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 3dc2e420d8a6cf02fc4215d4d8056c44e829157f..eaa51337616746a7ee1407c1fdcb7246f9483a8b 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -99,6 +99,41 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @NotNull + public Block getBlockAt(@NotNull Location location); + ++ // Paper start ++ /** ++ * Gets the {@link Block} at the given block key ++ * ++ * @param key The block key. See {@link Block#getBlockKey()} ++ * @return Block at the key ++ * @see Block#getBlockKey(int, int, int) ++ * @deprecated only encodes y block ranges from -512 to 511 and represents an already changed implementation detail ++ */ ++ @NotNull ++ @Deprecated(since = "1.18.1") ++ public default Block getBlockAtKey(long key) { ++ int x = Block.getBlockKeyX(key); ++ int y = Block.getBlockKeyY(key); ++ int z = Block.getBlockKeyZ(key); ++ return getBlockAt(x, y, z); ++ } ++ ++ /** ++ * Gets the {@link Location} at the given block key ++ * ++ * @param key The block key. See {@link Location#toBlockKey()} ++ * @return Location at the key ++ * @see Block#getBlockKey(int, int, int) ++ */ ++ @NotNull ++ @Deprecated(since = "1.18.1") ++ public default Location getLocationAtKey(long key) { ++ int x = Block.getBlockKeyX(key); ++ int y = Block.getBlockKeyY(key); ++ int z = Block.getBlockKeyZ(key); ++ return new Location(this, x, y, z); ++ } ++ // Paper end ++ + /** + * Gets the highest non-empty (impassable) block at the given coordinates. + * +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index 69d97a14715040263afec77d0ba623c2ac84062a..a5b03162e5c0484db57d0ce0e57e945840fe1357 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -156,6 +156,82 @@ public interface Block extends Metadatable, Translatable { + */ + int getZ(); + ++ // Paper start ++ /** ++ * Returns this block's coordinates packed into a long value. ++ * Computed via: {@code Block.getBlockKey(this.getX(), this.getY(), this.getZ())} ++ * @see Block#getBlockKey(int, int, int) ++ * @return This block's x, y, and z coordinates packed into a long value ++ * @deprecated see {@link #getBlockKey(int, int, int)} ++ */ ++ @Deprecated(since = "1.18.1") ++ public default long getBlockKey() { ++ return Block.getBlockKey(this.getX(), this.getY(), this.getZ()); ++ } ++ ++ /** ++ * Returns the specified block coordinates packed into a long value ++ *

      ++ * The return value can be computed as follows: ++ *
      ++ * {@code long value = ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54);} ++ *

      ++ * ++ *

      ++ * And may be unpacked as follows: ++ *
      ++ * {@code int x = (int) ((packed << 37) >> 37);} ++ *
      ++ * {@code int y = (int) (packed >> 54);} ++ *
      ++ * {@code int z = (int) ((packed << 10) >> 37);} ++ *

      ++ * ++ * @return This block's x, y, and z coordinates packed into a long value ++ * @deprecated only encodes y block ranges from -512 to 511 and represents an already changed implementation detail ++ */ ++ @Deprecated(since = "1.18.1") ++ public static long getBlockKey(int x, int y, int z) { ++ return ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54); ++ } ++ ++ /** ++ * Returns the x component from the packed value. ++ * @param packed The packed value, as computed by {@link Block#getBlockKey(int, int, int)} ++ * @see Block#getBlockKey(int, int, int) ++ * @return The x component from the packed value. ++ * @deprecated see {@link #getBlockKey(int, int, int)} ++ */ ++ @Deprecated(since = "1.18.1") ++ public static int getBlockKeyX(long packed) { ++ return (int) ((packed << 37) >> 37); ++ } ++ ++ /** ++ * Returns the y component from the packed value. ++ * @param packed The packed value, as computed by {@link Block#getBlockKey(int, int, int)} ++ * @see Block#getBlockKey(int, int, int) ++ * @return The y component from the packed value. ++ * @deprecated see {@link #getBlockKey(int, int, int)} ++ */ ++ @Deprecated(since = "1.18.1") ++ public static int getBlockKeyY(long packed) { ++ return (int) (packed >> 54); ++ } ++ ++ /** ++ * Returns the z component from the packed value. ++ * @param packed The packed value, as computed by {@link Block#getBlockKey(int, int, int)} ++ * @see Block#getBlockKey(int, int, int) ++ * @return The z component from the packed value. ++ * @deprecated see {@link #getBlockKey(int, int, int)} ++ */ ++ @Deprecated(since = "1.18.1") ++ public static int getBlockKeyZ(long packed) { ++ return (int) ((packed << 10) >> 37); ++ } ++ // Paper end ++ + /** + * Gets the Location of the block + * diff --git a/patches/api/0132-AnvilDamageEvent.patch b/patches/api/0132-AnvilDamageEvent.patch deleted file mode 100644 index 7561b6a9dbd9..000000000000 --- a/patches/api/0132-AnvilDamageEvent.patch +++ /dev/null @@ -1,160 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 20 Jul 2018 23:36:55 -0500 -Subject: [PATCH] AnvilDamageEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java b/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a83c286c1c11af25fc4d16af7a42b95ce90b9dee ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/block/AnvilDamagedEvent.java -@@ -0,0 +1,148 @@ -+package com.destroystokyo.paper.event.block; -+ -+import org.bukkit.Material; -+import org.bukkit.block.data.BlockData; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.inventory.InventoryEvent; -+import org.bukkit.inventory.AnvilInventory; -+import org.bukkit.inventory.InventoryView; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when an anvil is damaged from being used -+ */ -+public class AnvilDamagedEvent extends InventoryEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancel; -+ private DamageState damageState; -+ -+ public AnvilDamagedEvent(@NotNull InventoryView inventory, @NotNull BlockData blockData) { -+ super(inventory); -+ this.damageState = DamageState.getState(blockData); -+ } -+ -+ @NotNull -+ @Override -+ public AnvilInventory getInventory() { -+ return (AnvilInventory) super.getInventory(); -+ } -+ -+ /** -+ * Gets the new state of damage on the anvil -+ * -+ * @return Damage state -+ */ -+ @NotNull -+ public DamageState getDamageState() { -+ return damageState; -+ } -+ -+ /** -+ * Sets the new state of damage on the anvil -+ * -+ * @param damageState Damage state -+ */ -+ public void setDamageState(@NotNull DamageState damageState) { -+ this.damageState = damageState; -+ } -+ -+ /** -+ * Gets if anvil is breaking on this use -+ * -+ * @return True if breaking -+ */ -+ public boolean isBreaking() { -+ return damageState == DamageState.BROKEN; -+ } -+ -+ /** -+ * Sets if anvil is breaking on this use -+ * -+ * @param breaking True if breaking -+ */ -+ public void setBreaking(boolean breaking) { -+ if (breaking) { -+ damageState = DamageState.BROKEN; -+ } else if (damageState == DamageState.BROKEN) { -+ damageState = DamageState.DAMAGED; -+ } -+ } -+ -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ /** -+ * Represents the amount of damage on an anvil block -+ */ -+ public enum DamageState { -+ FULL(Material.ANVIL), -+ CHIPPED(Material.CHIPPED_ANVIL), -+ DAMAGED(Material.DAMAGED_ANVIL), -+ BROKEN(Material.AIR); -+ -+ private Material material; -+ -+ DamageState(@NotNull Material material) { -+ this.material = material; -+ } -+ -+ /** -+ * Get block material of this state -+ * -+ * @return Material -+ */ -+ @NotNull -+ public Material getMaterial() { -+ return material; -+ } -+ -+ /** -+ * Get damaged state by block data -+ * -+ * @param blockData Block data -+ * @return DamageState -+ * @throws IllegalArgumentException If non anvil block data is given -+ */ -+ @NotNull -+ public static DamageState getState(@Nullable BlockData blockData) { -+ return blockData == null ? BROKEN : getState(blockData.getMaterial()); -+ } -+ -+ /** -+ * Get damaged state by block material -+ * -+ * @param material Block material -+ * @return DamageState -+ * @throws IllegalArgumentException If non anvil material is given -+ */ -+ @NotNull -+ public static DamageState getState(@Nullable Material material) { -+ if (material == null) { -+ return BROKEN; -+ } -+ for (DamageState state : values()) { -+ if (state.material == material) { -+ return state; -+ } -+ } -+ throw new IllegalArgumentException("Material not an anvil"); -+ } -+ } -+} diff --git a/patches/api/0133-Remove-deadlock-risk-in-firing-async-events.patch b/patches/api/0133-Remove-deadlock-risk-in-firing-async-events.patch deleted file mode 100644 index 9949645beb5c..000000000000 --- a/patches/api/0133-Remove-deadlock-risk-in-firing-async-events.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 9 Sep 2018 00:32:05 -0400 -Subject: [PATCH] Remove deadlock risk in firing async events - -The PluginManager incorrectly used synchronization on firing any event -that was marked as synchronous. - -This synchronized did not even protect any concurrency risk as -handlers were already thread safe in terms of mutations during event -dispatch. - -The way it was used, has commonly led to deadlocks on the server, -which results in a hard crash. - -This change removes the synchronize and adds some protection around enable/disable - -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index 6b38b14bfd73f3b7d06b6f747d60373cedf1fa6f..45989646f5c32fd1470a9868afca3e3a9074579c 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -467,7 +467,7 @@ public final class SimplePluginManager implements PluginManager { - * @return true if the plugin is enabled, otherwise false - */ - @Override -- public boolean isPluginEnabled(@Nullable Plugin plugin) { -+ public synchronized boolean isPluginEnabled(@Nullable Plugin plugin) { // Paper - synchronize - if ((plugin != null) && (plugins.contains(plugin))) { - return plugin.isEnabled(); - } else { -@@ -476,7 +476,7 @@ public final class SimplePluginManager implements PluginManager { - } - - @Override -- public void enablePlugin(@NotNull final Plugin plugin) { -+ public synchronized void enablePlugin(@NotNull final Plugin plugin) { // Paper - synchronize - if (!plugin.isEnabled()) { - List pluginCommands = PluginCommandYamlParser.parse(plugin); - -@@ -519,7 +519,7 @@ public final class SimplePluginManager implements PluginManager { - // Paper end - - @Override -- public void disablePlugin(@NotNull final Plugin plugin) { -+ public synchronized void disablePlugin(@NotNull final Plugin plugin) { // Paper - synchronize - if (plugin.isEnabled()) { - try { - plugin.getPluginLoader().disablePlugin(plugin); -@@ -588,6 +588,7 @@ public final class SimplePluginManager implements PluginManager { - defaultPerms.get(false).clear(); - } - } -+ private void fireEvent(Event event) { callEvent(event); } // Paper - support old method incase plugin uses reflection - - /** - * Calls an event with the given details. -@@ -596,23 +597,13 @@ public final class SimplePluginManager implements PluginManager { - */ - @Override - public void callEvent(@NotNull Event event) { -- if (event.isAsynchronous()) { -- if (Thread.holdsLock(this)) { -- throw new IllegalStateException(event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); -- } -- if (server.isPrimaryThread()) { -- throw new IllegalStateException(event.getEventName() + " cannot be triggered asynchronously from primary server thread."); -- } -- } else { -- if (!server.isPrimaryThread()) { -- throw new IllegalStateException(event.getEventName() + " cannot be triggered asynchronously from another thread."); -- } -+ // Paper - replace callEvent by merging to below method -+ if (event.isAsynchronous() && server.isPrimaryThread()) { -+ throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously."); -+ } else if (!event.isAsynchronous() && !server.isPrimaryThread()) { -+ throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); - } - -- fireEvent(event); -- } -- -- private void fireEvent(@NotNull Event event) { - HandlerList handlers = event.getHandlers(); - RegisteredListener[] listeners = handlers.getRegisteredListeners(); - -diff --git a/src/test/java/org/bukkit/plugin/PluginManagerTest.java b/src/test/java/org/bukkit/plugin/PluginManagerTest.java -index f188cd4f3b07027c30d41f1162db77a506b7b6bb..1941c9f49e9514c1236c5f4ea9f7af47f7be85c5 100644 ---- a/src/test/java/org/bukkit/plugin/PluginManagerTest.java -+++ b/src/test/java/org/bukkit/plugin/PluginManagerTest.java -@@ -17,7 +17,7 @@ public class PluginManagerTest { - private static final PluginManager pm = TestServer.getInstance().getPluginManager(); - - private final MutableObject store = new MutableObject(); -- -+/* // Paper start - remove unneeded test - @Test - public void testAsyncSameThread() { - final Event event = new TestEvent(true); -@@ -28,14 +28,14 @@ public class PluginManagerTest { - return; - } - throw new IllegalStateException("No exception thrown"); -- } -+ }*/ // Paper end - - @Test - public void testSyncSameThread() { - final Event event = new TestEvent(false); - pm.callEvent(event); - } -- -+/* // Paper start - remove unneeded test - @Test - public void testAsyncLocked() throws InterruptedException { - final Event event = new TestEvent(true); -@@ -129,7 +129,7 @@ public class PluginManagerTest { - if (store.value == null) { - throw new IllegalStateException("No exception thrown"); - } -- } -+ } */ // Paper - - @Test - public void testRemovePermissionByNameLower() { diff --git a/patches/api/0133-Slime-Pathfinder-Events.patch b/patches/api/0133-Slime-Pathfinder-Events.patch new file mode 100644 index 000000000000..9779ef7b215f --- /dev/null +++ b/patches/api/0133-Slime-Pathfinder-Events.patch @@ -0,0 +1,231 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 24 Aug 2018 08:18:27 -0500 +Subject: [PATCH] Slime Pathfinder Events + + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a5d4442b53c4bd70165c3240c7dbd3d56b6bf0ae +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java +@@ -0,0 +1,41 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Slime; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a Slime decides to change its facing direction. ++ *

      ++ * This event does not fire for the entity's actual movement. Only when it ++ * is choosing to change direction. ++ */ ++@NullMarked ++public class SlimeChangeDirectionEvent extends SlimePathfindEvent { ++ ++ private float yaw; ++ ++ @ApiStatus.Internal ++ public SlimeChangeDirectionEvent(final Slime slime, final float yaw) { ++ super(slime); ++ this.yaw = yaw; ++ } ++ ++ /** ++ * Get the new chosen yaw ++ * ++ * @return Chosen yaw ++ */ ++ public float getNewYaw() { ++ return this.yaw; ++ } ++ ++ /** ++ * Set the new chosen yaw ++ * ++ * @param yaw Chosen yaw ++ */ ++ public void setNewYaw(final float yaw) { ++ this.yaw = yaw; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d481d116452fb5a702bc88a08da3c28cd0401a70 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java +@@ -0,0 +1,56 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Slime; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a Slime decides to start pathfinding. ++ *

      ++ * This event does not fire for the entity's actual movement. Only when it ++ * is choosing to start moving. ++ */ ++@NullMarked ++public class SlimePathfindEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public SlimePathfindEvent(final Slime slime) { ++ super(slime); ++ } ++ ++ /** ++ * The Slime that is pathfinding. ++ * ++ * @return The Slime that is pathfinding. ++ */ ++ @Override ++ public Slime getEntity() { ++ return (Slime) super.getEntity(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4233ea3012c03660c42e3ec93832a6e019440eba +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java +@@ -0,0 +1,20 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Slime; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a Slime decides to start jumping while swimming in water/lava. ++ *

      ++ * This event does not fire for the entity's actual movement. Only when it ++ * is choosing to start jumping. ++ */ ++@NullMarked ++public class SlimeSwimEvent extends SlimeWanderEvent { ++ ++ @ApiStatus.Internal ++ public SlimeSwimEvent(final Slime slime) { ++ super(slime); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ba7369aab0c257acafda7d3a43a41e409240bf1d +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java +@@ -0,0 +1,33 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.entity.Slime; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a Slime decides to change direction to target a LivingEntity. ++ *

      ++ * This event does not fire for the entity's actual movement. Only when it ++ * is choosing to start moving. ++ */ ++@NullMarked ++public class SlimeTargetLivingEntityEvent extends SlimePathfindEvent { ++ ++ private final LivingEntity target; ++ ++ @ApiStatus.Internal ++ public SlimeTargetLivingEntityEvent(final Slime slime, final LivingEntity target) { ++ super(slime); ++ this.target = target; ++ } ++ ++ /** ++ * Get the targeted entity ++ * ++ * @return Targeted entity ++ */ ++ public LivingEntity getTarget() { ++ return this.target; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0ea085c4a1cf663e2333444cebda876db321164d +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java +@@ -0,0 +1,20 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Slime; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a Slime decides to start wandering. ++ *

      ++ * This event does not fire for the entity's actual movement. Only when it ++ * is choosing to start moving. ++ */ ++@NullMarked ++public class SlimeWanderEvent extends SlimePathfindEvent { ++ ++ @ApiStatus.Internal ++ public SlimeWanderEvent(final Slime slime) { ++ super(slime); ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Slime.java b/src/main/java/org/bukkit/entity/Slime.java +index 0a2d603bf6a3f60d3fa7d85df6ef2373fc93d848..26d09d2029d470343b2b70112cb1460945c026e7 100644 +--- a/src/main/java/org/bukkit/entity/Slime.java ++++ b/src/main/java/org/bukkit/entity/Slime.java +@@ -24,4 +24,20 @@ public interface Slime extends Mob, Enemy { + * @param sz The new size of the slime. + */ + public void setSize(int sz); ++ ++ // Paper start ++ /** ++ * Get whether this slime can randomly wander/jump around on its own ++ * ++ * @return true if can wander ++ */ ++ public boolean canWander(); ++ ++ /** ++ * Set whether this slime can randomly wander/jump around on its own ++ * ++ * @param canWander true if can wander ++ */ ++ public void setWander(boolean canWander); ++ // Paper end + } diff --git a/patches/api/0134-Add-PhantomPreSpawnEvent.patch b/patches/api/0134-Add-PhantomPreSpawnEvent.patch new file mode 100644 index 000000000000..aac9b3567273 --- /dev/null +++ b/patches/api/0134-Add-PhantomPreSpawnEvent.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 25 Aug 2018 19:56:42 -0500 +Subject: [PATCH] Add PhantomPreSpawnEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e465222aa8218a7fef85f2e1df1a919a88499eab +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java +@@ -0,0 +1,32 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.Location; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.EntityType; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a phantom is spawned for an exhausted player ++ */ ++@NullMarked ++public class PhantomPreSpawnEvent extends PreCreatureSpawnEvent { ++ ++ private final Entity entity; ++ ++ @ApiStatus.Internal ++ public PhantomPreSpawnEvent(final Location location, final Entity entity, final CreatureSpawnEvent.SpawnReason reason) { ++ super(location, EntityType.PHANTOM, reason); ++ this.entity = entity; ++ } ++ ++ /** ++ * Get the entity this phantom is spawning for ++ * ++ * @return the Entity ++ */ ++ public Entity getSpawningEntity() { ++ return this.entity; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Phantom.java b/src/main/java/org/bukkit/entity/Phantom.java +index 86cfdcf3060876c87066483d122e12f5feb55e02..082601f349ae2cebbffd1012c19c521241696a09 100644 +--- a/src/main/java/org/bukkit/entity/Phantom.java ++++ b/src/main/java/org/bukkit/entity/Phantom.java +@@ -1,5 +1,8 @@ + package org.bukkit.entity; + ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ + /** + * Represents a phantom. + */ +@@ -14,4 +17,14 @@ public interface Phantom extends Flying, Enemy { + * @param sz The new size of the phantom. + */ + public void setSize(int sz); ++ ++ // Paper start ++ /** ++ * Get the UUID of the entity that caused this phantom to spawn ++ * ++ * @return UUID ++ */ ++ @Nullable ++ public java.util.UUID getSpawningEntity(); ++ // Paper end + } diff --git a/patches/api/0134-Add-hand-to-bucket-events.patch b/patches/api/0134-Add-hand-to-bucket-events.patch deleted file mode 100644 index 85c5c370f32f..000000000000 --- a/patches/api/0134-Add-hand-to-bucket-events.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Thu, 2 Aug 2018 08:44:20 -0500 -Subject: [PATCH] Add hand to bucket events - - -diff --git a/src/main/java/org/bukkit/event/player/PlayerBucketEmptyEvent.java b/src/main/java/org/bukkit/event/player/PlayerBucketEmptyEvent.java -index 7f225baa9fd3ff6f4f950ae70f9500141c674f66..25bd8153ef2ab7ab1052cf756bb599f1095732e7 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerBucketEmptyEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerBucketEmptyEvent.java -@@ -5,6 +5,7 @@ import org.bukkit.block.Block; - import org.bukkit.block.BlockFace; - import org.bukkit.entity.Player; - import org.bukkit.event.HandlerList; -+import org.bukkit.inventory.EquipmentSlot; - import org.bukkit.inventory.ItemStack; - import org.jetbrains.annotations.NotNull; - -@@ -22,6 +23,16 @@ public class PlayerBucketEmptyEvent extends PlayerBucketEvent { - public PlayerBucketEmptyEvent(@NotNull final Player who, @NotNull final Block block, @NotNull final Block blockClicked, @NotNull final BlockFace blockFace, @NotNull final Material bucket, @NotNull final ItemStack itemInHand) { - super(who, block, blockClicked, blockFace, bucket, itemInHand); - } -+ // Paper start - add EquipmentSlot -+ @Deprecated -+ public PlayerBucketEmptyEvent(@NotNull final Player who, @NotNull final Block blockClicked, @NotNull final BlockFace blockFace, @NotNull final Material bucket, @NotNull final ItemStack itemInHand, @org.jetbrains.annotations.Nullable final EquipmentSlot hand) { -+ super(who, blockClicked, blockFace, bucket, itemInHand, hand); -+ } -+ -+ public PlayerBucketEmptyEvent(@NotNull final Player who, @NotNull final Block block, @NotNull final Block blockClicked, @NotNull final BlockFace blockFace, @NotNull final Material bucket, @NotNull final ItemStack itemInHand, @org.jetbrains.annotations.Nullable final EquipmentSlot hand) { -+ super(who, block, blockClicked, blockFace, bucket, itemInHand, hand); -+ } -+ // Paper end - - @NotNull - @Override -diff --git a/src/main/java/org/bukkit/event/player/PlayerBucketEvent.java b/src/main/java/org/bukkit/event/player/PlayerBucketEvent.java -index 0e4fa04ea73baaf2f9ad86725d379b569d7d6381..1e0f7ee7d198c08ce421ce105be42c4d01dc924f 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerBucketEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerBucketEvent.java -@@ -5,6 +5,7 @@ import org.bukkit.block.Block; - import org.bukkit.block.BlockFace; - import org.bukkit.entity.Player; - import org.bukkit.event.Cancellable; -+import org.bukkit.inventory.EquipmentSlot; - import org.bukkit.inventory.ItemStack; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; -@@ -19,6 +20,7 @@ public abstract class PlayerBucketEvent extends PlayerEvent implements Cancellab - private final Block blockClicked; - private final BlockFace blockFace; - private final Material bucket; -+ private final EquipmentSlot hand; // Paper - add EquipmentSlot - - @Deprecated - public PlayerBucketEvent(@NotNull final Player who, @NotNull final Block blockClicked, @NotNull final BlockFace blockFace, @NotNull final Material bucket, @NotNull final ItemStack itemInHand) { -@@ -26,12 +28,24 @@ public abstract class PlayerBucketEvent extends PlayerEvent implements Cancellab - } - - public PlayerBucketEvent(@NotNull final Player who, @NotNull final Block block, @NotNull final Block blockClicked, @NotNull final BlockFace blockFace, @NotNull final Material bucket, @NotNull final ItemStack itemInHand) { -+ // Paper start - add EquipmentSlot -+ this(who, block, blockClicked, blockFace, bucket, itemInHand, null); -+ } -+ -+ @Deprecated -+ public PlayerBucketEvent(@NotNull final Player who,@NotNull final Block blockClicked, @NotNull final BlockFace blockFace, @NotNull final Material bucket, @NotNull final ItemStack itemInHand, @Nullable final EquipmentSlot hand) { -+ this(who, null, blockClicked, blockFace, bucket, itemInHand, hand); -+ } -+ -+ public PlayerBucketEvent(@NotNull final Player who, @NotNull final Block block, @NotNull final Block blockClicked, @NotNull final BlockFace blockFace, @NotNull final Material bucket, @NotNull final ItemStack itemInHand, @Nullable final EquipmentSlot hand) { -+ // Paper end - super(who); - this.block = block; - this.blockClicked = blockClicked; - this.blockFace = blockFace; - this.itemStack = itemInHand; - this.bucket = bucket; -+ this.hand = hand == null ? player.getInventory().getItemInMainHand().equals(itemInHand) ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND : hand; // Paper - add EquipmentSlot - } - - /** -@@ -93,6 +107,18 @@ public abstract class PlayerBucketEvent extends PlayerEvent implements Cancellab - return blockFace; - } - -+ // Paper start -+ /** -+ * The hand used to perform this action. -+ * -+ * @return the hand used -+ */ -+ @NotNull -+ public EquipmentSlot getHand() { -+ return hand; -+ } -+ // Paper end -+ - @Override - public boolean isCancelled() { - return cancelled; -diff --git a/src/main/java/org/bukkit/event/player/PlayerBucketFillEvent.java b/src/main/java/org/bukkit/event/player/PlayerBucketFillEvent.java -index 77c3a6e5c89ffde564d63b98b2d9e36c356d79fd..56f1cc2d773d2c58207ee291bac596692980a731 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerBucketFillEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerBucketFillEvent.java -@@ -5,6 +5,7 @@ import org.bukkit.block.Block; - import org.bukkit.block.BlockFace; - import org.bukkit.entity.Player; - import org.bukkit.event.HandlerList; -+import org.bukkit.inventory.EquipmentSlot; - import org.bukkit.inventory.ItemStack; - import org.jetbrains.annotations.NotNull; - -@@ -23,6 +24,18 @@ public class PlayerBucketFillEvent extends PlayerBucketEvent { - super(who, block, blockClicked, blockFace, bucket, itemInHand); - } - -+ // Paper start - add EquipmentSlot -+ @Deprecated -+ public PlayerBucketFillEvent(@NotNull final Player who, @NotNull final Block blockClicked, @NotNull final BlockFace blockFace, @NotNull final Material bucket, @NotNull final ItemStack itemInHand, @org.jetbrains.annotations.Nullable final EquipmentSlot hand) { -+ super(who, blockClicked, blockFace, bucket, itemInHand, hand); -+ } -+ -+ // Paper start - add EquipmentSlot -+ public PlayerBucketFillEvent(@NotNull final Player who, @NotNull Block block, @NotNull final Block blockClicked, @NotNull final BlockFace blockFace, @NotNull final Material bucket, @NotNull final ItemStack itemInHand, @org.jetbrains.annotations.Nullable final EquipmentSlot hand) { -+ super(who, block, blockClicked, blockFace, bucket, itemInHand, hand); -+ } -+ // Paper end -+ - @NotNull - @Override - public HandlerList getHandlers() { diff --git a/patches/api/0135-Add-More-Creeper-API.patch b/patches/api/0135-Add-More-Creeper-API.patch new file mode 100644 index 000000000000..8e7c0d2ad1a5 --- /dev/null +++ b/patches/api/0135-Add-More-Creeper-API.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 24 Aug 2018 11:50:16 -0500 +Subject: [PATCH] Add More Creeper API + + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8b97cc830aa8bdb09dec3c4b8ebe4fb22d279f46 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java +@@ -0,0 +1,60 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Creeper; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a Creeper is ignited either by a ++ * flint and steel, {@link Creeper#ignite()} or ++ * {@link Creeper#setIgnited(boolean)}. ++ */ ++@NullMarked ++public class CreeperIgniteEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private boolean ignited; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public CreeperIgniteEvent(final Creeper creeper, final boolean ignited) { ++ super(creeper); ++ this.ignited = ignited; ++ } ++ ++ @Override ++ public Creeper getEntity() { ++ return (Creeper) super.getEntity(); ++ } ++ ++ public boolean isIgnited() { ++ return this.ignited; ++ } ++ ++ public void setIgnited(final boolean ignited) { ++ this.ignited = ignited; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Creeper.java b/src/main/java/org/bukkit/entity/Creeper.java +index e440b06f358e7edc87254e46d1a2002216ebbab1..5e750f4043fdf5ac9836056a015148df92aed067 100644 +--- a/src/main/java/org/bukkit/entity/Creeper.java ++++ b/src/main/java/org/bukkit/entity/Creeper.java +@@ -112,4 +112,20 @@ public interface Creeper extends Monster { + */ + @Nullable + public Entity getIgniter(); ++ // Paper start ++ ++ /** ++ * Set whether creeper is ignited or not (armed to explode) ++ * ++ * @param ignited New ignited state ++ */ ++ public void setIgnited(boolean ignited); ++ ++ /** ++ * Check if creeper is ignited or not (armed to explode) ++ * ++ * @return Ignited state ++ */ ++ public boolean isIgnited(); ++ // Paper end + } diff --git a/patches/api/0135-Add-TNTPrimeEvent.patch b/patches/api/0135-Add-TNTPrimeEvent.patch deleted file mode 100644 index 2bddc56f13d9..000000000000 --- a/patches/api/0135-Add-TNTPrimeEvent.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Sun, 15 Jul 2018 22:17:55 +0300 -Subject: [PATCH] Add TNTPrimeEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java b/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..73dabb82c7fbea3f0cccade0a2944b11a80ede06 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java -@@ -0,0 +1,114 @@ -+package com.destroystokyo.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.entity.Entity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when TNT block is about to turn into {@link org.bukkit.entity.TNTPrimed} -+ *

      -+ * Cancelling it won't turn TNT into {@link org.bukkit.entity.TNTPrimed} and leaves -+ * the TNT block as-is -+ * -+ * @author Mark Vainomaa -+ */ -+public class TNTPrimeEvent extends BlockEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ @NotNull private PrimeReason reason; -+ @Nullable private Entity primerEntity; -+ -+ public TNTPrimeEvent(@NotNull Block theBlock, @NotNull PrimeReason reason, @Nullable Entity primerEntity) { -+ super(theBlock); -+ this.reason = reason; -+ this.primerEntity = primerEntity; -+ } -+ -+ /** -+ * Gets the TNT prime reason -+ * -+ * @return Prime reason -+ */ -+ @NotNull -+ public PrimeReason getReason() { -+ return this.reason; -+ } -+ -+ /** -+ * Gets the TNT primer {@link Entity}. -+ * -+ * It's null if {@link #getReason()} is {@link PrimeReason#REDSTONE} or {@link PrimeReason#FIRE}. -+ * It's not null if {@link #getReason()} is {@link PrimeReason#ITEM} or {@link PrimeReason#PROJECTILE} -+ * It might be null if {@link #getReason()} is {@link PrimeReason#EXPLOSION} -+ * -+ * @return The {@link Entity} who primed the TNT -+ */ -+ @Nullable -+ public Entity getPrimerEntity() { -+ return this.primerEntity; -+ } -+ -+ /** -+ * Gets whether spawning {@link org.bukkit.entity.TNTPrimed} should be cancelled or not -+ * -+ * @return Whether spawning {@link org.bukkit.entity.TNTPrimed} should be cancelled or not -+ */ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ /** -+ * Sets whether to cancel spawning {@link org.bukkit.entity.TNTPrimed} or not -+ * -+ * @param cancel whether spawning {@link org.bukkit.entity.TNTPrimed} should be cancelled or not -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @Nullable -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @Nullable -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ public enum PrimeReason { -+ /** -+ * When TNT prime was caused by other explosion (chain reaction) -+ */ -+ EXPLOSION, -+ -+ /** -+ * When TNT prime was caused by fire -+ */ -+ FIRE, -+ -+ /** -+ * When {@link org.bukkit.entity.Player} used {@link org.bukkit.Material#FLINT_AND_STEEL} or -+ * {@link org.bukkit.Material#FIRE_CHARGE} on given TNT block -+ */ -+ ITEM, -+ -+ /** -+ * When TNT prime was caused by an {@link Entity} shooting TNT -+ * using a bow with {@link org.bukkit.enchantments.Enchantment#ARROW_FIRE} enchantment -+ */ -+ PROJECTILE, -+ -+ /** -+ * When redstone power triggered the TNT prime -+ */ -+ REDSTONE -+ } -+} diff --git a/patches/api/0136-Inventory-removeItemAnySlot.patch b/patches/api/0136-Inventory-removeItemAnySlot.patch new file mode 100644 index 000000000000..25b79cf6bd95 --- /dev/null +++ b/patches/api/0136-Inventory-removeItemAnySlot.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Tue, 28 Aug 2018 23:04:06 -0400 +Subject: [PATCH] Inventory#removeItemAnySlot + + +diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/org/bukkit/inventory/Inventory.java +index 5576a6a8df8c95164bf2dde45d756ce8b7ec957a..f1a48eab1a357ae64545e1f1dc941c383cff8707 100644 +--- a/src/main/java/org/bukkit/inventory/Inventory.java ++++ b/src/main/java/org/bukkit/inventory/Inventory.java +@@ -104,7 +104,9 @@ public interface Inventory extends Iterable { + public HashMap addItem(@NotNull ItemStack... items) throws IllegalArgumentException; + + /** +- * Removes the given ItemStacks from the inventory. ++ * Removes the given ItemStacks from the storage contents of the inventory. ++ * For removing ItemStacks from the inventories that have other content groups, ++ * like Player inventories, see {@link #removeItemAnySlot(ItemStack...)}. + *

      + * It will try to remove 'as much as possible' from the types and amounts + * you give as arguments. +@@ -121,10 +123,39 @@ public interface Inventory extends Iterable { + * @param items The ItemStacks to remove + * @return A HashMap containing items that couldn't be removed. + * @throws IllegalArgumentException if items is null ++ * @see #removeItemAnySlot(ItemStack...) + */ + @NotNull + public HashMap removeItem(@NotNull ItemStack... items) throws IllegalArgumentException; + ++ // Paper start ++ /** ++ * Searches all possible inventory slots in order to remove the given ItemStacks. ++ *

      ++ * Similar to {@link Inventory#removeItem(ItemStack...)} in behavior, except this ++ * method will check all possible slots in the inventory, rather than just the main ++ * storage contents. ++ *

      ++ * It will try to remove 'as much as possible' from the types and amounts ++ * you give as arguments. ++ *

      ++ * The returned HashMap contains what it couldn't remove, where the key is ++ * the index of the parameter, and the value is the ItemStack at that ++ * index of the varargs parameter. If all the given ItemStacks are ++ * removed, it will return an empty HashMap. ++ *

      ++ * It is known that in some implementations this method will also set the ++ * inputted argument amount to the number of that item not removed from ++ * slots. ++ * ++ * @param items The ItemStacks to remove ++ * @return A HashMap containing items that couldn't be removed. ++ * @throws IllegalArgumentException if items is null ++ */ ++ @NotNull ++ public HashMap removeItemAnySlot(@NotNull ItemStack... items) throws IllegalArgumentException; ++ // Paper end ++ + /** + * Returns all ItemStacks from the inventory + * diff --git a/patches/api/0136-Provide-Chunk-Coordinates-as-a-Long-API.patch b/patches/api/0136-Provide-Chunk-Coordinates-as-a-Long-API.patch deleted file mode 100644 index 493bf262e6c9..000000000000 --- a/patches/api/0136-Provide-Chunk-Coordinates-as-a-Long-API.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 4 Aug 2018 19:37:35 -0400 -Subject: [PATCH] Provide Chunk Coordinates as a Long API - -Allows you to easily access the chunks X/z as a long, and a method -to look up by the long key too. - -diff --git a/src/main/java/org/bukkit/Chunk.java b/src/main/java/org/bukkit/Chunk.java -index 06737962b844275a74ee2407cc09918599cbaea4..1a4b6922c0a881b60ddf305b1e2b3af0dfde46c3 100644 ---- a/src/main/java/org/bukkit/Chunk.java -+++ b/src/main/java/org/bukkit/Chunk.java -@@ -28,6 +28,32 @@ public interface Chunk extends PersistentDataHolder { - */ - int getZ(); - -+ // Paper start -+ /** -+ * @return The Chunks X and Z coordinates packed into a long -+ */ -+ default long getChunkKey() { -+ return getChunkKey(getX(), getZ()); -+ } -+ -+ /** -+ * @param loc Location to get chunk key -+ * @return Location's chunk coordinates packed into a long -+ */ -+ static long getChunkKey(@NotNull Location loc) { -+ return getChunkKey((int) Math.floor(loc.getX()) >> 4, (int) Math.floor(loc.getZ()) >> 4); -+ } -+ -+ /** -+ * @param x X Coordinate -+ * @param z Z Coordinate -+ * @return Chunk coordinates packed into a long -+ */ -+ static long getChunkKey(int x, int z) { -+ return (long) x & 0xffffffffL | ((long) z & 0xffffffffL) << 32; -+ } -+ // Paper end -+ - /** - * Gets the world containing this chunk - * -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index f46032ac8d48ba172e6a9157dd6b477ddf2cd4cb..cbfd9f994e545aa36c62f9cf801a595d3db71e9f 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -212,6 +212,22 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - @NotNull - public Chunk getChunkAt(@NotNull Block block); - -+ // Paper start -+ /** -+ * Gets the chunk at the specified chunk key, which is the X and Z packed into a long. -+ * -+ * See {@link Chunk#getChunkKey()} for easy access to the key, or you may calculate it as: -+ * long chunkKey = (long) chunkX & 0xffffffffL | ((long) chunkZ & 0xffffffffL) >> 32; -+ * -+ * @param chunkKey The Chunk Key to look up the chunk by -+ * @return The chunk at the specified key -+ */ -+ @NotNull -+ public default Chunk getChunkAt(long chunkKey) { -+ return getChunkAt((int) chunkKey, (int) (chunkKey >> 32)); -+ } -+ // Paper end -+ - /** - * Checks if the specified {@link Chunk} is loaded - * diff --git a/patches/api/0137-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch b/patches/api/0137-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch deleted file mode 100644 index 55575b064244..000000000000 --- a/patches/api/0137-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 15 Aug 2018 01:04:58 -0400 -Subject: [PATCH] Ability to get Tile Entities from a chunk without snapshots - - -diff --git a/src/main/java/org/bukkit/Chunk.java b/src/main/java/org/bukkit/Chunk.java -index 1a4b6922c0a881b60ddf305b1e2b3af0dfde46c3..049c36807d2a970842442c1b7517c06f3f150041 100644 ---- a/src/main/java/org/bukkit/Chunk.java -+++ b/src/main/java/org/bukkit/Chunk.java -@@ -1,6 +1,8 @@ - package org.bukkit; - - import java.util.Collection; -+import java.util.function.Predicate; -+ - import org.bukkit.block.Block; - import org.bukkit.block.BlockState; - import org.bukkit.block.data.BlockData; -@@ -111,13 +113,36 @@ public interface Chunk extends PersistentDataHolder { - @NotNull - Entity[] getEntities(); - -+ // Paper start - /** - * Get a list of all tile entities in the chunk. - * - * @return The tile entities. - */ - @NotNull -- BlockState[] getTileEntities(); -+ default BlockState[] getTileEntities() { -+ return getTileEntities(true); -+ } -+ -+ /** -+ * Get a list of all tile entities in the chunk. -+ * -+ * @param useSnapshot Take snapshots or direct references -+ * @return The tile entities. -+ */ -+ @NotNull -+ BlockState[] getTileEntities(boolean useSnapshot); -+ -+ /** -+ * Get a list of all tile entities that match a given predicate in the chunk. -+ * -+ * @param blockPredicate The predicate of blocks to return tile entities for -+ * @param useSnapshot Take snapshots or direct references -+ * @return The tile entities. -+ */ -+ @NotNull -+ Collection getTileEntities(@NotNull Predicate blockPredicate, boolean useSnapshot); -+ // Paper end - - /** - * Checks if the chunk is loaded. diff --git a/patches/api/0137-isChunkGenerated-API.patch b/patches/api/0137-isChunkGenerated-API.patch new file mode 100644 index 000000000000..ed7a4601f8fa --- /dev/null +++ b/patches/api/0137-isChunkGenerated-API.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: cswhite2000 <18whitechristop@gmail.com> +Date: Tue, 21 Aug 2018 19:39:46 -0700 +Subject: [PATCH] isChunkGenerated API + + +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index 12e1733d06471d0c2253ae846ee93a09140843cc..b02efba048be00e42502111fcdd2297529926666 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -3,6 +3,7 @@ package org.bukkit; + import com.google.common.base.Preconditions; + import java.lang.ref.Reference; + import java.lang.ref.WeakReference; ++import com.google.common.base.Preconditions; // Paper + import java.util.HashMap; + import java.util.Map; + import org.bukkit.block.Block; +@@ -544,6 +545,19 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + + public boolean isChunkLoaded() { return this.getWorld().isChunkLoaded(locToBlock(x) >> 4, locToBlock(z) >> 4); } // Paper + ++ // Paper start - isGenerated API ++ /** ++ * Checks if a {@link Chunk} has been generated at this location. ++ * ++ * @return true if a chunk has been generated at this location ++ */ ++ public boolean isGenerated() { ++ World world = this.getWorld(); ++ Preconditions.checkNotNull(world, "Location has no world!"); ++ return world.isChunkGenerated(locToBlock(x) >> 4, locToBlock(z) >> 4); ++ } ++ // Paper end - isGenerated API ++ + // Paper start - expand location manipulation API + + /** +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index eaa51337616746a7ee1407c1fdcb7246f9483a8b..2986793d6e3e71ae900bbd3293af288d4ad0b503 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -248,6 +248,19 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + } + // Paper end - chunk long key API + ++ // Paper start - isChunkGenerated API ++ /** ++ * Checks if a {@link Chunk} has been generated at the specified chunk key, ++ * which is the X and Z packed into a long. ++ * ++ * @param chunkKey The Chunk Key to look up the chunk by ++ * @return true if the chunk has been generated, otherwise false ++ */ ++ default boolean isChunkGenerated(long chunkKey) { ++ return isChunkGenerated((int) chunkKey, (int) (chunkKey >> 32)); ++ } ++ // Paper end - isChunkGenerated API ++ + /** + * Checks if the specified {@link Chunk} is loaded + * diff --git a/patches/api/0138-Add-source-block-constructor-and-getChangedBlockData.patch b/patches/api/0138-Add-source-block-constructor-and-getChangedBlockData.patch new file mode 100644 index 000000000000..f12e6ac1f5c4 --- /dev/null +++ b/patches/api/0138-Add-source-block-constructor-and-getChangedBlockData.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sotr +Date: Thu, 23 Aug 2018 16:14:25 +0800 +Subject: [PATCH] Add source block constructor and getChangedBlockData() to + BlockPhysicsEvent + + +diff --git a/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java b/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java +index e3a5f5824ed882058f5bac5003f66ce79733a868..b23686d2e452dc0b8bde453b4a375f424cb7504a 100644 +--- a/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java +@@ -32,6 +32,13 @@ public class BlockPhysicsEvent extends BlockEvent implements Cancellable { + private final Block sourceBlock; + private boolean cancel = false; + ++ // Paper start - Legacy constructor, use #BlockPhysicsEvent(Block, BlockData, Block) ++ @Deprecated ++ public BlockPhysicsEvent(final Block block, final BlockData changed, final int sourceX, final int sourceY, final int sourceZ) { ++ this(block, changed, block.getWorld().getBlockAt(sourceX, sourceY, sourceZ)); ++ } ++ // Paper end ++ + public BlockPhysicsEvent(@NotNull final Block block, @NotNull final BlockData changed) { + this(block, changed, block); + } +@@ -55,7 +62,8 @@ public class BlockPhysicsEvent extends BlockEvent implements Cancellable { + } + + /** +- * Gets the type of block that changed, causing this event ++ * Gets the type of block that changed, causing this event. ++ * This is the type of {@link #getBlock()} at the time of the event. + * + * @return Changed block's type + */ +@@ -64,6 +72,19 @@ public class BlockPhysicsEvent extends BlockEvent implements Cancellable { + return changed.getMaterial(); + } + ++ // Paper start - Getter for the BlockData ++ /** ++ * Gets the BlockData of the block that changed, causing this event. ++ * This is the BlockData of {@link #getBlock()} at the time of the event. ++ * ++ * @return Changed block's BlockData ++ */ ++ @NotNull ++ public BlockData getChangedBlockData() { ++ return changed.clone(); ++ } ++ // Paper end ++ + @Override + public boolean isCancelled() { + return cancel; diff --git a/patches/api/0138-Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch b/patches/api/0138-Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch deleted file mode 100644 index 536fdc2d0623..000000000000 --- a/patches/api/0138-Don-t-use-snapshots-for-Timings-Tile-Entity-reports.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 15 Aug 2018 01:19:37 -0400 -Subject: [PATCH] Don't use snapshots for Timings Tile Entity reports - - -diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java -index ddaed81275fcc12d1671b668697acf318e96888b..203cda0f9a4dea4f28a21ea9ee8db7a7369842e3 100644 ---- a/src/main/java/co/aikar/timings/TimingHistory.java -+++ b/src/main/java/co/aikar/timings/TimingHistory.java -@@ -119,7 +119,7 @@ public class TimingHistory { - data.entityCounts.get(entity.getType()).increment(); - } - -- for (BlockState tileEntity : chunk.getTileEntities()) { -+ for (BlockState tileEntity : chunk.getTileEntities(false)) { - if (tileEntity == null) { - Bukkit.getLogger().warning("Null tileentity detected in chunk at position x: " + chunk.getX() + ", z: " + chunk.getZ()); - continue; diff --git a/patches/api/0139-Allow-Blocks-to-be-accessed-via-a-long-key.patch b/patches/api/0139-Allow-Blocks-to-be-accessed-via-a-long-key.patch deleted file mode 100644 index e23878d10627..000000000000 --- a/patches/api/0139-Allow-Blocks-to-be-accessed-via-a-long-key.patch +++ /dev/null @@ -1,183 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Tue, 14 Aug 2018 21:42:10 -0700 -Subject: [PATCH] Allow Blocks to be accessed via a long key - -The key can be retrieved via methods Location#toBlockKey() and -Block#getBlockKey() - -World provides lookup for blocks by long key via method World#getBlockAtKey(long) - -The formatting for the key is as follows: - -10 bit y|27 bit z|27 bit x - -The y value is considered unsigned while z and x are considered two's complement - -Y range: [0, 1023] -X, Z range: [-67 108 864, 67 108 863] - -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index 36ed248f0716f2cc465c08ab851b7d83d4c7c0a7..5c5e05673e0912f4dbd6c728f4c3b7fcdae8f0e8 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -15,7 +15,6 @@ import org.jetbrains.annotations.Nullable; - - // Paper start - import java.util.Collection; --import java.util.Collections; - import java.util.function.Predicate; - import org.bukkit.entity.Entity; - import org.bukkit.entity.LivingEntity; -@@ -605,6 +604,19 @@ public class Location implements Cloneable, ConfigurationSerializable { - blockLoc.setZ(getBlockZ()); - return blockLoc; - } -+ -+ // Paper Start -+ /** -+ * @return The block key for this location's block location. -+ * @see Block#getBlockKey(int, int, int) -+ * @deprecated only encodes y block ranges from -512 to 511 and represents an already changed implementation detail -+ */ -+ @Deprecated -+ public long toBlockKey() { -+ return Block.getBlockKey(getBlockX(), getBlockY(), getBlockZ()); -+ } -+ // Paper End -+ - /** - * @return A new location where X/Y/Z are the center of the block - */ -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index cbfd9f994e545aa36c62f9cf801a595d3db71e9f..89e46828639b85da1f70f03bfd2a8e9c8487033f 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -95,6 +95,40 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - @NotNull - public Block getBlockAt(@NotNull Location location); - -+ // Paper start -+ /** -+ * Gets the {@link Block} at the given block key -+ * -+ * @param key The block key. See {@link Block#getBlockKey()} -+ * @return Block at the key -+ * @see Block#getBlockKey(int, int, int) -+ * @deprecated only encodes y block ranges from -512 to 511 and represents an already changed implementation detail -+ */ -+ @NotNull -+ @Deprecated -+ public default Block getBlockAtKey(long key) { -+ int x = Block.getBlockKeyX(key); -+ int y = Block.getBlockKeyY(key); -+ int z = Block.getBlockKeyZ(key); -+ return getBlockAt(x, y, z); -+ } -+ -+ /** -+ * Gets the {@link Location} at the given block key -+ * -+ * @param key The block key. See {@link Location#toBlockKey()} -+ * @return Location at the key -+ * @see Block#getBlockKey(int, int, int) -+ */ -+ @NotNull -+ public default Location getLocationAtKey(long key) { -+ int x = Block.getBlockKeyX(key); -+ int y = Block.getBlockKeyY(key); -+ int z = Block.getBlockKeyZ(key); -+ return new Location(this, x, y, z); -+ } -+ // Paper end -+ - /** - * Gets the highest non-empty (impassable) coordinate at the given - * coordinates. -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index d29bdc125dba0128d93d57e8d9393b970e6c00a9..b101f5264bdde8bd14913d5161c1047020830f8d 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -155,6 +155,82 @@ public interface Block extends Metadatable { - */ - int getZ(); - -+ // Paper Start -+ /** -+ * Returns this block's coordinates packed into a long value. -+ * Computed via: {@code Block.getBlockKey(this.getX(), this.getY(), this.getZ())} -+ * @see Block#getBlockKey(int, int, int) -+ * @return This block's x, y, and z coordinates packed into a long value -+ * @deprecated see {@link #getBlockKey(int, int, int)} -+ */ -+ @Deprecated -+ public default long getBlockKey() { -+ return Block.getBlockKey(this.getX(), this.getY(), this.getZ()); -+ } -+ -+ /** -+ * Returns the specified block coordinates packed into a long value -+ *

      -+ * The return value can be computed as follows: -+ *
      -+ * {@code long value = ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54);} -+ *

      -+ * -+ *

      -+ * And may be unpacked as follows: -+ *
      -+ * {@code int x = (int) ((packed << 37) >> 37);} -+ *
      -+ * {@code int y = (int) (packed >> 54);} -+ *
      -+ * {@code int z = (int) ((packed << 10) >> 37);} -+ *

      -+ * -+ * @return This block's x, y, and z coordinates packed into a long value -+ * @deprecated only encodes y block ranges from -512 to 511 and represents an already changed implementation detail -+ */ -+ @Deprecated -+ public static long getBlockKey(int x, int y, int z) { -+ return ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54); -+ } -+ -+ /** -+ * Returns the x component from the packed value. -+ * @param packed The packed value, as computed by {@link Block#getBlockKey(int, int, int)} -+ * @see Block#getBlockKey(int, int, int) -+ * @return The x component from the packed value. -+ * @deprecated see {@link #getBlockKey(int, int, int)} -+ */ -+ @Deprecated -+ public static int getBlockKeyX(long packed) { -+ return (int) ((packed << 37) >> 37); -+ } -+ -+ /** -+ * Returns the y component from the packed value. -+ * @param packed The packed value, as computed by {@link Block#getBlockKey(int, int, int)} -+ * @see Block#getBlockKey(int, int, int) -+ * @return The y component from the packed value. -+ * @deprecated see {@link #getBlockKey(int, int, int)} -+ */ -+ @Deprecated -+ public static int getBlockKeyY(long packed) { -+ return (int) (packed >> 54); -+ } -+ -+ /** -+ * Returns the z component from the packed value. -+ * @param packed The packed value, as computed by {@link Block#getBlockKey(int, int, int)} -+ * @see Block#getBlockKey(int, int, int) -+ * @return The z component from the packed value. -+ * @deprecated see {@link #getBlockKey(int, int, int)} -+ */ -+ @Deprecated -+ public static int getBlockKeyZ(long packed) { -+ return (int) ((packed << 10) >> 37); -+ } -+ // Paper End -+ - /** - * Gets the Location of the block - * diff --git a/patches/api/0139-Async-Chunks-API.patch b/patches/api/0139-Async-Chunks-API.patch new file mode 100644 index 000000000000..422531ab397e --- /dev/null +++ b/patches/api/0139-Async-Chunks-API.patch @@ -0,0 +1,567 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 29 Feb 2016 17:43:33 -0600 +Subject: [PATCH] Async Chunks API + +Adds API's to load or generate chunks asynchronously. + +Also adds utility methods to Entity to teleport asynchronously. + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 2986793d6e3e71ae900bbd3293af288d4ad0b503..9517091f601f362f80ff6062f53eff760f040e6c 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -977,6 +977,509 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + } + // Paper end - additional getNearbyEntities API + ++ // Paper start - async chunks API ++ /** ++ * This is the Legacy API before Java 8 was supported. Java 8 Consumer is provided, ++ * as well as future support ++ * ++ * Used by {@link World#getChunkAtAsync(Location,ChunkLoadCallback)} methods ++ * to request a {@link Chunk} to be loaded, with this callback receiving ++ * the chunk when it is finished. ++ * ++ * This callback will be executed on synchronously on the main thread. ++ * ++ * Timing and order this callback is fired is intentionally not defined and ++ * and subject to change. ++ * ++ * @deprecated Use either the Future or the Consumer based methods ++ */ ++ @Deprecated(since = "1.13.1") ++ public static interface ChunkLoadCallback extends java.util.function.Consumer { ++ public void onLoad(@NotNull Chunk chunk); ++ ++ // backwards compat to old api ++ @Override ++ default void accept(@NotNull Chunk chunk) { ++ onLoad(chunk); ++ } ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link ChunkLoadCallback} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @deprecated Use either the Future or the Consumer based methods ++ * @param x Chunk X-coordinate of the chunk - floor(world coordinate / 16) ++ * @param z Chunk Z-coordinate of the chunk - floor(world coordinate / 16) ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ @Deprecated(since = "1.13.1") ++ public default void getChunkAtAsync(int x, int z, @NotNull ChunkLoadCallback cb) { ++ this.getChunkAtAsync(x, z, (java.util.function.Consumer)cb); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given {@link Location} ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link ChunkLoadCallback} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @deprecated Use either the Future or the Consumer based methods ++ * @param loc Location of the chunk ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ @Deprecated(since = "1.13.1") ++ public default void getChunkAtAsync(@NotNull Location loc, @NotNull ChunkLoadCallback cb) { ++ this.getChunkAtAsync(loc.getBlockX() >> 4, loc.getBlockZ() >> 4, cb); ++ } ++ ++ /** ++ * Requests {@link Chunk} to be loaded that contains the given {@link Block} ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link ChunkLoadCallback} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @deprecated Use either the Future or the Consumer based methods ++ * @param block Block to get the containing chunk from ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ @Deprecated(since = "1.13.1") ++ public default void getChunkAtAsync(@NotNull Block block, @NotNull ChunkLoadCallback cb) { ++ this.getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, cb); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link java.util.function.Consumer} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param x Chunk X-coordinate of the chunk - floor(world coordinate / 16) ++ * @param z Chunk Z-coordinate of the chunk - floor(world coordinate / 16) ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ default void getChunkAtAsync(final int x, final int z, final @NotNull Consumer cb) { ++ this.getChunkAtAsync(x, z, true, cb); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link java.util.function.Consumer} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param x Chunk X-coordinate of the chunk - floor(world coordinate / 16) ++ * @param z Chunk Z-coordinate of the chunk - floor(world coordinate / 16) ++ * @param gen Should we generate a chunk if it doesn't exist or not ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ default void getChunkAtAsync(final int x, final int z, final boolean gen, final @NotNull Consumer cb) { ++ this.getChunkAtAsync(x, z, gen, false, cb); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link java.util.function.Consumer} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param x Chunk X-coordinate of the chunk - floor(world coordinate / 16) ++ * @param z Chunk Z-coordinate of the chunk - floor(world coordinate / 16) ++ * @param gen Should we generate a chunk if it doesn't exist or not ++ * @param urgent If true, the chunk may be prioritised to be loaded above other chunks in queue ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ void getChunkAtAsync(final int x, final int z, final boolean gen, final boolean urgent, final @NotNull Consumer cb); ++ ++ /** ++ * Requests all chunks with x between [minX, maxZ] and z ++ * between [minZ, maxZ] to be loaded. ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will invoke the callback at possibly a later time. ++ * ++ * You should use this method if you need chunks loaded but do not need them ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link Runnable} will always be executed synchronously ++ * on the main Server Thread, and when invoked all chunks requested will be loaded. ++ * ++ * @param minX Minimum chunk X-coordinate of the chunk - floor(world coordinate / 16) ++ * @param minZ Minimum chunk Z-coordinate of the chunk - floor(world coordinate / 16) ++ * @param maxX Maximum chunk X-coordinate of the chunk - floor(world coordinate / 16) ++ * @param maxZ Maximum chunk Z-coordinate of the chunk - floor(world coordinate / 16) ++ * @param urgent If true, the chunks may be prioritised to be loaded above other chunks in queue ++ * @param cb Callback to invoke when all chunks are loaded. ++ * Will be executed synchronously ++ * @see Chunk ++ */ ++ void getChunksAtAsync(final int minX, final int minZ, final int maxX, final int maxZ, final boolean urgent, ++ final @NotNull Runnable cb); ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given {@link Location} ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link java.util.function.Consumer} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param loc Location of the chunk ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ default void getChunkAtAsync(final @NotNull Location loc, final @NotNull Consumer cb) { ++ this.getChunkAtAsync((int) Math.floor(loc.getX()) >> 4, (int) Math.floor(loc.getZ()) >> 4, true, cb); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given {@link Location} ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link java.util.function.Consumer} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param loc Location of the chunk ++ * @param gen Should the chunk generate if it doesn't exist ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ default void getChunkAtAsync(final @NotNull Location loc, final boolean gen, final @NotNull Consumer cb) { ++ this.getChunkAtAsync((int) Math.floor(loc.getX()) >> 4, (int) Math.floor(loc.getZ()) >> 4, gen, cb); ++ } ++ ++ /** ++ * Requests {@link Chunk} to be loaded that contains the given {@link Block} ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link java.util.function.Consumer} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param block Block to get the containing chunk from ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ default void getChunkAtAsync(final @NotNull Block block, final @NotNull Consumer cb) { ++ this.getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, true, cb); ++ } ++ ++ /** ++ * Requests {@link Chunk} to be loaded that contains the given {@link Block} ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The {@link java.util.function.Consumer} will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param block Block to get the containing chunk from ++ * @param gen Should the chunk generate if it doesn't exist ++ * @param cb Callback to receive the chunk when it is loaded. ++ * will be executed synchronously ++ */ ++ default void getChunkAtAsync(final @NotNull Block block, final boolean gen, final @NotNull Consumer cb) { ++ this.getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, gen, cb); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param loc Location to load the corresponding chunk from ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsync(final @NotNull Location loc) { ++ return this.getChunkAtAsync((int) Math.floor(loc.getX()) >> 4, (int) Math.floor(loc.getZ()) >> 4, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param loc Location to load the corresponding chunk from ++ * @param gen Should the chunk generate if it doesn't exist ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsync(final @NotNull Location loc, final boolean gen) { ++ return this.getChunkAtAsync((int) Math.floor(loc.getX()) >> 4, (int) Math.floor(loc.getZ()) >> 4, gen); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param block Block to load the corresponding chunk from ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsync(final @NotNull Block block) { ++ return this.getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param block Block to load the corresponding chunk from ++ * @param gen Should the chunk generate if it doesn't exist ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsync(final @NotNull Block block, final boolean gen) { ++ return this.getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, gen); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param x Chunk X-coordinate of the chunk - floor(world coordinate / 16) ++ * @param z Chunk Z-coordinate of the chunk - floor(world coordinate / 16) ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsync(final int x, final int z) { ++ return this.getChunkAtAsync(x, z, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param x Chunk X-coordinate of the chunk - floor(world coordinate / 16) ++ * @param z Chunk Z-coordinate of the chunk - floor(world coordinate / 16) ++ * @param gen Should we generate a chunk if it doesn't exist or not ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsync(final int x, final int z, final boolean gen) { ++ return this.getChunkAtAsync(x, z, gen, false); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param loc Location to load the corresponding chunk from ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(final @NotNull Location loc) { ++ return this.getChunkAtAsync((int) Math.floor(loc.getX()) >> 4, (int) Math.floor(loc.getZ()) >> 4, true, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param loc Location to load the corresponding chunk from ++ * @param gen Should the chunk generate if it doesn't exist ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(final @NotNull Location loc, final boolean gen) { ++ return this.getChunkAtAsync((int) Math.floor(loc.getX()) >> 4, (int) Math.floor(loc.getZ()) >> 4, gen, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param block Block to load the corresponding chunk from ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(final @NotNull Block block) { ++ return this.getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, true, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param block Block to load the corresponding chunk from ++ * @param gen Should the chunk generate if it doesn't exist ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(final @NotNull Block block, final boolean gen) { ++ return this.getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, gen, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param x X Coord ++ * @param z Z Coord ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(final int x, final int z) { ++ return this.getChunkAtAsync(x, z, true, true); ++ } ++ ++ default @NotNull java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent) { ++ java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); ++ this.getChunkAtAsync(x, z, gen, urgent, ret::complete); ++ return ret; ++ } ++ // Paper end - async chunks API ++ + /** + * Get a list of all players in this World + * +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 45f06224d476551267e9b083985051ae9954d756..b808044403e6b38d1801aefde2176d630c747a64 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -168,6 +168,39 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + public boolean teleport(@NotNull Entity destination, @NotNull TeleportCause cause); + ++ // Paper start ++ /** ++ * Loads/Generates(in 1.13+) the Chunk asynchronously, and then teleports the entity when the chunk is ready. ++ * @param loc Location to teleport to ++ * @return A future that will be completed with the result of the teleport ++ */ ++ default java.util.concurrent.@NotNull CompletableFuture teleportAsync(final @NotNull Location loc) { ++ return this.teleportAsync(loc, TeleportCause.PLUGIN); ++ } ++ ++ /** ++ * Loads/Generates(in 1.13+) the Chunk asynchronously, and then teleports the entity when the chunk is ready. ++ * @param loc Location to teleport to ++ * @param cause Reason for teleport ++ * @return A future that will be completed with the result of the teleport ++ */ ++ default java.util.concurrent.@NotNull CompletableFuture teleportAsync(final @NotNull Location loc, final @NotNull TeleportCause cause) { ++ final class Holder { ++ static final io.papermc.paper.entity.TeleportFlag[] EMPTY_FLAGS = new io.papermc.paper.entity.TeleportFlag[0]; ++ } ++ return this.teleportAsync(loc, cause, Holder.EMPTY_FLAGS); ++ } ++ ++ /** ++ * Loads/Generates(in 1.13+) the Chunk asynchronously, and then teleports the entity when the chunk is ready. ++ * @param loc Location to teleport to ++ * @param cause Reason for teleport ++ * @param teleportFlags Flags to be used in this teleportation ++ * @return A future that will be completed with the result of the teleport ++ */ ++ java.util.concurrent.@NotNull CompletableFuture teleportAsync(@NotNull Location loc, @NotNull TeleportCause cause, @NotNull io.papermc.paper.entity.TeleportFlag @NotNull... teleportFlags); ++ // Paper end ++ + /** + * Returns a list of entities within a bounding box centered around this + * entity diff --git a/patches/api/0140-Add-ray-tracing-methods-to-LivingEntity.patch b/patches/api/0140-Add-ray-tracing-methods-to-LivingEntity.patch new file mode 100644 index 000000000000..87ba02db1756 --- /dev/null +++ b/patches/api/0140-Add-ray-tracing-methods-to-LivingEntity.patch @@ -0,0 +1,182 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 3 Sep 2018 18:13:53 -0500 +Subject: [PATCH] Add ray tracing methods to LivingEntity + + +diff --git a/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java b/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bb12061985cdffbacfa2d113beaa35b2c92df567 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java +@@ -0,0 +1,67 @@ ++package com.destroystokyo.paper.block; ++ ++import org.bukkit.FluidCollisionMode; ++import org.bukkit.block.Block; ++import org.bukkit.block.BlockFace; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents information about a targeted block ++ * @deprecated use {@link org.bukkit.util.RayTraceResult} ++ */ ++@Deprecated(forRemoval = true, since = "1.19.3") ++public class TargetBlockInfo { ++ private final Block block; ++ private final BlockFace blockFace; ++ ++ public TargetBlockInfo(@NotNull Block block, @NotNull BlockFace blockFace) { ++ this.block = block; ++ this.blockFace = blockFace; ++ } ++ ++ /** ++ * Get the block that is targeted ++ * ++ * @return Targeted block ++ */ ++ @NotNull ++ public Block getBlock() { ++ return block; ++ } ++ ++ /** ++ * Get the targeted BlockFace ++ * ++ * @return Targeted blockface ++ */ ++ @NotNull ++ public BlockFace getBlockFace() { ++ return blockFace; ++ } ++ ++ /** ++ * Get the relative Block to the targeted block on the side it is targeted at ++ * ++ * @return Block relative to targeted block ++ */ ++ @NotNull ++ public Block getRelativeBlock() { ++ return block.getRelative(blockFace); ++ } ++ ++ /** ++ * @deprecated use {@link org.bukkit.FluidCollisionMode} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.3") ++ public enum FluidMode { ++ NEVER(FluidCollisionMode.NEVER), ++ SOURCE_ONLY(FluidCollisionMode.SOURCE_ONLY), ++ ALWAYS(FluidCollisionMode.ALWAYS); ++ ++ public final FluidCollisionMode bukkit; ++ ++ FluidMode(FluidCollisionMode bukkit) { ++ this.bukkit = bukkit; ++ } ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index f8eb5527b4e0520712f4d8c329ba9d5dc4a4d206..9ffa42e3d241dd209813cea993c8fcda72f1a935 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -85,6 +85,98 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + @NotNull + public Block getTargetBlock(@Nullable Set transparent, int maxDistance); + ++ // Paper start ++ /** ++ * Gets the block that the living entity has targeted, ignoring fluids ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @return block that the living entity has targeted, ++ * or null if no block is within maxDistance ++ * @deprecated use {@link #getTargetBlockExact(int)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.3") ++ @Nullable ++ public default Block getTargetBlock(int maxDistance) { ++ return getTargetBlock(maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode.NEVER); ++ } ++ ++ /** ++ * Gets the block that the living entity has targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @param fluidMode whether to check fluids or not ++ * @return block that the living entity has targeted, ++ * or null if no block is within maxDistance ++ * @deprecated use {@link #getTargetBlockExact(int, FluidCollisionMode)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.3") ++ @Nullable ++ public Block getTargetBlock(int maxDistance, @NotNull com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode); ++ ++ /** ++ * Gets the blockface of that block that the living entity has targeted, ignoring fluids ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @return blockface of the block that the living entity has targeted, ++ * or null if no block is targeted ++ */ ++ @Nullable ++ public default org.bukkit.block.BlockFace getTargetBlockFace(int maxDistance) { ++ return getTargetBlockFace(maxDistance, org.bukkit.FluidCollisionMode.NEVER); ++ } ++ ++ /** ++ * Gets the blockface of that block that the living entity has targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @param fluidMode whether to check fluids or not ++ * @return blockface of the block that the living entity has targeted, ++ * or null if no block is targeted ++ * @deprecated use {@link #getTargetBlockFace(int, FluidCollisionMode)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.3") ++ @Nullable ++ public org.bukkit.block.BlockFace getTargetBlockFace(int maxDistance, @NotNull com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode); ++ ++ /** ++ * Gets the blockface of that block that the living entity has targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @param fluidMode whether to check fluids or not ++ * @return blockface of the block that the living entity has targeted, ++ * or null if no block is targeted ++ */ ++ @Nullable ++ public org.bukkit.block.BlockFace getTargetBlockFace(int maxDistance, @NotNull FluidCollisionMode fluidMode); ++ ++ /** ++ * Gets information about the block the living entity has targeted, ignoring fluids ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @return TargetBlockInfo about the block the living entity has targeted, ++ * or null if no block is targeted ++ * @deprecated use {@link #rayTraceBlocks(double)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.3") ++ @Nullable ++ public default com.destroystokyo.paper.block.TargetBlockInfo getTargetBlockInfo(int maxDistance) { ++ return getTargetBlockInfo(maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode.NEVER); ++ } ++ ++ /** ++ * Gets information about the block the living entity has targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @param fluidMode whether to check fluids or not ++ * @return TargetBlockInfo about the block the living entity has targeted, ++ * or null if no block is targeted ++ * @deprecated use {@link #rayTraceBlocks(double, FluidCollisionMode)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.3") ++ @Nullable ++ public com.destroystokyo.paper.block.TargetBlockInfo getTargetBlockInfo(int maxDistance, @NotNull com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode); ++ // Paper end ++ + /** + * Gets the last two blocks along the living entity's line of sight. + *

      diff --git a/patches/api/0140-Slime-Pathfinder-Events.patch b/patches/api/0140-Slime-Pathfinder-Events.patch deleted file mode 100644 index 953bdc27eb81..000000000000 --- a/patches/api/0140-Slime-Pathfinder-Events.patch +++ /dev/null @@ -1,217 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 24 Aug 2018 08:18:27 -0500 -Subject: [PATCH] Slime Pathfinder Events - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2638bbd3e1392b3d8640be58163f6eb2789dee4a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeChangeDirectionEvent.java -@@ -0,0 +1,38 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Slime; -+import org.bukkit.event.Cancellable; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a Slime decides to change it's facing direction. -+ *

      -+ * This event does not fire for the entity's actual movement. Only when it -+ * is choosing to change direction. -+ */ -+public class SlimeChangeDirectionEvent extends SlimePathfindEvent implements Cancellable { -+ private float yaw; -+ -+ public SlimeChangeDirectionEvent(@NotNull Slime slime, float yaw) { -+ super(slime); -+ this.yaw = yaw; -+ } -+ -+ /** -+ * Get the new chosen yaw -+ * -+ * @return Chosen yaw -+ */ -+ public float getNewYaw() { -+ return yaw; -+ } -+ -+ /** -+ * Set the new chosen yaw -+ * -+ * @param yaw Chosen yaw -+ */ -+ public void setNewYaw(float yaw) { -+ this.yaw = yaw; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..14b67da109321ae6521eab2ac6f6945f05d02db5 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimePathfindEvent.java -@@ -0,0 +1,53 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Slime; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a Slime decides to start pathfinding. -+ *

      -+ * This event does not fire for the entity's actual movement. Only when it -+ * is choosing to start moving. -+ */ -+public class SlimePathfindEvent extends EntityEvent implements Cancellable { -+ public SlimePathfindEvent(@NotNull Slime slime) { -+ super(slime); -+ } -+ -+ /** -+ * The Slime that is pathfinding. -+ * -+ * @return The Slime that is pathfinding. -+ */ -+ @NotNull -+ public Slime getEntity() { -+ return (Slime) entity; -+ } -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ private boolean cancelled = false; -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c8dd49d11da5a90a1bac965a75f2b65fd825f3f7 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeSwimEvent.java -@@ -0,0 +1,17 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Slime; -+import org.bukkit.event.Cancellable; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a Slime decides to start jumping while swimming in water/lava. -+ *

      -+ * This event does not fire for the entity's actual movement. Only when it -+ * is choosing to start jumping. -+ */ -+public class SlimeSwimEvent extends SlimeWanderEvent implements Cancellable { -+ public SlimeSwimEvent(@NotNull Slime slime) { -+ super(slime); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e9ba32799ed838779e49cd4c5011b7515b3363cb ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeTargetLivingEntityEvent.java -@@ -0,0 +1,31 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.entity.Slime; -+import org.bukkit.event.Cancellable; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a Slime decides to change direction to target a LivingEntity. -+ *

      -+ * This event does not fire for the entity's actual movement. Only when it -+ * is choosing to start moving. -+ */ -+public class SlimeTargetLivingEntityEvent extends SlimePathfindEvent implements Cancellable { -+ @NotNull private final LivingEntity target; -+ -+ public SlimeTargetLivingEntityEvent(@NotNull Slime slime, @NotNull LivingEntity target) { -+ super(slime); -+ this.target = target; -+ } -+ -+ /** -+ * Get the targeted entity -+ * -+ * @return Targeted entity -+ */ -+ @NotNull -+ public LivingEntity getTarget() { -+ return target; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4683a7237d2ed527fc85b9b4e5b2eaaf5ae3d797 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/SlimeWanderEvent.java -@@ -0,0 +1,17 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Slime; -+import org.bukkit.event.Cancellable; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a Slime decides to start wandering. -+ *

      -+ * This event does not fire for the entity's actual movement. Only when it -+ * is choosing to start moving. -+ */ -+public class SlimeWanderEvent extends SlimePathfindEvent implements Cancellable { -+ public SlimeWanderEvent(@NotNull Slime slime) { -+ super(slime); -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/Slime.java b/src/main/java/org/bukkit/entity/Slime.java -index 4631647c64c89ffdde2d9b63bdab974acfe6cb3d..1308dc4ab5779a5cfd9a4e22c43501fc9ceaa7af 100644 ---- a/src/main/java/org/bukkit/entity/Slime.java -+++ b/src/main/java/org/bukkit/entity/Slime.java -@@ -24,4 +24,20 @@ public interface Slime extends Mob { - * @param sz The new size of the slime. - */ - public void setSize(int sz); -+ -+ // Paper start -+ /** -+ * Get whether this slime can randomly wander/jump around on its own -+ * -+ * @return true if can wander -+ */ -+ public boolean canWander(); -+ -+ /** -+ * Set whether this slime can randomly wander/jump around on its own -+ * -+ * @param canWander true if can wander -+ */ -+ public void setWander(boolean canWander); -+ // Paper end - } diff --git a/patches/api/0141-Add-PhantomPreSpawnEvent.patch b/patches/api/0141-Add-PhantomPreSpawnEvent.patch deleted file mode 100644 index 5ffdc818cbcc..000000000000 --- a/patches/api/0141-Add-PhantomPreSpawnEvent.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 25 Aug 2018 19:56:42 -0500 -Subject: [PATCH] Add PhantomPreSpawnEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9022f697ab244df43074e48c9150f39d44217531 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/PhantomPreSpawnEvent.java -@@ -0,0 +1,31 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.EntityType; -+import org.bukkit.event.entity.CreatureSpawnEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+ -+/** -+ * Called when a phantom is spawned for an exhausted player -+ */ -+public class PhantomPreSpawnEvent extends PreCreatureSpawnEvent { -+ @NotNull private final Entity entity; -+ -+ public PhantomPreSpawnEvent(@NotNull Location location, @NotNull Entity entity, @NotNull CreatureSpawnEvent.SpawnReason reason) { -+ super(location, EntityType.PHANTOM, reason); -+ this.entity = entity; -+ } -+ -+ /** -+ * Get the entity this phantom is spawning for -+ * -+ * @return Entity -+ */ -+ @Nullable -+ public Entity getSpawningEntity() { -+ return entity; -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/Phantom.java b/src/main/java/org/bukkit/entity/Phantom.java -index 1a1044edc57078f96c4a95c994d0865da382c152..ed4d417c2deefb78807cb61b01df5afcd334d754 100644 ---- a/src/main/java/org/bukkit/entity/Phantom.java -+++ b/src/main/java/org/bukkit/entity/Phantom.java -@@ -1,5 +1,8 @@ - package org.bukkit.entity; - -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ - /** - * Represents a phantom. - */ -@@ -14,4 +17,14 @@ public interface Phantom extends Flying { - * @param sz The new size of the phantom. - */ - public void setSize(int sz); -+ -+ // Paper start -+ /** -+ * Get the UUID of the entity that caused this phantom to spawn -+ * -+ * @return UUID -+ */ -+ @Nullable -+ public java.util.UUID getSpawningEntity(); -+ // Paper end - } diff --git a/patches/api/0141-Expose-attack-cooldown-methods-for-Player.patch b/patches/api/0141-Expose-attack-cooldown-methods-for-Player.patch new file mode 100644 index 000000000000..3087b9684439 --- /dev/null +++ b/patches/api/0141-Expose-attack-cooldown-methods-for-Player.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 4 Sep 2018 15:01:54 -0500 +Subject: [PATCH] Expose attack cooldown methods for Player + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index c65a1204c948df81664357524d9d1e6abafb7776..f84c55b9a93aae762ed28cc536eccbd7a503177a 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3356,6 +3356,28 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + void setPlayerProfile(com.destroystokyo.paper.profile.@NotNull PlayerProfile profile); + // Paper end - Player Profile API + ++ // Paper start - attack cooldown API ++ /** ++ * Returns the amount of ticks the current cooldown lasts ++ * ++ * @return Amount of ticks cooldown will last ++ */ ++ float getCooldownPeriod(); ++ ++ /** ++ * Returns the percentage of attack power available based on the cooldown (zero to one). ++ * ++ * @param adjustTicks Amount of ticks to add to cooldown counter for this calculation ++ * @return Percentage of attack power available ++ */ ++ float getCooledAttackStrength(float adjustTicks); ++ ++ /** ++ * Reset the cooldown counter to 0, effectively starting the cooldown period. ++ */ ++ void resetCooldown(); ++ // Paper end - attack cooldown API ++ + // Spigot start + public class Spigot extends Entity.Spigot { + diff --git a/patches/api/0142-Add-More-Creeper-API.patch b/patches/api/0142-Add-More-Creeper-API.patch deleted file mode 100644 index b45e2fbeba53..000000000000 --- a/patches/api/0142-Add-More-Creeper-API.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 24 Aug 2018 11:50:16 -0500 -Subject: [PATCH] Add More Creeper API - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ff10251b6ded533b08048ec533525176eff03707 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/CreeperIgniteEvent.java -@@ -0,0 +1,54 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Creeper; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a Creeper is ignite flag is changed (armed/disarmed to explode). -+ */ -+public class CreeperIgniteEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean canceled; -+ private boolean ignited; -+ -+ public CreeperIgniteEvent(@NotNull Creeper creeper, boolean ignited) { -+ super(creeper); -+ this.ignited = ignited; -+ } -+ -+ @NotNull -+ @Override -+ public Creeper getEntity() { -+ return (Creeper) entity; -+ } -+ -+ public boolean isIgnited() { -+ return ignited; -+ } -+ -+ public void setIgnited(boolean ignited) { -+ this.ignited = ignited; -+ } -+ -+ public boolean isCancelled() { -+ return canceled; -+ } -+ -+ public void setCancelled(boolean cancel) { -+ canceled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/Creeper.java b/src/main/java/org/bukkit/entity/Creeper.java -index 5793193d93d76a062fd0431475c269c4978ec993..e144f618702122bf28ebedc5cb8ce0f6ef27c107 100644 ---- a/src/main/java/org/bukkit/entity/Creeper.java -+++ b/src/main/java/org/bukkit/entity/Creeper.java -@@ -87,4 +87,20 @@ public interface Creeper extends Monster { - * griefing gamerule. - */ - public void ignite(); -+ // Paper start -+ -+ /** -+ * Set whether creeper is ignited or not (armed to explode) -+ * -+ * @param ignited New ignited state -+ */ -+ public void setIgnited(boolean ignited); -+ -+ /** -+ * Check if creeper is ignited or not (armed to explode) -+ * -+ * @return Ignited state -+ */ -+ public boolean isIgnited(); -+ // Paper end - } diff --git a/patches/api/0142-Improve-death-events.patch b/patches/api/0142-Improve-death-events.patch new file mode 100644 index 000000000000..1ddc0abdba43 --- /dev/null +++ b/patches/api/0142-Improve-death-events.patch @@ -0,0 +1,205 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 +Date: Tue, 21 Aug 2018 01:32:28 +0100 +Subject: [PATCH] Improve death events + +This adds the ability to cancel the death events and to modify the sound +an entity makes when dying. (In cases were no sound should it will be +called with shouldPlaySound set to false allowing unsilencing of silent +entities) + +It makes handling of entity deaths a lot nicer as you no longer need +to listen on the damage event and calculate if the entity dies yourself +to cancel the death which has the benefit of also receiving the dropped +items and experience which is otherwise only properly possible by using +internal code. + +diff --git a/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java +index b0c069f65da29c6e9eff8e0490fda43a6bed307c..086bec9daa89315b1d4719ab74de0e889f93e340 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java +@@ -6,15 +6,25 @@ import org.bukkit.entity.LivingEntity; + import org.bukkit.event.HandlerList; + import org.bukkit.inventory.ItemStack; + import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; + + /** + * Thrown whenever a LivingEntity dies + */ +-public class EntityDeathEvent extends EntityEvent { ++public class EntityDeathEvent extends EntityEvent implements org.bukkit.event.Cancellable { // Paper - make cancellable + private static final HandlerList handlers = new HandlerList(); + private final DamageSource damageSource; + private final List drops; + private int dropExp = 0; ++ // Paper start - make cancellable ++ private boolean cancelled; ++ private double reviveHealth = 0; ++ private boolean shouldPlayDeathSound; ++ @Nullable private org.bukkit.Sound deathSound; ++ @Nullable private org.bukkit.SoundCategory deathSoundCategory; ++ private float deathSoundVolume; ++ private float deathSoundPitch; ++ // Paper end + + public EntityDeathEvent(@NotNull final LivingEntity entity, @NotNull DamageSource damageSource, @NotNull final List drops) { + this(entity, damageSource, drops, 0); +@@ -87,4 +97,133 @@ public class EntityDeathEvent extends EntityEvent { + public static HandlerList getHandlerList() { + return handlers; + } ++ ++ // Paper start - make cancellable ++ @Override ++ public boolean isCancelled() { ++ return cancelled; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ cancelled = cancel; ++ } ++ ++ /** ++ * Get the amount of health that the entity should revive with after cancelling the event. ++ * Set to the entity's max health by default. ++ * ++ * @return The amount of health ++ */ ++ public double getReviveHealth() { ++ return reviveHealth; ++ } ++ ++ /** ++ * Set the amount of health that the entity should revive with after cancelling the event. ++ * Revive health value must be between 0 (exclusive) and the entity's max health (inclusive). ++ * ++ * @param reviveHealth The amount of health ++ * @throws IllegalArgumentException Thrown if the health is {@literal <= 0 or >} max health ++ */ ++ public void setReviveHealth(double reviveHealth) throws IllegalArgumentException { ++ double maxHealth = ((LivingEntity) entity).getAttribute(org.bukkit.attribute.Attribute.MAX_HEALTH).getValue(); ++ if ((maxHealth != 0 && reviveHealth <= 0) || (reviveHealth > maxHealth)) { ++ throw new IllegalArgumentException("Health must be between 0 (exclusive) and " + maxHealth + " (inclusive), but was " + reviveHealth); ++ } ++ this.reviveHealth = reviveHealth; ++ } ++ ++ /** ++ * Whether or not the death sound should play when the entity dies. If the event is cancelled it does not play! ++ * ++ * @return Whether or not the death sound should play. Event is called with this set to false if the entity is silent. ++ */ ++ public boolean shouldPlayDeathSound() { ++ return shouldPlayDeathSound; ++ } ++ ++ /** ++ * Set whether or not the death sound should play when the entity dies. If the event is cancelled it does not play! ++ * ++ * @param playDeathSound Enable or disable the death sound ++ */ ++ public void setShouldPlayDeathSound(boolean playDeathSound) { ++ this.shouldPlayDeathSound = playDeathSound; ++ } ++ ++ /** ++ * Get the sound that the entity makes when dying ++ * ++ * @return The sound that the entity makes ++ */ ++ @Nullable ++ public org.bukkit.Sound getDeathSound() { ++ return deathSound; ++ } ++ ++ /** ++ * Set the sound that the entity makes when dying ++ * ++ * @param sound The sound that the entity should make when dying ++ */ ++ public void setDeathSound(@Nullable org.bukkit.Sound sound) { ++ deathSound = sound; ++ } ++ ++ /** ++ * Get the sound category that the death sound should play in ++ * ++ * @return The sound category ++ */ ++ @Nullable ++ public org.bukkit.SoundCategory getDeathSoundCategory() { ++ return deathSoundCategory; ++ } ++ ++ /** ++ * Set the sound category that the death sound should play in. ++ * ++ * @param soundCategory The sound category ++ */ ++ public void setDeathSoundCategory(@Nullable org.bukkit.SoundCategory soundCategory) { ++ this.deathSoundCategory = soundCategory; ++ } ++ ++ /** ++ * Get the volume that the death sound will play at. ++ * ++ * @return The volume the death sound will play at ++ */ ++ public float getDeathSoundVolume() { ++ return deathSoundVolume; ++ } ++ ++ /** ++ * Set the volume the death sound should play at. If the event is cancelled this will not play the sound! ++ * ++ * @param volume The volume the death sound should play at ++ */ ++ public void setDeathSoundVolume(float volume) { ++ this.deathSoundVolume = volume; ++ } ++ ++ /** ++ * Get the pitch that the death sound will play with. ++ * ++ * @return The pitch the death sound will play with ++ */ ++ public float getDeathSoundPitch() { ++ return deathSoundPitch; ++ } ++ ++ /** ++ * Set the pitch that the death sound should play with. ++ * ++ * @param pitch The pitch the death sound should play with ++ */ ++ public void setDeathSoundPitch(float pitch) { ++ this.deathSoundPitch = pitch; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +index 9473303bd8ab1f6b63b6999a5f5ff3eca1cc23d6..76f00e386110f361549690d20dc0f73884a2fdda 100644 +--- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java ++++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +@@ -63,6 +63,19 @@ public class PlayerDeathEvent extends EntityDeathEvent { + return (Player) entity; + } + ++ // Paper start - improve death events ++ /** ++ * Clarity method for getting the player. Not really needed except ++ * for reasons of clarity. ++ * ++ * @return Player who is involved in this event ++ */ ++ public @NotNull Player getPlayer() { ++ return this.getEntity(); ++ } ++ ++ // Paper end - improve death events ++ + // Paper start - adventure + /** + * Set the death message that will appear to everyone on the server. diff --git a/patches/api/0143-Inventory-removeItemAnySlot.patch b/patches/api/0143-Inventory-removeItemAnySlot.patch deleted file mode 100644 index 4d6f2e9e5744..000000000000 --- a/patches/api/0143-Inventory-removeItemAnySlot.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Tue, 28 Aug 2018 23:04:06 -0400 -Subject: [PATCH] Inventory#removeItemAnySlot - - -diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/org/bukkit/inventory/Inventory.java -index 5576a6a8df8c95164bf2dde45d756ce8b7ec957a..9c6a5bdac8c3ab682bbfae04ff24b76a62bc2883 100644 ---- a/src/main/java/org/bukkit/inventory/Inventory.java -+++ b/src/main/java/org/bukkit/inventory/Inventory.java -@@ -125,6 +125,34 @@ public interface Inventory extends Iterable { - @NotNull - public HashMap removeItem(@NotNull ItemStack... items) throws IllegalArgumentException; - -+ // Paper start -+ /** -+ * Searches all possible inventory slots in order to remove the given ItemStacks. -+ *

      -+ * Similar to {@link Inventory#removeItem(ItemStack...)} in behavior, except this -+ * method will check all possible slots in the inventory, rather than just the main -+ * storage contents. -+ *

      -+ * It will try to remove 'as much as possible' from the types and amounts -+ * you give as arguments. -+ *

      -+ * The returned HashMap contains what it couldn't remove, where the key is -+ * the index of the parameter, and the value is the ItemStack at that -+ * index of the varargs parameter. If all the given ItemStacks are -+ * removed, it will return an empty HashMap. -+ *

      -+ * It is known that in some implementations this method will also set the -+ * inputted argument amount to the number of that item not removed from -+ * slots. -+ * -+ * @param items The ItemStacks to remove -+ * @return A HashMap containing items that couldn't be removed. -+ * @throws IllegalArgumentException if items is null -+ */ -+ @NotNull -+ public HashMap removeItemAnySlot(@NotNull ItemStack... items) throws IllegalArgumentException; -+ // Paper end -+ - /** - * Returns all ItemStacks from the inventory - * diff --git a/patches/api/0143-Mob-Pathfinding-API.patch b/patches/api/0143-Mob-Pathfinding-API.patch new file mode 100644 index 000000000000..63c4c6770a20 --- /dev/null +++ b/patches/api/0143-Mob-Pathfinding-API.patch @@ -0,0 +1,266 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 9 Sep 2018 12:39:06 -0400 +Subject: [PATCH] Mob Pathfinding API + +Adds an API to allow plugins to instruct a Mob to Pathfind to a Location or Entity + +This does not do anything to stop other AI rules from changing the location, so +it is still up to the plugin to control that or override after another goal changed +the location. + +You can use EntityPathfindEvent to cancel new pathfinds from overriding your current. + +diff --git a/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java b/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5f6d6e222f9f1ac1648a11b6d4a240371c4f07e9 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java +@@ -0,0 +1,221 @@ ++package com.destroystokyo.paper.entity; ++ ++import java.util.List; ++import org.bukkit.Location; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.entity.Mob; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Handles pathfinding operations for an Entity ++ */ ++@NullMarked ++public interface Pathfinder { ++ ++ /** ++ * @return The entity that is controlled by this pathfinder ++ */ ++ Mob getEntity(); ++ ++ /** ++ * Instructs the Entity to stop trying to navigate to its current desired location ++ */ ++ void stopPathfinding(); ++ ++ /** ++ * If the entity is currently trying to navigate to a destination, this will return true ++ * ++ * @return true if the entity is navigating to a destination ++ */ ++ boolean hasPath(); ++ ++ /** ++ * @return The location the entity is trying to navigate to, or null if there is no destination ++ */ ++ @Nullable PathResult getCurrentPath(); ++ ++ /** ++ * Calculates a destination for the Entity to navigate to, but does not set it ++ * as the current target. Useful for calculating what would happen before setting it. ++ * ++ * @param loc Location to navigate to ++ * @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated ++ */ ++ @Nullable PathResult findPath(Location loc); ++ ++ /** ++ * Calculates a destination for the Entity to navigate to to reach the target entity, ++ * but does not set it as the current target. ++ * Useful for calculating what would happen before setting it. ++ *

      ++ * The behavior of this PathResult is subject to the games pathfinding rules, and may ++ * result in the pathfinding automatically updating to follow the target Entity. ++ *

      ++ * However, this behavior is not guaranteed, and is subject to the games behavior. ++ * ++ * @param target the Entity to navigate to ++ * @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated ++ */ ++ @Nullable PathResult findPath(LivingEntity target); ++ ++ /** ++ * Calculates a destination for the Entity to navigate to, and sets it with default speed ++ * as the current target. ++ * ++ * @param loc Location to navigate to ++ * @return If the pathfinding was successfully started ++ */ ++ default boolean moveTo(Location loc) { ++ return this.moveTo(loc, 1); ++ } ++ ++ /** ++ * Calculates a destination for the Entity to navigate to, with desired speed ++ * as the current target. ++ * ++ * @param loc Location to navigate to ++ * @param speed Speed multiplier to navigate at, where 1 is 'normal' ++ * @return If the pathfinding was successfully started ++ */ ++ default boolean moveTo(Location loc, double speed) { ++ PathResult path = this.findPath(loc); ++ return path != null && this.moveTo(path, speed); ++ } ++ ++ /** ++ * Calculates a destination for the Entity to navigate to to reach the target entity, ++ * and sets it with default speed. ++ *

      ++ * The behavior of this PathResult is subject to the games pathfinding rules, and may ++ * result in the pathfinding automatically updating to follow the target Entity. ++ *

      ++ * However, this behavior is not guaranteed, and is subject to the games behavior. ++ * ++ * @param target the Entity to navigate to ++ * @return If the pathfinding was successfully started ++ */ ++ default boolean moveTo(LivingEntity target) { ++ return this.moveTo(target, 1); ++ } ++ ++ /** ++ * Calculates a destination for the Entity to navigate to to reach the target entity, ++ * and sets it with specified speed. ++ *

      ++ * The behavior of this PathResult is subject to the games pathfinding rules, and may ++ * result in the pathfinding automatically updating to follow the target Entity. ++ *

      ++ * However, this behavior is not guaranteed, and is subject to the games behavior. ++ * ++ * @param target the Entity to navigate to ++ * @param speed Speed multiplier to navigate at, where 1 is 'normal' ++ * @return If the pathfinding was successfully started ++ */ ++ default boolean moveTo(LivingEntity target, double speed) { ++ PathResult path = this.findPath(target); ++ return path != null && this.moveTo(path, speed); ++ } ++ ++ /** ++ * Takes the result of a previous pathfinding calculation and sets it ++ * as the active pathfinding with default speed. ++ * ++ * @param path The Path to start following ++ * @return If the pathfinding was successfully started ++ */ ++ default boolean moveTo(PathResult path) { ++ return this.moveTo(path, 1); ++ } ++ ++ /** ++ * Takes the result of a previous pathfinding calculation and sets it ++ * as the active pathfinding, ++ * ++ * @param path The Path to start following ++ * @param speed Speed multiplier to navigate at, where 1 is 'normal' ++ * @return If the pathfinding was successfully started ++ */ ++ boolean moveTo(PathResult path, double speed); ++ ++ /** ++ * Checks if this pathfinder allows passing through closed doors. ++ * ++ * @return if this pathfinder allows passing through closed doors ++ */ ++ boolean canOpenDoors(); ++ ++ /** ++ * Allows this pathfinder to pass through closed doors, or not ++ * ++ * @param canOpenDoors if the mob can pass through closed doors, or not ++ */ ++ void setCanOpenDoors(boolean canOpenDoors); ++ ++ /** ++ * Checks if this pathfinder allows passing through open doors. ++ * ++ * @return if this pathfinder allows passing through open doors ++ */ ++ boolean canPassDoors(); ++ ++ /** ++ * Allows this pathfinder to pass through open doors, or not ++ * ++ * @param canPassDoors if the mob can pass through open doors, or not ++ */ ++ void setCanPassDoors(boolean canPassDoors); ++ ++ /** ++ * Checks if this pathfinder assumes that the mob can float ++ * ++ * @return if this pathfinder assumes that the mob can float ++ */ ++ boolean canFloat(); ++ ++ /** ++ * Makes this pathfinder assume that the mob can float, or not ++ * ++ * @param canFloat if the mob can float, or not ++ */ ++ void setCanFloat(boolean canFloat); ++ ++ /** ++ * Represents the result of a pathfinding calculation ++ */ ++ interface PathResult { ++ ++ /** ++ * All currently calculated points to follow along the path to reach the destination location ++ *

      ++ * Will return points the entity has already moved past, see {@link #getNextPointIndex()} ++ * ++ * @return List of points ++ */ ++ List getPoints(); ++ ++ /** ++ * @return Returns the index of the current point along the points returned in {@link #getPoints()} the entity ++ * is trying to reach. This value will be higher than the maximum index of {@link #getPoints()} if this path finding is done. ++ */ ++ int getNextPointIndex(); ++ ++ /** ++ * @return The next location in the path points the entity is trying to reach, or null if there is no next point ++ */ ++ @Nullable Location getNextPoint(); ++ ++ /** ++ * @return The closest point the path can get to the target location ++ */ ++ @Nullable Location getFinalPoint(); ++ ++ /** ++ * Checks whether the final point can be reached ++ * ++ * @return whether the final point can be reached ++ * @see #getFinalPoint() ++ */ ++ boolean canReachFinalPoint(); ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java +index ad5dbf310fe7b34c997bb339f09697222f862005..63a14bec00d0b23431d1d002139f48a7d0bc2a88 100644 +--- a/src/main/java/org/bukkit/entity/Mob.java ++++ b/src/main/java/org/bukkit/entity/Mob.java +@@ -2,6 +2,7 @@ package org.bukkit.entity; + + import org.bukkit.Sound; + import org.bukkit.loot.Lootable; ++import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + + /** +@@ -12,6 +13,13 @@ public interface Mob extends LivingEntity, Lootable { + // Paper start + @Override + org.bukkit.inventory.@org.jetbrains.annotations.NotNull EntityEquipment getEquipment(); ++ ++ /** ++ * Enables access to control the pathing of an Entity ++ * @return Pathfinding Manager for this entity ++ */ ++ @NotNull ++ com.destroystokyo.paper.entity.Pathfinder getPathfinder(); + // Paper end + /** + * Instructs this Mob to set the specified LivingEntity as its target. diff --git a/patches/api/0144-Performance-Concurrency-Improvements-to-Permissions.patch b/patches/api/0144-Performance-Concurrency-Improvements-to-Permissions.patch new file mode 100644 index 000000000000..503eb3cf507f --- /dev/null +++ b/patches/api/0144-Performance-Concurrency-Improvements-to-Permissions.patch @@ -0,0 +1,113 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 13 Sep 2018 20:51:50 -0400 +Subject: [PATCH] Performance & Concurrency Improvements to Permissions + +Modifying of permissions was only half protected, enabling concurrency +issues to occur if permissions were modified async. + +While no plugin really should be doing that, modifying operations +are not heavily called, so they are safe to add synchronization to. + +Now, all modification API's will be synchronized ensuring safety. + +Additionally, hasPermission was victim to a common java newbie mistake +of calling if (containsKey(k)) return get(k), resulting in 2 map lookups. + +Optimized it to simply be a single get call cutting permission map +lookups in half. + +diff --git a/src/main/java/org/bukkit/permissions/PermissibleBase.java b/src/main/java/org/bukkit/permissions/PermissibleBase.java +index d0fd41a0ddee550cf880bb212b15dfe79cb4e683..75b77cc4fe189b4b6baa1af3663dc492e992a266 100644 +--- a/src/main/java/org/bukkit/permissions/PermissibleBase.java ++++ b/src/main/java/org/bukkit/permissions/PermissibleBase.java +@@ -73,8 +73,11 @@ public class PermissibleBase implements Permissible { + + String name = inName.toLowerCase(Locale.ROOT); + +- if (isPermissionSet(name)) { +- return permissions.get(name).getValue(); ++ // Paper start ++ PermissionAttachmentInfo info = permissions.get(name); ++ if (info != null) { ++ return info.getValue(); ++ // Paper end + } else { + Permission perm = Bukkit.getServer().getPluginManager().getPermission(name); + +@@ -94,15 +97,18 @@ public class PermissibleBase implements Permissible { + + String name = perm.getName().toLowerCase(Locale.ROOT); + +- if (isPermissionSet(name)) { +- return permissions.get(name).getValue(); ++ // Paper start ++ PermissionAttachmentInfo info = permissions.get(name); ++ if (info != null) { ++ return info.getValue(); + } ++ // Paper end + return perm.getDefault().getValue(isOp()); + } + + @Override + @NotNull +- public PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value) { ++ public synchronized PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value) { // Paper - synchronized + if (name == null) { + throw new IllegalArgumentException("Permission name cannot be null"); + } else if (plugin == null) { +@@ -121,7 +127,7 @@ public class PermissibleBase implements Permissible { + + @Override + @NotNull +- public PermissionAttachment addAttachment(@NotNull Plugin plugin) { ++ public synchronized PermissionAttachment addAttachment(@NotNull Plugin plugin) { // Paper - synchronized + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } else if (!plugin.isEnabled()) { +@@ -137,7 +143,7 @@ public class PermissibleBase implements Permissible { + } + + @Override +- public void removeAttachment(@NotNull PermissionAttachment attachment) { ++ public synchronized void removeAttachment(@NotNull PermissionAttachment attachment) { // Paper - synchronized + if (attachment == null) { + throw new IllegalArgumentException("Attachment cannot be null"); + } +@@ -156,7 +162,7 @@ public class PermissibleBase implements Permissible { + } + + @Override +- public void recalculatePermissions() { ++ public synchronized void recalculatePermissions() { // Paper - synchronized + clearPermissions(); + Set defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(isOp()); + Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(isOp(), parent); +@@ -205,7 +211,7 @@ public class PermissibleBase implements Permissible { + + @Override + @Nullable +- public PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value, int ticks) { ++ public synchronized PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value, int ticks) { // Paper + if (name == null) { + throw new IllegalArgumentException("Permission name cannot be null"); + } else if (plugin == null) { +@@ -225,7 +231,7 @@ public class PermissibleBase implements Permissible { + + @Override + @Nullable +- public PermissionAttachment addAttachment(@NotNull Plugin plugin, int ticks) { ++ public synchronized PermissionAttachment addAttachment(@NotNull Plugin plugin, int ticks) { // Paper - synchronized + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } else if (!plugin.isEnabled()) { +@@ -245,7 +251,7 @@ public class PermissibleBase implements Permissible { + + @Override + @NotNull +- public Set getEffectivePermissions() { ++ public synchronized Set getEffectivePermissions() { // Paper - synchronized + return new HashSet(permissions.values()); + } + diff --git a/patches/api/0144-isChunkGenerated-API.patch b/patches/api/0144-isChunkGenerated-API.patch deleted file mode 100644 index 1899b4e2d279..000000000000 --- a/patches/api/0144-isChunkGenerated-API.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: cswhite2000 <18whitechristop@gmail.com> -Date: Tue, 21 Aug 2018 19:39:46 -0700 -Subject: [PATCH] isChunkGenerated API - - -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index 5c5e05673e0912f4dbd6c728f4c3b7fcdae8f0e8..57cb548683f7b2972c998afd34176952426f8b47 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -3,6 +3,7 @@ package org.bukkit; - import com.google.common.base.Preconditions; - import java.lang.ref.Reference; - import java.lang.ref.WeakReference; -+import com.google.common.base.Preconditions; // Paper - import java.util.HashMap; - import java.util.Map; - import org.bukkit.block.Block; -@@ -545,6 +546,16 @@ public class Location implements Cloneable, ConfigurationSerializable { - public boolean isChunkLoaded() { return this.getWorld().isChunkLoaded(locToBlock(x) >> 4, locToBlock(z) >> 4); } // Paper - - // Paper start -+ /** -+ * Checks if a {@link Chunk} has been generated at this location. -+ * -+ * @return true if a chunk has been generated at this location -+ */ -+ public boolean isGenerated() { -+ World world = this.getWorld(); -+ Preconditions.checkNotNull(world, "Location has no world!"); -+ return world.isChunkGenerated(locToBlock(x) >> 4, locToBlock(z) >> 4); -+ } - - /** - * Sets the position of this Location and returns itself -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 89e46828639b85da1f70f03bfd2a8e9c8487033f..324fca7bf480a463adb30842fa169052534f5252 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -260,6 +260,17 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - public default Chunk getChunkAt(long chunkKey) { - return getChunkAt((int) chunkKey, (int) (chunkKey >> 32)); - } -+ -+ /** -+ * Checks if a {@link Chunk} has been generated at the specified chunk key, -+ * which is the X and Z packed into a long. -+ * -+ * @param chunkKey The Chunk Key to look up the chunk by -+ * @return true if the chunk has been generated, otherwise false -+ */ -+ public default boolean isChunkGenerated(long chunkKey) { -+ return isChunkGenerated((int) chunkKey, (int) (chunkKey >> 32)); -+ } - // Paper end - - /** diff --git a/patches/api/0145-Add-source-block-constructor-and-getChangedBlockData.patch b/patches/api/0145-Add-source-block-constructor-and-getChangedBlockData.patch deleted file mode 100644 index 9f9e760855a8..000000000000 --- a/patches/api/0145-Add-source-block-constructor-and-getChangedBlockData.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Sotr -Date: Thu, 23 Aug 2018 16:14:25 +0800 -Subject: [PATCH] Add source block constructor and getChangedBlockData() to - BlockPhysicsEvent - - -diff --git a/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java b/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java -index e3a5f5824ed882058f5bac5003f66ce79733a868..1d496e5a3d1541bf0a257a4358b3943fd6415204 100644 ---- a/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java -+++ b/src/main/java/org/bukkit/event/block/BlockPhysicsEvent.java -@@ -32,6 +32,13 @@ public class BlockPhysicsEvent extends BlockEvent implements Cancellable { - private final Block sourceBlock; - private boolean cancel = false; - -+ // Paper start - Legacy constructor, use #BlockPhysicsEvent(Block, BlockData, Block) -+ @Deprecated -+ public BlockPhysicsEvent(final Block block, final BlockData changed, final int sourceX, final int sourceY, final int sourceZ) { -+ this(block, changed, block.getWorld().getBlockAt(sourceX, sourceY, sourceZ)); -+ } -+ // Paper end -+ - public BlockPhysicsEvent(@NotNull final Block block, @NotNull final BlockData changed) { - this(block, changed, block); - } -@@ -55,7 +62,8 @@ public class BlockPhysicsEvent extends BlockEvent implements Cancellable { - } - - /** -- * Gets the type of block that changed, causing this event -+ * Gets the type of block that changed, causing this event. -+ * This is the type of {@link #getBlock()} at the time of the event. - * - * @return Changed block's type - */ -@@ -64,6 +72,19 @@ public class BlockPhysicsEvent extends BlockEvent implements Cancellable { - return changed.getMaterial(); - } - -+ // Paper start - Getter for the BlockData -+ /** -+ * Gets the BlockData of the block that changed, causing this event. -+ * This is the BlockData of {@link #getBlock()} at the time of the event. -+ * -+ * @return Changed block's BlockData -+ */ -+ @NotNull -+ public BlockData getChangedBlockData() { -+ return changed; -+ } -+ // Paper end -+ - @Override - public boolean isCancelled() { - return cancel; diff --git a/patches/api/0145-Implement-furnace-cook-speed-multiplier-API.patch b/patches/api/0145-Implement-furnace-cook-speed-multiplier-API.patch new file mode 100644 index 000000000000..6e836a844d6f --- /dev/null +++ b/patches/api/0145-Implement-furnace-cook-speed-multiplier-API.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tassu +Date: Thu, 13 Sep 2018 08:45:01 +0300 +Subject: [PATCH] Implement furnace cook speed multiplier API + +Signed-off-by: Tassu + +diff --git a/src/main/java/org/bukkit/block/Furnace.java b/src/main/java/org/bukkit/block/Furnace.java +index ac3b24c5c99eeb1435d785efade728dd40947da5..dbdf3dbe9517b09a7965cf9d65cae1edd87af67d 100644 +--- a/src/main/java/org/bukkit/block/Furnace.java ++++ b/src/main/java/org/bukkit/block/Furnace.java +@@ -74,6 +74,26 @@ public interface Furnace extends Container { + @NotNull + public Map, Integer> getRecipesUsed(); + ++ // Paper start ++ /** ++ * Gets the cook speed multiplier that this {@link Furnace} will cook ++ * compared to vanilla. ++ * ++ * @return the multiplier, a value between 0 and 200 ++ */ ++ public double getCookSpeedMultiplier(); ++ ++ /** ++ * Sets the speed multiplier that this {@link Furnace} will cook ++ * compared to vanilla. ++ * ++ * @param multiplier the multiplier to set, a value between 0 and 200 ++ * @throws IllegalArgumentException if value is less than 0 ++ * @throws IllegalArgumentException if value is more than 200 ++ */ ++ public void setCookSpeedMultiplier(double multiplier); ++ // Paper end ++ + @NotNull + @Override + public FurnaceInventory getInventory(); +diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java +index 0808e7aeffb69160913344de5b5e21d5e857f1d6..d386ab5dd46cc6706ace61fe6b646713ffd50cb7 100644 +--- a/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java +@@ -18,10 +18,17 @@ public class FurnaceStartSmeltEvent extends InventoryBlockStartEvent { + private final CookingRecipe recipe; + private int totalCookTime; + ++ @Deprecated // Paper - furnace cook speed multiplier + public FurnaceStartSmeltEvent(@NotNull final Block furnace, @NotNull ItemStack source, @NotNull final CookingRecipe recipe) { ++ // Paper start ++ this(furnace, source, recipe, recipe.getCookingTime()); ++ } ++ ++ public FurnaceStartSmeltEvent(final @NotNull Block furnace, final @NotNull ItemStack source, final @NotNull CookingRecipe recipe, final int cookingTime) { ++ // Paper end + super(furnace, source); + this.recipe = recipe; +- this.totalCookTime = recipe.getCookingTime(); ++ this.totalCookTime = cookingTime; // Paper - furnace cook speed multiplier + } + + /** diff --git a/patches/api/0146-Async-Chunks-API.patch b/patches/api/0146-Async-Chunks-API.patch deleted file mode 100644 index 699def16c025..000000000000 --- a/patches/api/0146-Async-Chunks-API.patch +++ /dev/null @@ -1,534 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 29 Feb 2016 17:43:33 -0600 -Subject: [PATCH] Async Chunks API - -Adds API's to load or generate chunks asynchronously. - -Also adds utility methods to Entity to teleport asynchronously. - -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 324fca7bf480a463adb30842fa169052534f5252..3e3682be2a1afe92ccdc9a1d97469a69f952a9ed 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -969,6 +969,482 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - } - return nearby; - } -+ -+ /** -+ * This is the Legacy API before Java 8 was supported. Java 8 Consumer is provided, -+ * as well as future support -+ * -+ * Used by {@link World#getChunkAtAsync(Location,ChunkLoadCallback)} methods -+ * to request a {@link Chunk} to be loaded, with this callback receiving -+ * the chunk when it is finished. -+ * -+ * This callback will be executed on synchronously on the main thread. -+ * -+ * Timing and order this callback is fired is intentionally not defined and -+ * and subject to change. -+ * -+ * @deprecated Use either the Future or the Consumer based methods -+ */ -+ @Deprecated -+ public static interface ChunkLoadCallback extends java.util.function.Consumer { -+ public void onLoad(@NotNull Chunk chunk); -+ -+ // backwards compat to old api -+ @Override -+ default void accept(@NotNull Chunk chunk) { -+ onLoad(chunk); -+ } -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The {@link ChunkLoadCallback} will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @deprecated Use either the Future or the Consumer based methods -+ * @param x Chunk X-coordinate of the chunk - (world coordinate / 16) -+ * @param z Chunk Z-coordinate of the chunk - (world coordinate / 16) -+ * @param cb Callback to receive the chunk when it is loaded. -+ * will be executed synchronously -+ */ -+ @Deprecated -+ public default void getChunkAtAsync(int x, int z, @NotNull ChunkLoadCallback cb) { -+ getChunkAtAsync(x, z, true).thenAccept(cb::onLoad).exceptionally((ex) -> { -+ Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Exception in chunk load callback", ex); -+ return null; -+ }); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given {@link Location} -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The {@link ChunkLoadCallback} will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @deprecated Use either the Future or the Consumer based methods -+ * @param loc Location of the chunk -+ * @param cb Callback to receive the chunk when it is loaded. -+ * will be executed synchronously -+ */ -+ @Deprecated -+ public default void getChunkAtAsync(@NotNull Location loc, @NotNull ChunkLoadCallback cb) { -+ getChunkAtAsync(loc, true).thenAccept(cb::onLoad).exceptionally((ex) -> { -+ Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Exception in chunk load callback", ex); -+ return null; -+ }); -+ } -+ -+ /** -+ * Requests {@link Chunk} to be loaded that contains the given {@link Block} -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The {@link ChunkLoadCallback} will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @deprecated Use either the Future or the Consumer based methods -+ * @param block Block to get the containing chunk from -+ * @param cb Callback to receive the chunk when it is loaded. -+ * will be executed synchronously -+ */ -+ @Deprecated -+ public default void getChunkAtAsync(@NotNull Block block, @NotNull ChunkLoadCallback cb) { -+ getChunkAtAsync(block, true).thenAccept(cb::onLoad).exceptionally((ex) -> { -+ Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Exception in chunk load callback", ex); -+ return null; -+ }); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The {@link java.util.function.Consumer} will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @param x Chunk X-coordinate of the chunk - (world coordinate / 16) -+ * @param z Chunk Z-coordinate of the chunk - (world coordinate / 16) -+ * @param cb Callback to receive the chunk when it is loaded. -+ * will be executed synchronously -+ */ -+ public default void getChunkAtAsync(int x, int z, @NotNull java.util.function.Consumer cb) { -+ getChunkAtAsync(x, z, true).thenAccept(cb).exceptionally((ex) -> { -+ Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Exception in chunk load callback", ex); -+ return null; -+ }); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The {@link java.util.function.Consumer} will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @param x Chunk X-coordinate of the chunk - (world coordinate / 16) -+ * @param z Chunk Z-coordinate of the chunk - (world coordinate / 16) -+ * @param gen Should we generate a chunk if it doesn't exists or not -+ * @param cb Callback to receive the chunk when it is loaded. -+ * will be executed synchronously -+ */ -+ public default void getChunkAtAsync(int x, int z, boolean gen, @NotNull java.util.function.Consumer cb) { -+ getChunkAtAsync(x, z, gen).thenAccept(cb).exceptionally((ex) -> { -+ Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Exception in chunk load callback", ex); -+ return null; -+ }); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given {@link Location} -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The {@link java.util.function.Consumer} will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @param loc Location of the chunk -+ * @param cb Callback to receive the chunk when it is loaded. -+ * will be executed synchronously -+ */ -+ public default void getChunkAtAsync(@NotNull Location loc, @NotNull java.util.function.Consumer cb) { -+ getChunkAtAsync((int)Math.floor(loc.getX()) >> 4, (int)Math.floor(loc.getZ()) >> 4, true, cb); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given {@link Location} -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The {@link java.util.function.Consumer} will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @param loc Location of the chunk -+ * @param gen Should the chunk generate -+ * @param cb Callback to receive the chunk when it is loaded. -+ * will be executed synchronously -+ */ -+ public default void getChunkAtAsync(@NotNull Location loc, boolean gen, @NotNull java.util.function.Consumer cb) { -+ getChunkAtAsync((int)Math.floor(loc.getX()) >> 4, (int)Math.floor(loc.getZ()) >> 4, gen, cb); -+ } -+ -+ /** -+ * Requests {@link Chunk} to be loaded that contains the given {@link Block} -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The {@link java.util.function.Consumer} will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @param block Block to get the containing chunk from -+ * @param cb Callback to receive the chunk when it is loaded. -+ * will be executed synchronously -+ */ -+ public default void getChunkAtAsync(@NotNull Block block, @NotNull java.util.function.Consumer cb) { -+ getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, true, cb); -+ } -+ -+ /** -+ * Requests {@link Chunk} to be loaded that contains the given {@link Block} -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The {@link java.util.function.Consumer} will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @param block Block to get the containing chunk from -+ * @param gen Should the chunk generate -+ * @param cb Callback to receive the chunk when it is loaded. -+ * will be executed synchronously -+ */ -+ public default void getChunkAtAsync(@NotNull Block block, boolean gen, @NotNull java.util.function.Consumer cb) { -+ getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, gen, cb); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * @param loc Location to load the corresponding chunk from -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsync(@NotNull Location loc) { -+ return getChunkAtAsync((int)Math.floor(loc.getX()) >> 4, (int)Math.floor(loc.getZ()) >> 4, true); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * @param loc Location to load the corresponding chunk from -+ * @param gen Should the chunk generate -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsync(@NotNull Location loc, boolean gen) { -+ return getChunkAtAsync((int)Math.floor(loc.getX()) >> 4, (int)Math.floor(loc.getZ()) >> 4, gen); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * @param block Block to load the corresponding chunk from -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsync(@NotNull Block block) { -+ return getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, true); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * @param block Block to load the corresponding chunk from -+ * @param gen Should the chunk generate -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsync(@NotNull Block block, boolean gen) { -+ return getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, gen); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @param x X Coord -+ * @param z Z Coord -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z) { -+ return getChunkAtAsync(x, z, true); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @param x Chunk X-coordinate of the chunk - (world coordinate / 16) -+ * @param z Chunk Z-coordinate of the chunk - (world coordinate / 16) -+ * @param gen Should we generate a chunk if it doesn't exists or not -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen) { -+ return getChunkAtAsync(x, z, gen, false); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * @param loc Location to load the corresponding chunk from -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(@NotNull Location loc) { -+ return getChunkAtAsync((int)Math.floor(loc.getX()) >> 4, (int)Math.floor(loc.getZ()) >> 4, true, true); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * @param loc Location to load the corresponding chunk from -+ * @param gen Should the chunk generate -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(@NotNull Location loc, boolean gen) { -+ return getChunkAtAsync((int)Math.floor(loc.getX()) >> 4, (int)Math.floor(loc.getZ()) >> 4, gen, true); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * @param block Block to load the corresponding chunk from -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(@NotNull Block block) { -+ return getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, true, true); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * @param block Block to load the corresponding chunk from -+ * @param gen Should the chunk generate -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(@NotNull Block block, boolean gen) { -+ return getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, gen, true); -+ } -+ -+ /** -+ * Requests a {@link Chunk} to be loaded at the given coordinates -+ * -+ * This method makes no guarantee on how fast the chunk will load, -+ * and will return the chunk to the callback at a later time. -+ * -+ * You should use this method if you need a chunk but do not need it -+ * immediately, and you wish to let the server control the speed -+ * of chunk loads, keeping performance in mind. -+ * -+ * The future will always be executed synchronously -+ * on the main Server Thread. -+ * -+ * @param x X Coord -+ * @param z Z Coord -+ * @return Future that will resolve when the chunk is loaded -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(int x, int z) { -+ return getChunkAtAsync(x, z, true, true); -+ } -+ -+ @NotNull -+ java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent); - // Paper end - - /** -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index df07eb07896790a09d1022daef5cffc6a435f739..7a05615ec7678338801bcae2ec9a029b13d323d2 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -163,6 +163,33 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - */ - public boolean teleport(@NotNull Entity destination, @NotNull TeleportCause cause); - -+ // Paper start -+ /** -+ * Loads/Generates(in 1.13+) the Chunk asynchronously, and then teleports the entity when the chunk is ready. -+ * @param loc Location to teleport to -+ * @return A future that will be completed with the result of the teleport -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture teleportAsync(@NotNull Location loc) { -+ return teleportAsync(loc, TeleportCause.PLUGIN); -+ } -+ /** -+ * Loads/Generates(in 1.13+) the Chunk asynchronously, and then teleports the entity when the chunk is ready. -+ * @param loc Location to teleport to -+ * @param cause Reason for teleport -+ * @return A future that will be completed with the result of the teleport -+ */ -+ @NotNull -+ public default java.util.concurrent.CompletableFuture teleportAsync(@NotNull Location loc, @NotNull TeleportCause cause) { -+ java.util.concurrent.CompletableFuture future = new java.util.concurrent.CompletableFuture<>(); -+ loc.getWorld().getChunkAtAsyncUrgently(loc).thenAccept((chunk) -> future.complete(teleport(loc, cause))).exceptionally(ex -> { -+ future.completeExceptionally(ex); -+ return null; -+ }); -+ return future; -+ } -+ // Paper end -+ - /** - * Returns a list of entities within a bounding box centered around this - * entity diff --git a/patches/api/0146-Material-API-additions.patch b/patches/api/0146-Material-API-additions.patch new file mode 100644 index 000000000000..1703b81e1f33 --- /dev/null +++ b/patches/api/0146-Material-API-additions.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 6 Oct 2018 21:14:29 -0400 +Subject: [PATCH] Material API additions + + +diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java +index b8d3b0c4738c5a2886d9728f396df1746ea4f859..9d1f82be4f23af37ccc6db65756f6dd3028c6837 100644 +--- a/src/main/java/org/bukkit/Material.java ++++ b/src/main/java/org/bukkit/Material.java +@@ -135,6 +135,7 @@ import org.jetbrains.annotations.Nullable; + /** + * An enum of all material IDs accepted by the official server and client + */ ++@SuppressWarnings({"DeprecatedIsStillUsed", "deprecation"}) // Paper + public enum Material implements Keyed, Translatable { + // + AIR(9648, 0), +@@ -4817,6 +4818,22 @@ public enum Material implements Keyed, Translatable { + }); + } + ++ // Paper start ++ ++ /** ++ * @return If the type is either AIR, CAVE_AIR or VOID_AIR ++ */ ++ public boolean isEmpty() { ++ switch (this) { ++ case AIR: ++ case CAVE_AIR: ++ case VOID_AIR: ++ return true; ++ } ++ return false; ++ } ++ // Paper end ++ + /** + * Do not use for any reason. + * diff --git a/patches/api/0147-Add-Material-Tags.patch b/patches/api/0147-Add-Material-Tags.patch new file mode 100644 index 000000000000..6029e08ddc7e --- /dev/null +++ b/patches/api/0147-Add-Material-Tags.patch @@ -0,0 +1,1255 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 17 Jul 2018 01:27:15 -0400 +Subject: [PATCH] Add Material Tags + +This adds a bunch of useful and missing Tags to be able to identify items that +are related to each other by a trait. + +Co-authored-by: Jake Potrebic +Co-authored-by: Lena Kolb +Co-authored-by: Layla Silbernberg +Co-authored-by: Newwind + +diff --git a/src/main/java/com/destroystokyo/paper/MaterialSetTag.java b/src/main/java/com/destroystokyo/paper/MaterialSetTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..28282090c8b3668c11faefa0523f9e4ad9e43c42 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/MaterialSetTag.java +@@ -0,0 +1,100 @@ ++/* ++ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License ++ */ ++ ++package com.destroystokyo.paper; ++ ++import com.google.common.collect.Lists; ++import io.papermc.paper.tag.BaseTag; ++import org.bukkit.Material; ++import org.bukkit.NamespacedKey; ++import org.bukkit.block.Block; ++import org.bukkit.block.BlockState; ++import org.bukkit.block.data.BlockData; ++import org.bukkit.inventory.ItemStack; ++ ++import java.util.Collection; ++import java.util.Set; ++import java.util.function.Predicate; ++import java.util.stream.Collectors; ++import java.util.stream.Stream; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class MaterialSetTag extends BaseTag { ++ ++ /** ++ * @deprecated Use NamespacedKey version of constructor ++ */ ++ @Deprecated ++ public MaterialSetTag(@NotNull Predicate filter) { ++ this(null, Stream.of(Material.values()).filter(filter).collect(Collectors.toList())); ++ } ++ ++ /** ++ * @deprecated Use NamespacedKey version of constructor ++ */ ++ @Deprecated ++ public MaterialSetTag(@NotNull Collection materials) { ++ this(null, materials); ++ } ++ ++ /** ++ * @deprecated Use NamespacedKey version of constructor ++ */ ++ @Deprecated ++ public MaterialSetTag(@NotNull Material... materials) { ++ this(null, materials); ++ } ++ ++ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Predicate filter) { ++ this(key, Stream.of(Material.values()).filter(filter).collect(Collectors.toList())); ++ } ++ ++ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Material... materials) { ++ this(key, Lists.newArrayList(materials)); ++ } ++ ++ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Collection materials) { ++ this(key != null ? key : NamespacedKey.randomKey(), materials, ((Predicate) Material::isLegacy).negate()); ++ } ++ ++ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Collection materials, @NotNull Predicate...globalPredicates) { ++ super(Material.class, key != null ? key : NamespacedKey.randomKey(), materials, globalPredicates); ++ } ++ ++ @NotNull ++ @Override ++ @ApiStatus.Internal ++ protected Set getAllPossibleValues() { ++ return Stream.of(Material.values()).collect(Collectors.toSet()); ++ } ++ ++ @Override ++ @NotNull ++ @ApiStatus.Internal ++ protected String getName(@NotNull Material value) { ++ return value.name(); ++ } ++ ++ public boolean isTagged(@NotNull BlockData block) { ++ return isTagged(block.getMaterial()); ++ } ++ ++ public boolean isTagged(@NotNull BlockState block) { ++ return isTagged(block.getType()); ++ } ++ ++ public boolean isTagged(@NotNull Block block) { ++ return isTagged(block.getType()); ++ } ++ ++ public boolean isTagged(@NotNull ItemStack item) { ++ return isTagged(item.getType()); ++ } ++ ++ public boolean isTagged(@NotNull Material material) { ++ return this.tagged.contains(material); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/MaterialTags.java b/src/main/java/com/destroystokyo/paper/MaterialTags.java +new file mode 100644 +index 0000000000000000000000000000000000000000..679f78e07a3a2de745fa237165d0a8db5e086f29 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/MaterialTags.java +@@ -0,0 +1,724 @@ ++/* ++ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++package com.destroystokyo.paper; ++ ++import org.bukkit.Material; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Tag; ++ ++/** ++ * Represents a collection tags to identify materials that share common properties. ++ * Will map to minecraft for missing tags, as well as custom ones that may be useful. ++ *

      ++ * All tags in this class are unmodifiable, attempting to modify them will throw an ++ * {@link UnsupportedOperationException}. ++ */ ++@SuppressWarnings({"NonFinalUtilityClass", "unused", "WeakerAccess"}) ++public class MaterialTags { ++ ++ private static NamespacedKey keyFor(String key) { ++ //noinspection deprecation ++ return new NamespacedKey("paper", key + "_settag"); ++ } ++ public static final MaterialSetTag ARROWS = new MaterialSetTag(keyFor("arrows")) ++ .endsWith("ARROW") ++ .ensureSize("ARROWS", 3).lock(); ++ ++ /** ++ * Covers all colors of beds. ++ */ ++ public static final MaterialSetTag BEDS = new MaterialSetTag(keyFor("beds")) ++ .endsWith("_BED") ++ .ensureSize("BEDS", 16).lock(); ++ ++ /** ++ * Covers all bucket items. ++ */ ++ public static final MaterialSetTag BUCKETS = new MaterialSetTag(keyFor("buckets")) ++ .endsWith("BUCKET") ++ .ensureSize("BUCKETS", 11).lock(); ++ ++ /** ++ * Covers coal and charcoal. ++ */ ++ public static final MaterialSetTag COALS = new MaterialSetTag(keyFor("coals")) ++ .add(Material.COAL, Material.CHARCOAL).lock(); ++ ++ /** ++ * Covers both cobblestone wall variants. ++ */ ++ public static final MaterialSetTag COBBLESTONE_WALLS = new MaterialSetTag(keyFor("cobblestone_walls")) ++ .endsWith("COBBLESTONE_WALL") ++ .ensureSize("COBBLESTONE_WALLS", 2).lock(); ++ ++ /** ++ * Covers both cobblestone and mossy Cobblestone. ++ */ ++ public static final MaterialSetTag COBBLESTONES = new MaterialSetTag(keyFor("cobblestones")) ++ .add(Material.COBBLESTONE, Material.MOSSY_COBBLESTONE).lock(); ++ ++ /** ++ * Covers all colors of concrete. ++ */ ++ public static final MaterialSetTag CONCRETES = new MaterialSetTag(keyFor("concretes")) ++ .endsWith("_CONCRETE") ++ .ensureSize("CONCRETES", 16).lock(); ++ ++ /** ++ * Covers all colors of concrete powder. ++ */ ++ public static final MaterialSetTag CONCRETE_POWDER = new MaterialSetTag(keyFor("concrete_powder")) ++ .endsWith("_CONCRETE_POWDER") ++ .ensureSize("CONCRETE_POWDER", 16).lock(); ++ ++ /** ++ * Covers the two types of cooked fish. ++ */ ++ public static final MaterialSetTag COOKED_FISH = new MaterialSetTag(keyFor("cooked_fish")) ++ .add(Material.COOKED_COD, Material.COOKED_SALMON).lock(); ++ ++ /** ++ * Covers all variants of doors. ++ */ ++ public static final MaterialSetTag DOORS = new MaterialSetTag(keyFor("doors")) ++ .endsWith("_DOOR") ++ .ensureSize("DOORS", 21).lock(); ++ ++ /** ++ * Covers all dyes. ++ */ ++ public static final MaterialSetTag DYES = new MaterialSetTag(keyFor("dyes")) ++ .endsWith("_DYE") ++ .ensureSize("DYES", 16).lock(); ++ ++ /** ++ * Covers all variants of gates. ++ */ ++ public static final MaterialSetTag FENCE_GATES = new MaterialSetTag(keyFor("fence_gates")) ++ .endsWith("_GATE") ++ .ensureSize("FENCE_GATES", 12).lock(); ++ ++ /** ++ * Covers all variants of fences. ++ */ ++ public static final MaterialSetTag FENCES = new MaterialSetTag(keyFor("fences")) ++ .endsWith("_FENCE") ++ .ensureSize("FENCES", 13).lock(); ++ ++ /** ++ * Covers all variants of fish buckets. ++ */ ++ public static final MaterialSetTag FISH_BUCKETS = new MaterialSetTag(keyFor("fish_buckets")) ++ .add(Material.COD_BUCKET, Material.PUFFERFISH_BUCKET, Material.SALMON_BUCKET, Material.TROPICAL_FISH_BUCKET).lock(); ++ ++ /** ++ * Covers the non-colored glass and 16 stained glass (not panes). ++ */ ++ public static final MaterialSetTag GLASS = new MaterialSetTag(keyFor("glass")) ++ .endsWith("_GLASS") ++ .add(Material.GLASS) ++ .ensureSize("GLASS", 18).lock(); ++ ++ /** ++ * Covers the non-colored glass panes and stained glass panes (panes only). ++ */ ++ public static final MaterialSetTag GLASS_PANES = new MaterialSetTag(keyFor("glass_panes")) ++ .endsWith("GLASS_PANE") ++ .ensureSize("GLASS_PANES", 17).lock(); ++ ++ /** ++ * Covers all glazed terracotta blocks. ++ */ ++ public static final MaterialSetTag GLAZED_TERRACOTTA = new MaterialSetTag(keyFor("glazed_terracotta")) ++ .endsWith("GLAZED_TERRACOTTA") ++ .ensureSize("GLAZED_TERRACOTTA", 16).lock(); ++ ++ /** ++ * Covers the colors of stained terracotta. ++ */ ++ public static final MaterialSetTag STAINED_TERRACOTTA = new MaterialSetTag(keyFor("stained_terracotta")) ++ .endsWith("TERRACOTTA") ++ .not(Material.TERRACOTTA) ++ .notEndsWith("GLAZED_TERRACOTTA") ++ .ensureSize("STAINED_TERRACOTTA", 16).lock(); ++ ++ /** ++ * Covers terracotta along with the stained variants. ++ */ ++ public static final MaterialSetTag TERRACOTTA = new MaterialSetTag(keyFor("terracotta")) ++ .endsWith("TERRACOTTA") ++ .ensureSize("TERRACOTTA", 33).lock(); ++ ++ /** ++ * Covers both golden apples. ++ */ ++ public static final MaterialSetTag GOLDEN_APPLES = new MaterialSetTag(keyFor("golden_apples")) ++ .endsWith("GOLDEN_APPLE") ++ .ensureSize("GOLDEN_APPLES", 2).lock(); ++ ++ /** ++ * Covers the variants of horse armor. ++ */ ++ public static final MaterialSetTag HORSE_ARMORS = new MaterialSetTag(keyFor("horse_armors")) ++ .endsWith("_HORSE_ARMOR") ++ .ensureSize("HORSE_ARMORS", 4).lock(); ++ ++ /** ++ * Covers the variants of infested blocks. ++ */ ++ public static final MaterialSetTag INFESTED_BLOCKS = new MaterialSetTag(keyFor("infested_blocks")) ++ .startsWith("INFESTED_") ++ .ensureSize("INFESTED_BLOCKS", 7).lock(); ++ ++ /** ++ * Covers the variants of mushroom blocks. ++ */ ++ public static final MaterialSetTag MUSHROOM_BLOCKS = new MaterialSetTag(keyFor("mushroom_blocks")) ++ .endsWith("MUSHROOM_BLOCK") ++ .add(Material.MUSHROOM_STEM) ++ .ensureSize("MUSHROOM_BLOCKS", 3).lock(); ++ ++ /** ++ * Covers all mushrooms. ++ */ ++ public static final MaterialSetTag MUSHROOMS = new MaterialSetTag(keyFor("mushrooms")) ++ .add(Material.BROWN_MUSHROOM, Material.RED_MUSHROOM).lock(); ++ ++ /** ++ * Covers all music disc items. ++ */ ++ public static final MaterialSetTag MUSIC_DISCS = new MaterialSetTag(keyFor("music_discs")) ++ .startsWith("MUSIC_DISC_").lock(); ++ ++ /** ++ * Covers all ores. ++ */ ++ public static final MaterialSetTag ORES = new MaterialSetTag(keyFor("ores")) ++ .add(Material.ANCIENT_DEBRIS) ++ .endsWith("_ORE") ++ .ensureSize("ORES", 19).lock(); ++ ++ /** ++ * Covers all piston typed items and blocks including the piston head and moving piston. ++ */ ++ public static final MaterialSetTag PISTONS = new MaterialSetTag(keyFor("pistons")) ++ .contains("PISTON") ++ .ensureSize("PISTONS", 4).lock(); ++ ++ /** ++ * Covers all potato items. ++ */ ++ public static final MaterialSetTag POTATOES = new MaterialSetTag(keyFor("potatoes")) ++ .endsWith("POTATO") ++ .ensureSize("POTATOES", 3).lock(); ++ ++ /** ++ * Covers all wooden pressure plates and the weighted pressure plates and the stone pressure plate. ++ */ ++ public static final MaterialSetTag PRESSURE_PLATES = new MaterialSetTag(keyFor("pressure_plates")) ++ .endsWith("_PRESSURE_PLATE") ++ .ensureSize("PRESSURE_PLATES", 16).lock(); ++ ++ /** ++ * Covers the variants of prismarine blocks. ++ */ ++ public static final MaterialSetTag PRISMARINE = new MaterialSetTag(keyFor("prismarine")) ++ .add(Material.PRISMARINE, Material.PRISMARINE_BRICKS, Material.DARK_PRISMARINE).lock(); ++ ++ /** ++ * Covers the variants of prismarine slabs. ++ */ ++ public static final MaterialSetTag PRISMARINE_SLABS = new MaterialSetTag(keyFor("prismarine_slabs")) ++ .add(Material.PRISMARINE_SLAB, Material.PRISMARINE_BRICK_SLAB, Material.DARK_PRISMARINE_SLAB).lock(); ++ ++ /** ++ * Covers the variants of prismarine stairs. ++ */ ++ public static final MaterialSetTag PRISMARINE_STAIRS = new MaterialSetTag(keyFor("prismarine_stairs")) ++ .add(Material.PRISMARINE_STAIRS, Material.PRISMARINE_BRICK_STAIRS, Material.DARK_PRISMARINE_STAIRS).lock(); ++ ++ /** ++ * Covers the variants of pumpkins. ++ */ ++ public static final MaterialSetTag PUMPKINS = new MaterialSetTag(keyFor("pumpkins")) ++ .add(Material.CARVED_PUMPKIN, Material.JACK_O_LANTERN, Material.PUMPKIN).lock(); ++ ++ /** ++ * Covers the variants of quartz blocks. ++ */ ++ public static final MaterialSetTag QUARTZ_BLOCKS = new MaterialSetTag(keyFor("quartz_blocks")) ++ .add(Material.QUARTZ_BLOCK, Material.QUARTZ_PILLAR, Material.CHISELED_QUARTZ_BLOCK, Material.SMOOTH_QUARTZ).lock(); ++ ++ /** ++ * Covers all uncooked fish items. ++ */ ++ public static final MaterialSetTag RAW_FISH = new MaterialSetTag(keyFor("raw_fish")) ++ .add(Material.COD, Material.PUFFERFISH, Material.SALMON, Material.TROPICAL_FISH).lock(); ++ ++ /** ++ * Covers the variants of red sandstone blocks. ++ */ ++ public static final MaterialSetTag RED_SANDSTONES = new MaterialSetTag(keyFor("red_sandstones")) ++ .endsWith("RED_SANDSTONE") ++ .ensureSize("RED_SANDSTONES", 4).lock(); ++ ++ /** ++ * Covers the variants of sandstone blocks. ++ */ ++ public static final MaterialSetTag SANDSTONES = new MaterialSetTag(keyFor("sandstones")) ++ .add(Material.SANDSTONE, Material.CHISELED_SANDSTONE, Material.CUT_SANDSTONE, Material.SMOOTH_SANDSTONE).lock(); ++ ++ /** ++ * Covers sponge and wet sponge. ++ */ ++ public static final MaterialSetTag SPONGES = new MaterialSetTag(keyFor("sponges")) ++ .endsWith("SPONGE") ++ .ensureSize("SPONGES", 2).lock(); ++ ++ /** ++ * Covers the non-colored and colored shulker boxes. ++ */ ++ public static final MaterialSetTag SHULKER_BOXES = new MaterialSetTag(keyFor("shulker_boxes")) ++ .endsWith("SHULKER_BOX") ++ .ensureSize("SHULKER_BOXES", 17).lock(); ++ ++ /** ++ * Covers zombie, creeper, skeleton, dragon, and player heads. ++ */ ++ public static final MaterialSetTag SKULLS = new MaterialSetTag(keyFor("skulls")) ++ .endsWith("_HEAD") ++ .endsWith("_SKULL") ++ .not(Material.PISTON_HEAD) ++ .ensureSize("SKULLS", 14).lock(); ++ ++ /** ++ * Covers all spawn egg items. ++ */ ++ public static final MaterialSetTag SPAWN_EGGS = new MaterialSetTag(keyFor("spawn_eggs")) ++ .endsWith("_SPAWN_EGG") ++ .ensureSize("SPAWN_EGGS", 81).lock(); ++ ++ /** ++ * Covers all colors of stained glass. ++ */ ++ public static final MaterialSetTag STAINED_GLASS = new MaterialSetTag(keyFor("stained_glass")) ++ .endsWith("_STAINED_GLASS") ++ .ensureSize("STAINED_GLASS", 16).lock(); ++ ++ /** ++ * Covers all colors of stained glass panes. ++ */ ++ public static final MaterialSetTag STAINED_GLASS_PANES = new MaterialSetTag(keyFor("stained_glass_panes")) ++ .endsWith("STAINED_GLASS_PANE") ++ .ensureSize("STAINED_GLASS_PANES", 16).lock(); ++ ++ /** ++ * Covers all variants of trapdoors. ++ */ ++ public static final MaterialSetTag TRAPDOORS = new MaterialSetTag(keyFor("trapdoors")) ++ .endsWith("_TRAPDOOR") ++ .ensureSize("TRAPDOORS", 21).lock(); ++ ++ /** ++ * Covers all wood variants of doors. ++ */ ++ public static final MaterialSetTag WOODEN_DOORS = new MaterialSetTag(keyFor("wooden_doors")) ++ .endsWith("_DOOR") ++ .not(Material.IRON_DOOR) ++ .notContains("COPPER") ++ .ensureSize("WOODEN_DOORS", 12).lock(); ++ ++ /** ++ * Covers all wood variants of fences. ++ */ ++ public static final MaterialSetTag WOODEN_FENCES = new MaterialSetTag(keyFor("wooden_fences")) ++ .endsWith("_FENCE") ++ .not(Material.NETHER_BRICK_FENCE) ++ .ensureSize("WOODEN_FENCES", 12).lock(); ++ ++ /** ++ * Covers all wood variants of trapdoors. ++ */ ++ public static final MaterialSetTag WOODEN_TRAPDOORS = new MaterialSetTag(keyFor("wooden_trapdoors")) ++ .endsWith("_TRAPDOOR") ++ .not(Material.IRON_TRAPDOOR) ++ .notContains("COPPER") ++ .ensureSize("WOODEN_TRAPDOORS", 12).lock(); ++ ++ /** ++ * Covers the wood variants of gates. ++ */ ++ public static final MaterialSetTag WOODEN_GATES = new MaterialSetTag(keyFor("wooden_gates")) ++ .endsWith("_GATE") ++ .ensureSize("WOODEN_GATES", 12).lock(); ++ ++ /** ++ * Covers the variants of purpur. ++ */ ++ public static final MaterialSetTag PURPUR = new MaterialSetTag(keyFor("purpur")) ++ .startsWith("PURPUR_") ++ .ensureSize("PURPUR", 4).lock(); ++ ++ /** ++ * Covers the variants of signs. ++ */ ++ public static final MaterialSetTag SIGNS = new MaterialSetTag(keyFor("signs")) ++ .endsWith("_SIGN") ++ .ensureSize("SIGNS", 48).lock(); ++ ++ /** ++ * Covers the variants of a regular torch. ++ */ ++ public static final MaterialSetTag TORCH = new MaterialSetTag(keyFor("torch")) ++ .add(Material.TORCH, Material.WALL_TORCH) ++ .ensureSize("TORCH", 2).lock(); ++ ++ /** ++ * Covers the variants of a redstone torch. ++ */ ++ public static final MaterialSetTag REDSTONE_TORCH = new MaterialSetTag(keyFor("redstone_torch")) ++ .add(Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH) ++ .ensureSize("REDSTONE_TORCH", 2).lock(); ++ ++ /** ++ * Covers the variants of a soul torch. ++ */ ++ public static final MaterialSetTag SOUL_TORCH = new MaterialSetTag(keyFor("soul_torch")) ++ .add(Material.SOUL_TORCH, Material.SOUL_WALL_TORCH) ++ .ensureSize("SOUL_TORCH", 2).lock(); ++ ++ /** ++ * Covers the variants of torches. ++ */ ++ public static final MaterialSetTag TORCHES = new MaterialSetTag(keyFor("torches")) ++ .add(TORCH, REDSTONE_TORCH, SOUL_TORCH) ++ .ensureSize("TORCHES", 6).lock(); ++ ++ /** ++ * Covers the variants of lanterns. ++ */ ++ public static final MaterialSetTag LANTERNS = new MaterialSetTag(keyFor("lanterns")) ++ .add(Material.LANTERN, Material.SOUL_LANTERN) ++ .ensureSize("LANTERNS", 2).lock(); ++ ++ /** ++ * Covers the variants of rails. ++ */ ++ public static final MaterialSetTag RAILS = new MaterialSetTag(keyFor("rails")) ++ .endsWith("RAIL") ++ .ensureSize("RAILS", 4).lock(); ++ ++ /** ++ * Covers the variants of swords. ++ */ ++ public static final MaterialSetTag SWORDS = new MaterialSetTag(keyFor("swords")) ++ .endsWith("_SWORD") ++ .ensureSize("SWORDS", 6).lock(); ++ ++ /** ++ * Covers the variants of shovels. ++ */ ++ public static final MaterialSetTag SHOVELS = new MaterialSetTag(keyFor("shovels")) ++ .endsWith("_SHOVEL") ++ .ensureSize("SHOVELS", 6).lock(); ++ ++ /** ++ * Covers the variants of pickaxes. ++ */ ++ public static final MaterialSetTag PICKAXES = new MaterialSetTag(keyFor("pickaxes")) ++ .endsWith("_PICKAXE") ++ .ensureSize("PICKAXES", 6).lock(); ++ ++ /** ++ * Covers the variants of axes. ++ */ ++ public static final MaterialSetTag AXES = new MaterialSetTag(keyFor("axes")) ++ .endsWith("_AXE") ++ .ensureSize("AXES", 6).lock(); ++ ++ /** ++ * Covers the variants of hoes. ++ */ ++ public static final MaterialSetTag HOES = new MaterialSetTag(keyFor("hoes")) ++ .endsWith("_HOE") ++ .ensureSize("HOES", 6).lock(); ++ ++ /** ++ * Covers the variants of helmets. ++ */ ++ public static final MaterialSetTag HELMETS = new MaterialSetTag(keyFor("helmets")) ++ .endsWith("_HELMET") ++ .ensureSize("HELMETS", 7).lock(); ++ ++ /** ++ * Covers the variants of items that can be equipped in the helmet slot. ++ */ ++ public static final MaterialSetTag HEAD_EQUIPPABLE = new MaterialSetTag(keyFor("head_equippable")) ++ .endsWith("_HELMET") ++ .add(SKULLS) ++ .add(Material.CARVED_PUMPKIN) ++ .ensureSize("HEAD_EQUIPPABLE", 22).lock(); ++ ++ /** ++ * Covers the variants of chestplate. ++ */ ++ public static final MaterialSetTag CHESTPLATES = new MaterialSetTag(keyFor("chestplates")) ++ .endsWith("_CHESTPLATE") ++ .ensureSize("CHESTPLATES", 6).lock(); ++ ++ /** ++ * Covers the variants of items that can be equipped in the chest slot. ++ */ ++ public static final MaterialSetTag CHEST_EQUIPPABLE = new MaterialSetTag(keyFor("chest_equippable")) ++ .endsWith("_CHESTPLATE") ++ .add(Material.ELYTRA) ++ .ensureSize("CHEST_EQUIPPABLE", 7).lock(); ++ ++ /** ++ * Covers the variants of leggings. ++ */ ++ public static final MaterialSetTag LEGGINGS = new MaterialSetTag(keyFor("leggings")) ++ .endsWith("_LEGGINGS") ++ .ensureSize("LEGGINGS", 6).lock(); ++ ++ /** ++ * Covers the variants of boots. ++ */ ++ public static final MaterialSetTag BOOTS = new MaterialSetTag(keyFor("boots")) ++ .endsWith("_BOOTS") ++ .ensureSize("BOOTS", 6).lock(); ++ ++ /** ++ * Covers all variants of armor. ++ */ ++ public static final MaterialSetTag ARMOR = new MaterialSetTag(keyFor("armor")).add(HELMETS, CHESTPLATES, LEGGINGS, BOOTS) ++ .ensureSize("ARMOR", 25).lock(); ++ ++ /** ++ * Covers the variants of bows. ++ */ ++ public static final MaterialSetTag BOWS = new MaterialSetTag(keyFor("bows")) ++ .add(Material.BOW) ++ .add(Material.CROSSBOW) ++ .ensureSize("BOWS", 2).lock(); ++ ++ /** ++ * Covers the variants of player-throwable projectiles (not requiring a bow or any other "assistance"). ++ */ ++ public static final MaterialSetTag THROWABLE_PROJECTILES = new MaterialSetTag(keyFor("throwable_projectiles")) ++ .add(Material.EGG, Material.SNOWBALL, Material.SPLASH_POTION, Material.TRIDENT, Material.ENDER_PEARL, Material.EXPERIENCE_BOTTLE, Material.FIREWORK_ROCKET).lock(); ++ ++ /** ++ * Covers materials that can be colored, such as wool, shulker boxes, stained glass etc. ++ */ ++ @SuppressWarnings("unchecked") ++ public static final MaterialSetTag COLORABLE = new MaterialSetTag(keyFor("colorable")) ++ .add(Tag.WOOL, Tag.CARPETS).add(SHULKER_BOXES, STAINED_GLASS, STAINED_GLASS_PANES, CONCRETES, BEDS).lock(); ++ //.ensureSize("COLORABLE", 81).lock(); unit test don't have the vanilla item tags, so counts don't line up for real ++ ++ /** ++ * Covers the variants of coral. ++ */ ++ public static final MaterialSetTag CORAL = new MaterialSetTag(keyFor("coral")) ++ .endsWith("_CORAL") ++ .ensureSize("CORAL", 10).lock(); ++ ++ /** ++ * Covers the variants of coral fans. ++ */ ++ public static final MaterialSetTag CORAL_FANS = new MaterialSetTag(keyFor("coral_fans")) ++ .endsWith("_CORAL_FAN") ++ .endsWith("_CORAL_WALL_FAN") ++ .ensureSize("CORAL_FANS", 20).lock(); ++ ++ /** ++ * Covers the variants of coral blocks. ++ */ ++ public static final MaterialSetTag CORAL_BLOCKS = new MaterialSetTag(keyFor("coral_blocks")) ++ .endsWith("_CORAL_BLOCK") ++ .ensureSize("CORAL_BLOCKS", 10).lock(); ++ ++ /** ++ * Covers all items that can be enchanted from the enchantment table or anvil. ++ */ ++ public static final MaterialSetTag ENCHANTABLE = new MaterialSetTag(keyFor("enchantable")) ++ .add(PICKAXES, SWORDS, SHOVELS, AXES, HOES, HELMETS, CHEST_EQUIPPABLE, LEGGINGS, BOOTS, BOWS) ++ .add(Material.TRIDENT, Material.SHIELD, Material.FISHING_ROD, Material.SHEARS, ++ Material.FLINT_AND_STEEL, Material.CARROT_ON_A_STICK, Material.WARPED_FUNGUS_ON_A_STICK, ++ Material.BRUSH, Material.CARVED_PUMPKIN, Material.COMPASS, Material.SKELETON_SKULL, ++ Material.WITHER_SKELETON_SKULL, Material.PLAYER_HEAD, Material.ZOMBIE_HEAD, ++ Material.CREEPER_HEAD, Material.DRAGON_HEAD, Material.PIGLIN_HEAD) ++ .ensureSize("ENCHANTABLE", 75).lock(); ++ ++ /** ++ * Covers the variants of raw ores. ++ */ ++ public static final MaterialSetTag RAW_ORES = new MaterialSetTag(keyFor("raw_ores")) ++ .add(Material.RAW_COPPER, Material.RAW_GOLD, Material.RAW_IRON).lock(); ++ ++ /** ++ * Covers all command block types. ++ */ ++ public static final MaterialSetTag COMMAND_BLOCKS = new MaterialSetTag(keyFor("command_blocks")) ++ .endsWith("COMMAND_BLOCK") ++ .ensureSize("COMMAND_BLOCKS", 3).lock(); ++ ++ /** ++ * Covers the variants of deepslate ores. ++ */ ++ public static final MaterialSetTag DEEPSLATE_ORES = new MaterialSetTag(keyFor("deepslate_ores")) ++ .add(material -> material.name().startsWith("DEEPSLATE_") && material.name().endsWith("_ORE")) ++ .ensureSize("DEEPSLATE_ORES", 8).lock(); ++ ++ /** ++ * Covers the variants of raw ore blocks. ++ */ ++ public static final MaterialSetTag RAW_ORE_BLOCKS = new MaterialSetTag(keyFor("raw_ore_blocks")) ++ .add(Material.RAW_COPPER_BLOCK, Material.RAW_GOLD_BLOCK, Material.RAW_IRON_BLOCK).lock(); ++ ++ /** ++ * Covers all oxidized copper blocks. ++ */ ++ public static final MaterialSetTag OXIDIZED_COPPER_BLOCKS = new MaterialSetTag(keyFor("oxidized_copper_blocks")) ++ .startsWith("OXIDIZED_").startsWith("WAXED_OXIDIZED_").ensureSize("OXIDIZED_COPPER_BLOCKS", 18).lock(); ++ ++ /** ++ * Covers all weathered copper blocks. ++ */ ++ public static final MaterialSetTag WEATHERED_COPPER_BLOCKS = new MaterialSetTag(keyFor("weathered_copper_blocks")) ++ .startsWith("WEATHERED_").startsWith("WAXED_WEATHERED_").ensureSize("WEATHERED_COPPER_BLOCKS", 18).lock(); ++ ++ /** ++ * Covers all exposed copper blocks. ++ */ ++ public static final MaterialSetTag EXPOSED_COPPER_BLOCKS = new MaterialSetTag(keyFor("exposed_copper_blocks")) ++ .startsWith("EXPOSED_").startsWith("WAXED_EXPOSED_").ensureSize("EXPOSED_COPPER_BLOCKS", 18).lock(); ++ ++ /** ++ * Covers all un-weathered copper blocks. ++ */ ++ public static final MaterialSetTag UNAFFECTED_COPPER_BLOCKS = new MaterialSetTag(keyFor("unaffected_copper_blocks")) ++ .startsWith("CUT_COPPER").startsWith("WAXED_CUT_COPPER") ++ .startsWith("WAXED_COPPER_").startsWith("COPPER_") ++ .add(Material.CHISELED_COPPER, Material.WAXED_CHISELED_COPPER) ++ .not(Material.COPPER_INGOT, Material.COPPER_ORE) ++ .ensureSize("UNAFFECTED_COPPER_BLOCKS", 18).lock(); ++ ++ /** ++ * Covers all waxed copper blocks. ++ *

      ++ * Combine with other copper-related tags to filter is-waxed or not. ++ */ ++ public static final MaterialSetTag WAXED_COPPER_BLOCKS = new MaterialSetTag(keyFor("waxed_copper_blocks")) ++ .add(m -> m.name().startsWith("WAXED_") && m.name().contains("COPPER")).ensureSize("WAXED_COPPER_BLOCKS", 36).lock(); ++ ++ /** ++ * Covers all un-waxed copper blocks. ++ *

      ++ * Combine with other copper-related tags to filter is-un-waxed or not. ++ */ ++ public static final MaterialSetTag UNWAXED_COPPER_BLOCKS = new MaterialSetTag(keyFor("unwaxed_copper_blocks")) ++ .startsWith("EXPOSED_").startsWith("WEATHERED_").startsWith("OXIDIZED_") ++ .startsWith("CUT_COPPER") ++ .add(Material.COPPER_BLOCK, Material.CHISELED_COPPER, Material.COPPER_DOOR, Material.COPPER_TRAPDOOR, Material.COPPER_GRATE, Material.COPPER_BULB) ++ .ensureSize("UNWAXED_COPPER_BLOCKS", 36).lock(); ++ ++ /** ++ * Covers all copper block variants. ++ */ ++ public static final MaterialSetTag COPPER_BLOCKS = new MaterialSetTag(keyFor("copper_blocks")) ++ .add(WAXED_COPPER_BLOCKS).add(UNWAXED_COPPER_BLOCKS).ensureSize("COPPER_BLOCKS", 72).lock(); ++ ++ /** ++ * Covers all weathering/waxed states of the plain copper block. ++ */ ++ public static final MaterialSetTag FULL_COPPER_BLOCKS = new MaterialSetTag(keyFor("full_copper_blocks")) ++ .endsWith("OXIDIZED_COPPER") ++ .endsWith("WEATHERED_COPPER") ++ .endsWith("EXPOSED_COPPER") ++ .endsWith("COPPER_BLOCK") ++ .not(Material.RAW_COPPER_BLOCK) ++ .ensureSize("FULL_COPPER_BLOCKS", 8).lock(); ++ ++ /** ++ * Covers all weathering/waxed states of the cut copper block. ++ */ ++ public static final MaterialSetTag CUT_COPPER_BLOCKS = new MaterialSetTag(keyFor("cut_copper_blocks")) ++ .endsWith("CUT_COPPER").ensureSize("CUT_COPPER_BLOCKS", 8).lock(); ++ ++ /** ++ * Covers all weathering/waxed states of the cut copper stairs. ++ */ ++ public static final MaterialSetTag CUT_COPPER_STAIRS = new MaterialSetTag(keyFor("cut_copper_stairs")) ++ .endsWith("CUT_COPPER_STAIRS").ensureSize("CUT_COPPER_STAIRS", 8).lock(); ++ ++ /** ++ * Covers all weathering/waxed states of the cut copper slab. ++ */ ++ public static final MaterialSetTag CUT_COPPER_SLABS = new MaterialSetTag(keyFor("cut_copper_slabs")) ++ .endsWith("CUT_COPPER_SLAB").ensureSize("CUT_COPPER_SLABS", 8).lock(); ++ ++ /** ++ * Covers all Wooden Tools. ++ */ ++ public static final MaterialSetTag WOODEN_TOOLS = new MaterialSetTag(keyFor("wooden_tools")) ++ .add(Material.WOODEN_AXE, Material.WOODEN_HOE, Material.WOODEN_PICKAXE, Material.WOODEN_SHOVEL, Material.WOODEN_SWORD) ++ .ensureSize("WOODEN_TOOLS", 5).lock(); ++ ++ /** ++ * Covers all Stone Tools. ++ */ ++ public static final MaterialSetTag STONE_TOOLS = new MaterialSetTag(keyFor("stone_tools")) ++ .add(Material.STONE_AXE, Material.STONE_HOE, Material.STONE_PICKAXE, Material.STONE_SHOVEL, Material.STONE_SWORD) ++ .ensureSize("STONE_TOOLS", 5).lock(); ++ ++ /** ++ * Covers all Iron Tools. ++ */ ++ public static final MaterialSetTag IRON_TOOLS = new MaterialSetTag(keyFor("iron_tools")) ++ .add(Material.IRON_AXE, Material.IRON_HOE, Material.IRON_PICKAXE, Material.IRON_SHOVEL, Material.IRON_SWORD) ++ .ensureSize("IRON_TOOLS", 5).lock(); ++ ++ /** ++ * Covers all Gold Tools. ++ */ ++ public static final MaterialSetTag GOLDEN_TOOLS = new MaterialSetTag(keyFor("golden_tools")) ++ .add(Material.GOLDEN_AXE, Material.GOLDEN_HOE, Material.GOLDEN_PICKAXE, Material.GOLDEN_SHOVEL, Material.GOLDEN_SWORD) ++ .ensureSize("GOLDEN_TOOLS", 5).lock(); ++ ++ /** ++ * Covers all Diamond Tools. ++ */ ++ public static final MaterialSetTag DIAMOND_TOOLS = new MaterialSetTag(keyFor("diamond_tools")) ++ .add(Material.DIAMOND_AXE, Material.DIAMOND_HOE, Material.DIAMOND_PICKAXE, Material.DIAMOND_SHOVEL, Material.DIAMOND_SWORD) ++ .ensureSize("DIAMOND_TOOLS", 5).lock(); ++ ++ /** ++ * Covers all Netherite Tools. ++ */ ++ public static final MaterialSetTag NETHERITE_TOOLS = new MaterialSetTag(keyFor("netherite_tools")) ++ .add(Material.NETHERITE_AXE, Material.NETHERITE_HOE, Material.NETHERITE_PICKAXE, Material.NETHERITE_SHOVEL, Material.NETHERITE_SWORD) ++ .ensureSize("NETHERITE_TOOLS", 5).lock(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/tag/BaseTag.java b/src/main/java/io/papermc/paper/tag/BaseTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..216a40c0c7830ce97b6767d3c70d3b1fd25c0510 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/tag/BaseTag.java +@@ -0,0 +1,184 @@ ++package io.papermc.paper.tag; ++ ++import com.google.common.collect.Lists; ++import java.util.Collections; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Tag; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.Collection; ++import java.util.EnumSet; ++import java.util.HashSet; ++import java.util.List; ++import java.util.Set; ++import java.util.function.Predicate; ++import java.util.stream.Collectors; ++ ++public abstract class BaseTag> implements Tag { ++ ++ protected final NamespacedKey key; ++ protected final Set tagged; ++ private final List> globalPredicates; ++ private boolean locked = false; ++ ++ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Predicate filter) { ++ this(clazz, key); ++ add(filter); ++ } ++ ++ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull T...values) { ++ this(clazz, key, Lists.newArrayList(values)); ++ } ++ ++ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Collection values) { ++ this(clazz, key, values, o -> true); ++ } ++ ++ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Collection values, @NotNull Predicate... globalPredicates) { ++ this.key = key; ++ this.tagged = clazz.isEnum() ? createEnumSet(clazz) : new HashSet<>(); ++ this.tagged.addAll(values); ++ this.globalPredicates = Lists.newArrayList(globalPredicates); ++ } ++ ++ private Set createEnumSet(Class enumClass) { ++ assert enumClass.isEnum(); ++ return (Set) EnumSet.noneOf((Class) enumClass); ++ } ++ ++ public @NotNull C lock() { ++ this.locked = true; ++ return (C) this; ++ } ++ ++ public boolean isLocked() { ++ return this.locked; ++ } ++ ++ private void checkLock() { ++ if (this.locked) { ++ throw new UnsupportedOperationException("Tag (" + this.key + ") is locked"); ++ } ++ } ++ ++ @NotNull ++ @Override ++ public NamespacedKey getKey() { ++ return key; ++ } ++ ++ @NotNull ++ @Override ++ public Set getValues() { ++ return Collections.unmodifiableSet(tagged); ++ } ++ ++ @Override ++ public boolean isTagged(@NotNull T item) { ++ return tagged.contains(item); ++ } ++ ++ @NotNull ++ public C add(@NotNull Tag...tags) { ++ for (Tag tag : tags) { ++ add(tag.getValues()); ++ } ++ return (C) this; ++ } ++ ++ @NotNull ++ public C add(@NotNull T...values) { ++ this.checkLock(); ++ this.tagged.addAll(Lists.newArrayList(values)); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C add(@NotNull Collection collection) { ++ this.checkLock(); ++ this.tagged.addAll(collection); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C add(@NotNull Predicate filter) { ++ return add(getAllPossibleValues().stream().filter(globalPredicates.stream().reduce(Predicate::or).orElse(t -> true)).filter(filter).collect(Collectors.toSet())); ++ } ++ ++ @NotNull ++ public C contains(@NotNull String with) { ++ return add(value -> getName(value).contains(with)); ++ } ++ ++ @NotNull ++ public C endsWith(@NotNull String with) { ++ return add(value -> getName(value).endsWith(with)); ++ } ++ ++ @NotNull ++ public C startsWith(@NotNull String with) { ++ return add(value -> getName(value).startsWith(with)); ++ } ++ ++ @NotNull ++ public C not(@NotNull Tag...tags) { ++ for (Tag tag : tags) { ++ not(tag.getValues()); ++ } ++ return (C) this; ++ } ++ ++ @NotNull ++ public C not(@NotNull T...values) { ++ this.checkLock(); ++ this.tagged.removeAll(Lists.newArrayList(values)); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C not(@NotNull Collection values) { ++ this.checkLock(); ++ this.tagged.removeAll(values); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C not(@NotNull Predicate filter) { ++ not(getAllPossibleValues().stream().filter(globalPredicates.stream().reduce(Predicate::or).orElse(t -> true)).filter(filter).collect(Collectors.toSet())); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C notContains(@NotNull String with) { ++ return not(value -> getName(value).contains(with)); ++ } ++ ++ @NotNull ++ public C notEndsWith(@NotNull String with) { ++ return not(value -> getName(value).endsWith(with)); ++ } ++ ++ @NotNull ++ public C notStartsWith(@NotNull String with) { ++ return not(value -> getName(value).startsWith(with)); ++ } ++ ++ @NotNull ++ public C ensureSize(@NotNull String label, int size) { ++ long actual = this.tagged.stream().filter(globalPredicates.stream().reduce(Predicate::or).orElse(t -> true)).count(); ++ if (size != actual) { ++ throw new IllegalStateException(key.toString() + ": " + label + " - Expected " + size + " values, got " + actual); ++ } ++ return (C) this; ++ } ++ ++ @NotNull ++ @ApiStatus.Internal ++ protected abstract Set getAllPossibleValues(); ++ ++ @NotNull ++ @ApiStatus.Internal ++ protected abstract String getName(@NotNull T value); ++} +diff --git a/src/main/java/io/papermc/paper/tag/EntitySetTag.java b/src/main/java/io/papermc/paper/tag/EntitySetTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c89c4619aaf388197834d98eb95af2f1e93db871 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/tag/EntitySetTag.java +@@ -0,0 +1,42 @@ ++package io.papermc.paper.tag; ++ ++import org.bukkit.NamespacedKey; ++import org.bukkit.entity.EntityType; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.Collection; ++import java.util.Set; ++import java.util.function.Predicate; ++import java.util.stream.Collectors; ++import java.util.stream.Stream; ++ ++public class EntitySetTag extends BaseTag { ++ ++ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Predicate filter) { ++ super(EntityType.class, key, filter); ++ } ++ ++ public EntitySetTag(@NotNull NamespacedKey key, @NotNull EntityType... values) { ++ super(EntityType.class, key, values); ++ } ++ ++ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Collection values) { ++ super(EntityType.class, key, values); ++ } ++ ++ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Collection values, @NotNull Predicate... globalPredicates) { ++ super(EntityType.class, key, values, globalPredicates); ++ } ++ ++ @NotNull ++ @Override ++ protected Set getAllPossibleValues() { ++ return Stream.of(EntityType.values()).collect(Collectors.toSet()); ++ } ++ ++ @NotNull ++ @Override ++ protected String getName(@NotNull EntityType value) { ++ return value.name(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/tag/EntityTags.java b/src/main/java/io/papermc/paper/tag/EntityTags.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bc07aaa5a001f8b58d0603d5db88f9c51064fd27 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/tag/EntityTags.java +@@ -0,0 +1,56 @@ ++package io.papermc.paper.tag; ++ ++import org.bukkit.NamespacedKey; ++ ++import static org.bukkit.entity.EntityType.*; ++ ++/** ++ * All tags in this class are unmodifiable, attempting to modify them will throw an ++ * {@link UnsupportedOperationException}. ++ */ ++public class EntityTags { ++ ++ private static NamespacedKey keyFor(String key) { ++ //noinspection deprecation ++ return new NamespacedKey("paper", key + "_settag"); ++ } ++ ++ /** ++ * Covers undead mobs ++ * @see https://minecraft.wiki/wiki/Mob#Undead_mobs ++ */ ++ public static final EntitySetTag UNDEADS = new EntitySetTag(keyFor("undeads")) ++ .add(DROWNED, HUSK, PHANTOM, SKELETON, SKELETON_HORSE, STRAY, WITHER, WITHER_SKELETON, ZOGLIN, ZOMBIE, ZOMBIE_HORSE, ZOMBIE_VILLAGER, ZOMBIFIED_PIGLIN, BOGGED) ++ .ensureSize("UNDEADS", 14).lock(); ++ ++ /** ++ * Covers all horses ++ */ ++ public static final EntitySetTag HORSES = new EntitySetTag(keyFor("horses")) ++ .contains("HORSE") ++ .ensureSize("HORSES", 3).lock(); ++ ++ /** ++ * Covers all minecarts ++ */ ++ public static final EntitySetTag MINECARTS = new EntitySetTag(keyFor("minecarts")) ++ .contains("MINECART") ++ .ensureSize("MINECARTS", 7).lock(); ++ ++ /** ++ * Covers mobs that split into smaller mobs ++ */ ++ public static final EntitySetTag SPLITTING_MOBS = new EntitySetTag(keyFor("splitting_mobs")) ++ .add(SLIME, MAGMA_CUBE) ++ .ensureSize("SLIMES", 2).lock(); ++ ++ /** ++ * Covers all water based mobs ++ * @see https://minecraft.wiki/wiki/Mob#Aquatic_mobs ++ * @deprecated in favour of {@link org.bukkit.Tag#ENTITY_TYPES_AQUATIC} ++ */ ++ @Deprecated ++ public static final EntitySetTag WATER_BASED = new EntitySetTag(keyFor("water_based")) ++ .add(AXOLOTL, DOLPHIN, SQUID, GLOW_SQUID, GUARDIAN, ELDER_GUARDIAN, TURTLE, COD, SALMON, PUFFERFISH, TROPICAL_FISH, TADPOLE) ++ .ensureSize("WATER_BASED", 12).lock(); ++} +diff --git a/src/main/java/org/bukkit/Tag.java b/src/main/java/org/bukkit/Tag.java +index fb7d8bb34561ef686c2b53175ba55b4b72a82674..8420fb1c6059ea9f782a47d18c465ba515765085 100644 +--- a/src/main/java/org/bukkit/Tag.java ++++ b/src/main/java/org/bukkit/Tag.java +@@ -11,6 +11,10 @@ import org.jetbrains.annotations.NotNull; + * Note that whilst all tags defined within this interface must be present in + * implementations, their existence is not guaranteed across future versions. + * ++ *

      Custom tags defined by Paper are not present (as constants) in this class. ++ * To access them please refer to {@link com.destroystokyo.paper.MaterialTags} ++ * and {@link io.papermc.paper.tag.EntityTags}.

      ++ * + * @param the type of things grouped by this tag + */ + public interface Tag extends Keyed { +diff --git a/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java b/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..82ee9a486d1c3deec6e529b1cb12ecc2c6a5862e +--- /dev/null ++++ b/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License ++ */ ++ ++package com.destroystokyo.paper; ++ ++import io.papermc.paper.tag.BaseTag; ++import io.papermc.paper.tag.EntityTags; ++import java.lang.reflect.Field; ++import java.lang.reflect.Modifier; ++import java.util.HashSet; ++import java.util.Set; ++import java.util.logging.Level; ++import org.bukkit.Bukkit; ++import org.bukkit.support.AbstractTestingBase; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertTrue; ++ ++public class MaterialTagsTest extends AbstractTestingBase { ++ ++ @Test ++ public void testInitialize() { ++ try { ++ MaterialTags.SHULKER_BOXES.getValues(); ++ assert true; ++ } catch (Throwable e) { ++ Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e); ++ assert false; ++ } ++ } ++ ++ @Test ++ public void testLocked() { ++ testLocked(MaterialTags.class); ++ testLocked(EntityTags.class); ++ } ++ ++ private static void testLocked(Class clazz) { ++ for (BaseTag tag : collectTags(clazz)) { ++ assertTrue(tag.isLocked(), "Tag " + tag.key() + " is not locked"); ++ } ++ } ++ ++ private static Set> collectTags(Class clazz) { ++ Set> tags = new HashSet<>(); ++ try { ++ for (Field field : clazz.getDeclaredFields()) { ++ if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && BaseTag.class.isAssignableFrom(field.getType())) { ++ tags.add((BaseTag) field.get(null)); ++ } ++ } ++ } catch (IllegalAccessException e) { ++ e.printStackTrace(); ++ } ++ return tags; ++ } ++} +diff --git a/src/test/java/io/papermc/paper/EntityTagsTest.java b/src/test/java/io/papermc/paper/EntityTagsTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..91d70cc703192b5a3a48211ee0dadd2e4260ec00 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/EntityTagsTest.java +@@ -0,0 +1,21 @@ ++package io.papermc.paper; ++ ++import io.papermc.paper.tag.EntityTags; ++import java.util.logging.Level; ++import org.bukkit.Bukkit; ++import org.bukkit.support.AbstractTestingBase; ++import org.junit.jupiter.api.Test; ++ ++public class EntityTagsTest extends AbstractTestingBase { ++ ++ @Test ++ public void testInitialize() { ++ try { ++ EntityTags.HORSES.getValues(); ++ assert true; ++ } catch (Throwable e) { ++ Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e); ++ assert false; ++ } ++ } ++} diff --git a/patches/api/0147-Add-ray-tracing-methods-to-LivingEntity.patch b/patches/api/0147-Add-ray-tracing-methods-to-LivingEntity.patch deleted file mode 100644 index b3732ab33f3a..000000000000 --- a/patches/api/0147-Add-ray-tracing-methods-to-LivingEntity.patch +++ /dev/null @@ -1,148 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 3 Sep 2018 18:13:53 -0500 -Subject: [PATCH] Add ray tracing methods to LivingEntity - - -diff --git a/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java b/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java -new file mode 100644 -index 0000000000000000000000000000000000000000..18a96dbb01d3b34476652264b2d6be3782a154ec ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java -@@ -0,0 +1,54 @@ -+package com.destroystokyo.paper.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.block.BlockFace; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Represents information about a targeted block -+ */ -+public class TargetBlockInfo { -+ private final Block block; -+ private final BlockFace blockFace; -+ -+ public TargetBlockInfo(@NotNull Block block, @NotNull BlockFace blockFace) { -+ this.block = block; -+ this.blockFace = blockFace; -+ } -+ -+ /** -+ * Get the block that is targeted -+ * -+ * @return Targeted block -+ */ -+ @NotNull -+ public Block getBlock() { -+ return block; -+ } -+ -+ /** -+ * Get the targeted BlockFace -+ * -+ * @return Targeted blockface -+ */ -+ @NotNull -+ public BlockFace getBlockFace() { -+ return blockFace; -+ } -+ -+ /** -+ * Get the relative Block to the targeted block on the side it is targeted at -+ * -+ * @return Block relative to targeted block -+ */ -+ @NotNull -+ public Block getRelativeBlock() { -+ return block.getRelative(blockFace); -+ } -+ -+ public enum FluidMode { -+ NEVER, -+ SOURCE_ONLY, -+ ALWAYS -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index 1dd9f7ac1f26c253b8181519aa1873784bc54a07..a4b1ae0caea94882f601a0420354838c6a52ef28 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -81,6 +81,77 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - @NotNull - public Block getTargetBlock(@Nullable Set transparent, int maxDistance); - -+ // Paper start -+ /** -+ * Gets the block that the living entity has targeted, ignoring fluids -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @return block that the living entity has targeted, -+ * or null if no block is within maxDistance -+ */ -+ @Nullable -+ public default Block getTargetBlock(int maxDistance) { -+ return getTargetBlock(maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode.NEVER); -+ } -+ -+ /** -+ * Gets the block that the living entity has targeted -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @param fluidMode whether to check fluids or not -+ * @return block that the living entity has targeted, -+ * or null if no block is within maxDistance -+ */ -+ @Nullable -+ public Block getTargetBlock(int maxDistance, @NotNull com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode); -+ -+ /** -+ * Gets the blockface of that block that the living entity has targeted, ignoring fluids -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @return blockface of the block that the living entity has targeted, -+ * or null if no block is targeted -+ */ -+ @Nullable -+ public default org.bukkit.block.BlockFace getTargetBlockFace(int maxDistance) { -+ return getTargetBlockFace(maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode.NEVER); -+ } -+ -+ /** -+ * Gets the blockface of that block that the living entity has targeted -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @param fluidMode whether to check fluids or not -+ * @return blockface of the block that the living entity has targeted, -+ * or null if no block is targeted -+ */ -+ @Nullable -+ public org.bukkit.block.BlockFace getTargetBlockFace(int maxDistance, @NotNull com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode); -+ -+ /** -+ * Gets information about the block the living entity has targeted, ignoring fluids -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @return TargetBlockInfo about the block the living entity has targeted, -+ * or null if no block is targeted -+ */ -+ @Nullable -+ public default com.destroystokyo.paper.block.TargetBlockInfo getTargetBlockInfo(int maxDistance) { -+ return getTargetBlockInfo(maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode.NEVER); -+ } -+ -+ /** -+ * Gets information about the block the living entity has targeted -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @param fluidMode whether to check fluids or not -+ * @return TargetBlockInfo about the block the living entity has targeted, -+ * or null if no block is targeted -+ */ -+ @Nullable -+ public com.destroystokyo.paper.block.TargetBlockInfo getTargetBlockInfo(int maxDistance, @NotNull com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode); -+ // Paper end -+ - /** - * Gets the last two blocks along the living entity's line of sight. - *

      diff --git a/patches/api/0148-Expose-attack-cooldown-methods-for-Player.patch b/patches/api/0148-Expose-attack-cooldown-methods-for-Player.patch deleted file mode 100644 index 4bc983ddf1f3..000000000000 --- a/patches/api/0148-Expose-attack-cooldown-methods-for-Player.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Tue, 4 Sep 2018 15:01:54 -0500 -Subject: [PATCH] Expose attack cooldown methods for Player - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 5093a978dd44f0e6e14af7d8e12b50b602f0b2bd..f218b1dd0b0ae97a6ccc0f88adcde7cc167432a9 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -2461,6 +2461,26 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @param profile The new profile to use - */ - void setPlayerProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile); -+ -+ /** -+ * Returns the amount of ticks the current cooldown lasts -+ * -+ * @return Amount of ticks cooldown will last -+ */ -+ float getCooldownPeriod(); -+ -+ /** -+ * Returns the percentage of attack power available based on the cooldown (zero to one). -+ * -+ * @param adjustTicks Amount of ticks to add to cooldown counter for this calculation -+ * @return Percentage of attack power available -+ */ -+ float getCooledAttackStrength(float adjustTicks); -+ -+ /** -+ * Reset the cooldown counter to 0, effectively starting the cooldown period. -+ */ -+ void resetCooldown(); - // Paper end - - // Spigot start diff --git a/patches/api/0148-PreSpawnerSpawnEvent.patch b/patches/api/0148-PreSpawnerSpawnEvent.patch new file mode 100644 index 000000000000..ffdc677b643d --- /dev/null +++ b/patches/api/0148-PreSpawnerSpawnEvent.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 +Date: Tue, 18 Sep 2018 23:50:10 +0100 +Subject: [PATCH] PreSpawnerSpawnEvent + +This adds a separate event before an entity is spawned by a spawner +which contains the location of the spawner too similarly to how the +SpawnerSpawnEvent gets called instead of the CreatureSpawnEvent for +spawners. + +Dropped as it does not apply due to the earlier PreCreatureSpawnEvent patch not being applied + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..679b37056be9515c69922285affbf0301f5335e3 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java +@@ -0,0 +1,29 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.Location; ++import org.bukkit.entity.EntityType; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called before an entity is spawned into a world by a spawner. ++ *

      ++ * This only includes the spawner's location and not the full BlockState snapshot for performance reasons. ++ * If you really need it you have to get the spawner yourself. ++ */ ++@NullMarked ++public class PreSpawnerSpawnEvent extends PreCreatureSpawnEvent { ++ ++ private final Location spawnerLocation; ++ ++ @ApiStatus.Internal ++ public PreSpawnerSpawnEvent(final Location location, final EntityType type, final Location spawnerLocation) { ++ super(location, type, CreatureSpawnEvent.SpawnReason.SPAWNER); ++ this.spawnerLocation = spawnerLocation; ++ } ++ ++ public Location getSpawnerLocation() { ++ return this.spawnerLocation.clone(); ++ } ++} diff --git a/patches/api/0149-Add-LivingEntity-getTargetEntity.patch b/patches/api/0149-Add-LivingEntity-getTargetEntity.patch new file mode 100644 index 000000000000..0a684b4e75f7 --- /dev/null +++ b/patches/api/0149-Add-LivingEntity-getTargetEntity.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 22 Sep 2018 00:32:53 -0500 +Subject: [PATCH] Add LivingEntity#getTargetEntity + + +diff --git a/src/main/java/com/destroystokyo/paper/entity/TargetEntityInfo.java b/src/main/java/com/destroystokyo/paper/entity/TargetEntityInfo.java +new file mode 100644 +index 0000000000000000000000000000000000000000..caa56541c435a3d9103cb0220ab88563a976c6b8 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/TargetEntityInfo.java +@@ -0,0 +1,40 @@ ++package com.destroystokyo.paper.entity; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.util.Vector; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents information about a targeted entity ++ * @deprecated use {@link org.bukkit.util.RayTraceResult} ++ */ ++@Deprecated(forRemoval = true, since = "1.19.3") ++public class TargetEntityInfo { ++ private final Entity entity; ++ private final Vector hitVec; ++ ++ public TargetEntityInfo(@NotNull Entity entity, @NotNull Vector hitVec) { ++ this.entity = entity; ++ this.hitVec = hitVec; ++ } ++ ++ /** ++ * Get the entity that is targeted ++ * ++ * @return Targeted entity ++ */ ++ @NotNull ++ public Entity getEntity() { ++ return entity; ++ } ++ ++ /** ++ * Get the position the entity is targeted at ++ * ++ * @return Targeted position ++ */ ++ @NotNull ++ public Vector getHitVector() { ++ return hitVec; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 9ffa42e3d241dd209813cea993c8fcda72f1a935..775f18abe007edc73ed60eb45f84bd79912f9331 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -175,6 +175,77 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + @Deprecated(forRemoval = true, since = "1.19.3") + @Nullable + public com.destroystokyo.paper.block.TargetBlockInfo getTargetBlockInfo(int maxDistance, @NotNull com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode); ++ ++ /** ++ * Gets information about the entity being targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @return entity being targeted, or null if no entity is targeted ++ */ ++ @Nullable ++ public default Entity getTargetEntity(int maxDistance) { ++ return getTargetEntity(maxDistance, false); ++ } ++ ++ /** ++ * Gets information about the entity being targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @param ignoreBlocks true to scan through blocks ++ * @return entity being targeted, or null if no entity is targeted ++ */ ++ @Nullable ++ public Entity getTargetEntity(int maxDistance, boolean ignoreBlocks); ++ ++ /** ++ * Gets information about the entity being targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @return TargetEntityInfo about the entity being targeted, ++ * or null if no entity is targeted ++ * @deprecated use {@link #rayTraceEntities(int)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.3") ++ @Nullable ++ public default com.destroystokyo.paper.entity.TargetEntityInfo getTargetEntityInfo(int maxDistance) { ++ return getTargetEntityInfo(maxDistance, false); ++ } ++ ++ /** ++ * Gets information about the entity being targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @return RayTraceResult about the entity being targeted, ++ * or null if no entity is targeted ++ */ ++ @Nullable ++ default RayTraceResult rayTraceEntities(int maxDistance) { ++ return this.rayTraceEntities(maxDistance, false); ++ } ++ ++ /** ++ * Gets information about the entity being targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @param ignoreBlocks true to scan through blocks ++ * @return TargetEntityInfo about the entity being targeted, ++ * or null if no entity is targeted ++ * @deprecated use {@link #rayTraceEntities(int, boolean)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.3") ++ @Nullable ++ public com.destroystokyo.paper.entity.TargetEntityInfo getTargetEntityInfo(int maxDistance, boolean ignoreBlocks); ++ ++ /** ++ * Gets information about the entity being targeted ++ * ++ * @param maxDistance this is the maximum distance to scan ++ * @param ignoreBlocks true to scan through blocks ++ * @return RayTraceResult about the entity being targeted, ++ * or null if no entity is targeted ++ */ ++ @Nullable ++ RayTraceResult rayTraceEntities(int maxDistance, boolean ignoreBlocks); + // Paper end + + /** diff --git a/patches/api/0149-Improve-death-events.patch b/patches/api/0149-Improve-death-events.patch deleted file mode 100644 index 7cad311edea9..000000000000 --- a/patches/api/0149-Improve-death-events.patch +++ /dev/null @@ -1,203 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Tue, 21 Aug 2018 01:32:28 +0100 -Subject: [PATCH] Improve death events - -This adds the ability to cancel the death events and to modify the sound -an entity makes when dying. (In cases were no sound should it will be -called with shouldPlaySound set to false allowing unsilencing of silent -entities) - -It makes handling of entity deaths a lot nicer as you no longer need -to listen on the damage event and calculate if the entity dies yourself -to cancel the death which has the benefit of also receiving the dropped -items and experience which is otherwise only properly possible by using -internal code. - -diff --git a/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java -index a5984ab06cce95d30e70511e125f69339b574c04..e19a3df9aa2204b44c0b029bda141ae6306f60a1 100644 ---- a/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java -+++ b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java -@@ -5,14 +5,24 @@ import org.bukkit.entity.LivingEntity; - import org.bukkit.event.HandlerList; - import org.bukkit.inventory.ItemStack; - import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; - - /** - * Thrown whenever a LivingEntity dies - */ --public class EntityDeathEvent extends EntityEvent { -+public class EntityDeathEvent extends EntityEvent implements org.bukkit.event.Cancellable { // Paper - make cancellable - private static final HandlerList handlers = new HandlerList(); - private final List drops; - private int dropExp = 0; -+ // Paper start - make cancellable -+ private boolean cancelled; -+ private double reviveHealth = 0; -+ private boolean shouldPlayDeathSound; -+ @Nullable private org.bukkit.Sound deathSound; -+ @Nullable private org.bukkit.SoundCategory deathSoundCategory; -+ private float deathSoundVolume; -+ private float deathSoundPitch; -+ // Paper end - - public EntityDeathEvent(@NotNull final LivingEntity entity, @NotNull final List drops) { - this(entity, drops, 0); -@@ -74,4 +84,134 @@ public class EntityDeathEvent extends EntityEvent { - public static HandlerList getHandlerList() { - return handlers; - } -+ -+ // Paper start - make cancellable -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ /** -+ * Get the amount of health that the entity should revive with after cancelling the event. -+ * Set to the entity's max health by default. -+ * -+ * @return The amount of health -+ */ -+ public double getReviveHealth() { -+ return reviveHealth; -+ } -+ -+ /** -+ * Set the amount of health that the entity should revive with after cancelling the event. -+ * Revive health value must be between 0 (exclusive) and the entity's max health (inclusive). -+ * -+ * @param reviveHealth The amount of health -+ * @throws IllegalArgumentException Thrown if the health is {@literal <= 0 or >} max health -+ */ -+ public void setReviveHealth(double reviveHealth) throws IllegalArgumentException { -+ double maxHealth = ((LivingEntity) entity).getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue(); -+ if ((maxHealth != 0 && reviveHealth <= 0) || (reviveHealth > maxHealth)) { -+ throw new IllegalArgumentException("Health must be between 0 (exclusive) and " + maxHealth + " (inclusive), but was " + reviveHealth); -+ } -+ this.reviveHealth = reviveHealth; -+ } -+ -+ -+ /** -+ * Whether or not the death sound should play when the entity dies. If the event is cancelled it does not play! -+ * -+ * @return Whether or not the death sound should play. Event is called with this set to false if the entity is silent. -+ */ -+ public boolean shouldPlayDeathSound() { -+ return shouldPlayDeathSound; -+ } -+ -+ /** -+ * Set whether or not the death sound should play when the entity dies. If the event is cancelled it does not play! -+ * -+ * @param playDeathSound Enable or disable the death sound -+ */ -+ public void setShouldPlayDeathSound(boolean playDeathSound) { -+ this.shouldPlayDeathSound = playDeathSound; -+ } -+ -+ /** -+ * Get the sound that the entity makes when dying -+ * -+ * @return The sound that the entity makes -+ */ -+ @Nullable -+ public org.bukkit.Sound getDeathSound() { -+ return deathSound; -+ } -+ -+ /** -+ * Set the sound that the entity makes when dying -+ * -+ * @param sound The sound that the entity should make when dying -+ */ -+ public void setDeathSound(@Nullable org.bukkit.Sound sound) { -+ deathSound = sound; -+ } -+ -+ /** -+ * Get the sound category that the death sound should play in -+ * -+ * @return The sound category -+ */ -+ @Nullable -+ public org.bukkit.SoundCategory getDeathSoundCategory() { -+ return deathSoundCategory; -+ } -+ -+ /** -+ * Set the sound category that the death sound should play in. -+ * -+ * @param soundCategory The sound category -+ */ -+ public void setDeathSoundCategory(@Nullable org.bukkit.SoundCategory soundCategory) { -+ this.deathSoundCategory = soundCategory; -+ } -+ -+ /** -+ * Get the volume that the death sound will play at. -+ * -+ * @return The volume the death sound will play at -+ */ -+ public float getDeathSoundVolume() { -+ return deathSoundVolume; -+ } -+ -+ /** -+ * Set the volume the death sound should play at. If the event is cancelled this will not play the sound! -+ * -+ * @param volume The volume the death sound should play at -+ */ -+ public void setDeathSoundVolume(float volume) { -+ this.deathSoundVolume = volume; -+ } -+ -+ /** -+ * Get the pitch that the death sound will play with. -+ * -+ * @return The pitch the death sound will play with -+ */ -+ public float getDeathSoundPitch() { -+ return deathSoundPitch; -+ } -+ -+ /** -+ * GSetet the pitch that the death sound should play with. -+ * -+ * @param pitch The pitch the death sound should play with -+ */ -+ public void setDeathSoundPitch(float pitch) { -+ this.deathSoundPitch = pitch; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -index 7941c60b0e1840785ba2b250071591bd75bc6e35..a871eddf73f918c0e3d2554ef8d9cfd0f830fcaa 100644 ---- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -+++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -@@ -63,6 +63,17 @@ public class PlayerDeathEvent extends EntityDeathEvent { - } - - // Paper start -+ /** -+ * Clarity method for getting the player. Not really needed except -+ * for reasons of clarity. -+ * -+ * @return Player who is involved in this event -+ */ -+ @NotNull -+ public Player getPlayer() { -+ return getEntity(); -+ } -+ - /** - * Set the death message that will appear to everyone on the server. - * diff --git a/patches/api/0150-Add-Git-information-to-version-command-on-startup.patch b/patches/api/0150-Add-Git-information-to-version-command-on-startup.patch deleted file mode 100644 index 29ee37a8b182..000000000000 --- a/patches/api/0150-Add-Git-information-to-version-command-on-startup.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Professor Bloodstone -Date: Sun, 20 Jun 2021 01:48:31 +0200 -Subject: [PATCH] Add Git information to version command/on startup - - -diff --git a/src/main/java/io/papermc/paper/util/JarManifests.java b/src/main/java/io/papermc/paper/util/JarManifests.java -new file mode 100644 -index 0000000000000000000000000000000000000000..909617079db61b675cc7b60b44ef96b306076343 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/util/JarManifests.java -@@ -0,0 +1,37 @@ -+package io.papermc.paper.util; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.net.URL; -+import java.util.Collections; -+import java.util.Map; -+import java.util.WeakHashMap; -+import java.util.jar.Manifest; -+import org.jetbrains.annotations.ApiStatus; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+@ApiStatus.Internal -+public final class JarManifests { -+ private JarManifests() { -+ } -+ -+ private static final Map MANIFESTS = Collections.synchronizedMap(new WeakHashMap<>()); -+ -+ public static @Nullable Manifest manifest(final @NotNull Class clazz) { -+ return MANIFESTS.computeIfAbsent(clazz.getClassLoader(), classLoader -> { -+ final String classLocation = "/" + clazz.getName().replace(".", "/") + ".class"; -+ final URL resource = clazz.getResource(classLocation); -+ if (resource == null) { -+ return null; -+ } -+ final String classFilePath = resource.toString().replace("\\", "/"); -+ final String archivePath = classFilePath.substring(0, classFilePath.length() - classLocation.length()); -+ try (final InputStream stream = new URL(archivePath + "/META-INF/MANIFEST.MF").openStream()) { -+ return new Manifest(stream); -+ } catch (final IOException ex) { -+ return null; -+ } -+ }); -+ } -+} -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 098a09baa481f76e63991268d3dfabc413626fcf..653fe32bd134945e1cb1cf40f2623ffffdf5d762 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -53,6 +53,7 @@ import org.bukkit.util.CachedServerIcon; - import org.jetbrains.annotations.Contract; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; -+import io.papermc.paper.util.JarManifests; // Paper - - /** - * Represents the Bukkit core, for version and Server singleton handling -@@ -102,7 +103,25 @@ public final class Bukkit { - } - - Bukkit.server = server; -- server.getLogger().info("This server is running " + getName() + " version " + getVersion() + " (Implementing API version " + getBukkitVersion() + ")"); -+ // Paper start - add git information -+ server.getLogger().info(getVersionMessage()); -+ } -+ /** -+ * Gets message describing the version server is running. -+ * -+ * @return message describing the version server is running -+ */ -+ @NotNull -+ public static String getVersionMessage() { -+ final var manifest = JarManifests.manifest(Bukkit.getServer().getClass()); -+ final String gitBranch = manifest == null ? null : manifest.getMainAttributes().getValue("Git-Branch"); -+ final String gitCommit = manifest == null ? null : manifest.getMainAttributes().getValue("Git-Commit"); -+ String branchMsg = " on " + gitBranch; -+ if ("master".equals(gitBranch) || "main".equals(gitBranch)) { -+ branchMsg = ""; // Don't show branch on main/master -+ } -+ return "This server is running " + getName() + " version " + getVersion() + " (Implementing API version " + getBukkitVersion() + ") (Git: " + gitCommit + branchMsg + ")"; -+ // Paper end - } - - /** -diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java -index b50f614806f4634960d383e8a33f094c2f46935f..e40f017f87d6b6b4770501b106c76dc69ec69abb 100644 ---- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java -+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java -@@ -240,7 +240,7 @@ public class VersionCommand extends BukkitCommand { - private void setVersionMessage(final @NotNull net.kyori.adventure.text.Component msg) { - lastCheck = System.currentTimeMillis(); - final net.kyori.adventure.text.Component message = net.kyori.adventure.text.TextComponent.ofChildren( -- net.kyori.adventure.text.Component.text("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")", net.kyori.adventure.text.format.NamedTextColor.WHITE), -+ net.kyori.adventure.text.Component.text(Bukkit.getVersionMessage(), net.kyori.adventure.text.format.NamedTextColor.WHITE), - net.kyori.adventure.text.Component.newline(), - msg - ); diff --git a/patches/api/0150-Add-sun-related-API.patch b/patches/api/0150-Add-sun-related-API.patch new file mode 100644 index 000000000000..e8ac87454d71 --- /dev/null +++ b/patches/api/0150-Add-sun-related-API.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 7 Oct 2018 00:54:15 -0500 +Subject: [PATCH] Add sun related API + + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 9517091f601f362f80ff6062f53eff760f040e6c..10e9981c9068c39dfdda5c9f82558d481288a8c6 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -1835,6 +1835,16 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + */ + public void setFullTime(long time); + ++ // Paper start ++ ++ /** ++ * Check if it is currently daytime in this world ++ * ++ * @return True if it is daytime ++ */ ++ public boolean isDayTime(); ++ // Paper end ++ + /** + * Gets the full in-game time on this world since the world generation + * +diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java +index 63a14bec00d0b23431d1d002139f48a7d0bc2a88..ef89a82669a6c5bf911827b90facf36a2ff26e91 100644 +--- a/src/main/java/org/bukkit/entity/Mob.java ++++ b/src/main/java/org/bukkit/entity/Mob.java +@@ -20,6 +20,13 @@ public interface Mob extends LivingEntity, Lootable { + */ + @NotNull + com.destroystokyo.paper.entity.Pathfinder getPathfinder(); ++ ++ /** ++ * Check if this mob is exposed to daylight ++ * ++ * @return True if mob is exposed to daylight ++ */ ++ boolean isInDaylight(); + // Paper end + /** + * Instructs this Mob to set the specified LivingEntity as its target. diff --git a/patches/api/0151-Mob-Pathfinding-API.patch b/patches/api/0151-Mob-Pathfinding-API.patch deleted file mode 100644 index 9d4bbc82aaef..000000000000 --- a/patches/api/0151-Mob-Pathfinding-API.patch +++ /dev/null @@ -1,257 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 9 Sep 2018 12:39:06 -0400 -Subject: [PATCH] Mob Pathfinding API - -Adds an API to allow plugins to instruct a Mob to Pathfind to a Location or Entity - -This does not do anything to stop other AI rules from changing the location, so -it is still up to the plugin to control that or override after another goal changed -the location. - -You can use EntityPathfindEvent to cancel new pathfinds from overriding your current. - -diff --git a/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java b/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java -new file mode 100644 -index 0000000000000000000000000000000000000000..43f062257472a06e9e64c2feef6c3b1012aee00e ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java -@@ -0,0 +1,212 @@ -+package com.destroystokyo.paper.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.entity.Mob; -+ -+import java.util.List; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Handles pathfinding operations for an Entity -+ */ -+public interface Pathfinder { -+ -+ /** -+ * -+ * @return The entity that is controlled by this pathfinder -+ */ -+ @NotNull -+ Mob getEntity(); -+ -+ /** -+ * Instructs the Entity to stop trying to navigate to its current desired location -+ */ -+ void stopPathfinding(); -+ -+ /** -+ * If the entity is currently trying to navigate to a destination, this will return true -+ * @return true if the entity is navigating to a destination -+ */ -+ boolean hasPath(); -+ -+ /** -+ * @return The location the entity is trying to navigate to, or null if there is no destination -+ */ -+ @Nullable -+ PathResult getCurrentPath(); -+ -+ /** -+ * Calculates a destination for the Entity to navigate to, but does not set it -+ * as the current target. Useful for calculating what would happen before setting it. -+ * @param loc Location to navigate to -+ * @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated -+ */ -+ @Nullable PathResult findPath(@NotNull Location loc); -+ -+ /** -+ * Calculates a destination for the Entity to navigate to to reach the target entity, -+ * but does not set it as the current target. -+ * Useful for calculating what would happen before setting it. -+ * -+ * The behavior of this PathResult is subject to the games pathfinding rules, and may -+ * result in the pathfinding automatically updating to follow the target Entity. -+ * -+ * However, this behavior is not guaranteed, and is subject to the games behavior. -+ * -+ * @param target the Entity to navigate to -+ * @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated -+ */ -+ @Nullable PathResult findPath(@NotNull LivingEntity target); -+ -+ /** -+ * Calculates a destination for the Entity to navigate to, and sets it with default speed -+ * as the current target. -+ * @param loc Location to navigate to -+ * @return If the pathfinding was successfully started -+ */ -+ default boolean moveTo(@NotNull Location loc) { -+ return moveTo(loc, 1); -+ } -+ -+ /** -+ * Calculates a destination for the Entity to navigate to, with desired speed -+ * as the current target. -+ * @param loc Location to navigate to -+ * @param speed Speed multiplier to navigate at, where 1 is 'normal' -+ * @return If the pathfinding was successfully started -+ */ -+ default boolean moveTo(@NotNull Location loc, double speed) { -+ PathResult path = findPath(loc); -+ return path != null && moveTo(path, speed); -+ } -+ -+ /** -+ * Calculates a destination for the Entity to navigate to to reach the target entity, -+ * and sets it with default speed. -+ * -+ * The behavior of this PathResult is subject to the games pathfinding rules, and may -+ * result in the pathfinding automatically updating to follow the target Entity. -+ * -+ * However, this behavior is not guaranteed, and is subject to the games behavior. -+ * -+ * @param target the Entity to navigate to -+ * @return If the pathfinding was successfully started -+ */ -+ default boolean moveTo(@NotNull LivingEntity target) { -+ return moveTo(target, 1); -+ } -+ -+ /** -+ * Calculates a destination for the Entity to navigate to to reach the target entity, -+ * and sets it with specified speed. -+ * -+ * The behavior of this PathResult is subject to the games pathfinding rules, and may -+ * result in the pathfinding automatically updating to follow the target Entity. -+ * -+ * However, this behavior is not guaranteed, and is subject to the games behavior. -+ * -+ * @param target the Entity to navigate to -+ * @param speed Speed multiplier to navigate at, where 1 is 'normal' -+ * @return If the pathfinding was successfully started -+ */ -+ default boolean moveTo(@NotNull LivingEntity target, double speed) { -+ PathResult path = findPath(target); -+ return path != null && moveTo(path, speed); -+ } -+ -+ /** -+ * Takes the result of a previous pathfinding calculation and sets it -+ * as the active pathfinding with default speed. -+ * -+ * @param path The Path to start following -+ * @return If the pathfinding was successfully started -+ */ -+ default boolean moveTo(@NotNull PathResult path) { -+ return moveTo(path, 1); -+ } -+ -+ /** -+ * Takes the result of a previous pathfinding calculation and sets it -+ * as the active pathfinding, -+ * -+ * @param path The Path to start following -+ * @param speed Speed multiplier to navigate at, where 1 is 'normal' -+ * @return If the pathfinding was successfully started -+ */ -+ boolean moveTo(@NotNull PathResult path, double speed); -+ -+ /** -+ * Checks if this pathfinder allows passing through closed doors. -+ * -+ * @return if this pathfinder allows passing through closed doors -+ */ -+ boolean canOpenDoors(); -+ -+ /** -+ * Allows this pathfinder to pass through closed doors, or not -+ * -+ * @param canOpenDoors if the mob can pass through closed doors, or not -+ */ -+ void setCanOpenDoors(boolean canOpenDoors); -+ -+ /** -+ * Checks if this pathfinder allows passing through open doors. -+ * -+ * @return if this pathfinder allows passing through open doors -+ */ -+ boolean canPassDoors(); -+ -+ /** -+ * Allows this pathfinder to pass through open doors, or not -+ * -+ * @param canPassDoors if the mob can pass through open doors, or not -+ */ -+ void setCanPassDoors(boolean canPassDoors); -+ -+ /** -+ * Checks if this pathfinder assumes that the mob can float -+ * -+ * @return if this pathfinder assumes that the mob can float -+ */ -+ boolean canFloat(); -+ -+ /** -+ * Makes this pathfinder assume that the mob can float, or not -+ * -+ * @param canFloat if the mob can float, or not -+ */ -+ void setCanFloat(boolean canFloat); -+ -+ /** -+ * Represents the result of a pathfinding calculation -+ */ -+ interface PathResult { -+ -+ /** -+ * All currently calculated points to follow along the path to reach the destination location -+ * -+ * Will return points the entity has already moved past, see {@link #getNextPointIndex()} -+ * @return List of points -+ */ -+ @NotNull -+ List getPoints(); -+ -+ /** -+ * @return Returns the index of the current point along the points returned in {@link #getPoints()} the entity -+ * is trying to reach. This value will be higher than the maximum index of {@link #getPoints()} if this path finding is done. -+ */ -+ int getNextPointIndex(); -+ -+ /** -+ * @return The next location in the path points the entity is trying to reach, or null if there is no next point -+ */ -+ @Nullable Location getNextPoint(); -+ -+ /** -+ * @return The closest point the path can get to the target location -+ */ -+ @Nullable Location getFinalPoint(); -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java -index 0514a141cb93a650be38c63d4336d46e4304f4b6..cc30b4e22ee238de13f031398fc566f4123694ff 100644 ---- a/src/main/java/org/bukkit/entity/Mob.java -+++ b/src/main/java/org/bukkit/entity/Mob.java -@@ -1,6 +1,7 @@ - package org.bukkit.entity; - - import org.bukkit.loot.Lootable; -+import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; - - /** -@@ -11,6 +12,13 @@ public interface Mob extends LivingEntity, Lootable { - // Paper start - @Override - org.bukkit.inventory.@org.jetbrains.annotations.NotNull EntityEquipment getEquipment(); -+ -+ /** -+ * Enables access to control the pathing of an Entity -+ * @return Pathfinding Manager for this entity -+ */ -+ @NotNull -+ com.destroystokyo.paper.entity.Pathfinder getPathfinder(); - // Paper end - /** - * Instructs this Mob to set the specified LivingEntity as its target. diff --git a/patches/api/0151-Turtle-API.patch b/patches/api/0151-Turtle-API.patch new file mode 100644 index 000000000000..1d29a1055ba6 --- /dev/null +++ b/patches/api/0151-Turtle-API.patch @@ -0,0 +1,288 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 28 Sep 2018 17:08:09 -0500 +Subject: [PATCH] Turtle API + + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..91cede0e53cf6f1089e549053ebc2e2b190a1aab +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java +@@ -0,0 +1,53 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.Turtle; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a Turtle decides to go home ++ */ ++@NullMarked ++public class TurtleGoHomeEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public TurtleGoHomeEvent(final Turtle turtle) { ++ super(turtle); ++ } ++ ++ /** ++ * The turtle going home ++ * ++ * @return The turtle ++ */ ++ @Override ++ public Turtle getEntity() { ++ return (Turtle) super.getEntity(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1492d168aa1dc538b732b0ff262074cc7c9900e6 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java +@@ -0,0 +1,90 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.Location; ++import org.bukkit.entity.Turtle; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a Turtle lays eggs ++ */ ++@NullMarked ++public class TurtleLayEggEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Location location; ++ private int eggCount; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public TurtleLayEggEvent(final Turtle turtle, final Location location, final int eggCount) { ++ super(turtle); ++ this.location = location; ++ this.eggCount = eggCount; ++ } ++ ++ /** ++ * The turtle laying the eggs ++ * ++ * @return The turtle ++ */ ++ @Override ++ public Turtle getEntity() { ++ return (Turtle) super.getEntity(); ++ } ++ ++ /** ++ * Get the location where the eggs are being laid ++ * ++ * @return Location of eggs ++ */ ++ public Location getLocation() { ++ return this.location.clone(); ++ } ++ ++ /** ++ * Get the number of eggs being laid ++ * ++ * @return Number of eggs ++ */ ++ public int getEggCount() { ++ return this.eggCount; ++ } ++ ++ /** ++ * Set the number of eggs being laid ++ * ++ * @param eggCount Number of eggs ++ */ ++ public void setEggCount(final int eggCount) { ++ if (eggCount < 1) { ++ this.cancelled = true; ++ return; ++ } ++ this.eggCount = Math.min(eggCount, 4); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a84101fb1b478f3018f283bc47d3e73a7ae5bbc8 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java +@@ -0,0 +1,65 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.Location; ++import org.bukkit.entity.Turtle; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a Turtle starts digging to lay eggs ++ */ ++@NullMarked ++public class TurtleStartDiggingEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Location location; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public TurtleStartDiggingEvent(final Turtle turtle, final Location location) { ++ super(turtle); ++ this.location = location; ++ } ++ ++ /** ++ * The turtle digging ++ * ++ * @return The turtle ++ */ ++ @Override ++ public Turtle getEntity() { ++ return (Turtle) super.getEntity(); ++ } ++ ++ /** ++ * Get the location where the turtle is digging ++ * ++ * @return Location where digging ++ */ ++ public Location getLocation() { ++ return this.location.clone(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Turtle.java b/src/main/java/org/bukkit/entity/Turtle.java +index 5584936158e3762d348cb2eaee2082da24ede367..aa83615a0c6565c9874c906a83cfe20c2a964b22 100644 +--- a/src/main/java/org/bukkit/entity/Turtle.java ++++ b/src/main/java/org/bukkit/entity/Turtle.java +@@ -1,5 +1,8 @@ + package org.bukkit.entity; + ++import org.bukkit.Location; ++import org.jetbrains.annotations.NotNull; ++ + /** + * Represents a turtle. + */ +@@ -18,4 +21,42 @@ public interface Turtle extends Animals { + * @return Whether the turtle is laying an egg + */ + boolean isLayingEgg(); ++ ++ // Paper start ++ /** ++ * Get the turtle's home location ++ * ++ * @return Home location ++ */ ++ @NotNull ++ Location getHome(); ++ ++ /** ++ * Set the turtle's home location ++ * ++ * @param location Home location ++ */ ++ void setHome(@NotNull Location location); ++ ++ /** ++ * Check if turtle is currently pathfinding to it's home ++ * ++ * @return True if going home ++ */ ++ boolean isGoingHome(); ++ ++ /** ++ * Get if turtle is digging to lay eggs ++ * ++ * @return True if digging ++ */ ++ boolean isDigging(); ++ ++ /** ++ * Set if turtle is carrying egg ++ * ++ * @param hasEgg True if carrying egg ++ */ ++ void setHasEgg(boolean hasEgg); ++ // Paper end + } diff --git a/patches/api/0152-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch b/patches/api/0152-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch deleted file mode 100644 index 56ad8fa03cec..000000000000 --- a/patches/api/0152-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch +++ /dev/null @@ -1,319 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Wed, 12 Sep 2018 18:53:35 +0300 -Subject: [PATCH] Add an API for CanPlaceOn and CanDestroy NBT values - - -diff --git a/src/main/java/com/destroystokyo/paper/Namespaced.java b/src/main/java/com/destroystokyo/paper/Namespaced.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cd1a34b82870684e09e18c47169bd472ecbbb91f ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/Namespaced.java -@@ -0,0 +1,40 @@ -+package com.destroystokyo.paper; -+ -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Represents a namespaced resource, see {@link org.bukkit.NamespacedKey} for single elements -+ * or {@link com.destroystokyo.paper.NamespacedTag} for a collection of elements -+ * -+ * Namespaces may only contain lowercase alphanumeric characters, periods, -+ * underscores, and hyphens. -+ *

      -+ * Keys may only contain lowercase alphanumeric characters, periods, -+ * underscores, hyphens, and forward slashes. -+ *

      -+ * You should not be implementing this interface yourself, use {@link org.bukkit.NamespacedKey} -+ * or {@link com.destroystokyo.paper.NamespacedTag} as needed instead. -+ */ -+public interface Namespaced { -+ /** -+ * Gets the namespace this resource is a part of -+ *

      -+ * This is contractually obligated to only contain lowercase alphanumeric characters, -+ * periods, underscores, and hyphens. -+ * -+ * @return resource namespace -+ */ -+ @NotNull -+ String getNamespace(); -+ -+ /** -+ * Gets the key corresponding to this resource -+ *

      -+ * This is contractually obligated to only contain lowercase alphanumeric characters, -+ * periods, underscores, hyphens, and forward slashes. -+ * -+ * @return resource key -+ */ -+ @NotNull -+ String getKey(); -+} -diff --git a/src/main/java/com/destroystokyo/paper/NamespacedTag.java b/src/main/java/com/destroystokyo/paper/NamespacedTag.java -new file mode 100644 -index 0000000000000000000000000000000000000000..28f3fda950999a9c964a3608042ca60567ae1d6a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/NamespacedTag.java -@@ -0,0 +1,142 @@ -+package com.destroystokyo.paper; -+ -+import com.google.common.base.Preconditions; -+import java.util.Locale; -+import java.util.UUID; -+import java.util.regex.Pattern; -+import org.bukkit.plugin.Plugin; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Represents a String based key pertaining to a tagged entry. Consists of two components - a namespace -+ * and a key. -+ *

      -+ * Namespaces may only contain lowercase alphanumeric characters, periods, -+ * underscores, and hyphens. -+ *

      -+ * Keys may only contain lowercase alphanumeric characters, periods, -+ * underscores, hyphens, and forward slashes. -+ * -+ */ -+// Paper - entire class, based on org.bukkit.NamespacedKey -+public final class NamespacedTag implements com.destroystokyo.paper.Namespaced { -+ -+ /** -+ * The namespace representing all inbuilt keys. -+ */ -+ public static final String MINECRAFT = "minecraft"; -+ /** -+ * The namespace representing all keys generated by Bukkit for backwards -+ * compatibility measures. -+ */ -+ public static final String BUKKIT = "bukkit"; -+ // -+ private static final Pattern VALID_NAMESPACE = Pattern.compile("[a-z0-9._-]+"); -+ private static final Pattern VALID_KEY = Pattern.compile("[a-z0-9/._-]+"); -+ // -+ private final String namespace; -+ private final String key; -+ -+ /** -+ * Create a key in a specific namespace. -+ * -+ * @param namespace String representing a grouping of keys -+ * @param key Name for this specific key -+ * @deprecated should never be used by plugins, for internal use only!! -+ */ -+ @Deprecated -+ public NamespacedTag(@NotNull String namespace, @NotNull String key) { -+ Preconditions.checkArgument(namespace != null && VALID_NAMESPACE.matcher(namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", namespace); -+ Preconditions.checkArgument(key != null && VALID_KEY.matcher(key).matches(), "Invalid key. Must be [a-z0-9/._-]: %s", key); -+ -+ this.namespace = namespace; -+ this.key = key; -+ -+ String string = toString(); -+ Preconditions.checkArgument(string.length() < 256, "NamespacedTag must be less than 256 characters", string); -+ } -+ -+ /** -+ * Create a key in the plugin's namespace. -+ *

      -+ * Namespaces may only contain lowercase alphanumeric characters, periods, -+ * underscores, and hyphens. -+ *

      -+ * Keys may only contain lowercase alphanumeric characters, periods, -+ * underscores, hyphens, and forward slashes. -+ * -+ * @param plugin the plugin to use for the namespace -+ * @param key the key to create -+ */ -+ public NamespacedTag(@NotNull Plugin plugin, @NotNull String key) { -+ Preconditions.checkArgument(plugin != null, "Plugin cannot be null"); -+ Preconditions.checkArgument(key != null, "Key cannot be null"); -+ -+ this.namespace = plugin.getName().toLowerCase(Locale.ROOT); -+ this.key = key.toLowerCase().toLowerCase(Locale.ROOT); -+ -+ // Check validity after normalization -+ Preconditions.checkArgument(VALID_NAMESPACE.matcher(this.namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", this.namespace); -+ Preconditions.checkArgument(VALID_KEY.matcher(this.key).matches(), "Invalid key. Must be [a-z0-9/._-]: %s", this.key); -+ -+ String string = toString(); -+ Preconditions.checkArgument(string.length() < 256, "NamespacedTag must be less than 256 characters (%s)", string); -+ } -+ -+ @NotNull -+ public String getNamespace() { -+ return namespace; -+ } -+ -+ @NotNull -+ public String getKey() { -+ return key; -+ } -+ -+ @Override -+ public int hashCode() { -+ int hash = 7; -+ hash = 47 * hash + this.namespace.hashCode(); -+ hash = 47 * hash + this.key.hashCode(); -+ return hash; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (obj == null) { -+ return false; -+ } -+ if (getClass() != obj.getClass()) { -+ return false; -+ } -+ final NamespacedTag other = (NamespacedTag) obj; -+ return this.namespace.equals(other.namespace) && this.key.equals(other.key); -+ } -+ -+ @Override -+ public String toString() { -+ return "#" + this.namespace + ":" + this.key; -+ } -+ -+ /** -+ * Return a new random key in the {@link #BUKKIT} namespace. -+ * -+ * @return new key -+ * @deprecated should never be used by plugins, for internal use only!! -+ */ -+ @Deprecated -+ public static NamespacedTag randomKey() { -+ return new NamespacedTag(BUKKIT, UUID.randomUUID().toString()); -+ } -+ -+ /** -+ * Get a key in the Minecraft namespace. -+ * -+ * @param key the key to use -+ * @return new key in the Minecraft namespace -+ */ -+ @NotNull -+ public static NamespacedTag minecraft(@NotNull String key) { -+ return new NamespacedTag(MINECRAFT, key); -+ } -+} -diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java -index c65f0d6569c130b4920a9e71ad24af6427f1f030..01bcb3a1bdb5accdf844d0178cec3d25746b3eaa 100644 ---- a/src/main/java/org/bukkit/NamespacedKey.java -+++ b/src/main/java/org/bukkit/NamespacedKey.java -@@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable; - * underscores, hyphens, and forward slashes. - * - */ --public final class NamespacedKey implements net.kyori.adventure.key.Key { // Paper - implement Key -+public final class NamespacedKey implements net.kyori.adventure.key.Key, com.destroystokyo.paper.Namespaced { // Paper - implement Key and Namespaced - - /** - * The namespace representing all inbuilt keys. -@@ -84,11 +84,13 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key { // Pap - } - - @NotNull -+ @Override // Paper - public String getNamespace() { - return namespace; - } - - @NotNull -+ @Override // Paper - public String getKey() { - return key; - } -diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -index a19635c38705e6221ae25d58e976e483e7ed17e4..71c7780424a986a95852b1ca15116096896500df 100644 ---- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -+++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -@@ -444,4 +444,87 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - @SuppressWarnings("javadoc") - @NotNull - ItemMeta clone(); -+ -+ // Paper start - Add an API for CanPlaceOn and CanDestroy NBT values -+ /** -+ * Gets set of materials what given item can destroy in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @return Set of materials -+ * @deprecated Minecraft does not limit this to the material enum, Use {@link #getDestroyableKeys()} as a replacement -+ */ -+ @Deprecated -+ Set getCanDestroy(); -+ -+ /** -+ * Sets set of materials what given item can destroy in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @param canDestroy Set of materials -+ * @deprecated Minecraft does not limit this to the material enum, Use {@link #setDestroyableKeys(Collection)} as a replacement -+ */ -+ @Deprecated -+ void setCanDestroy(Set canDestroy); -+ -+ /** -+ * Gets set of materials where given item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @return Set of materials -+ * @deprecated Minecraft does not limit this to the material enum, Use {@link #getPlaceableKeys()} as a replacement -+ */ -+ @Deprecated -+ Set getCanPlaceOn(); -+ -+ /** -+ * Sets set of materials where given item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @param canPlaceOn Set of materials -+ * @deprecated Minecraft does not limit this to the material enum, Use {@link #setPlaceableKeys(Collection)} as a replacement -+ */ -+ @Deprecated -+ void setCanPlaceOn(Set canPlaceOn); -+ -+ /** -+ * Gets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @return Set of {@link com.destroystokyo.paper.Namespaced} -+ */ -+ @NotNull -+ Set getDestroyableKeys(); -+ -+ /** -+ * Sets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @param canDestroy Collection of {@link com.destroystokyo.paper.Namespaced} -+ */ -+ void setDestroyableKeys(@NotNull Collection canDestroy); -+ -+ /** -+ * Gets the collection of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @return Set of {@link com.destroystokyo.paper.Namespaced} -+ */ -+ @NotNull -+ Set getPlaceableKeys(); -+ -+ /** -+ * Sets the set of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} -+ * -+ * @param canPlaceOn Collection of {@link com.destroystokyo.paper.Namespaced} -+ */ -+ @NotNull -+ void setPlaceableKeys(@NotNull Collection canPlaceOn); -+ -+ /** -+ * Checks for the existence of any keys that the item can be placed on -+ * -+ * @return true if this item has placeable keys -+ */ -+ boolean hasPlaceableKeys(); -+ -+ /** -+ * Checks for the existence of any keys that the item can destroy -+ * -+ * @return true if this item has destroyable keys -+ */ -+ boolean hasDestroyableKeys(); -+ // Paper end - } diff --git a/patches/api/0152-Add-spectator-target-events.patch b/patches/api/0152-Add-spectator-target-events.patch new file mode 100644 index 000000000000..ea32c2a4be89 --- /dev/null +++ b/patches/api/0152-Add-spectator-target-events.patch @@ -0,0 +1,143 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Caleb Bassham +Date: Fri, 28 Sep 2018 02:30:56 -0500 +Subject: [PATCH] Add spectator target events + +- PlayerStartSpectatingEntityEvent +- PlayerStopSpectatingEntityEvent + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5ce2f30c094608cc547d2f2517f0ac2546bab85a +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java +@@ -0,0 +1,68 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Triggered when a player starts spectating an entity in spectator mode. ++ */ ++@NullMarked ++public class PlayerStartSpectatingEntityEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Entity currentSpectatorTarget; ++ private final Entity newSpectatorTarget; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerStartSpectatingEntityEvent(final Player player, final Entity currentSpectatorTarget, final Entity newSpectatorTarget) { ++ super(player); ++ this.currentSpectatorTarget = currentSpectatorTarget; ++ this.newSpectatorTarget = newSpectatorTarget; ++ } ++ ++ /** ++ * Gets the entity that the player is currently spectating or themselves if they weren't spectating anything ++ * ++ * @return The entity the player is currently spectating (before they start spectating the new target). ++ */ ++ public Entity getCurrentSpectatorTarget() { ++ return this.currentSpectatorTarget; ++ } ++ ++ /** ++ * Gets the new entity that the player will now be spectating ++ * ++ * @return The entity the player is now going to be spectating. ++ */ ++ public Entity getNewSpectatorTarget() { ++ return this.newSpectatorTarget; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} ++ +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ebda87b7914995a28abce844654ee4f5089c416e +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java +@@ -0,0 +1,55 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Triggered when a player stops spectating an entity in spectator mode. ++ */ ++@NullMarked ++public class PlayerStopSpectatingEntityEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Entity spectatorTarget; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerStopSpectatingEntityEvent(final Player player, final Entity spectatorTarget) { ++ super(player); ++ this.spectatorTarget = spectatorTarget; ++ } ++ ++ /** ++ * Gets the entity that the player is spectating ++ * ++ * @return The entity the player is currently spectating (before they will stop). ++ */ ++ public Entity getSpectatorTarget() { ++ return this.spectatorTarget; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0153-Add-more-Witch-API.patch b/patches/api/0153-Add-more-Witch-API.patch new file mode 100644 index 000000000000..d2db0041e3e4 --- /dev/null +++ b/patches/api/0153-Add-more-Witch-API.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 12 Oct 2018 03:47:26 -0500 +Subject: [PATCH] Add more Witch API + + +diff --git a/src/main/java/org/bukkit/entity/Witch.java b/src/main/java/org/bukkit/entity/Witch.java +index 6618f2129e108c0a6cd15f6d0e86426021b6ff0d..e833250798e1811bd922c2335a113bf3468ec8a5 100644 +--- a/src/main/java/org/bukkit/entity/Witch.java ++++ b/src/main/java/org/bukkit/entity/Witch.java +@@ -2,6 +2,11 @@ package org.bukkit.entity; + + import com.destroystokyo.paper.entity.RangedEntity; + ++// Paper start ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.Nullable; ++// Paper end ++ + /** + * Represents a Witch + */ +@@ -13,4 +18,38 @@ public interface Witch extends Raider, RangedEntity { // Paper + * @return whether the witch is drinking a potion + */ + boolean isDrinkingPotion(); ++ ++ // Paper start ++ /** ++ * Get time remaining (in ticks) the Witch is drinking a potion ++ * ++ * @return Time remaining (in ticks) ++ */ ++ int getPotionUseTimeLeft(); ++ ++ /** ++ * Set time remaining (in ticks) that the Witch is drinking a potion. ++ *

      ++ * This only has an effect while the Witch is drinking a potion. ++ * ++ * @param ticks Time in ticks remaining ++ * @see #isDrinkingPotion ++ */ ++ void setPotionUseTimeLeft(int ticks); ++ ++ /** ++ * Get the potion the Witch is drinking ++ * ++ * @return The potion the witch is drinking ++ */ ++ @org.jetbrains.annotations.NotNull ++ ItemStack getDrinkingPotion(); ++ ++ /** ++ * Set the potion the Witch should drink ++ * ++ * @param potion Potion to drink ++ */ ++ void setDrinkingPotion(@Nullable ItemStack potion); ++ // Paper end + } diff --git a/patches/api/0153-Performance-Concurrency-Improvements-to-Permissions.patch b/patches/api/0153-Performance-Concurrency-Improvements-to-Permissions.patch deleted file mode 100644 index 6befcec378cb..000000000000 --- a/patches/api/0153-Performance-Concurrency-Improvements-to-Permissions.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 13 Sep 2018 20:51:50 -0400 -Subject: [PATCH] Performance & Concurrency Improvements to Permissions - -Modifying of permissions was only half protected, enabling concurrency -issues to occur if permissions were modified async. - -While no plugin really should be doing that, modifying operations -are not heavily called, so they are safe to add synchronization to. - -Now, all modification API's will be synchronized ensuring safety. - -Additionally, hasPermission was victim to a common java newbie mistake -of calling if (containsKey(k)) return get(k), resulting in 2 map lookups. - -Optimized it to simply be a single get call cutting permission map -lookups in half. - -diff --git a/src/main/java/org/bukkit/permissions/PermissibleBase.java b/src/main/java/org/bukkit/permissions/PermissibleBase.java -index 728fc46daf7a38f13906353bdd7362133853af92..cd3296fea01648592d2af89b3d80135acb6d0958 100644 ---- a/src/main/java/org/bukkit/permissions/PermissibleBase.java -+++ b/src/main/java/org/bukkit/permissions/PermissibleBase.java -@@ -72,8 +72,11 @@ public class PermissibleBase implements Permissible { - - String name = inName.toLowerCase(java.util.Locale.ENGLISH); - -- if (isPermissionSet(name)) { -- return permissions.get(name).getValue(); -+ // Paper start -+ PermissionAttachmentInfo info = permissions.get(name); -+ if (info != null) { -+ return info.getValue(); -+ // Paper end - } else { - Permission perm = Bukkit.getServer().getPluginManager().getPermission(name); - -@@ -93,15 +96,18 @@ public class PermissibleBase implements Permissible { - - String name = perm.getName().toLowerCase(java.util.Locale.ENGLISH); - -- if (isPermissionSet(name)) { -- return permissions.get(name).getValue(); -+ // Paper start -+ PermissionAttachmentInfo info = permissions.get(name); -+ if (info != null) { -+ return info.getValue(); - } -+ // Paper end - return perm.getDefault().getValue(isOp()); - } - - @Override - @NotNull -- public PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value) { -+ public synchronized PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value) { // Paper - synchronized - if (name == null) { - throw new IllegalArgumentException("Permission name cannot be null"); - } else if (plugin == null) { -@@ -120,7 +126,7 @@ public class PermissibleBase implements Permissible { - - @Override - @NotNull -- public PermissionAttachment addAttachment(@NotNull Plugin plugin) { -+ public synchronized PermissionAttachment addAttachment(@NotNull Plugin plugin) { // Paper - synchronized - if (plugin == null) { - throw new IllegalArgumentException("Plugin cannot be null"); - } else if (!plugin.isEnabled()) { -@@ -136,7 +142,7 @@ public class PermissibleBase implements Permissible { - } - - @Override -- public void removeAttachment(@NotNull PermissionAttachment attachment) { -+ public synchronized void removeAttachment(@NotNull PermissionAttachment attachment) { // Paper - synchronized - if (attachment == null) { - throw new IllegalArgumentException("Attachment cannot be null"); - } -@@ -155,7 +161,7 @@ public class PermissibleBase implements Permissible { - } - - @Override -- public void recalculatePermissions() { -+ public synchronized void recalculatePermissions() { // Paper - synchronized - clearPermissions(); - Set defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(isOp()); - Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(isOp(), parent); -@@ -204,7 +210,7 @@ public class PermissibleBase implements Permissible { - - @Override - @Nullable -- public PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value, int ticks) { -+ public synchronized PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value, int ticks) { // Paper - if (name == null) { - throw new IllegalArgumentException("Permission name cannot be null"); - } else if (plugin == null) { -@@ -224,7 +230,7 @@ public class PermissibleBase implements Permissible { - - @Override - @Nullable -- public PermissionAttachment addAttachment(@NotNull Plugin plugin, int ticks) { -+ public synchronized PermissionAttachment addAttachment(@NotNull Plugin plugin, int ticks) { // Paper - synchronized - if (plugin == null) { - throw new IllegalArgumentException("Plugin cannot be null"); - } else if (!plugin.isEnabled()) { -@@ -244,7 +250,7 @@ public class PermissibleBase implements Permissible { - - @Override - @NotNull -- public Set getEffectivePermissions() { -+ public synchronized Set getEffectivePermissions() { // Paper - synchronized - return new HashSet(permissions.values()); - } - diff --git a/patches/api/0154-Add-ItemStackRecipeChoice-Draft-API.patch b/patches/api/0154-Add-ItemStackRecipeChoice-Draft-API.patch deleted file mode 100644 index 1a4eca8cc016..000000000000 --- a/patches/api/0154-Add-ItemStackRecipeChoice-Draft-API.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 13 Sep 2018 21:39:26 -0400 -Subject: [PATCH] Add ItemStackRecipeChoice Draft API - -This is based on Spigots Draft API. This is subject to change - -Allows creating recipes that must match isSimilar to full item stack. - -diff --git a/src/main/java/com/destroystokyo/paper/inventory/ItemStackRecipeChoice.java b/src/main/java/com/destroystokyo/paper/inventory/ItemStackRecipeChoice.java -new file mode 100644 -index 0000000000000000000000000000000000000000..43e6576b1d1bb811f9feb22de0024d9c823cb21a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/inventory/ItemStackRecipeChoice.java -@@ -0,0 +1,51 @@ -+package com.destroystokyo.paper.inventory; -+ -+import org.bukkit.inventory.ItemStack; -+import org.bukkit.inventory.RecipeChoice; -+ -+import java.util.ArrayList; -+import java.util.List; -+ -+/** -+ * Allows crafting Items that require full matching itemstacks to complete the recipe for custom items -+ * @deprecated Draft API -+ */ -+@Deprecated -+public class ItemStackRecipeChoice implements RecipeChoice { -+ -+ protected final List choices = new ArrayList<>(); -+ -+ public ItemStackRecipeChoice(ItemStack choices) { -+ this.choices.add(choices); -+ } -+ -+ public ItemStackRecipeChoice(List choices) { -+ this.choices.addAll(choices); -+ } -+ -+ @Override -+ public ItemStack getItemStack() { -+ return choices.isEmpty() ? null : choices.get(0); -+ } -+ -+ @Override -+ public RecipeChoice clone() { -+ try { -+ ItemStackRecipeChoice clone = (ItemStackRecipeChoice) super.clone(); -+ clone.choices.addAll(this.choices); -+ return clone; -+ } catch (CloneNotSupportedException ex) { -+ throw new AssertionError(ex); -+ } -+ } -+ -+ @Override -+ public boolean test(ItemStack itemStack) { -+ for (ItemStack stack : choices) { -+ if (stack.isSimilar(itemStack)) { -+ return true; -+ } -+ } -+ return false; -+ } -+} diff --git a/patches/api/0154-Make-the-default-permission-message-configurable.patch b/patches/api/0154-Make-the-default-permission-message-configurable.patch new file mode 100644 index 000000000000..ff93cc28f7f2 --- /dev/null +++ b/patches/api/0154-Make-the-default-permission-message-configurable.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sun, 18 Nov 2018 19:44:54 +0000 +Subject: [PATCH] Make the default permission message configurable + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 4cdbcb96b358bc678255ae3852cef047a2df2457..e0b22dd1124f02a78e5adfcf2179eadebff1dba6 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2445,6 +2445,28 @@ public final class Bukkit { + return server.suggestPlayerNamesWhenNullTabCompletions(); + } + ++ /** ++ * Gets the default no permission message used on the server ++ * ++ * @return the default message ++ * @deprecated use {@link #permissionMessage()} ++ */ ++ @NotNull ++ @Deprecated ++ public static String getPermissionMessage() { ++ return server.getPermissionMessage(); ++ } ++ ++ /** ++ * Gets the default no permission message used on the server ++ * ++ * @return the default message ++ */ ++ @NotNull ++ public static net.kyori.adventure.text.Component permissionMessage() { ++ return server.permissionMessage(); ++ } ++ + /** + * Creates a PlayerProfile for the specified uuid, with name as null. + * +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 957bc4c3e4c1eb6a4d89b5e559f95b604ecf59c4..7b5f6091c8e930526a2a5346a02b52912c38e2af 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2127,6 +2127,23 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + boolean suggestPlayerNamesWhenNullTabCompletions(); + ++ /** ++ * Gets the default no permission message used on the server ++ * ++ * @return the default message ++ * @deprecated use {@link #permissionMessage()} ++ */ ++ @NotNull ++ @Deprecated ++ String getPermissionMessage(); ++ ++ /** ++ * Gets the default no permission message used on the server ++ * ++ * @return the default message ++ */ ++ @NotNull net.kyori.adventure.text.Component permissionMessage(); ++ + /** + * Creates a PlayerProfile for the specified uuid, with name as null. + * +diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java +index 0ee08b6cd80e72ae67e1316ddbb58b7c1d47e5ce..92b905e5da3cb8f477bb17d848c3523781545ae3 100644 +--- a/src/main/java/org/bukkit/command/Command.java ++++ b/src/main/java/org/bukkit/command/Command.java +@@ -192,10 +192,9 @@ public abstract class Command { + return true; + } + +- if (permissionMessage == null) { +- target.sendMessage(ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is a mistake."); + // Paper start - use components for permissionMessage +- } else if (!permissionMessage.equals(net.kyori.adventure.text.Component.empty())) { ++ net.kyori.adventure.text.Component permissionMessage = this.permissionMessage != null ? this.permissionMessage : Bukkit.permissionMessage(); ++ if (!permissionMessage.equals(net.kyori.adventure.text.Component.empty())) { + target.sendMessage(permissionMessage.replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("").replacement(permission).build())); + // Paper end + } diff --git a/patches/api/0155-Implement-furnace-cook-speed-multiplier-API.patch b/patches/api/0155-Implement-furnace-cook-speed-multiplier-API.patch deleted file mode 100644 index 709ba414da13..000000000000 --- a/patches/api/0155-Implement-furnace-cook-speed-multiplier-API.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Tassu -Date: Thu, 13 Sep 2018 08:45:01 +0300 -Subject: [PATCH] Implement furnace cook speed multiplier API - -Signed-off-by: Tassu - -diff --git a/src/main/java/org/bukkit/block/Furnace.java b/src/main/java/org/bukkit/block/Furnace.java -index ac3b24c5c99eeb1435d785efade728dd40947da5..dbdf3dbe9517b09a7965cf9d65cae1edd87af67d 100644 ---- a/src/main/java/org/bukkit/block/Furnace.java -+++ b/src/main/java/org/bukkit/block/Furnace.java -@@ -74,6 +74,26 @@ public interface Furnace extends Container { - @NotNull - public Map, Integer> getRecipesUsed(); - -+ // Paper start -+ /** -+ * Gets the cook speed multiplier that this {@link Furnace} will cook -+ * compared to vanilla. -+ * -+ * @return the multiplier, a value between 0 and 200 -+ */ -+ public double getCookSpeedMultiplier(); -+ -+ /** -+ * Sets the speed multiplier that this {@link Furnace} will cook -+ * compared to vanilla. -+ * -+ * @param multiplier the multiplier to set, a value between 0 and 200 -+ * @throws IllegalArgumentException if value is less than 0 -+ * @throws IllegalArgumentException if value is more than 200 -+ */ -+ public void setCookSpeedMultiplier(double multiplier); -+ // Paper end -+ - @NotNull - @Override - public FurnaceInventory getInventory(); -diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java -index 533a33dbd4c4c3c07fe759206dc288efec5cd531..f13f1b4daa99fb86b60acc94d0406dcd8cb4d98b 100644 ---- a/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java -+++ b/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java -@@ -13,11 +13,18 @@ public class FurnaceStartSmeltEvent extends BlockEvent { - private final CookingRecipe recipe; - private int totalCookTime; - -+ @Deprecated // Paper - furnace cook speed multiplier - public FurnaceStartSmeltEvent(@NotNull final Block furnace, @NotNull ItemStack source, @NotNull final CookingRecipe recipe) { -+ // Paper start - furnace cook speed multiplier -+ this(furnace, source, recipe, recipe.getCookingTime()); -+ } -+ -+ public FurnaceStartSmeltEvent(@NotNull final Block furnace, @NotNull ItemStack source, @NotNull CookingRecipe recipe, int cookingTime) { -+ // Paper end - super(furnace); - this.source = source; - this.recipe = recipe; -- this.totalCookTime = recipe.getCookingTime(); -+ this.totalCookTime = cookingTime; // Paper - furnace cook speed multiplier - } - - /** diff --git a/patches/api/0155-Support-cancellation-supression-of-EntityDismount-Ve.patch b/patches/api/0155-Support-cancellation-supression-of-EntityDismount-Ve.patch new file mode 100644 index 000000000000..420a97487dbc --- /dev/null +++ b/patches/api/0155-Support-cancellation-supression-of-EntityDismount-Ve.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sun, 18 Nov 2018 15:53:43 +0000 +Subject: [PATCH] Support cancellation supression of EntityDismount/VehicleExit + events" + +Entities must be dismounted before teleportation in order to avoid +multiple issues in the server with regards to teleportation, shamefully, +too many plugins rely on the events firing, which means that not firing +these events caues more issues than it solves; + +In order to counteract this, Entity dismount/exit vehicle events have +been modified to supress cancellation (and has a method to allow plugins +to check if this has been set), noting that cancellation will be silently +surpressed given that plugins are not expecting this event to not be cancellable. + +This is a far from ideal scenario, however: given the current state of this +event and other alternatives causing issues elsewhere, I believe that +this is going to be the best soultion all around. + +Improvements/suggestions welcome! + +diff --git a/src/main/java/org/bukkit/event/entity/EntityDismountEvent.java b/src/main/java/org/bukkit/event/entity/EntityDismountEvent.java +index 00c3f50532392455070ae77ee4ad77cbf8d8827c..91188d77ff350aef20c3bde2bd27a8096825f337 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityDismountEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityDismountEvent.java +@@ -13,10 +13,18 @@ public class EntityDismountEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final Entity dismounted; ++ private final boolean isCancellable; // Paper + + public EntityDismountEvent(@NotNull Entity what, @NotNull Entity dismounted) { ++ // Paper start ++ this(what, dismounted, true); ++ } ++ ++ public EntityDismountEvent(@NotNull Entity what, @NotNull Entity dismounted, boolean isCancellable) { ++ // Paper end + super(what); + this.dismounted = dismounted; ++ this.isCancellable = isCancellable; // Paper + } + + /** +@@ -36,9 +44,18 @@ public class EntityDismountEvent extends EntityEvent implements Cancellable { + + @Override + public void setCancelled(boolean cancel) { ++ // Paper start ++ if (cancel && !this.isCancellable) { ++ return; ++ } + this.cancelled = cancel; + } + ++ public boolean isCancellable() { ++ return this.isCancellable; ++ // Paper end ++ } ++ + @NotNull + @Override + public HandlerList getHandlers() { +diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java +index 963b9ead4ca0426b2e95c5641b0e89317c48853d..39f6afd2f9cbcff6a74a91a21dcc3e29d2497dd8 100644 +--- a/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java ++++ b/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java +@@ -13,10 +13,18 @@ public class VehicleExitEvent extends VehicleEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final LivingEntity exited; ++ private final boolean isCancellable; // Paper + +- public VehicleExitEvent(@NotNull final Vehicle vehicle, @NotNull final LivingEntity exited) { ++ public VehicleExitEvent(@NotNull final Vehicle vehicle, @NotNull final LivingEntity exited, boolean isCancellable) { // Paper + super(vehicle); + this.exited = exited; ++ // Paper start ++ this.isCancellable = isCancellable; ++ } ++ ++ public VehicleExitEvent(@NotNull final Vehicle vehicle, @NotNull final LivingEntity exited) { ++ this(vehicle, exited, true); ++ // Paper end + } + + /** +@@ -36,9 +44,18 @@ public class VehicleExitEvent extends VehicleEvent implements Cancellable { + + @Override + public void setCancelled(boolean cancel) { ++ // Paper start ++ if (cancel && !isCancellable) { ++ return; ++ } + this.cancelled = cancel; + } + ++ public boolean isCancellable() { ++ return isCancellable; ++ // Paper end ++ } ++ + @NotNull + @Override + public HandlerList getHandlers() { diff --git a/patches/api/0156-Add-more-Zombie-API.patch b/patches/api/0156-Add-more-Zombie-API.patch new file mode 100644 index 000000000000..d3c4c2def313 --- /dev/null +++ b/patches/api/0156-Add-more-Zombie-API.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 7 Oct 2018 04:29:51 -0500 +Subject: [PATCH] Add more Zombie API + + +diff --git a/src/main/java/org/bukkit/entity/Zombie.java b/src/main/java/org/bukkit/entity/Zombie.java +index c69eaf2ff582a6ec8a3b83daba2ab1e3a7bec7d3..ec6d6052bfd0deb431e9a71329169c97fa498bcd 100644 +--- a/src/main/java/org/bukkit/entity/Zombie.java ++++ b/src/main/java/org/bukkit/entity/Zombie.java +@@ -107,4 +107,60 @@ public interface Zombie extends Monster, Ageable { + * @param flag Whether this zombie can break doors + */ + void setCanBreakDoors(boolean flag); ++ ++ // Paper start ++ /** ++ * Check if zombie is drowning ++ * ++ * @return True if zombie conversion process has begun ++ */ ++ boolean isDrowning(); ++ ++ /** ++ * Make zombie start drowning ++ * ++ * @param drownedConversionTime Amount of time until zombie converts from drowning ++ * ++ * @deprecated See {@link #setConversionTime(int)} ++ */ ++ @Deprecated ++ void startDrowning(int drownedConversionTime); ++ ++ /** ++ * Stop a zombie from starting the drowning conversion process ++ */ ++ void stopDrowning(); ++ ++ /** ++ * Set if zombie has its arms raised ++ * ++ * @param raised True to raise arms ++ * @deprecated use {{@link #setAggressive(boolean)}} ++ */ ++ @Deprecated ++ void setArmsRaised(boolean raised); ++ ++ /** ++ * Check if zombie has arms raised ++ * ++ * @return True if arms are raised ++ * @deprecated use {@link #isAggressive()} ++ */ ++ @Deprecated ++ boolean isArmsRaised(); ++ ++ /** ++ * Check if this zombie will burn in the sunlight ++ * ++ * @return True if zombie will burn in sunlight ++ */ ++ boolean shouldBurnInDay(); ++ ++ /** ++ * Set if this zombie should burn in the sunlight ++ * ++ * @param shouldBurnInDay True to burn in sunlight ++ */ ++ void setShouldBurnInDay(boolean shouldBurnInDay); ++ // Paper end + } diff --git a/patches/api/0156-Material-API-additions.patch b/patches/api/0156-Material-API-additions.patch deleted file mode 100644 index 421ed84d3854..000000000000 --- a/patches/api/0156-Material-API-additions.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 6 Oct 2018 21:14:29 -0400 -Subject: [PATCH] Material API additions - - -diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index 2f53bb42dc6a09ed35ec1335d23adf07289575fa..e40766c56fea6daae9f84fbdeb0b3f533e28d0b7 100644 ---- a/src/main/java/org/bukkit/Material.java -+++ b/src/main/java/org/bukkit/Material.java -@@ -106,6 +106,7 @@ import org.jetbrains.annotations.Nullable; - /** - * An enum of all material IDs accepted by the official server and client - */ -+@SuppressWarnings({"DeprecatedIsStillUsed", "deprecation"}) // Paper - public enum Material implements Keyed { - // - AIR(9648, 0), -@@ -4110,6 +4111,22 @@ public enum Material implements Keyed { - } - } - -+ // Paper start -+ -+ /** -+ * @return If the type is either AIR, CAVE_AIR or VOID_AIR -+ */ -+ public boolean isEmpty() { -+ switch (this) { -+ case AIR: -+ case CAVE_AIR: -+ case VOID_AIR: -+ return true; -+ } -+ return false; -+ } -+ // Paper end -+ - /** - * Do not use for any reason. - * diff --git a/patches/api/0157-Add-Material-Tags.patch b/patches/api/0157-Add-Material-Tags.patch deleted file mode 100644 index 8cee9a502564..000000000000 --- a/patches/api/0157-Add-Material-Tags.patch +++ /dev/null @@ -1,1211 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 17 Jul 2018 01:27:15 -0400 -Subject: [PATCH] Add Material Tags - -This adds a bunch of useful and missing Tags to be able to identify items that -are related to each other by a trait. - -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/com/destroystokyo/paper/MaterialSetTag.java b/src/main/java/com/destroystokyo/paper/MaterialSetTag.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a02a02aa0c87e0f0ed9e509e4dcab01565b3d92a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/MaterialSetTag.java -@@ -0,0 +1,97 @@ -+/* -+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License -+ */ -+ -+package com.destroystokyo.paper; -+ -+import com.google.common.collect.Lists; -+import io.papermc.paper.tag.BaseTag; -+import org.bukkit.Material; -+import org.bukkit.NamespacedKey; -+import org.bukkit.block.Block; -+import org.bukkit.block.BlockState; -+import org.bukkit.block.data.BlockData; -+import org.bukkit.inventory.ItemStack; -+ -+import java.util.Collection; -+import java.util.Set; -+import java.util.function.Predicate; -+import java.util.stream.Collectors; -+import java.util.stream.Stream; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class MaterialSetTag extends BaseTag { -+ -+ /** -+ * @deprecated Use NamespacedKey version of constructor -+ */ -+ @Deprecated -+ public MaterialSetTag(@NotNull Predicate filter) { -+ this(null, Stream.of(Material.values()).filter(filter).collect(Collectors.toList())); -+ } -+ -+ /** -+ * @deprecated Use NamespacedKey version of constructor -+ */ -+ @Deprecated -+ public MaterialSetTag(@NotNull Collection materials) { -+ this(null, materials); -+ } -+ -+ /** -+ * @deprecated Use NamespacedKey version of constructor -+ */ -+ @Deprecated -+ public MaterialSetTag(@NotNull Material... materials) { -+ this(null, materials); -+ } -+ -+ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Predicate filter) { -+ this(key, Stream.of(Material.values()).filter(filter).collect(Collectors.toList())); -+ } -+ -+ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Material... materials) { -+ this(key, Lists.newArrayList(materials)); -+ } -+ -+ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Collection materials) { -+ this(key != null ? key : NamespacedKey.randomKey(), materials, ((Predicate) Material::isLegacy).negate()); -+ } -+ -+ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Collection materials, @NotNull Predicate...globalPredicates) { -+ super(Material.class, key != null ? key : NamespacedKey.randomKey(), materials, globalPredicates); -+ } -+ -+ @NotNull -+ @Override -+ protected Set getAllPossibleValues() { -+ return Stream.of(Material.values()).collect(Collectors.toSet()); -+ } -+ -+ @Override -+ @NotNull -+ protected String getName(@NotNull Material value) { -+ return value.name(); -+ } -+ -+ public boolean isTagged(@NotNull BlockData block) { -+ return isTagged(block.getMaterial()); -+ } -+ -+ public boolean isTagged(@NotNull BlockState block) { -+ return isTagged(block.getType()); -+ } -+ -+ public boolean isTagged(@NotNull Block block) { -+ return isTagged(block.getType()); -+ } -+ -+ public boolean isTagged(@NotNull ItemStack item) { -+ return isTagged(item.getType()); -+ } -+ -+ public boolean isTagged(@NotNull Material material) { -+ return this.tagged.contains(material); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/MaterialTags.java b/src/main/java/com/destroystokyo/paper/MaterialTags.java -new file mode 100644 -index 0000000000000000000000000000000000000000..41384ef616c5d3099482ea7d09dea12a240e758a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/MaterialTags.java -@@ -0,0 +1,661 @@ -+/* -+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be -+ * included in all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+package com.destroystokyo.paper; -+ -+import org.bukkit.Material; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Tag; -+ -+/** -+ * Represents a collection tags to identify materials that share common properties. -+ * Will map to minecraft for missing tags, as well as custom ones that may be useful. -+ *

      -+ * All tags in this class are unmodifiable, attempting to modify them will throw an -+ * {@link UnsupportedOperationException}. -+ */ -+@SuppressWarnings({"NonFinalUtilityClass", "unused", "WeakerAccess"}) -+public class MaterialTags { -+ -+ private static NamespacedKey keyFor(String key) { -+ //noinspection deprecation -+ return new NamespacedKey("paper", key + "_settag"); -+ } -+ public static final MaterialSetTag ARROWS = new MaterialSetTag(keyFor("arrows")) -+ .endsWith("ARROW") -+ .ensureSize("ARROWS", 3).lock(); -+ -+ /** -+ * Covers all colors of beds. -+ */ -+ public static final MaterialSetTag BEDS = new MaterialSetTag(keyFor("beds")) -+ .endsWith("_BED") -+ .ensureSize("BEDS", 16).lock(); -+ -+ /** -+ * Covers all bucket items. -+ */ -+ public static final MaterialSetTag BUCKETS = new MaterialSetTag(keyFor("buckets")) -+ .endsWith("BUCKET") -+ .ensureSize("BUCKETS", 11).lock(); -+ -+ /** -+ * Covers coal and charcoal. -+ */ -+ public static final MaterialSetTag COALS = new MaterialSetTag(keyFor("coals")) -+ .add(Material.COAL, Material.CHARCOAL).lock(); -+ -+ /** -+ * Covers both cobblestone wall variants. -+ */ -+ public static final MaterialSetTag COBBLESTONE_WALLS = new MaterialSetTag(keyFor("cobblestone_walls")) -+ .endsWith("COBBLESTONE_WALL") -+ .ensureSize("COBBLESTONE_WALLS", 2).lock(); -+ -+ /** -+ * Covers both cobblestone and mossy Cobblestone. -+ */ -+ public static final MaterialSetTag COBBLESTONES = new MaterialSetTag(keyFor("cobblestones")) -+ .add(Material.COBBLESTONE, Material.MOSSY_COBBLESTONE).lock(); -+ -+ /** -+ * Covers all colors of concrete. -+ */ -+ public static final MaterialSetTag CONCRETES = new MaterialSetTag(keyFor("concretes")) -+ .endsWith("_CONCRETE") -+ .ensureSize("CONCRETES", 16).lock(); -+ -+ /** -+ * Covers all colors of concrete powder. -+ */ -+ public static final MaterialSetTag CONCRETE_POWDER = new MaterialSetTag(keyFor("concrete_powder")) -+ .endsWith("_CONCRETE_POWDER") -+ .ensureSize("CONCRETE_POWDER", 16).lock(); -+ -+ /** -+ * Covers the two types of cooked fish. -+ */ -+ public static final MaterialSetTag COOKED_FISH = new MaterialSetTag(keyFor("cooked_fish")) -+ .add(Material.COOKED_COD, Material.COOKED_SALMON).lock(); -+ -+ /** -+ * Covers all variants of doors. -+ */ -+ public static final MaterialSetTag DOORS = new MaterialSetTag(keyFor("doors")) -+ .endsWith("_DOOR") -+ .ensureSize("DOORS", 10).lock(); -+ -+ /** -+ * Covers all dyes. -+ */ -+ public static final MaterialSetTag DYES = new MaterialSetTag(keyFor("dyes")) -+ .endsWith("_DYE") -+ .ensureSize("DYES", 16).lock(); -+ -+ /** -+ * Covers all variants of gates. -+ */ -+ public static final MaterialSetTag FENCE_GATES = new MaterialSetTag(keyFor("fence_gates")) -+ .endsWith("_GATE") -+ .ensureSize("FENCE_GATES", 9).lock(); -+ -+ /** -+ * Covers all variants of fences. -+ */ -+ public static final MaterialSetTag FENCES = new MaterialSetTag(keyFor("fences")) -+ .endsWith("_FENCE") -+ .ensureSize("FENCES", 10).lock(); -+ -+ /** -+ * Covers all variants of fish buckets. -+ */ -+ public static final MaterialSetTag FISH_BUCKETS = new MaterialSetTag(keyFor("fish_buckets")) -+ .add(Material.COD_BUCKET, Material.PUFFERFISH_BUCKET, Material.SALMON_BUCKET, Material.TROPICAL_FISH_BUCKET).lock(); -+ -+ /** -+ * Covers the non-colored glass and 16 stained glass (not panes). -+ */ -+ public static final MaterialSetTag GLASS = new MaterialSetTag(keyFor("glass")) -+ .endsWith("_GLASS") -+ .add(Material.GLASS) -+ .ensureSize("GLASS", 18).lock(); -+ -+ /** -+ * Covers the non-colored glass panes and stained glass panes (panes only). -+ */ -+ public static final MaterialSetTag GLASS_PANES = new MaterialSetTag(keyFor("glass_panes")) -+ .endsWith("GLASS_PANE") -+ .ensureSize("GLASS_PANES", 17).lock(); -+ -+ /** -+ * Covers all glazed terracotta blocks. -+ */ -+ public static final MaterialSetTag GLAZED_TERRACOTTA = new MaterialSetTag(keyFor("glazed_terracotta")) -+ .endsWith("GLAZED_TERRACOTTA") -+ .ensureSize("GLAZED_TERRACOTTA", 16).lock(); -+ -+ /** -+ * Covers the colors of stained terracotta. -+ */ -+ public static final MaterialSetTag STAINED_TERRACOTTA = new MaterialSetTag(keyFor("stained_terracotta")) -+ .endsWith("TERRACOTTA") -+ .not(Material.TERRACOTTA) -+ .notEndsWith("GLAZED_TERRACOTTA") -+ .ensureSize("STAINED_TERRACOTTA", 16).lock(); -+ -+ /** -+ * Covers terracotta along with the stained variants. -+ */ -+ public static final MaterialSetTag TERRACOTTA = new MaterialSetTag(keyFor("terracotta")) -+ .endsWith("TERRACOTTA") -+ .ensureSize("TERRACOTTA", 33).lock(); -+ -+ /** -+ * Covers both golden apples. -+ */ -+ public static final MaterialSetTag GOLDEN_APPLES = new MaterialSetTag(keyFor("golden_apples")) -+ .endsWith("GOLDEN_APPLE") -+ .ensureSize("GOLDEN_APPLES", 2).lock(); -+ -+ /** -+ * Covers the variants of horse armor. -+ */ -+ public static final MaterialSetTag HORSE_ARMORS = new MaterialSetTag(keyFor("horse_armors")) -+ .endsWith("_HORSE_ARMOR") -+ .ensureSize("HORSE_ARMORS", 4).lock(); -+ -+ /** -+ * Covers the variants of infested blocks. -+ */ -+ public static final MaterialSetTag INFESTED_BLOCKS = new MaterialSetTag(keyFor("infested_blocks")) -+ .startsWith("INFESTED_") -+ .ensureSize("INFESTED_BLOCKS", 7).lock(); -+ -+ /** -+ * Covers the variants of mushroom blocks. -+ */ -+ public static final MaterialSetTag MUSHROOM_BLOCKS = new MaterialSetTag(keyFor("mushroom_blocks")) -+ .endsWith("MUSHROOM_BLOCK") -+ .add(Material.MUSHROOM_STEM) -+ .ensureSize("MUSHROOM_BLOCKS", 3).lock(); -+ -+ /** -+ * Covers all mushrooms. -+ */ -+ public static final MaterialSetTag MUSHROOMS = new MaterialSetTag(keyFor("mushrooms")) -+ .add(Material.BROWN_MUSHROOM, Material.RED_MUSHROOM).lock(); -+ -+ /** -+ * Covers all music disc items. -+ */ -+ public static final MaterialSetTag MUSIC_DISCS = new MaterialSetTag(keyFor("music_discs")) -+ .startsWith("MUSIC_DISC_").lock(); -+ -+ /** -+ * Covers all ores. -+ */ -+ public static final MaterialSetTag ORES = new MaterialSetTag(keyFor("ores")) -+ .add(Material.ANCIENT_DEBRIS) -+ .endsWith("_ORE") -+ .ensureSize("ORES", 19).lock(); -+ -+ /** -+ * Covers all piston typed items and blocks including the piston head and moving piston. -+ */ -+ public static final MaterialSetTag PISTONS = new MaterialSetTag(keyFor("pistons")) -+ .contains("PISTON") -+ .ensureSize("PISTONS", 4).lock(); -+ -+ /** -+ * Covers all potato items. -+ */ -+ public static final MaterialSetTag POTATOES = new MaterialSetTag(keyFor("potatoes")) -+ .endsWith("POTATO") -+ .ensureSize("POTATOES", 3).lock(); -+ -+ /** -+ * Covers all wooden pressure plates and the weighted pressure plates and the stone pressure plate. -+ */ -+ public static final MaterialSetTag PRESSURE_PLATES = new MaterialSetTag(keyFor("pressure_plates")) -+ .endsWith("_PRESSURE_PLATE") -+ .ensureSize("PRESSURE_PLATES", 13).lock(); -+ -+ /** -+ * Covers the variants of prismarine blocks. -+ */ -+ public static final MaterialSetTag PRISMARINE = new MaterialSetTag(keyFor("prismarine")) -+ .add(Material.PRISMARINE, Material.PRISMARINE_BRICKS, Material.DARK_PRISMARINE).lock(); -+ -+ /** -+ * Covers the variants of prismarine slabs. -+ */ -+ public static final MaterialSetTag PRISMARINE_SLABS = new MaterialSetTag(keyFor("prismarine_slabs")) -+ .add(Material.PRISMARINE_SLAB, Material.PRISMARINE_BRICK_SLAB, Material.DARK_PRISMARINE_SLAB).lock(); -+ -+ /** -+ * Covers the variants of prismarine stairs. -+ */ -+ public static final MaterialSetTag PRISMARINE_STAIRS = new MaterialSetTag(keyFor("prismarine_stairs")) -+ .add(Material.PRISMARINE_STAIRS, Material.PRISMARINE_BRICK_STAIRS, Material.DARK_PRISMARINE_STAIRS).lock(); -+ -+ /** -+ * Covers the variants of pumpkins. -+ */ -+ public static final MaterialSetTag PUMPKINS = new MaterialSetTag(keyFor("pumpkins")) -+ .add(Material.CARVED_PUMPKIN, Material.JACK_O_LANTERN, Material.PUMPKIN).lock(); -+ -+ /** -+ * Covers the variants of quartz blocks. -+ */ -+ public static final MaterialSetTag QUARTZ_BLOCKS = new MaterialSetTag(keyFor("quartz_blocks")) -+ .add(Material.QUARTZ_BLOCK, Material.QUARTZ_PILLAR, Material.CHISELED_QUARTZ_BLOCK, Material.SMOOTH_QUARTZ).lock(); -+ -+ /** -+ * Covers all uncooked fish items. -+ */ -+ public static final MaterialSetTag RAW_FISH = new MaterialSetTag(keyFor("raw_fish")) -+ .add(Material.COD, Material.PUFFERFISH, Material.SALMON, Material.TROPICAL_FISH).lock(); -+ -+ /** -+ * Covers the variants of red sandstone blocks. -+ */ -+ public static final MaterialSetTag RED_SANDSTONES = new MaterialSetTag(keyFor("red_sandstones")) -+ .endsWith("RED_SANDSTONE") -+ .ensureSize("RED_SANDSTONES", 4).lock(); -+ -+ /** -+ * Covers the variants of sandstone blocks. -+ */ -+ public static final MaterialSetTag SANDSTONES = new MaterialSetTag(keyFor("sandstones")) -+ .add(Material.SANDSTONE, Material.CHISELED_SANDSTONE, Material.CUT_SANDSTONE, Material.SMOOTH_SANDSTONE).lock(); -+ -+ /** -+ * Covers sponge and wet sponge. -+ */ -+ public static final MaterialSetTag SPONGES = new MaterialSetTag(keyFor("sponges")) -+ .endsWith("SPONGE") -+ .ensureSize("SPONGES", 2).lock(); -+ -+ /** -+ * Covers the non-colored and colored shulker boxes. -+ */ -+ public static final MaterialSetTag SHULKER_BOXES = new MaterialSetTag(keyFor("shulker_boxes")) -+ .endsWith("SHULKER_BOX") -+ .ensureSize("SHULKER_BOXES", 17).lock(); -+ -+ /** -+ * Covers zombie, creeper, skeleton, dragon, and player heads. -+ */ -+ public static final MaterialSetTag SKULLS = new MaterialSetTag(keyFor("skulls")) -+ .endsWith("_HEAD") -+ .endsWith("_SKULL") -+ .not(Material.PISTON_HEAD) -+ .ensureSize("SKULLS", 12).lock(); -+ -+ /** -+ * Covers all spawn egg items. -+ */ -+ public static final MaterialSetTag SPAWN_EGGS = new MaterialSetTag(keyFor("spawn_eggs")) -+ .endsWith("_SPAWN_EGG") -+ .ensureSize("SPAWN_EGGS", 71).lock(); -+ -+ /** -+ * Covers all colors of stained glass. -+ */ -+ public static final MaterialSetTag STAINED_GLASS = new MaterialSetTag(keyFor("stained_glass")) -+ .endsWith("_STAINED_GLASS") -+ .ensureSize("STAINED_GLASS", 16).lock(); -+ -+ /** -+ * Covers all colors of stained glass panes. -+ */ -+ public static final MaterialSetTag STAINED_GLASS_PANES = new MaterialSetTag(keyFor("stained_glass_panes")) -+ .endsWith("STAINED_GLASS_PANE") -+ .ensureSize("STAINED_GLASS_PANES", 16).lock(); -+ -+ /** -+ * Covers all variants of trapdoors. -+ */ -+ public static final MaterialSetTag TRAPDOORS = new MaterialSetTag(keyFor("trapdoors")) -+ .endsWith("_TRAPDOOR") -+ .ensureSize("TRAPDOORS", 10).lock(); -+ -+ /** -+ * Covers all wood variants of doors. -+ */ -+ public static final MaterialSetTag WOODEN_DOORS = new MaterialSetTag(keyFor("wooden_doors")) -+ .endsWith("_DOOR") -+ .not(Material.IRON_DOOR) -+ .ensureSize("WOODEN_DOORS", 9).lock(); -+ -+ /** -+ * Covers all wood variants of fences. -+ */ -+ public static final MaterialSetTag WOODEN_FENCES = new MaterialSetTag(keyFor("wooden_fences")) -+ .endsWith("_FENCE") -+ .not(Material.NETHER_BRICK_FENCE) -+ .ensureSize("WOODEN_FENCES", 9).lock(); -+ -+ /** -+ * Covers all wood variants of trapdoors. -+ */ -+ public static final MaterialSetTag WOODEN_TRAPDOORS = new MaterialSetTag(keyFor("wooden_trapdoors")) -+ .endsWith("_TRAPDOOR") -+ .not(Material.IRON_TRAPDOOR) -+ .ensureSize("WOODEN_TRAPDOORS", 9).lock(); -+ -+ /** -+ * Covers the wood variants of gates. -+ */ -+ public static final MaterialSetTag WOODEN_GATES = new MaterialSetTag(keyFor("wooden_gates")) -+ .endsWith("_GATE") -+ .ensureSize("WOODEN_GATES", 9).lock(); -+ -+ /** -+ * Covers the variants of purpur. -+ */ -+ public static final MaterialSetTag PURPUR = new MaterialSetTag(keyFor("purpur")) -+ .startsWith("PURPUR_") -+ .ensureSize("PURPUR", 4).lock(); -+ -+ /** -+ * Covers the variants of signs. -+ */ -+ public static final MaterialSetTag SIGNS = new MaterialSetTag(keyFor("signs")) -+ .endsWith("_SIGN") -+ .ensureSize("SIGNS", 18).lock(); -+ -+ /** -+ * Covers the variants of a regular torch. -+ */ -+ public static final MaterialSetTag TORCH = new MaterialSetTag(keyFor("torch")) -+ .add(Material.TORCH, Material.WALL_TORCH) -+ .ensureSize("TORCH", 2).lock(); -+ -+ /** -+ * Covers the variants of a redstone torch. -+ */ -+ public static final MaterialSetTag REDSTONE_TORCH = new MaterialSetTag(keyFor("restone_torch")) -+ .add(Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH) -+ .ensureSize("REDSTONE_TORCH", 2).lock(); -+ -+ /** -+ * Covers the variants of a soul torch. -+ */ -+ public static final MaterialSetTag SOUL_TORCH = new MaterialSetTag(keyFor("soul_torch")) -+ .add(Material.SOUL_TORCH, Material.SOUL_WALL_TORCH) -+ .ensureSize("SOUL_TORCH", 2).lock(); -+ -+ /** -+ * Covers the variants of torches. -+ */ -+ public static final MaterialSetTag TORCHES = new MaterialSetTag(keyFor("torches")) -+ .add(TORCH, REDSTONE_TORCH, SOUL_TORCH) -+ .ensureSize("TORCHES", 6).lock(); -+ -+ /** -+ * Covers the variants of lanterns. -+ */ -+ public static final MaterialSetTag LANTERNS = new MaterialSetTag(keyFor("lanterns")) -+ .add(Material.LANTERN, Material.SOUL_LANTERN) -+ .ensureSize("LANTERNS", 2).lock(); -+ -+ /** -+ * Covers the variants of rails. -+ */ -+ public static final MaterialSetTag RAILS = new MaterialSetTag(keyFor("rails")) -+ .endsWith("RAIL") -+ .ensureSize("RAILS", 4).lock(); -+ -+ /** -+ * Covers the variants of swords. -+ */ -+ public static final MaterialSetTag SWORDS = new MaterialSetTag(keyFor("swords")) -+ .endsWith("_SWORD") -+ .ensureSize("SWORDS", 6).lock(); -+ -+ /** -+ * Covers the variants of shovels. -+ */ -+ public static final MaterialSetTag SHOVELS = new MaterialSetTag(keyFor("shovels")) -+ .endsWith("_SHOVEL") -+ .ensureSize("SHOVELS", 6).lock(); -+ -+ /** -+ * Covers the variants of pickaxes. -+ */ -+ public static final MaterialSetTag PICKAXES = new MaterialSetTag(keyFor("pickaxes")) -+ .endsWith("_PICKAXE") -+ .ensureSize("PICKAXES", 6).lock(); -+ -+ /** -+ * Covers the variants of axes. -+ */ -+ public static final MaterialSetTag AXES = new MaterialSetTag(keyFor("axes")) -+ .endsWith("_AXE") -+ .ensureSize("AXES", 6).lock(); -+ -+ /** -+ * Covers the variants of hoes. -+ */ -+ public static final MaterialSetTag HOES = new MaterialSetTag(keyFor("hoes")) -+ .endsWith("_HOE") -+ .ensureSize("HOES", 6).lock(); -+ -+ /** -+ * Covers the variants of helmets. -+ */ -+ public static final MaterialSetTag HELMETS = new MaterialSetTag(keyFor("helmets")) -+ .endsWith("_HELMET") -+ .ensureSize("HELMETS", 7).lock(); -+ -+ /** -+ * Covers the variants of items that can be equipped in the helmet slot. -+ */ -+ public static final MaterialSetTag HEAD_EQUIPPABLE = new MaterialSetTag(keyFor("head_equippable")) -+ .endsWith("_HELMET") -+ .add(SKULLS) -+ .add(Material.CARVED_PUMPKIN) -+ .ensureSize("HEAD_EQUIPPABLE", 20).lock(); -+ -+ /** -+ * Covers the variants of chestplate. -+ */ -+ public static final MaterialSetTag CHESTPLATES = new MaterialSetTag(keyFor("chestplates")) -+ .endsWith("_CHESTPLATE") -+ .ensureSize("CHESTPLATES", 6).lock(); -+ -+ /** -+ * Covers the variants of items that can be equipped in the chest slot. -+ */ -+ public static final MaterialSetTag CHEST_EQUIPPABLE = new MaterialSetTag(keyFor("chest_equippable")) -+ .endsWith("_CHESTPLATE") -+ .add(Material.ELYTRA) -+ .ensureSize("CHEST_EQUIPPABLE", 7).lock(); -+ -+ /** -+ * Covers the variants of leggings. -+ */ -+ public static final MaterialSetTag LEGGINGS = new MaterialSetTag(keyFor("leggings")) -+ .endsWith("_LEGGINGS") -+ .ensureSize("LEGGINGS", 6).lock(); -+ -+ /** -+ * Covers the variants of boots. -+ */ -+ public static final MaterialSetTag BOOTS = new MaterialSetTag(keyFor("boots")) -+ .endsWith("_BOOTS") -+ .ensureSize("BOOTS", 6).lock(); -+ -+ /** -+ * Covers all variants of armor. -+ */ -+ public static final MaterialSetTag ARMOR = new MaterialSetTag(keyFor("armor")).add(HELMETS, CHESTPLATES, LEGGINGS, BOOTS) -+ .ensureSize("ARMOR", 25).lock(); -+ -+ /** -+ * Covers the variants of bows. -+ */ -+ public static final MaterialSetTag BOWS = new MaterialSetTag(keyFor("bows")) -+ .add(Material.BOW) -+ .add(Material.CROSSBOW) -+ .ensureSize("BOWS", 2).lock(); -+ -+ /** -+ * Covers the variants of player-throwable projectiles (not requiring a bow or any other "assistance"). -+ */ -+ public static final MaterialSetTag THROWABLE_PROJECTILES = new MaterialSetTag(keyFor("throwable_projectiles")) -+ .add(Material.EGG, Material.SNOWBALL, Material.SPLASH_POTION, Material.TRIDENT, Material.ENDER_PEARL, Material.EXPERIENCE_BOTTLE, Material.FIREWORK_ROCKET).lock(); -+ -+ /** -+ * Covers materials that can be colored, such as wool, shulker boxes, stained glass etc. -+ */ -+ @SuppressWarnings("unchecked") -+ public static final MaterialSetTag COLORABLE = new MaterialSetTag(keyFor("colorable")) -+ .add(Tag.WOOL, Tag.CARPETS).add(SHULKER_BOXES, STAINED_GLASS, STAINED_GLASS_PANES, CONCRETES, BEDS).lock(); -+ //.ensureSize("COLORABLE", 81).lock(); unit test don't have the vanilla item tags, so counts don't line up for real -+ -+ /** -+ * Covers the variants of coral. -+ */ -+ public static final MaterialSetTag CORAL = new MaterialSetTag(keyFor("coral")) -+ .endsWith("_CORAL") -+ .ensureSize("CORAL", 10).lock(); -+ -+ /** -+ * Covers the variants of coral fans. -+ */ -+ public static final MaterialSetTag CORAL_FANS = new MaterialSetTag(keyFor("coral_fans")) -+ .endsWith("_CORAL_FAN") -+ .endsWith("_CORAL_WALL_FAN") -+ .ensureSize("CORAL_FANS", 20).lock(); -+ -+ /** -+ * Covers the variants of coral blocks. -+ */ -+ public static final MaterialSetTag CORAL_BLOCKS = new MaterialSetTag(keyFor("coral_blocks")) -+ .endsWith("_CORAL_BLOCK") -+ .ensureSize("CORAL_BLOCKS", 10).lock(); -+ -+ /** -+ * Covers all items that can be enchanted from the enchantment table or anvil. -+ */ -+ public static final MaterialSetTag ENCHANTABLE = new MaterialSetTag(keyFor("enchantable")) -+ .add(PICKAXES, SWORDS, SHOVELS, AXES, HOES, HELMETS, CHEST_EQUIPPABLE, LEGGINGS, BOOTS, BOWS) -+ .add(Material.TRIDENT, Material.SHIELD, Material.FISHING_ROD, Material.SHEARS, Material.FLINT_AND_STEEL, Material.CARROT_ON_A_STICK, Material.WARPED_FUNGUS_ON_A_STICK) -+ .ensureSize("ENCHANTABLE", 65).lock(); -+ -+ /** -+ * Covers the variants of raw ores. -+ */ -+ public static final MaterialSetTag RAW_ORES = new MaterialSetTag(keyFor("raw_ores")) -+ .add(Material.RAW_COPPER, Material.RAW_GOLD, Material.RAW_IRON).lock(); -+ -+ /** -+ * Covers the variants of deepslate ores. -+ */ -+ public static final MaterialSetTag DEEPSLATE_ORES = new MaterialSetTag(keyFor("deepslate_ores")) -+ .add(material -> material.name().startsWith("DEEPSLATE_") && material.name().endsWith("_ORE")) -+ .ensureSize("DEEPSLATE_ORES", 8).lock(); -+ -+ /** -+ * Covers the variants of raw ore blocks. -+ */ -+ public static final MaterialSetTag RAW_ORE_BLOCKS = new MaterialSetTag(keyFor("raw_ore_blocks")) -+ .add(Material.RAW_COPPER_BLOCK, Material.RAW_GOLD_BLOCK, Material.RAW_IRON_BLOCK).lock(); -+ -+ /** -+ * Covers all oxidized copper blocks. -+ */ -+ public static final MaterialSetTag OXIDIZED_COPPER_BLOCKS = new MaterialSetTag(keyFor("oxidized_copper_blocks")) -+ .startsWith("OXIDIZED_").startsWith("WAXED_OXIDIZED_").ensureSize("OXIDIZED_COPPER_BLOCKS", 8).lock(); -+ -+ /** -+ * Covers all weathered copper blocks. -+ */ -+ public static final MaterialSetTag WEATHERED_COPPER_BLOCKS = new MaterialSetTag(keyFor("weathered_copper_blocks")) -+ .startsWith("WEATHERED_").startsWith("WAXED_WEATHERED_").ensureSize("WEATHERED_COPPER_BLOCKS", 8).lock(); -+ -+ /** -+ * Covers all exposed copper blocks. -+ */ -+ public static final MaterialSetTag EXPOSED_COPPER_BLOCKS = new MaterialSetTag(keyFor("exposed_copper_blocks")) -+ .startsWith("EXPOSED_").startsWith("WAXED_EXPOSED_").ensureSize("EXPOSED_COPPER_BLOCKS", 8).lock(); -+ -+ /** -+ * Covers all un-weathered copper blocks. -+ */ -+ public static final MaterialSetTag UNAFFECTED_COPPER_BLOCKS = new MaterialSetTag(keyFor("unaffected_copper_blocks")) -+ .startsWith("CUT_COPPER").startsWith("WAXED_CUT_COPPER").add(Material.COPPER_BLOCK).add(Material.WAXED_COPPER_BLOCK).ensureSize("UNAFFECTED_COPPER_BLOCKS", 8).lock(); -+ -+ /** -+ * Covers all waxed copper blocks. -+ *

      -+ * Combine with other copper-related tags to filter is-waxed or not. -+ */ -+ public static final MaterialSetTag WAXED_COPPER_BLOCKS = new MaterialSetTag(keyFor("waxed_copper_blocks")) -+ .add(m -> m.name().startsWith("WAXED_") && m.name().contains("COPPER")).ensureSize("WAXED_COPPER_BLOCKS", 16).lock(); -+ -+ /** -+ * Covers all un-waxed copper blocks. -+ *

      -+ * Combine with other copper-related tags to filter is-un-waxed or not. -+ */ -+ public static final MaterialSetTag UNWAXED_COPPER_BLOCKS = new MaterialSetTag(keyFor("unwaxed_copper_blocks")) -+ .contains("CUT_COPPER").endsWith("_COPPER").notContains("WAXED").ensureSize("UNWAXED_COPPER_BLOCKS", 16).lock(); -+ -+ /** -+ * Covers all copper block variants. -+ */ -+ public static final MaterialSetTag COPPER_BLOCKS = new MaterialSetTag(keyFor("copper_blocks")) -+ .add(WAXED_COPPER_BLOCKS).add(UNWAXED_COPPER_BLOCKS).ensureSize("COPPER_BLOCKS", 32).lock(); -+ -+ /** -+ * Covers all weathering/waxed states of the plain copper block. -+ */ -+ public static final MaterialSetTag FULL_COPPER_BLOCKS = new MaterialSetTag(keyFor("full_copper_blocks")) -+ .contains("OXIDIZED_COPPER") -+ .contains("WEATHERED_COPPER") -+ .contains("EXPOSED_COPPER") -+ .contains("COPPER_BLOCK") -+ .not(Material.RAW_COPPER_BLOCK) -+ .ensureSize("FULL_COPPER_BLOCKS", 8).lock(); -+ -+ /** -+ * Covers all weathering/waxed states of the cut copper block. -+ */ -+ public static final MaterialSetTag CUT_COPPER_BLOCKS = new MaterialSetTag(keyFor("cut_copper_blocks")) -+ .endsWith("CUT_COPPER").ensureSize("CUT_COPPER_BLOCKS", 8).lock(); -+ -+ /** -+ * Covers all weathering/waxed states of the cut copper stairs. -+ */ -+ public static final MaterialSetTag CUT_COPPER_STAIRS = new MaterialSetTag(keyFor("cut_copper_stairs")) -+ .endsWith("CUT_COPPER_STAIRS").ensureSize("CUT_COPPER_STAIRS", 8).lock(); -+ -+ /** -+ * Covers all weathering/waxed states of the cut copper slab. -+ */ -+ public static final MaterialSetTag CUT_COPPER_SLABS = new MaterialSetTag(keyFor("cut_copper_slabs")) -+ .endsWith("CUT_COPPER_SLAB").ensureSize("CUT_COPPER_SLABS", 8).lock(); -+} -diff --git a/src/main/java/io/papermc/paper/tag/BaseTag.java b/src/main/java/io/papermc/paper/tag/BaseTag.java -new file mode 100644 -index 0000000000000000000000000000000000000000..71484259de4783b861803c48850317eb2d60bda0 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/tag/BaseTag.java -@@ -0,0 +1,180 @@ -+package io.papermc.paper.tag; -+ -+import com.google.common.collect.Lists; -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Tag; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.Collection; -+import java.util.EnumSet; -+import java.util.HashSet; -+import java.util.List; -+import java.util.Set; -+import java.util.function.Predicate; -+import java.util.stream.Collectors; -+ -+public abstract class BaseTag> implements Tag { -+ -+ protected final NamespacedKey key; -+ protected final Set tagged; -+ private final List> globalPredicates; -+ private boolean locked = false; -+ -+ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Predicate filter) { -+ this(clazz, key); -+ add(filter); -+ } -+ -+ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull T...values) { -+ this(clazz, key, Lists.newArrayList(values)); -+ } -+ -+ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Collection values) { -+ this(clazz, key, values, o -> true); -+ } -+ -+ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Collection values, @NotNull Predicate... globalPredicates) { -+ this.key = key != null ? key : NamespacedKey.randomKey(); -+ this.tagged = clazz.isEnum() ? createEnumSet(clazz) : new HashSet<>(); -+ this.tagged.addAll(values); -+ this.globalPredicates = Lists.newArrayList(globalPredicates); -+ } -+ -+ private Set createEnumSet(Class enumClass) { -+ assert enumClass.isEnum(); -+ return (Set) EnumSet.noneOf((Class) enumClass); -+ } -+ -+ public @NotNull C lock() { -+ this.locked = true; -+ return (C) this; -+ } -+ -+ public boolean isLocked() { -+ return this.locked; -+ } -+ -+ private void checkLock() { -+ if (this.locked) { -+ throw new UnsupportedOperationException("Tag (" + this.key + ") is locked"); -+ } -+ } -+ -+ @NotNull -+ @Override -+ public NamespacedKey getKey() { -+ return key; -+ } -+ -+ @NotNull -+ @Override -+ public Set getValues() { -+ return tagged; -+ } -+ -+ @Override -+ public boolean isTagged(@NotNull T item) { -+ return tagged.contains(item); -+ } -+ -+ @NotNull -+ public C add(@NotNull Tag...tags) { -+ for (Tag tag : tags) { -+ add(tag.getValues()); -+ } -+ return (C) this; -+ } -+ -+ @NotNull -+ public C add(@NotNull T...values) { -+ this.checkLock(); -+ this.tagged.addAll(Lists.newArrayList(values)); -+ return (C) this; -+ } -+ -+ @NotNull -+ public C add(@NotNull Collection collection) { -+ this.checkLock(); -+ this.tagged.addAll(collection); -+ return (C) this; -+ } -+ -+ @NotNull -+ public C add(@NotNull Predicate filter) { -+ return add(getAllPossibleValues().stream().filter(globalPredicates.stream().reduce(Predicate::or).orElse(t -> true)).filter(filter).collect(Collectors.toSet())); -+ } -+ -+ @NotNull -+ public C contains(@NotNull String with) { -+ return add(value -> getName(value).contains(with)); -+ } -+ -+ @NotNull -+ public C endsWith(@NotNull String with) { -+ return add(value -> getName(value).endsWith(with)); -+ } -+ -+ @NotNull -+ public C startsWith(@NotNull String with) { -+ return add(value -> getName(value).startsWith(with)); -+ } -+ -+ @NotNull -+ public C not(@NotNull Tag...tags) { -+ for (Tag tag : tags) { -+ not(tag.getValues()); -+ } -+ return (C) this; -+ } -+ -+ @NotNull -+ public C not(@NotNull T...values) { -+ this.checkLock(); -+ this.tagged.removeAll(Lists.newArrayList(values)); -+ return (C) this; -+ } -+ -+ @NotNull -+ public C not(@NotNull Collection values) { -+ this.checkLock(); -+ this.tagged.removeAll(values); -+ return (C) this; -+ } -+ -+ @NotNull -+ public C not(@NotNull Predicate filter) { -+ not(getAllPossibleValues().stream().filter(globalPredicates.stream().reduce(Predicate::or).orElse(t -> true)).filter(filter).collect(Collectors.toSet())); -+ return (C) this; -+ } -+ -+ @NotNull -+ public C notContains(@NotNull String with) { -+ return not(value -> getName(value).contains(with)); -+ } -+ -+ @NotNull -+ public C notEndsWith(@NotNull String with) { -+ return not(value -> getName(value).endsWith(with)); -+ } -+ -+ @NotNull -+ public C notStartsWith(@NotNull String with) { -+ return not(value -> getName(value).startsWith(with)); -+ } -+ -+ @NotNull -+ public C ensureSize(@NotNull String label, int size) { -+ long actual = this.tagged.stream().filter(globalPredicates.stream().reduce(Predicate::or).orElse(t -> true)).count(); -+ if (size != actual) { -+ throw new IllegalStateException(key.toString() + ": " + label + " - Expected " + size + " values, got " + actual); -+ } -+ return (C) this; -+ } -+ -+ @NotNull -+ protected abstract Set getAllPossibleValues(); -+ -+ @NotNull -+ protected abstract String getName(@NotNull T value); -+} -diff --git a/src/main/java/io/papermc/paper/tag/EntitySetTag.java b/src/main/java/io/papermc/paper/tag/EntitySetTag.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c89c4619aaf388197834d98eb95af2f1e93db871 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/tag/EntitySetTag.java -@@ -0,0 +1,42 @@ -+package io.papermc.paper.tag; -+ -+import org.bukkit.NamespacedKey; -+import org.bukkit.entity.EntityType; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.Collection; -+import java.util.Set; -+import java.util.function.Predicate; -+import java.util.stream.Collectors; -+import java.util.stream.Stream; -+ -+public class EntitySetTag extends BaseTag { -+ -+ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Predicate filter) { -+ super(EntityType.class, key, filter); -+ } -+ -+ public EntitySetTag(@NotNull NamespacedKey key, @NotNull EntityType... values) { -+ super(EntityType.class, key, values); -+ } -+ -+ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Collection values) { -+ super(EntityType.class, key, values); -+ } -+ -+ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Collection values, @NotNull Predicate... globalPredicates) { -+ super(EntityType.class, key, values, globalPredicates); -+ } -+ -+ @NotNull -+ @Override -+ protected Set getAllPossibleValues() { -+ return Stream.of(EntityType.values()).collect(Collectors.toSet()); -+ } -+ -+ @NotNull -+ @Override -+ protected String getName(@NotNull EntityType value) { -+ return value.name(); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/tag/EntityTags.java b/src/main/java/io/papermc/paper/tag/EntityTags.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d7eb49a05c3f0cacf285f8995433c5d5e988de0f ---- /dev/null -+++ b/src/main/java/io/papermc/paper/tag/EntityTags.java -@@ -0,0 +1,54 @@ -+package io.papermc.paper.tag; -+ -+import org.bukkit.NamespacedKey; -+ -+import static org.bukkit.entity.EntityType.*; -+ -+/** -+ * All tags in this class are unmodifiable, attempting to modify them will throw an -+ * {@link UnsupportedOperationException}. -+ */ -+public class EntityTags { -+ -+ private static NamespacedKey keyFor(String key) { -+ //noinspection deprecation -+ return new NamespacedKey("paper", key + "_settag"); -+ } -+ -+ /** -+ * Covers undead mobs -+ * @see https://minecraft.gamepedia.com/Mob#Undead_mobs -+ */ -+ public static final EntitySetTag UNDEADS = new EntitySetTag(keyFor("undeads")) -+ .add(DROWNED, HUSK, PHANTOM, SKELETON, SKELETON_HORSE, STRAY, WITHER, WITHER_SKELETON, ZOGLIN, ZOMBIE, ZOMBIE_HORSE, ZOMBIE_VILLAGER, ZOMBIFIED_PIGLIN) -+ .ensureSize("UNDEADS", 13).lock(); -+ -+ /** -+ * Covers all horses -+ */ -+ public static final EntitySetTag HORSES = new EntitySetTag(keyFor("horses")) -+ .contains("HORSE") -+ .ensureSize("HORSES", 3).lock(); -+ -+ /** -+ * Covers all minecarts -+ */ -+ public static final EntitySetTag MINECARTS = new EntitySetTag(keyFor("minecarts")) -+ .contains("MINECART") -+ .ensureSize("MINECARTS", 7).lock(); -+ -+ /** -+ * Covers mobs that split into smaller mobs -+ */ -+ public static final EntitySetTag SPLITTING_MOBS = new EntitySetTag(keyFor("splitting_mobs")) -+ .add(SLIME, MAGMA_CUBE) -+ .ensureSize("SLIMES", 2).lock(); -+ -+ /** -+ * Covers all water based mobs -+ * @see https://minecraft.gamepedia.com/Mob#Water-based_mobs -+ */ -+ public static final EntitySetTag WATER_BASED = new EntitySetTag(keyFor("water_based")) -+ .add(AXOLOTL, DOLPHIN, SQUID, GLOW_SQUID, GUARDIAN, ELDER_GUARDIAN, TURTLE, COD, SALMON, PUFFERFISH, TROPICAL_FISH) -+ .ensureSize("WATER_BASED", 11).lock(); -+} -diff --git a/src/main/java/org/bukkit/Tag.java b/src/main/java/org/bukkit/Tag.java -index 7e3c8812247f86313c49c1a0d9af557abd30d029..33f022a01e44e6b806e6d38eef003da161b6be53 100644 ---- a/src/main/java/org/bukkit/Tag.java -+++ b/src/main/java/org/bukkit/Tag.java -@@ -11,6 +11,10 @@ import org.jetbrains.annotations.NotNull; - * Note that whilst all tags defined within this interface must be present in - * implementations, their existence is not guaranteed across future versions. - * -+ *

      Custom tags defined by Paper are not present (as constants) in this class. -+ * To access them please refer to {@link com.destroystokyo.paper.MaterialTags} -+ * and {@link io.papermc.paper.tag.EntityTags}.

      -+ * - * @param the type of things grouped by this tag - */ - public interface Tag extends Keyed { -diff --git a/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java b/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f849d8b12a7e3d1606698408ab4bb140a3b370e4 ---- /dev/null -+++ b/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java -@@ -0,0 +1,65 @@ -+/* -+ * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License -+ */ -+ -+package com.destroystokyo.paper; -+ -+import io.papermc.paper.tag.BaseTag; -+import io.papermc.paper.tag.EntityTags; -+import org.bukkit.Bukkit; -+import org.bukkit.TestServer; -+import org.junit.Before; -+import org.junit.Test; -+ -+import java.lang.reflect.Field; -+import java.lang.reflect.Modifier; -+import java.util.HashSet; -+import java.util.Set; -+import java.util.logging.Level; -+ -+import static org.junit.Assert.assertTrue; -+ -+public class MaterialTagsTest { -+ -+ @Before -+ public void before() { -+ TestServer.getInstance(); -+ } -+ -+ @Test -+ public void testInitialize() { -+ try { -+ MaterialTags.SHULKER_BOXES.getValues(); -+ assert true; -+ } catch (Throwable e) { -+ Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e); -+ assert false; -+ } -+ } -+ -+ @Test -+ public void testLocked() { -+ testLocked(MaterialTags.class); -+ testLocked(EntityTags.class); -+ } -+ -+ private static void testLocked(Class clazz) { -+ for (BaseTag tag : collectTags(clazz)) { -+ assertTrue("Tag " + tag.key() + " is not locked", tag.isLocked()); -+ } -+ } -+ -+ private static Set> collectTags(Class clazz) { -+ Set> tags = new HashSet<>(); -+ try { -+ for (Field field : clazz.getDeclaredFields()) { -+ if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && BaseTag.class.isAssignableFrom(field.getType())) { -+ tags.add((BaseTag) field.get(null)); -+ } -+ } -+ } catch (IllegalAccessException e) { -+ e.printStackTrace(); -+ } -+ return tags; -+ } -+} -diff --git a/src/test/java/io/papermc/paper/EntityTagsTest.java b/src/test/java/io/papermc/paper/EntityTagsTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..06bb9d1180361d3d00c699796bbacbce5bef2177 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/EntityTagsTest.java -@@ -0,0 +1,24 @@ -+package io.papermc.paper; -+ -+import com.destroystokyo.paper.MaterialTags; -+import io.papermc.paper.tag.EntityTags; -+import org.bukkit.Bukkit; -+import org.bukkit.TestServer; -+import org.junit.Test; -+ -+import java.util.logging.Level; -+ -+public class EntityTagsTest { -+ -+ @Test -+ public void testInitialize() { -+ try { -+ TestServer.getInstance(); -+ EntityTags.HORSES.getValues(); -+ assert true; -+ } catch (Throwable e) { -+ Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e); -+ assert false; -+ } -+ } -+} -diff --git a/src/test/java/org/bukkit/TestServer.java b/src/test/java/org/bukkit/TestServer.java -index 622cf46ae12540dc168631a4884a9a69e9d2f6c7..2f907c18c8f3228df107bfc05c5454354e89b943 100644 ---- a/src/test/java/org/bukkit/TestServer.java -+++ b/src/test/java/org/bukkit/TestServer.java -@@ -32,6 +32,16 @@ public final class TestServer implements InvocationHandler { - } - } - ); -+ // Paper start -+ methodMap.put( -+ Server.class.getMethod("getTag", String.class, NamespacedKey.class, Class.class), -+ new MethodHandler() { -+ public Object handle(TestServer server, Object[] args) { -+ return new com.destroystokyo.paper.MaterialSetTag(); -+ } -+ } -+ ); -+ // Paper end - methodMap.put( - Server.class.getMethod("getPluginManager"), - new MethodHandler() { diff --git a/patches/api/0157-Change-the-reserved-channel-check-to-be-sensible.patch b/patches/api/0157-Change-the-reserved-channel-check-to-be-sensible.patch new file mode 100644 index 000000000000..332cd2a1ac04 --- /dev/null +++ b/patches/api/0157-Change-the-reserved-channel-check-to-be-sensible.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DoNotSpamPls <7570108+DoNotSpamPls@users.noreply.github.com> +Date: Tue, 23 Oct 2018 19:32:55 +0300 +Subject: [PATCH] Change the reserved channel check to be sensible + + +diff --git a/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java b/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java +index ed39f5116bdfba63f14aadfe81173fe2b68af4d7..8e96be6033e94d4f0bebb346ad222abe18d1f274 100644 +--- a/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java ++++ b/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java +@@ -172,7 +172,7 @@ public class StandardMessenger implements Messenger { + public boolean isReservedChannel(@NotNull String channel) { + channel = validateAndCorrectChannel(channel); + +- return channel.contains("minecraft") && !channel.equals("minecraft:brand"); ++ return channel.equals("minecraft:register") || channel.equals("minecraft:unregister"); // Paper + } + + @Override +diff --git a/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java b/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java +index 144ae2f31badb8142bc4a76a7abab37a57118191..8ffaa33d97c045c0fd6851ec2f189344b4a070d2 100644 +--- a/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java ++++ b/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java +@@ -26,8 +26,8 @@ public class StandardMessengerTest { + assertTrue(messenger.isReservedChannel("minecraft:register")); + assertFalse(messenger.isReservedChannel("test:register")); + assertTrue(messenger.isReservedChannel("minecraft:unregister")); +- assertFalse(messenger.isReservedChannel("test:nregister")); +- assertTrue(messenger.isReservedChannel("minecraft:something")); ++ assertFalse(messenger.isReservedChannel("test:unregister")); // Paper - fix typo ++ assertFalse(messenger.isReservedChannel("minecraft:something")); // Paper - now less strict + assertFalse(messenger.isReservedChannel("minecraft:brand")); + } + diff --git a/patches/api/0158-Add-PlayerConnectionCloseEvent.patch b/patches/api/0158-Add-PlayerConnectionCloseEvent.patch new file mode 100644 index 000000000000..98f34635d059 --- /dev/null +++ b/patches/api/0158-Add-PlayerConnectionCloseEvent.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 7 Oct 2018 12:05:06 -0700 +Subject: [PATCH] Add PlayerConnectionCloseEvent + +This event is invoked when a player has disconnected. It is guaranteed that, +if the server is in online-mode, that the provided uuid and username have been +validated. + +The event is invoked for players who have not yet logged into the world, whereas +PlayerQuitEvent is only invoked on players who have logged into the world. + +The event is invoked for players who have already logged into the world, +although whether or not the player exists in the world at the time of +firing is undefined. (That is, whether the plugin can retrieve a Player object +using the event parameters is undefined). However, it is guaranteed that this +event is invoked AFTER PlayerQuitEvent, if the player has already logged into +the world. + +This event is guaranteed to never fire unless AsyncPlayerPreLoginEvent has +been called beforehand, and this event may not be called in parallel with +AsyncPlayerPreLoginEvent for the same connection. + +Cancelling the AsyncPlayerPreLoginEvent guarantees the corresponding +PlayerConnectionCloseEvent is never called. + +The event may be invoked asynchronously or synchronously. As it stands, +it is never invoked asynchronously. However, plugins should check +Event#isAsynchronous to be future-proof. + +On purpose, the deprecated PlayerPreLoginEvent event is left out of the +API spec for this event. Plugins should not be using that event, and +how PlayerPreLoginEvent interacts with PlayerConnectionCloseEvent +is undefined. + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5f5afcdb3c9e669ed0e730c720ad91d16b95602c +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java +@@ -0,0 +1,83 @@ ++package com.destroystokyo.paper.event.player; ++ ++import java.net.InetAddress; ++import java.util.UUID; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.AsyncPlayerPreLoginEvent; ++import org.bukkit.event.player.PlayerQuitEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ *

      ++ * This event is invoked when a player has disconnected. It is guaranteed that, ++ * if the server is in online-mode, that the provided uuid and username have been ++ * validated. ++ *

      ++ * The event is invoked for players who have not yet logged into the world, whereas ++ * {@link PlayerQuitEvent} is only invoked on players who have logged into the world. ++ *

      ++ * The event is invoked for players who have already logged into the world, ++ * although whether or not the player exists in the world at the time of ++ * firing is undefined. (That is, whether the plugin can retrieve a Player object ++ * using the event parameters is undefined). However, it is guaranteed that this ++ * event is invoked AFTER {@link PlayerQuitEvent}, if the player has already logged into the world. ++ *

      ++ * This event is guaranteed to never fire unless {@link AsyncPlayerPreLoginEvent} has ++ * been fired beforehand, and this event may not be called in parallel with ++ * {@link AsyncPlayerPreLoginEvent} for the same connection. ++ *

      ++ * Cancelling the {@link AsyncPlayerPreLoginEvent} guarantees the corresponding ++ * {@code PlayerConnectionCloseEvent} is never called. ++ *

      ++ * The event may be invoked asynchronously or synchronously. Plugins should check ++ * {@link Event#isAsynchronous()} and handle accordingly. ++ */ ++@NullMarked ++public class PlayerConnectionCloseEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final UUID playerUniqueId; ++ private final String playerName; ++ private final InetAddress ipAddress; ++ ++ @ApiStatus.Internal ++ public PlayerConnectionCloseEvent(final UUID playerUniqueId, final String playerName, final InetAddress ipAddress, final boolean async) { ++ super(async); ++ this.playerUniqueId = playerUniqueId; ++ this.playerName = playerName; ++ this.ipAddress = ipAddress; ++ } ++ ++ /** ++ * Returns the {@code UUID} of the player disconnecting. ++ */ ++ public UUID getPlayerUniqueId() { ++ return this.playerUniqueId; ++ } ++ ++ /** ++ * Returns the name of the player disconnecting. ++ */ ++ public String getPlayerName() { ++ return this.playerName; ++ } ++ ++ /** ++ * Returns the player's IP address. ++ */ ++ public InetAddress getIpAddress() { ++ return this.ipAddress; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0158-PreSpawnerSpawnEvent.patch b/patches/api/0158-PreSpawnerSpawnEvent.patch deleted file mode 100644 index dcb362d8bc65..000000000000 --- a/patches/api/0158-PreSpawnerSpawnEvent.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Tue, 18 Sep 2018 23:50:10 +0100 -Subject: [PATCH] PreSpawnerSpawnEvent - -This adds a separate event before an entity is spawned by a spawner -which contains the location of the spawner too similarly to how the -SpawnerSpawnEvent gets called instead of the CreatureSpawnEvent for -spawners. - -Dropped as it does not apply due to the earlier PreCreatureSpawnEvent patch not being applied - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..48cff063594840a07aeaf35513780e28ea019a76 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/PreSpawnerSpawnEvent.java -@@ -0,0 +1,29 @@ -+package com.destroystokyo.paper.event.entity; -+ -+ -+import com.google.common.base.Preconditions; -+import org.bukkit.Location; -+import org.bukkit.entity.EntityType; -+import org.bukkit.event.entity.CreatureSpawnEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called before an entity is spawned into a world by a spawner. -+ * -+ * This only includes the spawner's location and not the full BlockState snapshot for performance reasons. -+ * If you really need it you have to get the spawner yourself. -+ */ -+ -+public class PreSpawnerSpawnEvent extends PreCreatureSpawnEvent { -+ @NotNull private final Location spawnerLocation; -+ -+ public PreSpawnerSpawnEvent(@NotNull Location location, @NotNull EntityType type, @NotNull Location spawnerLocation) { -+ super(location, type, CreatureSpawnEvent.SpawnReason.SPAWNER); -+ this.spawnerLocation = Preconditions.checkNotNull(spawnerLocation, "Spawner location may not be null"); -+ } -+ -+ @NotNull -+ public Location getSpawnerLocation() { -+ return spawnerLocation; -+ } -+} diff --git a/patches/api/0159-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch b/patches/api/0159-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch new file mode 100644 index 000000000000..82d263b9e06a --- /dev/null +++ b/patches/api/0159-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Wed, 2 Jan 2019 00:31:12 -0600 +Subject: [PATCH] Add APIs to replace OfflinePlayer#getLastPlayed + +Currently OfflinePlayer#getLastPlayed could more accurately be described +as "OfflinePlayer#getLastTimeTheirDataWasSaved". + +The API doc says it should return the last time the server "witnessed" +the player, whilst also saying it should return the last time they +logged in. The current implementation does neither. + +Given this interesting contradiction in the API documentation and the +current defacto implementation, I've elected to deprecate (with no +intent to remove) and replace it with two new methods, clearly named and +documented as to their purpose. + +diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java +index 11b470b07a8b5d9e7f87df5abe9bd4f5bf9f86ef..9facde856fa9b1b8f2a6198a1b541b819ea12518 100644 +--- a/src/main/java/org/bukkit/OfflinePlayer.java ++++ b/src/main/java/org/bukkit/OfflinePlayer.java +@@ -223,7 +223,9 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio + * UTC. + * + * @return Date of last log-in for this player, or 0 ++ * @deprecated The API contract is ambiguous and the implementation may or may not return the correct value given this API ambiguity. It is instead recommended use {@link #getLastLogin()} or {@link #getLastSeen()} depending on your needs. + */ ++ @Deprecated + public long getLastPlayed(); + + /** +@@ -246,6 +248,30 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio + @Nullable + @Deprecated(since = "1.20.4") + public Location getBedSpawnLocation(); ++ // Paper start ++ /** ++ * Gets the last date and time that this player logged into the server. ++ *

      ++ * If the player has never played before, this will return 0. Otherwise, ++ * it will be the amount of milliseconds since midnight, January 1, 1970 ++ * UTC. ++ * ++ * @return last login time ++ */ ++ public long getLastLogin(); ++ ++ /** ++ * Gets the last date and time that this player was seen on the server. ++ *

      ++ * If the player has never played before, this will return 0. If the ++ * player is currently online, this will return the current time. ++ * Otherwise it will be the amount of milliseconds since midnight, ++ * January 1, 1970 UTC. ++ * ++ * @return last seen time ++ */ ++ public long getLastSeen(); ++ // Paper end + + /** + * Gets the Location where the player will spawn at, null if they diff --git a/patches/api/0159-Add-LivingEntity-getTargetEntity.patch b/patches/api/0159-Add-LivingEntity-getTargetEntity.patch deleted file mode 100644 index 5e2bb493a6ad..000000000000 --- a/patches/api/0159-Add-LivingEntity-getTargetEntity.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 22 Sep 2018 00:32:53 -0500 -Subject: [PATCH] Add LivingEntity#getTargetEntity - - -diff --git a/src/main/java/com/destroystokyo/paper/entity/TargetEntityInfo.java b/src/main/java/com/destroystokyo/paper/entity/TargetEntityInfo.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f52644fab1522bdf83ff4f489e9805b274421094 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/TargetEntityInfo.java -@@ -0,0 +1,38 @@ -+package com.destroystokyo.paper.entity; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.util.Vector; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Represents information about a targeted entity -+ */ -+public class TargetEntityInfo { -+ private final Entity entity; -+ private final Vector hitVec; -+ -+ public TargetEntityInfo(@NotNull Entity entity, @NotNull Vector hitVec) { -+ this.entity = entity; -+ this.hitVec = hitVec; -+ } -+ -+ /** -+ * Get the entity that is targeted -+ * -+ * @return Targeted entity -+ */ -+ @NotNull -+ public Entity getEntity() { -+ return entity; -+ } -+ -+ /** -+ * Get the position the entity is targeted at -+ * -+ * @return Targeted position -+ */ -+ @NotNull -+ public Vector getHitVector() { -+ return hitVec; -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index a4b1ae0caea94882f601a0420354838c6a52ef28..f479e8c26e88520a47f7beeec753b3af9978bde1 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -150,6 +150,50 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - */ - @Nullable - public com.destroystokyo.paper.block.TargetBlockInfo getTargetBlockInfo(int maxDistance, @NotNull com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode); -+ -+ /** -+ * Gets information about the entity being targeted -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @return entity being targeted, or null if no entity is targeted -+ */ -+ @Nullable -+ public default Entity getTargetEntity(int maxDistance) { -+ return getTargetEntity(maxDistance, false); -+ } -+ -+ /** -+ * Gets information about the entity being targeted -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @param ignoreBlocks true to scan through blocks -+ * @return entity being targeted, or null if no entity is targeted -+ */ -+ @Nullable -+ public Entity getTargetEntity(int maxDistance, boolean ignoreBlocks); -+ -+ /** -+ * Gets information about the entity being targeted -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @return TargetEntityInfo about the entity being targeted, -+ * or null if no entity is targeted -+ */ -+ @Nullable -+ public default com.destroystokyo.paper.entity.TargetEntityInfo getTargetEntityInfo(int maxDistance) { -+ return getTargetEntityInfo(maxDistance, false); -+ } -+ -+ /** -+ * Gets information about the entity being targeted -+ * -+ * @param maxDistance this is the maximum distance to scan -+ * @param ignoreBlocks true to scan through blocks -+ * @return TargetEntityInfo about the entity being targeted, -+ * or null if no entity is targeted -+ */ -+ @Nullable -+ public com.destroystokyo.paper.entity.TargetEntityInfo getTargetEntityInfo(int maxDistance, boolean ignoreBlocks); - // Paper end - - /** diff --git a/patches/api/0160-Add-ItemStack-Recipe-API-helper-methods.patch b/patches/api/0160-Add-ItemStack-Recipe-API-helper-methods.patch new file mode 100644 index 000000000000..bbe19e09f673 --- /dev/null +++ b/patches/api/0160-Add-ItemStack-Recipe-API-helper-methods.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 28 Jan 2014 19:13:57 -0500 +Subject: [PATCH] Add ItemStack Recipe API helper methods + +Allows using ExactChoice Recipes with easier methods + +Redirects some of upstream's APIs to these new methods to avoid +usage of magic values and the deprecated RecipeChoice#getItemStack + +diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java +index 9ef4221742eea7e091f240e2721d5260d153c7c1..653837b5f3a5fb9e5aa806f8ef8ae56fb53cce02 100644 +--- a/src/main/java/org/bukkit/inventory/RecipeChoice.java ++++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java +@@ -157,8 +157,6 @@ public interface RecipeChoice extends Predicate, Cloneable { + /** + * Represents a choice that will be valid only if one of the stacks is + * exactly matched (aside from stack size). +- *
      +- * Only valid for shaped recipes + */ + public static class ExactChoice implements RecipeChoice { + +diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java +index 55f4a6efa7dfb64f131f735f92356d01e7cc775a..90b58219ca99dfd4368119183bb414e51c0f0dd1 100644 +--- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java ++++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java +@@ -180,6 +180,13 @@ public class ShapedRecipe extends CraftingRecipe { + return this; + } + ++ // Paper start ++ @NotNull ++ public ShapedRecipe setIngredient(char key, @NotNull ItemStack item) { ++ return setIngredient(key, new RecipeChoice.ExactChoice(item)); ++ } ++ // Paper end ++ + /** + * Get a copy of the ingredients map. + * +diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +index a9d1f9fc129f757353b879fc5946c4b9299833ea..d4a9572a0fedee8993d32ca006a28a242d148e36 100644 +--- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java ++++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +@@ -132,6 +132,40 @@ public class ShapelessRecipe extends CraftingRecipe { + return this; + } + ++ // Paper start ++ @NotNull ++ public ShapelessRecipe addIngredient(@NotNull ItemStack item) { ++ return addIngredient(item.getAmount(), item); ++ } ++ ++ @NotNull ++ public ShapelessRecipe addIngredient(int count, @NotNull ItemStack item) { ++ Preconditions.checkArgument(ingredients.size() + count <= 9, "Shapeless recipes cannot have more than 9 ingredients"); ++ while (count-- > 0) { ++ ingredients.add(new RecipeChoice.ExactChoice(item)); ++ } ++ return this; ++ } ++ ++ @NotNull ++ public ShapelessRecipe removeIngredient(@NotNull ItemStack item) { ++ return removeIngredient(1, item); ++ } ++ ++ @NotNull ++ public ShapelessRecipe removeIngredient(int count, @NotNull ItemStack item) { ++ Iterator iterator = ingredients.iterator(); ++ while (count > 0 && iterator.hasNext()) { ++ RecipeChoice choice = iterator.next(); ++ if (choice.test(item)) { ++ iterator.remove(); ++ count--; ++ } ++ } ++ return this; ++ } ++ // Paper end ++ + /** + * Removes an ingredient from the list. + * +@@ -155,7 +189,7 @@ public class ShapelessRecipe extends CraftingRecipe { + */ + @NotNull + public ShapelessRecipe removeIngredient(@NotNull Material ingredient) { +- return removeIngredient(ingredient, 0); ++ return removeIngredient(new ItemStack(ingredient)); // Paper - avoid using deprecated methods (magic values; RecipeChoice#getItemStack) + } + + /** +@@ -182,7 +216,7 @@ public class ShapelessRecipe extends CraftingRecipe { + */ + @NotNull + public ShapelessRecipe removeIngredient(int count, @NotNull Material ingredient) { +- return removeIngredient(count, ingredient, 0); ++ return removeIngredient(count, new ItemStack(ingredient)); // Paper - avoid using deprecated methods (magic values; RecipeChoice#getItemStack) + } + + /** diff --git a/patches/api/0160-Add-sun-related-API.patch b/patches/api/0160-Add-sun-related-API.patch deleted file mode 100644 index 2e610f8a1a3f..000000000000 --- a/patches/api/0160-Add-sun-related-API.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 7 Oct 2018 00:54:15 -0500 -Subject: [PATCH] Add sun related API - - -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 3e3682be2a1afe92ccdc9a1d97469a69f952a9ed..8f7536e5ef73328cb69f7214956aac582a7d6f24 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -1796,6 +1796,16 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - */ - public void setFullTime(long time); - -+ // Paper start -+ -+ /** -+ * Check if it is currently daytime in this world -+ * -+ * @return True if it is daytime -+ */ -+ public boolean isDayTime(); -+ // Paper end -+ - /** - * Gets the full in-game time on this world since the world generation - * -diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java -index cc30b4e22ee238de13f031398fc566f4123694ff..55c5227a340e34621160afc9fae3ea843492881d 100644 ---- a/src/main/java/org/bukkit/entity/Mob.java -+++ b/src/main/java/org/bukkit/entity/Mob.java -@@ -19,6 +19,13 @@ public interface Mob extends LivingEntity, Lootable { - */ - @NotNull - com.destroystokyo.paper.entity.Pathfinder getPathfinder(); -+ -+ /** -+ * Check if this mob is exposed to daylight -+ * -+ * @return True if mob is exposed to daylight -+ */ -+ boolean isInDaylight(); - // Paper end - /** - * Instructs this Mob to set the specified LivingEntity as its target. diff --git a/patches/api/0161-BlockDestroyEvent.patch b/patches/api/0161-BlockDestroyEvent.patch new file mode 100644 index 000000000000..1797b0d60d60 --- /dev/null +++ b/patches/api/0161-BlockDestroyEvent.patch @@ -0,0 +1,138 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 6 Feb 2019 00:19:33 -0500 +Subject: [PATCH] BlockDestroyEvent + +Adds an event for when the server is going to destroy a current block, +potentially causing it to drop. This event can be cancelled to avoid +the block destruction, such as preventing signs from popping when +floating in the air. + +This can replace many uses of BlockPhysicsEvent + +diff --git a/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java b/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..122ccdef02c292c5705a6ac0a96e6095d28bd7bf +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java +@@ -0,0 +1,120 @@ ++package com.destroystokyo.paper.event.block; ++ ++import org.bukkit.block.Block; ++import org.bukkit.block.data.BlockData; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockExpEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired anytime the server intends to 'destroy' a block through some triggering reason. ++ * This does not fire anytime a block is set to air, but only with more direct triggers such ++ * as physics updates, pistons, Entities changing blocks, commands set to "Destroy". ++ *

      ++ * This event is associated with the game playing a sound effect at the block in question, when ++ * something can be described as "intend to destroy what is there", ++ *

      ++ * Events such as leaves decaying, pistons retracting (where the block is moving), does NOT fire this event. ++ */ ++@NullMarked ++public class BlockDestroyEvent extends BlockExpEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final BlockData newState; ++ private boolean willDrop; ++ private boolean playEffect = true; ++ private BlockData effectBlock; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public BlockDestroyEvent(final Block block, final BlockData newState, final BlockData effectBlock, final int xp, final boolean willDrop) { ++ super(block, xp); ++ this.newState = newState; ++ this.effectBlock = effectBlock; ++ this.willDrop = willDrop; ++ } ++ ++ /** ++ * Get the effect that will be played when the block is broken. ++ * ++ * @return block break effect ++ */ ++ public BlockData getEffectBlock() { ++ return this.effectBlock; ++ } ++ ++ /** ++ * Sets the effect that will be played when the block is broken. ++ * Note: {@link BlockDestroyEvent#playEffect()} must be {@code true} in order for this effect to be ++ * played. ++ * ++ * @param effectBlock block effect ++ */ ++ public void setEffectBlock(final BlockData effectBlock) { ++ this.effectBlock = effectBlock; ++ } ++ ++ /** ++ * @return The new state of this block (Air, or a Fluid type) ++ */ ++ public BlockData getNewState() { ++ return this.newState.clone(); ++ } ++ ++ /** ++ * @return If the server is going to drop the block in question with this destroy event ++ */ ++ public boolean willDrop() { ++ return this.willDrop; ++ } ++ ++ /** ++ * @param willDrop If the server is going to drop the block in question with this destroy event ++ */ ++ public void setWillDrop(final boolean willDrop) { ++ this.willDrop = willDrop; ++ } ++ ++ /** ++ * @return If the server is going to play the sound effect for this destruction ++ */ ++ public boolean playEffect() { ++ return this.playEffect; ++ } ++ ++ /** ++ * @param playEffect If the server should play the sound effect for this destruction ++ */ ++ public void setPlayEffect(final boolean playEffect) { ++ this.playEffect = playEffect; ++ } ++ ++ /** ++ * @return If the event is cancelled, meaning the block will not be destroyed ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * If the event is cancelled, the block will remain in its previous state. ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0161-Turtle-API.patch b/patches/api/0161-Turtle-API.patch deleted file mode 100644 index 8d4767cd07aa..000000000000 --- a/patches/api/0161-Turtle-API.patch +++ /dev/null @@ -1,290 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 28 Sep 2018 17:08:09 -0500 -Subject: [PATCH] Turtle API - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..021356d151ed638068e3e89b8cc77b3795883233 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleGoHomeEvent.java -@@ -0,0 +1,49 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Turtle; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a Turtle decides to go home -+ */ -+public class TurtleGoHomeEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled = false; -+ -+ public TurtleGoHomeEvent(@NotNull Turtle turtle) { -+ super(turtle); -+ } -+ -+ /** -+ * The turtle going home -+ * -+ * @return The turtle -+ */ -+ @NotNull -+ public Turtle getEntity() { -+ return (Turtle) entity; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a315c5185cd465dcf63c0ababef195da76dfc786 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleLayEggEvent.java -@@ -0,0 +1,87 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.entity.Turtle; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a Turtle lays eggs -+ */ -+public class TurtleLayEggEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled = false; -+ @NotNull -+ private final Location location; -+ private int eggCount; -+ -+ public TurtleLayEggEvent(@NotNull Turtle turtle, @NotNull Location location, int eggCount) { -+ super(turtle); -+ this.location = location; -+ this.eggCount = eggCount; -+ } -+ -+ /** -+ * The turtle laying the eggs -+ * -+ * @return The turtle -+ */ -+ @NotNull -+ public Turtle getEntity() { -+ return (Turtle) entity; -+ } -+ -+ /** -+ * Get the location where the eggs are being laid -+ * -+ * @return Location of eggs -+ */ -+ @NotNull -+ public Location getLocation() { -+ return location; -+ } -+ -+ /** -+ * Get the number of eggs being laid -+ * -+ * @return Number of eggs -+ */ -+ public int getEggCount() { -+ return eggCount; -+ } -+ -+ /** -+ * Set the number of eggs being laid -+ * -+ * @param eggCount Number of eggs -+ */ -+ public void setEggCount(int eggCount) { -+ if (eggCount < 1) { -+ cancelled = true; -+ return; -+ } -+ eggCount = Math.min(eggCount, 4); -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..abeb24fccda2acfdb0dfdadacb8fe688bd97cf78 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/TurtleStartDiggingEvent.java -@@ -0,0 +1,62 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.entity.Turtle; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a Turtle starts digging to lay eggs -+ */ -+public class TurtleStartDiggingEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled = false; -+ @NotNull private final Location location; -+ -+ public TurtleStartDiggingEvent(@NotNull Turtle turtle, @NotNull Location location) { -+ super(turtle); -+ this.location = location; -+ } -+ -+ /** -+ * The turtle digging -+ * -+ * @return The turtle -+ */ -+ @NotNull -+ public Turtle getEntity() { -+ return (Turtle) entity; -+ } -+ -+ /** -+ * Get the location where the turtle is digging -+ * -+ * @return Location where digging -+ */ -+ @NotNull -+ public Location getLocation() { -+ return location; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/Turtle.java b/src/main/java/org/bukkit/entity/Turtle.java -index 0a4cd29930c2f1c28f5a3e6884c7dec45b5cac11..8bee07c81172e189fab9b82b398983f509099474 100644 ---- a/src/main/java/org/bukkit/entity/Turtle.java -+++ b/src/main/java/org/bukkit/entity/Turtle.java -@@ -1,6 +1,62 @@ - package org.bukkit.entity; - -+import org.bukkit.Location; -+import org.jetbrains.annotations.NotNull; -+ - /** - * Represents a turtle. - */ --public interface Turtle extends Animals { } -+public interface Turtle extends Animals { -+ // Paper start -+ -+ /** -+ * Get the turtle's home location -+ * -+ * @return Home location -+ */ -+ @NotNull -+ Location getHome(); -+ -+ /** -+ * Set the turtle's home location -+ * -+ * @param location Home location -+ */ -+ void setHome(@NotNull Location location); -+ -+ /** -+ * Check if turtle is currently pathfinding to it's home -+ * -+ * @return True if going home -+ */ -+ boolean isGoingHome(); -+ -+ /** -+ * Get if turtle is digging to lay eggs -+ * -+ * @return True if digging -+ */ -+ boolean isDigging(); -+ -+ /** -+ * Get if turtle is carrying egg -+ * -+ * @return True if carrying egg -+ */ -+ boolean hasEgg(); -+ -+ /** -+ * Set if turtle is carrying egg -+ * -+ * @param hasEgg True if carrying egg -+ */ -+ void setHasEgg(boolean hasEgg); -+ -+ /** -+ * Returns whether the turtle is currently laying an egg. -+ * -+ * @return whether the turtle is laying an egg -+ */ -+ boolean isLayingEgg(); -+ // Paper end -+} diff --git a/patches/api/0162-Add-WhitelistToggleEvent.patch b/patches/api/0162-Add-WhitelistToggleEvent.patch new file mode 100644 index 000000000000..f435f2d8907d --- /dev/null +++ b/patches/api/0162-Add-WhitelistToggleEvent.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Vainomaa +Date: Wed, 13 Mar 2019 20:04:43 +0200 +Subject: [PATCH] Add WhitelistToggleEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java b/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b9a59a28c1dec6c174885892ff40d3caaaf409a4 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java +@@ -0,0 +1,42 @@ ++package com.destroystokyo.paper.event.server; ++ ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * This event is fired when whitelist is toggled ++ * ++ * @author Mark Vainomaa ++ */ ++@NullMarked ++public class WhitelistToggleEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final boolean enabled; ++ ++ @ApiStatus.Internal ++ public WhitelistToggleEvent(final boolean enabled) { ++ this.enabled = enabled; ++ } ++ ++ /** ++ * Gets whether whitelist is going to be enabled or not ++ * ++ * @return Whether whitelist is going to be enabled or not ++ */ ++ public boolean isEnabled() { ++ return this.enabled; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0162-Add-spectator-target-events.patch b/patches/api/0162-Add-spectator-target-events.patch deleted file mode 100644 index c5d4b7c4dbc2..000000000000 --- a/patches/api/0162-Add-spectator-target-events.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Caleb Bassham -Date: Fri, 28 Sep 2018 02:30:56 -0500 -Subject: [PATCH] Add spectator target events - -- PlayerStartSpectatingEntityEvent -- PlayerStopSpectatingEntityEvent - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b8ec7ef2d4ef0683cc0d6ca86885dd9a01f47e16 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerStartSpectatingEntityEvent.java -@@ -0,0 +1,67 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Triggered when a player starts spectating an entity in spectator mode. -+ */ -+public class PlayerStartSpectatingEntityEvent extends PlayerEvent implements Cancellable { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ @NotNull private final Entity currentSpectatorTarget; -+ @NotNull private final Entity newSpectatorTarget; -+ -+ public PlayerStartSpectatingEntityEvent(@NotNull Player player, @NotNull Entity currentSpectatorTarget, @NotNull Entity newSpectatorTarget) { -+ super(player); -+ this.currentSpectatorTarget = currentSpectatorTarget; -+ this.newSpectatorTarget = newSpectatorTarget; -+ } -+ -+ /** -+ * Gets the entity that the player is currently spectating or themselves if they weren't spectating anything -+ * -+ * @return The entity the player is currently spectating (before they start spectating the new target). -+ */ -+ @NotNull -+ public Entity getCurrentSpectatorTarget() { -+ return currentSpectatorTarget; -+ } -+ -+ /** -+ * Gets the new entity that the player will now be spectating -+ * -+ * @return The entity the player is now going to be spectating. -+ */ -+ @NotNull -+ public Entity getNewSpectatorTarget() { -+ return newSpectatorTarget; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -+ -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..693d119ab920a1bd0d1b5a0feb092631715ec0ad ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerStopSpectatingEntityEvent.java -@@ -0,0 +1,54 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Triggered when a player stops spectating an entity in spectator mode. -+ */ -+public class PlayerStopSpectatingEntityEvent extends PlayerEvent implements Cancellable { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ @NotNull private final Entity spectatorTarget; -+ -+ public PlayerStopSpectatingEntityEvent(@NotNull Player player, @NotNull Entity spectatorTarget) { -+ super(player); -+ this.spectatorTarget = spectatorTarget; -+ } -+ -+ /** -+ * Gets the entity that the player is spectating -+ * -+ * @return The entity the player is currently spectating (before they will stop). -+ */ -+ @NotNull -+ public Entity getSpectatorTarget() { -+ return spectatorTarget; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0163-Add-GS4-Query-event.patch b/patches/api/0163-Add-GS4-Query-event.patch new file mode 100644 index 000000000000..d6398c239c8a --- /dev/null +++ b/patches/api/0163-Add-GS4-Query-event.patch @@ -0,0 +1,407 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Vainomaa +Date: Sun, 17 Mar 2019 21:46:27 +0200 +Subject: [PATCH] Add GS4 Query event + + +diff --git a/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5a8813c80e56d17ccaa35a7eef2f6bd70c7a3d96 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java +@@ -0,0 +1,395 @@ ++package com.destroystokyo.paper.event.server; ++ ++import com.google.common.base.Preconditions; ++import com.google.common.collect.ImmutableList; ++import java.net.InetAddress; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.Collection; ++import java.util.List; ++import org.bukkit.Server; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * This event is fired if server is getting queried over GS4 Query protocol. ++ *
      ++ * Adapted from Velocity's ProxyQueryEvent ++ * ++ * @author Mark Vainomaa ++ */ ++@NullMarked ++public final class GS4QueryEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final QueryType queryType; ++ private final InetAddress querierAddress; ++ private QueryResponse response; ++ ++ @ApiStatus.Internal ++ public GS4QueryEvent(final QueryType queryType, final InetAddress querierAddress, final QueryResponse response) { ++ super(true); // should always be called async ++ this.queryType = queryType; ++ this.querierAddress = querierAddress; ++ this.response = response; ++ } ++ ++ /** ++ * Get query type ++ * ++ * @return query type ++ */ ++ public QueryType getQueryType() { ++ return this.queryType; ++ } ++ ++ /** ++ * Get querier address ++ * ++ * @return querier address ++ */ ++ public InetAddress getQuerierAddress() { ++ return this.querierAddress; ++ } ++ ++ /** ++ * Get query response ++ * ++ * @return query response ++ */ ++ public QueryResponse getResponse() { ++ return this.response; ++ } ++ ++ /** ++ * Set query response ++ * ++ * @param response query response ++ */ ++ public void setResponse(final QueryResponse response) { ++ this.response = Preconditions.checkNotNull(response, "response"); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ /** ++ * The type of query ++ */ ++ public enum QueryType { ++ /** ++ * Basic query asks only a subset of information, such as motd, game type (hardcoded to

      MINECRAFT
      ), map, ++ * current players, max players, server port and server motd ++ */ ++ BASIC, ++ ++ /** ++ * Full query asks pretty much everything present on this event (only hardcoded values cannot be modified here). ++ */ ++ FULL ++ } ++ ++ public static final class QueryResponse { ++ ++ private final String motd; ++ private final String gameVersion; ++ private final String map; ++ private final int currentPlayers; ++ private final int maxPlayers; ++ private final String hostname; ++ private final int port; ++ private final Collection players; ++ private final String serverVersion; ++ private final Collection plugins; ++ ++ private QueryResponse(final String motd, final String gameVersion, final String map, final int currentPlayers, final int maxPlayers, final String hostname, final int port, final Collection players, final String serverVersion, final Collection plugins) { ++ this.motd = motd; ++ this.gameVersion = gameVersion; ++ this.map = map; ++ this.currentPlayers = currentPlayers; ++ this.maxPlayers = maxPlayers; ++ this.hostname = hostname; ++ this.port = port; ++ this.players = players; ++ this.serverVersion = serverVersion; ++ this.plugins = plugins; ++ } ++ ++ /** ++ * Get motd which will be used to reply to the query. By default, it is {@link Server#getMotd()}. ++ * ++ * @return motd ++ */ ++ public String getMotd() { ++ return this.motd; ++ } ++ ++ /** ++ * Get game version which will be used to reply to the query. By default, supported Minecraft versions range is sent. ++ * ++ * @return game version ++ */ ++ public String getGameVersion() { ++ return this.gameVersion; ++ } ++ ++ /** ++ * Get map name which will be used to reply to the query. By default {@code world} is sent. ++ * ++ * @return map name ++ */ ++ public String getMap() { ++ return this.map; ++ } ++ ++ /** ++ * Get current online player count which will be used to reply to the query. ++ * ++ * @return online player count ++ */ ++ public int getCurrentPlayers() { ++ return this.currentPlayers; ++ } ++ ++ /** ++ * Get max player count which will be used to reply to the query. ++ * ++ * @return max player count ++ */ ++ public int getMaxPlayers() { ++ return this.maxPlayers; ++ } ++ ++ /** ++ * Get server (public facing) hostname. ++ * ++ * @return server hostname ++ */ ++ public String getHostname() { ++ return this.hostname; ++ } ++ ++ /** ++ * Get server (public facing) port. ++ * ++ * @return server port ++ */ ++ public int getPort() { ++ return this.port; ++ } ++ ++ /** ++ * Get collection of players which will be used to reply to the query. ++ * ++ * @return collection of players ++ */ ++ public Collection getPlayers() { ++ return this.players; ++ } ++ ++ /** ++ * Get server software (name and version) which will be used to reply to the query. ++ * ++ * @return server software ++ */ ++ public String getServerVersion() { ++ return this.serverVersion; ++ } ++ ++ /** ++ * Get list of plugins which will be used to reply to the query. ++ * ++ * @return collection of plugins ++ */ ++ public Collection getPlugins() { ++ return this.plugins; ++ } ++ ++ /** ++ * Creates a new {@link Builder} instance from data represented by this response. ++ * ++ * @return {@link QueryResponse} builder ++ */ ++ public Builder toBuilder() { ++ return QueryResponse.builder() ++ .motd(this.getMotd()) ++ .gameVersion(this.getGameVersion()) ++ .map(this.getMap()) ++ .currentPlayers(this.getCurrentPlayers()) ++ .maxPlayers(this.getMaxPlayers()) ++ .hostname(this.getHostname()) ++ .port(this.getPort()) ++ .players(this.getPlayers()) ++ .serverVersion(this.getServerVersion()) ++ .plugins(this.getPlugins()); ++ } ++ ++ /** ++ * Creates a new {@link Builder} instance. ++ * ++ * @return {@link QueryResponse} builder ++ */ ++ public static Builder builder() { ++ return new Builder(); ++ } ++ ++ /** ++ * A builder for {@link QueryResponse} objects. ++ */ ++ public static final class Builder { ++ ++ private @MonotonicNonNull String motd; ++ private @MonotonicNonNull String gameVersion; ++ private @MonotonicNonNull String map; ++ private @MonotonicNonNull String hostname; ++ private @MonotonicNonNull String serverVersion; ++ ++ private int currentPlayers; ++ private int maxPlayers; ++ private int port; ++ ++ private final List players = new ArrayList<>(); ++ private final List plugins = new ArrayList<>(); ++ ++ private Builder() { ++ } ++ ++ public Builder motd(final String motd) { ++ this.motd = Preconditions.checkNotNull(motd, "motd"); ++ return this; ++ } ++ ++ public Builder gameVersion(final String gameVersion) { ++ this.gameVersion = Preconditions.checkNotNull(gameVersion, "gameVersion"); ++ return this; ++ } ++ ++ public Builder map(final String map) { ++ this.map = Preconditions.checkNotNull(map, "map"); ++ return this; ++ } ++ ++ public Builder currentPlayers(final int currentPlayers) { ++ Preconditions.checkArgument(currentPlayers >= 0, "currentPlayers cannot be negative"); ++ this.currentPlayers = currentPlayers; ++ return this; ++ } ++ ++ public Builder maxPlayers(final int maxPlayers) { ++ Preconditions.checkArgument(maxPlayers >= 0, "maxPlayers cannot be negative"); ++ this.maxPlayers = maxPlayers; ++ return this; ++ } ++ ++ public Builder hostname(final String hostname) { ++ this.hostname = Preconditions.checkNotNull(hostname, "hostname"); ++ return this; ++ } ++ ++ public Builder port(final int port) { ++ Preconditions.checkArgument(port >= 1 && port <= 65535, "port must be between 1-65535"); ++ this.port = port; ++ return this; ++ } ++ ++ public Builder players(final Collection players) { ++ this.players.addAll(Preconditions.checkNotNull(players, "players")); ++ return this; ++ } ++ ++ public Builder players(final String... players) { ++ this.players.addAll(Arrays.asList(Preconditions.checkNotNull(players, "players"))); ++ return this; ++ } ++ ++ public Builder clearPlayers() { ++ this.players.clear(); ++ return this; ++ } ++ ++ public Builder serverVersion(final String serverVersion) { ++ this.serverVersion = Preconditions.checkNotNull(serverVersion, "serverVersion"); ++ return this; ++ } ++ ++ public Builder plugins(final Collection plugins) { ++ this.plugins.addAll(Preconditions.checkNotNull(plugins, "plugins")); ++ return this; ++ } ++ ++ public Builder plugins(final PluginInformation... plugins) { ++ this.plugins.addAll(Arrays.asList(Preconditions.checkNotNull(plugins, "plugins"))); ++ return this; ++ } ++ ++ public Builder clearPlugins() { ++ this.plugins.clear(); ++ return this; ++ } ++ ++ /** ++ * Builds new {@link QueryResponse} with supplied data. ++ * ++ * @return response ++ */ ++ public QueryResponse build() { ++ return new QueryResponse( ++ Preconditions.checkNotNull(this.motd, "motd"), ++ Preconditions.checkNotNull(this.gameVersion, "gameVersion"), ++ Preconditions.checkNotNull(this.map, "map"), ++ this.currentPlayers, ++ this.maxPlayers, ++ Preconditions.checkNotNull(this.hostname, "hostname"), ++ this.port, ++ ImmutableList.copyOf(this.players), ++ Preconditions.checkNotNull(this.serverVersion, "serverVersion"), ++ ImmutableList.copyOf(this.plugins) ++ ); ++ } ++ } ++ ++ /** ++ * Plugin information ++ */ ++ public static class PluginInformation { ++ ++ private String name; ++ private String version; ++ ++ public PluginInformation(final String name, final String version) { ++ this.name = Preconditions.checkNotNull(name, "name"); ++ this.version = Preconditions.checkNotNull(version, "version"); ++ } ++ ++ public String getName() { ++ return this.name; ++ } ++ ++ public void setName(final String name) { ++ this.name = name; ++ } ++ ++ public void setVersion(final String version) { ++ this.version = version; ++ } ++ ++ public String getVersion() { ++ return this.version; ++ } ++ ++ public static PluginInformation of(final String name, final String version) { ++ return new PluginInformation(name, version); ++ } ++ } ++ } ++} diff --git a/patches/api/0163-Add-more-Witch-API.patch b/patches/api/0163-Add-more-Witch-API.patch deleted file mode 100644 index 8fa1dd1e47e3..000000000000 --- a/patches/api/0163-Add-more-Witch-API.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 12 Oct 2018 03:47:26 -0500 -Subject: [PATCH] Add more Witch API - - -diff --git a/src/main/java/org/bukkit/entity/Witch.java b/src/main/java/org/bukkit/entity/Witch.java -index aa88aede6c4e66a608a63d07bc66d60357b0bee9..b7f9db08fb2e4633e1dfad5c752451f6ac23d437 100644 ---- a/src/main/java/org/bukkit/entity/Witch.java -+++ b/src/main/java/org/bukkit/entity/Witch.java -@@ -2,8 +2,53 @@ package org.bukkit.entity; - - import com.destroystokyo.paper.entity.RangedEntity; - -+// Paper start -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.Nullable; -+// Paper end -+ - /** - * Represents a Witch - */ - public interface Witch extends Raider, RangedEntity { // Paper -+ // Paper start -+ /** -+ * Check if Witch is drinking a potion -+ * -+ * @return True if drinking a potion -+ */ -+ boolean isDrinkingPotion(); -+ -+ /** -+ * Get time remaining (in ticks) the Witch is drinking a potion -+ * -+ * @return Time remaining (in ticks) -+ */ -+ int getPotionUseTimeLeft(); -+ -+ /** -+ * Set time remaining (in ticks) that the Witch is drinking a potion. -+ *

      -+ * This only has an effect while the Witch is drinking a potion. -+ * -+ * @param ticks Time in ticks remaining -+ * @see #isDrinkingPotion -+ */ -+ void setPotionUseTimeLeft(int ticks); -+ -+ /** -+ * Get the potion the Witch is drinking -+ * -+ * @return The potion the witch is drinking -+ */ -+ @Nullable -+ ItemStack getDrinkingPotion(); -+ -+ /** -+ * Set the potion the Witch should drink -+ * -+ * @param potion Potion to drink -+ */ -+ void setDrinkingPotion(@Nullable ItemStack potion); -+ // Paper end - } diff --git a/patches/api/0164-Add-PlayerPostRespawnEvent.patch b/patches/api/0164-Add-PlayerPostRespawnEvent.patch new file mode 100644 index 000000000000..1f345dab8032 --- /dev/null +++ b/patches/api/0164-Add-PlayerPostRespawnEvent.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MisterVector +Date: Fri, 26 Oct 2018 21:33:13 -0700 +Subject: [PATCH] Add PlayerPostRespawnEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e82446ec3d706c47ac9a544f70d0c19b658665d5 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java +@@ -0,0 +1,54 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.Location; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired after a player has respawned ++ */ ++@NullMarked ++public class PlayerPostRespawnEvent extends PlayerEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Location respawnedLocation; ++ private final boolean isBedSpawn; ++ ++ @ApiStatus.Internal ++ public PlayerPostRespawnEvent(final Player respawnPlayer, final Location respawnedLocation, final boolean isBedSpawn) { ++ super(respawnPlayer); ++ this.respawnedLocation = respawnedLocation; ++ this.isBedSpawn = isBedSpawn; ++ } ++ ++ /** ++ * Returns the location of the respawned player ++ * ++ * @return location of the respawned player ++ */ ++ public Location getRespawnedLocation() { ++ return this.respawnedLocation.clone(); ++ } ++ ++ /** ++ * Checks if the player respawned to their bed ++ * ++ * @return whether the player respawned to their bed ++ */ ++ public boolean isBedSpawn() { ++ return this.isBedSpawn; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java +index d6b4c81ef51662ee6bbfa0579c07d97ebd0e22ae..7e765886179b08d6b2edb5319aeacc9e7db5b8c2 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java +@@ -8,6 +8,9 @@ import org.jetbrains.annotations.NotNull; + + /** + * Called when a player respawns. ++ *

      ++ * If changing player state, see {@link com.destroystokyo.paper.event.player.PlayerPostRespawnEvent} ++ * because the player is "reset" between this event and that event and some changes won't persist. + */ + public class PlayerRespawnEvent extends PlayerEvent { + private static final HandlerList handlers = new HandlerList(); diff --git a/patches/api/0164-Make-the-default-permission-message-configurable.patch b/patches/api/0164-Make-the-default-permission-message-configurable.patch deleted file mode 100644 index f89e57963501..000000000000 --- a/patches/api/0164-Make-the-default-permission-message-configurable.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sun, 18 Nov 2018 19:44:54 +0000 -Subject: [PATCH] Make the default permission message configurable - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 1c416a48d2a069a0167bc0be6fa1d65d14f35816..62ecce029f38bd6a3e07981887916bb54e0c62f9 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2180,6 +2180,28 @@ public final class Bukkit { - return server.suggestPlayerNamesWhenNullTabCompletions(); - } - -+ /** -+ * Gets the default no permission message used on the server -+ * -+ * @return the default message -+ * @deprecated use {@link #permissionMessage()} -+ */ -+ @NotNull -+ @Deprecated -+ public static String getPermissionMessage() { -+ return server.getPermissionMessage(); -+ } -+ -+ /** -+ * Gets the default no permission message used on the server -+ * -+ * @return the default message -+ */ -+ @NotNull -+ public static net.kyori.adventure.text.Component permissionMessage() { -+ return server.permissionMessage(); -+ } -+ - /** - * Creates a PlayerProfile for the specified uuid, with name as null. - * -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 1a4559c88ece08e4a0c27e808f69693fb89fc474..85a0de6277aff8a81c8e58b3b29b98d99b6b1fb9 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1894,6 +1894,23 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - */ - boolean suggestPlayerNamesWhenNullTabCompletions(); - -+ /** -+ * Gets the default no permission message used on the server -+ * -+ * @return the default message -+ * @deprecated use {@link #permissionMessage()} -+ */ -+ @NotNull -+ @Deprecated -+ String getPermissionMessage(); -+ -+ /** -+ * Gets the default no permission message used on the server -+ * -+ * @return the default message -+ */ -+ @NotNull net.kyori.adventure.text.Component permissionMessage(); -+ - /** - * Creates a PlayerProfile for the specified uuid, with name as null. - * -diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java -index a26df5f6341d22ecd5e71da59b8f091848e627ad..608b541aef01f33891a492fff5b8400496832c3a 100644 ---- a/src/main/java/org/bukkit/command/Command.java -+++ b/src/main/java/org/bukkit/command/Command.java -@@ -184,10 +184,9 @@ public abstract class Command { - return true; - } - -- if (permissionMessage == null) { -- target.sendMessage(ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is a mistake."); - // Paper start - use components for permissionMessage -- } else if (!permissionMessage.equals(net.kyori.adventure.text.Component.empty())) { -+ net.kyori.adventure.text.Component permissionMessage = this.permissionMessage != null ? this.permissionMessage : Bukkit.permissionMessage(); -+ if (!permissionMessage.equals(net.kyori.adventure.text.Component.empty())) { - target.sendMessage(permissionMessage.replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("").replacement(permission).build())); - // Paper end - } diff --git a/patches/api/0165-Fixes-and-additions-to-the-spawn-reason-API.patch b/patches/api/0165-Fixes-and-additions-to-the-spawn-reason-API.patch new file mode 100644 index 000000000000..f1dc0f15a6b2 --- /dev/null +++ b/patches/api/0165-Fixes-and-additions-to-the-spawn-reason-API.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 24 Mar 2019 00:21:23 -0400 +Subject: [PATCH] Fixes and additions to the spawn reason API + +Expose an entities spawn reason on the entity. +Pre existing entities will return NATURAL if it was a non +persistenting Living Entity, SPAWNER for spawners, +or DEFAULT since data was not stored. + +Additionally, add missing spawn reasons. + +Co-authored-by: Aurora +Co-authored-by: Jakub Zacek + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index b808044403e6b38d1801aefde2176d630c747a64..cc1a619e54c2ce0ee49f81534c56d5b55aa5bfc2 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -857,5 +857,11 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + // TODO remove impl here + return getLocation().getChunk(); + } ++ ++ /** ++ * @return The {@link org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason} that initially spawned this entity. ++ */ ++ @NotNull ++ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason(); + // Paper end + } +diff --git a/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java b/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java +index 5d2597378d36ccace672db0768267d3499100cf1..361db256296d776c27e601c923b2cdc61967122b 100644 +--- a/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java ++++ b/src/main/java/org/bukkit/event/entity/CreatureSpawnEvent.java +@@ -206,6 +206,12 @@ public class CreatureSpawnEvent extends EntitySpawnEvent { + * When a creature is spawned by an enchantment + */ + ENCHANTMENT, ++ // Paper start - Fixes and additions to the SpawnReason API ++ /** ++ * When an entity spawns from an ominous item spawner ++ */ ++ OMINOUS_ITEM_SPAWNER, ++ // Paper end - Fixes and additions to the SpawnReason API + /** + * When a creature is spawned by a potion effect, for example: + * {@link org.bukkit.potion.PotionType#OOZING}, {@link org.bukkit.potion.PotionType#INFESTED} diff --git a/patches/api/0165-Support-cancellation-supression-of-EntityDismount-Ve.patch b/patches/api/0165-Support-cancellation-supression-of-EntityDismount-Ve.patch deleted file mode 100644 index 6eec41967270..000000000000 --- a/patches/api/0165-Support-cancellation-supression-of-EntityDismount-Ve.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sun, 18 Nov 2018 15:53:43 +0000 -Subject: [PATCH] Support cancellation supression of EntityDismount/VehicleExit - events" - -Entities must be dismounted before teleportation in order to avoid -multiple issues in the server with regards to teleportation, shamefully, -too many plugins rely on the events firing, which means that not firing -these events caues more issues than it solves; - -In order to counteract this, Entity dismount/exit vehicle events have -been modified to supress cancellation (and has a method to allow plugins -to check if this has been set), noting that cancellation will be silently -surpressed given that plugins are not expecting this event to not be cancellable. - -This is a far from ideal scenario, however: given the current state of this -event and other alternatives causing issues elsewhere, I believe that -this is going to be the best soultion all around. - -Improvements/suggestions welcome! - -diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java -index 963b9ead4ca0426b2e95c5641b0e89317c48853d..39f6afd2f9cbcff6a74a91a21dcc3e29d2497dd8 100644 ---- a/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java -+++ b/src/main/java/org/bukkit/event/vehicle/VehicleExitEvent.java -@@ -13,10 +13,18 @@ public class VehicleExitEvent extends VehicleEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); - private boolean cancelled; - private final LivingEntity exited; -+ private final boolean isCancellable; // Paper - -- public VehicleExitEvent(@NotNull final Vehicle vehicle, @NotNull final LivingEntity exited) { -+ public VehicleExitEvent(@NotNull final Vehicle vehicle, @NotNull final LivingEntity exited, boolean isCancellable) { // Paper - super(vehicle); - this.exited = exited; -+ // Paper start -+ this.isCancellable = isCancellable; -+ } -+ -+ public VehicleExitEvent(@NotNull final Vehicle vehicle, @NotNull final LivingEntity exited) { -+ this(vehicle, exited, true); -+ // Paper end - } - - /** -@@ -36,9 +44,18 @@ public class VehicleExitEvent extends VehicleEvent implements Cancellable { - - @Override - public void setCancelled(boolean cancel) { -+ // Paper start -+ if (cancel && !isCancellable) { -+ return; -+ } - this.cancelled = cancel; - } - -+ public boolean isCancellable() { -+ return isCancellable; -+ // Paper end -+ } -+ - @NotNull - @Override - public HandlerList getHandlers() { -diff --git a/src/main/java/org/spigotmc/event/entity/EntityDismountEvent.java b/src/main/java/org/spigotmc/event/entity/EntityDismountEvent.java -index 00d8ec81b4ae6ca5e438161ec9135e3c1edea6f4..a7632c8f5cb1bce4be0e456ec34f4a69c5ce80f3 100644 ---- a/src/main/java/org/spigotmc/event/entity/EntityDismountEvent.java -+++ b/src/main/java/org/spigotmc/event/entity/EntityDismountEvent.java -@@ -14,10 +14,19 @@ public class EntityDismountEvent extends EntityEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); - private boolean cancelled; - private final Entity dismounted; -+ private final boolean isCancellable; // Paper - - public EntityDismountEvent(@NotNull Entity what, @NotNull Entity dismounted) { -- super(what); -+ // Paper start -+ this(what, dismounted, true); -+ } -+ -+ -+ public EntityDismountEvent(@NotNull Entity what, @NotNull Entity dismounted, boolean isCancellable) { -+ // Paper end -+ super( what ); - this.dismounted = dismounted; -+ this.isCancellable = isCancellable; // Paper - } - - @NotNull -@@ -32,9 +41,18 @@ public class EntityDismountEvent extends EntityEvent implements Cancellable { - - @Override - public void setCancelled(boolean cancel) { -+ // Paper start -+ if (cancel && !isCancellable) { -+ return; -+ } - this.cancelled = cancel; - } - -+ public boolean isCancellable() { -+ return isCancellable; -+ // Paper end -+ } -+ - @NotNull - @Override - public HandlerList getHandlers() { diff --git a/patches/api/0166-Add-more-Zombie-API.patch b/patches/api/0166-Add-more-Zombie-API.patch deleted file mode 100644 index ec2c93dc4679..000000000000 --- a/patches/api/0166-Add-more-Zombie-API.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 7 Oct 2018 04:29:51 -0500 -Subject: [PATCH] Add more Zombie API - - -diff --git a/src/main/java/org/bukkit/entity/Zombie.java b/src/main/java/org/bukkit/entity/Zombie.java -index a5b20b0454af5ea78e2bb7f16a56c38670c84efb..1217576e6f08abf0175ab800cfca058d5deda116 100644 ---- a/src/main/java/org/bukkit/entity/Zombie.java -+++ b/src/main/java/org/bukkit/entity/Zombie.java -@@ -90,4 +90,55 @@ public interface Zombie extends Monster, Ageable { - * @param time new conversion time - */ - void setConversionTime(int time); -+ // Paper start -+ /** -+ * Check if zombie is drowning -+ * -+ * @return True if zombie conversion process has begun -+ */ -+ boolean isDrowning(); -+ -+ /** -+ * Make zombie start drowning -+ * -+ * @param drownedConversionTime Amount of time until zombie converts from drowning -+ * -+ * @deprecated See {@link #setConversionTime(int)} -+ */ -+ @Deprecated -+ void startDrowning(int drownedConversionTime); -+ -+ /** -+ * Stop a zombie from starting the drowning conversion process -+ */ -+ void stopDrowning(); -+ -+ /** -+ * Set if zombie has its arms raised -+ * -+ * @param raised True to raise arms -+ */ -+ void setArmsRaised(boolean raised); -+ -+ /** -+ * Check if zombie has arms raised -+ * -+ * @return True if arms are raised -+ */ -+ boolean isArmsRaised(); -+ -+ /** -+ * Check if this zombie will burn in the sunlight -+ * -+ * @return True if zombie will burn in sunlight -+ */ -+ boolean shouldBurnInDay(); -+ -+ /** -+ * Set if this zombie should burn in the sunlight -+ * -+ * @param shouldBurnInDay True to burn in sunlight -+ */ -+ void setShouldBurnInDay(boolean shouldBurnInDay); -+ // Paper end - } diff --git a/patches/api/0166-Fix-Spigot-annotation-mistakes.patch b/patches/api/0166-Fix-Spigot-annotation-mistakes.patch new file mode 100644 index 000000000000..57ee023c57ff --- /dev/null +++ b/patches/api/0166-Fix-Spigot-annotation-mistakes.patch @@ -0,0 +1,2862 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 24 Mar 2019 18:39:01 -0400 +Subject: [PATCH] Fix Spigot annotation mistakes + +while some of these may of been true, they are extreme cases and cause +a ton of noise to plugin developers. + +Use ApiStatus.Internal instead of Deprecated for actual internal API +that continues to have use (internally). + +These do not help plugin developers if they bring moise noise than value. + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index e0b22dd1124f02a78e5adfcf2179eadebff1dba6..0d743a27e0955af7b1baee49ce7e62e993a0a8b8 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -883,9 +883,8 @@ public final class Bukkit { + * + * @param id the id of the map to get + * @return a map view if it exists, or null otherwise +- * @deprecated Magic value + */ +- @Deprecated(since = "1.6.2") ++ // @Deprecated(since = "1.6.2") // Paper - Not a magic value + @Nullable + public static MapView getMap(int id) { + return server.getMap(id); +@@ -964,8 +963,14 @@ public final class Bukkit { + * Returns the primary logger associated with this server instance. + * + * @return Logger associated with this server ++ * @see org.bukkit.plugin.Plugin#getSLF4JLogger() ++ * @apiNote This logger is for the Minecraft server software, not for specific plugins. You should ++ * use a logger for a specific plugin, either via {@link org.bukkit.plugin.Plugin#getSLF4JLogger()} ++ * or {@link org.bukkit.plugin.Plugin#getLogger()} or create a specific logger for a class via slf4j. ++ * That way, log messages contain contextual information about the source of the message. + */ + @NotNull ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper - internalize Bukkit#getLogger + public static Logger getLogger() { + return server.getLogger(); + } +@@ -1362,10 +1367,8 @@ public final class Bukkit { + * @param name the name the player to retrieve + * @return an offline player + * @see #getOfflinePlayer(java.util.UUID) +- * @deprecated Persistent storage of users should be by UUID as names are no longer +- * unique past a single session. + */ +- @Deprecated(since = "1.7.5") ++ // @Deprecated(since = "1.7.5") // Paper + @NotNull + public static OfflinePlayer getOfflinePlayer(@NotNull String name) { + return server.getOfflinePlayer(name); +@@ -1978,7 +1981,7 @@ public final class Bukkit { + * + * @return the scoreboard manager or null if no worlds are loaded. + */ +- @Nullable ++ @NotNull // Paper + public static ScoreboardManager getScoreboardManager() { + return server.getScoreboardManager(); + } +diff --git a/src/main/java/org/bukkit/CoalType.java b/src/main/java/org/bukkit/CoalType.java +index 082632bcfa16342abf811aae30fcb280029ca1cf..ede570814963a0fb93e2e5affa54439880cd685b 100644 +--- a/src/main/java/org/bukkit/CoalType.java ++++ b/src/main/java/org/bukkit/CoalType.java +@@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents the two types of coal + */ ++@Deprecated(forRemoval = true, since = "1.13") + public enum CoalType { + COAL(0x0), + CHARCOAL(0x1); +diff --git a/src/main/java/org/bukkit/CropState.java b/src/main/java/org/bukkit/CropState.java +index c36e0ffe9b1d637d2fe3192a21f585e44437f48b..9420e919088392c6aac4114356af7a2096478195 100644 +--- a/src/main/java/org/bukkit/CropState.java ++++ b/src/main/java/org/bukkit/CropState.java +@@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents the different growth states of crops + */ ++@Deprecated(forRemoval = true, since = "1.13") + public enum CropState { + + /** +diff --git a/src/main/java/org/bukkit/Difficulty.java b/src/main/java/org/bukkit/Difficulty.java +index c1f1f29b70311ae51e4ce1be455b6557eb5fcc06..f35801783538d3377b04131b8bf6effd7eb8e1a5 100644 +--- a/src/main/java/org/bukkit/Difficulty.java ++++ b/src/main/java/org/bukkit/Difficulty.java +@@ -44,9 +44,9 @@ public enum Difficulty { + * Gets the difficulty value associated with this Difficulty. + * + * @return An integer value of this difficulty +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public int getValue() { + return value; + } +@@ -57,9 +57,9 @@ public enum Difficulty { + * @param value Value to check + * @return Associative {@link Difficulty} with the given value, or null if + * it doesn't exist +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static Difficulty getByValue(final int value) { + return BY_ID.get(value); +diff --git a/src/main/java/org/bukkit/DyeColor.java b/src/main/java/org/bukkit/DyeColor.java +index 807747db77d1e4d008c3e4086f9bf65415020cad..2f038f233afd4210687586800070d5f61e40562a 100644 +--- a/src/main/java/org/bukkit/DyeColor.java ++++ b/src/main/java/org/bukkit/DyeColor.java +@@ -96,9 +96,9 @@ public enum DyeColor { + * + * @return A byte containing the wool data value of this color + * @see #getDyeData() +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public byte getWoolData() { + return woolData; + } +@@ -142,9 +142,9 @@ public enum DyeColor { + * @return The {@link DyeColor} representing the given value, or null if + * it doesn't exist + * @see #getByDyeData(byte) +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static DyeColor getByWoolData(final byte data) { + int i = 0xff & data; +@@ -202,9 +202,9 @@ public enum DyeColor { + * + * @param name dye name + * @return dye color +- * @deprecated legacy use only ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.13") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @NotNull + public static DyeColor legacyValueOf(@Nullable String name) { + return "SILVER".equals(name) ? DyeColor.LIGHT_GRAY : DyeColor.valueOf(name); +diff --git a/src/main/java/org/bukkit/Effect.java b/src/main/java/org/bukkit/Effect.java +index c19620185026b8a6c535c9d328473699ad15a26e..d63395e588ec0d2ce7303379c9bee56cf7c33064 100644 +--- a/src/main/java/org/bukkit/Effect.java ++++ b/src/main/java/org/bukkit/Effect.java +@@ -357,9 +357,9 @@ public enum Effect { + * Gets the ID for this effect. + * + * @return ID of this effect +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public int getId() { + return this.id; + } +@@ -386,9 +386,9 @@ public enum Effect { + * + * @param id ID of the Effect to return + * @return Effect with the given ID +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static Effect getById(int id) { + return BY_ID.get(id); +diff --git a/src/main/java/org/bukkit/EntityEffect.java b/src/main/java/org/bukkit/EntityEffect.java +index 5b8dc0c5c2c062f8fe7bff9546c2cb5ed6c714c2..d7ccccdf3f5e2c572efd528a92e240ec6ea60028 100644 +--- a/src/main/java/org/bukkit/EntityEffect.java ++++ b/src/main/java/org/bukkit/EntityEffect.java +@@ -345,9 +345,9 @@ public enum EntityEffect { + * Gets the data value of this EntityEffect, may not be unique. + * + * @return The data value +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public byte getData() { + return data; + } +diff --git a/src/main/java/org/bukkit/GameMode.java b/src/main/java/org/bukkit/GameMode.java +index 3d693c42a8e277425a768ceaed9b40bc3d6cfba8..81e45984a88fc84acd0f76d825abf4ddaed0ac3b 100644 +--- a/src/main/java/org/bukkit/GameMode.java ++++ b/src/main/java/org/bukkit/GameMode.java +@@ -44,9 +44,9 @@ public enum GameMode { + * Gets the mode value associated with this GameMode + * + * @return An integer value of this gamemode +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public int getValue() { + return value; + } +@@ -57,9 +57,9 @@ public enum GameMode { + * @param value Value to check + * @return Associative {@link GameMode} with the given value, or null if + * it doesn't exist +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static GameMode getByValue(final int value) { + return BY_ID.get(value); +diff --git a/src/main/java/org/bukkit/GrassSpecies.java b/src/main/java/org/bukkit/GrassSpecies.java +index 9b6d8134f1b1b12e23dcd7e76cba1b78e20e360c..43da0eb033f7cb65e3b2cacd67946bc9dc187678 100644 +--- a/src/main/java/org/bukkit/GrassSpecies.java ++++ b/src/main/java/org/bukkit/GrassSpecies.java +@@ -6,7 +6,9 @@ import org.jetbrains.annotations.Nullable; + + /** + * Represents the different types of grass. ++ * @deprecated use {@link org.bukkit.block.data.BlockData} + */ ++@Deprecated(forRemoval = true, since = "1.13") + public enum GrassSpecies { + + /** +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index b02efba048be00e42502111fcdd2297529926666..fb4b6f0e908ffa50c3b2f8d04d9f3810898b8d5e 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -46,7 +46,7 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + * @param y The y-coordinate of this new location + * @param z The z-coordinate of this new location + */ +- public Location(@Nullable final World world, final double x, final double y, final double z) { ++ public Location(@UndefinedNullability final World world, final double x, final double y, final double z) { // Paper + this(world, x, y, z, 0, 0); + } + +@@ -60,7 +60,7 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + * @param yaw The absolute rotation on the x-plane, in degrees + * @param pitch The absolute rotation on the y-plane, in degrees + */ +- public Location(@Nullable final World world, final double x, final double y, final double z, final float yaw, final float pitch) { ++ public Location(@UndefinedNullability final World world, final double x, final double y, final double z, final float yaw, final float pitch) { // Paper + if (world != null) { + this.world = new WeakReference<>(world); + } +@@ -102,7 +102,7 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + * @throws IllegalArgumentException when world is unloaded + * @see #isWorldLoaded() + */ +- @Nullable ++ @UndefinedNullability // Paper + public World getWorld() { + if (this.world == null) { + return null; +diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java +index 9d1f82be4f23af37ccc6db65756f6dd3028c6837..fe63fef02ee208a5fc52d30a27519a0506c58f8c 100644 +--- a/src/main/java/org/bukkit/Material.java ++++ b/src/main/java/org/bukkit/Material.java +@@ -4838,20 +4838,20 @@ public enum Material implements Keyed, Translatable { + * Do not use for any reason. + * + * @return ID of this material +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @ApiStatus.Internal // Paper + public int getId() { + Preconditions.checkArgument(legacy, "Cannot get ID of Modern Material"); + return id; + } + + /** +- * Do not use for any reason. ++ * Checks if this constant is a legacy material. + * + * @return legacy status + */ +- @Deprecated(since = "1.13") ++ // @Deprecated(since = "1.13") // Paper - this is useful, don't deprecate + public boolean isLegacy() { + return legacy; + } +@@ -4927,8 +4927,10 @@ public enum Material implements Keyed, Translatable { + * Gets the MaterialData class associated with this Material + * + * @return MaterialData associated with this Material ++ * @deprecated use {@link #createBlockData()} + */ + @NotNull ++ @Deprecated // Paper + public Class getData() { + Preconditions.checkArgument(legacy, "Cannot get data class of Modern Material"); + return ctor.getDeclaringClass(); +@@ -5384,7 +5386,11 @@ public enum Material implements Keyed, Translatable { + * material. + * + * @return true if this material can be interacted with. ++ * @deprecated This method is not comprehensive and does not accurately reflect what block types are ++ * interactable. Many "interactions" are defined on the item not block, and many are conditional on some other world state ++ * checks being true. + */ ++ @Deprecated // Paper + public boolean isInteractable() { + BlockType type = asBlockType(); + return type != null && type.isInteractable(); +diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java +index 499c2293fe2eea3eaf7ede476e836704e13e5a02..ceb1009252e25e244baab9208b7494666aebc508 100644 +--- a/src/main/java/org/bukkit/NamespacedKey.java ++++ b/src/main/java/org/bukkit/NamespacedKey.java +@@ -74,12 +74,14 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key { // Pap + + /** + * Create a key in a specific namespace. ++ *

      ++ * For most plugin related code, you should prefer using the ++ * {@link NamespacedKey#NamespacedKey(Plugin, String)} constructor. + * + * @param namespace namespace + * @param key key +- * @apiNote should never be used by plugins, for internal use only!! ++ * @see #NamespacedKey(Plugin, String) + */ +- @ApiStatus.Internal + public NamespacedKey(@NotNull String namespace, @NotNull String key) { + Preconditions.checkArgument(namespace != null && isValidNamespace(namespace), "Invalid namespace. Must be [a-z0-9._-]: %s", namespace); + Preconditions.checkArgument(key != null && isValidKey(key), "Invalid key. Must be [a-z0-9/._-]: %s", key); +diff --git a/src/main/java/org/bukkit/NetherWartsState.java b/src/main/java/org/bukkit/NetherWartsState.java +index f43209cf7b752c26718c303ca8c3e1c7d9912ad3..d6c09d88189b3e9ecc629d8cf18a2b81e6801871 100644 +--- a/src/main/java/org/bukkit/NetherWartsState.java ++++ b/src/main/java/org/bukkit/NetherWartsState.java +@@ -1,5 +1,11 @@ + package org.bukkit; + ++// Paper start ++/** ++ * @deprecated use {@link org.bukkit.block.data.BlockData} and {@link org.bukkit.block.data.Ageable} ++ */ ++@Deprecated(forRemoval = true, since = "1.13") ++// Paper end + public enum NetherWartsState { + + /** +diff --git a/src/main/java/org/bukkit/Note.java b/src/main/java/org/bukkit/Note.java +index 3ecd0f34b7221bd80305f6cbf4a0e8397b7ba0a2..aff858346776386f1288b648b221404f7f412399 100644 +--- a/src/main/java/org/bukkit/Note.java ++++ b/src/main/java/org/bukkit/Note.java +@@ -39,9 +39,9 @@ public class Note { + * Returns the not sharped id of this tone. + * + * @return the not sharped id of this tone. +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public byte getId() { + return getId(false); + } +@@ -53,9 +53,9 @@ public class Note { + * + * @param sharped Set to true to return the sharped id. + * @return the id of this tone. +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public byte getId(boolean sharped) { + byte id = (byte) (sharped && sharpable ? this.id + 1 : this.id); + +@@ -78,9 +78,9 @@ public class Note { + * @return if the tone id is the sharped id of the tone. + * @throws IllegalArgumentException if neither the tone nor the + * semitone have the id. +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public boolean isSharped(byte id) { + if (id == getId(false)) { + return false; +@@ -97,9 +97,9 @@ public class Note { + * + * @param id the id of the tone. + * @return the tone to id. +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static Tone getById(byte id) { + return BY_DATA.get(id); +@@ -222,9 +222,9 @@ public class Note { + * Returns the internal id of this note. + * + * @return the internal id of this note. +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public byte getId() { + return note; + } +diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java +index f0e806865910578110f4794f7ebe93640516e7c1..b4f297f90e3c1deaa1fc3f4418418588ab19b6c5 100644 +--- a/src/main/java/org/bukkit/Registry.java ++++ b/src/main/java/org/bukkit/Registry.java +@@ -248,14 +248,12 @@ public interface Registry extends Iterable { + * + * @see TrimMaterial + */ +- @ApiStatus.Experimental + Registry TRIM_MATERIAL = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class), "No registry present for TrimMaterial. This is a bug."); + /** + * Trim patterns. + * + * @see TrimPattern + */ +- @ApiStatus.Experimental + Registry TRIM_PATTERN = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class), "No registry present for TrimPattern. This is a bug."); + /** + * Damage types. +@@ -385,8 +383,11 @@ public interface Registry extends Iterable { + * + * @param input non-null input + * @return registered object or null if does not exist ++ * @deprecated this method's behavior is broken and not useful. If you want to get an object ++ * based on its vanilla name, or a key, wrap it in a {@link NamespacedKey} object and use {@link #get(NamespacedKey)} + */ + @Nullable ++ @Deprecated(forRemoval = true) // Paper + default T match(@NotNull String input) { + Preconditions.checkArgument(input != null, "input must not be null"); + +diff --git a/src/main/java/org/bukkit/SandstoneType.java b/src/main/java/org/bukkit/SandstoneType.java +index 2306c5a6a6e3f27e580b024d5418c4944c75e881..d2ea2c81f94093414399512e289cea6c12855ec2 100644 +--- a/src/main/java/org/bukkit/SandstoneType.java ++++ b/src/main/java/org/bukkit/SandstoneType.java +@@ -6,7 +6,9 @@ import org.jetbrains.annotations.Nullable; + + /** + * Represents the three different types of Sandstone ++ * @deprecated use {@link org.bukkit.block.data.BlockData} + */ ++@Deprecated(forRemoval = true, since = "1.13") + public enum SandstoneType { + CRACKED(0x0), + GLYPHED(0x1), +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 7b5f6091c8e930526a2a5346a02b52912c38e2af..03d6e69b1771b1aabc22d680d8123239f7863e20 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -744,9 +744,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * + * @param id the id of the map to get + * @return a map view if it exists, or null otherwise +- * @deprecated Magic value + */ +- @Deprecated(since = "1.6.2") ++ // @Deprecated(since = "1.6.2") // Paper - Not a magic value + @Nullable + public MapView getMap(int id); + +@@ -813,8 +812,14 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * Returns the primary logger associated with this server instance. + * + * @return Logger associated with this server ++ * @see org.bukkit.plugin.Plugin#getSLF4JLogger() ++ * @apiNote This logger is for the Minecraft server software, not for specific plugins. You should ++ * use a logger for a specific plugin, either via {@link org.bukkit.plugin.Plugin#getSLF4JLogger()} ++ * or {@link org.bukkit.plugin.Plugin#getLogger()} or create a specific logger for a class via slf4j. ++ * That way, log messages contain contextual information about the source of the message. + */ + @NotNull ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper - internalize Bukkit#getLogger + public Logger getLogger(); + + /** +@@ -1151,10 +1156,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @param name the name the player to retrieve + * @return an offline player + * @see #getOfflinePlayer(java.util.UUID) +- * @deprecated Persistent storage of users should be by UUID as names are no longer +- * unique past a single session. + */ +- @Deprecated(since = "1.7.5") ++ // @Deprecated(since = "1.7.5") // Paper + @NotNull + public OfflinePlayer getOfflinePlayer(@NotNull String name); + +@@ -1672,7 +1675,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * + * @return the scoreboard manager or null if no worlds are loaded. + */ +- @Nullable ++ @NotNull // Paper + ScoreboardManager getScoreboardManager(); + + /** +diff --git a/src/main/java/org/bukkit/SkullType.java b/src/main/java/org/bukkit/SkullType.java +index 9b9769429470d7a3ac9c4498f896dd26d0474570..d2135724fb175674b4649b9e775d762d7fcc897e 100644 +--- a/src/main/java/org/bukkit/SkullType.java ++++ b/src/main/java/org/bukkit/SkullType.java +@@ -4,7 +4,7 @@ package org.bukkit; + * Represents the different types of skulls. + * @deprecated check {@link Material} instead + */ +-@Deprecated(since = "1.13") ++@Deprecated(since = "1.13", forRemoval = true) + public enum SkullType { + SKELETON, + WITHER, +diff --git a/src/main/java/org/bukkit/TreeSpecies.java b/src/main/java/org/bukkit/TreeSpecies.java +index 9203f396c84746c584f760987d4a47377633b0e7..abbe7c3b2984dc03098780d5678553685ea78dc4 100644 +--- a/src/main/java/org/bukkit/TreeSpecies.java ++++ b/src/main/java/org/bukkit/TreeSpecies.java +@@ -9,7 +9,7 @@ import org.jetbrains.annotations.Nullable; + * + * @deprecated Deprecated, see usage methods for replacement(s) + */ +-@Deprecated(since = "1.19") ++@Deprecated(since = "1.19", forRemoval = true) + public enum TreeSpecies { + + /** +diff --git a/src/main/java/org/bukkit/UndefinedNullability.java b/src/main/java/org/bukkit/UndefinedNullability.java +index 3f0ea49056c4bc8aeb8e59743807e72baea554cc..ce93ac1ada2c4058733c1952f6df8324fc78774b 100644 +--- a/src/main/java/org/bukkit/UndefinedNullability.java ++++ b/src/main/java/org/bukkit/UndefinedNullability.java +@@ -14,6 +14,7 @@ import org.jetbrains.annotations.ApiStatus; + * suggests a bad API design. + */ + @Retention(RetentionPolicy.CLASS) ++@java.lang.annotation.Documented // Paper + @ApiStatus.Internal + @Deprecated(since = "1.13.2") + public @interface UndefinedNullability { +diff --git a/src/main/java/org/bukkit/Vibration.java b/src/main/java/org/bukkit/Vibration.java +index e455eb21abf121dc6ff10ff8a13dd06f67096a8f..bbc01e7c192ae6689c301670047ff114306c57cb 100644 +--- a/src/main/java/org/bukkit/Vibration.java ++++ b/src/main/java/org/bukkit/Vibration.java +@@ -13,6 +13,14 @@ public class Vibration { + private final Destination destination; + private final int arrivalTime; + ++ // Paper start ++ public Vibration(@NotNull Destination destination, @NotNull int arrivalTime) { ++ this.destination = destination; ++ this.arrivalTime = arrivalTime; ++ this.origin = new Location(null, 0, 0, 0); // Dummy origin because getter expects null ++ } ++ ++ @Deprecated(forRemoval = true) // Paper end + public Vibration(@NotNull Location origin, @NotNull Destination destination, int arrivalTime) { + this.origin = origin; + this.destination = destination; +@@ -22,9 +30,11 @@ public class Vibration { + /** + * Get the origin of the vibration. + * ++ * @deprecated unused as of 1.19 + * @return origin + */ + @NotNull ++ @Deprecated(forRemoval = true) // Paper + public Location getOrigin() { + return origin; + } +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 10e9981c9068c39dfdda5c9f82558d481288a8c6..85900b9f41379d9c8366ae9f2f9e94f54f504ffb 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -418,9 +418,8 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + * @param z Z-coordinate of the chunk + * @return Whether the chunk was actually refreshed + * +- * @deprecated This method is not guaranteed to work suitably across all client implementations. + */ +- @Deprecated(since = "1.8") ++ // @Deprecated(since = "1.8") // Paper + public boolean refreshChunk(int x, int z); + + /** +@@ -3850,6 +3849,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + StructureSearchResult locateNearestStructure(@NotNull Location origin, @NotNull Structure structure, int radius, boolean findUnexplored); + + // Spigot start ++ @Deprecated(forRemoval = true) // Paper + public class Spigot { + + /** +@@ -3883,7 +3883,11 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + } + } + ++ /** ++ * @deprecated Unsupported api ++ */ + @NotNull ++ @Deprecated // Paper + Spigot spigot(); + // Spigot end + +@@ -4101,9 +4105,9 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + * Gets the dimension ID of this environment + * + * @return dimension ID +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public int getId() { + return id; + } +@@ -4113,9 +4117,9 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + * + * @param id The ID of the environment + * @return The environment +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static Environment getEnvironment(int id) { + return lookup.get(id); +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index a5b03162e5c0484db57d0ce0e57e945840fe1357..2566c7bb9e770483abdd3398af13179dc747b682 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -526,7 +526,7 @@ public interface Block extends Metadatable, Translatable { + * @return a list of dropped items for this type of block + */ + @NotNull +- Collection getDrops(@NotNull ItemStack tool, @Nullable Entity entity); ++ Collection getDrops(@Nullable ItemStack tool, @Nullable Entity entity); // Paper + + /** + * Returns if the given item is a preferred choice to break this Block. +diff --git a/src/main/java/org/bukkit/block/BlockState.java b/src/main/java/org/bukkit/block/BlockState.java +index dd1e7b71d7d332b3e22189c7e0eda6d47ec49e55..555d0492c2fcf85c1e2f95f145b974cb75bc5ecc 100644 +--- a/src/main/java/org/bukkit/block/BlockState.java ++++ b/src/main/java/org/bukkit/block/BlockState.java +@@ -36,8 +36,10 @@ public interface BlockState extends Metadatable { + * Gets the metadata for this block state. + * + * @return block specific metadata ++ * @deprecated use {@link #getBlockData()} + */ + @NotNull ++ @Deprecated(forRemoval = true, since = "1.13") + MaterialData getData(); + + /** +@@ -151,7 +153,9 @@ public interface BlockState extends Metadatable { + * Sets the metadata for this block state. + * + * @param data New block specific metadata ++ * @deprecated use {@link #setBlockData(BlockData)} + */ ++ @Deprecated(forRemoval = true, since = "1.13") + void setData(@NotNull MaterialData data); + + /** +diff --git a/src/main/java/org/bukkit/block/BlockType.java b/src/main/java/org/bukkit/block/BlockType.java +index 04bbbaba10cdd7ce3c394692579605d66953ac01..95eb7d7718a74382289ac3a7b2d5fac4c9ec19a2 100644 +--- a/src/main/java/org/bukkit/block/BlockType.java ++++ b/src/main/java/org/bukkit/block/BlockType.java +@@ -3551,9 +3551,14 @@ public interface BlockType extends Keyed, Translatable { + * state as well. This method will return true if there is at least one + * state in which additional interact handling is performed for the + * block type. ++ * ++ * @deprecated This method is not comprehensive and does not accurately reflect what block types are ++ * interactable. Many "interactions" are defined on the item not block, and many are conditional on some other world state ++ * checks being true. + * + * @return true if this block type can be interacted with. + */ ++ @Deprecated // Paper + boolean isInteractable(); + + /** +diff --git a/src/main/java/org/bukkit/block/BrushableBlock.java b/src/main/java/org/bukkit/block/BrushableBlock.java +index 4bd127b3646307398e0c937c3e36ab671235b72b..f2557a87f468ee20c2d276dbfc0e9a976656c75c 100644 +--- a/src/main/java/org/bukkit/block/BrushableBlock.java ++++ b/src/main/java/org/bukkit/block/BrushableBlock.java +@@ -15,7 +15,7 @@ public interface BrushableBlock extends Lootable, TileState { + * + * @return the item + */ +- @Nullable ++ @org.jetbrains.annotations.NotNull // Paper + public ItemStack getItem(); + + /** +diff --git a/src/main/java/org/bukkit/block/PistonMoveReaction.java b/src/main/java/org/bukkit/block/PistonMoveReaction.java +index c171f89ea418a3c4eb64436d08486df56d7cf74f..a7b915ded9154d53ac8ca599119c1699cfca2265 100644 +--- a/src/main/java/org/bukkit/block/PistonMoveReaction.java ++++ b/src/main/java/org/bukkit/block/PistonMoveReaction.java +@@ -48,9 +48,9 @@ public enum PistonMoveReaction { + + /** + * @return The ID of the move reaction +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public int getId() { + return this.id; + } +@@ -58,9 +58,9 @@ public enum PistonMoveReaction { + /** + * @param id An ID + * @return The move reaction with that ID +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static PistonMoveReaction getById(int id) { + return byId.get(id); +diff --git a/src/main/java/org/bukkit/block/SuspiciousSand.java b/src/main/java/org/bukkit/block/SuspiciousSand.java +index 3b5f6341c8ffdd356084462c86f26b1d2ddc512f..b223318c48812ca5ee82b8970c59fa19af9c7044 100644 +--- a/src/main/java/org/bukkit/block/SuspiciousSand.java ++++ b/src/main/java/org/bukkit/block/SuspiciousSand.java +@@ -5,6 +5,6 @@ package org.bukkit.block; + * + * @see BrushableBlock + */ +-@Deprecated(since = "1.20") ++@Deprecated(since = "1.20", forRemoval = true) + public interface SuspiciousSand extends BrushableBlock { + } +diff --git a/src/main/java/org/bukkit/enchantments/Enchantment.java b/src/main/java/org/bukkit/enchantments/Enchantment.java +index 4d8defb32544c4cb972d257f58e4eabbc14a2176..3ba81dc0e6bb907ca0ff2215ec1ac68ef0726352 100644 +--- a/src/main/java/org/bukkit/enchantments/Enchantment.java ++++ b/src/main/java/org/bukkit/enchantments/Enchantment.java +@@ -263,7 +263,7 @@ public abstract class Enchantment implements Keyed, Translatable { + * @deprecated enchantment groupings are now managed by tags, not categories + */ + @NotNull +- @Deprecated(since = "1.20.5") ++ @Deprecated(since = "1.20.5", forRemoval = true) @org.jetbrains.annotations.Contract("-> fail") // Paper + public abstract EnchantmentTarget getItemTarget(); + + /** +diff --git a/src/main/java/org/bukkit/entity/AbstractArrow.java b/src/main/java/org/bukkit/entity/AbstractArrow.java +index c901990454ec930169b0dc561987bea101f9b6ae..ebb6976aba314f592459cdfa49f6c15079207fd2 100644 +--- a/src/main/java/org/bukkit/entity/AbstractArrow.java ++++ b/src/main/java/org/bukkit/entity/AbstractArrow.java +@@ -157,7 +157,7 @@ public interface AbstractArrow extends Projectile { + * + * @return The firing ItemStack + */ +- @NotNull ++ @Nullable // Paper + @ApiStatus.Experimental + public ItemStack getWeapon(); + +diff --git a/src/main/java/org/bukkit/entity/Enderman.java b/src/main/java/org/bukkit/entity/Enderman.java +index 3afe2787de576f7190d87c796bea0ab34dc30248..875817b807c9f515eb07b03cc85d368955388dc3 100644 +--- a/src/main/java/org/bukkit/entity/Enderman.java ++++ b/src/main/java/org/bukkit/entity/Enderman.java +@@ -25,15 +25,19 @@ public interface Enderman extends Monster { + * Gets the id and data of the block that the Enderman is carrying. + * + * @return MaterialData containing the id and data of the block ++ * @deprecated use {@link #getCarriedBlock()} + */ + @NotNull ++ @Deprecated(forRemoval = true, since = "1.13") + public MaterialData getCarriedMaterial(); + + /** + * Sets the id and data of the block that the Enderman is carrying. + * + * @param material data to set the carried block to ++ * @deprecated use {@link #setCarriedBlock(BlockData)} + */ ++ @Deprecated(forRemoval = true, since = "1.13") + public void setCarriedMaterial(@NotNull MaterialData material); + + /** +diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java +index 896b87bfc39b82849e32398161269bffb0577efe..dc944ad75f04f5d2f72639615f64b5bb2d1b4117 100644 +--- a/src/main/java/org/bukkit/entity/EntityType.java ++++ b/src/main/java/org/bukkit/entity/EntityType.java +@@ -417,9 +417,9 @@ public enum EntityType implements Keyed, Translatable { + * + * @param name the entity type's name + * @return the matching entity type or null +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Contract("null -> null") + @Nullable + public static EntityType fromName(@Nullable String name) { +diff --git a/src/main/java/org/bukkit/entity/ItemDisplay.java b/src/main/java/org/bukkit/entity/ItemDisplay.java +index bd718c1cf6f20cd716d2fac11556437b4a5aab2e..586ac8abbd1a0f2724fdfadc01370cb6f1c1067a 100644 +--- a/src/main/java/org/bukkit/entity/ItemDisplay.java ++++ b/src/main/java/org/bukkit/entity/ItemDisplay.java +@@ -14,7 +14,7 @@ public interface ItemDisplay extends Display { + * + * @return the displayed item stack + */ +- @Nullable ++ @NotNull // Paper + ItemStack getItemStack(); + + /** +diff --git a/src/main/java/org/bukkit/entity/LightningStrike.java b/src/main/java/org/bukkit/entity/LightningStrike.java +index 186d0bbfca0320c1b3b18733254ddda6b7e6940c..608628b6328e4235fe2be0e4189babb5188361aa 100644 +--- a/src/main/java/org/bukkit/entity/LightningStrike.java ++++ b/src/main/java/org/bukkit/entity/LightningStrike.java +@@ -84,6 +84,10 @@ public interface LightningStrike extends Entity { + public void setCausingPlayer(@Nullable Player player); + + // Spigot start ++ /** ++ * @deprecated Unsupported api ++ */ ++ @Deprecated // Paper + public class Spigot extends Entity.Spigot { + + /** +@@ -98,8 +102,12 @@ public interface LightningStrike extends Entity { + } + } + ++ /** ++ * @deprecated Unsupported api ++ */ + @NotNull + @Override ++ @Deprecated // Paper + Spigot spigot(); + // Spigot end + } +diff --git a/src/main/java/org/bukkit/entity/LingeringPotion.java b/src/main/java/org/bukkit/entity/LingeringPotion.java +index 949ba8410cf89f0d31fc72ac05b5aa929919d9e2..ad8519ab9b4198b09a8c4d6e08deae7c066b0ee0 100644 +--- a/src/main/java/org/bukkit/entity/LingeringPotion.java ++++ b/src/main/java/org/bukkit/entity/LingeringPotion.java +@@ -3,7 +3,8 @@ package org.bukkit.entity; + /** + * Represents a thrown lingering potion bottle + * +- * @deprecated lingering status depends on only on the potion item. ++ * @deprecated should not be used for anything, use {@link ThrownPotion} and ++ * set the potion via the methods there. + */ +-@Deprecated(since = "1.20.5") ++@Deprecated(since = "1.20.5", forRemoval = true) // Paper + public interface LingeringPotion extends ThrownPotion { } +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 775f18abe007edc73ed60eb45f84bd79912f9331..72b83dedf025ef971b89e2c6a19fd411488948b7 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -716,7 +716,9 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + * This may have unexpected results if the entity is not in water. + * + * @param swimming True if the entity is swimming. ++ * @deprecated This does nothing and is immediately reverted by the server, in the next tick + */ ++ @Deprecated // Paper + public void setSwimming(boolean swimming); + + /** +@@ -981,7 +983,7 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + * @deprecated entity groupings are now managed by tags, not categories + */ + @NotNull +- @Deprecated(since = "1.20.5") ++ @Deprecated(since = "1.20.5", forRemoval = true) @org.jetbrains.annotations.Contract("-> fail") // Paper + public EntityCategory getCategory(); + + /** +diff --git a/src/main/java/org/bukkit/entity/Minecart.java b/src/main/java/org/bukkit/entity/Minecart.java +index e5c43a80375624b11653b0693a7883a490d73c6d..d9ad5fd48eec569eb4aef2aaf527ba24d2db3254 100644 +--- a/src/main/java/org/bukkit/entity/Minecart.java ++++ b/src/main/java/org/bukkit/entity/Minecart.java +@@ -102,7 +102,9 @@ public interface Minecart extends Vehicle { + * Passing a null value will set the minecart to have no display block. + * + * @param material the material to set as display block. ++ * @deprecated use {@link #setDisplayBlockData(BlockData)} + */ ++ @Deprecated(forRemoval = true, since = "1.13") + public void setDisplayBlock(@Nullable MaterialData material); + + /** +@@ -110,8 +112,10 @@ public interface Minecart extends Vehicle { + * This function will return the type AIR if none is set. + * + * @return the block displayed by this minecart. ++ * @deprecated use {@link #getDisplayBlockData()} + */ + @NotNull ++ @Deprecated(forRemoval = true, since = "1.13") + public MaterialData getDisplayBlock(); + + /** +diff --git a/src/main/java/org/bukkit/entity/OminousItemSpawner.java b/src/main/java/org/bukkit/entity/OminousItemSpawner.java +index 60522888bc320ba0a55655532e19185fac816bd1..4aa07d4edb2c81d0ae7999b30ad53ff8bb884ec7 100644 +--- a/src/main/java/org/bukkit/entity/OminousItemSpawner.java ++++ b/src/main/java/org/bukkit/entity/OminousItemSpawner.java +@@ -15,7 +15,7 @@ public interface OminousItemSpawner extends Entity { + * + * @return the item + */ +- @Nullable ++ @org.jetbrains.annotations.NotNull // Paper + ItemStack getItem(); + + /** +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index f84c55b9a93aae762ed28cc536eccbd7a503177a..70fef7c72b4ea24b8fd3bd99cb8f6f37b3b9832b 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -1680,11 +1680,8 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + + /** + * Forces an update of the player's entire inventory. +- * +- * @apiNote It should not be necessary for plugins to use this method. If it +- * is required for some reason, it is probably a bug. + */ +- @ApiStatus.Internal ++ // @ApiStatus.Internal // Paper - is valid API + public void updateInventory(); + + /** +diff --git a/src/main/java/org/bukkit/entity/Projectile.java b/src/main/java/org/bukkit/entity/Projectile.java +index 22d6dfdd8a271d067ab3493f35289a34b16ac310..fe64f4e87a0f600b5f1522f788f78ccfc5d7c7ea 100644 +--- a/src/main/java/org/bukkit/entity/Projectile.java ++++ b/src/main/java/org/bukkit/entity/Projectile.java +@@ -29,7 +29,7 @@ public interface Projectile extends Entity { + * @return true if it should bounce. + * @deprecated does not do anything + */ +- @Deprecated(since = "1.20.2") ++ @Deprecated(since = "1.20.2", forRemoval = true) + public boolean doesBounce(); + + /** +@@ -39,6 +39,6 @@ public interface Projectile extends Entity { + * @param doesBounce whether or not it should bounce. + * @deprecated does not do anything + */ +- @Deprecated(since = "1.20.2") ++ @Deprecated(since = "1.20.2", forRemoval = true) + public void setBounce(boolean doesBounce); + } +diff --git a/src/main/java/org/bukkit/entity/SplashPotion.java b/src/main/java/org/bukkit/entity/SplashPotion.java +index e706a78e3a74a564bfc3f0c4777aa6add5a91be9..c4702ce06d73118f03a1827cbc652cbff6e59d9b 100644 +--- a/src/main/java/org/bukkit/entity/SplashPotion.java ++++ b/src/main/java/org/bukkit/entity/SplashPotion.java +@@ -3,7 +3,8 @@ package org.bukkit.entity; + /** + * Represents a thrown splash potion bottle + * +- * @deprecated splash status depends on only on the potion item. ++ * @deprecated should not be used for anything, use {@link ThrownPotion} and ++ * set the potion via the methods there. + */ +-@Deprecated(since = "1.14") ++@Deprecated(since = "1.14", forRemoval = true) // Paper + public interface SplashPotion extends ThrownPotion { } +diff --git a/src/main/java/org/bukkit/entity/ZombieVillager.java b/src/main/java/org/bukkit/entity/ZombieVillager.java +index 7cc1d9a966454af70b7c25735fe474fe3eb97eb4..e38f38ebfc6e85f29b09c4bb3e2ea79639078ad0 100644 +--- a/src/main/java/org/bukkit/entity/ZombieVillager.java ++++ b/src/main/java/org/bukkit/entity/ZombieVillager.java +@@ -13,15 +13,15 @@ public interface ZombieVillager extends Zombie { + * Sets the villager profession of this zombie. + */ + @Override +- void setVillagerProfession(@Nullable Villager.Profession profession); ++ void setVillagerProfession(@NotNull Villager.Profession profession); // Paper + + /** + * Returns the villager profession of this zombie. + * +- * @return the profession or null ++ * @return the profession + */ + @Override +- @Nullable ++ @NotNull // Paper + Villager.Profession getVillagerProfession(); + + /** +diff --git a/src/main/java/org/bukkit/entity/memory/MemoryKey.java b/src/main/java/org/bukkit/entity/memory/MemoryKey.java +index 8f601e85df580ef8106eaff8b9eafb5691a4874b..d615c006c9153fb65024241604b744fbfc383efc 100644 +--- a/src/main/java/org/bukkit/entity/memory/MemoryKey.java ++++ b/src/main/java/org/bukkit/entity/memory/MemoryKey.java +@@ -69,6 +69,12 @@ public final class MemoryKey implements Keyed { + public static final MemoryKey LIKED_NOTEBLOCK_POSITION = new MemoryKey<>(NamespacedKey.minecraft("liked_noteblock"), Location.class); + public static final MemoryKey LIKED_NOTEBLOCK_COOLDOWN_TICKS = new MemoryKey<>(NamespacedKey.minecraft("liked_noteblock_cooldown_ticks"), Integer.class); + public static final MemoryKey ITEM_PICKUP_COOLDOWN_TICKS = new MemoryKey<>(NamespacedKey.minecraft("item_pickup_cooldown_ticks"), Integer.class); ++ /** ++ * @deprecated this constant uses the wrong generic type, the sniffer now stores different positions ++ * from possibly different worlds. Use the relevant methods in {@link org.bukkit.entity.Sniffer} directly ++ * for now. ++ */ ++ @Deprecated // Paper + public static final MemoryKey SNIFFER_EXPLORED_POSITIONS = new MemoryKey<>(NamespacedKey.minecraft("sniffer_explored_positions"), Location.class); + + /** +diff --git a/src/main/java/org/bukkit/event/block/BrewingStartEvent.java b/src/main/java/org/bukkit/event/block/BrewingStartEvent.java +index 9e54ef5b60bf5583c12e1edfa76f19013a5b2a65..37be83184cae203d5e99518b0ff5c708fafb0331 100644 +--- a/src/main/java/org/bukkit/event/block/BrewingStartEvent.java ++++ b/src/main/java/org/bukkit/event/block/BrewingStartEvent.java +@@ -8,6 +8,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Called when a brewing stand starts to brew. + */ ++@org.jetbrains.annotations.ApiStatus.Experimental // Paper + public class BrewingStartEvent extends InventoryBlockStartEvent { + + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/block/CampfireStartEvent.java b/src/main/java/org/bukkit/event/block/CampfireStartEvent.java +index 53119742beda00a38111063243665bb995ae2188..2d084214e991fecc51f8e18e3d733e43b1dca248 100644 +--- a/src/main/java/org/bukkit/event/block/CampfireStartEvent.java ++++ b/src/main/java/org/bukkit/event/block/CampfireStartEvent.java +@@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Called when a Campfire starts to cook. + */ ++@org.jetbrains.annotations.ApiStatus.Experimental // Paper + public class CampfireStartEvent extends InventoryBlockStartEvent { + + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/block/CrafterCraftEvent.java b/src/main/java/org/bukkit/event/block/CrafterCraftEvent.java +index f4efb2190ae4b1fa1823d5c97ad518c6d34f0a1a..3d6c0ecc70a748b8508b55513f9d5fa6b4bd6353 100644 +--- a/src/main/java/org/bukkit/event/block/CrafterCraftEvent.java ++++ b/src/main/java/org/bukkit/event/block/CrafterCraftEvent.java +@@ -17,6 +17,7 @@ public class CrafterCraftEvent extends BlockEvent implements Cancellable { + private ItemStack result; + private boolean cancelled; + ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper - fix upstream annotation mistakes + public CrafterCraftEvent(@NotNull Block theBlock, @NotNull CraftingRecipe recipe, @NotNull ItemStack result) { + super(theBlock); + this.result = result; +diff --git a/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java b/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java +index 4c8f388897ff9ddd077695172622c5550651858b..5a56eeb4bdb340920306d03014e536cceb568147 100644 +--- a/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java ++++ b/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java +@@ -23,7 +23,7 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab + private boolean cancelled; + private final Player enchanter; + +- public PrepareItemEnchantEvent(@NotNull final Player enchanter, @NotNull EnchantmentView view, @NotNull final Block table, @NotNull final ItemStack item, @NotNull final EnchantmentOffer[] offers, final int bonus) { ++ public PrepareItemEnchantEvent(@NotNull final Player enchanter, @NotNull EnchantmentView view, @NotNull final Block table, @NotNull final ItemStack item, @org.jetbrains.annotations.Nullable final EnchantmentOffer @NotNull [] offers, final int bonus) { // Paper - offers can contain null values + super(view); + this.enchanter = enchanter; + this.table = table; +@@ -86,8 +86,7 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab + * + * @return list of available enchantment offers + */ +- @NotNull +- public EnchantmentOffer[] getOffers() { ++ public @org.jetbrains.annotations.Nullable EnchantmentOffer @NotNull [] getOffers() { // Paper offers can contain null values + return offers; + } + +diff --git a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java +index d743cc5ee34fd7bc5db92f4b17fed9f3aa5ffbcc..8fdfcbc7d20fe0af6b220ab94516247093637621 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java +@@ -218,7 +218,10 @@ public class EntityPotionEffectEvent extends EntityEvent implements Cancellable + MILK, + /** + * When a player gets bad omen after killing a patrol captain. ++ * ++ * @deprecated no longer used, player now gets an ominous bottle instead + */ ++ @Deprecated(since = "1.21") // Paper + PATROL_CAPTAIN, + /** + * When a potion effect is modified through the plugin methods. +diff --git a/src/main/java/org/bukkit/event/entity/EntityTargetLivingEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityTargetLivingEntityEvent.java +index 090ec6f96ca9b7f760389994da988c44c32b9976..e6b4d4c1722bf4a11744a421d09646b22745b138 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityTargetLivingEntityEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityTargetLivingEntityEvent.java +@@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable; + * LivingEntity's. + */ + public class EntityTargetLivingEntityEvent extends EntityTargetEvent { +- public EntityTargetLivingEntityEvent(@NotNull final Entity entity, @Nullable final LivingEntity target, @Nullable final TargetReason reason) { ++ public EntityTargetLivingEntityEvent(@NotNull final Entity entity, @Nullable final LivingEntity target, @NotNull final TargetReason reason) { // Paper + super(entity, target, reason); + } + +diff --git a/src/main/java/org/bukkit/event/entity/EntityToggleSwimEvent.java b/src/main/java/org/bukkit/event/entity/EntityToggleSwimEvent.java +index e1123295b9511a2c610a1baf7195638f7f3e64c4..273ae8e5da0a858d3b82d1b0f5992318ff49f145 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityToggleSwimEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityToggleSwimEvent.java +@@ -24,6 +24,14 @@ public class EntityToggleSwimEvent extends EntityEvent implements Cancellable { + return cancel; + } + ++ /** ++ * @deprecated This does nothing, the server and the client doesn't work ++ * correctly when the server try to bypass this. A current workaround ++ * exists. If you want to cancel the switch from the ground state to the ++ * swimming state you need to disable the sprinting flag for the player after ++ * the cancel action. ++ */ ++ @Deprecated // Paper + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; +diff --git a/src/main/java/org/bukkit/event/entity/ProjectileHitEvent.java b/src/main/java/org/bukkit/event/entity/ProjectileHitEvent.java +index 56e6024f1fa64569481543dc076e575bb512eef0..7fccda2a48f7bac7da54862c5cb8f1b484cc9da9 100644 +--- a/src/main/java/org/bukkit/event/entity/ProjectileHitEvent.java ++++ b/src/main/java/org/bukkit/event/entity/ProjectileHitEvent.java +@@ -19,22 +19,27 @@ public class ProjectileHitEvent extends EntityEvent implements Cancellable { + private final BlockFace hitFace; + private boolean cancel = false; + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper + public ProjectileHitEvent(@NotNull final Projectile projectile) { +- this(projectile, null, null); ++ this(projectile, null, null, null); // Paper + } + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper + public ProjectileHitEvent(@NotNull final Projectile projectile, @Nullable Entity hitEntity) { +- this(projectile, hitEntity, null); ++ this(projectile, hitEntity, null, null); // Paper + } + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper + public ProjectileHitEvent(@NotNull final Projectile projectile, @Nullable Block hitBlock) { +- this(projectile, null, hitBlock); ++ this(projectile, null, hitBlock, null); // Paper + } + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper + public ProjectileHitEvent(@NotNull final Projectile projectile, @Nullable Entity hitEntity, @Nullable Block hitBlock) { + this(projectile, hitEntity, hitBlock, null); + } + ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public ProjectileHitEvent(@NotNull final Projectile projectile, @Nullable Entity hitEntity, @Nullable Block hitBlock, @Nullable BlockFace hitFace) { + super(projectile); + this.hitEntity = hitEntity; +diff --git a/src/main/java/org/bukkit/event/entity/SpawnerSpawnEvent.java b/src/main/java/org/bukkit/event/entity/SpawnerSpawnEvent.java +index 9353f0d09272404f42167ab8b7ad83a03620c436..f3ec8f67328b266defb31a44a36d31401d5e9371 100644 +--- a/src/main/java/org/bukkit/event/entity/SpawnerSpawnEvent.java ++++ b/src/main/java/org/bukkit/event/entity/SpawnerSpawnEvent.java +@@ -12,12 +12,19 @@ import org.jetbrains.annotations.NotNull; + public class SpawnerSpawnEvent extends EntitySpawnEvent { + private final CreatureSpawner spawner; + +- public SpawnerSpawnEvent(@NotNull final Entity spawnee, @NotNull final CreatureSpawner spawner) { ++ public SpawnerSpawnEvent(@NotNull final Entity spawnee, @org.jetbrains.annotations.Nullable final CreatureSpawner spawner) { // Paper + super(spawnee); + this.spawner = spawner; + } + +- @NotNull ++ /** ++ * Gets the spawner tile state, or null ++ * when the entity is spawned from a minecart ++ * spawner. ++ * ++ * @return the spawner tile state ++ */ ++ @org.jetbrains.annotations.Nullable // Paper + public CreatureSpawner getSpawner() { + return spawner; + } +diff --git a/src/main/java/org/bukkit/event/hanging/HangingBreakByEntityEvent.java b/src/main/java/org/bukkit/event/hanging/HangingBreakByEntityEvent.java +index 68517811f63838bdad41073ee26be82f95042a8e..454885e47611edd707358ddfe0a01b7acf9ad5c8 100644 +--- a/src/main/java/org/bukkit/event/hanging/HangingBreakByEntityEvent.java ++++ b/src/main/java/org/bukkit/event/hanging/HangingBreakByEntityEvent.java +@@ -11,22 +11,21 @@ import org.jetbrains.annotations.Nullable; + public class HangingBreakByEntityEvent extends HangingBreakEvent { + private final Entity remover; + +- public HangingBreakByEntityEvent(@NotNull final Hanging hanging, @Nullable final Entity remover) { ++ public HangingBreakByEntityEvent(@NotNull final Hanging hanging, @NotNull final Entity remover) { // Paper + this(hanging, remover, HangingBreakEvent.RemoveCause.ENTITY); + } + +- public HangingBreakByEntityEvent(@NotNull final Hanging hanging, @Nullable final Entity remover, @NotNull final HangingBreakEvent.RemoveCause cause) { ++ public HangingBreakByEntityEvent(@NotNull final Hanging hanging, @NotNull final Entity remover, @NotNull final HangingBreakEvent.RemoveCause cause) { // Paper + super(hanging, cause); + this.remover = remover; + } + + /** + * Gets the entity that removed the hanging entity. +- * May be null, for example when broken by an explosion. + * + * @return the entity that removed the hanging entity + */ +- @Nullable ++ @NotNull // Paper + public Entity getRemover() { + return remover; + } +diff --git a/src/main/java/org/bukkit/event/inventory/HopperInventorySearchEvent.java b/src/main/java/org/bukkit/event/inventory/HopperInventorySearchEvent.java +index 80a0a4ad813d6453b30273d25942e6612bb05c1b..18bb808e73c7a78f367ccdb44d5fe12bc54672cb 100644 +--- a/src/main/java/org/bukkit/event/inventory/HopperInventorySearchEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/HopperInventorySearchEvent.java +@@ -34,7 +34,7 @@ public class HopperInventorySearchEvent extends BlockEvent { + DESTINATION; + } + +- public HopperInventorySearchEvent(@NotNull Inventory inventory, @NotNull ContainerType containerType, @NotNull Block hopper, @NotNull Block searchBlock) { ++ public HopperInventorySearchEvent(@Nullable Inventory inventory, @NotNull ContainerType containerType, @NotNull Block hopper, @NotNull Block searchBlock) { // Paper + super(hopper); + this.inventory = inventory; + this.containerType = containerType; +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java +index 5832c610e4fad1372e70dc01bd04ba684a89b492..ff2d64550d8d834fb8e0e859bee5a8ff3329701e 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java +@@ -88,7 +88,7 @@ public class InventoryClickEvent extends InventoryInteractEvent { + * + * @return the cursor ItemStack + */ +- @Nullable ++ @NotNull // Paper - fix nullability + public ItemStack getCursor() { + return getView().getCursor(); + } +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java +index f80d5bc893efd8846365b4677ef1407158b1abc8..06e037ce94b368b3685ab04ba46c1ab5e5479dbb 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java +@@ -155,7 +155,7 @@ public enum InventoryType { + * + * @deprecated use {@link #SMITHING} + */ +- @Deprecated(since = "1.20.1") ++ @Deprecated(since = "1.20.1", forRemoval = true) // Paper + SMITHING_NEW(4, "Upgrade Gear", MenuType.SMITHING), + ; + +diff --git a/src/main/java/org/bukkit/event/player/PlayerBedLeaveEvent.java b/src/main/java/org/bukkit/event/player/PlayerBedLeaveEvent.java +index 1cb70b5c8776863f44f1c4cdde152c35cb51edb5..f09b378508fcc6299e7cb40f174028f6f88ba067 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerBedLeaveEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerBedLeaveEvent.java +@@ -43,7 +43,10 @@ public class PlayerBedLeaveEvent extends PlayerEvent implements Cancellable { + * {@link Player#setBedSpawnLocation(Location)}. + * + * @return true if the spawn location will be changed ++ * @deprecated the respawn point is now set when the player enter the bed and ++ * this option doesn't work since MC 1.15. + */ ++ @Deprecated(forRemoval = true) // Paper - Unused + public boolean shouldSetSpawnLocation() { + return setBedSpawn; + } +@@ -59,7 +62,10 @@ public class PlayerBedLeaveEvent extends PlayerEvent implements Cancellable { + * {@link Player#setBedSpawnLocation(Location)}. + * + * @param setBedSpawn true to change the new spawn location ++ * @deprecated the respawn point is now set when the player enter the bed and ++ * this option doesn't work since MC 1.15. + */ ++ @Deprecated(forRemoval = true) // Paper - Unused + public void setSpawnLocation(boolean setBedSpawn) { + this.setBedSpawn = setBedSpawn; + } +diff --git a/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java b/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java +index 1b2267f4e8ebded198773ec80e2bff2c861c7084..1a58734d919fae247eeb85dd785fd59990856505 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java +@@ -78,7 +78,7 @@ public class PlayerMoveEvent extends PlayerEvent implements Cancellable { + * + * @return Location the player moved to + */ +- @Nullable ++ @NotNull // Paper + public Location getTo() { + return to; + } +diff --git a/src/main/java/org/bukkit/event/raid/RaidSpawnWaveEvent.java b/src/main/java/org/bukkit/event/raid/RaidSpawnWaveEvent.java +index cd58dd7de781823804701fc023706e805c0142a8..1b8bb5241efcf4a90fd098f2000f8394072dca4a 100644 +--- a/src/main/java/org/bukkit/event/raid/RaidSpawnWaveEvent.java ++++ b/src/main/java/org/bukkit/event/raid/RaidSpawnWaveEvent.java +@@ -19,7 +19,7 @@ public class RaidSpawnWaveEvent extends RaidEvent { + private final List raiders; + private final Raider leader; + +- public RaidSpawnWaveEvent(@NotNull Raid raid, @NotNull World world, @Nullable Raider leader, @NotNull List raiders) { ++ public RaidSpawnWaveEvent(@NotNull Raid raid, @NotNull World world, @NotNull Raider leader, @NotNull List raiders) { // Paper + super(raid, world); + this.raiders = raiders; + this.leader = leader; +@@ -30,7 +30,7 @@ public class RaidSpawnWaveEvent extends RaidEvent { + * + * @return {@link Raider} + */ +- @Nullable ++ @NotNull // Paper + public Raider getPatrolLeader() { + return leader; + } +diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java +index 6bafc62e2235a6b783cbf96f4dabeeaf02bd5178..50c762d777ac90a05772501a28cacff8fd3f5126 100644 +--- a/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java ++++ b/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java +@@ -36,18 +36,22 @@ public class VehicleEntityCollisionEvent extends VehicleCollisionEvent implement + this.cancelled = cancel; + } + ++ @Deprecated(forRemoval = true) // Paper - Unused + public boolean isPickupCancelled() { + return cancelledPickup; + } + ++ @Deprecated(forRemoval = true) // Paper - Unused + public void setPickupCancelled(boolean cancel) { + cancelledPickup = cancel; + } + ++ @Deprecated(forRemoval = true) // Paper - Unused + public boolean isCollisionCancelled() { + return cancelledCollision; + } + ++ @Deprecated(forRemoval = true) // Paper - Unused + public void setCollisionCancelled(boolean cancel) { + cancelledCollision = cancel; + } +diff --git a/src/main/java/org/bukkit/generator/ChunkGenerator.java b/src/main/java/org/bukkit/generator/ChunkGenerator.java +index b4dab4cf521c7fb067e88d985572f12d14a2c8df..4e8d0b2f7364c8d5b6c272f566f8d40ce6b4ceb9 100644 +--- a/src/main/java/org/bukkit/generator/ChunkGenerator.java ++++ b/src/main/java/org/bukkit/generator/ChunkGenerator.java +@@ -656,7 +656,9 @@ public abstract class ChunkGenerator { + * @param y the y location in the chunk from minHeight (inclusive) - maxHeight (exclusive) + * @param z the z location in the chunk from 0-15 inclusive + * @param material the type to set the block to ++ * @deprecated use {@link #setBlock(int, int, int, BlockData)} + */ ++ @Deprecated // Paper + public void setBlock(int x, int y, int z, @NotNull MaterialData material); + + /** +@@ -700,7 +702,9 @@ public abstract class ChunkGenerator { + * @param yMax maximum y location (exclusive) in the chunk to set + * @param zMax maximum z location (exclusive) in the chunk to set + * @param material the type to set the blocks to ++ * @deprecated use {@link #setRegion(int, int, int, int, int, int, BlockData)} + */ ++ @Deprecated // Paper + public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, @NotNull MaterialData material); + + /** +@@ -741,8 +745,10 @@ public abstract class ChunkGenerator { + * @param y the y location in the chunk from minHeight (inclusive) - maxHeight (exclusive) + * @param z the z location in the chunk from 0-15 inclusive + * @return the type and data of the block or the MaterialData for air if x, y or z are outside the chunk's bounds ++ * @deprecated use {@link #getBlockData(int, int, int)} + */ + @NotNull ++ @Deprecated // Paper + public MaterialData getTypeAndData(int x, int y, int z); + + /** +diff --git a/src/main/java/org/bukkit/inventory/CookingRecipe.java b/src/main/java/org/bukkit/inventory/CookingRecipe.java +index 571652ba8843a9493f1843523e24145baa958637..f7fa79393aef40027446b78bac8e9490cfafd8bc 100644 +--- a/src/main/java/org/bukkit/inventory/CookingRecipe.java ++++ b/src/main/java/org/bukkit/inventory/CookingRecipe.java +@@ -68,7 +68,9 @@ public abstract class CookingRecipe implements Recipe, + * Get the input material. + * + * @return The input material. ++ * @deprecated Use {@link #getInputChoice()} instead for more complete data. + */ ++ @Deprecated // Paper + @NotNull + public ItemStack getInput() { + return this.ingredient.getItemStack(); +diff --git a/src/main/java/org/bukkit/inventory/CraftingInventory.java b/src/main/java/org/bukkit/inventory/CraftingInventory.java +index df81bac9ecff697f98941e5c8490e10391e90090..a32977ba3ba60a1c9aee6e469d5d6cd1887c55a2 100644 +--- a/src/main/java/org/bukkit/inventory/CraftingInventory.java ++++ b/src/main/java/org/bukkit/inventory/CraftingInventory.java +@@ -21,8 +21,7 @@ public interface CraftingInventory extends Inventory { + * + * @return The contents. Individual entries may be null. + */ +- @NotNull +- ItemStack[] getMatrix(); ++ @Nullable ItemStack @NotNull [] getMatrix(); // Paper - make array elements nullable instead array + + /** + * Set the item in the result slot of the crafting inventory. +@@ -38,7 +37,7 @@ public interface CraftingInventory extends Inventory { + * @throws IllegalArgumentException if the length of contents is greater + * than the size of the crafting matrix. + */ +- void setMatrix(@NotNull ItemStack[] contents); ++ void setMatrix(@Nullable ItemStack @NotNull [] contents); // Paper - make array elements nullable instead array + + /** + * Get the current recipe formed on the crafting inventory, if any. +diff --git a/src/main/java/org/bukkit/inventory/EntityEquipment.java b/src/main/java/org/bukkit/inventory/EntityEquipment.java +index 720038083f8c8ab1f29ac424f2d9dbb5cbc8b533..97c8b338f83f409a652fbaec5105e98b8af751e2 100644 +--- a/src/main/java/org/bukkit/inventory/EntityEquipment.java ++++ b/src/main/java/org/bukkit/inventory/EntityEquipment.java +@@ -525,6 +525,6 @@ public interface EntityEquipment { + * + * @return the entity this EntityEquipment belongs to + */ +- @Nullable ++ @NotNull // Paper + Entity getHolder(); + } +diff --git a/src/main/java/org/bukkit/inventory/FurnaceRecipe.java b/src/main/java/org/bukkit/inventory/FurnaceRecipe.java +index 82d4d0329adda9766ddf2eada3b3684dfef3f32e..d76fbab349a6bfa0ae8b8959d19145ce9b41c7bd 100644 +--- a/src/main/java/org/bukkit/inventory/FurnaceRecipe.java ++++ b/src/main/java/org/bukkit/inventory/FurnaceRecipe.java +@@ -67,8 +67,10 @@ public class FurnaceRecipe extends CookingRecipe { + * + * @param input The input material. + * @return The changed recipe, so you can chain calls. ++ * @deprecated use {@link #setInputChoice(RecipeChoice)} + */ + @NotNull ++ @Deprecated + public FurnaceRecipe setInput(@NotNull MaterialData input) { + return setInput(input.getItemType(), input.getData()); + } +diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/org/bukkit/inventory/Inventory.java +index f1a48eab1a357ae64545e1f1dc941c383cff8707..466d1bd7089b76f48f953e1a51c611ecd93dcd54 100644 +--- a/src/main/java/org/bukkit/inventory/Inventory.java ++++ b/src/main/java/org/bukkit/inventory/Inventory.java +@@ -161,8 +161,7 @@ public interface Inventory extends Iterable { + * + * @return An array of ItemStacks from the inventory. Individual items may be null. + */ +- @NotNull +- public ItemStack[] getContents(); ++ public @Nullable ItemStack @NotNull [] getContents(); // Paper - make array elements nullable instead array + + /** + * Completely replaces the inventory's contents. Removes all existing +@@ -173,7 +172,7 @@ public interface Inventory extends Iterable { + * @throws IllegalArgumentException If the array has more items than the + * inventory. + */ +- public void setContents(@NotNull ItemStack[] items) throws IllegalArgumentException; ++ public void setContents(@Nullable ItemStack @NotNull [] items) throws IllegalArgumentException; // Paper - make array elements nullable instead array + + /** + * Return the contents from the section of the inventory where items can +@@ -186,8 +185,7 @@ public interface Inventory extends Iterable { + * + * @return inventory storage contents. Individual items may be null. + */ +- @NotNull +- public ItemStack[] getStorageContents(); ++ public @Nullable ItemStack @NotNull [] getStorageContents(); // Paper - make array elements nullable instead array + + /** + * Put the given ItemStacks into the storage slots +@@ -196,7 +194,7 @@ public interface Inventory extends Iterable { + * @throws IllegalArgumentException If the array has more items than the + * inventory. + */ +- public void setStorageContents(@NotNull ItemStack[] items) throws IllegalArgumentException; ++ public void setStorageContents(@Nullable ItemStack @NotNull [] items) throws IllegalArgumentException; // Paper - make array elements nullable instead array + + /** + * Checks if the inventory contains any ItemStacks with the given +diff --git a/src/main/java/org/bukkit/inventory/InventoryView.java b/src/main/java/org/bukkit/inventory/InventoryView.java +index 0b5e2f4760a43a7a8d3de7bca557027822145a18..5c258b6077277575daa5d96349837bdf06f42500 100644 +--- a/src/main/java/org/bukkit/inventory/InventoryView.java ++++ b/src/main/java/org/bukkit/inventory/InventoryView.java +@@ -123,9 +123,9 @@ public interface InventoryView { + * Gets the id of this view. + * + * @return the id of this view +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public int getId() { + return id; + } +@@ -195,10 +195,10 @@ public interface InventoryView { + /** + * Get the item on the cursor of one of the viewing players. + * +- * @return The item on the player's cursor, or null if they aren't holding +- * one. ++ * @return The item on the player's cursor, or an empty stack ++ * if they aren't holding one. + */ +- @Nullable ++ @NotNull // Paper - fix nullability + public ItemStack getCursor(); + + /** +@@ -296,8 +296,10 @@ public interface InventoryView { + * made using {@link #setTitle(String)}. + * + * @return the original title ++ * @deprecated changing the title is not supported + */ + @NotNull ++ @Deprecated(since = "1.21.1") // Paper + public String getOriginalTitle(); + + /** +@@ -309,6 +311,9 @@ public interface InventoryView { + * exception. + * + * @param title The new title. ++ * @deprecated changing the title is not supported. This method has ++ * poorly defined and broken behaviors. It should not be used. + */ ++ @Deprecated(since = "1.21.1") // Paper + public void setTitle(@NotNull String title); + } +diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java +index c1ec8efffd5ff2a4dcb1d761be9a431a62284607..a1d8ef8eda3c0256e8c82b7a01c3e7b11454b250 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFactory.java ++++ b/src/main/java/org/bukkit/inventory/ItemFactory.java +@@ -29,7 +29,7 @@ public interface ItemFactory { + * @return a new ItemMeta that could be applied to an item stack of the + * specified material + */ +- @Nullable ++ @org.bukkit.UndefinedNullability // Paper + ItemMeta getItemMeta(@NotNull final Material material); + + /** +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index 080d9a9e26131eb43649104c3d59691308f79fe7..132cf07816b0d356c94fa4e8b8bfefccce2de103 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -10,6 +10,7 @@ import org.bukkit.Material; + import org.bukkit.NamespacedKey; + import org.bukkit.Registry; + import org.bukkit.Translatable; ++import org.bukkit.UndefinedNullability; + import org.bukkit.Utility; + import org.bukkit.configuration.serialization.ConfigurationSerializable; + import org.bukkit.enchantments.Enchantment; +@@ -82,7 +83,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + * @param data the data value or null + * @deprecated this method uses an ambiguous data byte object + */ +- @Deprecated(since = "1.4.5") ++ @Deprecated(since = "1.4.5", forRemoval = true) + public ItemStack(@NotNull Material type, final int amount, final short damage, @Nullable final Byte data) { + Preconditions.checkArgument(type != null, "Material cannot be null"); + if (type.isLegacy()) { +@@ -179,8 +180,10 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + * Gets the MaterialData for this stack of items + * + * @return MaterialData for this item ++ * @deprecated cast to {@link org.bukkit.inventory.meta.BlockDataMeta} and use {@link org.bukkit.inventory.meta.BlockDataMeta#getBlockData(Material)} + */ + @Nullable ++ @Deprecated(forRemoval = true, since = "1.13") + public MaterialData getData() { + Material mat = Bukkit.getUnsafe().toLegacy(getType()); + if (data == null && mat != null && mat.getData() != null) { +@@ -194,7 +197,9 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + * Sets the MaterialData for this stack of items + * + * @param data New MaterialData for this item ++ * @deprecated cast to {@link org.bukkit.inventory.meta.BlockDataMeta} and use {@link org.bukkit.inventory.meta.BlockDataMeta#setBlockData(org.bukkit.block.data.BlockData)} + */ ++ @Deprecated(forRemoval = true, since = "1.13") + public void setData(@Nullable MaterialData data) { + if (data == null) { + this.data = data; +@@ -574,7 +579,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + * + * @return a copy of the current ItemStack's ItemData + */ +- @Nullable ++ @UndefinedNullability // Paper + public ItemMeta getItemMeta() { + return this.meta == null ? Bukkit.getItemFactory().getItemMeta(this.type) : this.meta.clone(); + } +diff --git a/src/main/java/org/bukkit/inventory/PlayerInventory.java b/src/main/java/org/bukkit/inventory/PlayerInventory.java +index b1f4b8f2666e8012eb8a1e21a2b958fe6e03f74f..4294e9296fed42d01b431dbabec97fda26308530 100644 +--- a/src/main/java/org/bukkit/inventory/PlayerInventory.java ++++ b/src/main/java/org/bukkit/inventory/PlayerInventory.java +@@ -16,8 +16,7 @@ public interface PlayerInventory extends Inventory { + * null and are returned in a fixed order starting from the boots and going + * up to the helmet + */ +- @NotNull +- public ItemStack[] getArmorContents(); ++ public @Nullable ItemStack @NotNull [] getArmorContents(); // Paper - make array elements nullable instead array + + /** + * Get all additional ItemStacks stored in this inventory. +@@ -28,8 +27,7 @@ public interface PlayerInventory extends Inventory { + * + * @return All additional ItemStacks. Individual items can be null. + */ +- @NotNull +- public ItemStack[] getExtraContents(); ++ public @Nullable ItemStack @NotNull [] getExtraContents(); // Paper - make array elements nullable instead array + + /** + * Return the ItemStack from the helmet slot +@@ -106,9 +104,9 @@ public interface PlayerInventory extends Inventory { + * + * @param slot the slot to get the ItemStack + * +- * @return the ItemStack in the given slot or null if there is not one ++ * @return the ItemStack in the given slot + */ +- @Nullable ++ @NotNull // Paper + public ItemStack getItem(@NotNull EquipmentSlot slot); + + /** +diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java +index 90b58219ca99dfd4368119183bb414e51c0f0dd1..af540a218d92ca44f5f1bdecdb9ca9f89a7b1ef2 100644 +--- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java ++++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java +@@ -107,8 +107,10 @@ public class ShapedRecipe extends CraftingRecipe { + * @return The changed recipe, so you can chain calls. + * @throws IllegalArgumentException if the {@code key} is a space character + * @throws IllegalArgumentException if the {@code key} does not appear in the shape. ++ * @deprecated use {@link #setIngredient(char, RecipeChoice)} + */ + @NotNull ++ @Deprecated // Paper + public ShapedRecipe setIngredient(char key, @NotNull MaterialData ingredient) { + return setIngredient(key, ingredient.getItemType(), ingredient.getData()); + } +@@ -191,7 +193,9 @@ public class ShapedRecipe extends CraftingRecipe { + * Get a copy of the ingredients map. + * + * @return The mapping of character to ingredients. ++ * @deprecated Use {@link #getChoiceMap()} instead for more complete data. + */ ++ @Deprecated // Paper + @NotNull + public Map getIngredientMap() { + HashMap result = new HashMap(); +diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +index d4a9572a0fedee8993d32ca006a28a242d148e36..449f1ea47f8e5d8aa09e0db3dbfe75a6c05158ef 100644 +--- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java ++++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +@@ -44,8 +44,10 @@ public class ShapelessRecipe extends CraftingRecipe { + * + * @param ingredient The ingredient to add. + * @return The changed recipe, so you can chain calls. ++ * @deprecated use {@link #addIngredient(RecipeChoice)} + */ + @NotNull ++ @Deprecated + public ShapelessRecipe addIngredient(@NotNull MaterialData ingredient) { + return addIngredient(1, ingredient); + } +@@ -81,8 +83,10 @@ public class ShapelessRecipe extends CraftingRecipe { + * @param count How many to add (can't be more than 9!) + * @param ingredient The ingredient to add. + * @return The changed recipe, so you can chain calls. ++ * @deprecated use {@link #addIngredient(int, Material)} + */ + @NotNull ++ @Deprecated // Paper + public ShapelessRecipe addIngredient(int count, @NotNull MaterialData ingredient) { + return addIngredient(count, ingredient.getItemType(), ingredient.getData()); + } +@@ -199,8 +203,10 @@ public class ShapelessRecipe extends CraftingRecipe { + * + * @param ingredient The ingredient to remove + * @return The changed recipe. ++ * @deprecated use {@link #removeIngredient(Material)} + */ + @NotNull ++ @Deprecated // Paper + public ShapelessRecipe removeIngredient(@NotNull MaterialData ingredient) { + return removeIngredient(ingredient.getItemType(), ingredient.getData()); + } +@@ -227,8 +233,10 @@ public class ShapelessRecipe extends CraftingRecipe { + * @param count The number of copies to remove. + * @param ingredient The ingredient to remove. + * @return The changed recipe. ++ * @deprecated use {@link #removeIngredient(int, Material)} + */ + @NotNull ++ @Deprecated // Paper + public ShapelessRecipe removeIngredient(int count, @NotNull MaterialData ingredient) { + return removeIngredient(count, ingredient.getItemType(), ingredient.getData()); + } +@@ -278,7 +286,9 @@ public class ShapelessRecipe extends CraftingRecipe { + * Get the list of ingredients used for this recipe. + * + * @return The input list ++ * @deprecated Use {@link #getChoiceList()} instead for more complete data. + */ ++ @Deprecated // Paper + @NotNull + public List getIngredientList() { + ArrayList result = new ArrayList(ingredients.size()); +diff --git a/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java b/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java +index 597a18a767b68b47e81454b7d44613c7178c1366..bc3440eb72127824b3961fbdae583bb61385f65e 100644 +--- a/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java ++++ b/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java +@@ -57,7 +57,9 @@ public class StonecuttingRecipe implements Recipe, Keyed { + * Get the input material. + * + * @return The input material. ++ * @deprecated Use {@link #getInputChoice()} instead for more complete data. + */ ++ @Deprecated // Paper + @NotNull + public ItemStack getInput() { + return this.ingredient.getItemStack(); +diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +index c083ac4344dd1b2b56cbe103ce80daac945defd5..4012a1b4e9acdfafb38c78a54c4b422ffa07cf04 100644 +--- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +@@ -187,6 +187,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + /** + * Checks for existence of a localized name. + * ++ * @deprecated Use {@link ItemMeta#displayName()} and check if it is instanceof a {@link net.kyori.adventure.text.TranslatableComponent}. + * @return true if this has a localized name + * @deprecated meta no longer exists + */ +@@ -199,6 +200,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * Plugins should check that hasLocalizedName() returns true + * before calling this method. + * ++ * @deprecated Use {@link ItemMeta#displayName()} and cast it to a {@link net.kyori.adventure.text.TranslatableComponent}. No longer used by the client. + * @return the localized name that is set + * @deprecated meta no longer exists + */ +@@ -209,6 +211,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + /** + * Sets the localized name. + * ++ * @deprecated Use {@link ItemMeta#displayName(Component)} with a {@link net.kyori.adventure.text.TranslatableComponent}. No longer used by the client. + * @param name the name to set + * @deprecated meta no longer exists + */ +@@ -802,7 +805,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * + * @return component + */ +- @Nullable ++ @NotNull // Paper + JukeboxPlayableComponent getJukeboxPlayable(); + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/MapMeta.java b/src/main/java/org/bukkit/inventory/meta/MapMeta.java +index 8b0b36cd2ef2efc4bb68bb725c62117fe5b9c838..721164c26c5e219f854f65ab150a46670f4d33bd 100644 +--- a/src/main/java/org/bukkit/inventory/meta/MapMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/MapMeta.java +@@ -16,13 +16,8 @@ public interface MapMeta extends ItemMeta { + * + * @return true if this has a map ID number. + * @see #hasMapView() +- * @deprecated These methods are poor API: They rely on the caller to pass +- * in an only an integer property, and have poorly defined implementation +- * behavior if that integer is not a valid map (the current implementation +- * for example will generate a new map with a different ID). The xxxMapView +- * family of methods should be used instead. + */ +- @Deprecated(since = "1.13.2") ++ //@Deprecated(since = "1.13.2") // Paper + boolean hasMapId(); + + /** +@@ -34,13 +29,8 @@ public interface MapMeta extends ItemMeta { + * + * @return the map ID that is set + * @see #getMapView() +- * @deprecated These methods are poor API: They rely on the caller to pass +- * in an only an integer property, and have poorly defined implementation +- * behavior if that integer is not a valid map (the current implementation +- * for example will generate a new map with a different ID). The xxxMapView +- * family of methods should be used instead. + */ +- @Deprecated(since = "1.13.2") ++ // @Deprecated(since = "1.13.2") // Paper + int getMapId(); + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/components/EquippableComponent.java b/src/main/java/org/bukkit/inventory/meta/components/EquippableComponent.java +index c56e81eb71bccc03378aea71096fdf66b4bfa784..16713c9d4cfaed5ad509b4075121e44c55a8cc76 100644 +--- a/src/main/java/org/bukkit/inventory/meta/components/EquippableComponent.java ++++ b/src/main/java/org/bukkit/inventory/meta/components/EquippableComponent.java +@@ -37,7 +37,7 @@ public interface EquippableComponent extends ConfigurationSerializable { + * + * @return the sound + */ +- @Nullable ++ @NotNull // Paper + Sound getEquipSound(); + + /** +diff --git a/src/main/java/org/bukkit/map/MapCanvas.java b/src/main/java/org/bukkit/map/MapCanvas.java +index fcad167c03dd4f59702142a38ff5bf79ed198031..e63f9586e1cfefd8d1ab4a784444240f42e7b204 100644 +--- a/src/main/java/org/bukkit/map/MapCanvas.java ++++ b/src/main/java/org/bukkit/map/MapCanvas.java +@@ -95,9 +95,9 @@ public interface MapCanvas { + * @param x The x coordinate, from 0 to 127. + * @param y The y coordinate, from 0 to 127. + * @return The color. See {@link MapPalette}. +- * @deprecated Magic value, use {@link #getPixelColor(int, int)} ++ * @deprecated use {@link #getPixelColor(int, int)} + */ +- @Deprecated(since = "1.19") ++ @Deprecated(since = "1.19", forRemoval = true) // Paper + public byte getPixel(int x, int y); + + /** +@@ -106,9 +106,9 @@ public interface MapCanvas { + * @param x The x coordinate, from 0 to 127. + * @param y The y coordinate, from 0 to 127. + * @return The color. See {@link MapPalette}. +- * @deprecated Magic value, use {@link #getBasePixelColor(int, int)} ++ * @deprecated use {@link #getBasePixelColor(int, int)} + */ +- @Deprecated(since = "1.19") ++ @Deprecated(since = "1.19", forRemoval = true) // Paper + public byte getBasePixel(int x, int y); + + /** +diff --git a/src/main/java/org/bukkit/map/MapCursor.java b/src/main/java/org/bukkit/map/MapCursor.java +index 8de6d0c53bce0279a82b84b408e83d2128077400..bd1c0417fbf72731e6301bf79966c6ea4102fc70 100644 +--- a/src/main/java/org/bukkit/map/MapCursor.java ++++ b/src/main/java/org/bukkit/map/MapCursor.java +@@ -163,9 +163,9 @@ public final class MapCursor { + * Get the type of this cursor. + * + * @return The type (color/style) of the map cursor. +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public byte getRawType() { + return type.getValue(); + } +@@ -220,9 +220,9 @@ public final class MapCursor { + * Set the type of this cursor. + * + * @param type The type (color/style) of the map cursor. +- * @deprecated Magic value ++ * @deprecated use {@link #setType(Type)} + */ +- @Deprecated(since = "1.6.2") ++ @Deprecated(since = "1.6.2", forRemoval = true) // Paper + public void setRawType(byte type) { + Type enumType = Type.byValue(type); + Preconditions.checkArgument(enumType != null, "Unknown type by id %s", type); +@@ -332,9 +332,9 @@ public final class MapCursor { + * Gets the internal value of the cursor. + * + * @return the value +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + byte getValue(); + + /** +@@ -342,9 +342,9 @@ public final class MapCursor { + * + * @param value the value + * @return the matching type +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + static Type byValue(byte value) { + for (Type t : values()) { +diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java +index 13000c247e3e1a345832e6bd2d4f6074ef2a1b88..448f37249d21ecb321f53956878fe62293ed34ae 100644 +--- a/src/main/java/org/bukkit/map/MapPalette.java ++++ b/src/main/java/org/bukkit/map/MapPalette.java +@@ -197,9 +197,9 @@ public final class MapPalette { + * + * @param image The image to convert. + * @return A byte[] containing the pixels of the image. +- * @deprecated Magic value ++ * @deprecated use color-related methods + */ +- @Deprecated(since = "1.6.2") ++ @Deprecated(since = "1.6.2", forRemoval = true) // Paper + @NotNull + public static byte[] imageToBytes(@NotNull Image image) { + BufferedImage temp = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); +@@ -225,9 +225,9 @@ public final class MapPalette { + * @param b The blue component of the color. + * @param g The green component of the color. + * @return The index in the palette. +- * @deprecated Magic value ++ * @deprecated use color-related methods + */ +- @Deprecated(since = "1.6.2") ++ @Deprecated(since = "1.6.2", forRemoval = true) // Paper + public static byte matchColor(int r, int g, int b) { + return matchColor(new Color(r, g, b)); + } +@@ -238,9 +238,9 @@ public final class MapPalette { + * + * @param color The Color to match. + * @return The index in the palette. +- * @deprecated Magic value ++ * @deprecated use color-related methods + */ +- @Deprecated(since = "1.6.2") ++ @Deprecated(since = "1.6.2", forRemoval = true) // Paper + public static byte matchColor(@NotNull Color color) { + if (color.getAlpha() < 128) return 0; + +@@ -268,9 +268,9 @@ public final class MapPalette { + * + * @param index The index in the palette. + * @return The Color of the palette entry. +- * @deprecated Magic value ++ * @deprecated use color directly + */ +- @Deprecated(since = "1.6.2") ++ @Deprecated(since = "1.6.2", forRemoval = true) // Paper + @NotNull + public static Color getColor(byte index) { + // Minecraft has 143 colors, some of which have negative byte representations +@@ -311,9 +311,9 @@ public final class MapPalette { + * @param color The Color to match. + * @return The index in the palette. + * @throws IllegalStateException if {@link #isCached()} returns false +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.19") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + byte matchColor(@NotNull Color color); + } + } +diff --git a/src/main/java/org/bukkit/map/MapView.java b/src/main/java/org/bukkit/map/MapView.java +index 73bca3d371d4fe7033bb062d5f42ea4efd40d913..e998c5d871e02564c24260a8205dcfafb6e703d9 100644 +--- a/src/main/java/org/bukkit/map/MapView.java ++++ b/src/main/java/org/bukkit/map/MapView.java +@@ -32,9 +32,9 @@ public interface MapView { + * + * @param value The raw scale + * @return The enum scale, or null for an invalid input +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static Scale valueOf(byte value) { + switch (value) { +@@ -51,9 +51,9 @@ public interface MapView { + * Get the raw value of this scale level. + * + * @return The scale value +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public byte getValue() { + return value; + } +diff --git a/src/main/java/org/bukkit/material/Banner.java b/src/main/java/org/bukkit/material/Banner.java +index cd78e2c35d44ad5fa53947f84f818ef54e5d84fa..e3c2711690459326b875f6f94a2c34a19421d5ed 100644 +--- a/src/main/java/org/bukkit/material/Banner.java ++++ b/src/main/java/org/bukkit/material/Banner.java +@@ -7,7 +7,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(forRemoval = true, since = "1.13") + public class Banner extends MaterialData implements Attachable { + + public Banner() { +diff --git a/src/main/java/org/bukkit/material/Bed.java b/src/main/java/org/bukkit/material/Bed.java +index ff49e6e5b5f75d0a421908445a0c19d2de19b64e..5aafea9c6bbda2ff4282e321ae8815ef46d78e9f 100644 +--- a/src/main/java/org/bukkit/material/Bed.java ++++ b/src/main/java/org/bukkit/material/Bed.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(forRemoval = true, since = "1.13") + public class Bed extends MaterialData implements Directional { + + /** +diff --git a/src/main/java/org/bukkit/material/Button.java b/src/main/java/org/bukkit/material/Button.java +index 794dc81d0b7cad8c4a5c12389f5f19b8e1835a94..6c708737865440442aeaf818e7700c2998d95309 100644 +--- a/src/main/java/org/bukkit/material/Button.java ++++ b/src/main/java/org/bukkit/material/Button.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(forRemoval = true, since = "1.13") + public class Button extends SimpleAttachableMaterialData implements Redstone { + public Button() { + super(Material.LEGACY_STONE_BUTTON); +diff --git a/src/main/java/org/bukkit/material/Cake.java b/src/main/java/org/bukkit/material/Cake.java +index 5fd7b198e812b028dfa90271ccb59c1822a8b683..0d0d41c184652d8b34cf36cacbc8c3910ee579b7 100644 +--- a/src/main/java/org/bukkit/material/Cake.java ++++ b/src/main/java/org/bukkit/material/Cake.java +@@ -6,7 +6,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Cake extends MaterialData { + public Cake() { + super(Material.LEGACY_CAKE_BLOCK); +diff --git a/src/main/java/org/bukkit/material/Cauldron.java b/src/main/java/org/bukkit/material/Cauldron.java +index a72c74400a5e0b97ba0e88b99dbbf5e90e4f92e0..b8a15af79f9fdf0a948d6a0172bb9f250ed8ce3b 100644 +--- a/src/main/java/org/bukkit/material/Cauldron.java ++++ b/src/main/java/org/bukkit/material/Cauldron.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Cauldron extends MaterialData { + private static final int CAULDRON_FULL = 3; + private static final int CAULDRON_EMPTY = 0; +diff --git a/src/main/java/org/bukkit/material/Chest.java b/src/main/java/org/bukkit/material/Chest.java +index 302bf01e8b0eafdddab940cfe9d3d894329ce8f9..a07e320f3d7a32d11f3bb1c136ca2574dd9cf40f 100644 +--- a/src/main/java/org/bukkit/material/Chest.java ++++ b/src/main/java/org/bukkit/material/Chest.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Chest extends DirectionalContainer { + + public Chest() { +diff --git a/src/main/java/org/bukkit/material/Coal.java b/src/main/java/org/bukkit/material/Coal.java +index bc60ab8bda785798b36873596e6c186556ef73b3..bdb8345371cd64ec8bf17174ec9d874341572527 100644 +--- a/src/main/java/org/bukkit/material/Coal.java ++++ b/src/main/java/org/bukkit/material/Coal.java +@@ -9,7 +9,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Coal extends MaterialData { + public Coal() { + super(Material.LEGACY_COAL); +diff --git a/src/main/java/org/bukkit/material/CocoaPlant.java b/src/main/java/org/bukkit/material/CocoaPlant.java +index db1cdd8e26c71ca16b195307f4ba5b57b341cf9f..bebb09bca0565d18c4028ff6aa7a52fa4ff63c7a 100644 +--- a/src/main/java/org/bukkit/material/CocoaPlant.java ++++ b/src/main/java/org/bukkit/material/CocoaPlant.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class CocoaPlant extends MaterialData implements Directional, Attachable { + + public enum CocoaPlantSize { +diff --git a/src/main/java/org/bukkit/material/Command.java b/src/main/java/org/bukkit/material/Command.java +index c83abea1a81bacc8973004f31388c985e1ed70f4..d7953e28d050c03d37146484c0c5b346dd0bc84d 100644 +--- a/src/main/java/org/bukkit/material/Command.java ++++ b/src/main/java/org/bukkit/material/Command.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Command extends MaterialData implements Redstone { + public Command() { + super(Material.LEGACY_COMMAND); +diff --git a/src/main/java/org/bukkit/material/Comparator.java b/src/main/java/org/bukkit/material/Comparator.java +index 047f571be36e9f3862d04836b47d2168d6d91013..ec3a9ee830694162a31857b8c3559e76fada049a 100644 +--- a/src/main/java/org/bukkit/material/Comparator.java ++++ b/src/main/java/org/bukkit/material/Comparator.java +@@ -12,7 +12,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Comparator extends MaterialData implements Directional, Redstone { + protected static final BlockFace DEFAULT_DIRECTION = BlockFace.NORTH; + protected static final boolean DEFAULT_SUBTRACTION_MODE = false; +diff --git a/src/main/java/org/bukkit/material/Crops.java b/src/main/java/org/bukkit/material/Crops.java +index b76c144f4497ced42212916cff112161926a41c8..1de6ad1dc1c0aaa3e3d2877c61afc772eb46c634 100644 +--- a/src/main/java/org/bukkit/material/Crops.java ++++ b/src/main/java/org/bukkit/material/Crops.java +@@ -15,7 +15,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Crops extends MaterialData { + protected static final Material DEFAULT_TYPE = Material.LEGACY_CROPS; + protected static final CropState DEFAULT_STATE = CropState.SEEDED; +diff --git a/src/main/java/org/bukkit/material/DetectorRail.java b/src/main/java/org/bukkit/material/DetectorRail.java +index 3a46eea9120999a91b3127daa8fe3b0f456e35fe..234132a9e85a1a76ceaba4744fecc4c6afcdf7d5 100644 +--- a/src/main/java/org/bukkit/material/DetectorRail.java ++++ b/src/main/java/org/bukkit/material/DetectorRail.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class DetectorRail extends ExtendedRails implements PressureSensor { + public DetectorRail() { + super(Material.LEGACY_DETECTOR_RAIL); +diff --git a/src/main/java/org/bukkit/material/Diode.java b/src/main/java/org/bukkit/material/Diode.java +index 1576aaab7f06fc34c5ffa3a2b0ee797d67c19cbb..68c1e05726cf5b6bdc81cfdc8b0364ac91858649 100644 +--- a/src/main/java/org/bukkit/material/Diode.java ++++ b/src/main/java/org/bukkit/material/Diode.java +@@ -13,7 +13,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Diode extends MaterialData implements Directional, Redstone { + + protected static final BlockFace DEFAULT_DIRECTION = BlockFace.NORTH; +diff --git a/src/main/java/org/bukkit/material/DirectionalContainer.java b/src/main/java/org/bukkit/material/DirectionalContainer.java +index c862d36ff2593b56e29f795c2d114a44afc17eec..aac0197ff88853c21f9eaa084c25c24846c26168 100644 +--- a/src/main/java/org/bukkit/material/DirectionalContainer.java ++++ b/src/main/java/org/bukkit/material/DirectionalContainer.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class DirectionalContainer extends MaterialData implements Directional { + + public DirectionalContainer(final Material type) { +diff --git a/src/main/java/org/bukkit/material/Dispenser.java b/src/main/java/org/bukkit/material/Dispenser.java +index 340f372a9288811e9a650b55fad127d4887ec91c..c676d03b1313812a33fbead3fe4745223a00489e 100644 +--- a/src/main/java/org/bukkit/material/Dispenser.java ++++ b/src/main/java/org/bukkit/material/Dispenser.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Dispenser extends FurnaceAndDispenser { + + public Dispenser() { +diff --git a/src/main/java/org/bukkit/material/Door.java b/src/main/java/org/bukkit/material/Door.java +index a92da22234dea8543bc1180eb4f2942ddcc4061e..0205e134f608b6f9c674595c55e699dde1edbf35 100644 +--- a/src/main/java/org/bukkit/material/Door.java ++++ b/src/main/java/org/bukkit/material/Door.java +@@ -22,7 +22,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Door extends MaterialData implements Directional, Openable { + + // This class breaks API contracts on Directional and Openable because +diff --git a/src/main/java/org/bukkit/material/Dye.java b/src/main/java/org/bukkit/material/Dye.java +index 72d494631a4779f5b2147492a0dc8085b4b388b8..11375c51c0ed3493642335e1c8ef2d6c36987735 100644 +--- a/src/main/java/org/bukkit/material/Dye.java ++++ b/src/main/java/org/bukkit/material/Dye.java +@@ -9,7 +9,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Dye extends MaterialData implements Colorable { + public Dye() { + super(Material.LEGACY_INK_SACK); +diff --git a/src/main/java/org/bukkit/material/EnderChest.java b/src/main/java/org/bukkit/material/EnderChest.java +index 65f286a7ca3ebd98a9b0e2cd89b4775e769beaad..1d49f78e32eba67a21b4e7f23d3bb1d0f8532711 100644 +--- a/src/main/java/org/bukkit/material/EnderChest.java ++++ b/src/main/java/org/bukkit/material/EnderChest.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class EnderChest extends DirectionalContainer { + + public EnderChest() { +diff --git a/src/main/java/org/bukkit/material/ExtendedRails.java b/src/main/java/org/bukkit/material/ExtendedRails.java +index cbbf953b746c27ea2e30324ecea26543fa397cbb..23a329c7cef93f7f146edac9b0829f82aec4f76a 100644 +--- a/src/main/java/org/bukkit/material/ExtendedRails.java ++++ b/src/main/java/org/bukkit/material/ExtendedRails.java +@@ -10,7 +10,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class ExtendedRails extends Rails { + + public ExtendedRails(final Material type) { +diff --git a/src/main/java/org/bukkit/material/FlowerPot.java b/src/main/java/org/bukkit/material/FlowerPot.java +index 45ebe2671b01fdd918dd6254d48dc35d0f46a899..5bf2cc1baeb9a7fd329cb49f34b8ba6cef4a4862 100644 +--- a/src/main/java/org/bukkit/material/FlowerPot.java ++++ b/src/main/java/org/bukkit/material/FlowerPot.java +@@ -10,7 +10,7 @@ import org.bukkit.TreeSpecies; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.9.4") ++@Deprecated(since = "1.13", forRemoval = true) + public class FlowerPot extends MaterialData { + + /** +diff --git a/src/main/java/org/bukkit/material/Furnace.java b/src/main/java/org/bukkit/material/Furnace.java +index 7bfc7c6edb6fea760dc568932da6ba4716b7f995..9cd029934d40e9490ef6309fb50b066fc19623a0 100644 +--- a/src/main/java/org/bukkit/material/Furnace.java ++++ b/src/main/java/org/bukkit/material/Furnace.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Furnace extends FurnaceAndDispenser { + + public Furnace() { +diff --git a/src/main/java/org/bukkit/material/FurnaceAndDispenser.java b/src/main/java/org/bukkit/material/FurnaceAndDispenser.java +index b7fb6cf424becdfc356e0ea2c57b7fd38ccdf0b2..119dca552267b1ca0b566ddff1f8e70253af5f56 100644 +--- a/src/main/java/org/bukkit/material/FurnaceAndDispenser.java ++++ b/src/main/java/org/bukkit/material/FurnaceAndDispenser.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class FurnaceAndDispenser extends DirectionalContainer { + + public FurnaceAndDispenser(final Material type) { +diff --git a/src/main/java/org/bukkit/material/Gate.java b/src/main/java/org/bukkit/material/Gate.java +index 10c259338f16d2a0e8b18a79b4f159f1fb782d3f..441a796cbb546e4a577f7189ea463614c6028281 100644 +--- a/src/main/java/org/bukkit/material/Gate.java ++++ b/src/main/java/org/bukkit/material/Gate.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Gate extends MaterialData implements Directional, Openable { + private static final byte OPEN_BIT = 0x4; + private static final byte DIR_BIT = 0x3; +diff --git a/src/main/java/org/bukkit/material/Hopper.java b/src/main/java/org/bukkit/material/Hopper.java +index b5fc3746c8c6c72656a17880823c26e49b23c1d2..69abe65bca9562382c4307be497fb41fe38ce935 100644 +--- a/src/main/java/org/bukkit/material/Hopper.java ++++ b/src/main/java/org/bukkit/material/Hopper.java +@@ -12,7 +12,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Hopper extends MaterialData implements Directional, Redstone { + + protected static final BlockFace DEFAULT_DIRECTION = BlockFace.DOWN; +diff --git a/src/main/java/org/bukkit/material/Ladder.java b/src/main/java/org/bukkit/material/Ladder.java +index ab607ae626ef6832955d25126285998d007013e4..ada73c2576e112926fa573e0665fa2879e8056bd 100644 +--- a/src/main/java/org/bukkit/material/Ladder.java ++++ b/src/main/java/org/bukkit/material/Ladder.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Ladder extends SimpleAttachableMaterialData { + public Ladder() { + super(Material.LEGACY_LADDER); +diff --git a/src/main/java/org/bukkit/material/Leaves.java b/src/main/java/org/bukkit/material/Leaves.java +index 69f47d00f17a8de564fc7d7903df7624d7872db2..f9dd206a4070dd9d24ad97616da7de81b9607f0b 100644 +--- a/src/main/java/org/bukkit/material/Leaves.java ++++ b/src/main/java/org/bukkit/material/Leaves.java +@@ -13,7 +13,7 @@ import org.bukkit.TreeSpecies; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Leaves extends Wood { + protected static final Material DEFAULT_TYPE = Material.LEGACY_LEAVES; + protected static final boolean DEFAULT_DECAYABLE = true; +diff --git a/src/main/java/org/bukkit/material/Lever.java b/src/main/java/org/bukkit/material/Lever.java +index e2add49ce34b46c24154cd9f0c5a755a2013cddf..1c1b36ea1ca646a3624c19c837cf4292da8c2464 100644 +--- a/src/main/java/org/bukkit/material/Lever.java ++++ b/src/main/java/org/bukkit/material/Lever.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Lever extends SimpleAttachableMaterialData implements Redstone { + public Lever() { + super(Material.LEGACY_LEVER); +diff --git a/src/main/java/org/bukkit/material/LongGrass.java b/src/main/java/org/bukkit/material/LongGrass.java +index 5b7f21fff6570b848f21b6bf0a2806ac4f85ae3f..4db8006dc4210d416f1ea296528e458655f7824d 100644 +--- a/src/main/java/org/bukkit/material/LongGrass.java ++++ b/src/main/java/org/bukkit/material/LongGrass.java +@@ -9,7 +9,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class LongGrass extends MaterialData { + public LongGrass() { + super(Material.LEGACY_LONG_GRASS); +diff --git a/src/main/java/org/bukkit/material/MaterialData.java b/src/main/java/org/bukkit/material/MaterialData.java +index 4b778e828f6d1b6b9cbb766ae7681f586812f1ec..874559af354ca12166f239882d95c74056f8d57f 100644 +--- a/src/main/java/org/bukkit/material/MaterialData.java ++++ b/src/main/java/org/bukkit/material/MaterialData.java +@@ -9,7 +9,7 @@ import org.bukkit.inventory.ItemStack; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.13") ++@Deprecated(since = "1.13", forRemoval = true) + public class MaterialData implements Cloneable { + private final Material type; + private byte data = 0; +diff --git a/src/main/java/org/bukkit/material/MonsterEggs.java b/src/main/java/org/bukkit/material/MonsterEggs.java +index 3c25dd940ebe0c8b1b091a7062073c093f150bd3..8fc242e4eb98af9b40bc54e1436b568d7890987c 100644 +--- a/src/main/java/org/bukkit/material/MonsterEggs.java ++++ b/src/main/java/org/bukkit/material/MonsterEggs.java +@@ -10,7 +10,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class MonsterEggs extends TexturedMaterial { + + private static final List textures = new ArrayList(); +diff --git a/src/main/java/org/bukkit/material/Mushroom.java b/src/main/java/org/bukkit/material/Mushroom.java +index 6e41bddacbe82e8c9195f3a5f270d211924d8c58..a05959f97390525bd6881770a3087093a7089cad 100644 +--- a/src/main/java/org/bukkit/material/Mushroom.java ++++ b/src/main/java/org/bukkit/material/Mushroom.java +@@ -17,7 +17,7 @@ import org.bukkit.material.types.MushroomBlockTexture; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Mushroom extends MaterialData { + private static final byte NORTH_LIMIT = 4; + private static final byte SOUTH_LIMIT = 6; +diff --git a/src/main/java/org/bukkit/material/NetherWarts.java b/src/main/java/org/bukkit/material/NetherWarts.java +index 1e6f4c6cc4bfd0fc20870251c04920f133239e6b..da784d87d260b9782d8a3a817cb4bdb69f65a867 100644 +--- a/src/main/java/org/bukkit/material/NetherWarts.java ++++ b/src/main/java/org/bukkit/material/NetherWarts.java +@@ -9,7 +9,7 @@ import org.bukkit.NetherWartsState; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class NetherWarts extends MaterialData { + public NetherWarts() { + super(Material.LEGACY_NETHER_WARTS); +diff --git a/src/main/java/org/bukkit/material/Observer.java b/src/main/java/org/bukkit/material/Observer.java +index e7ade2dd22826d52f5624fdfba3496c1468af0e9..06c7206b871981c8f874e009aad8167fe572668e 100644 +--- a/src/main/java/org/bukkit/material/Observer.java ++++ b/src/main/java/org/bukkit/material/Observer.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Observer extends MaterialData implements Directional, Redstone { + + public Observer() { +diff --git a/src/main/java/org/bukkit/material/Openable.java b/src/main/java/org/bukkit/material/Openable.java +index 0ae54f973d11df74abb3105cf9226afb130b4f33..df2c2a774155d79ccf6fa7f366fe011ae4a43b90 100644 +--- a/src/main/java/org/bukkit/material/Openable.java ++++ b/src/main/java/org/bukkit/material/Openable.java +@@ -1,5 +1,6 @@ + package org.bukkit.material; + ++@Deprecated(forRemoval = true, since = "1.13") + public interface Openable { + + /** +diff --git a/src/main/java/org/bukkit/material/PistonBaseMaterial.java b/src/main/java/org/bukkit/material/PistonBaseMaterial.java +index a0fe943735ca40813e2c629407f87471f9f7df3d..2fdd7f2adf34a0ed11235c135bca295601f89a21 100644 +--- a/src/main/java/org/bukkit/material/PistonBaseMaterial.java ++++ b/src/main/java/org/bukkit/material/PistonBaseMaterial.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class PistonBaseMaterial extends MaterialData implements Directional, Redstone { + + public PistonBaseMaterial(final Material type) { +diff --git a/src/main/java/org/bukkit/material/PistonExtensionMaterial.java b/src/main/java/org/bukkit/material/PistonExtensionMaterial.java +index 19dfe68e3380165e5f1ce3a5aa506db000d75e32..c87e54ca5a1420ec6212800ab33744cdb8bcab9d 100644 +--- a/src/main/java/org/bukkit/material/PistonExtensionMaterial.java ++++ b/src/main/java/org/bukkit/material/PistonExtensionMaterial.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class PistonExtensionMaterial extends MaterialData implements Attachable { + + public PistonExtensionMaterial(final Material type) { +diff --git a/src/main/java/org/bukkit/material/PoweredRail.java b/src/main/java/org/bukkit/material/PoweredRail.java +index e563c8e53a748bbe42ff8ae867c964444b391519..d24968b9e3067e70cc17a9bd2d9c204787b01d3e 100644 +--- a/src/main/java/org/bukkit/material/PoweredRail.java ++++ b/src/main/java/org/bukkit/material/PoweredRail.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class PoweredRail extends ExtendedRails implements Redstone { + public PoweredRail() { + super(Material.LEGACY_POWERED_RAIL); +diff --git a/src/main/java/org/bukkit/material/PressurePlate.java b/src/main/java/org/bukkit/material/PressurePlate.java +index 8827062fcd26741ead93fd2c0614719045034ae1..a04c024a48367ba36a92a6738200c73a855fbfec 100644 +--- a/src/main/java/org/bukkit/material/PressurePlate.java ++++ b/src/main/java/org/bukkit/material/PressurePlate.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class PressurePlate extends MaterialData implements PressureSensor { + public PressurePlate() { + super(Material.LEGACY_WOOD_PLATE); +diff --git a/src/main/java/org/bukkit/material/Pumpkin.java b/src/main/java/org/bukkit/material/Pumpkin.java +index 55b0ade2cbf3ba147fbd34768fb95e7eb9398477..49e3442377e1fb89dfdb2ea97a62f16c69bfe5ab 100644 +--- a/src/main/java/org/bukkit/material/Pumpkin.java ++++ b/src/main/java/org/bukkit/material/Pumpkin.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Pumpkin extends MaterialData implements Directional { + + public Pumpkin() { +diff --git a/src/main/java/org/bukkit/material/Rails.java b/src/main/java/org/bukkit/material/Rails.java +index 8b6b0139da8127d38dfb3b1f3e70ddf530d1788c..852e06835f8bb0982cb260e3660290fb3e6ecf50 100644 +--- a/src/main/java/org/bukkit/material/Rails.java ++++ b/src/main/java/org/bukkit/material/Rails.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Rails extends MaterialData { + + public Rails() { +diff --git a/src/main/java/org/bukkit/material/Redstone.java b/src/main/java/org/bukkit/material/Redstone.java +index 3e46603f8cd38041394e0e1baf788d9009b3ffc7..eb621f34d0461c9bfe1bd7535344b6778e7b39c5 100644 +--- a/src/main/java/org/bukkit/material/Redstone.java ++++ b/src/main/java/org/bukkit/material/Redstone.java +@@ -3,6 +3,7 @@ package org.bukkit.material; + /** + * Indicated a Material that may carry or create a Redstone current + */ ++@Deprecated(forRemoval = true, since = "1.13") + public interface Redstone { + + /** +diff --git a/src/main/java/org/bukkit/material/RedstoneTorch.java b/src/main/java/org/bukkit/material/RedstoneTorch.java +index 369f1826ecaafdb0ca096e8dd1506f35b8ceb283..9c7f7f72922ccd1ecf9dfba8618d7c618d9cf718 100644 +--- a/src/main/java/org/bukkit/material/RedstoneTorch.java ++++ b/src/main/java/org/bukkit/material/RedstoneTorch.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class RedstoneTorch extends Torch implements Redstone { + public RedstoneTorch() { + super(Material.LEGACY_REDSTONE_TORCH_ON); +diff --git a/src/main/java/org/bukkit/material/RedstoneWire.java b/src/main/java/org/bukkit/material/RedstoneWire.java +index 01f93fbacc6152a3786a4082e00d92d2c0ce2920..b9a88c4efadcea415ebc65ffeb9df90a929230c3 100644 +--- a/src/main/java/org/bukkit/material/RedstoneWire.java ++++ b/src/main/java/org/bukkit/material/RedstoneWire.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class RedstoneWire extends MaterialData implements Redstone { + public RedstoneWire() { + super(Material.LEGACY_REDSTONE_WIRE); +diff --git a/src/main/java/org/bukkit/material/Sandstone.java b/src/main/java/org/bukkit/material/Sandstone.java +index 6bab43f68a9282106586a63a31a5784e0bbe71e5..302db083d129a91eb24ddc06d835c85ce10bdf9a 100644 +--- a/src/main/java/org/bukkit/material/Sandstone.java ++++ b/src/main/java/org/bukkit/material/Sandstone.java +@@ -9,7 +9,7 @@ import org.bukkit.SandstoneType; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Sandstone extends MaterialData { + public Sandstone() { + super(Material.LEGACY_SANDSTONE); +diff --git a/src/main/java/org/bukkit/material/Sapling.java b/src/main/java/org/bukkit/material/Sapling.java +index 84daf0d756ecfd6d46c9b6398b29ae5994364ce3..9a34ed6241a3b6a170d7e3a3cf52dbd49e82dc1b 100644 +--- a/src/main/java/org/bukkit/material/Sapling.java ++++ b/src/main/java/org/bukkit/material/Sapling.java +@@ -11,7 +11,7 @@ import org.bukkit.TreeSpecies; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Sapling extends Wood { + + /** +diff --git a/src/main/java/org/bukkit/material/Sign.java b/src/main/java/org/bukkit/material/Sign.java +index 48cd4599b723b1fe8cab0e2d439773ea31f28569..ed63a98e8902d4f473881777f905fdc8ff9b1293 100644 +--- a/src/main/java/org/bukkit/material/Sign.java ++++ b/src/main/java/org/bukkit/material/Sign.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Sign extends MaterialData implements Attachable { + public Sign() { + super(Material.LEGACY_SIGN_POST); +diff --git a/src/main/java/org/bukkit/material/SimpleAttachableMaterialData.java b/src/main/java/org/bukkit/material/SimpleAttachableMaterialData.java +index d9527c6f786f7e9628dcb18afd20f36051d8b922..500eb54ba22f0534a858a4374aae1f62c30b1cdf 100644 +--- a/src/main/java/org/bukkit/material/SimpleAttachableMaterialData.java ++++ b/src/main/java/org/bukkit/material/SimpleAttachableMaterialData.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public abstract class SimpleAttachableMaterialData extends MaterialData implements Attachable { + + public SimpleAttachableMaterialData(Material type, BlockFace direction) { +diff --git a/src/main/java/org/bukkit/material/Skull.java b/src/main/java/org/bukkit/material/Skull.java +index 8339519118c24206db38b55f8756941e9f762abc..95a38ab49303ebb38b8dfc0f996d8e786e273aa7 100644 +--- a/src/main/java/org/bukkit/material/Skull.java ++++ b/src/main/java/org/bukkit/material/Skull.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Skull extends MaterialData implements Directional { + public Skull() { + super(Material.LEGACY_SKULL); +diff --git a/src/main/java/org/bukkit/material/SmoothBrick.java b/src/main/java/org/bukkit/material/SmoothBrick.java +index 0dfbe2891ff9f3a8f18e7e9867b2eab7fb3b4ae0..f97a874360ed0890df8452535698cb9148b57c1a 100644 +--- a/src/main/java/org/bukkit/material/SmoothBrick.java ++++ b/src/main/java/org/bukkit/material/SmoothBrick.java +@@ -10,7 +10,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class SmoothBrick extends TexturedMaterial { + + private static final List textures = new ArrayList(); +diff --git a/src/main/java/org/bukkit/material/SpawnEgg.java b/src/main/java/org/bukkit/material/SpawnEgg.java +index 601bd3cfd38d02d0e8b652c4c4771795cc2349c6..69011a06f0cd695370b63798113e30c4e4039f28 100644 +--- a/src/main/java/org/bukkit/material/SpawnEgg.java ++++ b/src/main/java/org/bukkit/material/SpawnEgg.java +@@ -8,7 +8,7 @@ import org.bukkit.inventory.meta.SpawnEggMeta; + * Represents a spawn egg that can be used to spawn mobs + * @deprecated use {@link SpawnEggMeta} + */ +-@Deprecated(since = "1.11") ++@Deprecated(since = "1.13", forRemoval = true) + public class SpawnEgg extends MaterialData { + + public SpawnEgg() { +diff --git a/src/main/java/org/bukkit/material/Stairs.java b/src/main/java/org/bukkit/material/Stairs.java +index c68a7045b98471ca150a00e977489cb0802eab10..3b3ca6e6e907521b18b7ce74cd5fb2edd58d2371 100644 +--- a/src/main/java/org/bukkit/material/Stairs.java ++++ b/src/main/java/org/bukkit/material/Stairs.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Stairs extends MaterialData implements Directional { + + public Stairs(final Material type) { +diff --git a/src/main/java/org/bukkit/material/Step.java b/src/main/java/org/bukkit/material/Step.java +index dc5eedb278c07e7f447fe8aae7a182d33b05cdfd..2ca3794b697dedec5b34d73104886c51e292575f 100644 +--- a/src/main/java/org/bukkit/material/Step.java ++++ b/src/main/java/org/bukkit/material/Step.java +@@ -10,7 +10,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Step extends TexturedMaterial { + private static final List textures = new ArrayList(); + static { +diff --git a/src/main/java/org/bukkit/material/TexturedMaterial.java b/src/main/java/org/bukkit/material/TexturedMaterial.java +index 39adc75f7f81075f61a26e775b622ffc4eec4cff..361e2697308fbddc12e3bdbff336d6dfd6f39a25 100644 +--- a/src/main/java/org/bukkit/material/TexturedMaterial.java ++++ b/src/main/java/org/bukkit/material/TexturedMaterial.java +@@ -9,7 +9,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public abstract class TexturedMaterial extends MaterialData { + + public TexturedMaterial(Material m) { +diff --git a/src/main/java/org/bukkit/material/Torch.java b/src/main/java/org/bukkit/material/Torch.java +index 194cd646221af2dd11f78ca427a7e672120ad1ca..b74e70f89c8a237eac0f0d0c4d5a94bd964a4163 100644 +--- a/src/main/java/org/bukkit/material/Torch.java ++++ b/src/main/java/org/bukkit/material/Torch.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Torch extends SimpleAttachableMaterialData { + public Torch() { + super(Material.LEGACY_TORCH); +diff --git a/src/main/java/org/bukkit/material/TrapDoor.java b/src/main/java/org/bukkit/material/TrapDoor.java +index 24b4391a915f5ffd8b236277764c73b25acddfff..3c1082931790b5b65792a04f63f70cd00d2db118 100644 +--- a/src/main/java/org/bukkit/material/TrapDoor.java ++++ b/src/main/java/org/bukkit/material/TrapDoor.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class TrapDoor extends SimpleAttachableMaterialData implements Openable { + public TrapDoor() { + super(Material.LEGACY_TRAP_DOOR); +diff --git a/src/main/java/org/bukkit/material/Tree.java b/src/main/java/org/bukkit/material/Tree.java +index 5c733a33633829efc7c6429dcff2ef5146bcc347..0c113a39a6a954a1606c2eeeb236838d341d2388 100644 +--- a/src/main/java/org/bukkit/material/Tree.java ++++ b/src/main/java/org/bukkit/material/Tree.java +@@ -13,7 +13,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Tree extends Wood { + protected static final Material DEFAULT_TYPE = Material.LEGACY_LOG; + protected static final BlockFace DEFAULT_DIRECTION = BlockFace.UP; +diff --git a/src/main/java/org/bukkit/material/Tripwire.java b/src/main/java/org/bukkit/material/Tripwire.java +index 4378b2992b32b730d1cc8fa43a8ac693b9c5e2a6..676d5ebeac4536d37e24ccf2ce4c7a9aa4816c03 100644 +--- a/src/main/java/org/bukkit/material/Tripwire.java ++++ b/src/main/java/org/bukkit/material/Tripwire.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Tripwire extends MaterialData { + + public Tripwire() { +diff --git a/src/main/java/org/bukkit/material/TripwireHook.java b/src/main/java/org/bukkit/material/TripwireHook.java +index 458a3e9fc2e8f6d2a0a5c665422cee063c521f56..1864bb64d7dd464064fd0f63e7d78d9dd623dced 100644 +--- a/src/main/java/org/bukkit/material/TripwireHook.java ++++ b/src/main/java/org/bukkit/material/TripwireHook.java +@@ -9,7 +9,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class TripwireHook extends SimpleAttachableMaterialData implements Redstone { + + public TripwireHook() { +diff --git a/src/main/java/org/bukkit/material/Vine.java b/src/main/java/org/bukkit/material/Vine.java +index 784ea52519fee07507cd42a449e75afdec72aa66..4cb1d983217ce727f1ad39af1075640ce797a01f 100644 +--- a/src/main/java/org/bukkit/material/Vine.java ++++ b/src/main/java/org/bukkit/material/Vine.java +@@ -11,7 +11,7 @@ import org.bukkit.block.BlockFace; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Vine extends MaterialData { + private static final int VINE_NORTH = 0x4; + private static final int VINE_EAST = 0x8; +diff --git a/src/main/java/org/bukkit/material/Wood.java b/src/main/java/org/bukkit/material/Wood.java +index 62253cfc84473bfa0028271893a87984385c356b..d139a212f46f970839dec8607c40937e2750cc40 100644 +--- a/src/main/java/org/bukkit/material/Wood.java ++++ b/src/main/java/org/bukkit/material/Wood.java +@@ -13,7 +13,7 @@ import org.bukkit.TreeSpecies; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Wood extends MaterialData { + protected static final Material DEFAULT_TYPE = Material.LEGACY_WOOD; + protected static final TreeSpecies DEFAULT_SPECIES = TreeSpecies.GENERIC; +diff --git a/src/main/java/org/bukkit/material/WoodenStep.java b/src/main/java/org/bukkit/material/WoodenStep.java +index 24990ed25759cd7a77bbd1b88bedb6063d1b3463..df6223d836bbb1ff0233f3071b0464df8ad9616c 100644 +--- a/src/main/java/org/bukkit/material/WoodenStep.java ++++ b/src/main/java/org/bukkit/material/WoodenStep.java +@@ -11,7 +11,7 @@ import org.bukkit.TreeSpecies; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class WoodenStep extends Wood { + protected static final Material DEFAULT_TYPE = Material.LEGACY_WOOD_STEP; + protected static final boolean DEFAULT_INVERTED = false; +diff --git a/src/main/java/org/bukkit/material/Wool.java b/src/main/java/org/bukkit/material/Wool.java +index 5ad1f9f1995d3b8e4d71126c66217e817c587291..9758818bfbcee789bc8a705df0ff3c0b2fe56e97 100644 +--- a/src/main/java/org/bukkit/material/Wool.java ++++ b/src/main/java/org/bukkit/material/Wool.java +@@ -8,7 +8,7 @@ import org.bukkit.Material; + * @deprecated all usage of MaterialData is deprecated and subject to removal. + * Use {@link org.bukkit.block.data.BlockData}. + */ +-@Deprecated(since = "1.14.1") ++@Deprecated(since = "1.13", forRemoval = true) + public class Wool extends MaterialData implements Colorable { + public Wool() { + super(Material.LEGACY_WOOL); +diff --git a/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java b/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java +index 0044381b8ac521968b0915b76a74fd1f2542c2d0..8e6e22cefb432b07aa59f8b73b89e952bacbf902 100644 +--- a/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java ++++ b/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java +@@ -7,7 +7,9 @@ import org.jetbrains.annotations.Nullable; + + /** + * Represents the different textured blocks of mushroom. ++ * @deprecated use BlockData + */ ++@Deprecated // Paper + public enum MushroomBlockTexture { + + /** +diff --git a/src/main/java/org/bukkit/potion/PotionEffectType.java b/src/main/java/org/bukkit/potion/PotionEffectType.java +index 7fbcb12516a77b594061375abb0a447832abccc2..6375eed0ef4f8e897a00b4f77fb45b354888e74e 100644 +--- a/src/main/java/org/bukkit/potion/PotionEffectType.java ++++ b/src/main/java/org/bukkit/potion/PotionEffectType.java +@@ -278,9 +278,9 @@ public abstract class PotionEffectType implements Keyed, Translatable { + * Returns the unique ID of this type. + * + * @return Unique ID +- * @deprecated Magic value ++ * @deprecated use {@link #key()} + */ +- @Deprecated(since = "1.6.2") ++ @Deprecated(since = "1.6.2", forRemoval = true) // Paper + public abstract int getId(); + + /** +@@ -316,9 +316,9 @@ public abstract class PotionEffectType implements Keyed, Translatable { + * + * @param id Unique ID to fetch + * @return Resulting type, or null if not found. +- * @deprecated Magic value ++ * @apiNote Internal Use Only + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static PotionEffectType getById(int id) { + PotionEffectType type = ID_MAP.get(id); +diff --git a/src/test/java/org/bukkit/materials/MaterialDataTest.java b/src/test/java/org/bukkit/materials/MaterialDataTest.java +index 8d78435cc42a9e668b2d4d674b79b4094c3bd1b1..24a8ce4387b897c717b55405f363ffafff45894d 100644 +--- a/src/test/java/org/bukkit/materials/MaterialDataTest.java ++++ b/src/test/java/org/bukkit/materials/MaterialDataTest.java +@@ -22,6 +22,7 @@ import org.bukkit.material.WoodenStep; + import org.bukkit.material.types.MushroomBlockTexture; + import org.junit.jupiter.api.Test; + ++@Deprecated // Paper + public class MaterialDataTest { + + @Test diff --git a/patches/api/0167-Change-the-reserved-channel-check-to-be-sensible.patch b/patches/api/0167-Change-the-reserved-channel-check-to-be-sensible.patch deleted file mode 100644 index fa3de628646c..000000000000 --- a/patches/api/0167-Change-the-reserved-channel-check-to-be-sensible.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoNotSpamPls <7570108+DoNotSpamPls@users.noreply.github.com> -Date: Tue, 23 Oct 2018 19:32:55 +0300 -Subject: [PATCH] Change the reserved channel check to be sensible - - -diff --git a/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java b/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java -index 1d061412cdafa28c6940c7433747ab1dabe23de1..6fda7f3aa68e76af64362e9afed70fc6a5e92986 100644 ---- a/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java -+++ b/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java -@@ -172,7 +172,7 @@ public class StandardMessenger implements Messenger { - public boolean isReservedChannel(@NotNull String channel) { - channel = validateAndCorrectChannel(channel); - -- return channel.contains("minecraft") && !channel.equals("minecraft:brand"); -+ return channel.equals("minecraft:register") || channel.equals("minecraft:unregister"); // Paper - } - - @Override -diff --git a/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java b/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java -index dce3d619a6f1791197e44277c2dee9eaf19ff56f..7e2335ed8acc692af1e70eddcf97ee7a56e30f68 100644 ---- a/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java -+++ b/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java -@@ -25,8 +25,8 @@ public class StandardMessengerTest { - assertTrue(messenger.isReservedChannel("minecraft:register")); - assertFalse(messenger.isReservedChannel("test:register")); - assertTrue(messenger.isReservedChannel("minecraft:unregister")); -- assertFalse(messenger.isReservedChannel("test:nregister")); -- assertTrue(messenger.isReservedChannel("minecraft:something")); -+ assertFalse(messenger.isReservedChannel("test:unregister")); // Paper - fix typo -+ assertFalse(messenger.isReservedChannel("minecraft:something")); // Paper - now less strict - assertFalse(messenger.isReservedChannel("minecraft:brand")); - } - diff --git a/patches/api/0167-Server-Tick-Events.patch b/patches/api/0167-Server-Tick-Events.patch new file mode 100644 index 000000000000..dd0e4b3defb5 --- /dev/null +++ b/patches/api/0167-Server-Tick-Events.patch @@ -0,0 +1,116 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 27 Mar 2019 21:58:55 -0400 +Subject: [PATCH] Server Tick Events + +Fires event at start and end of a server tick + +diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c879588693c930226049e60393f2f23aad1588b9 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java +@@ -0,0 +1,62 @@ ++package com.destroystokyo.paper.event.server; ++ ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when the server has finished ticking the main loop ++ */ ++@NullMarked ++public class ServerTickEndEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final int tickNumber; ++ private final double tickDuration; ++ private final long timeEnd; ++ ++ @ApiStatus.Internal ++ public ServerTickEndEvent(final int tickNumber, final double tickDuration, final long timeRemaining) { ++ this.tickNumber = tickNumber; ++ this.tickDuration = tickDuration; ++ this.timeEnd = System.nanoTime() + timeRemaining; ++ } ++ ++ /** ++ * @return What tick this was since start (first tick = 1) ++ */ ++ public int getTickNumber() { ++ return this.tickNumber; ++ } ++ ++ /** ++ * @return Time in milliseconds of how long this tick took ++ */ ++ public double getTickDuration() { ++ return this.tickDuration; ++ } ++ ++ /** ++ * Amount of nanoseconds remaining before the next tick should start. ++ *

      ++ * If this value is negative, then that means the server has exceeded the tick time limit and TPS has been lost. ++ *

      ++ * Method will continuously return the updated time remaining value. (return value is not static) ++ * ++ * @return Amount of nanoseconds remaining before the next tick should start ++ */ ++ public long getTimeRemaining() { ++ return this.timeEnd - System.nanoTime(); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..890153657ea5b756a8a3a038d6b53857e0d17fea +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java +@@ -0,0 +1,35 @@ ++package com.destroystokyo.paper.event.server; ++ ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public class ServerTickStartEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final int tickNumber; ++ ++ @ApiStatus.Internal ++ public ServerTickStartEvent(final int tickNumber) { ++ this.tickNumber = tickNumber; ++ } ++ ++ /** ++ * @return What tick this is going be since start (first tick = 1) ++ */ ++ public int getTickNumber() { ++ return this.tickNumber; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0168-Add-PlayerConnectionCloseEvent.patch b/patches/api/0168-Add-PlayerConnectionCloseEvent.patch deleted file mode 100644 index f1a017f4fbdd..000000000000 --- a/patches/api/0168-Add-PlayerConnectionCloseEvent.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 7 Oct 2018 12:05:06 -0700 -Subject: [PATCH] Add PlayerConnectionCloseEvent - -This event is invoked when a player has disconnected. It is guaranteed that, -if the server is in online-mode, that the provided uuid and username have been -validated. - -The event is invoked for players who have not yet logged into the world, whereas -PlayerQuitEvent is only invoked on players who have logged into the world. - -The event is invoked for players who have already logged into the world, -although whether or not the player exists in the world at the time of -firing is undefined. (That is, whether the plugin can retrieve a Player object -using the event parameters is undefined). However, it is guaranteed that this -event is invoked AFTER PlayerQuitEvent, if the player has already logged into -the world. - -This event is guaranteed to never fire unless AsyncPlayerPreLoginEvent has -been called beforehand, and this event may not be called in parallel with -AsyncPlayerPreLoginEvent for the same connection. - -Cancelling the AsyncPlayerPreLoginEvent guarantees the corresponding -PlayerConnectionCloseEvent is never called. - -The event may be invoked asynchronously or synchronously. As it stands, -it is never invoked asynchronously. However, plugins should check -Event#isAsynchronous to be future-proof. - -On purpose, the deprecated PlayerPreLoginEvent event is left out of the -API spec for this event. Plugins should not be using that event, and -how PlayerPreLoginEvent interacts with PlayerConnectionCloseEvent -is undefined. - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..12c1c6fe9dc8dc5f5faf6dcf99f6857219ef22b8 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java -@@ -0,0 +1,95 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+ -+import java.net.InetAddress; -+import java.util.UUID; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ *

      -+ * This event is invoked when a player has disconnected. It is guaranteed that, -+ * if the server is in online-mode, that the provided uuid and username have been -+ * validated. -+ *

      -+ * -+ *

      -+ * The event is invoked for players who have not yet logged into the world, whereas -+ * {@link org.bukkit.event.player.PlayerQuitEvent} is only invoked on players who have logged into the world. -+ *

      -+ * -+ *

      -+ * The event is invoked for players who have already logged into the world, -+ * although whether or not the player exists in the world at the time of -+ * firing is undefined. (That is, whether the plugin can retrieve a Player object -+ * using the event parameters is undefined). However, it is guaranteed that this -+ * event is invoked AFTER {@link org.bukkit.event.player.PlayerQuitEvent}, if the player has already logged into the world. -+ *

      -+ * -+ *

      -+ * This event is guaranteed to never fire unless {@link org.bukkit.event.player.AsyncPlayerPreLoginEvent} has -+ * been fired beforehand, and this event may not be called in parallel with -+ * {@link org.bukkit.event.player.AsyncPlayerPreLoginEvent} for the same connection. -+ *

      -+ * -+ *

      -+ * Cancelling the {@link org.bukkit.event.player.AsyncPlayerPreLoginEvent} guarantees the corresponding -+ * {@code PlayerConnectionCloseEvent} is never called. -+ *

      -+ * -+ *

      -+ * The event may be invoked asynchronously or synchronously. Plugins should check -+ * {@link Event#isAsynchronous()} and handle accordingly. -+ *

      -+ */ -+public class PlayerConnectionCloseEvent extends Event { -+ -+ private static final HandlerList HANDLERS = new HandlerList(); -+ -+ @NotNull private final UUID playerUniqueId; -+ @NotNull private final String playerName; -+ @NotNull private final InetAddress ipAddress; -+ -+ public PlayerConnectionCloseEvent(@NotNull final UUID playerUniqueId, @NotNull final String playerName, @NotNull final InetAddress ipAddress, final boolean async) { -+ super(async); -+ this.playerUniqueId = playerUniqueId; -+ this.playerName = playerName; -+ this.ipAddress = ipAddress; -+ } -+ -+ /** -+ * Returns the {@code UUID} of the player disconnecting. -+ */ -+ @NotNull -+ public UUID getPlayerUniqueId() { -+ return this.playerUniqueId; -+ } -+ -+ /** -+ * Returns the name of the player disconnecting. -+ */ -+ @NotNull -+ public String getPlayerName() { -+ return this.playerName; -+ } -+ -+ /** -+ * Returns the player's IP address. -+ */ -+ @NotNull -+ public InetAddress getIpAddress() { -+ return this.ipAddress; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLERS; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLERS; -+ } -+} diff --git a/patches/api/0168-PlayerDeathEvent-getItemsToKeep.patch b/patches/api/0168-PlayerDeathEvent-getItemsToKeep.patch new file mode 100644 index 000000000000..4d28221bcdfe --- /dev/null +++ b/patches/api/0168-PlayerDeathEvent-getItemsToKeep.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 11 Mar 2013 20:04:34 -0400 +Subject: [PATCH] PlayerDeathEvent#getItemsToKeep + +Exposes a mutable array on items a player should keep on death + +Example Usage: https://gist.github.com/aikar/5bb202de6057a051a950ce1f29feb0b4 + +diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +index 76f00e386110f361549690d20dc0f73884a2fdda..edf14dac359e996f76e0af551a81a4dd8e48bd6c 100644 +--- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java ++++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +@@ -57,6 +57,41 @@ public class PlayerDeathEvent extends EntityDeathEvent { + this.deathMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(deathMessage); // Paper + } + ++ @Deprecated // Paper ++ // Paper start ++ private List itemsToKeep = new java.util.ArrayList<>(); ++ ++ /** ++ * A mutable collection to add items that the player should retain in their inventory on death (Similar to KeepInventory game rule) ++ * ++ * You MUST remove the item from the .getDrops() collection too or it will duplicate! ++ *
      {@code
      ++     *    {@literal @EventHandler(ignoreCancelled = true)}
      ++     *     public void onPlayerDeath(PlayerDeathEvent event) {
      ++     *         for (Iterator iterator = event.getDrops().iterator(); iterator.hasNext(); ) {
      ++     *             ItemStack drop = iterator.next();
      ++     *             List lore = drop.getLore();
      ++     *             if (lore != null && !lore.isEmpty()) {
      ++     *                 if (lore.get(0).contains("(SOULBOUND)")) {
      ++     *                     iterator.remove();
      ++     *                     event.getItemsToKeep().add(drop);
      ++     *                 }
      ++     *             }
      ++     *         }
      ++     *     }
      ++     * }
      ++ * ++ * Adding an item to this list that the player did not previously have will give them the item on death. ++ * An example case could be a "Note" that "You died at X/Y/Z coordinates" ++ * ++ * @return The list to hold items to keep ++ */ ++ @NotNull ++ public List getItemsToKeep() { ++ return itemsToKeep; ++ } ++ // Paper end ++ + @NotNull + @Override + public Player getEntity() { diff --git a/patches/api/0169-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch b/patches/api/0169-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch deleted file mode 100644 index 99524ae7c9a2..000000000000 --- a/patches/api/0169-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Wed, 2 Jan 2019 00:31:12 -0600 -Subject: [PATCH] Add APIs to replace OfflinePlayer#getLastPlayed - -Currently OfflinePlayer#getLastPlayed could more accurately be described -as "OfflinePlayer#getLastTimeTheirDataWasSaved". - -The API doc says it should return the last time the server "witnessed" -the player, whilst also saying it should return the last time they -logged in. The current implementation does neither. - -Given this interesting contradiction in the API documentation and the -current defacto implementation, I've elected to deprecate (with no -intent to remove) and replace it with two new methods, clearly named and -documented as to their purpose. - -diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java -index 9d774a10b9543e9293cb10ee9d7c9adebbfef34c..23e853bae0e051cd43deb9eb24c54e74a56d8ab0 100644 ---- a/src/main/java/org/bukkit/OfflinePlayer.java -+++ b/src/main/java/org/bukkit/OfflinePlayer.java -@@ -160,7 +160,9 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio - * UTC. - * - * @return Date of last log-in for this player, or 0 -+ * @deprecated The API contract is ambiguous and the implementation may or may not return the correct value given this API ambiguity. It is instead recommended use {@link #getLastLogin()} or {@link #getLastSeen()} depending on your needs. - */ -+ @Deprecated - public long getLastPlayed(); - - /** -@@ -178,6 +180,30 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio - */ - @Nullable - public Location getBedSpawnLocation(); -+ // Paper start -+ /** -+ * Gets the last date and time that this player logged into the server. -+ *

      -+ * If the player has never played before, this will return 0. Otherwise, -+ * it will be the amount of milliseconds since midnight, January 1, 1970 -+ * UTC. -+ * -+ * @return last login time -+ */ -+ public long getLastLogin(); -+ -+ /** -+ * Gets the last date and time that this player was seen on the server. -+ *

      -+ * If the player has never played before, this will return 0. If the -+ * player is currently online, this will return the current time. -+ * Otherwise it will be the amount of milliseconds since midnight, -+ * January 1, 1970 UTC. -+ * -+ * @return last seen time -+ */ -+ public long getLastSeen(); -+ // Paper end - - /** - * Increments the given statistic for this player. diff --git a/patches/api/0169-Add-Heightmap-API.patch b/patches/api/0169-Add-Heightmap-API.patch new file mode 100644 index 000000000000..a60fccf2adde --- /dev/null +++ b/patches/api/0169-Add-Heightmap-API.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sat, 1 Dec 2018 19:00:36 -0800 +Subject: [PATCH] Add Heightmap API + +Changed to use upstream's heightmap API - Machine_Maker + +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index fb4b6f0e908ffa50c3b2f8d04d9f3810898b8d5e..bdc065a486306236c7f0960718bea53bc0b0a9b6 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -649,6 +649,30 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + } + // Paper end - expand Location API + ++ // Paper start - Add heightmap api ++ /** ++ * Returns a copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ()) ++ * @return A copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ()) ++ * @throws NullPointerException if {{@link #getWorld()}} is {@code null} ++ */ ++ @NotNull ++ public Location toHighestLocation() { ++ return this.toHighestLocation(HeightMap.WORLD_SURFACE); ++ } ++ ++ /** ++ * Returns a copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ(), heightMap) ++ * @param heightMap The heightmap to use for finding the highest y location. ++ * @return A copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ(), heightMap) ++ */ ++ @NotNull ++ public Location toHighestLocation(@NotNull final HeightMap heightMap) { ++ final Location ret = this.clone(); ++ ret.setY(this.getWorld().getHighestBlockYAt(this, heightMap)); ++ return ret; ++ } ++ // Paper end - Add heightmap api ++ + // Paper start - Expand Explosions API + /** + * Creates explosion at this location with given power diff --git a/patches/api/0170-Add-ItemStack-Recipe-API-helper-methods.patch b/patches/api/0170-Add-ItemStack-Recipe-API-helper-methods.patch deleted file mode 100644 index cba58643e407..000000000000 --- a/patches/api/0170-Add-ItemStack-Recipe-API-helper-methods.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 28 Jan 2014 19:13:57 -0500 -Subject: [PATCH] Add ItemStack Recipe API helper methods - -Allows using ExactChoice Recipes with easier methodss - -diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java -index ad2ab6e97ccf6900d19f8bfbe08181d4c7743a99..ecf8cd763ae600c11be6385ea6240e4d2c08abc9 100644 ---- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java -+++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java -@@ -144,6 +144,13 @@ public class ShapedRecipe implements Recipe, Keyed { - return this; - } - -+ // Paper start -+ @NotNull -+ public ShapedRecipe setIngredient(char key, @NotNull ItemStack item) { -+ return setIngredient(key, new RecipeChoice.ExactChoice(item)); -+ } -+ // Paper end -+ - /** - * Get a copy of the ingredients map. - * -diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java -index 75b47c608d0a902e4ea5f03c395667f47dec8980..ff5a0e378a7c1e0f89d81144629251dc61af6355 100644 ---- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java -+++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java -@@ -142,6 +142,40 @@ public class ShapelessRecipe implements Recipe, Keyed { - return this; - } - -+ // Paper start -+ @NotNull -+ public ShapelessRecipe addIngredient(@NotNull ItemStack item) { -+ return addIngredient(item.getAmount(), item); -+ } -+ -+ @NotNull -+ public ShapelessRecipe addIngredient(int count, @NotNull ItemStack item) { -+ Preconditions.checkArgument(ingredients.size() + count <= 9, "Shapeless recipes cannot have more than 9 ingredients"); -+ while (count-- > 0) { -+ ingredients.add(new RecipeChoice.ExactChoice(item)); -+ } -+ return this; -+ } -+ -+ @NotNull -+ public ShapelessRecipe removeIngredient(@NotNull ItemStack item) { -+ return removeIngredient(1, item); -+ } -+ -+ @NotNull -+ public ShapelessRecipe removeIngredient(int count, @NotNull ItemStack item) { -+ Iterator iterator = ingredients.iterator(); -+ while (count > 0 && iterator.hasNext()) { -+ ItemStack stack = iterator.next().getItemStack(); -+ if (stack.equals(item)) { -+ iterator.remove(); -+ count--; -+ } -+ } -+ return this; -+ } -+ // Paper end -+ - /** - * Removes an ingredient from the list. - * diff --git a/patches/api/0170-Mob-Spawner-API-Enhancements.patch b/patches/api/0170-Mob-Spawner-API-Enhancements.patch new file mode 100644 index 000000000000..c7d05493f661 --- /dev/null +++ b/patches/api/0170-Mob-Spawner-API-Enhancements.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 19 Apr 2019 12:41:19 -0500 +Subject: [PATCH] Mob Spawner API Enhancements + + +diff --git a/src/main/java/org/bukkit/spawner/Spawner.java b/src/main/java/org/bukkit/spawner/Spawner.java +index c595c44698cd3c6379e83248ed3a05e325cadc7f..640767bd16a5406b1f7093c1f6bb7dbc46051b5a 100644 +--- a/src/main/java/org/bukkit/spawner/Spawner.java ++++ b/src/main/java/org/bukkit/spawner/Spawner.java +@@ -107,4 +107,30 @@ public interface Spawner extends BaseSpawner { + * @param maxNearbyEntities the maximum number of nearby, similar, entities + */ + public void setMaxNearbyEntities(int maxNearbyEntities); ++ ++ // Paper start ++ /** ++ * Check if spawner is activated (a player is close enough) ++ * ++ * @return True if a player is close enough to activate it ++ */ ++ public boolean isActivated(); ++ ++ /** ++ * Resets the spawn delay timer within the min/max range ++ */ ++ public void resetTimer(); ++ ++ /** ++ * Sets the {@link EntityType} to {@link EntityType#ITEM} and sets the data to the given ++ * {@link org.bukkit.inventory.ItemStack ItemStack}. ++ *

      ++ * {@link #setSpawnCount(int)} does not dictate the amount of items in the stack spawned, but rather how many ++ * stacks should be spawned. ++ * ++ * @param itemStack The item to spawn. Must not {@link org.bukkit.Material#isAir be air}. ++ * @see #setSpawnedType(EntityType) ++ */ ++ void setSpawnedItem(org.bukkit.inventory.@org.jetbrains.annotations.NotNull ItemStack itemStack); ++ // Paper end + } diff --git a/patches/api/0171-Add-BlockSoundGroup-interface.patch b/patches/api/0171-Add-BlockSoundGroup-interface.patch new file mode 100644 index 000000000000..b66d3fc6f7ab --- /dev/null +++ b/patches/api/0171-Add-BlockSoundGroup-interface.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: simpleauthority +Date: Tue, 28 May 2019 03:41:28 -0700 +Subject: [PATCH] Add BlockSoundGroup interface + +This PR adds the getSoundGroup() method in Block which returns a BlockSoundGroup + +diff --git a/src/main/java/com/destroystokyo/paper/block/BlockSoundGroup.java b/src/main/java/com/destroystokyo/paper/block/BlockSoundGroup.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2bde2b7c960b321d0c1396212858c780280f0520 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/block/BlockSoundGroup.java +@@ -0,0 +1,64 @@ ++package com.destroystokyo.paper.block; ++ ++import org.bukkit.Sound; ++import org.bukkit.block.Block; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents the sounds that a {@link Block} makes in certain situations ++ *

      ++ * The sound group includes break, step, place, hit, and fall sounds. ++ * @deprecated use {@link org.bukkit.SoundGroup} ++ */ ++@Deprecated(forRemoval = true, since = "1.18.2") ++public interface BlockSoundGroup { ++ /** ++ * Gets the sound that plays when breaking this block ++ * ++ * @return The break sound ++ * @deprecated use {@link org.bukkit.SoundGroup#getBreakSound()} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ Sound getBreakSound(); ++ ++ /** ++ * Gets the sound that plays when stepping on this block ++ * ++ * @return The step sound ++ * @deprecated use {@link org.bukkit.SoundGroup#getStepSound()} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ Sound getStepSound(); ++ ++ /** ++ * Gets the sound that plays when placing this block ++ * ++ * @return The place sound ++ * @deprecated use {@link org.bukkit.SoundGroup#getPlaceSound()} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ Sound getPlaceSound(); ++ ++ /** ++ * Gets the sound that plays when hitting this block ++ * ++ * @return The hit sound ++ * @deprecated use {@link org.bukkit.SoundGroup#getHitSound()} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ Sound getHitSound(); ++ ++ /** ++ * Gets the sound that plays when this block falls ++ * ++ * @return The fall sound ++ * @deprecated use {@link org.bukkit.SoundGroup#getFallSound()} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ Sound getFallSound(); ++} +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index 2566c7bb9e770483abdd3398af13179dc747b682..c278e7a3da5989b0f41c571e3cb7579289795e95 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -616,4 +616,25 @@ public interface Block extends Metadatable, Translatable { + * @return true if the block data can be placed here + */ + boolean canPlace(@NotNull BlockData data); ++ ++ // Paper start ++ /** ++ * Gets the {@link com.destroystokyo.paper.block.BlockSoundGroup} for this block. ++ *

      ++ * This object contains the block, step, place, hit, and fall sounds. ++ * ++ * @return the sound group for this block ++ * @deprecated use {@link #getBlockSoundGroup()} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.18.2") ++ com.destroystokyo.paper.block.BlockSoundGroup getSoundGroup(); ++ ++ /** ++ * Gets the {@link org.bukkit.SoundGroup} for this block. ++ * ++ * @return the sound group for this block ++ */ ++ @NotNull org.bukkit.SoundGroup getBlockSoundGroup(); ++ // Paper end + } diff --git a/patches/api/0171-BlockDestroyEvent.patch b/patches/api/0171-BlockDestroyEvent.patch deleted file mode 100644 index 4ad73d8ef143..000000000000 --- a/patches/api/0171-BlockDestroyEvent.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 6 Feb 2019 00:19:33 -0500 -Subject: [PATCH] BlockDestroyEvent - -Adds an event for when the server is going to destroy a current block, -potentially causing it to drop. This event can be cancelled to avoid -the block destruction, such as preventing signs from popping when -floating in the air. - -This can replace many uses of BlockPhysicsEvent - -diff --git a/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java b/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..28255dc39eab5faf324d1fe556ab12daed527ff6 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java -@@ -0,0 +1,92 @@ -+package com.destroystokyo.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.block.data.BlockData; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired anytime the server intends to 'destroy' a block through some triggering reason. -+ * This does not fire anytime a block is set to air, but only with more direct triggers such -+ * as physics updates, pistons, Entities changing blocks, commands set to "Destroy". -+ * -+ * This event is associated with the game playing a sound effect at the block in question, when -+ * something can be described as "intend to destroy what is there", -+ * -+ * Events such as leaves decaying, pistons retracting (where the block is moving), does NOT fire this event. -+ * -+ */ -+public class BlockDestroyEvent extends BlockEvent implements Cancellable { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull private final BlockData newState; -+ private final boolean willDrop; -+ private boolean playEffect = true; -+ -+ private boolean cancelled = false; -+ -+ public BlockDestroyEvent(@NotNull Block block, @NotNull BlockData newState, boolean willDrop) { -+ super(block); -+ this.newState = newState; -+ this.willDrop = willDrop; -+ } -+ -+ /** -+ * @return The new state of this block (Air, or a Fluid type) -+ */ -+ @NotNull -+ public BlockData getNewState() { -+ return newState; -+ } -+ -+ /** -+ * @return If the server is going to drop the block in question with this destroy event -+ */ -+ public boolean willDrop() { -+ return this.willDrop; -+ } -+ -+ /** -+ * @return If the server is going to play the sound effect for this destruction -+ */ -+ public boolean playEffect() { -+ return this.playEffect; -+ } -+ -+ /** -+ * @param playEffect If the server should play the sound effect for this destruction -+ */ -+ public void setPlayEffect(boolean playEffect) { -+ this.playEffect = playEffect; -+ } -+ -+ /** -+ * @return If the event is cancelled, meaning the block will not be destroyed -+ */ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * If the event is cancelled, the block will remain in its previous state. -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0172-Add-WhitelistToggleEvent.patch b/patches/api/0172-Add-WhitelistToggleEvent.patch deleted file mode 100644 index 4bb54b5c9291..000000000000 --- a/patches/api/0172-Add-WhitelistToggleEvent.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Wed, 13 Mar 2019 20:04:43 +0200 -Subject: [PATCH] Add WhitelistToggleEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java b/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fdd5eedb2b7401439912a3a4343a920f32edc860 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/server/WhitelistToggleEvent.java -@@ -0,0 +1,40 @@ -+package com.destroystokyo.paper.event.server; -+ -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * This event is fired when whitelist is toggled -+ * -+ * @author Mark Vainomaa -+ */ -+public class WhitelistToggleEvent extends Event { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ private boolean enabled; -+ -+ public WhitelistToggleEvent(boolean enabled) { -+ this.enabled = enabled; -+ } -+ -+ /** -+ * Gets whether whitelist is going to be enabled or not -+ * -+ * @return Whether whitelist is going to be enabled or not -+ */ -+ public boolean isEnabled() { -+ return enabled; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0182-Amend-PlayerInteractAtEntityEvent-javadoc-for-ArmorS.patch b/patches/api/0172-Amend-PlayerInteractAtEntityEvent-javadoc-for-ArmorS.patch similarity index 100% rename from patches/api/0182-Amend-PlayerInteractAtEntityEvent-javadoc-for-ArmorS.patch rename to patches/api/0172-Amend-PlayerInteractAtEntityEvent-javadoc-for-ArmorS.patch diff --git a/patches/api/0173-Add-GS4-Query-event.patch b/patches/api/0173-Add-GS4-Query-event.patch deleted file mode 100644 index ffab49a92a53..000000000000 --- a/patches/api/0173-Add-GS4-Query-event.patch +++ /dev/null @@ -1,424 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Sun, 17 Mar 2019 21:46:27 +0200 -Subject: [PATCH] Add GS4 Query event - - -diff --git a/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..77a19995f6792a182c5a43d6714e7bda0f42df5b ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java -@@ -0,0 +1,412 @@ -+package com.destroystokyo.paper.event.server; -+ -+import com.google.common.base.Preconditions; -+import com.google.common.collect.ImmutableList; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+import java.net.InetAddress; -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Collection; -+import java.util.List; -+ -+/** -+ * This event is fired if server is getting queried over GS4 Query protocol -+ * -+ * Adapted from Velocity's ProxyQueryEvent -+ * -+ * @author Mark Vainomaa -+ */ -+public final class GS4QueryEvent extends Event { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ private final QueryType queryType; -+ private final InetAddress querierAddress; -+ private QueryResponse response; -+ -+ public GS4QueryEvent(@NotNull QueryType queryType, @NotNull InetAddress querierAddress, @NotNull QueryResponse response) { -+ super(true); // should always be called async -+ this.queryType = Preconditions.checkNotNull(queryType, "queryType"); -+ this.querierAddress = Preconditions.checkNotNull(querierAddress, "querierAddress"); -+ this.response = Preconditions.checkNotNull(response, "response"); -+ } -+ -+ /** -+ * Get query type -+ * @return query type -+ */ -+ @NotNull -+ public QueryType getQueryType() { -+ return queryType; -+ } -+ -+ /** -+ * Get querier address -+ * @return querier address -+ */ -+ @NotNull -+ public InetAddress getQuerierAddress() { -+ return querierAddress; -+ } -+ -+ /** -+ * Get query response -+ * @return query response -+ */ -+ @NotNull -+ public QueryResponse getResponse() { -+ return response; -+ } -+ -+ /** -+ * Set query response -+ * @param response query response -+ */ -+ public void setResponse(@NotNull QueryResponse response) { -+ this.response = Preconditions.checkNotNull(response, "response"); -+ } -+ -+ @Override -+ public String toString() { -+ return "GS4QueryEvent{" + -+ "queryType=" + queryType + -+ ", querierAddress=" + querierAddress + -+ ", response=" + response + -+ '}'; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ /** -+ * The type of query -+ */ -+ public enum QueryType { -+ /** -+ * Basic query asks only a subset of information, such as motd, game type (hardcoded to

      MINECRAFT
      ), map, -+ * current players, max players, server port and server motd -+ */ -+ BASIC, -+ -+ /** -+ * Full query asks pretty much everything present on this event (only hardcoded values cannot be modified here). -+ */ -+ FULL -+ ; -+ } -+ -+ public final static class QueryResponse { -+ private final String motd; -+ private final String gameVersion; -+ private final String map; -+ private final int currentPlayers; -+ private final int maxPlayers; -+ private final String hostname; -+ private final int port; -+ private final Collection players; -+ private final String serverVersion; -+ private final Collection plugins; -+ -+ private QueryResponse(String motd, String gameVersion, String map, int currentPlayers, int maxPlayers, String hostname, int port, Collection players, String serverVersion, Collection plugins) { -+ this.motd = motd; -+ this.gameVersion = gameVersion; -+ this.map = map; -+ this.currentPlayers = currentPlayers; -+ this.maxPlayers = maxPlayers; -+ this.hostname = hostname; -+ this.port = port; -+ this.players = players; -+ this.serverVersion = serverVersion; -+ this.plugins = plugins; -+ } -+ -+ /** -+ * Get motd which will be used to reply to the query. By default it is {@link org.bukkit.Server#getMotd()}. -+ * @return motd -+ */ -+ @NotNull -+ public String getMotd() { -+ return motd; -+ } -+ -+ /** -+ * Get game version which will be used to reply to the query. By default supported Minecraft versions range is sent. -+ * @return game version -+ */ -+ @NotNull -+ public String getGameVersion() { -+ return gameVersion; -+ } -+ -+ /** -+ * Get map name which will be used to reply to the query. By default {@code world} is sent. -+ * @return map name -+ */ -+ @NotNull -+ public String getMap() { -+ return map; -+ } -+ -+ /** -+ * Get current online player count which will be used to reply to the query. -+ * @return online player count -+ */ -+ public int getCurrentPlayers() { -+ return currentPlayers; -+ } -+ -+ /** -+ * Get max player count which will be used to reply to the query. -+ * @return max player count -+ */ -+ public int getMaxPlayers() { -+ return maxPlayers; -+ } -+ -+ /** -+ * Get server (public facing) hostname -+ * @return server hostname -+ */ -+ @NotNull -+ public String getHostname() { -+ return hostname; -+ } -+ -+ /** -+ * Get server (public facing) port -+ * @return server port -+ */ -+ public int getPort() { -+ return port; -+ } -+ -+ /** -+ * Get collection of players which will be used to reply to the query. -+ * @return collection of players -+ */ -+ @NotNull -+ public Collection getPlayers() { -+ return players; -+ } -+ -+ /** -+ * Get server software (name and version) which will be used to reply to the query. -+ * @return server software -+ */ -+ @NotNull -+ public String getServerVersion() { -+ return serverVersion; -+ } -+ -+ /** -+ * Get list of plugins which will be used to reply to the query. -+ * @return collection of plugins -+ */ -+ @NotNull -+ public Collection getPlugins() { -+ return plugins; -+ } -+ -+ -+ /** -+ * Creates a new {@link Builder} instance from data represented by this response -+ * @return {@link QueryResponse} builder -+ */ -+ @NotNull -+ public Builder toBuilder() { -+ return QueryResponse.builder() -+ .motd(getMotd()) -+ .gameVersion(getGameVersion()) -+ .map(getMap()) -+ .currentPlayers(getCurrentPlayers()) -+ .maxPlayers(getMaxPlayers()) -+ .hostname(getHostname()) -+ .port(getPort()) -+ .players(getPlayers()) -+ .serverVersion(getServerVersion()) -+ .plugins(getPlugins()); -+ } -+ -+ /** -+ * Creates a new {@link Builder} instance -+ * @return {@link QueryResponse} builder -+ */ -+ @NotNull -+ public static Builder builder() { -+ return new Builder(); -+ } -+ -+ /** -+ * A builder for {@link QueryResponse} objects. -+ */ -+ public static final class Builder { -+ private String motd; -+ private String gameVersion; -+ private String map; -+ private String hostname; -+ private String serverVersion; -+ -+ private int currentPlayers; -+ private int maxPlayers; -+ private int port; -+ -+ private List players = new ArrayList<>(); -+ private List plugins = new ArrayList<>(); -+ -+ private Builder() {} -+ -+ @NotNull -+ public Builder motd(@NotNull String motd) { -+ this.motd = Preconditions.checkNotNull(motd, "motd"); -+ return this; -+ } -+ -+ @NotNull -+ public Builder gameVersion(@NotNull String gameVersion) { -+ this.gameVersion = Preconditions.checkNotNull(gameVersion, "gameVersion"); -+ return this; -+ } -+ -+ @NotNull -+ public Builder map(@NotNull String map) { -+ this.map = Preconditions.checkNotNull(map, "map"); -+ return this; -+ } -+ -+ @NotNull -+ public Builder currentPlayers(int currentPlayers) { -+ Preconditions.checkArgument(currentPlayers >= 0, "currentPlayers cannot be negative"); -+ this.currentPlayers = currentPlayers; -+ return this; -+ } -+ -+ @NotNull -+ public Builder maxPlayers(int maxPlayers) { -+ Preconditions.checkArgument(maxPlayers >= 0, "maxPlayers cannot be negative"); -+ this.maxPlayers = maxPlayers; -+ return this; -+ } -+ -+ @NotNull -+ public Builder hostname(@NotNull String hostname) { -+ this.hostname = Preconditions.checkNotNull(hostname, "hostname"); -+ return this; -+ } -+ -+ @NotNull -+ public Builder port(int port) { -+ Preconditions.checkArgument(port >= 1 && port <= 65535, "port must be between 1-65535"); -+ this.port = port; -+ return this; -+ } -+ -+ @NotNull -+ public Builder players(@NotNull Collection players) { -+ this.players.addAll(Preconditions.checkNotNull(players, "players")); -+ return this; -+ } -+ -+ @NotNull -+ public Builder players(@NotNull String... players) { -+ this.players.addAll(Arrays.asList(Preconditions.checkNotNull(players, "players"))); -+ return this; -+ } -+ -+ @NotNull -+ public Builder clearPlayers() { -+ this.players.clear(); -+ return this; -+ } -+ -+ @NotNull -+ public Builder serverVersion(@NotNull String serverVersion) { -+ this.serverVersion = Preconditions.checkNotNull(serverVersion, "serverVersion"); -+ return this; -+ } -+ -+ @NotNull -+ public Builder plugins(@NotNull Collection plugins) { -+ this.plugins.addAll(Preconditions.checkNotNull(plugins, "plugins")); -+ return this; -+ } -+ -+ @NotNull -+ public Builder plugins(@NotNull PluginInformation... plugins) { -+ this.plugins.addAll(Arrays.asList(Preconditions.checkNotNull(plugins, "plugins"))); -+ return this; -+ } -+ -+ @NotNull -+ public Builder clearPlugins() { -+ this.plugins.clear(); -+ return this; -+ } -+ -+ /** -+ * Builds new {@link QueryResponse} with supplied data -+ * @return response -+ */ -+ @NotNull -+ public QueryResponse build() { -+ return new QueryResponse( -+ Preconditions.checkNotNull(motd, "motd"), -+ Preconditions.checkNotNull(gameVersion, "gameVersion"), -+ Preconditions.checkNotNull(map, "map"), -+ currentPlayers, -+ maxPlayers, -+ Preconditions.checkNotNull(hostname, "hostname"), -+ port, -+ ImmutableList.copyOf(players), -+ Preconditions.checkNotNull(serverVersion, "serverVersion"), -+ ImmutableList.copyOf(plugins) -+ ); -+ } -+ } -+ -+ /** -+ * Plugin information -+ */ -+ public static class PluginInformation { -+ private String name; -+ private String version; -+ -+ public PluginInformation(@NotNull String name, @NotNull String version) { -+ this.name = Preconditions.checkNotNull(name, "name"); -+ this.version = Preconditions.checkNotNull(version, "version"); -+ } -+ -+ @NotNull -+ public String getName() { -+ return name; -+ } -+ -+ public void setName(@NotNull String name) { -+ this.name = name; -+ } -+ -+ public void setVersion(@NotNull String version) { -+ this.version = version; -+ } -+ -+ @NotNull -+ public String getVersion() { -+ return version; -+ } -+ -+ @NotNull -+ public static PluginInformation of(@NotNull String name, @NotNull String version) { -+ return new PluginInformation(name, version); -+ } -+ } -+ } -+} diff --git a/patches/api/0173-Set-true-custom-payload-channel-size-limit.patch b/patches/api/0173-Set-true-custom-payload-channel-size-limit.patch new file mode 100644 index 000000000000..e64cd78834e7 --- /dev/null +++ b/patches/api/0173-Set-true-custom-payload-channel-size-limit.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Fri, 18 Oct 2019 17:39:05 +0100 +Subject: [PATCH] Set true custom payload channel size limit + +This fixes compatibility with some mods that are sending very long channel names. Also gives developers the ability to send longer channel names. + +diff --git a/src/main/java/org/bukkit/plugin/messaging/Messenger.java b/src/main/java/org/bukkit/plugin/messaging/Messenger.java +index c748a94523c8bc2140e1842ed7d8d462b52507d5..754fac6b2a45399efa34b06c6aa61f88c19e3d2b 100644 +--- a/src/main/java/org/bukkit/plugin/messaging/Messenger.java ++++ b/src/main/java/org/bukkit/plugin/messaging/Messenger.java +@@ -24,7 +24,7 @@ public interface Messenger { + /** + * Represents the largest size that a Plugin Channel may be. + */ +- public static final int MAX_CHANNEL_SIZE = 64; ++ public static final int MAX_CHANNEL_SIZE = Integer.getInteger("paper.maxCustomChannelName", java.lang.Short.MAX_VALUE); // Paper - set true max channel size + + /** + * Checks if the specified channel is a reserved name. diff --git a/patches/api/0174-Add-PlayerPostRespawnEvent.patch b/patches/api/0174-Add-PlayerPostRespawnEvent.patch deleted file mode 100644 index 004d74e96dbd..000000000000 --- a/patches/api/0174-Add-PlayerPostRespawnEvent.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MisterVector -Date: Fri, 26 Oct 2018 21:33:13 -0700 -Subject: [PATCH] Add PlayerPostRespawnEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..31f34b54801f6699ce43355fa2a0a51f1ad0c997 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerPostRespawnEvent.java -@@ -0,0 +1,52 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.Location; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired after a player has respawned -+ */ -+public class PlayerPostRespawnEvent extends PlayerEvent { -+ private final static HandlerList handlers = new HandlerList(); -+ private final Location respawnedLocation; -+ private final boolean isBedSpawn; -+ -+ public PlayerPostRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnedLocation, final boolean isBedSpawn) { -+ super(respawnPlayer); -+ this.respawnedLocation = respawnedLocation; -+ this.isBedSpawn = isBedSpawn; -+ } -+ -+ /** -+ * Returns the location of the respawned player -+ * -+ * @return location of the respawned player -+ */ -+ @NotNull -+ public Location getRespawnedLocation() { -+ return respawnedLocation.clone(); -+ } -+ -+ /** -+ * Checks if the player respawned to their bed -+ * -+ * @return whether the player respawned to their bed -+ */ -+ public boolean isBedSpawn() { -+ return isBedSpawn; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java -index 7c2cec60cbaf199416496292f2264fa3864b499c..f5bdb5244c8d993c624f938c8fb7ccff74655d75 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java -@@ -8,6 +8,9 @@ import org.jetbrains.annotations.NotNull; - - /** - * Called when a player respawns. -+ *

      -+ * If changing player state, see {@link com.destroystokyo.paper.event.player.PlayerPostRespawnEvent} -+ * because the player is "reset" between this event and that event and some changes won't persist. - */ - public class PlayerRespawnEvent extends PlayerEvent { - private static final HandlerList handlers = new HandlerList(); diff --git a/patches/api/0174-Expose-the-internal-current-tick.patch b/patches/api/0174-Expose-the-internal-current-tick.patch new file mode 100644 index 000000000000..d68e63883e66 --- /dev/null +++ b/patches/api/0174-Expose-the-internal-current-tick.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 20 Apr 2019 19:47:29 -0500 +Subject: [PATCH] Expose the internal current tick + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 0d743a27e0955af7b1baee49ce7e62e993a0a8b8..f16f0a72a7b533106e1703197e370d67e13d77a3 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2552,6 +2552,10 @@ public final class Bukkit { + public static com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name) { + return server.createProfileExact(uuid, name); + } ++ ++ public static int getCurrentTick() { ++ return server.getCurrentTick(); ++ } + // Paper end + + @NotNull +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 03d6e69b1771b1aabc22d680d8123239f7863e20..b8f1ecb16e3e1d969873f99f3b029d9a12437bd9 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2221,5 +2221,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + @NotNull + com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name); ++ ++ /** ++ * Get the current internal server tick ++ * ++ * @return Current tick ++ */ ++ int getCurrentTick(); + // Paper end + } diff --git a/patches/api/0175-Entity-getEntitySpawnReason.patch b/patches/api/0175-Entity-getEntitySpawnReason.patch deleted file mode 100644 index ad78118bc345..000000000000 --- a/patches/api/0175-Entity-getEntitySpawnReason.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 24 Mar 2019 00:21:23 -0400 -Subject: [PATCH] Entity#getEntitySpawnReason - -Allows you to return the SpawnReason for why an Entity Spawned - -Pre existing entities will return NATURAL if it was a non -persistenting Living Entity, SPAWNER for spawners, -or DEFAULT since data was not stored. - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 7a05615ec7678338801bcae2ec9a029b13d323d2..634f3b5dd22bf439aaec7c3ecfb3477b66e994e8 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -727,5 +727,11 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - // TODO remove impl here - return getLocation().getChunk(); - } -+ -+ /** -+ * @return The {@link org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason} that spawned this entity. -+ */ -+ @NotNull -+ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason(); - // Paper end - } diff --git a/patches/api/0175-Improve-Block-breakNaturally-API.patch b/patches/api/0175-Improve-Block-breakNaturally-API.patch new file mode 100644 index 000000000000..1ce6e632a268 --- /dev/null +++ b/patches/api/0175-Improve-Block-breakNaturally-API.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 2 Jan 2020 12:25:16 -0600 +Subject: [PATCH] Improve Block#breakNaturally API + +Adds bool param to trigger world particle effects + +Adds bool param to trigger exp drops for blocks + +Co-authored-by: William Blake Galbreath + +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index c278e7a3da5989b0f41c571e3cb7579289795e95..4e79dc21824e4b1f286c344b0733057be27fb6c5 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -481,6 +481,52 @@ public interface Block extends Metadatable, Translatable { + */ + boolean breakNaturally(@Nullable ItemStack tool); + ++ // Paper start ++ /** ++ * Breaks the block and spawns item drops as if a player had broken it ++ * ++ * @param triggerEffect Play the block break particle effect and sound ++ * @return true if the block was destroyed ++ * @see #breakNaturally(boolean, boolean) to trigger exp drops ++ */ ++ default boolean breakNaturally(boolean triggerEffect) { ++ return this.breakNaturally(triggerEffect, false); ++ } ++ ++ /** ++ * Breaks the block and spawns item drops as if a player had broken it ++ * ++ * @param triggerEffect Play the block break particle effect and sound ++ * @param dropExperience drop exp if the block normally does so ++ * @return true if the block was destroyed ++ */ ++ boolean breakNaturally(boolean triggerEffect, boolean dropExperience); ++ ++ /** ++ * Breaks the block and spawns item drops as if a player had broken it ++ * with a specific tool ++ * ++ * @param tool The tool or item in hand used for digging ++ * @param triggerEffect Play the block break particle effect and sound ++ * @return true if the block was destroyed ++ * @see #breakNaturally(ItemStack, boolean, boolean) to trigger exp drops ++ */ ++ default boolean breakNaturally(@NotNull ItemStack tool, boolean triggerEffect) { ++ return this.breakNaturally(tool, triggerEffect, false); ++ } ++ ++ /** ++ * Breaks the block and spawns item drops as if a player had broken it ++ * with a specific tool ++ * ++ * @param tool The tool or item in hand used for digging ++ * @param triggerEffect Play the block break particle effect and sound ++ * @param dropExperience drop exp if the block normally does so ++ * @return true if the block was destroyed ++ */ ++ boolean breakNaturally(@NotNull ItemStack tool, boolean triggerEffect, boolean dropExperience); ++ // Paper end ++ + /** + * Simulate bone meal application to this block (if possible). + * diff --git a/patches/api/0176-Fix-Spigot-annotation-mistakes.patch b/patches/api/0176-Fix-Spigot-annotation-mistakes.patch deleted file mode 100644 index 77b6221d7468..000000000000 --- a/patches/api/0176-Fix-Spigot-annotation-mistakes.patch +++ /dev/null @@ -1,830 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 24 Mar 2019 18:39:01 -0400 -Subject: [PATCH] Fix Spigot annotation mistakes - -while some of these may of been true, they are extreme cases and cause -a ton of noise to plugin developers. - -These do not help plugin developers if they bring moise noise than value. - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 62ecce029f38bd6a3e07981887916bb54e0c62f9..5f684c9ac218f105efe77ef08cae4b759868b0ea 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -1197,10 +1197,8 @@ public final class Bukkit { - * @param name the name the player to retrieve - * @return an offline player - * @see #getOfflinePlayer(java.util.UUID) -- * @deprecated Persistent storage of users should be by UUID as names are no longer -- * unique past a single session. - */ -- @Deprecated -+ // @Deprecated // Paper - @NotNull - public static OfflinePlayer getOfflinePlayer(@NotNull String name) { - return server.getOfflinePlayer(name); -@@ -1749,7 +1747,7 @@ public final class Bukkit { - * - * @return the scoreboard manager or null if no worlds are loaded. - */ -- @Nullable -+ @NotNull // Paper - public static ScoreboardManager getScoreboardManager() { - return server.getScoreboardManager(); - } -diff --git a/src/main/java/org/bukkit/GrassSpecies.java b/src/main/java/org/bukkit/GrassSpecies.java -index f9c9ae463aacd593e3aa9caf037ea1e23d56c780..f8ae143acbf586d5279b44f7311ca97f3ae4ead2 100644 ---- a/src/main/java/org/bukkit/GrassSpecies.java -+++ b/src/main/java/org/bukkit/GrassSpecies.java -@@ -6,7 +6,9 @@ import org.jetbrains.annotations.Nullable; - - /** - * Represents the different types of grass. -+ * @deprecated use {@link org.bukkit.block.data.BlockData} - */ -+@Deprecated // Paper - public enum GrassSpecies { - - /** -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index 57cb548683f7b2972c998afd34176952426f8b47..d4c87bfed81b2d73919705912f59fab05c0ee61b 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -46,7 +46,7 @@ public class Location implements Cloneable, ConfigurationSerializable { - * @param y The y-coordinate of this new location - * @param z The z-coordinate of this new location - */ -- public Location(@Nullable final World world, final double x, final double y, final double z) { -+ public Location(@UndefinedNullability final World world, final double x, final double y, final double z) { // Paper - this(world, x, y, z, 0, 0); - } - -@@ -60,7 +60,7 @@ public class Location implements Cloneable, ConfigurationSerializable { - * @param yaw The absolute rotation on the x-plane, in degrees - * @param pitch The absolute rotation on the y-plane, in degrees - */ -- public Location(@Nullable final World world, final double x, final double y, final double z, final float yaw, final float pitch) { -+ public Location(@UndefinedNullability final World world, final double x, final double y, final double z, final float yaw, final float pitch) { // Paper - if (world != null) { - this.world = new WeakReference<>(world); - } -@@ -102,7 +102,7 @@ public class Location implements Cloneable, ConfigurationSerializable { - * @throws IllegalArgumentException when world is unloaded - * @see #isWorldLoaded() - */ -- @Nullable -+ @UndefinedNullability // Paper - public World getWorld() { - if (this.world == null) { - return null; -diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index e40766c56fea6daae9f84fbdeb0b3f533e28d0b7..80b79ffa10ce7eba30d1df4ffa0e928be42f445f 100644 ---- a/src/main/java/org/bukkit/Material.java -+++ b/src/main/java/org/bukkit/Material.java -@@ -4140,11 +4140,11 @@ public enum Material implements Keyed { - } - - /** -- * Do not use for any reason. -+ * Checks if this constant is a legacy material. - * - * @return legacy status - */ -- @Deprecated -+ // @Deprecated // Paper - this is useful, don't deprecate - public boolean isLegacy() { - return legacy; - } -@@ -4215,8 +4215,10 @@ public enum Material implements Keyed { - * Gets the MaterialData class associated with this Material - * - * @return MaterialData associated with this Material -+ * @deprecated use {@link #createBlockData()} - */ - @NotNull -+ @Deprecated // Paper - public Class getData() { - Preconditions.checkArgument(legacy, "Cannot get data class of Modern Material"); - return ctor.getDeclaringClass(); -diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java -index 01bcb3a1bdb5accdf844d0178cec3d25746b3eaa..236c9aea9ffc36269e5c32eacc9f1fd6bd039c88 100644 ---- a/src/main/java/org/bukkit/NamespacedKey.java -+++ b/src/main/java/org/bukkit/NamespacedKey.java -@@ -39,12 +39,14 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key, com.des - - /** - * Create a key in a specific namespace. -+ *

      -+ * For most plugin related code, you should prefer using the -+ * {@link NamespacedKey#NamespacedKey(Plugin, String)} constructor. - * - * @param namespace namespace - * @param key key -- * @deprecated should never be used by plugins, for internal use only!! -+ * @see #NamespacedKey(Plugin, String) - */ -- @Deprecated - public NamespacedKey(@NotNull String namespace, @NotNull String key) { - Preconditions.checkArgument(namespace != null && VALID_NAMESPACE.matcher(namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", namespace); - Preconditions.checkArgument(key != null && VALID_KEY.matcher(key).matches(), "Invalid key. Must be [a-z0-9/._-]: %s", key); -diff --git a/src/main/java/org/bukkit/NetherWartsState.java b/src/main/java/org/bukkit/NetherWartsState.java -index f43209cf7b752c26718c303ca8c3e1c7d9912ad3..f0094e6fb05e526736629ad3181c8d2c16ba6ca4 100644 ---- a/src/main/java/org/bukkit/NetherWartsState.java -+++ b/src/main/java/org/bukkit/NetherWartsState.java -@@ -1,5 +1,11 @@ - package org.bukkit; - -+// Paper start -+/** -+ * @deprecated use {@link org.bukkit.block.data.BlockData} and {@link org.bukkit.block.data.Ageable} -+ */ -+@Deprecated -+// Paper end - public enum NetherWartsState { - - /** -diff --git a/src/main/java/org/bukkit/SandstoneType.java b/src/main/java/org/bukkit/SandstoneType.java -index 6277451c3c6c551078c237cd767b6d70c4f585ea..10f5cfb1885833a1d2c1027c03974da45ab28e2f 100644 ---- a/src/main/java/org/bukkit/SandstoneType.java -+++ b/src/main/java/org/bukkit/SandstoneType.java -@@ -6,7 +6,9 @@ import org.jetbrains.annotations.Nullable; - - /** - * Represents the three different types of Sandstone -+ * @deprecated use {@link org.bukkit.block.data.BlockData} - */ -+@Deprecated // Paper - public enum SandstoneType { - CRACKED(0x0), - GLYPHED(0x1), -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 85a0de6277aff8a81c8e58b3b29b98d99b6b1fb9..1fecaed0b5774e3888bd1f5103828cc38f0265d9 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -998,10 +998,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * @param name the name the player to retrieve - * @return an offline player - * @see #getOfflinePlayer(java.util.UUID) -- * @deprecated Persistent storage of users should be by UUID as names are no longer -- * unique past a single session. - */ -- @Deprecated -+ // @Deprecated // Paper - @NotNull - public OfflinePlayer getOfflinePlayer(@NotNull String name); - -@@ -1467,7 +1465,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * - * @return the scoreboard manager or null if no worlds are loaded. - */ -- @Nullable -+ @NotNull // Paper - ScoreboardManager getScoreboardManager(); - - /** -diff --git a/src/main/java/org/bukkit/Vibration.java b/src/main/java/org/bukkit/Vibration.java -index 8d568d21fcbf706f55cda087bd7222ac60889c0a..209a302c3a2ed333780ed760314a6ed352fc0767 100644 ---- a/src/main/java/org/bukkit/Vibration.java -+++ b/src/main/java/org/bukkit/Vibration.java -@@ -13,6 +13,14 @@ public class Vibration { - private final Destination destination; - private final int arrivalTime; - -+ // Paper start -+ public Vibration(@NotNull Destination destination, @NotNull int arrivalTime) { -+ this.destination = destination; -+ this.arrivalTime = arrivalTime; -+ this.origin = new Location(null, 0, 0, 0); // Dummy origin because getter expects null -+ } -+ -+ @Deprecated(forRemoval = true) // Paper end - public Vibration(@NotNull Location origin, @NotNull Destination destination, @NotNull int arrivalTime) { - this.origin = origin; - this.destination = destination; -@@ -22,9 +30,11 @@ public class Vibration { - /** - * Get the origin of the vibration. - * -+ * @deprecated unused as of 1.19 - * @return origin - */ - @NotNull -+ @Deprecated(forRemoval = true) // Paper - public Location getOrigin() { - return origin; - } -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 8f7536e5ef73328cb69f7214956aac582a7d6f24..7358c9148853d4b5b35998094838156231497747 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -430,9 +430,8 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - * @param z Z-coordinate of the chunk - * @return Whether the chunk was actually refreshed - * -- * @deprecated This method is not guaranteed to work suitably across all client implementations. - */ -- @Deprecated -+ //@Deprecated // Paper - public boolean refreshChunk(int x, int z); - - /** -@@ -2145,8 +2144,10 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - * @return The spawned {@link FallingBlock} instance - * @throws IllegalArgumentException if {@link Location} or {@link - * MaterialData} are null or {@link Material} of the {@link MaterialData} is not a block -+ * @deprecated use {@link #spawnFallingBlock(Location, BlockData)} - */ - @NotNull -+ @Deprecated // Paper - public FallingBlock spawnFallingBlock(@NotNull Location location, @NotNull MaterialData data) throws IllegalArgumentException; - - /** -diff --git a/src/main/java/org/bukkit/block/BlockState.java b/src/main/java/org/bukkit/block/BlockState.java -index 631cbf2be51040eee00aa39a39c5ec4003f91843..3147e278eac674ed21d714bbe318b135c0a6b408 100644 ---- a/src/main/java/org/bukkit/block/BlockState.java -+++ b/src/main/java/org/bukkit/block/BlockState.java -@@ -35,8 +35,10 @@ public interface BlockState extends Metadatable { - * Gets the metadata for this block state. - * - * @return block specific metadata -+ * @deprecated use {@link #getBlockData()} - */ - @NotNull -+ @Deprecated // Paper - MaterialData getData(); - - /** -@@ -131,7 +133,9 @@ public interface BlockState extends Metadatable { - * Sets the metadata for this block state. - * - * @param data New block specific metadata -+ * @deprecated use {@link #setBlockData(BlockData)} - */ -+ @Deprecated // Paper - void setData(@NotNull MaterialData data); - - /** -diff --git a/src/main/java/org/bukkit/entity/Enderman.java b/src/main/java/org/bukkit/entity/Enderman.java -index 821c690f8a32918bdb284ffec4af98f411f76ccc..94f3a8c4bf8cf14263d34d866db66728e98dfdb0 100644 ---- a/src/main/java/org/bukkit/entity/Enderman.java -+++ b/src/main/java/org/bukkit/entity/Enderman.java -@@ -25,15 +25,19 @@ public interface Enderman extends Monster { - * Gets the id and data of the block that the Enderman is carrying. - * - * @return MaterialData containing the id and data of the block -+ * @deprecated use {@link #getCarriedBlock()} - */ - @NotNull -+ @Deprecated // Paper - public MaterialData getCarriedMaterial(); - - /** - * Sets the id and data of the block that the Enderman is carrying. - * - * @param material data to set the carried block to -+ * @deprecated use {@link #setCarriedBlock(BlockData)} - */ -+ @Deprecated // Paper - public void setCarriedMaterial(@NotNull MaterialData material); - - /** -diff --git a/src/main/java/org/bukkit/entity/LingeringPotion.java b/src/main/java/org/bukkit/entity/LingeringPotion.java -index f124b35ec76e6cb6a1a0dc464005087043c3efd0..f50aaddf8582be55fd4860ad374d8f2206991897 100644 ---- a/src/main/java/org/bukkit/entity/LingeringPotion.java -+++ b/src/main/java/org/bukkit/entity/LingeringPotion.java -@@ -3,6 +3,8 @@ package org.bukkit.entity; - /** - * Represents a thrown lingering potion bottle - * -- * @deprecated lingering status depends on only on the potion item. -+ * @deprecated should not be used for anything, use {@link ThrownPotion} and -+ * set the potion via the methods there. - */ -+@Deprecated(forRemoval = true) // Paper - public interface LingeringPotion extends ThrownPotion { } -diff --git a/src/main/java/org/bukkit/entity/Minecart.java b/src/main/java/org/bukkit/entity/Minecart.java -index 95c79c5fa0c4e30201f887da6467ce5f81c8a255..7f9c4d4b430a3f0276461346ff2621bacf864075 100644 ---- a/src/main/java/org/bukkit/entity/Minecart.java -+++ b/src/main/java/org/bukkit/entity/Minecart.java -@@ -101,7 +101,9 @@ public interface Minecart extends Vehicle { - * Passing a null value will set the minecart to have no display block. - * - * @param material the material to set as display block. -+ * @deprecated use {@link #setDisplayBlockData(BlockData)} - */ -+ @Deprecated // Paper - public void setDisplayBlock(@Nullable MaterialData material); - - /** -@@ -109,8 +111,10 @@ public interface Minecart extends Vehicle { - * This function will return the type AIR if none is set. - * - * @return the block displayed by this minecart. -+ * @deprecated use {@link #getDisplayBlockData()} - */ - @NotNull -+ @Deprecated // Paper - public MaterialData getDisplayBlock(); - - /** -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index f218b1dd0b0ae97a6ccc0f88adcde7cc167432a9..ed2f50647df598a4f289736dcc524281910d1931 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -1368,9 +1368,8 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * - * @param plugin Plugin that wants to hide the entity - * @param entity Entity to hide -- * @deprecated draft API - */ -- @Deprecated -+ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - public void hideEntity(@NotNull Plugin plugin, @NotNull Entity entity); - - /** -@@ -1380,9 +1379,8 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * - * @param plugin Plugin that wants to show the entity - * @param entity Entity to show -- * @deprecated draft API - */ -- @Deprecated -+ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - public void showEntity(@NotNull Plugin plugin, @NotNull Entity entity); - - /** -@@ -1391,9 +1389,8 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @param entity Entity to check - * @return True if the provided entity is not being hidden from this - * player -- * @deprecated draft API - */ -- @Deprecated -+ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - public boolean canSee(@NotNull Entity entity); - - /** -diff --git a/src/main/java/org/bukkit/entity/Projectile.java b/src/main/java/org/bukkit/entity/Projectile.java -index c854860c13912f9a8707eb825cca23763d1323a6..a523fca4baab447181ef91df67fa69b24e010149 100644 ---- a/src/main/java/org/bukkit/entity/Projectile.java -+++ b/src/main/java/org/bukkit/entity/Projectile.java -@@ -29,7 +29,9 @@ public interface Projectile extends Entity { - * If a small fireball does not bounce it will set the target on fire. - * - * @return true if it should bounce. -+ * @deprecated Does not do anything - */ -+ @Deprecated(forRemoval = true) // Paper - public boolean doesBounce(); - - /** -@@ -37,6 +39,8 @@ public interface Projectile extends Entity { - * something. - * - * @param doesBounce whether or not it should bounce. -+ * @deprecated Does not do anything - */ -+ @Deprecated(forRemoval = true) // Paper - public void setBounce(boolean doesBounce); - } -diff --git a/src/main/java/org/bukkit/entity/SplashPotion.java b/src/main/java/org/bukkit/entity/SplashPotion.java -index 9cb08fe7201a9f91e88c7b1ee22c17889a7bf1c3..c0fcfccdf476106b48e626a099658c04244ebff8 100644 ---- a/src/main/java/org/bukkit/entity/SplashPotion.java -+++ b/src/main/java/org/bukkit/entity/SplashPotion.java -@@ -3,7 +3,8 @@ package org.bukkit.entity; - /** - * Represents a thrown splash potion bottle - * -- * @deprecated splash status depends on only on the potion item. -+ * @deprecated should not be used for anything, use {@link ThrownPotion} and -+ * set the potion via the methods there. - */ --@Deprecated -+@Deprecated(forRemoval = true) // Paper - public interface SplashPotion extends ThrownPotion { } -diff --git a/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java b/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java -index 2ff1b1308571d8f8056d3359e8a8ba4a589c3726..8eb6f4090578d9e1b12aff813840108fdeece730 100644 ---- a/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java -+++ b/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java -@@ -23,7 +23,7 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab - private boolean cancelled; - private final Player enchanter; - -- public PrepareItemEnchantEvent(@NotNull final Player enchanter, @NotNull InventoryView view, @NotNull final Block table, @NotNull final ItemStack item, @NotNull final EnchantmentOffer[] offers, final int bonus) { -+ public PrepareItemEnchantEvent(@NotNull final Player enchanter, @NotNull InventoryView view, @NotNull final Block table, @NotNull final ItemStack item, @org.jetbrains.annotations.Nullable final EnchantmentOffer @NotNull [] offers, final int bonus) { // Paper - offers can contain null values - super(view); - this.enchanter = enchanter; - this.table = table; -@@ -68,6 +68,7 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab - * @return experience level costs offered - * @deprecated Use {@link #getOffers()} instead of this method - */ -+ @Deprecated // Paper - @NotNull - public int[] getExpLevelCostsOffered() { - int[] levelOffers = new int[offers.length]; -@@ -85,8 +86,7 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab - * - * @return list of available enchantment offers - */ -- @NotNull -- public EnchantmentOffer[] getOffers() { -+ public @org.jetbrains.annotations.Nullable EnchantmentOffer @NotNull [] getOffers() { // Paper offers can contain null values - return offers; - } - -diff --git a/src/main/java/org/bukkit/event/player/PlayerHideEntityEvent.java b/src/main/java/org/bukkit/event/player/PlayerHideEntityEvent.java -index d8a73cd22268e90eb438f522b9019f826f343275..78869fdb9cf4c541dff7d67b51866914987abf18 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerHideEntityEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerHideEntityEvent.java -@@ -15,9 +15,8 @@ import org.jetbrains.annotations.NotNull; - * This event is called regardless of if the entity was within tracking range. - * - * @see Player#hideEntity(org.bukkit.plugin.Plugin, org.bukkit.entity.Entity) -- * @deprecated draft API - */ --@Deprecated -+@org.jetbrains.annotations.ApiStatus.Experimental // Paper - @Warning(false) - public class PlayerHideEntityEvent extends PlayerEvent { - -diff --git a/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java b/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java -index 1b2267f4e8ebded198773ec80e2bff2c861c7084..1a58734d919fae247eeb85dd785fd59990856505 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerMoveEvent.java -@@ -78,7 +78,7 @@ public class PlayerMoveEvent extends PlayerEvent implements Cancellable { - * - * @return Location the player moved to - */ -- @Nullable -+ @NotNull // Paper - public Location getTo() { - return to; - } -diff --git a/src/main/java/org/bukkit/event/player/PlayerShowEntityEvent.java b/src/main/java/org/bukkit/event/player/PlayerShowEntityEvent.java -index 5408a8c123942a56ef11597ae6cdb77e14f741e3..29bb84145be18ef9162abdfc8820f2b3f7fd0db5 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerShowEntityEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerShowEntityEvent.java -@@ -16,9 +16,8 @@ import org.jetbrains.annotations.NotNull; - * range. - * - * @see Player#showEntity(org.bukkit.plugin.Plugin, org.bukkit.entity.Entity) -- * @deprecated draft API - */ --@Deprecated -+@org.jetbrains.annotations.ApiStatus.Experimental // Paper - @Warning(false) - public class PlayerShowEntityEvent extends PlayerEvent { - -diff --git a/src/main/java/org/bukkit/generator/ChunkGenerator.java b/src/main/java/org/bukkit/generator/ChunkGenerator.java -index 4c9a64ace0d0f9f83d31ea75dabdf4666d48461a..e70e6949a9d5a5a37f0c92e139071d4060548e96 100644 ---- a/src/main/java/org/bukkit/generator/ChunkGenerator.java -+++ b/src/main/java/org/bukkit/generator/ChunkGenerator.java -@@ -515,7 +515,9 @@ public abstract class ChunkGenerator { - * @param y the y location in the chunk from minHeight (inclusive) - maxHeight (exclusive) - * @param z the z location in the chunk from 0-15 inclusive - * @param material the type to set the block to -+ * @deprecated use {@link #setBlock(int, int, int, BlockData)} - */ -+ @Deprecated // Paper - public void setBlock(int x, int y, int z, @NotNull MaterialData material); - - /** -@@ -559,7 +561,9 @@ public abstract class ChunkGenerator { - * @param yMax maximum y location (exclusive) in the chunk to set - * @param zMax maximum z location (exclusive) in the chunk to set - * @param material the type to set the blocks to -+ * @deprecated use {@link #setRegion(int, int, int, int, int, int, BlockData)} - */ -+ @Deprecated // Paper - public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, @NotNull MaterialData material); - - /** -@@ -600,8 +604,10 @@ public abstract class ChunkGenerator { - * @param y the y location in the chunk from minHeight (inclusive) - maxHeight (exclusive) - * @param z the z location in the chunk from 0-15 inclusive - * @return the type and data of the block or the MaterialData for air if x, y or z are outside the chunk's bounds -+ * @deprecated use {@link #getBlockData(int, int, int)} - */ - @NotNull -+ @Deprecated // Paper - public MaterialData getTypeAndData(int x, int y, int z); - - /** -diff --git a/src/main/java/org/bukkit/inventory/CraftingInventory.java b/src/main/java/org/bukkit/inventory/CraftingInventory.java -index df81bac9ecff697f98941e5c8490e10391e90090..a32977ba3ba60a1c9aee6e469d5d6cd1887c55a2 100644 ---- a/src/main/java/org/bukkit/inventory/CraftingInventory.java -+++ b/src/main/java/org/bukkit/inventory/CraftingInventory.java -@@ -21,8 +21,7 @@ public interface CraftingInventory extends Inventory { - * - * @return The contents. Individual entries may be null. - */ -- @NotNull -- ItemStack[] getMatrix(); -+ @Nullable ItemStack @NotNull [] getMatrix(); // Paper - make array elements nullable instead array - - /** - * Set the item in the result slot of the crafting inventory. -@@ -38,7 +37,7 @@ public interface CraftingInventory extends Inventory { - * @throws IllegalArgumentException if the length of contents is greater - * than the size of the crafting matrix. - */ -- void setMatrix(@NotNull ItemStack[] contents); -+ void setMatrix(@Nullable ItemStack @NotNull [] contents); // Paper - make array elements nullable instead array - - /** - * Get the current recipe formed on the crafting inventory, if any. -diff --git a/src/main/java/org/bukkit/inventory/EntityEquipment.java b/src/main/java/org/bukkit/inventory/EntityEquipment.java -index a91fa5386afd7a1137adb921ad5adb798604772f..42f76751ec414648ee719c341d471d947bf85be6 100644 ---- a/src/main/java/org/bukkit/inventory/EntityEquipment.java -+++ b/src/main/java/org/bukkit/inventory/EntityEquipment.java -@@ -511,6 +511,6 @@ public interface EntityEquipment { - * - * @return the entity this EntityEquipment belongs to - */ -- @Nullable -+ @NotNull // Paper - Entity getHolder(); - } -diff --git a/src/main/java/org/bukkit/inventory/FurnaceRecipe.java b/src/main/java/org/bukkit/inventory/FurnaceRecipe.java -index 1d442dc16cbb0fed21714d47007f3f11e30c57d4..af8f7b88edf0fa790edcf16356a030c4834f531e 100644 ---- a/src/main/java/org/bukkit/inventory/FurnaceRecipe.java -+++ b/src/main/java/org/bukkit/inventory/FurnaceRecipe.java -@@ -67,8 +67,10 @@ public class FurnaceRecipe extends CookingRecipe { - * - * @param input The input material. - * @return The changed recipe, so you can chain calls. -+ * @deprecated use {@link #setInputChoice(RecipeChoice)} - */ - @NotNull -+ @Deprecated - public FurnaceRecipe setInput(@NotNull MaterialData input) { - return setInput(input.getItemType(), input.getData()); - } -diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/org/bukkit/inventory/Inventory.java -index 9c6a5bdac8c3ab682bbfae04ff24b76a62bc2883..875c401153349b0f2468525e54cf10ca86430087 100644 ---- a/src/main/java/org/bukkit/inventory/Inventory.java -+++ b/src/main/java/org/bukkit/inventory/Inventory.java -@@ -158,8 +158,7 @@ public interface Inventory extends Iterable { - * - * @return An array of ItemStacks from the inventory. Individual items may be null. - */ -- @NotNull -- public ItemStack[] getContents(); -+ public @Nullable ItemStack @NotNull [] getContents(); // Paper - make array elements nullable instead array - - /** - * Completely replaces the inventory's contents. Removes all existing -@@ -170,7 +169,7 @@ public interface Inventory extends Iterable { - * @throws IllegalArgumentException If the array has more items than the - * inventory. - */ -- public void setContents(@NotNull ItemStack[] items) throws IllegalArgumentException; -+ public void setContents(@Nullable ItemStack @NotNull [] items) throws IllegalArgumentException; // Paper - make array elements nullable instead array - - /** - * Return the contents from the section of the inventory where items can -@@ -183,8 +182,7 @@ public interface Inventory extends Iterable { - * - * @return inventory storage contents. Individual items may be null. - */ -- @NotNull -- public ItemStack[] getStorageContents(); -+ public @Nullable ItemStack @NotNull [] getStorageContents(); // Paper - make array elements nullable instead array - - /** - * Put the given ItemStacks into the storage slots -@@ -193,7 +191,7 @@ public interface Inventory extends Iterable { - * @throws IllegalArgumentException If the array has more items than the - * inventory. - */ -- public void setStorageContents(@NotNull ItemStack[] items) throws IllegalArgumentException; -+ public void setStorageContents(@Nullable ItemStack @NotNull [] items) throws IllegalArgumentException; // Paper - make array elements nullable instead array - - /** - * Checks if the inventory contains any ItemStacks with the given -diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java -index 66ffc658dba85942f179760dc6c50258e24ab903..50fe28b48d885c782278bdb53a0bbae303f4a32d 100644 ---- a/src/main/java/org/bukkit/inventory/ItemFactory.java -+++ b/src/main/java/org/bukkit/inventory/ItemFactory.java -@@ -26,7 +26,7 @@ public interface ItemFactory { - * @return a new ItemMeta that could be applied to an item stack of the - * specified material - */ -- @Nullable -+ @org.bukkit.UndefinedNullability // Paper - ItemMeta getItemMeta(@NotNull final Material material); - - /** -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 7559f75dcc6665fa3d19d6e53a141a214407d1c5..515f623b3b6e76dbf24ec1d204f7983adb100858 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -7,6 +7,7 @@ import java.util.List; // Paper - import java.util.Map; - import org.bukkit.Bukkit; - import org.bukkit.Material; -+import org.bukkit.UndefinedNullability; - import org.bukkit.Utility; - import org.bukkit.configuration.serialization.ConfigurationSerializable; - import org.bukkit.enchantments.Enchantment; -@@ -67,6 +68,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - * @param damage durability / damage - * @deprecated see {@link #setDurability(short)} - */ -+ @Deprecated // Paper - public ItemStack(@NotNull final Material type, final int amount, final short damage) { - this(type, amount, damage, null); - } -@@ -168,8 +170,10 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - * Gets the MaterialData for this stack of items - * - * @return MaterialData for this item -+ * @deprecated cast to {@link org.bukkit.inventory.meta.BlockDataMeta} and use {@link org.bukkit.inventory.meta.BlockDataMeta#getBlockData(Material)} - */ - @Nullable -+ @Deprecated // Paper - public MaterialData getData() { - Material mat = Bukkit.getUnsafe().toLegacy(getType()); - if (data == null && mat != null && mat.getData() != null) { -@@ -183,7 +187,9 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - * Sets the MaterialData for this stack of items - * - * @param data New MaterialData for this item -+ * @deprecated cast to {@link org.bukkit.inventory.meta.BlockDataMeta} and use {@link org.bukkit.inventory.meta.BlockDataMeta#setBlockData(org.bukkit.block.data.BlockData)} - */ -+ @Deprecated // Paper - public void setData(@Nullable MaterialData data) { - if (data == null) { - this.data = data; -@@ -545,7 +551,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - * - * @return a copy of the current ItemStack's ItemData - */ -- @Nullable -+ @UndefinedNullability // Paper - public ItemMeta getItemMeta() { - return this.meta == null ? Bukkit.getItemFactory().getItemMeta(this.type) : this.meta.clone(); - } -diff --git a/src/main/java/org/bukkit/inventory/PlayerInventory.java b/src/main/java/org/bukkit/inventory/PlayerInventory.java -index 5461f7fa75f5a065bb333b4a113640b5fe1e3825..c4d657727e508cb941320730a9d3aa5486712ef3 100644 ---- a/src/main/java/org/bukkit/inventory/PlayerInventory.java -+++ b/src/main/java/org/bukkit/inventory/PlayerInventory.java -@@ -14,8 +14,7 @@ public interface PlayerInventory extends Inventory { - * - * @return All the ItemStacks from the armor slots. Individual items can be null. - */ -- @NotNull -- public ItemStack[] getArmorContents(); -+ public @Nullable ItemStack @NotNull [] getArmorContents(); // Paper - make array elements nullable instead array - - /** - * Get all additional ItemStacks stored in this inventory. -@@ -26,8 +25,7 @@ public interface PlayerInventory extends Inventory { - * - * @return All additional ItemStacks. Individual items can be null. - */ -- @NotNull -- public ItemStack[] getExtraContents(); -+ public @Nullable ItemStack @NotNull [] getExtraContents(); // Paper - make array elements nullable instead array - - /** - * Return the ItemStack from the helmet slot -@@ -104,9 +102,9 @@ public interface PlayerInventory extends Inventory { - * - * @param slot the slot to get the ItemStack - * -- * @return the ItemStack in the given slot or null if there is not one -+ * @return the ItemStack in the given slot - */ -- @Nullable -+ @NotNull // Paper - public ItemStack getItem(@NotNull EquipmentSlot slot); - - /** -diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java -index ecf8cd763ae600c11be6385ea6240e4d2c08abc9..40e9040fec4e7d39aa1b0d75d183cf97aff44438 100644 ---- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java -+++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java -@@ -95,8 +95,10 @@ public class ShapedRecipe implements Recipe, Keyed { - * @param key The character that represents the ingredient in the shape. - * @param ingredient The ingredient. - * @return The changed recipe, so you can chain calls. -+ * @deprecated use {@link #setIngredient(char, RecipeChoice)} - */ - @NotNull -+ @Deprecated // Paper - public ShapedRecipe setIngredient(char key, @NotNull MaterialData ingredient) { - return setIngredient(key, ingredient.getItemType(), ingredient.getData()); - } -diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java -index ff5a0e378a7c1e0f89d81144629251dc61af6355..c6dba5bbca302237bb4abd2b7ef17c1281d74a29 100644 ---- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java -+++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java -@@ -54,8 +54,10 @@ public class ShapelessRecipe implements Recipe, Keyed { - * - * @param ingredient The ingredient to add. - * @return The changed recipe, so you can chain calls. -+ * @deprecated use {@link #addIngredient(RecipeChoice)} - */ - @NotNull -+ @Deprecated - public ShapelessRecipe addIngredient(@NotNull MaterialData ingredient) { - return addIngredient(1, ingredient); - } -@@ -91,8 +93,10 @@ public class ShapelessRecipe implements Recipe, Keyed { - * @param count How many to add (can't be more than 9!) - * @param ingredient The ingredient to add. - * @return The changed recipe, so you can chain calls. -+ * @deprecated use {@link #addIngredient(int, Material)} - */ - @NotNull -+ @Deprecated // Paper - public ShapelessRecipe addIngredient(int count, @NotNull MaterialData ingredient) { - return addIngredient(count, ingredient.getItemType(), ingredient.getData()); - } -@@ -209,8 +213,10 @@ public class ShapelessRecipe implements Recipe, Keyed { - * - * @param ingredient The ingredient to remove - * @return The changed recipe. -+ * @deprecated use {@link #removeIngredient(Material)} - */ - @NotNull -+ @Deprecated // Paper - public ShapelessRecipe removeIngredient(@NotNull MaterialData ingredient) { - return removeIngredient(ingredient.getItemType(), ingredient.getData()); - } -@@ -237,8 +243,10 @@ public class ShapelessRecipe implements Recipe, Keyed { - * @param count The number of copies to remove. - * @param ingredient The ingredient to remove. - * @return The changed recipe. -+ * @deprecated use {@link #removeIngredient(int, Material)} - */ - @NotNull -+ @Deprecated // Paper - public ShapelessRecipe removeIngredient(int count, @NotNull MaterialData ingredient) { - return removeIngredient(count, ingredient.getItemType(), ingredient.getData()); - } -diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -index 35009498aafd1bd36c493085127135fc8a5c36ec..1beedb446a9dd554d05d1d94dba8598e4b69eba6 100644 ---- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -+++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -@@ -74,8 +74,10 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - /** - * Checks for existence of a localized name. - * -+ * @deprecated Use {@link ItemMeta#displayName()} and check if it is instanceof a {@link net.kyori.adventure.text.TranslatableComponent}. - * @return true if this has a localized name - */ -+ @Deprecated // Paper - Deprecate old localized API - boolean hasLocalizedName(); - - /** -@@ -84,16 +86,20 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - * Plugins should check that hasLocalizedName() returns true - * before calling this method. - * -+ * @deprecated Use {@link ItemMeta#displayName()} and cast it to a {@link net.kyori.adventure.text.TranslatableComponent}. No longer used by the client. - * @return the localized name that is set - */ -+ @Deprecated // Paper - Deprecate old localized API - @NotNull - String getLocalizedName(); - - /** - * Sets the localized name. - * -+ * @deprecated Use {@link ItemMeta#displayName(Component)} with a {@link net.kyori.adventure.text.TranslatableComponent}. No longer used by the client. - * @param name the name to set - */ -+ @Deprecated // Paper - Deprecate old localized API - void setLocalizedName(@Nullable String name); - - /** -diff --git a/src/main/java/org/bukkit/material/Step.java b/src/main/java/org/bukkit/material/Step.java -index 9f502e7ee05d0512e190a1722cc112ece068c4e2..10c0465cf58d680bfa9a0f9233f94e8b6d5a9b93 100644 ---- a/src/main/java/org/bukkit/material/Step.java -+++ b/src/main/java/org/bukkit/material/Step.java -@@ -78,6 +78,7 @@ public class Step extends TexturedMaterial { - * - * @deprecated Magic value - */ -+ @Deprecated // Paper - @Override - protected int getTextureIndex() { - return getData() & 0x7; -diff --git a/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java b/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java -index 0ea9c6b2420a0f990bd1fdf50fc015e37a7060d8..e99644eae1c662b117aa19060d2484aca19fe0a4 100644 ---- a/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java -+++ b/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java -@@ -7,7 +7,9 @@ import org.jetbrains.annotations.Nullable; - - /** - * Represents the different textured blocks of mushroom. -+ * @deprecated use BlockData - */ -+@Deprecated // Paper - public enum MushroomBlockTexture { - - /** diff --git a/patches/api/0176-PlayerDeathEvent-shouldDropExperience.patch b/patches/api/0176-PlayerDeathEvent-shouldDropExperience.patch new file mode 100644 index 000000000000..9f043baab66d --- /dev/null +++ b/patches/api/0176-PlayerDeathEvent-shouldDropExperience.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Tue, 24 Dec 2019 00:35:31 +0000 +Subject: [PATCH] PlayerDeathEvent#shouldDropExperience + + +diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +index edf14dac359e996f76e0af551a81a4dd8e48bd6c..bba3821d1215eb00489f841195c890a3f3353912 100644 +--- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java ++++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +@@ -17,6 +17,7 @@ public class PlayerDeathEvent extends EntityDeathEvent { + private int newTotalExp = 0; + private boolean keepLevel = false; + private boolean keepInventory = false; ++ private boolean doExpDrop; // Paper - shouldDropExperience API + // Paper start - adventure + @org.jetbrains.annotations.ApiStatus.Internal + public PlayerDeathEvent(final @NotNull Player player, final @NotNull DamageSource damageSource, final @NotNull List drops, final int droppedExp, final @Nullable net.kyori.adventure.text.Component deathMessage) { +@@ -30,11 +31,18 @@ public class PlayerDeathEvent extends EntityDeathEvent { + + @org.jetbrains.annotations.ApiStatus.Internal + public PlayerDeathEvent(final @NotNull Player player, final @NotNull DamageSource damageSource, final @NotNull List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, final @Nullable net.kyori.adventure.text.Component deathMessage) { ++ // Paper start - shouldDropExperience API ++ this(player, damageSource, drops, droppedExp, newExp, newTotalExp, newLevel, deathMessage, true); ++ } ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public PlayerDeathEvent(final @NotNull Player player, final @NotNull DamageSource damageSource, final @NotNull List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, final @Nullable net.kyori.adventure.text.Component deathMessage, final boolean doExpDrop) { ++ // Paper end - shouldDropExperience API + super(player, damageSource, drops, droppedExp); + this.newExp = newExp; + this.newTotalExp = newTotalExp; + this.newLevel = newLevel; + this.deathMessage = deathMessage; ++ this.doExpDrop = doExpDrop; // Paper - shouldDropExperience API + } + // Paper end - adventure + +@@ -50,11 +58,19 @@ public class PlayerDeathEvent extends EntityDeathEvent { + + @Deprecated // Paper + public PlayerDeathEvent(@NotNull final Player player, @NotNull DamageSource damageSource, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final String deathMessage) { ++ // Paper start - shouldDropExperience API ++ this(player, damageSource, drops, droppedExp, newExp, newTotalExp, newLevel, deathMessage, true); ++ } ++ ++ @Deprecated // Paper ++ public PlayerDeathEvent(@NotNull final Player player, final @NotNull DamageSource damageSource, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final String deathMessage, boolean doExpDrop) { ++ // Paper end - shouldDropExperience API + super(player, damageSource, drops, droppedExp); + this.newExp = newExp; + this.newTotalExp = newTotalExp; + this.newLevel = newLevel; + this.deathMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(deathMessage); // Paper ++ this.doExpDrop = doExpDrop; // Paper - shouldDropExperience API + } + + @Deprecated // Paper +@@ -92,6 +108,22 @@ public class PlayerDeathEvent extends EntityDeathEvent { + } + // Paper end + ++ // Paper start - shouldDropExperience API ++ /** ++ * @return should experience be dropped from this death ++ */ ++ public boolean shouldDropExperience() { ++ return doExpDrop; ++ } ++ ++ /** ++ * @param doExpDrop sets if experience should be dropped from this death ++ */ ++ public void setShouldDropExperience(boolean doExpDrop) { ++ this.doExpDrop = doExpDrop; ++ } ++ // Paper end - shouldDropExperience API ++ + @NotNull + @Override + public Player getEntity() { diff --git a/patches/api/0177-Add-ThrownEggHatchEvent.patch b/patches/api/0177-Add-ThrownEggHatchEvent.patch new file mode 100644 index 000000000000..3e2a10697a19 --- /dev/null +++ b/patches/api/0177-Add-ThrownEggHatchEvent.patch @@ -0,0 +1,131 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 9 Feb 2020 00:19:08 -0600 +Subject: [PATCH] Add ThrownEggHatchEvent + +Adds a new event similar to PlayerEggThrowEvent, but without the Player requirement +(dispensers can throw eggs to hatch them, too). + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..26526049a4c7f7ebe6bea27a9c5a638df3ef8854 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java +@@ -0,0 +1,117 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.entity.Egg; ++import org.bukkit.entity.EntityType; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a thrown egg might hatch. ++ *

      ++ * This event fires for all thrown eggs that may hatch, players, dispensers, etc. ++ */ ++@NullMarked ++public class ThrownEggHatchEvent extends Event { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Egg egg; ++ private boolean hatching; ++ private byte numHatches; ++ private EntityType hatchType; ++ ++ @ApiStatus.Internal ++ public ThrownEggHatchEvent(final Egg egg, final boolean hatching, final byte numHatches, final EntityType hatchingType) { ++ this.egg = egg; ++ this.hatching = hatching; ++ this.numHatches = numHatches; ++ this.hatchType = hatchingType; ++ } ++ ++ /** ++ * Gets the egg involved in this event. ++ * ++ * @return the egg involved in this event ++ */ ++ public Egg getEgg() { ++ return this.egg; ++ } ++ ++ /** ++ * Gets whether the egg is hatching or not. Will be what the server ++ * would've done without interaction. ++ * ++ * @return boolean Whether the egg is going to hatch or not ++ */ ++ public boolean isHatching() { ++ return this.hatching; ++ } ++ ++ /** ++ * Sets whether the egg will hatch or not. ++ * ++ * @param hatching {@code true} if you want the egg to hatch, {@code false} if you want it ++ * not to ++ */ ++ public void setHatching(final boolean hatching) { ++ this.hatching = hatching; ++ } ++ ++ /** ++ * Get the type of the mob being hatched ({@link EntityType#CHICKEN} by default) ++ * ++ * @return The type of the mob being hatched by the egg ++ */ ++ public EntityType getHatchingType() { ++ return this.hatchType; ++ } ++ ++ /** ++ * Change the type of mob being hatched by the egg ++ * ++ * @param hatchType The type of the mob being hatched by the egg ++ */ ++ public void setHatchingType(final EntityType hatchType) { ++ Preconditions.checkArgument(hatchType.isSpawnable(), "Can't spawn that entity type from an egg!"); ++ this.hatchType = hatchType; ++ } ++ ++ /** ++ * Get the number of mob hatches from the egg. By default, the number will ++ * be the number the server would've done ++ *

        ++ *
      • 7/8 chance of being 0 ++ *
      • 31/256 ~= 1/8 chance to be 1 ++ *
      • 1/256 chance to be 4 ++ *
      ++ * ++ * @return The number of mobs going to be hatched by the egg ++ */ ++ public byte getNumHatches() { ++ return this.numHatches; ++ } ++ ++ /** ++ * Change the number of mobs coming out of the hatched egg ++ *

      ++ * The boolean hatching will override this number. I.e. If hatching is ++ * {@code false}, this number will not matter ++ * ++ * @param numHatches The number of mobs coming out of the egg ++ */ ++ public void setNumHatches(final byte numHatches) { ++ this.numHatches = numHatches; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0177-Server-Tick-Events.patch b/patches/api/0177-Server-Tick-Events.patch deleted file mode 100644 index 9cb8b9a4c0ed..000000000000 --- a/patches/api/0177-Server-Tick-Events.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 27 Mar 2019 21:58:55 -0400 -Subject: [PATCH] Server Tick Events - -Fires event at start and end of a server tick - -diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9fd28e03649f66f71fb7f0536a137557ec32cd25 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerTickEndEvent.java -@@ -0,0 +1,59 @@ -+package com.destroystokyo.paper.event.server; -+ -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when the server has finished ticking the main loop -+ */ -+public class ServerTickEndEvent extends Event { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ private final int tickNumber; -+ private final double tickDuration; -+ private final long timeEnd; -+ -+ public ServerTickEndEvent(int tickNumber, double tickDuration, long timeRemaining) { -+ this.tickNumber = tickNumber; -+ this.tickDuration = tickDuration; -+ this.timeEnd = System.nanoTime() + timeRemaining; -+ } -+ -+ /** -+ * @return What tick this was since start (first tick = 1) -+ */ -+ public int getTickNumber() { -+ return tickNumber; -+ } -+ -+ /** -+ * @return Time in milliseconds of how long this tick took -+ */ -+ public double getTickDuration() { -+ return tickDuration; -+ } -+ -+ /** -+ * Amount of nanoseconds remaining before the next tick should start. -+ * -+ * If this value is negative, then that means the server has exceeded the tick time limit and TPS has been lost. -+ * -+ * Method will continously return the updated time remaining value. (return value is not static) -+ * -+ * @return Amount of nanoseconds remaining before the next tick should start -+ */ -+ public long getTimeRemaining() { -+ return this.timeEnd - System.nanoTime(); -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..eac85f1f49088bb71afb01eff4d5f53887306461 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java -@@ -0,0 +1,32 @@ -+package com.destroystokyo.paper.event.server; -+ -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+public class ServerTickStartEvent extends Event { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ private final int tickNumber; -+ -+ public ServerTickStartEvent(int tickNumber) { -+ this.tickNumber = tickNumber; -+ } -+ -+ /** -+ * @return What tick this is going be since start (first tick = 1) -+ */ -+ public int getTickNumber() { -+ return tickNumber; -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0178-Entity-Jump-API.patch b/patches/api/0178-Entity-Jump-API.patch new file mode 100644 index 000000000000..eda3d309c776 --- /dev/null +++ b/patches/api/0178-Entity-Jump-API.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 8 Feb 2020 23:26:18 -0600 +Subject: [PATCH] Entity Jump API + + +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b49b72608573ad5b98fc6e0070f6ef105bf177e4 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java +@@ -0,0 +1,50 @@ ++package com.destroystokyo.paper.event.entity; ++ ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when an entity jumps ++ *

      ++ * Cancelling the event will stop the entity from jumping ++ */ ++@NullMarked ++public class EntityJumpEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityJumpEvent(final LivingEntity entity) { ++ super(entity); ++ } ++ ++ @Override ++ public LivingEntity getEntity() { ++ return (LivingEntity) super.getEntity(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 72b83dedf025ef971b89e2c6a19fd411488948b7..f9e2b5a7cd3db267d8f543898b9f6b00586d1b4a 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1159,4 +1159,26 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + return this.getActiveItemHand(); + } + // Paper end - active item API ++ ++ // Paper start - entity jump API ++ /** ++ * Get entity jump state. ++ *

      ++ * Jump state will be true when the entity has been marked to jump. ++ * ++ * @return entity jump state. ++ */ ++ boolean isJumping(); ++ ++ /** ++ * Set entity jump state ++ *

      ++ * Setting to true will mark the entity to jump. ++ *

      ++ * Setting to false will unmark the entity to jump but will not stop a jump already in-progress. ++ * ++ * @param jumping entity jump state ++ */ ++ void setJumping(boolean jumping); ++ // Paper end - entity jump API + } diff --git a/patches/api/0178-PlayerDeathEvent-getItemsToKeep.patch b/patches/api/0178-PlayerDeathEvent-getItemsToKeep.patch deleted file mode 100644 index 871984a4fc80..000000000000 --- a/patches/api/0178-PlayerDeathEvent-getItemsToKeep.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 11 Mar 2013 20:04:34 -0400 -Subject: [PATCH] PlayerDeathEvent#getItemsToKeep - -Exposes a mutable array on items a player should keep on death - -Example Usage: https://gist.github.com/aikar/5bb202de6057a051a950ce1f29feb0b4 - -diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -index a871eddf73f918c0e3d2554ef8d9cfd0f830fcaa..5f7d0d08be8bca06c9aa89659b7865a7b5a547f8 100644 ---- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -+++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -@@ -36,7 +36,6 @@ public class PlayerDeathEvent extends EntityDeathEvent { - } - // Paper end - -- @Deprecated // Paper - public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, @Nullable final String deathMessage) { - this(player, drops, droppedExp, 0, deathMessage); - } -@@ -56,6 +55,41 @@ public class PlayerDeathEvent extends EntityDeathEvent { - this.adventure$deathMessage = deathMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(deathMessage) : net.kyori.adventure.text.Component.empty(); // Paper - } - -+ @Deprecated // Paper -+ // Paper start -+ private List itemsToKeep = new java.util.ArrayList<>(); -+ -+ /** -+ * A mutable collection to add items that the player should retain in their inventory on death (Similar to KeepInventory game rule) -+ * -+ * You MUST remove the item from the .getDrops() collection too or it will duplicate! -+ *

      {@code
      -+     *    {@literal @EventHandler(ignoreCancelled = true)}
      -+     *     public void onPlayerDeath(PlayerDeathEvent event) {
      -+     *         for (Iterator iterator = event.getDrops().iterator(); iterator.hasNext(); ) {
      -+     *             ItemStack drop = iterator.next();
      -+     *             List lore = drop.getLore();
      -+     *             if (lore != null && !lore.isEmpty()) {
      -+     *                 if (lore.get(0).contains("(SOULBOUND)")) {
      -+     *                     iterator.remove();
      -+     *                     event.getItemsToKeep().add(drop);
      -+     *                 }
      -+     *             }
      -+     *         }
      -+     *     }
      -+     * }
      -+ * -+ * Adding an item to this list that the player did not previously have will give them the item on death. -+ * An example case could be a "Note" that "You died at X/Y/Z coordinates" -+ * -+ * @return The list to hold items to keep -+ */ -+ @NotNull -+ public List getItemsToKeep() { -+ return itemsToKeep; -+ } -+ // Paper end -+ - @NotNull - @Override - public Player getEntity() { diff --git a/patches/api/0179-Add-Heightmap-API.patch b/patches/api/0179-Add-Heightmap-API.patch deleted file mode 100644 index d2e3bd00116f..000000000000 --- a/patches/api/0179-Add-Heightmap-API.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 1 Dec 2018 19:00:36 -0800 -Subject: [PATCH] Add Heightmap API - -Changed to use upstream's heightmap API - Machine_Maker - -diff --git a/src/main/java/com/destroystokyo/paper/HeightmapType.java b/src/main/java/com/destroystokyo/paper/HeightmapType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..709e44ea1b14ab6917501c928e689cc6cbdf4bb4 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/HeightmapType.java -@@ -0,0 +1,39 @@ -+package com.destroystokyo.paper; -+ -+import org.bukkit.*; -+ -+/** -+ * Enumeration of different heightmap types maintained by the server. Generally using these maps is much faster -+ * than using an iterative search for a block in a given x, z coordinate. -+ * -+ * @deprecated Upstream has added their own API for using the game heightmaps. See {@link org.bukkit.HeightMap} and the -+ * non-deprecated getHighestBlock methods on World such as {@link org.bukkit.World#getHighestBlockAt(Location, HeightMap)}. -+ */ -+@Deprecated -+public enum HeightmapType { -+ -+ /** -+ * The highest block used for lighting in the world. Also the block returned by {@link World#getHighestBlockYAt(int, int)}} -+ */ -+ LIGHT_BLOCKING, -+ -+ /** -+ * References the highest block in the world. -+ */ -+ ANY, -+ -+ /** -+ * References the highest solid block in a world. -+ */ -+ SOLID, -+ -+ /** -+ * References the highest solid or liquid block in a world. -+ */ -+ SOLID_OR_LIQUID, -+ -+ /** -+ * References the highest solid or liquid block in a world, excluding leaves. -+ */ -+ SOLID_OR_LIQUID_NO_LEAVES; -+} -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index d4c87bfed81b2d73919705912f59fab05c0ee61b..ef0cb00ca4cb7d2f5e4ec1c950cce036566d1ae4 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -640,6 +640,47 @@ public class Location implements Cloneable, ConfigurationSerializable { - return centerLoc; - } - -+ // Paper start - Add heightmap api -+ -+ /** -+ * Returns a copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ()) -+ * @return A copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ()) -+ * @throws NullPointerException if {{@link #getWorld()}} is {@code null} -+ */ -+ @NotNull -+ public Location toHighestLocation() { -+ return this.toHighestLocation(HeightMap.WORLD_SURFACE); -+ } -+ -+ /** -+ * Returns a copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ(), heightmap) -+ * @param heightmap The heightmap to use for finding the highest y location. -+ * @return A copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ(), heightmap) -+ * @throws NullPointerException if {{@link #getWorld()}} is {@code null} -+ * @throws UnsupportedOperationException if {@link World#getHighestBlockYAt(int, int, com.destroystokyo.paper.HeightmapType)} does not support the specified heightmap -+ * @deprecated Use {@link org.bukkit.Location#toHighestLocation(HeightMap)} -+ */ -+ @NotNull -+ @Deprecated -+ public Location toHighestLocation(@NotNull final com.destroystokyo.paper.HeightmapType heightmap) { -+ final Location ret = this.clone(); -+ ret.setY(this.getWorld().getHighestBlockYAt(this, heightmap)); -+ return ret; -+ } -+ -+ /** -+ * Returns a copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ(), heightMap) -+ * @param heightMap The heightmap to use for finding the highest y location. -+ * @return A copy of this location except with y = getWorld().getHighestBlockYAt(this.getBlockX(), this.getBlockZ(), heightMap) -+ */ -+ @NotNull -+ public Location toHighestLocation(@NotNull final HeightMap heightMap) { -+ final Location ret = this.clone(); -+ ret.setY(this.getWorld().getHighestBlockYAt(this, heightMap)); -+ return ret; -+ } -+ // Paper end -+ - /** - * Creates explosion at this location with given power - * -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 7358c9148853d4b5b35998094838156231497747..352a20da402b3b0182b7a0c69d94397f42054053 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -167,6 +167,87 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - @NotNull - public Block getHighestBlockAt(@NotNull Location location); - -+ // Paper start - Add heightmap API -+ /** -+ * Returns the highest block's y-coordinate at the specified block coordinates that match the specified heightmap's conditions. -+ *

      -+ * implNote: Implementations are recommended to use an iterative search as a fallback before resorting to -+ * throwing an {@code UnsupportedOperationException}. -+ *

      -+ * -+ * @param x The block's x-coordinate. -+ * @param z The block's z-coordinate. -+ * @param heightmap The specified heightmap to use. See {@link com.destroystokyo.paper.HeightmapType} -+ * @return The highest block's y-coordinate at (x, z) that matches the specified heightmap's conditions. -+ * @throws UnsupportedOperationException If the heightmap type is not supported. -+ * @deprecated Upstream has added support for this, use {@link World#getHighestBlockYAt(int, int, HeightMap)} -+ * -+ * @see com.destroystokyo.paper.HeightmapType -+ */ -+ @Deprecated -+ public int getHighestBlockYAt(int x, int z, @NotNull com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException; -+ -+ /** -+ * Returns the highest block's y-coordinate at the specified block coordinates that match the specified heightmap's conditions. -+ * Note that the y-coordinate of the specified location is ignored. -+ *

      -+ * implNote: Implementations are recommended to use an iterative search as a fallback before resorting to -+ * throwing an {@code UnsupportedOperationException}. -+ *

      -+ * -+ * @param location The specified block coordinates. -+ * @param heightmap The specified heightmap to use. See {@link com.destroystokyo.paper.HeightmapType} -+ * @return The highest block's y-coordinate at {@code location} that matches the specified heightmap's conditions. -+ * @throws UnsupportedOperationException If the heightmap type is not supported. -+ * @deprecated Upstream has added support for this, use {@link World#getHighestBlockYAt(Location, HeightMap)} -+ * @see com.destroystokyo.paper.HeightmapType -+ */ -+ @Deprecated -+ default int getHighestBlockYAt(@NotNull Location location, @NotNull com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { -+ return this.getHighestBlockYAt(location.getBlockX(), location.getBlockZ(), heightmap); -+ } -+ -+ /** -+ * Returns the highest {@link Block} at the specified block coordinates that match the specified heightmap's conditions. -+ *

      -+ * implNote: Implementations are recommended to use an iterative search as a fallback before resorting to -+ * throwing an {@code UnsupportedOperationException}. -+ *

      -+ * @param x The block's x-coordinate. -+ * @param z The block's z-coordinate. -+ * @param heightmap The specified heightmap to use. See {@link com.destroystokyo.paper.HeightmapType} -+ * @return The highest {@link Block} at (x, z) that matches the specified heightmap's conditions. -+ * @throws UnsupportedOperationException If the heightmap type is not supported. -+ * @deprecated Upstream has added support for this, use {@link World#getHighestBlockAt(int, int, HeightMap)} -+ * @see com.destroystokyo.paper.HeightmapType -+ */ -+ @Deprecated -+ @NotNull -+ default Block getHighestBlockAt(int x, int z, @NotNull com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { -+ return this.getBlockAt(x, this.getHighestBlockYAt(x, z, heightmap), z); -+ } -+ -+ /** -+ * Returns the highest {@link Block} at the specified block coordinates that match the specified heightmap's conditions. -+ * Note that the y-coordinate of the specified location is ignored. -+ *

      -+ * implNote: Implementations are recommended to use an iterative search as a fallback before resorting to -+ * throwing an {@code UnsupportedOperationException}. -+ *

      -+ * @param location The specified block coordinates. -+ * @param heightmap The specified heightmap to use. See {@link com.destroystokyo.paper.HeightmapType} -+ * @return The highest {@link Block} at {@code location} that matches the specified heightmap's conditions. -+ * @throws UnsupportedOperationException If the heightmap type is not supported. -+ * @deprecated Upstream has added support for this, use {@link World#getHighestBlockAt(Location, HeightMap)} -+ * @see com.destroystokyo.paper.HeightmapType -+ */ -+ @Deprecated -+ @NotNull -+ default Block getHighestBlockAt(@NotNull Location location, @NotNull com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { -+ return this.getHighestBlockAt(location.getBlockX(), location.getBlockZ(), heightmap); -+ } -+ // Paper end -+ - /** - * Gets the highest coordinate corresponding to the {@link HeightMap} at the - * given coordinates. diff --git a/patches/api/0189-add-hand-to-BlockMultiPlaceEvent.patch b/patches/api/0179-add-hand-to-BlockMultiPlaceEvent.patch similarity index 100% rename from patches/api/0189-add-hand-to-BlockMultiPlaceEvent.patch rename to patches/api/0179-add-hand-to-BlockMultiPlaceEvent.patch diff --git a/patches/api/0180-Add-tick-times-API.patch b/patches/api/0180-Add-tick-times-API.patch new file mode 100644 index 000000000000..d2c97d40a4e9 --- /dev/null +++ b/patches/api/0180-Add-tick-times-API.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 5 Apr 2020 22:22:58 -0500 +Subject: [PATCH] Add tick times API + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index f16f0a72a7b533106e1703197e370d67e13d77a3..2e44d7e90015d713b952f49f06d3ba7744d1eb42 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2218,6 +2218,25 @@ public final class Bukkit { + public static double[] getTPS() { + return server.getTPS(); + } ++ ++ /** ++ * Get a sample of the servers last tick times (in nanos) ++ * ++ * @return A sample of the servers last tick times (in nanos) ++ */ ++ @NotNull ++ public static long[] getTickTimes() { ++ return server.getTickTimes(); ++ } ++ ++ /** ++ * Get the average tick time (in millis) ++ * ++ * @return Average tick time (in millis) ++ */ ++ public static double getAverageTickTime() { ++ return server == null ? 0D : server.getAverageTickTime(); ++ } + // Paper end + + /** +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index b8f1ecb16e3e1d969873f99f3b029d9a12437bd9..6d4f181be4000803392a59d3a9314c1d70be7533 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1877,6 +1877,21 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + @NotNull + public double[] getTPS(); ++ ++ /** ++ * Get a sample of the servers last tick times (in nanos) ++ * ++ * @return A sample of the servers last tick times (in nanos) ++ */ ++ @NotNull ++ long[] getTickTimes(); ++ ++ /** ++ * Get the average tick time (in millis) ++ * ++ * @return Average tick time (in millis) ++ */ ++ double getAverageTickTime(); + // Paper end + + // Paper start diff --git a/patches/api/0180-Mob-Spawner-API-Enhancements.patch b/patches/api/0180-Mob-Spawner-API-Enhancements.patch deleted file mode 100644 index 2bbe92cbe988..000000000000 --- a/patches/api/0180-Mob-Spawner-API-Enhancements.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 19 Apr 2019 12:41:19 -0500 -Subject: [PATCH] Mob Spawner API Enhancements - - -diff --git a/src/main/java/org/bukkit/block/CreatureSpawner.java b/src/main/java/org/bukkit/block/CreatureSpawner.java -index cb447a4ad5a9dce7c98999a5d7fcd6111fc9b10e..5bbae759ce39d42886994e500fd9454ec328f804 100644 ---- a/src/main/java/org/bukkit/block/CreatureSpawner.java -+++ b/src/main/java/org/bukkit/block/CreatureSpawner.java -@@ -199,4 +199,30 @@ public interface CreatureSpawner extends TileState { - * @see #getSpawnRange() - */ - public void setSpawnRange(int spawnRange); -+ -+ // Paper start -+ /** -+ * Check if spawner is activated (a player is close enough) -+ * -+ * @return True if a player is close enough to activate it -+ */ -+ public boolean isActivated(); -+ -+ /** -+ * Resets the spawn delay timer within the min/max range -+ */ -+ public void resetTimer(); -+ -+ /** -+ * Sets the {@link EntityType} to {@link EntityType#DROPPED_ITEM} and sets the data to the given -+ * {@link org.bukkit.inventory.ItemStack ItemStack}. -+ *

      -+ * {@link #setSpawnCount(int)} does not dictate the amount of items in the stack spawned, but rather how many -+ * stacks should be spawned. -+ * -+ * @param itemStack The item to spawn. Must not {@link org.bukkit.Material#isAir be air}. -+ * @see #setSpawnedType(EntityType) -+ */ -+ void setSpawnedItem(@NotNull org.bukkit.inventory.ItemStack itemStack); -+ // Paper end - } diff --git a/patches/api/0181-Add-BlockSoundGroup-interface.patch b/patches/api/0181-Add-BlockSoundGroup-interface.patch deleted file mode 100644 index 1d34e11a3bb0..000000000000 --- a/patches/api/0181-Add-BlockSoundGroup-interface.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: simpleauthority -Date: Tue, 28 May 2019 03:41:28 -0700 -Subject: [PATCH] Add BlockSoundGroup interface - -This PR adds the getSoundGroup() method in Block which returns a BlockSoundGroup - -diff --git a/src/main/java/com/destroystokyo/paper/block/BlockSoundGroup.java b/src/main/java/com/destroystokyo/paper/block/BlockSoundGroup.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ec36942128cbacae171584c89480b4aae3ae3e2f ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/block/BlockSoundGroup.java -@@ -0,0 +1,64 @@ -+package com.destroystokyo.paper.block; -+ -+import org.bukkit.Sound; -+import org.bukkit.block.Block; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Represents the sounds that a {@link Block} makes in certain situations -+ *

      -+ * The sound group includes break, step, place, hit, and fall sounds. -+ * @deprecated use {@link org.bukkit.SoundGroup} -+ */ -+@Deprecated(forRemoval = true) -+public interface BlockSoundGroup { -+ /** -+ * Gets the sound that plays when breaking this block -+ * -+ * @return The break sound -+ * @deprecated use {@link org.bukkit.SoundGroup#getBreakSound()} -+ */ -+ @NotNull -+ @Deprecated(forRemoval = true) -+ Sound getBreakSound(); -+ -+ /** -+ * Gets the sound that plays when stepping on this block -+ * -+ * @return The step sound -+ * @deprecated use {@link org.bukkit.SoundGroup#getStepSound()} -+ */ -+ @NotNull -+ @Deprecated(forRemoval = true) -+ Sound getStepSound(); -+ -+ /** -+ * Gets the sound that plays when placing this block -+ * -+ * @return The place sound -+ * @deprecated use {@link org.bukkit.SoundGroup#getPlaceSound()} -+ */ -+ @NotNull -+ @Deprecated(forRemoval = true) -+ Sound getPlaceSound(); -+ -+ /** -+ * Gets the sound that plays when hitting this block -+ * -+ * @return The hit sound -+ * @deprecated use {@link org.bukkit.SoundGroup#getHitSound()} -+ */ -+ @NotNull -+ @Deprecated(forRemoval = true) -+ Sound getHitSound(); -+ -+ /** -+ * Gets the sound that plays when this block falls -+ * -+ * @return The fall sound -+ * @deprecated use {@link org.bukkit.SoundGroup#getFallSound()} -+ */ -+ @NotNull -+ @Deprecated(forRemoval = true) -+ Sound getFallSound(); -+} -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index b101f5264bdde8bd14913d5161c1047020830f8d..db441e463b02ee734f85c855f5538cd41041dbae 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -606,4 +606,25 @@ public interface Block extends Metadatable { - * @return true if the block data can be placed here - */ - boolean canPlace(@NotNull BlockData data); -+ -+ // Paper start -+ /** -+ * Gets the {@link com.destroystokyo.paper.block.BlockSoundGroup} for this block. -+ *

      -+ * This object contains the block, step, place, hit, and fall sounds. -+ * -+ * @return the sound group for this block -+ * @deprecated use {@link #getBlockSoundGroup()} -+ */ -+ @NotNull -+ @Deprecated(forRemoval = true) -+ com.destroystokyo.paper.block.BlockSoundGroup getSoundGroup(); -+ -+ /** -+ * Gets the {@link org.bukkit.SoundGroup} for this block. -+ * -+ * @return the sound group for this block -+ */ -+ @NotNull org.bukkit.SoundGroup getBlockSoundGroup(); -+ // Paper end - } diff --git a/patches/api/0181-Expose-MinecraftServer-isRunning.patch b/patches/api/0181-Expose-MinecraftServer-isRunning.patch new file mode 100644 index 000000000000..3b469b93f4d4 --- /dev/null +++ b/patches/api/0181-Expose-MinecraftServer-isRunning.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Fri, 10 Apr 2020 21:24:35 -0400 +Subject: [PATCH] Expose MinecraftServer#isRunning + +This allows for plugins to detect if the server is actually turning off in onDisable rather than just plugins reloading. + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 2e44d7e90015d713b952f49f06d3ba7744d1eb42..40d04b4ebecaa0cff8937451568d998a0dfae088 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2575,6 +2575,15 @@ public final class Bukkit { + public static int getCurrentTick() { + return server.getCurrentTick(); + } ++ ++ /** ++ * Checks if the server is in the process of being shutdown. ++ * ++ * @return true if server is in the process of being shutdown ++ */ ++ public static boolean isStopping() { ++ return server.isStopping(); ++ } + // Paper end + + @NotNull +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 6d4f181be4000803392a59d3a9314c1d70be7533..90509d2e4c61de29611312c0864ef7622072d540 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2243,5 +2243,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @return Current tick + */ + int getCurrentTick(); ++ ++ /** ++ * Checks if the server is in the process of being shutdown. ++ * ++ * @return true if server is in the process of being shutdown ++ */ ++ boolean isStopping(); + // Paper end + } diff --git a/patches/api/0182-Add-Raw-Byte-ItemStack-Serialization.patch b/patches/api/0182-Add-Raw-Byte-ItemStack-Serialization.patch new file mode 100644 index 000000000000..229906593367 --- /dev/null +++ b/patches/api/0182-Add-Raw-Byte-ItemStack-Serialization.patch @@ -0,0 +1,177 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Thu, 30 Apr 2020 16:56:31 +0200 +Subject: [PATCH] Add Raw Byte ItemStack Serialization + +Serializes using NBT which is safer for server data migrations than bukkits format. + +Co-authored-by: Nassim Jahnke + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 012b46c82d9d06d1d2da8da626fc5cde6e9e2ca4..739f117a0fd91ae98b5e5a39ae8e23feca0b741d 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -164,5 +164,9 @@ public interface UnsafeValues { + default com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { + return new com.destroystokyo.paper.util.VersionFetcher.DummyVersionFetcher(); + } ++ ++ byte[] serializeItem(ItemStack item); ++ ++ ItemStack deserializeItem(byte[] data); + // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index 132cf07816b0d356c94fa4e8b8bfefccce2de103..a919d50b31ed48a43bc47596eae44b3d05a417ee 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -661,6 +661,117 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + return Bukkit.getServer().getItemFactory().ensureServerConversions(this); + } + ++ /** ++ * Deserializes this itemstack from raw NBT bytes. NBT is safer for data migrations as it will ++ * use the built in data converter instead of bukkits dangerous serialization system. ++ * ++ * This expects that the DataVersion was stored on the root of the Compound, as saved from ++ * the {@link #serializeAsBytes()} API returned. ++ * @param bytes bytes representing an item in NBT ++ * @return ItemStack migrated to this version of Minecraft if needed. ++ */ ++ @NotNull ++ public static ItemStack deserializeBytes(@NotNull byte[] bytes) { ++ return org.bukkit.Bukkit.getUnsafe().deserializeItem(bytes); ++ } ++ ++ /** ++ * Serializes this itemstack to raw bytes in NBT. NBT is safer for data migrations as it will ++ * use the built in data converter instead of bukkits dangerous serialization system. ++ * @return bytes representing this item in NBT. ++ */ ++ @NotNull ++ public byte[] serializeAsBytes() { ++ return org.bukkit.Bukkit.getUnsafe().serializeItem(this); ++ } ++ ++ /** ++ * The current version byte of the item array format used in {@link #serializeItemsAsBytes(java.util.Collection)} ++ * and {@link #deserializeItemsFromBytes(byte[])} respectively. ++ */ ++ private static final byte ARRAY_SERIALIZATION_VERSION = 1; ++ ++ /** ++ * Serializes a collection of items to raw bytes in NBT. Serializes null items as {@link #empty()}. ++ *

      ++ * If you need a string representation to put into a file, you can for example use {@link java.util.Base64} encoding. ++ * ++ * @param items items to serialize ++ * @return bytes representing the items in NBT ++ * @see #serializeAsBytes() ++ */ ++ public static byte @NotNull [] serializeItemsAsBytes(java.util.@NotNull Collection items) { ++ try (final java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream()) { ++ final java.io.DataOutput output = new java.io.DataOutputStream(outputStream); ++ output.writeByte(ARRAY_SERIALIZATION_VERSION); ++ output.writeInt(items.size()); ++ for (final ItemStack item : items) { ++ if (item == null || item.isEmpty()) { ++ // Ensure the correct order by including empty/null items ++ output.writeInt(0); ++ continue; ++ } ++ ++ final byte[] itemBytes = item.serializeAsBytes(); ++ output.writeInt(itemBytes.length); ++ output.write(itemBytes); ++ } ++ return outputStream.toByteArray(); ++ } catch (final java.io.IOException e) { ++ throw new RuntimeException("Error while writing itemstack", e); ++ } ++ } ++ ++ /** ++ * Serializes a collection of items to raw bytes in NBT. Serializes null items as {@link #empty()}. ++ *

      ++ * If you need a string representation to put into a file, you can for example use {@link java.util.Base64} encoding. ++ * ++ * @param items items to serialize ++ * @return bytes representing the items in NBT ++ * @see #serializeAsBytes() ++ */ ++ public static byte @NotNull [] serializeItemsAsBytes(@Nullable ItemStack @NotNull [] items) { ++ return serializeItemsAsBytes(java.util.Arrays.asList(items)); ++ } ++ ++ /** ++ * Deserializes this itemstack from raw NBT bytes. ++ *

      ++ * If you need a string representation to put into a file, you can for example use {@link java.util.Base64} encoding. ++ * ++ * @param bytes bytes representing an item in NBT ++ * @return ItemStack array migrated to this version of Minecraft if needed ++ * @see #deserializeBytes(byte[]) ++ */ ++ public static @NotNull ItemStack @NotNull [] deserializeItemsFromBytes(final byte @NotNull [] bytes) { ++ try (final java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(bytes)) { ++ final java.io.DataInputStream input = new java.io.DataInputStream(inputStream); ++ final byte version = input.readByte(); ++ if (version != ARRAY_SERIALIZATION_VERSION) { ++ throw new IllegalArgumentException("Unsupported version or bad data: " + version); ++ } ++ ++ final int count = input.readInt(); ++ final ItemStack[] items = new ItemStack[count]; ++ for (int i = 0; i < count; i++) { ++ final int length = input.readInt(); ++ if (length == 0) { ++ // Empty item, keep entry as empty ++ items[i] = ItemStack.empty(); ++ continue; ++ } ++ ++ final byte[] itemBytes = new byte[length]; ++ input.read(itemBytes); ++ items[i] = ItemStack.deserializeBytes(itemBytes); ++ } ++ return items; ++ } catch (final java.io.IOException e) { ++ throw new RuntimeException("Error while reading itemstack", e); ++ } ++ } ++ + /** + * Gets the Display name as seen in the Client. + * Currently the server only supports the English language. To override this, +diff --git a/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java b/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java +index 0f8eb97bd5e2f8b0f0cc03f7c4342aae06c4520c..6c074ff2dcfc279657037013b9b54890d7c8a533 100644 +--- a/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java ++++ b/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java +@@ -14,7 +14,11 @@ import org.bukkit.configuration.serialization.ConfigurationSerialization; + *

      + * Behavior of implementations extending this class is not guaranteed across + * future versions. ++ * @deprecated Object streams on their own are not safe. For safer and more consistent serialization of items, ++ * use {@link org.bukkit.inventory.ItemStack#serializeAsBytes()} or ++ * {@link org.bukkit.inventory.ItemStack#serializeItemsAsBytes(java.util.Collection)}. + */ ++@Deprecated(since = "1.21") // Paper + public class BukkitObjectInputStream extends ObjectInputStream { + + /** +diff --git a/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java b/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java +index dd1b9ee5f57773f07924aa311823fd8d63195cb2..4e24e7c73271a579db2c4309951693dfb2fecceb 100644 +--- a/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java ++++ b/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java +@@ -14,7 +14,11 @@ import org.bukkit.configuration.serialization.ConfigurationSerializable; + *

      + * Behavior of implementations extending this class is not guaranteed across + * future versions. ++ * @deprecated Object streams on their own are not safe. For safer and more consistent serialization of items, ++ * use {@link org.bukkit.inventory.ItemStack#serializeAsBytes()} or ++ * {@link org.bukkit.inventory.ItemStack#serializeItemsAsBytes(java.util.Collection)}. + */ ++@Deprecated(since = "1.21") // Paper + public class BukkitObjectOutputStream extends ObjectOutputStream { + + /** diff --git a/patches/api/0183-Add-Player-Client-Options-API.patch b/patches/api/0183-Add-Player-Client-Options-API.patch new file mode 100644 index 000000000000..2217f1bba120 --- /dev/null +++ b/patches/api/0183-Add-Player-Client-Options-API.patch @@ -0,0 +1,280 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger +Date: Mon, 20 Jan 2020 21:38:34 +0100 +Subject: [PATCH] Add Player Client Options API + + +diff --git a/src/main/java/com/destroystokyo/paper/ClientOption.java b/src/main/java/com/destroystokyo/paper/ClientOption.java +new file mode 100644 +index 0000000000000000000000000000000000000000..290bde7050f43cb5cd6c0cea9eb7a05297536dec +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/ClientOption.java +@@ -0,0 +1,76 @@ ++package com.destroystokyo.paper; ++ ++import net.kyori.adventure.translation.Translatable; ++import net.kyori.adventure.util.Index; ++import org.bukkit.inventory.MainHand; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public final class ClientOption { ++ ++ public static final ClientOption SKIN_PARTS = new ClientOption<>(SkinParts.class); ++ public static final ClientOption CHAT_COLORS_ENABLED = new ClientOption<>(Boolean.class); ++ public static final ClientOption CHAT_VISIBILITY = new ClientOption<>(ChatVisibility.class); ++ public static final ClientOption LOCALE = new ClientOption<>(String.class); ++ public static final ClientOption MAIN_HAND = new ClientOption<>(MainHand.class); ++ public static final ClientOption VIEW_DISTANCE = new ClientOption<>(Integer.class); ++ public static final ClientOption TEXT_FILTERING_ENABLED = new ClientOption<>(Boolean.class); ++ public static final ClientOption ALLOW_SERVER_LISTINGS = new ClientOption<>(Boolean.class); ++ public static final ClientOption PARTICLE_VISIBILITY = new ClientOption<>(ParticleVisibility.class); ++ ++ private final Class type; ++ ++ private ClientOption(final Class type) { ++ this.type = type; ++ } ++ ++ public Class getType() { ++ return this.type; ++ } ++ ++ public enum ChatVisibility implements Translatable { ++ FULL("full"), ++ SYSTEM("system"), ++ HIDDEN("hidden"), ++ /** ++ * @deprecated no longer used anymore since 1.15.2, the value fallback ++ * to the default value of the setting when unknown on the server. ++ * In this case {@link #FULL} will be returned. ++ */ ++ @Deprecated(since = "1.15.2", forRemoval = true) ++ UNKNOWN("unknown"); ++ ++ public static final Index NAMES = Index.create(ChatVisibility.class, chatVisibility -> chatVisibility.name); ++ private final String name; ++ ++ ChatVisibility(final String name) { ++ this.name = name; ++ } ++ ++ @Override ++ public String translationKey() { ++ if (this == UNKNOWN) { ++ throw new UnsupportedOperationException(this.name + " doesn't have a translation key"); ++ } ++ return "options.chat.visibility." + this.name; ++ } ++ } ++ ++ public enum ParticleVisibility implements Translatable { ++ ALL("all"), ++ DECREASED("decreased"), ++ MINIMAL("minimal"); ++ ++ public static final Index NAMES = Index.create(ParticleVisibility.class, particleVisibility -> particleVisibility.name); ++ private final String name; ++ ++ ParticleVisibility(final String name) { ++ this.name = name; ++ } ++ ++ @Override ++ public String translationKey() { ++ return "options.particles." + this.name; ++ } ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/SkinParts.java b/src/main/java/com/destroystokyo/paper/SkinParts.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4a0c39405d4fbed457787e3c6ded4cc6591bc8c2 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/SkinParts.java +@@ -0,0 +1,20 @@ ++package com.destroystokyo.paper; ++ ++public interface SkinParts { ++ ++ boolean hasCapeEnabled(); ++ ++ boolean hasJacketEnabled(); ++ ++ boolean hasLeftSleeveEnabled(); ++ ++ boolean hasRightSleeveEnabled(); ++ ++ boolean hasLeftPantsEnabled(); ++ ++ boolean hasRightPantsEnabled(); ++ ++ boolean hasHatsEnabled(); ++ ++ int getRaw(); ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5245955fb3466d2b89eaad4027d145ebf7bb122c +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java +@@ -0,0 +1,142 @@ ++package com.destroystokyo.paper.event.player; ++ ++import com.destroystokyo.paper.ClientOption; ++import com.destroystokyo.paper.ClientOption.ChatVisibility; ++import com.destroystokyo.paper.ClientOption.ParticleVisibility; ++import com.destroystokyo.paper.SkinParts; ++import java.util.Map; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.MainHand; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when the player changes their client settings ++ */ ++@NullMarked ++public class PlayerClientOptionsChangeEvent extends PlayerEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final String locale; ++ private final int viewDistance; ++ private final ChatVisibility chatVisibility; ++ private final boolean chatColors; ++ private final SkinParts skinparts; ++ private final MainHand mainHand; ++ private final boolean allowsServerListings; ++ private final boolean textFilteringEnabled; ++ private final ParticleVisibility particleVisibility; ++ ++ @Deprecated ++ public PlayerClientOptionsChangeEvent(final Player player, final String locale, final int viewDistance, final ChatVisibility chatVisibility, final boolean chatColors, final SkinParts skinParts, final MainHand mainHand) { ++ super(player); ++ this.locale = locale; ++ this.viewDistance = viewDistance; ++ this.chatVisibility = chatVisibility; ++ this.chatColors = chatColors; ++ this.skinparts = skinParts; ++ this.mainHand = mainHand; ++ this.allowsServerListings = false; ++ this.textFilteringEnabled = false; ++ this.particleVisibility = ParticleVisibility.ALL; ++ } ++ ++ @ApiStatus.Internal ++ public PlayerClientOptionsChangeEvent(final Player player, final Map, ?> options) { ++ super(player); ++ ++ this.locale = (String) options.get(ClientOption.LOCALE); ++ this.viewDistance = (int) options.get(ClientOption.VIEW_DISTANCE); ++ this.chatVisibility = (ChatVisibility) options.get(ClientOption.CHAT_VISIBILITY); ++ this.chatColors = (boolean) options.get(ClientOption.CHAT_COLORS_ENABLED); ++ this.skinparts = (SkinParts) options.get(ClientOption.SKIN_PARTS); ++ this.mainHand = (MainHand) options.get(ClientOption.MAIN_HAND); ++ this.allowsServerListings = (boolean) options.get(ClientOption.ALLOW_SERVER_LISTINGS); ++ this.textFilteringEnabled = (boolean) options.get(ClientOption.TEXT_FILTERING_ENABLED); ++ this.particleVisibility = (ParticleVisibility) options.get(ClientOption.PARTICLE_VISIBILITY); ++ } ++ ++ public String getLocale() { ++ return this.locale; ++ } ++ ++ public boolean hasLocaleChanged() { ++ return !this.locale.equals(this.player.getClientOption(ClientOption.LOCALE)); ++ } ++ ++ public int getViewDistance() { ++ return this.viewDistance; ++ } ++ ++ public boolean hasViewDistanceChanged() { ++ return this.viewDistance != this.player.getClientOption(ClientOption.VIEW_DISTANCE); ++ } ++ ++ public ChatVisibility getChatVisibility() { ++ return this.chatVisibility; ++ } ++ ++ public boolean hasChatVisibilityChanged() { ++ return this.chatVisibility != this.player.getClientOption(ClientOption.CHAT_VISIBILITY); ++ } ++ ++ public boolean hasChatColorsEnabled() { ++ return this.chatColors; ++ } ++ ++ public boolean hasChatColorsEnabledChanged() { ++ return this.chatColors != this.player.getClientOption(ClientOption.CHAT_COLORS_ENABLED); ++ } ++ ++ public SkinParts getSkinParts() { ++ return this.skinparts; ++ } ++ ++ public boolean hasSkinPartsChanged() { ++ return this.skinparts.getRaw() != this.player.getClientOption(ClientOption.SKIN_PARTS).getRaw(); ++ } ++ ++ public MainHand getMainHand() { ++ return this.mainHand; ++ } ++ ++ public boolean hasMainHandChanged() { ++ return this.mainHand != this.player.getClientOption(ClientOption.MAIN_HAND); ++ } ++ ++ public boolean hasTextFilteringEnabled() { ++ return this.textFilteringEnabled; ++ } ++ ++ public boolean hasTextFilteringChanged() { ++ return this.textFilteringEnabled != this.player.getClientOption(ClientOption.TEXT_FILTERING_ENABLED); ++ } ++ ++ public boolean allowsServerListings() { ++ return this.allowsServerListings; ++ } ++ ++ public boolean hasAllowServerListingsChanged() { ++ return this.allowsServerListings != this.player.getClientOption(ClientOption.ALLOW_SERVER_LISTINGS); ++ } ++ ++ public ParticleVisibility getParticleVisibility() { ++ return this.particleVisibility; ++ } ++ ++ public boolean hasParticleVisibilityChanged() { ++ return this.particleVisibility != this.player.getClientOption(ClientOption.PARTICLE_VISIBILITY); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 70fef7c72b4ea24b8fd3bd99cb8f6f37b3b9832b..1a94a914894524b0087044227e9e692102e89e9e 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3375,6 +3375,13 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + void resetCooldown(); + // Paper end - attack cooldown API + ++ // Paper start - client option API ++ /** ++ * @return the client option value of the player ++ */ ++ @NotNull T getClientOption(com.destroystokyo.paper.@NotNull ClientOption option); ++ // Paper end - client option API ++ + // Spigot start + public class Spigot extends Entity.Spigot { + diff --git a/patches/api/0183-Increase-custom-payload-channel-message-size.patch b/patches/api/0183-Increase-custom-payload-channel-message-size.patch deleted file mode 100644 index 24aacd2b2970..000000000000 --- a/patches/api/0183-Increase-custom-payload-channel-message-size.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Fri, 18 Oct 2019 17:39:05 +0100 -Subject: [PATCH] Increase custom payload channel message size - -Doubles the custom payload size limit imposed by bukkit, also creates a system -property to allow customizing the size `paper.maxCustomChannelName` - -diff --git a/src/main/java/org/bukkit/plugin/messaging/Messenger.java b/src/main/java/org/bukkit/plugin/messaging/Messenger.java -index 9d2c68c826f3b867d407e7f13c6394a899cc8ee8..682c77188436d696d4dafbc70cf131d5c921e94d 100644 ---- a/src/main/java/org/bukkit/plugin/messaging/Messenger.java -+++ b/src/main/java/org/bukkit/plugin/messaging/Messenger.java -@@ -24,7 +24,7 @@ public interface Messenger { - /** - * Represents the largest size that a Plugin Channel may be. - */ -- public static final int MAX_CHANNEL_SIZE = 64; -+ public static final int MAX_CHANNEL_SIZE = Integer.getInteger("paper.maxCustomChannelName", 64); // Paper - - /** - * Checks if the specified channel is a reserved name. diff --git a/patches/api/0184-Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/api/0184-Add-PlayerAttackEntityCooldownResetEvent.patch new file mode 100644 index 000000000000..3d2999a705e9 --- /dev/null +++ b/patches/api/0184-Add-PlayerAttackEntityCooldownResetEvent.patch @@ -0,0 +1,89 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: nossr50 +Date: Thu, 26 Mar 2020 19:30:58 -0700 +Subject: [PATCH] Add PlayerAttackEntityCooldownResetEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2cd5c9c344cacbabe64dae8ec87babb506b5fb09 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java +@@ -0,0 +1,77 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when processing a player's attack on an entity when the player's attack strength cooldown is reset ++ */ ++@NullMarked ++public class PlayerAttackEntityCooldownResetEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Entity attackedEntity; ++ private final float cooledAttackStrength; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerAttackEntityCooldownResetEvent(final Player player, final Entity attackedEntity, final float cooledAttackStrength) { ++ super(player); ++ this.attackedEntity = attackedEntity; ++ this.cooledAttackStrength = cooledAttackStrength; ++ } ++ ++ /** ++ * Get the value of the players cooldown attack strength when they initiated the attack ++ * ++ * @return returns the original player cooldown value ++ */ ++ public float getCooledAttackStrength() { ++ return this.cooledAttackStrength; ++ } ++ ++ /** ++ * Returns the entity attacked by the player ++ * ++ * @return the entity attacked by the player ++ */ ++ public Entity getAttackedEntity() { ++ return this.attackedEntity; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * If an attack cooldown event is cancelled, the players attack strength will remain at the same value instead of being reset. ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * Cancelling this event will prevent the target player from having their cooldown reset from attacking this entity ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0184-Expose-the-internal-current-tick.patch b/patches/api/0184-Expose-the-internal-current-tick.patch deleted file mode 100644 index dc8b2199c921..000000000000 --- a/patches/api/0184-Expose-the-internal-current-tick.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 20 Apr 2019 19:47:29 -0500 -Subject: [PATCH] Expose the internal current tick - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 5f684c9ac218f105efe77ef08cae4b759868b0ea..fb5ba85b324eb78c31367bc59f2d1ca7eec1bf2b 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2276,6 +2276,10 @@ public final class Bukkit { - public static com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name) { - return server.createProfileExact(uuid, name); - } -+ -+ public static int getCurrentTick() { -+ return server.getCurrentTick(); -+ } - // Paper end - - @NotNull -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 1fecaed0b5774e3888bd1f5103828cc38f0265d9..05587286b253b6f877aa5fae19d556cc8967a326 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1977,5 +1977,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - */ - @NotNull - com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name); -+ -+ /** -+ * Get the current internal server tick -+ * -+ * @return Current tick -+ */ -+ int getCurrentTick(); - // Paper end - } diff --git a/patches/api/0185-Add-item-slot-convenience-methods.patch b/patches/api/0185-Add-item-slot-convenience-methods.patch new file mode 100644 index 000000000000..8da43fffbfaa --- /dev/null +++ b/patches/api/0185-Add-item-slot-convenience-methods.patch @@ -0,0 +1,330 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Sat, 25 Apr 2020 23:31:28 +0200 +Subject: [PATCH] Add item slot convenience methods + +Co-authored-by: Janet Blackquill + +diff --git a/src/main/java/org/bukkit/inventory/AnvilInventory.java b/src/main/java/org/bukkit/inventory/AnvilInventory.java +index 4f484df010dabf03ac4712996a0fd4d8f3649b59..f1f97a85ec713c05c882d7588f4a3e4a017f4795 100644 +--- a/src/main/java/org/bukkit/inventory/AnvilInventory.java ++++ b/src/main/java/org/bukkit/inventory/AnvilInventory.java +@@ -78,4 +78,64 @@ public interface AnvilInventory extends Inventory { + */ + @Deprecated(forRemoval = true, since = "1.21") + void setMaximumRepairCost(int levels); ++ ++ // Paper start ++ /** ++ * Gets the item in the left input slot. ++ * ++ * @return item in the first slot ++ */ ++ @Nullable ++ default ItemStack getFirstItem() { ++ return getItem(0); ++ } ++ ++ /** ++ * Sets the item in the left input slot. ++ * ++ * @param firstItem item to set ++ */ ++ default void setFirstItem(@Nullable ItemStack firstItem) { ++ setItem(0, firstItem); ++ } ++ ++ /** ++ * Gets the item in the right input slot. ++ * ++ * @return item in the second slot ++ */ ++ @Nullable ++ default ItemStack getSecondItem() { ++ return getItem(1); ++ } ++ ++ /** ++ * Sets the item in the right input slot. ++ * ++ * @param secondItem item to set ++ */ ++ default void setSecondItem(@Nullable ItemStack secondItem) { ++ setItem(1, secondItem); ++ } ++ ++ /** ++ * Gets the item in the result slot. ++ * ++ * @return item in the result slot ++ */ ++ @Nullable ++ default ItemStack getResult() { ++ return getItem(2); ++ } ++ ++ /** ++ * Sets the item in the result slot. ++ * Note that the client might not be able to take out the item if it does not match the input items. ++ * ++ * @param result item to set ++ */ ++ default void setResult(@Nullable ItemStack result) { ++ setItem(2, result); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/CartographyInventory.java b/src/main/java/org/bukkit/inventory/CartographyInventory.java +index 29c9b2682b92433f468d434d25d3c2495b5ac91b..d040ecea3a086711acbf5a852def090ba6c51fae 100644 +--- a/src/main/java/org/bukkit/inventory/CartographyInventory.java ++++ b/src/main/java/org/bukkit/inventory/CartographyInventory.java +@@ -3,4 +3,25 @@ package org.bukkit.inventory; + /** + * Interface to the inventory of a Cartography table. + */ +-public interface CartographyInventory extends Inventory { } ++public interface CartographyInventory extends Inventory { ++ // Paper begin - add getResult/setResult to CartographyInventory ++ /** ++ * Check what item is in the result slot of this smithing table. ++ * ++ * @return the result item ++ */ ++ @org.jetbrains.annotations.Nullable ++ default ItemStack getResult() { ++ return this.getItem(2); // net.minecraft.world.inventory.CartographyTableMenu.RESULT_SLOT ++ } ++ ++ /** ++ * Set the item in the result slot of the smithing table ++ * ++ * @param newResult the new result item ++ */ ++ default void setResult(final @org.jetbrains.annotations.Nullable ItemStack newResult) { ++ this.setItem(2, newResult); // net.minecraft.world.inventory.CartographyTableMenu.RESULT_SLOT ++ } ++ // Paper end - add getResult/setResult to CartographyInventory ++} +diff --git a/src/main/java/org/bukkit/inventory/GrindstoneInventory.java b/src/main/java/org/bukkit/inventory/GrindstoneInventory.java +index 9048892c8768c6b4d6cea03da73339f13bfbe82e..1c750108f55a0a31ad23433b333e0ea486a63ff2 100644 +--- a/src/main/java/org/bukkit/inventory/GrindstoneInventory.java ++++ b/src/main/java/org/bukkit/inventory/GrindstoneInventory.java +@@ -1,6 +1,68 @@ + package org.bukkit.inventory; + ++import org.jetbrains.annotations.Nullable; // Paper ++ + /** + * Interface to the inventory of a Grindstone. + */ +-public interface GrindstoneInventory extends Inventory { } ++public interface GrindstoneInventory extends Inventory { ++ ++ // Paper start ++ /** ++ * Gets the upper input item. ++ * ++ * @return upper input item ++ */ ++ @Nullable ++ default ItemStack getUpperItem() { ++ return getItem(0); ++ } ++ ++ /** ++ * Sets the upper input item. ++ * ++ * @param upperItem item to set ++ */ ++ default void setUpperItem(@Nullable ItemStack upperItem) { ++ setItem(0, upperItem); ++ } ++ ++ /** ++ * Gets the lower input item. ++ * ++ * @return lower input item ++ */ ++ @Nullable ++ default ItemStack getLowerItem() { ++ return getItem(1); ++ } ++ ++ /** ++ * Sets the lower input item. ++ * ++ * @param lowerItem item to set ++ */ ++ default void setLowerItem(@Nullable ItemStack lowerItem) { ++ setItem(1, lowerItem); ++ } ++ ++ /** ++ * Gets the result. ++ * ++ * @return result ++ */ ++ @Nullable ++ default ItemStack getResult() { ++ return getItem(2); ++ } ++ ++ /** ++ * Sets the result. ++ * ++ * @param result item to set ++ */ ++ default void setResult(@Nullable ItemStack result) { ++ setItem(2, result); ++ } ++ // Paper end ++} +diff --git a/src/main/java/org/bukkit/inventory/LecternInventory.java b/src/main/java/org/bukkit/inventory/LecternInventory.java +index 4a0c43acc2714e095973eb78536041bb1a179ddc..acf2244f77133df53eb5f862c8e713c85192f13d 100644 +--- a/src/main/java/org/bukkit/inventory/LecternInventory.java ++++ b/src/main/java/org/bukkit/inventory/LecternInventory.java +@@ -11,4 +11,25 @@ public interface LecternInventory extends Inventory { + @Nullable + @Override + public Lectern getHolder(); ++ ++ // Paper start ++ /** ++ * Gets the lectern's held book. ++ * ++ * @return book set in the lectern ++ */ ++ @Nullable ++ default ItemStack getBook() { ++ return getItem(0); ++ } ++ ++ /** ++ * Sets the lectern's held book. ++ * ++ * @param book the new book ++ */ ++ default void setBook(@Nullable ItemStack book) { ++ setItem(0, book); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/SmithingInventory.java b/src/main/java/org/bukkit/inventory/SmithingInventory.java +index 96d526b7b153e56c9a97de42ce3270b6638510e4..5ed72b7305428f6be98a86fa9aa174d1b8ad4c17 100644 +--- a/src/main/java/org/bukkit/inventory/SmithingInventory.java ++++ b/src/main/java/org/bukkit/inventory/SmithingInventory.java +@@ -30,4 +30,59 @@ public interface SmithingInventory extends Inventory { + */ + @Nullable + Recipe getRecipe(); ++ ++ // Paper start ++ /** ++ * Gets the input template (first slot). ++ * ++ * @return input template item ++ */ ++ default @Nullable ItemStack getInputTemplate() { ++ return this.getItem(0); ++ } ++ ++ /** ++ * Sets the input template (first slot). ++ * ++ * @param itemStack item to set ++ */ ++ default void setInputTemplate(@Nullable ItemStack itemStack) { ++ this.setItem(0, itemStack); ++ } ++ /** ++ * Gets the input equipment (second slot). ++ * ++ * @return input equipment item ++ */ ++ default @Nullable ItemStack getInputEquipment() { ++ return this.getItem(1); ++ } ++ ++ /** ++ * Sets the input equipment (second slot). ++ * ++ * @param itemStack item to set ++ */ ++ default void setInputEquipment(@Nullable ItemStack itemStack) { ++ this.setItem(1, itemStack); ++ } ++ ++ /** ++ * Gets the input mineral (third slot). ++ * ++ * @return input mineral item ++ */ ++ default @Nullable ItemStack getInputMineral() { ++ return this.getItem(2); ++ } ++ ++ /** ++ * Sets the input mineral (third slot). ++ * ++ * @param itemStack item to set ++ */ ++ default void setInputMineral(@Nullable ItemStack itemStack) { ++ this.setItem(2, itemStack); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/StonecutterInventory.java b/src/main/java/org/bukkit/inventory/StonecutterInventory.java +index dbb034fae3b8bfaf40e6341460e274c21e321a3b..e7a8e7188bf8b9840de56dc80c2b79d64a9389cb 100644 +--- a/src/main/java/org/bukkit/inventory/StonecutterInventory.java ++++ b/src/main/java/org/bukkit/inventory/StonecutterInventory.java +@@ -1,6 +1,49 @@ + package org.bukkit.inventory; + ++import org.jetbrains.annotations.Nullable; // Paper ++ + /** + * Interface to the inventory of a Stonecutter. + */ +-public interface StonecutterInventory extends Inventory { } ++public interface StonecutterInventory extends Inventory { ++ ++ // Paper start ++ /** ++ * Gets the input item. ++ * ++ * @return input item ++ */ ++ @Nullable ++ default ItemStack getInputItem() { ++ return getItem(0); ++ } ++ ++ /** ++ * Sets the input item. ++ * ++ * @param itemStack item to set ++ */ ++ default void setInputItem(@Nullable ItemStack itemStack) { ++ setItem(0, itemStack); ++ } ++ ++ /** ++ * Gets the result item. ++ * ++ * @return result ++ */ ++ @Nullable ++ default ItemStack getResult() { ++ return getItem(1); ++ } ++ ++ /** ++ * Sets the result item. ++ * ++ * @param itemStack item to set ++ */ ++ default void setResult(@Nullable ItemStack itemStack) { ++ setItem(1, itemStack); ++ } ++ // Paper end ++} diff --git a/patches/api/0185-PlayerDeathEvent-shouldDropExperience.patch b/patches/api/0185-PlayerDeathEvent-shouldDropExperience.patch deleted file mode 100644 index 056104652083..000000000000 --- a/patches/api/0185-PlayerDeathEvent-shouldDropExperience.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Tue, 24 Dec 2019 00:35:31 +0000 -Subject: [PATCH] PlayerDeathEvent#shouldDropExperience - - -diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -index 5f7d0d08be8bca06c9aa89659b7865a7b5a547f8..9d95218b49895ab76b00fe9524d9b25ea9f9b8c2 100644 ---- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -+++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java -@@ -1,6 +1,8 @@ - package org.bukkit.event.entity; - - import java.util.List; -+ -+import org.bukkit.GameMode; - import org.bukkit.entity.Player; - import org.bukkit.inventory.ItemStack; - import org.jetbrains.annotations.NotNull; -@@ -18,6 +20,8 @@ public class PlayerDeathEvent extends EntityDeathEvent { - private boolean keepLevel = false; - private boolean keepInventory = false; - // Paper start -+ private boolean doExpDrop; -+ - public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, @Nullable final net.kyori.adventure.text.Component adventure$deathMessage) { - this(player, drops, droppedExp, 0, adventure$deathMessage, null); - } -@@ -27,12 +31,17 @@ public class PlayerDeathEvent extends EntityDeathEvent { - } - - public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final net.kyori.adventure.text.Component adventure$deathMessage, @Nullable String deathMessage) { -+ this(player, drops, droppedExp, newExp, newTotalExp, newLevel, adventure$deathMessage, deathMessage, true); -+ } -+ -+ public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final net.kyori.adventure.text.Component adventure$deathMessage, @Nullable String deathMessage, boolean doExpDrop) { - super(player, drops, droppedExp); - this.newExp = newExp; - this.newTotalExp = newTotalExp; - this.newLevel = newLevel; - this.deathMessage = deathMessage; - this.adventure$deathMessage = adventure$deathMessage; -+ this.doExpDrop = doExpDrop; - } - // Paper end - -@@ -47,6 +56,11 @@ public class PlayerDeathEvent extends EntityDeathEvent { - - @Deprecated // Paper - public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final String deathMessage) { -+ this(player, drops, droppedExp, newExp, newTotalExp, newLevel, deathMessage, true); -+ } -+ -+ @Deprecated // Paper -+ public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final String deathMessage, boolean doExpDrop) { - super(player, drops, droppedExp); - this.newExp = newExp; - this.newTotalExp = newTotalExp; -@@ -88,6 +102,20 @@ public class PlayerDeathEvent extends EntityDeathEvent { - public List getItemsToKeep() { - return itemsToKeep; - } -+ -+ /** -+ * @return should experience be dropped from this death -+ */ -+ public boolean shouldDropExperience() { -+ return doExpDrop; -+ } -+ -+ /** -+ * @param doExpDrop sets if experience should be dropped from this death -+ */ -+ public void setShouldDropExperience(boolean doExpDrop) { -+ this.doExpDrop = doExpDrop; -+ } - // Paper end - - @NotNull diff --git a/patches/api/0186-Add-effect-to-block-break-naturally.patch b/patches/api/0186-Add-effect-to-block-break-naturally.patch deleted file mode 100644 index 81c136c000b0..000000000000 --- a/patches/api/0186-Add-effect-to-block-break-naturally.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 2 Jan 2020 12:25:16 -0600 -Subject: [PATCH] Add effect to block break naturally - - -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index db441e463b02ee734f85c855f5538cd41041dbae..1e7ee68e56f8d4399c2cbf26aa45bf8b599b3b02 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -480,6 +480,26 @@ public interface Block extends Metadatable { - */ - boolean breakNaturally(@Nullable ItemStack tool); - -+ // Paper start -+ /** -+ * Breaks the block and spawns item drops as if a player had broken it -+ * -+ * @param triggerEffect Play the block break particle effect and sound -+ * @return true if the block was destroyed -+ */ -+ boolean breakNaturally(boolean triggerEffect); -+ -+ /** -+ * Breaks the block and spawns item drops as if a player had broken it -+ * with a specific tool -+ * -+ * @param tool The tool or item in hand used for digging -+ * @param triggerEffect Play the block break particle effect and sound -+ * @return true if the block was destroyed -+ */ -+ boolean breakNaturally(@NotNull ItemStack tool, boolean triggerEffect); -+ // Paper end -+ - /** - * Simulate bone meal application to this block (if possible). - * diff --git a/patches/api/0186-Villager-Restocks-API.patch b/patches/api/0186-Villager-Restocks-API.patch new file mode 100644 index 000000000000..66dc60c254fc --- /dev/null +++ b/patches/api/0186-Villager-Restocks-API.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: zbk +Date: Sun, 26 Apr 2020 23:49:03 -0400 +Subject: [PATCH] Villager Restocks API + + +diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java +index af4582f3e4687933dac6ccd43667a373f8daedb6..5a61175ccfe67c0a3c55cc2b84772fa8f6e6a6cb 100644 +--- a/src/main/java/org/bukkit/entity/Villager.java ++++ b/src/main/java/org/bukkit/entity/Villager.java +@@ -82,6 +82,20 @@ public interface Villager extends AbstractVillager { + */ + public void setVillagerExperience(int experience); + ++ // Paper start ++ /** ++ * Gets the amount of times a villager has restocked their trades today ++ * @return The amount of trade restocks. ++ */ ++ public int getRestocksToday(); ++ ++ /** ++ * Sets the amount of times a villager has restocked their trades today ++ * @param restocksToday new restock count ++ */ ++ public void setRestocksToday(int restocksToday); ++ // Paper end ++ + /** + * Attempts to make this villager sleep at the given location. + *
      diff --git a/patches/api/0187-Add-Mob-Goal-API.patch b/patches/api/0187-Add-Mob-Goal-API.patch new file mode 100644 index 000000000000..9fe67d644113 --- /dev/null +++ b/patches/api/0187-Add-Mob-Goal-API.patch @@ -0,0 +1,250 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger +Date: Fri, 3 Jan 2020 16:24:46 +0100 +Subject: [PATCH] Add Mob Goal API + + +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java +new file mode 100644 +index 0000000000000000000000000000000000000000..88f64a84c6b81246a4936e37c9f0410eefc847fd +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java +@@ -0,0 +1,63 @@ ++package com.destroystokyo.paper.entity.ai; ++ ++import java.util.EnumSet; ++import org.bukkit.entity.Mob; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents an AI goal of an entity ++ */ ++@NullMarked ++public interface Goal { ++ ++ /** ++ * Checks if this goal should be activated ++ * ++ * @return if this goal should be activated ++ */ ++ boolean shouldActivate(); ++ ++ /** ++ * Checks if this goal should stay active, defaults to {@link Goal#shouldActivate()} ++ * ++ * @return if this goal should stay active ++ */ ++ default boolean shouldStayActive() { ++ return this.shouldActivate(); ++ } ++ ++ /** ++ * Called when this goal gets activated ++ */ ++ default void start() { ++ } ++ ++ /** ++ * Called when this goal gets stopped ++ */ ++ default void stop() { ++ } ++ ++ /** ++ * Called each tick the goal is activated ++ */ ++ default void tick() { ++ } ++ ++ /** ++ * A unique key that identifies this type of goal. Plugins should use their own namespace, not the minecraft ++ * namespace. Additionally, this key also specifies to what mobs this goal can be applied to ++ * ++ * @return the goal key ++ */ ++ GoalKey getKey(); ++ ++ /** ++ * Returns a list of all applicable flags for this goal.
      ++ *

      ++ * This method is only called on construction. ++ * ++ * @return the subtypes. ++ */ ++ EnumSet getTypes(); ++} +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fb626065c642a3f43075f2ae751419e23431763c +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java +@@ -0,0 +1,59 @@ ++package com.destroystokyo.paper.entity.ai; ++ ++import com.google.common.base.Objects; ++import java.util.StringJoiner; ++import org.bukkit.NamespacedKey; ++import org.bukkit.entity.Mob; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Used to identify a Goal. Consists of a {@link NamespacedKey} and the type of mob the goal can be applied to ++ * ++ * @param the type of mob the goal can be applied to ++ */ ++@NullMarked ++public final class GoalKey { ++ ++ private final Class entityClass; ++ private final NamespacedKey namespacedKey; ++ ++ private GoalKey(Class entityClass, NamespacedKey namespacedKey) { ++ this.entityClass = entityClass; ++ this.namespacedKey = namespacedKey; ++ } ++ ++ public Class getEntityClass() { ++ return this.entityClass; ++ } ++ ++ public NamespacedKey getNamespacedKey() { ++ return this.namespacedKey; ++ } ++ ++ @Override ++ public boolean equals(@Nullable Object o) { ++ if (this == o) return true; ++ if (o == null || this.getClass() != o.getClass()) return false; ++ GoalKey goalKey = (GoalKey) o; ++ return Objects.equal(this.entityClass, goalKey.entityClass) && ++ Objects.equal(this.namespacedKey, goalKey.namespacedKey); ++ } ++ ++ @Override ++ public int hashCode() { ++ return Objects.hashCode(this.entityClass, this.namespacedKey); ++ } ++ ++ @Override ++ public String toString() { ++ return new StringJoiner(", ", GoalKey.class.getSimpleName() + "[", "]") ++ .add("entityClass=" + this.entityClass) ++ .add("namespacedKey=" + this.namespacedKey) ++ .toString(); ++ } ++ ++ public static GoalKey of(Class entityClass, NamespacedKey namespacedKey) { ++ return new GoalKey<>(entityClass, namespacedKey); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java b/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7024c8f484d2460abf3abfe65a29771d814105ec +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java +@@ -0,0 +1,17 @@ ++package com.destroystokyo.paper.entity.ai; ++ ++/** ++ * Represents the subtype of a goal. Used by minecraft to disable certain types of goals if needed. ++ */ ++public enum GoalType { ++ ++ MOVE, ++ LOOK, ++ JUMP, ++ TARGET, ++ /** ++ * Used to map vanilla goals, that are a behavior goal but don't have a type set... ++ */ ++ UNKNOWN_BEHAVIOR, ++ ++} +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0203e7efbb8c729ed378c53c2630a523b697314f +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java +@@ -0,0 +1,42 @@ ++package com.destroystokyo.paper.entity.ai; ++ ++ ++import java.util.Collection; ++import org.bukkit.entity.Mob; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Represents a part of the "brain" of a mob. It tracks all tasks (running or not), allows adding and removing goals ++ */ ++@NullMarked ++public interface MobGoals { ++ ++ void addGoal(T mob, int priority, Goal goal); ++ ++ void removeGoal(T mob, Goal goal); ++ ++ void removeAllGoals(T mob); ++ ++ void removeAllGoals(T mob, GoalType type); ++ ++ void removeGoal(T mob, GoalKey key); ++ ++ boolean hasGoal(T mob, GoalKey key); ++ ++ @Nullable Goal getGoal(T mob, GoalKey key); ++ ++ Collection> getGoals(T mob, GoalKey key); ++ ++ Collection> getAllGoals(T mob); ++ ++ Collection> getAllGoals(T mob, GoalType type); ++ ++ Collection> getAllGoalsWithout(T mob, GoalType type); ++ ++ Collection> getRunningGoals(T mob); ++ ++ Collection> getRunningGoals(T mob, GoalType type); ++ ++ Collection> getRunningGoalsWithout(T mob, GoalType type); ++} +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 40d04b4ebecaa0cff8937451568d998a0dfae088..aca049c29cc7397a830883a45b4b24a33863e533 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2584,6 +2584,16 @@ public final class Bukkit { + public static boolean isStopping() { + return server.isStopping(); + } ++ ++ /** ++ * Returns the {@link com.destroystokyo.paper.entity.ai.MobGoals} manager ++ * ++ * @return the mob goals manager ++ */ ++ @NotNull ++ public static com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { ++ return server.getMobGoals(); ++ } + // Paper end + + @NotNull +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 90509d2e4c61de29611312c0864ef7622072d540..89208165cc6b864a9273c364ba4b2d6d86e3c31f 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2250,5 +2250,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @return true if server is in the process of being shutdown + */ + boolean isStopping(); ++ ++ /** ++ * Returns the {@link com.destroystokyo.paper.entity.ai.MobGoals} manager ++ * ++ * @return the mob goals manager ++ */ ++ @NotNull ++ com.destroystokyo.paper.entity.ai.MobGoals getMobGoals(); + // Paper end + } diff --git a/patches/api/0187-Add-ThrownEggHatchEvent.patch b/patches/api/0187-Add-ThrownEggHatchEvent.patch deleted file mode 100644 index f605a2a11b28..000000000000 --- a/patches/api/0187-Add-ThrownEggHatchEvent.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 9 Feb 2020 00:19:08 -0600 -Subject: [PATCH] Add ThrownEggHatchEvent - -Adds a new event similar to PlayerEggThrowEvent, but without the Player requirement -(dispensers can throw eggs to hatch them, too). - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..085d77dde83d6ed13eb83f23cf3e51d380187c9c ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/ThrownEggHatchEvent.java -@@ -0,0 +1,115 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.Egg; -+import org.bukkit.entity.EntityType; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a thrown egg might hatch. -+ *

      -+ * This event fires for all thrown eggs that may hatch, players, dispensers, etc. -+ */ -+public class ThrownEggHatchEvent extends Event { -+ private static final HandlerList handlers = new HandlerList(); -+ private final Egg egg; -+ private boolean hatching; -+ private EntityType hatchType; -+ private byte numHatches; -+ -+ public ThrownEggHatchEvent(@NotNull final Egg egg, final boolean hatching, final byte numHatches, @NotNull final EntityType hatchingType) { -+ this.egg = egg; -+ this.hatching = hatching; -+ this.numHatches = numHatches; -+ this.hatchType = hatchingType; -+ } -+ -+ /** -+ * Gets the egg involved in this event. -+ * -+ * @return the egg involved in this event -+ */ -+ @NotNull -+ public Egg getEgg() { -+ return egg; -+ } -+ -+ /** -+ * Gets whether the egg is hatching or not. Will be what the server -+ * would've done without interaction. -+ * -+ * @return boolean Whether the egg is going to hatch or not -+ */ -+ public boolean isHatching() { -+ return hatching; -+ } -+ -+ /** -+ * Sets whether the egg will hatch or not. -+ * -+ * @param hatching true if you want the egg to hatch, false if you want it -+ * not to -+ */ -+ public void setHatching(boolean hatching) { -+ this.hatching = hatching; -+ } -+ -+ /** -+ * Get the type of the mob being hatched (EntityType.CHICKEN by default) -+ * -+ * @return The type of the mob being hatched by the egg -+ */ -+ @NotNull -+ public EntityType getHatchingType() { -+ return hatchType; -+ } -+ -+ /** -+ * Change the type of mob being hatched by the egg -+ * -+ * @param hatchType The type of the mob being hatched by the egg -+ */ -+ public void setHatchingType(@NotNull EntityType hatchType) { -+ if (!hatchType.isSpawnable()) throw new IllegalArgumentException("Can't spawn that entity type from an egg!"); -+ this.hatchType = hatchType; -+ } -+ -+ /** -+ * Get the number of mob hatches from the egg. By default the number will -+ * be the number the server would've done -+ *

      -+ * -+ * @return The number of mobs going to be hatched by the egg -+ */ -+ public byte getNumHatches() { -+ return numHatches; -+ } -+ -+ /** -+ * Change the number of mobs coming out of the hatched egg -+ *

      -+ * The boolean hatching will override this number. Ie. If hatching = -+ * false, this number will not matter -+ * -+ * @param numHatches The number of mobs coming out of the egg -+ */ -+ public void setNumHatches(byte numHatches) { -+ this.numHatches = numHatches; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0188-Add-villager-reputation-API.patch b/patches/api/0188-Add-villager-reputation-API.patch new file mode 100644 index 000000000000..b9fa646f28ca --- /dev/null +++ b/patches/api/0188-Add-villager-reputation-API.patch @@ -0,0 +1,174 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Wed, 22 Apr 2020 23:13:49 +0200 +Subject: [PATCH] Add villager reputation API + + +diff --git a/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java b/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cbbf70507c2df922e75b686c36500f6f85f92db6 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java +@@ -0,0 +1,56 @@ ++package com.destroystokyo.paper.entity.villager; ++ ++import com.google.common.base.Preconditions; ++import java.util.EnumMap; ++import java.util.Map; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A reputation score for a player on a villager. ++ */ ++@NullMarked ++public final class Reputation { ++ ++ private final Map reputation; ++ ++ public Reputation() { ++ this(new EnumMap<>(ReputationType.class)); ++ } ++ ++ public Reputation(final Map reputation) { ++ Preconditions.checkNotNull(reputation, "reputation cannot be null"); ++ this.reputation = reputation; ++ } ++ ++ /** ++ * Gets the reputation value for a specific {@link ReputationType}. ++ * ++ * @param type The {@link ReputationType type} of reputation to get. ++ * @return The value of the {@link ReputationType type}. ++ */ ++ public int getReputation(final ReputationType type) { ++ Preconditions.checkNotNull(type, "the reputation type cannot be null"); ++ return this.reputation.getOrDefault(type, 0); ++ } ++ ++ /** ++ * Sets the reputation value for a specific {@link ReputationType}. ++ * ++ * @param type The {@link ReputationType type} of reputation to set. ++ * @param value The value of the {@link ReputationType type}. ++ */ ++ public void setReputation(final ReputationType type, final int value) { ++ Preconditions.checkNotNull(type, "the reputation type cannot be null"); ++ this.reputation.put(type, value); ++ } ++ ++ /** ++ * Gets if a reputation value is currently set for a specific {@link ReputationType}. ++ * ++ * @param type The {@link ReputationType type} to check ++ * @return If there is a value for this {@link ReputationType type} set. ++ */ ++ public boolean hasReputationSet(final ReputationType type) { ++ return this.reputation.containsKey(type); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/entity/villager/ReputationType.java b/src/main/java/com/destroystokyo/paper/entity/villager/ReputationType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5600fcdc9795a9f49091db48d73bbd4964b8b737 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/villager/ReputationType.java +@@ -0,0 +1,36 @@ ++package com.destroystokyo.paper.entity.villager; ++ ++/** ++ * A type of reputation gained with a {@link org.bukkit.entity.Villager Villager}. ++ *

      ++ * All types but {@link #MAJOR_POSITIVE} are shared to other villagers. ++ */ ++public enum ReputationType { ++ /** ++ * A gossip with a majorly negative effect. This is only gained through killing a nearby ++ * villager. ++ */ ++ MAJOR_NEGATIVE, ++ ++ /** ++ * A gossip with a minor negative effect. This is only gained through damaging a villager. ++ */ ++ MINOR_NEGATIVE, ++ ++ /** ++ * A gossip with a minor positive effect. This is only gained through curing a zombie ++ * villager. ++ */ ++ MINOR_POSITIVE, ++ ++ /** ++ * A gossip with a major positive effect. This is only gained through curing a zombie ++ * villager. ++ */ ++ MAJOR_POSITIVE, ++ ++ /** ++ * A gossip with a minor positive effect. This is only gained through trading with a villager. ++ */ ++ TRADING, ++} +diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java +index 5a61175ccfe67c0a3c55cc2b84772fa8f6e6a6cb..98a7c5c549e797100f6aaf440606ef31a2be1e3b 100644 +--- a/src/main/java/org/bukkit/entity/Villager.java ++++ b/src/main/java/org/bukkit/entity/Villager.java +@@ -3,6 +3,8 @@ package org.bukkit.entity; + import com.google.common.base.Preconditions; + import com.google.common.collect.Lists; + import java.util.Locale; ++import java.util.Map; // Paper ++import java.util.UUID; // Paper + import org.bukkit.Keyed; + import org.bukkit.Location; + import org.bukkit.NamespacedKey; +@@ -281,4 +283,50 @@ public interface Villager extends AbstractVillager { + return Lists.newArrayList(Registry.VILLAGER_PROFESSION).toArray(new Profession[0]); + } + } ++ ++ // Paper start - Add villager reputation API ++ /** ++ * Get the {@link com.destroystokyo.paper.entity.villager.Reputation reputation} ++ * for a specific player by {@link UUID}. ++ * ++ * @param uniqueId The {@link UUID} of the player to get the reputation of. ++ * @return The player's copied reputation with this villager. ++ */ ++ @NotNull ++ public com.destroystokyo.paper.entity.villager.Reputation getReputation(@NotNull UUID uniqueId); ++ ++ /** ++ * Get all {@link com.destroystokyo.paper.entity.villager.Reputation reputations} ++ * for all players mapped by their {@link UUID unique IDs}. ++ * ++ * @return All {@link com.destroystokyo.paper.entity.villager.Reputation reputations} for all players ++ * in a copied map. ++ */ ++ @NotNull ++ public Map getReputations(); ++ ++ /** ++ * Set the {@link com.destroystokyo.paper.entity.villager.Reputation reputation} ++ * for a specific player by {@link UUID}. ++ * ++ * @param uniqueId The {@link UUID} of the player to set the reputation of. ++ * @param reputation The {@link com.destroystokyo.paper.entity.villager.Reputation reputation} to set. ++ */ ++ public void setReputation(@NotNull UUID uniqueId, @NotNull com.destroystokyo.paper.entity.villager.Reputation reputation); ++ ++ /** ++ * Set all {@link com.destroystokyo.paper.entity.villager.Reputation reputations} ++ * for all players mapped by their {@link UUID unique IDs}. ++ * ++ * @param reputations All {@link com.destroystokyo.paper.entity.villager.Reputation reputations} ++ * for all players mapped by their {@link UUID unique IDs}. ++ */ ++ public void setReputations(@NotNull Map reputations); ++ ++ /** ++ * Clear all reputations from this villager. This removes every single ++ * reputation regardless of its impact and the player associated. ++ */ ++ public void clearReputations(); ++ // Paper end + } diff --git a/patches/api/0188-Entity-Jump-API.patch b/patches/api/0188-Entity-Jump-API.patch deleted file mode 100644 index 41a503617afd..000000000000 --- a/patches/api/0188-Entity-Jump-API.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 8 Feb 2020 23:26:18 -0600 -Subject: [PATCH] Entity Jump API - - -diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f0067c2e953d18e1a33536980071ba3f0152ecb4 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityJumpEvent.java -@@ -0,0 +1,46 @@ -+package com.destroystokyo.paper.event.entity; -+ -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when an entity jumps -+ *

      -+ * Cancelling the event will stop the entity from jumping -+ */ -+public class EntityJumpEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean canceled; -+ -+ public EntityJumpEvent(@NotNull LivingEntity entity) { -+ super(entity); -+ } -+ -+ @NotNull -+ @Override -+ public LivingEntity getEntity() { -+ return (LivingEntity) entity; -+ } -+ -+ public boolean isCancelled() { -+ return canceled; -+ } -+ -+ public void setCancelled(boolean cancel) { -+ canceled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index f479e8c26e88520a47f7beeec753b3af9978bde1..c11de6fbaa6fce8b341ac6c4d9478c18481cc0ef 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -801,5 +801,25 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - */ - @NotNull - org.bukkit.inventory.EquipmentSlot getHandRaised(); -+ -+ /** -+ * Get entity jump state. -+ *

      -+ * Jump state will be true when the entity has been marked to jump. -+ * -+ * @return entity jump state. -+ */ -+ boolean isJumping(); -+ -+ /** -+ * Set entity jump state -+ *

      -+ * Setting to true will mark the entity to jump. -+ *

      -+ * Setting to false will unmark the entity to jump but will not stop a jump already in-progress. -+ * -+ * @param jumping entity jump state -+ */ -+ void setJumping(boolean jumping); - // Paper end - } diff --git a/patches/api/0189-Spawn-Reason-API.patch b/patches/api/0189-Spawn-Reason-API.patch new file mode 100644 index 000000000000..97edb6ab3ffe --- /dev/null +++ b/patches/api/0189-Spawn-Reason-API.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 10 Apr 2014 23:18:28 -0400 +Subject: [PATCH] Spawn Reason API + + +diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java +index 458119a9ef7ce8e1f59bd47caa5b4bc698715440..316d04db78c23ec236cc6f8d5c17e328cbd8ec75 100644 +--- a/src/main/java/org/bukkit/RegionAccessor.java ++++ b/src/main/java/org/bukkit/RegionAccessor.java +@@ -326,8 +326,31 @@ public interface RegionAccessor { + * @throws IllegalArgumentException if either parameter is null or the + * {@link Entity} requested cannot be spawned + */ +- @NotNull +- T spawn(@NotNull Location location, @NotNull Class clazz, @Nullable Consumer function) throws IllegalArgumentException; ++ // Paper start ++ default @NotNull T spawn(final @NotNull Location location, final @NotNull Class clazz, final @Nullable Consumer function) throws IllegalArgumentException { ++ return this.spawn(location, clazz, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CUSTOM, function); ++ } ++ ++ default @NotNull T spawn(final @NotNull Location location, final @NotNull Class clazz, final org.bukkit.event.entity.CreatureSpawnEvent.@NotNull SpawnReason reason) throws IllegalArgumentException { ++ return this.spawn(location, clazz, reason, null); ++ } ++ ++ default @NotNull T spawn(final @NotNull Location location, final @NotNull Class clazz, final org.bukkit.event.entity.CreatureSpawnEvent.@NotNull SpawnReason reason, final @Nullable Consumer function) throws IllegalArgumentException { ++ return this.spawn(location, clazz, function, reason); ++ } ++ ++ default @NotNull Entity spawnEntity(final @NotNull Location loc, final @NotNull EntityType type, final org.bukkit.event.entity.CreatureSpawnEvent.@NotNull SpawnReason reason) { ++ com.google.common.base.Preconditions.checkArgument(type.getEntityClass() != null, "%s is not a valid EntityType, must have an entity class", type); ++ return this.spawn(loc, type.getEntityClass(), reason, null); ++ } ++ ++ default @NotNull Entity spawnEntity(final @NotNull Location loc, final @NotNull EntityType type, final org.bukkit.event.entity.CreatureSpawnEvent.@NotNull SpawnReason reason, final @Nullable Consumer function) { ++ com.google.common.base.Preconditions.checkArgument(type.getEntityClass() != null, "%s is not a valid EntityType, must have an entity class", type); ++ return this.spawn(loc, type.getEntityClass(), reason, function); ++ } ++ ++ @NotNull T spawn(@NotNull Location location, @NotNull Class clazz, @Nullable Consumer function, org.bukkit.event.entity.CreatureSpawnEvent.@NotNull SpawnReason reason) throws IllegalArgumentException; ++ // Paper end + + /** + * Creates a new entity at the given {@link Location} with the supplied diff --git a/patches/api/0190-Add-tick-times-API.patch b/patches/api/0190-Add-tick-times-API.patch deleted file mode 100644 index 4d0f9baea5d9..000000000000 --- a/patches/api/0190-Add-tick-times-API.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 5 Apr 2020 22:22:58 -0500 -Subject: [PATCH] Add tick times API - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 9e33d1a649118613cb28c97a895872949b3bb05b..95c4e23ece5f7bdf814d4259dc89016cd96a0a2f 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -1948,6 +1948,25 @@ public final class Bukkit { - public static double[] getTPS() { - return server.getTPS(); - } -+ -+ /** -+ * Get a sample of the servers last tick times (in nanos) -+ * -+ * @return A sample of the servers last tick times (in nanos) -+ */ -+ @NotNull -+ public static long[] getTickTimes() { -+ return server.getTickTimes(); -+ } -+ -+ /** -+ * Get the average tick time (in millis) -+ * -+ * @return Average tick time (in millis) -+ */ -+ public static double getAverageTickTime() { -+ return server == null ? 0D : server.getAverageTickTime(); -+ } - // Paper end - - /** -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 16db591ecb07a238a5bd14c13192198086bda13d..11b281b43e4fd2a23116163e611f11aad179b8fa 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1639,6 +1639,21 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - */ - @NotNull - public double[] getTPS(); -+ -+ /** -+ * Get a sample of the servers last tick times (in nanos) -+ * -+ * @return A sample of the servers last tick times (in nanos) -+ */ -+ @NotNull -+ long[] getTickTimes(); -+ -+ /** -+ * Get the average tick time (in millis) -+ * -+ * @return Average tick time (in millis) -+ */ -+ double getAverageTickTime(); - // Paper end - - // Paper start diff --git a/patches/api/0190-Potential-bed-API.patch b/patches/api/0190-Potential-bed-API.patch new file mode 100644 index 000000000000..7a11d211bc8e --- /dev/null +++ b/patches/api/0190-Potential-bed-API.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Sun, 10 May 2020 23:06:41 -0400 +Subject: [PATCH] Potential bed API + +Adds a new method to fetch the location of a player's bed without generating any sync loads. + +getPotentialBedLocation - Gets the last known location of a player's bed. This does not preform any check if the bed is still valid and does not load any chunks. + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index a7824c9f133f433cb9f98326348b4b6ae725a39d..d87261e0500d34696a50e9d6d136ca844c9a2cea 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -308,6 +308,19 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder + */ + public int getSleepTicks(); + ++ ++ // Paper start - Potential bed api ++ /** ++ * Gets the Location of the player's bed, null if they have not slept ++ * in one. This method will not attempt to validate if the current bed ++ * is still valid. ++ * ++ * @return Bed Location if has slept in one, otherwise null. ++ */ ++ @Nullable ++ public Location getPotentialBedLocation(); ++ // Paper end ++ + /** + * Attempts to make the entity sleep at the given location. + *
      diff --git a/patches/api/0191-Expose-MinecraftServer-isRunning.patch b/patches/api/0191-Expose-MinecraftServer-isRunning.patch deleted file mode 100644 index 844c2aff6b69..000000000000 --- a/patches/api/0191-Expose-MinecraftServer-isRunning.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Fri, 10 Apr 2020 21:24:35 -0400 -Subject: [PATCH] Expose MinecraftServer#isRunning - -This allows for plugins to detect if the server is actually turning off in onDisable rather than just plugins reloading. - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 4ba11b4a22981472e3fcbfe8ffadaa3f3c140e2f..88fe6c7dabdcf5c1a81126e7c98a361ec25438a0 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2299,6 +2299,15 @@ public final class Bukkit { - public static int getCurrentTick() { - return server.getCurrentTick(); - } -+ -+ /** -+ * Checks if the server is in the process of being shutdown. -+ * -+ * @return true if server is in the process of being shutdown -+ */ -+ public static boolean isStopping() { -+ return server.isStopping(); -+ } - // Paper end - - @NotNull -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index a4775467581c351f4c89521c2e017b31d48bf3b5..8cf4a6d82278770598dee9191409c676b7fb1b08 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1999,5 +1999,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * @return Current tick - */ - int getCurrentTick(); -+ -+ /** -+ * Checks if the server is in the process of being shutdown. -+ * -+ * @return true if server is in the process of being shutdown -+ */ -+ boolean isStopping(); - // Paper end - } diff --git a/patches/api/0191-Inventory-getHolder-method-without-block-snapshot.patch b/patches/api/0191-Inventory-getHolder-method-without-block-snapshot.patch new file mode 100644 index 000000000000..d834d6cdb338 --- /dev/null +++ b/patches/api/0191-Inventory-getHolder-method-without-block-snapshot.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 +Date: Wed, 10 Jun 2020 23:55:16 +0100 +Subject: [PATCH] Inventory getHolder method without block snapshot + + +diff --git a/src/main/java/org/bukkit/block/DoubleChest.java b/src/main/java/org/bukkit/block/DoubleChest.java +index 83a4642119c3f33749e04c774cf2b39839f797e2..a39d2f1acbbd84ae0e2cf29f85594e09e55e9355 100644 +--- a/src/main/java/org/bukkit/block/DoubleChest.java ++++ b/src/main/java/org/bukkit/block/DoubleChest.java +@@ -34,6 +34,18 @@ public class DoubleChest implements InventoryHolder { + return inventory.getRightSide().getHolder(); + } + ++ // Paper start - getHolder without snapshot ++ @Nullable ++ public InventoryHolder getLeftSide(boolean useSnapshot) { ++ return inventory.getLeftSide().getHolder(useSnapshot); ++ } ++ ++ @Nullable ++ public InventoryHolder getRightSide(boolean useSnapshot) { ++ return inventory.getRightSide().getHolder(useSnapshot); ++ } ++ // Paper end ++ + @NotNull + public Location getLocation() { + return getInventory().getLocation(); +diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/org/bukkit/inventory/Inventory.java +index 466d1bd7089b76f48f953e1a51c611ecd93dcd54..129b5ab5062beeb9bb52465a788bc3a3aee9c49e 100644 +--- a/src/main/java/org/bukkit/inventory/Inventory.java ++++ b/src/main/java/org/bukkit/inventory/Inventory.java +@@ -385,6 +385,17 @@ public interface Inventory extends Iterable { + @Nullable + public InventoryHolder getHolder(); + ++ // Paper start - getHolder without snapshot ++ /** ++ * Gets the block or entity belonging to the open inventory ++ * ++ * @param useSnapshot Create a snapshot if the holder is a tile entity ++ * @return The holder of the inventory; null if it has no holder. ++ */ ++ @Nullable ++ public InventoryHolder getHolder(boolean useSnapshot); ++ // Paper end ++ + @NotNull + @Override + public ListIterator iterator(); diff --git a/patches/api/0192-Add-Raw-Byte-ItemStack-Serialization.patch b/patches/api/0192-Add-Raw-Byte-ItemStack-Serialization.patch deleted file mode 100644 index ffc54997ee7f..000000000000 --- a/patches/api/0192-Add-Raw-Byte-ItemStack-Serialization.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Thu, 30 Apr 2020 16:56:31 +0200 -Subject: [PATCH] Add Raw Byte ItemStack Serialization - -Serializes using NBT which is safer for server data migrations than bukkits format. - -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index cbf7df30a7ec8445c8492e3b9f108747dbe1717b..1b5f36b78d81b688ded88ab91e36d9df8c5d64ee 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -107,5 +107,9 @@ public interface UnsafeValues { - static boolean isLegacyPlugin(org.bukkit.plugin.Plugin plugin) { - return !Bukkit.getUnsafe().isSupportedApiVersion(plugin.getDescription().getAPIVersion()); - } -+ -+ byte[] serializeItem(ItemStack item); -+ -+ ItemStack deserializeItem(byte[] data); - // Paper end - } -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 515f623b3b6e76dbf24ec1d204f7983adb100858..d3334c62bf39abf17ee7f3e68e106fd637ffdf00 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -632,6 +632,30 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - return Bukkit.getServer().getItemFactory().ensureServerConversions(this); - } - -+ /** -+ * Deserializes this itemstack from raw NBT bytes. NBT is safer for data migrations as it will -+ * use the built in data converter instead of bukkits dangerous serialization system. -+ * -+ * This expects that the DataVersion was stored on the root of the Compound, as saved from -+ * the {@link #serializeAsBytes()} API returned. -+ * @param bytes bytes representing an item in NBT -+ * @return ItemStack migrated to this version of Minecraft if needed. -+ */ -+ @NotNull -+ public static ItemStack deserializeBytes(@NotNull byte[] bytes) { -+ return org.bukkit.Bukkit.getUnsafe().deserializeItem(bytes); -+ } -+ -+ /** -+ * Serializes this itemstack to raw bytes in NBT. NBT is safer for data migrations as it will -+ * use the built in data converter instead of bukkits dangerous serialization system. -+ * @return bytes representing this item in NBT. -+ */ -+ @NotNull -+ public byte[] serializeAsBytes() { -+ return org.bukkit.Bukkit.getUnsafe().serializeItem(this); -+ } -+ - /** - * Gets the Display name as seen in the Client. - * Currently the server only supports the English language. To override this, diff --git a/patches/api/0192-Add-and-implement-PlayerRecipeBookClickEvent.patch b/patches/api/0192-Add-and-implement-PlayerRecipeBookClickEvent.patch new file mode 100644 index 000000000000..f0a90f120022 --- /dev/null +++ b/patches/api/0192-Add-and-implement-PlayerRecipeBookClickEvent.patch @@ -0,0 +1,114 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: LordKorea +Date: Mon, 11 May 2020 22:38:10 -0400 +Subject: [PATCH] Add and implement PlayerRecipeBookClickEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a7becccb2cf3b72744fcac4efa52d7c61e607765 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java +@@ -0,0 +1,87 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.NamespacedKey; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player clicks a recipe in the recipe book ++ */ ++@NullMarked ++public class PlayerRecipeBookClickEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private NamespacedKey recipe; ++ private boolean makeAll; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerRecipeBookClickEvent(final Player player, final NamespacedKey recipe, final boolean makeAll) { ++ super(player); ++ this.recipe = recipe; ++ this.makeAll = makeAll; ++ } ++ ++ /** ++ * Gets the namespaced key of the recipe that was clicked by the player ++ * ++ * @return The namespaced key of the recipe ++ */ ++ public NamespacedKey getRecipe() { ++ return this.recipe; ++ } ++ ++ /** ++ * Changes what recipe is requested. This sets the requested recipe to the recipe with the given key ++ * ++ * @param recipe The key of the recipe that should be requested ++ */ ++ public void setRecipe(final NamespacedKey recipe) { ++ this.recipe = recipe; ++ } ++ ++ /** ++ * Gets a boolean which indicates whether the player requested to make the maximum amount of results. This is ++ * {@code true} if shift is pressed while the recipe is clicked in the recipe book ++ * ++ * @return {@code true} if shift is pressed while the recipe is clicked ++ */ ++ public boolean isMakeAll() { ++ return this.makeAll; ++ } ++ ++ /** ++ * Sets whether the maximum amount of results should be made. If this is {@code true}, the request is handled as if ++ * the player had pressed shift while clicking on the recipe ++ * ++ * @param makeAll {@code true} if the request should attempt to make the maximum amount of results ++ */ ++ public void setMakeAll(final boolean makeAll) { ++ this.makeAll = makeAll; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/org/bukkit/event/player/PlayerRecipeBookClickEvent.java b/src/main/java/org/bukkit/event/player/PlayerRecipeBookClickEvent.java +index eb8623184f69e213196558b077bd0004f08832af..a843f7347308a15b9fba4a3676f60bafafd83a66 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerRecipeBookClickEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerRecipeBookClickEvent.java +@@ -9,7 +9,10 @@ import org.jetbrains.annotations.NotNull; + + /** + * Called when a player clicks a recipe in the recipe book. ++ * @deprecated use {@link com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent} + */ ++@Deprecated(forRemoval = true) // Paper ++@org.bukkit.Warning(false) // Paper + public class PlayerRecipeBookClickEvent extends PlayerEvent { + + private static final HandlerList handlers = new HandlerList(); diff --git a/patches/api/0193-Disable-Sync-Events-firing-Async-errors-during-shutd.patch b/patches/api/0193-Disable-Sync-Events-firing-Async-errors-during-shutd.patch deleted file mode 100644 index b74732077c42..000000000000 --- a/patches/api/0193-Disable-Sync-Events-firing-Async-errors-during-shutd.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 11 Apr 2020 21:38:59 -0400 -Subject: [PATCH] Disable Sync Events firing Async errors during shutdown - -This is how it use to behave on Paper, and this is totally destroying -the ability to try to shut the server down gracefully during the -shutdown process as events firing on the watchdog thread are throwing -errors. - -This isn't an issue on Spigot - -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index 45989646f5c32fd1470a9868afca3e3a9074579c..9654f4fb230945086a88f64b09a46a5b10e8d1d7 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -600,7 +600,7 @@ public final class SimplePluginManager implements PluginManager { - // Paper - replace callEvent by merging to below method - if (event.isAsynchronous() && server.isPrimaryThread()) { - throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously."); -- } else if (!event.isAsynchronous() && !server.isPrimaryThread()) { -+ } else if (!event.isAsynchronous() && !server.isPrimaryThread() && !server.isStopping() ) { - throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); - } - diff --git a/patches/api/0193-Support-components-in-ItemMeta.patch b/patches/api/0193-Support-components-in-ItemMeta.patch new file mode 100644 index 000000000000..6de921bc0b96 --- /dev/null +++ b/patches/api/0193-Support-components-in-ItemMeta.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger +Date: Sat, 6 Jun 2020 18:13:16 +0200 +Subject: [PATCH] Support components in ItemMeta + + +diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +index 4012a1b4e9acdfafb38c78a54c4b422ffa07cf04..cca91212e702a73e9fc37ec46d575967fedf68c9 100644 +--- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +@@ -5,6 +5,7 @@ import java.util.Collection; + import java.util.List; + import java.util.Map; + import java.util.Set; ++import net.kyori.adventure.text.Component; + import org.bukkit.NamespacedKey; + import org.bukkit.Tag; + import org.bukkit.attribute.Attribute; +@@ -111,6 +112,20 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + @NotNull + String getDisplayName(); + ++ // Paper start ++ /** ++ * Gets the display name that is set. ++ *

      ++ * Plugins should check that hasDisplayName() returns true ++ * before calling this method. ++ * ++ * @return the display name that is set ++ * @deprecated use {@link #displayName()} ++ */ ++ @NotNull ++ @Deprecated ++ net.md_5.bungee.api.chat.BaseComponent[] getDisplayNameComponent(); ++ // Paper end + /** + * Sets the display name. + * +@@ -120,6 +135,16 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + @Deprecated // Paper + void setDisplayName(@Nullable String name); + ++ // Paper start ++ /** ++ * Sets the display name. ++ * ++ * @param component the name component to set ++ * @deprecated use {@link #displayName(Component)} ++ */ ++ @Deprecated ++ void setDisplayNameComponent(@Nullable net.md_5.bungee.api.chat.BaseComponent[] component); ++ // Paper end + /** + * Checks for existence of an item name. + *
      +@@ -256,6 +281,19 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + @Nullable + List getLore(); + ++ /** ++ * Gets the lore that is set. ++ *

      ++ * Plugins should check if hasLore() returns true before ++ * calling this method. ++ * ++ * @return a list of lore that is set ++ * @deprecated use {@link #lore()} ++ */ ++ @Nullable ++ @Deprecated ++ List getLoreComponents(); ++ + /** + * Sets the lore for this item. + * Removes lore when given null. +@@ -266,6 +304,16 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + @Deprecated // Paper + void setLore(@Nullable List lore); + ++ /** ++ * Sets the lore for this item. ++ * Removes lore when given null. ++ * ++ * @param lore the lore that will be set ++ * @deprecated use {@link #lore(List)} ++ */ ++ @Deprecated ++ void setLoreComponents(@Nullable List lore); ++ + /** + * Checks for existence of custom model data. + *

      diff --git a/patches/api/0194-Make-JavaPluginLoader-thread-safe.patch b/patches/api/0194-Make-JavaPluginLoader-thread-safe.patch deleted file mode 100644 index 9afcec16571d..000000000000 --- a/patches/api/0194-Make-JavaPluginLoader-thread-safe.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trigary -Date: Wed, 15 Apr 2020 01:24:55 -0400 -Subject: [PATCH] Make JavaPluginLoader thread-safe - - -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index e98934d32b8dac88b3c3fd14ea5d726872212807..cf809eda2a3feb6abccf7286068280f430452135 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -52,6 +52,8 @@ import org.yaml.snakeyaml.error.YAMLException; - public final class JavaPluginLoader implements PluginLoader { - final Server server; - private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")}; -+ private final Map classLoadLock = new java.util.HashMap(); // Paper -+ private final Map classLoadLockCount = new java.util.HashMap(); // Paper - private final List loaders = new CopyOnWriteArrayList(); - private final LibraryLoader libraryLoader; - -@@ -201,12 +203,33 @@ public final class JavaPluginLoader implements PluginLoader { - - @Nullable - Class getClassByName(final String name, boolean resolve, PluginDescriptionFile description) { -+ // Paper start - make MT safe -+ java.util.concurrent.locks.ReentrantReadWriteLock lock; -+ synchronized (classLoadLock) { -+ lock = classLoadLock.computeIfAbsent(name, (x) -> new java.util.concurrent.locks.ReentrantReadWriteLock()); -+ classLoadLockCount.compute(name, (x, prev) -> prev != null ? prev + 1 : 1); -+ } -+ lock.writeLock().lock();try { -+ // Paper end - for (PluginClassLoader loader : loaders) { - try { - return loader.loadClass0(name, resolve, false, ((SimplePluginManager) server.getPluginManager()).isTransitiveDepend(description, loader.plugin.getDescription())); - } catch (ClassNotFoundException cnfe) { - } - } -+ // Paper start - make MT safe -+ } finally { -+ synchronized (classLoadLock) { -+ lock.writeLock().unlock(); -+ if (classLoadLockCount.get(name) == 1) { -+ classLoadLock.remove(name); -+ classLoadLockCount.remove(name); -+ } else { -+ classLoadLockCount.compute(name, (x, prev) -> prev - 1); -+ } -+ } -+ } -+ // Paper end - return null; - } - diff --git a/patches/api/0194-added-2-new-TargetReasons-for-1.16-mob-behavior.patch b/patches/api/0194-added-2-new-TargetReasons-for-1.16-mob-behavior.patch new file mode 100644 index 000000000000..f5b6d2a49c74 --- /dev/null +++ b/patches/api/0194-added-2-new-TargetReasons-for-1.16-mob-behavior.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 3 Jul 2020 15:05:54 -0700 +Subject: [PATCH] added 2 new TargetReasons for 1.16 mob behavior + + +diff --git a/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java b/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java +index 808142232a722cb6466bac78d00dc55c18ebe109..ef2d1fe4f2fa7f35ef76f2b4e179050d07b7021a 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java +@@ -159,6 +159,14 @@ public class EntityTargetEvent extends EntityEvent implements Cancellable { + * as wheat in its hand. + */ + TEMPT, ++ /** ++ * When the target is in a different dimension ++ */ ++ TARGET_OTHER_LEVEL, // Paper ++ /** ++ * When the target is in creative or spectator gamemode, or the difficulty is peaceful, or other reasons ++ */ ++ TARGET_INVALID, // Paper + /** + * A currently unknown reason for the entity changing target. + */ diff --git a/patches/api/0195-Add-Player-Client-Options-API.patch b/patches/api/0195-Add-Player-Client-Options-API.patch deleted file mode 100644 index 355fd87af515..000000000000 --- a/patches/api/0195-Add-Player-Client-Options-API.patch +++ /dev/null @@ -1,219 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MiniDigger -Date: Mon, 20 Jan 2020 21:38:34 +0100 -Subject: [PATCH] Add Player Client Options API - - -diff --git a/src/main/java/com/destroystokyo/paper/ClientOption.java b/src/main/java/com/destroystokyo/paper/ClientOption.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cedb51f9f3a9150035c2b44970a096448c441dd9 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/ClientOption.java -@@ -0,0 +1,50 @@ -+package com.destroystokyo.paper; -+ -+import net.kyori.adventure.translation.Translatable; -+import net.kyori.adventure.util.Index; -+import org.jetbrains.annotations.NotNull; -+ -+import org.bukkit.inventory.MainHand; -+ -+public final class ClientOption { -+ -+ public static final ClientOption SKIN_PARTS = new ClientOption<>(SkinParts.class); -+ public static final ClientOption CHAT_COLORS_ENABLED = new ClientOption<>(Boolean.class); -+ public static final ClientOption CHAT_VISIBILITY = new ClientOption<>(ChatVisibility.class); -+ public static final ClientOption LOCALE = new ClientOption<>(String.class); -+ public static final ClientOption MAIN_HAND = new ClientOption<>(MainHand.class); -+ public static final ClientOption VIEW_DISTANCE = new ClientOption<>(Integer.class); -+ -+ private final Class type; -+ -+ private ClientOption(@NotNull Class type) { -+ this.type = type; -+ } -+ -+ @NotNull -+ public Class getType() { -+ return type; -+ } -+ -+ public enum ChatVisibility implements Translatable { -+ FULL("full"), -+ SYSTEM("system"), -+ HIDDEN("hidden"), -+ UNKNOWN("unknown"); -+ -+ public static Index NAMES = Index.create(ChatVisibility.class, chatVisibility -> chatVisibility.name); -+ private final String name; -+ -+ ChatVisibility(String name) { -+ this.name = name; -+ } -+ -+ @Override -+ public @NotNull String translationKey() { -+ if (this == UNKNOWN) { -+ throw new UnsupportedOperationException(this.name + " doesn't have a translation key"); -+ } -+ return "options.chat.visibility." + this.name; -+ } -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/SkinParts.java b/src/main/java/com/destroystokyo/paper/SkinParts.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4a0c39405d4fbed457787e3c6ded4cc6591bc8c2 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/SkinParts.java -@@ -0,0 +1,20 @@ -+package com.destroystokyo.paper; -+ -+public interface SkinParts { -+ -+ boolean hasCapeEnabled(); -+ -+ boolean hasJacketEnabled(); -+ -+ boolean hasLeftSleeveEnabled(); -+ -+ boolean hasRightSleeveEnabled(); -+ -+ boolean hasLeftPantsEnabled(); -+ -+ boolean hasRightPantsEnabled(); -+ -+ boolean hasHatsEnabled(); -+ -+ int getRaw(); -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f7f171c4ee0b8339b2f8fbe82442d65f17202f28 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerClientOptionsChangeEvent.java -@@ -0,0 +1,100 @@ -+package com.destroystokyo.paper.event.player; -+ -+import com.destroystokyo.paper.ClientOption; -+import com.destroystokyo.paper.ClientOption.ChatVisibility; -+import com.destroystokyo.paper.SkinParts; -+ -+import org.jetbrains.annotations.NotNull; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.MainHand; -+ -+/** -+ * Called when the player changes his client settings -+ */ -+public class PlayerClientOptionsChangeEvent extends PlayerEvent { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ private final String locale; -+ private final int viewDistance; -+ private final ChatVisibility chatVisibility; -+ private final boolean chatColors; -+ private final SkinParts skinparts; -+ private final MainHand mainHand; -+ -+ public PlayerClientOptionsChangeEvent(@NotNull Player player, @NotNull String locale, int viewDistance, @NotNull ChatVisibility chatVisibility, boolean chatColors, @NotNull SkinParts skinParts, @NotNull MainHand mainHand) { -+ super(player); -+ this.locale = locale; -+ this.viewDistance = viewDistance; -+ this.chatVisibility = chatVisibility; -+ this.chatColors = chatColors; -+ this.skinparts = skinParts; -+ this.mainHand = mainHand; -+ } -+ -+ @NotNull -+ public String getLocale() { -+ return locale; -+ } -+ -+ public boolean hasLocaleChanged() { -+ return !locale.equals(player.getClientOption(ClientOption.LOCALE)); -+ } -+ -+ public int getViewDistance() { -+ return viewDistance; -+ } -+ -+ public boolean hasViewDistanceChanged() { -+ return viewDistance != player.getClientOption(ClientOption.VIEW_DISTANCE); -+ } -+ -+ @NotNull -+ public ChatVisibility getChatVisibility() { -+ return chatVisibility; -+ } -+ -+ public boolean hasChatVisibilityChanged() { -+ return chatVisibility != player.getClientOption(ClientOption.CHAT_VISIBILITY); -+ } -+ -+ public boolean hasChatColorsEnabled() { -+ return chatColors; -+ } -+ -+ public boolean hasChatColorsEnabledChanged() { -+ return chatColors != player.getClientOption(ClientOption.CHAT_COLORS_ENABLED); -+ } -+ -+ @NotNull -+ public SkinParts getSkinParts() { -+ return skinparts; -+ } -+ -+ public boolean hasSkinPartsChanged() { -+ return skinparts.getRaw() != player.getClientOption(ClientOption.SKIN_PARTS).getRaw(); -+ } -+ -+ @NotNull -+ public MainHand getMainHand() { -+ return mainHand; -+ } -+ -+ public boolean hasMainHandChanged() { -+ return mainHand != player.getClientOption(ClientOption.MAIN_HAND); -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index ed2f50647df598a4f289736dcc524281910d1931..797c49510a515b4423bb7b886726afaf63305227 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -2,6 +2,7 @@ package org.bukkit.entity; - - import java.net.InetSocketAddress; - import java.util.UUID; -+import com.destroystokyo.paper.ClientOption; // Paper - import com.destroystokyo.paper.Title; // Paper - import net.kyori.adventure.text.Component; - import org.bukkit.DyeColor; -@@ -2478,6 +2479,12 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * Reset the cooldown counter to 0, effectively starting the cooldown period. - */ - void resetCooldown(); -+ -+ /** -+ * @return the client option value of the player -+ */ -+ @NotNull -+ T getClientOption(@NotNull ClientOption option); - // Paper end - - // Spigot start diff --git a/patches/api/0195-Add-entity-liquid-API.patch b/patches/api/0195-Add-entity-liquid-API.patch new file mode 100644 index 000000000000..0e82f061c9c9 --- /dev/null +++ b/patches/api/0195-Add-entity-liquid-API.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 2 Jul 2020 18:11:33 -0500 +Subject: [PATCH] Add entity liquid API + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index cc1a619e54c2ce0ee49f81534c56d5b55aa5bfc2..c09064e066435f87fa108552ca7e87ccded0fccf 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -863,5 +863,40 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + @NotNull + org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason(); ++ ++ /** ++ * Check if entity is underwater ++ */ ++ boolean isUnderWater(); ++ ++ /** ++ * Check if entity is in rain ++ */ ++ boolean isInRain(); ++ ++ /** ++ * Check if entity is in bubble column ++ */ ++ boolean isInBubbleColumn(); ++ ++ /** ++ * Check if entity is in water or rain ++ */ ++ boolean isInWaterOrRain(); ++ ++ /** ++ * Check if entity is in water or bubble column ++ */ ++ boolean isInWaterOrBubbleColumn(); ++ ++ /** ++ * Check if entity is in water or rain or bubble column ++ */ ++ boolean isInWaterOrRainOrBubbleColumn(); ++ ++ /** ++ * Check if entity is in lava ++ */ ++ boolean isInLava(); + // Paper end + } diff --git a/patches/api/0196-Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/api/0196-Add-PlayerAttackEntityCooldownResetEvent.patch deleted file mode 100644 index 15fa2db392ef..000000000000 --- a/patches/api/0196-Add-PlayerAttackEntityCooldownResetEvent.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: nossr50 -Date: Thu, 26 Mar 2020 19:30:58 -0700 -Subject: [PATCH] Add PlayerAttackEntityCooldownResetEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ebdebe7b6ec6ed5aadc7ee925ba0147e61e6bc84 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerAttackEntityCooldownResetEvent.java -@@ -0,0 +1,76 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when processing a player's attack on an entity when the player's attack strength cooldown is reset -+ */ -+public class PlayerAttackEntityCooldownResetEvent extends PlayerEvent implements Cancellable { -+ -+ private final float cooledAttackStrength; -+ private boolean cancel = false; -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull private final Entity attackedEntity; -+ -+ public PlayerAttackEntityCooldownResetEvent(@NotNull Player who, @NotNull Entity attackedEntity, float cooledAttackStrength) { -+ super(who); -+ this.attackedEntity = attackedEntity; -+ this.cooledAttackStrength = cooledAttackStrength; -+ } -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ public static @NotNull HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ /** -+ * Gets the cancellation state of this event. A cancelled event will not -+ * be executed in the server, but will still pass to other plugins -+ *

      -+ * If an attack cooldown event is cancelled, the players attack strength will remain at the same value instead of being reset. -+ * -+ * @return true if this event is cancelled -+ */ -+ @Override -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ /** -+ * Cancelling this event will prevent the target player from having their cooldown reset from attacking this entity -+ * -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ /** -+ * Get the value of the players cooldown attack strength when they initiated the attack -+ * -+ * @return returns the original player cooldown value -+ */ -+ public float getCooledAttackStrength() { -+ return cooledAttackStrength; -+ } -+ -+ /** -+ * Returns the entity attacked by the player -+ * -+ * @return the entity attacked by the player -+ */ -+ @NotNull -+ public Entity getAttackedEntity() { -+ return attackedEntity; -+ } -+} diff --git a/patches/api/0196-Add-PrepareResultEvent-PrepareGrindstoneEvent.patch b/patches/api/0196-Add-PrepareResultEvent-PrepareGrindstoneEvent.patch new file mode 100644 index 000000000000..5bcc9f3d0b67 --- /dev/null +++ b/patches/api/0196-Add-PrepareResultEvent-PrepareGrindstoneEvent.patch @@ -0,0 +1,206 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 3 Jul 2020 11:58:56 -0500 +Subject: [PATCH] Add PrepareResultEvent / PrepareGrindstoneEvent + +Adds a new event for all crafting stations that generate a result slot item + +Anvil, Grindstone and Smithing now extend this event + +Grindstone is a backwards compat from a previous PrepareGrindstoneEvent + +diff --git a/src/main/java/com/destroystokyo/paper/event/inventory/PrepareGrindstoneEvent.java b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareGrindstoneEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f75933948cdf0aa0c9bb2f06da5418f164af1148 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareGrindstoneEvent.java +@@ -0,0 +1,31 @@ ++package com.destroystokyo.paper.event.inventory; ++ ++import org.bukkit.Warning; ++import org.bukkit.inventory.GrindstoneInventory; ++import org.bukkit.inventory.InventoryView; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Called when an item is put in a slot for grinding in a Grindstone ++ * ++ * @deprecated use {@link org.bukkit.event.inventory.PrepareGrindstoneEvent} ++ */ ++@Deprecated(since = "1.16.1") ++@Warning ++public class PrepareGrindstoneEvent extends PrepareResultEvent { ++ ++ @ApiStatus.Internal ++ public PrepareGrindstoneEvent(@NotNull InventoryView inventory, @Nullable ItemStack result) { ++ super(inventory, result); ++ } ++ ++ @NotNull ++ @Override ++ public GrindstoneInventory getInventory() { ++ return (GrindstoneInventory) super.getInventory(); ++ } ++ ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8ca7858613bb78ee1f9453b55fc38e00414fefb5 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java +@@ -0,0 +1,42 @@ ++package com.destroystokyo.paper.event.inventory; ++ ++import org.bukkit.event.inventory.PrepareInventoryResultEvent; ++import org.bukkit.inventory.InventoryView; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when an item is put in an inventory containing a result slot ++ */ ++@NullMarked ++public class PrepareResultEvent extends PrepareInventoryResultEvent { ++ ++ // HandlerList on PrepareInventoryResultEvent to ensure api compat ++ ++ @ApiStatus.Internal ++ public PrepareResultEvent(final InventoryView inventory, final @Nullable ItemStack result) { ++ super(inventory, result); ++ } ++ ++ /** ++ * Get result item, may be {@code null}. ++ * ++ * @return result item ++ */ ++ @Override ++ public @Nullable ItemStack getResult() { ++ return super.getResult(); ++ } ++ ++ /** ++ * Set result item, may be {@code null}. ++ * ++ * @param result result item ++ */ ++ @Override ++ public void setResult(final @Nullable ItemStack result) { ++ super.setResult(result); ++ } ++} +diff --git a/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java b/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java +index 8a5be3f0322ac19aeac3f00df54add0e73bc87ed..d2b4b2e9385e7c1e0e1e42886481b99ecc8dcf8e 100644 +--- a/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java +@@ -10,9 +10,9 @@ import org.jetbrains.annotations.Nullable; + /** + * Called when an item is put in a slot for repair by an anvil. + */ +-public class PrepareAnvilEvent extends PrepareInventoryResultEvent { ++public class PrepareAnvilEvent extends com.destroystokyo.paper.event.inventory.PrepareResultEvent { + +- private static final HandlerList handlers = new HandlerList(); ++ // Paper - move HandlerList to PrepareInventoryResultEvent + + public PrepareAnvilEvent(@NotNull AnvilView inventory, @Nullable ItemStack result) { + super(inventory, result); +@@ -44,14 +44,5 @@ public class PrepareAnvilEvent extends PrepareInventoryResultEvent { + return (AnvilView) super.getView(); + } + +- @NotNull +- @Override +- public HandlerList getHandlers() { +- return handlers; +- } +- +- @NotNull +- public static HandlerList getHandlerList() { +- return handlers; +- } ++ // Paper - move HandlerList to PrepareInventoryResultEvent + } +diff --git a/src/main/java/org/bukkit/event/inventory/PrepareGrindstoneEvent.java b/src/main/java/org/bukkit/event/inventory/PrepareGrindstoneEvent.java +index fb172479ce28edbf969b9492236e30fb04395bf9..a7e03600099b8d6a117b8f5455fee24eed03e3a3 100644 +--- a/src/main/java/org/bukkit/event/inventory/PrepareGrindstoneEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/PrepareGrindstoneEvent.java +@@ -10,9 +10,9 @@ import org.jetbrains.annotations.Nullable; + /** + * Called when an item is put in a slot for repair or unenchanting in a grindstone. + */ +-public class PrepareGrindstoneEvent extends PrepareInventoryResultEvent { ++public class PrepareGrindstoneEvent extends com.destroystokyo.paper.event.inventory.PrepareGrindstoneEvent { // Paper + +- private static final HandlerList handlers = new HandlerList(); ++ // Paper - move HandlerList to PrepareInventoryResultEvent + + public PrepareGrindstoneEvent(@NotNull InventoryView inventory, @Nullable ItemStack result) { + super(inventory, result); +@@ -24,14 +24,5 @@ public class PrepareGrindstoneEvent extends PrepareInventoryResultEvent { + return (GrindstoneInventory) super.getInventory(); + } + +- @NotNull +- @Override +- public HandlerList getHandlers() { +- return handlers; +- } +- +- @NotNull +- public static HandlerList getHandlerList() { +- return handlers; +- } ++ // Paper - move HandlerList to PrepareInventoryResultEvent + } +diff --git a/src/main/java/org/bukkit/event/inventory/PrepareInventoryResultEvent.java b/src/main/java/org/bukkit/event/inventory/PrepareInventoryResultEvent.java +index b543bc17fb9354d1939c67c1fb6c92d88fdbe4ec..0b58ffff39845b658dee7c35dcae6cdb333f20b3 100644 +--- a/src/main/java/org/bukkit/event/inventory/PrepareInventoryResultEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/PrepareInventoryResultEvent.java +@@ -8,7 +8,9 @@ import org.jetbrains.annotations.Nullable; + + /** + * Called when an item is put in a slot and the result is calculated. ++ * @deprecated use {@link com.destroystokyo.paper.event.inventory.PrepareResultEvent} + */ ++@Deprecated @org.bukkit.Warning(false) // Paper + public class PrepareInventoryResultEvent extends InventoryEvent { + + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/inventory/PrepareSmithingEvent.java b/src/main/java/org/bukkit/event/inventory/PrepareSmithingEvent.java +index 901774e03f8789dddff4e7695ac599ff69cc97a5..8d7924fa81e9b53514fa534f0572fd7effef73c4 100644 +--- a/src/main/java/org/bukkit/event/inventory/PrepareSmithingEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/PrepareSmithingEvent.java +@@ -10,9 +10,9 @@ import org.jetbrains.annotations.Nullable; + /** + * Called when an item is put in a slot for upgrade by a Smithing Table. + */ +-public class PrepareSmithingEvent extends PrepareInventoryResultEvent { ++public class PrepareSmithingEvent extends com.destroystokyo.paper.event.inventory.PrepareResultEvent { + +- private static final HandlerList handlers = new HandlerList(); ++ // Paper - move HandlerList ot PrepareInventoryResultEvent + + public PrepareSmithingEvent(@NotNull InventoryView inventory, @Nullable ItemStack result) { + super(inventory, result); +@@ -24,14 +24,5 @@ public class PrepareSmithingEvent extends PrepareInventoryResultEvent { + return (SmithingInventory) super.getInventory(); + } + +- @NotNull +- @Override +- public HandlerList getHandlers() { +- return handlers; +- } +- +- @NotNull +- public static HandlerList getHandlerList() { +- return handlers; +- } ++ // Paper - move HandlerList to PrepareInventoryResultEvent + } diff --git a/patches/api/0197-Add-BellRingEvent.patch b/patches/api/0197-Add-BellRingEvent.patch new file mode 100644 index 000000000000..07b7fc2c6c2d --- /dev/null +++ b/patches/api/0197-Add-BellRingEvent.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eearslya Sleiarion +Date: Mon, 24 Jun 2019 21:27:39 -0700 +Subject: [PATCH] Add BellRingEvent + +Add a new event, BellRingEvent, to trigger whenever a player rings a +village bell. Passes along the bell block and the player who rang it. + +diff --git a/src/main/java/io/papermc/paper/event/block/BellRingEvent.java b/src/main/java/io/papermc/paper/event/block/BellRingEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6ec5afa994d2a1ce33967f31bb0c58919fdb7e01 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BellRingEvent.java +@@ -0,0 +1,22 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.block.Block; ++import org.bukkit.block.BlockFace; ++import org.bukkit.entity.Entity; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Called when a bell is rung. ++ * ++ * @deprecated use {@link org.bukkit.event.block.BellRingEvent} ++ */ ++@Deprecated(since = "1.19.4") ++public class BellRingEvent extends org.bukkit.event.block.BellRingEvent { ++ ++ @ApiStatus.Internal ++ public BellRingEvent(@NotNull Block block, @NotNull BlockFace direction, @Nullable Entity entity) { ++ super(block, direction, entity); ++ } ++} diff --git a/patches/api/0197-Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch b/patches/api/0197-Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch deleted file mode 100644 index 2fa02a778816..000000000000 --- a/patches/api/0197-Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Wesley Smith -Date: Fri, 24 Apr 2020 18:30:26 -0400 -Subject: [PATCH] Fix Potion#toItemStack swapping the extended and upgraded - constructor values. - -While the Potion class is deprecated, it is still used in some plugins for cross-version potion handling. This issue has existed for a long time, and has caused many heaches along the way. - -diff --git a/src/main/java/org/bukkit/potion/Potion.java b/src/main/java/org/bukkit/potion/Potion.java -index 266547c6da0e3270af5c9ca81268934294a7c48d..69e7ce61090e3e3a7a337a96b380c8ffe78ffb8d 100644 ---- a/src/main/java/org/bukkit/potion/Potion.java -+++ b/src/main/java/org/bukkit/potion/Potion.java -@@ -267,7 +267,7 @@ public class Potion { - } - ItemStack itemStack = new ItemStack(material, amount); - PotionMeta meta = (PotionMeta) itemStack.getItemMeta(); -- meta.setBasePotionData(new PotionData(type, level == 2, extended)); -+ meta.setBasePotionData(new PotionData(type, extended, level == 2)); // Paper - fix swapped values - itemStack.setItemMeta(meta); - return itemStack; - } diff --git a/patches/api/0198-Add-item-slot-convenience-methods.patch b/patches/api/0198-Add-item-slot-convenience-methods.patch deleted file mode 100644 index 9614f432d56e..000000000000 --- a/patches/api/0198-Add-item-slot-convenience-methods.patch +++ /dev/null @@ -1,283 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Sat, 25 Apr 2020 23:31:28 +0200 -Subject: [PATCH] Add item slot convenience methods - - -diff --git a/src/main/java/org/bukkit/inventory/AnvilInventory.java b/src/main/java/org/bukkit/inventory/AnvilInventory.java -index 52519cd877017704b53d36088d4d4c28f8f27397..c60be4fd24c7fdf65251dd6169e5e1ac3b588d95 100644 ---- a/src/main/java/org/bukkit/inventory/AnvilInventory.java -+++ b/src/main/java/org/bukkit/inventory/AnvilInventory.java -@@ -63,4 +63,64 @@ public interface AnvilInventory extends Inventory { - * @param levels the maximum experience cost - */ - void setMaximumRepairCost(int levels); -+ -+ // Paper start -+ /** -+ * Gets the item in the left input slot. -+ * -+ * @return item in the first slot -+ */ -+ @Nullable -+ default ItemStack getFirstItem() { -+ return getItem(0); -+ } -+ -+ /** -+ * Sets the item in the left input slot. -+ * -+ * @param firstItem item to set -+ */ -+ default void setFirstItem(@Nullable ItemStack firstItem) { -+ setItem(0, firstItem); -+ } -+ -+ /** -+ * Gets the item in the right input slot. -+ * -+ * @return item in the second slot -+ */ -+ @Nullable -+ default ItemStack getSecondItem() { -+ return getItem(1); -+ } -+ -+ /** -+ * Sets the item in the right input slot. -+ * -+ * @param secondItem item to set -+ */ -+ default void setSecondItem(@Nullable ItemStack secondItem) { -+ setItem(1, secondItem); -+ } -+ -+ /** -+ * Gets the item in the result slot. -+ * -+ * @return item in the result slot -+ */ -+ @Nullable -+ default ItemStack getResult() { -+ return getItem(2); -+ } -+ -+ /** -+ * Sets the item in the result slot. -+ * Note that the client might not be able to take out the item if it does not match the input items. -+ * -+ * @param result item to set -+ */ -+ default void setResult(@Nullable ItemStack result) { -+ setItem(2, result); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/inventory/GrindstoneInventory.java b/src/main/java/org/bukkit/inventory/GrindstoneInventory.java -index 9048892c8768c6b4d6cea03da73339f13bfbe82e..1c750108f55a0a31ad23433b333e0ea486a63ff2 100644 ---- a/src/main/java/org/bukkit/inventory/GrindstoneInventory.java -+++ b/src/main/java/org/bukkit/inventory/GrindstoneInventory.java -@@ -1,6 +1,68 @@ - package org.bukkit.inventory; - -+import org.jetbrains.annotations.Nullable; // Paper -+ - /** - * Interface to the inventory of a Grindstone. - */ --public interface GrindstoneInventory extends Inventory { } -+public interface GrindstoneInventory extends Inventory { -+ -+ // Paper start -+ /** -+ * Gets the upper input item. -+ * -+ * @return upper input item -+ */ -+ @Nullable -+ default ItemStack getUpperItem() { -+ return getItem(0); -+ } -+ -+ /** -+ * Sets the upper input item. -+ * -+ * @param upperItem item to set -+ */ -+ default void setUpperItem(@Nullable ItemStack upperItem) { -+ setItem(0, upperItem); -+ } -+ -+ /** -+ * Gets the lower input item. -+ * -+ * @return lower input item -+ */ -+ @Nullable -+ default ItemStack getLowerItem() { -+ return getItem(1); -+ } -+ -+ /** -+ * Sets the lower input item. -+ * -+ * @param lowerItem item to set -+ */ -+ default void setLowerItem(@Nullable ItemStack lowerItem) { -+ setItem(1, lowerItem); -+ } -+ -+ /** -+ * Gets the result. -+ * -+ * @return result -+ */ -+ @Nullable -+ default ItemStack getResult() { -+ return getItem(2); -+ } -+ -+ /** -+ * Sets the result. -+ * -+ * @param result item to set -+ */ -+ default void setResult(@Nullable ItemStack result) { -+ setItem(2, result); -+ } -+ // Paper end -+} -diff --git a/src/main/java/org/bukkit/inventory/LecternInventory.java b/src/main/java/org/bukkit/inventory/LecternInventory.java -index 4a0c43acc2714e095973eb78536041bb1a179ddc..acf2244f77133df53eb5f862c8e713c85192f13d 100644 ---- a/src/main/java/org/bukkit/inventory/LecternInventory.java -+++ b/src/main/java/org/bukkit/inventory/LecternInventory.java -@@ -11,4 +11,25 @@ public interface LecternInventory extends Inventory { - @Nullable - @Override - public Lectern getHolder(); -+ -+ // Paper start -+ /** -+ * Gets the lectern's held book. -+ * -+ * @return book set in the lectern -+ */ -+ @Nullable -+ default ItemStack getBook() { -+ return getItem(0); -+ } -+ -+ /** -+ * Sets the lectern's held book. -+ * -+ * @param book the new book -+ */ -+ default void setBook(@Nullable ItemStack book) { -+ setItem(0, book); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/inventory/SmithingInventory.java b/src/main/java/org/bukkit/inventory/SmithingInventory.java -index 96d526b7b153e56c9a97de42ce3270b6638510e4..a41ca6bd2672db2810dd70c4925b84a4f081af05 100644 ---- a/src/main/java/org/bukkit/inventory/SmithingInventory.java -+++ b/src/main/java/org/bukkit/inventory/SmithingInventory.java -@@ -30,4 +30,44 @@ public interface SmithingInventory extends Inventory { - */ - @Nullable - Recipe getRecipe(); -+ -+ // Paper start -+ /** -+ * Gets the input equipment (first slot). -+ * -+ * @return input equipment item -+ */ -+ @Nullable -+ default ItemStack getInputEquipment() { -+ return getItem(0); -+ } -+ -+ /** -+ * Sets the input equipment (first slot). -+ * -+ * @param itemStack item to set -+ */ -+ default void setInputEquipment(@Nullable ItemStack itemStack) { -+ setItem(0, itemStack); -+ } -+ -+ /** -+ * Gets the input mineral (second slot). -+ * -+ * @return input mineral item -+ */ -+ @Nullable -+ default ItemStack getInputMineral() { -+ return getItem(1); -+ } -+ -+ /** -+ * Sets the input mineral (second slot). -+ * -+ * @param itemStack item to set -+ */ -+ default void setInputMineral(@Nullable ItemStack itemStack) { -+ setItem(1, itemStack); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/inventory/StonecutterInventory.java b/src/main/java/org/bukkit/inventory/StonecutterInventory.java -index dbb034fae3b8bfaf40e6341460e274c21e321a3b..e7a8e7188bf8b9840de56dc80c2b79d64a9389cb 100644 ---- a/src/main/java/org/bukkit/inventory/StonecutterInventory.java -+++ b/src/main/java/org/bukkit/inventory/StonecutterInventory.java -@@ -1,6 +1,49 @@ - package org.bukkit.inventory; - -+import org.jetbrains.annotations.Nullable; // Paper -+ - /** - * Interface to the inventory of a Stonecutter. - */ --public interface StonecutterInventory extends Inventory { } -+public interface StonecutterInventory extends Inventory { -+ -+ // Paper start -+ /** -+ * Gets the input item. -+ * -+ * @return input item -+ */ -+ @Nullable -+ default ItemStack getInputItem() { -+ return getItem(0); -+ } -+ -+ /** -+ * Sets the input item. -+ * -+ * @param itemStack item to set -+ */ -+ default void setInputItem(@Nullable ItemStack itemStack) { -+ setItem(0, itemStack); -+ } -+ -+ /** -+ * Gets the result item. -+ * -+ * @return result -+ */ -+ @Nullable -+ default ItemStack getResult() { -+ return getItem(1); -+ } -+ -+ /** -+ * Sets the result item. -+ * -+ * @param itemStack item to set -+ */ -+ default void setResult(@Nullable ItemStack itemStack) { -+ setItem(1, itemStack); -+ } -+ // Paper end -+} diff --git a/patches/api/0198-Brand-support.patch b/patches/api/0198-Brand-support.patch new file mode 100644 index 000000000000..c048bd6f367a --- /dev/null +++ b/patches/api/0198-Brand-support.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DigitalRegent +Date: Mon, 6 Apr 2020 20:30:09 +0200 +Subject: [PATCH] Brand support + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 1a94a914894524b0087044227e9e692102e89e9e..644c20bcf6bba3f581e15cec21a1295b3dc50d43 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3488,6 +3488,16 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + // Paper end + } + ++ // Paper start - brand support ++ /** ++ * Returns player's client brand name. If the client didn't send this information, the brand name will be null.
      ++ * For the Notchian client this name defaults to vanilla. Some modified clients report other names such as forge.
      ++ * @return client brand name ++ */ ++ @Nullable ++ String getClientBrandName(); ++ // Paper end ++ + @NotNull + @Override + Spigot spigot(); diff --git a/patches/api/0199-Add-moon-phase-API.patch b/patches/api/0199-Add-moon-phase-API.patch new file mode 100644 index 000000000000..bb0b1570be20 --- /dev/null +++ b/patches/api/0199-Add-moon-phase-API.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 23 Aug 2020 16:32:03 +0200 +Subject: [PATCH] Add moon phase API + + +diff --git a/src/main/java/io/papermc/paper/world/MoonPhase.java b/src/main/java/io/papermc/paper/world/MoonPhase.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0b24e1a92bba4fed0ca2d4336a3b8351a800f93a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/world/MoonPhase.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper.world; ++ ++import java.util.HashMap; ++import java.util.Map; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public enum MoonPhase { ++ FULL_MOON(0L), ++ WANING_GIBBOUS(1L), ++ LAST_QUARTER(2L), ++ WANING_CRESCENT(3L), ++ NEW_MOON(4L), ++ WAXING_CRESCENT(5L), ++ FIRST_QUARTER(6L), ++ WAXING_GIBBOUS(7L); ++ ++ private final long day; ++ ++ MoonPhase(final long day) { ++ this.day = day; ++ } ++ ++ private static final Map BY_DAY = new HashMap<>(); ++ ++ static { ++ for (final MoonPhase phase : values()) { ++ BY_DAY.put(phase.day, phase); ++ } ++ } ++ ++ public static MoonPhase getPhase(final long day) { ++ return BY_DAY.get(day % 8L); ++ } ++} +diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java +index 316d04db78c23ec236cc6f8d5c17e328cbd8ec75..27eff0826d5b5b48697fefd9571886e7bbce74b1 100644 +--- a/src/main/java/org/bukkit/RegionAccessor.java ++++ b/src/main/java/org/bukkit/RegionAccessor.java +@@ -445,4 +445,12 @@ public interface RegionAccessor { + */ + @NotNull + public T addEntity(@NotNull T entity); ++ ++ // Paper start ++ /** ++ * @return the current moon phase at the current time in the world ++ */ ++ @NotNull ++ io.papermc.paper.world.MoonPhase getMoonPhase(); ++ // Paper end + } diff --git a/patches/api/0199-Villager-Restocks-API.patch b/patches/api/0199-Villager-Restocks-API.patch deleted file mode 100644 index b456e877c6c8..000000000000 --- a/patches/api/0199-Villager-Restocks-API.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: zbk -Date: Sun, 26 Apr 2020 23:49:03 -0400 -Subject: [PATCH] Villager Restocks API - - -diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java -index 6bf3af3ed81b66f61e53105d3591165ea74dba0e..d8cf5e5921357ce9645f5dcb5a3bffcf3c10af7e 100644 ---- a/src/main/java/org/bukkit/entity/Villager.java -+++ b/src/main/java/org/bukkit/entity/Villager.java -@@ -78,6 +78,20 @@ public interface Villager extends AbstractVillager { - */ - public void setVillagerExperience(int experience); - -+ // Paper start -+ /** -+ * Gets the amount of times a villager has restocked their trades today -+ * @return The amount of trade restocks. -+ */ -+ public int getRestocksToday(); -+ -+ /** -+ * Sets the amount of times a villager has restocked their trades today -+ * @param restocksToday new restock count -+ */ -+ public void setRestocksToday(int restocksToday); -+ // Paper end -+ - /** - * Attempts to make this villager sleep at the given location. - *
      diff --git a/patches/api/0200-Add-playPickupItemAnimation-to-LivingEntity.patch b/patches/api/0200-Add-playPickupItemAnimation-to-LivingEntity.patch new file mode 100644 index 000000000000..d75641f55365 --- /dev/null +++ b/patches/api/0200-Add-playPickupItemAnimation-to-LivingEntity.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 23 Aug 2020 19:36:08 +0200 +Subject: [PATCH] Add playPickupItemAnimation to LivingEntity + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index f9e2b5a7cd3db267d8f543898b9f6b00586d1b4a..e37ae6f7641c813c916618a60d97679125ebc16e 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1181,4 +1181,29 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + void setJumping(boolean jumping); + // Paper end - entity jump API ++ ++ // Paper start - pickup animation API ++ /** ++ * Plays pickup item animation towards this entity. ++ *

      ++ * This will remove the item on the client. ++ *

      ++ * Quantity is inferred to be that of the {@link Item}. ++ * ++ * @param item item to pickup ++ */ ++ default void playPickupItemAnimation(@NotNull Item item) { ++ playPickupItemAnimation(item, item.getItemStack().getAmount()); ++ } ++ ++ /** ++ * Plays pickup item animation towards this entity. ++ *

      ++ * This will remove the item on the client. ++ * ++ * @param item item to pickup ++ * @param quantity quantity of item ++ */ ++ void playPickupItemAnimation(@NotNull Item item, int quantity); ++ // Paper end - pickup animation API + } diff --git a/patches/api/0200-Expose-game-version.patch b/patches/api/0200-Expose-game-version.patch deleted file mode 100644 index c95b82afef25..000000000000 --- a/patches/api/0200-Expose-game-version.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Fri, 1 May 2020 17:39:02 +0300 -Subject: [PATCH] Expose game version - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 3455de478517a91285bb9d1b306ce1c4be619389..706e42172b938840c6ec06f0f7b686eee17a4a93 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -154,6 +154,18 @@ public final class Bukkit { - return server.getBukkitVersion(); - } - -+ // Paper start - expose game version -+ /** -+ * Gets the version of game this server implements -+ * -+ * @return version of game -+ */ -+ @NotNull -+ public static String getMinecraftVersion() { -+ return server.getMinecraftVersion(); -+ } -+ // Paper end -+ - /** - * Gets a view of all currently logged in players. This {@linkplain - * Collections#unmodifiableCollection(Collection) view} is a reused -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index d59a7e0c9ec50040fb0b2cc3239cae46760aba04..9b2c1eb7e215a9227c60bc85906fed33ec1dd60a 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -112,6 +112,16 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - @NotNull - public String getBukkitVersion(); - -+ // Paper start - expose game version -+ /** -+ * Gets the version of game this server implements -+ * -+ * @return version of game -+ */ -+ @NotNull -+ String getMinecraftVersion(); -+ // Paper end -+ - /** - * Gets a view of all currently logged in players. This {@linkplain - * Collections#unmodifiableCollection(Collection) view} is a reused diff --git a/patches/api/0201-Add-Mob-Goal-API.patch b/patches/api/0201-Add-Mob-Goal-API.patch deleted file mode 100644 index b655037f4039..000000000000 --- a/patches/api/0201-Add-Mob-Goal-API.patch +++ /dev/null @@ -1,563 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MiniDigger -Date: Fri, 3 Jan 2020 16:24:46 +0100 -Subject: [PATCH] Add Mob Goal API - - -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c57c5416c88e2070a082403ab0dda9d7f08d2a57 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java -@@ -0,0 +1,66 @@ -+package com.destroystokyo.paper.entity.ai; -+ -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.EnumSet; -+ -+import org.bukkit.entity.Mob; -+ -+/** -+ * Represents an AI goal of an entity -+ */ -+public interface Goal { -+ -+ /** -+ * Checks if this goal should be activated -+ * -+ * @return if this goal should be activated -+ */ -+ boolean shouldActivate(); -+ -+ /** -+ * Checks if this goal should stay active, defaults to {@link Goal#shouldActivate()} -+ * -+ * @return if this goal should stay active -+ */ -+ default boolean shouldStayActive() { -+ return shouldActivate(); -+ } -+ -+ /** -+ * Called when this goal gets activated -+ */ -+ default void start() { -+ } -+ -+ /** -+ * Called when this goal gets stopped -+ */ -+ default void stop() { -+ } -+ -+ /** -+ * Called each tick the goal is activated -+ */ -+ default void tick() { -+ } -+ -+ /** -+ * A unique key that identifies this type of goal. Plugins should use their own namespace, not the minecraft -+ * namespace. Additionally, this key also specifies to what mobs this goal can be applied to -+ * -+ * @return the goal key -+ */ -+ @NotNull -+ GoalKey getKey(); -+ -+ /** -+ * Returns a list of all applicable flags for this goal.
      -+ * -+ * This method is only called on construction. -+ * -+ * @return the subtypes. -+ */ -+ @NotNull -+ EnumSet getTypes(); -+} -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9cd98c6fcfa3eb439d9013ef76ef4661175a0e5a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java -@@ -0,0 +1,64 @@ -+package com.destroystokyo.paper.entity.ai; -+ -+import com.google.common.base.Objects; -+ -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.StringJoiner; -+ -+import org.bukkit.NamespacedKey; -+import org.bukkit.entity.Mob; -+ -+/** -+ * -+ * Used to identify a Goal. Consists of a {@link NamespacedKey} and the type of mob the goal can be applied to -+ * -+ * @param the type of mob the goal can be applied to -+ */ -+public class GoalKey { -+ -+ private final Class entityClass; -+ private final NamespacedKey namespacedKey; -+ -+ private GoalKey(@NotNull Class entityClass, @NotNull NamespacedKey namespacedKey) { -+ this.entityClass = entityClass; -+ this.namespacedKey = namespacedKey; -+ } -+ -+ @NotNull -+ public Class getEntityClass() { -+ return entityClass; -+ } -+ -+ @NotNull -+ public NamespacedKey getNamespacedKey() { -+ return namespacedKey; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (this == o) return true; -+ if (o == null || getClass() != o.getClass()) return false; -+ GoalKey goalKey = (GoalKey) o; -+ return Objects.equal(entityClass, goalKey.entityClass) && -+ Objects.equal(namespacedKey, goalKey.namespacedKey); -+ } -+ -+ @Override -+ public int hashCode() { -+ return Objects.hashCode(entityClass, namespacedKey); -+ } -+ -+ @Override -+ public String toString() { -+ return new StringJoiner(", ", GoalKey.class.getSimpleName() + "[", "]") -+ .add("entityClass=" + entityClass) -+ .add("namespacedKey=" + namespacedKey) -+ .toString(); -+ } -+ -+ @NotNull -+ public static
      GoalKey of(@NotNull Class entityClass, @NotNull NamespacedKey namespacedKey) { -+ return new GoalKey<>(entityClass, namespacedKey); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java b/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7024c8f484d2460abf3abfe65a29771d814105ec ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java -@@ -0,0 +1,17 @@ -+package com.destroystokyo.paper.entity.ai; -+ -+/** -+ * Represents the subtype of a goal. Used by minecraft to disable certain types of goals if needed. -+ */ -+public enum GoalType { -+ -+ MOVE, -+ LOOK, -+ JUMP, -+ TARGET, -+ /** -+ * Used to map vanilla goals, that are a behavior goal but don't have a type set... -+ */ -+ UNKNOWN_BEHAVIOR, -+ -+} -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e21f7574763dd4f13794f91bbef192ef66a8f5e9 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java -@@ -0,0 +1,50 @@ -+package com.destroystokyo.paper.entity.ai; -+ -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.Collection; -+ -+import org.bukkit.entity.Mob; -+ -+/** -+ * Represents a part of the "brain" of a mob. It tracks all tasks (running or not), allows adding and removing goals -+ */ -+public interface MobGoals { -+ -+ void addGoal(@NotNull T mob, int priority, @NotNull Goal goal); -+ -+ void removeGoal(@NotNull T mob, @NotNull Goal goal); -+ -+ void removeAllGoals(@NotNull T mob); -+ -+ void removeAllGoals(@NotNull T mob, @NotNull GoalType type); -+ -+ void removeGoal(@NotNull T mob, @NotNull GoalKey key); -+ -+ boolean hasGoal(@NotNull T mob, @NotNull GoalKey key); -+ -+ @Nullable -+ Goal getGoal(@NotNull T mob, @NotNull GoalKey key); -+ -+ @NotNull -+ Collection> getGoals(@NotNull T mob, @NotNull GoalKey key); -+ -+ @NotNull -+ Collection> getAllGoals(@NotNull T mob); -+ -+ @NotNull -+ Collection> getAllGoals(@NotNull T mob, @NotNull GoalType type); -+ -+ @NotNull -+ Collection> getAllGoalsWithout(@NotNull T mob, @NotNull GoalType type); -+ -+ @NotNull -+ Collection> getRunningGoals(@NotNull T mob); -+ -+ @NotNull -+ Collection> getRunningGoals(@NotNull T mob, @NotNull GoalType type); -+ -+ @NotNull -+ Collection> getRunningGoalsWithout(@NotNull T mob, @NotNull GoalType type); -+} -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8fd399f791b45eb7fc62693ca954eea0c68e2881 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java -@@ -0,0 +1,291 @@ -+package com.destroystokyo.paper.entity.ai; -+ -+import com.destroystokyo.paper.entity.RangedEntity; -+ -+import org.bukkit.NamespacedKey; -+import org.bukkit.entity.*; -+ -+/** -+ * Represents a vanilla goal. Plugins should never implement this.
      -+ * Generated by VanillaPathfinderTest in paper-server -+ */ -+public interface VanillaGoal extends Goal { -+ -+ GoalKey AVOID_ENTITY = GoalKey.of(Creature.class, NamespacedKey.minecraft("avoid_entity")); -+ GoalKey BEG = GoalKey.of(Wolf.class, NamespacedKey.minecraft("beg")); -+ GoalKey BREAK_DOOR = GoalKey.of(Mob.class, NamespacedKey.minecraft("break_door")); -+ GoalKey BREATH_AIR = GoalKey.of(Creature.class, NamespacedKey.minecraft("breath_air")); -+ GoalKey BREED = GoalKey.of(Animals.class, NamespacedKey.minecraft("breed")); -+ GoalKey CAT_LIE_ON_BED = GoalKey.of(Cat.class, NamespacedKey.minecraft("cat_lie_on_bed")); -+ GoalKey CAT_SIT_ON_BLOCK = GoalKey.of(Cat.class, NamespacedKey.minecraft("cat_sit_on_block")); -+ GoalKey DOLPHIN_JUMP = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("dolphin_jump")); -+ GoalKey EAT_BLOCK = GoalKey.of(Mob.class, NamespacedKey.minecraft("eat_block")); -+ GoalKey FLEE_SUN = GoalKey.of(Creature.class, NamespacedKey.minecraft("flee_sun")); -+ GoalKey FLOAT = GoalKey.of(Mob.class, NamespacedKey.minecraft("float")); -+ GoalKey FOLLOW_BOAT = GoalKey.of(Creature.class, NamespacedKey.minecraft("follow_boat")); -+ GoalKey FOLLOW_FLOCK_LEADER = GoalKey.of(Fish.class, NamespacedKey.minecraft("follow_flock_leader")); -+ GoalKey FOLLOW_MOB = GoalKey.of(Mob.class, NamespacedKey.minecraft("follow_mob")); -+ GoalKey FOLLOW_OWNER = GoalKey.of(Tameable.class, NamespacedKey.minecraft("follow_owner")); -+ GoalKey FOLLOW_PARENT = GoalKey.of(Animals.class, NamespacedKey.minecraft("follow_parent")); -+ GoalKey GOLEM_RANDOM_STROLL_IN_VILLAGE = GoalKey.of(Creature.class, NamespacedKey.minecraft("golem_random_stroll_in_village")); -+ GoalKey INTERACT = GoalKey.of(Mob.class, NamespacedKey.minecraft("interact")); -+ GoalKey LAND_ON_OWNERS_SHOULDER = GoalKey.of(Parrot.class, NamespacedKey.minecraft("land_on_owners_shoulder")); -+ GoalKey LEAP_AT = GoalKey.of(Mob.class, NamespacedKey.minecraft("leap_at")); -+ GoalKey LLAMA_FOLLOW_CARAVAN = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_follow_caravan")); -+ GoalKey LOOK_AT_PLAYER = GoalKey.of(Mob.class, NamespacedKey.minecraft("look_at_player")); -+ GoalKey LOOK_AT_TRADING_PLAYER = GoalKey.of(AbstractVillager.class, NamespacedKey.minecraft("look_at_trading_player")); -+ GoalKey MELEE_ATTACK = GoalKey.of(Creature.class, NamespacedKey.minecraft("melee_attack")); -+ GoalKey MOVE_BACK_TO_VILLAGE = GoalKey.of(Creature.class, NamespacedKey.minecraft("move_back_to_village")); -+ GoalKey MOVE_THROUGH_VILLAGE = GoalKey.of(Creature.class, NamespacedKey.minecraft("move_through_village")); -+ GoalKey MOVE_TOWARDS_RESTRICTION = GoalKey.of(Creature.class, NamespacedKey.minecraft("move_towards_restriction")); -+ GoalKey MOVE_TOWARDS = GoalKey.of(Creature.class, NamespacedKey.minecraft("move_towards")); -+ GoalKey OCELOT_ATTACK = GoalKey.of(Mob.class, NamespacedKey.minecraft("ocelot_attack")); -+ GoalKey OFFER_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("offer_flower")); -+ GoalKey OPEN_DOOR = GoalKey.of(Mob.class, NamespacedKey.minecraft("open_door")); -+ GoalKey PANIC = GoalKey.of(Creature.class, NamespacedKey.minecraft("panic")); -+ GoalKey PATHFIND_TO_RAID = GoalKey.of(Raider.class, NamespacedKey.minecraft("pathfind_to_raid")); -+ GoalKey RANDOM_LOOK_AROUND = GoalKey.of(Mob.class, NamespacedKey.minecraft("random_look_around")); -+ GoalKey RANDOM_STROLL = GoalKey.of(Creature.class, NamespacedKey.minecraft("random_stroll")); -+ GoalKey RANDOM_SWIMMING = GoalKey.of(Creature.class, NamespacedKey.minecraft("random_swimming")); -+ GoalKey RANGED_ATTACK = GoalKey.of(RangedEntity.class, NamespacedKey.minecraft("ranged_attack")); -+ GoalKey RANGED_BOW_ATTACK = GoalKey.of(Monster.class, NamespacedKey.minecraft("ranged_bow_attack")); -+ GoalKey RANGED_CROSSBOW_ATTACK = GoalKey.of(Monster.class, NamespacedKey.minecraft("ranged_crossbow_attack")); -+ GoalKey REMOVE_BLOCK = GoalKey.of(Creature.class, NamespacedKey.minecraft("remove_block")); -+ GoalKey RESTRICT_SUN = GoalKey.of(Creature.class, NamespacedKey.minecraft("restrict_sun")); -+ GoalKey RUN_AROUND_LIKE_CRAZY = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("run_around_like_crazy")); -+ GoalKey SIT_WHEN_ORDERED_TO = GoalKey.of(Tameable.class, NamespacedKey.minecraft("sit_when_ordered_to")); -+ GoalKey STROLL_THROUGH_VILLAGE = GoalKey.of(Creature.class, NamespacedKey.minecraft("stroll_through_village")); -+ GoalKey SWELL = GoalKey.of(Creeper.class, NamespacedKey.minecraft("swell")); -+ GoalKey TEMPT = GoalKey.of(Creature.class, NamespacedKey.minecraft("tempt")); -+ GoalKey TRADE_WITH_PLAYER = GoalKey.of(AbstractVillager.class, NamespacedKey.minecraft("trade_with_player")); -+ GoalKey TRY_FIND_WATER = GoalKey.of(Creature.class, NamespacedKey.minecraft("try_find_water")); -+ GoalKey USE_ITEM = GoalKey.of(Mob.class, NamespacedKey.minecraft("use_item")); -+ GoalKey WATER_AVOIDING_RANDOM_FLYING = GoalKey.of(Creature.class, NamespacedKey.minecraft("water_avoiding_random_flying")); -+ GoalKey WATER_AVOIDING_RANDOM_STROLL = GoalKey.of(Creature.class, NamespacedKey.minecraft("water_avoiding_random_stroll")); -+ GoalKey ZOMBIE_ATTACK = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack")); -+ GoalKey DEFEND_VILLAGE = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("defend_village")); -+ GoalKey HURT_BY = GoalKey.of(Creature.class, NamespacedKey.minecraft("hurt_by")); -+ GoalKey NEAREST_ATTACKABLE = GoalKey.of(Mob.class, NamespacedKey.minecraft("nearest_attackable")); -+ GoalKey NEAREST_ATTACKABLE_WITCH = GoalKey.of(Raider.class, NamespacedKey.minecraft("nearest_attackable_witch")); -+ GoalKey NEAREST_HEALABLE_RAIDER = GoalKey.of(Raider.class, NamespacedKey.minecraft("nearest_healable_raider")); -+ GoalKey NON_TAME_RANDOM = GoalKey.of(Tameable.class, NamespacedKey.minecraft("non_tame_random")); -+ GoalKey OWNER_HURT_BY = GoalKey.of(Tameable.class, NamespacedKey.minecraft("owner_hurt_by")); -+ GoalKey OWNER_HURT = GoalKey.of(Tameable.class, NamespacedKey.minecraft("owner_hurt")); -+ GoalKey RESET_UNIVERSAL_ANGER = GoalKey.of(Mob.class, NamespacedKey.minecraft("reset_universal_anger")); -+ GoalKey FISH_SWIM = GoalKey.of(Fish.class, NamespacedKey.minecraft("fish_swim")); -+ GoalKey BEE_ATTACK = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_attack")); -+ GoalKey BEE_BECOME_ANGRY = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_become_angry")); -+ GoalKey BEE_ENTER_HIVE = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_enter_hive")); -+ GoalKey BEE_GO_TO_HIVE = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_go_to_hive")); -+ GoalKey BEE_GO_TO_KNOWN_FLOWER = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_go_to_known_flower")); -+ GoalKey BEE_GROW_CROP = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_grow_crop")); -+ GoalKey BEE_HURT_BY_OTHER = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_hurt_by_other")); -+ GoalKey BEE_LOCATE_HIVE = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_locate_hive")); -+ GoalKey BEE_POLLINATE = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_pollinate")); -+ GoalKey BEE_WANDER = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_wander")); -+ GoalKey CAT_AVOID_ENTITY = GoalKey.of(Cat.class, NamespacedKey.minecraft("cat_avoid_entity")); -+ GoalKey CAT_RELAX_ON_OWNER = GoalKey.of(Cat.class, NamespacedKey.minecraft("cat_relax_on_owner")); -+ GoalKey CAT_TEMPT = GoalKey.of(Cat.class, NamespacedKey.minecraft("cat_tempt")); -+ GoalKey DOLPHIN_SWIM_TO_TREASURE = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("dolphin_swim_to_treasure")); -+ GoalKey DOLPHIN_SWIM_WITH_PLAYER = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("dolphin_swim_with_player")); -+ GoalKey PLAY_WITH_ITEMS = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("play_with_items")); -+ GoalKey DEFEND_TRUSTED = GoalKey.of(Fox.class, NamespacedKey.minecraft("defend_trusted")); -+ GoalKey FACEPLANT = GoalKey.of(Fox.class, NamespacedKey.minecraft("faceplant")); -+ GoalKey FOX_BREED = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_breed")); -+ GoalKey FOX_EAT_BERRIES = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_eat_berries")); -+ GoalKey FOX_FLOAT = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_float")); -+ GoalKey FOX_FOLLOW_PARENT = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_follow_parent")); -+ GoalKey FOX_LOOK_AT_PLAYER = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_look_at_player")); -+ GoalKey FOX_MELEE_ATTACK = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_melee_attack")); -+ GoalKey FOX_PANIC = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_panic")); -+ GoalKey FOX_POUNCE = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_pounce")); -+ GoalKey FOX_SEARCH_FOR_ITEMS = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_search_for_items")); -+ GoalKey FOX_STROLL_THROUGH_VILLAGE = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_stroll_through_village")); -+ GoalKey PERCH_AND_SEARCH = GoalKey.of(Fox.class, NamespacedKey.minecraft("perch_and_search")); -+ GoalKey SEEK_SHELTER = GoalKey.of(Fox.class, NamespacedKey.minecraft("seek_shelter")); -+ GoalKey SLEEP = GoalKey.of(Fox.class, NamespacedKey.minecraft("sleep")); -+ GoalKey STALK_PREY = GoalKey.of(Fox.class, NamespacedKey.minecraft("stalk_prey")); -+ GoalKey OCELOT_AVOID_ENTITY = GoalKey.of(Ocelot.class, NamespacedKey.minecraft("ocelot_avoid_entity")); -+ GoalKey OCELOT_TEMPT = GoalKey.of(Ocelot.class, NamespacedKey.minecraft("ocelot_tempt")); -+ GoalKey PANDA_ATTACK = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_attack")); -+ GoalKey PANDA_AVOID = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_avoid")); -+ GoalKey PANDA_BREED = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_breed")); -+ GoalKey PANDA_HURT_BY = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_hurt_by")); -+ GoalKey PANDA_LIE_ON_BACK = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_lie_on_back")); -+ GoalKey PANDA_LOOK_AT_PLAYER = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_look_at_player")); -+ GoalKey PANDA_PANIC = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_panic")); -+ GoalKey PANDA_ROLL = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_roll")); -+ GoalKey PANDA_SIT = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_sit")); -+ GoalKey PANDA_SNEEZE = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_sneeze")); -+ GoalKey POLAR_BEAR_ATTACK_PLAYERS = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polar_bear_attack_players")); -+ GoalKey POLAR_BEAR_HURT_BY = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polar_bear_hurt_by")); -+ GoalKey POLAR_BEAR_MELEE_ATTACK = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polar_bear_melee_attack")); -+ GoalKey POLAR_BEAR_PANIC = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polar_bear_panic")); -+ GoalKey PUFFERFISH_PUFF = GoalKey.of(PufferFish.class, NamespacedKey.minecraft("pufferfish_puff")); -+ GoalKey EVIL_RABBIT_ATTACK = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("evil_rabbit_attack")); -+ GoalKey RABBIT_AVOID_ENTITY = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("rabbit_avoid_entity")); -+ GoalKey RABBIT_PANIC = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("rabbit_panic")); -+ GoalKey RAID_GARDEN = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("raid_garden")); -+ GoalKey SQUID_FLEE = GoalKey.of(Squid.class, NamespacedKey.minecraft("squid_flee")); -+ GoalKey SQUID_RANDOM_MOVEMENT = GoalKey.of(Squid.class, NamespacedKey.minecraft("squid_random_movement")); -+ GoalKey TURTLE_BREED = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_breed")); -+ GoalKey TURTLE_GO_HOME = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_go_home")); -+ GoalKey TURTLE_GO_TO_WATER = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_go_to_water")); -+ GoalKey TURTLE_LAY_EGG = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_lay_egg")); -+ GoalKey TURTLE_PANIC = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_panic")); -+ GoalKey TURTLE_RANDOM_STROLL = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_random_stroll")); -+ GoalKey TURTLE_TRAVEL = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_travel")); -+ GoalKey WOLF_AVOID_ENTITY = GoalKey.of(Wolf.class, NamespacedKey.minecraft("wolf_avoid_entity")); -+ GoalKey LLAMA_ATTACK_WOLF = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_attack_wolf")); -+ GoalKey LLAMA_HURT_BY = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_hurt_by")); -+ GoalKey SKELETON_TRAP = GoalKey.of(SkeletonHorse.class, NamespacedKey.minecraft("skeleton_trap")); -+ GoalKey TRADER_LLAMA_DEFEND_WANDERING_TRADER = GoalKey.of(Llama.class, NamespacedKey.minecraft("trader_llama_defend_wandering_trader")); -+ GoalKey WITHER_DO_NOTHING = GoalKey.of(Wither.class, NamespacedKey.minecraft("wither_do_nothing")); -+ GoalKey RAIDER_OPEN_DOOR = GoalKey.of(Illager.class, NamespacedKey.minecraft("raider_open_door")); -+ GoalKey SKELETON_MELEE = GoalKey.of(AbstractSkeleton.class, NamespacedKey.minecraft("abstract_skeleton_melee")); -+ GoalKey BLAZE_ATTACK = GoalKey.of(Blaze.class, NamespacedKey.minecraft("blaze_attack")); -+ GoalKey DROWNED_ATTACK = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack")); -+ GoalKey DROWNED_GO_TO_BEACH = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_go_to_beach")); -+ GoalKey DROWNED_GO_TO_WATER = GoalKey.of(Creature.class, NamespacedKey.minecraft("drowned_go_to_water")); -+ GoalKey DROWNED_SWIM_UP = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_swim_up")); -+ GoalKey DROWNED_TRIDENT_ATTACK = GoalKey.of(RangedEntity.class, NamespacedKey.minecraft("drowned_trident_attack")); -+ GoalKey ENDERMAN_FREEZE_WHEN_LOOKED_AT = GoalKey.of(Enderman.class, NamespacedKey.minecraft("enderman_freeze_when_looked_at")); -+ GoalKey ENDERMAN_LEAVE_BLOCK = GoalKey.of(Enderman.class, NamespacedKey.minecraft("enderman_leave_block")); -+ GoalKey ENDERMAN_LOOK_FOR_PLAYER = GoalKey.of(Enderman.class, NamespacedKey.minecraft("enderman_look_for_player")); -+ GoalKey ENDERMAN_TAKE_BLOCK = GoalKey.of(Enderman.class, NamespacedKey.minecraft("enderman_take_block")); -+ GoalKey EVOKER_ATTACK_SPELL = GoalKey.of(Evoker.class, NamespacedKey.minecraft("evoker_attack_spell")); -+ GoalKey EVOKER_CASTING_SPELL = GoalKey.of(Evoker.class, NamespacedKey.minecraft("evoker_casting_spell")); -+ GoalKey EVOKER_SUMMON_SPELL = GoalKey.of(Evoker.class, NamespacedKey.minecraft("evoker_summon_spell")); -+ GoalKey EVOKER_WOLOLO_SPELL = GoalKey.of(Evoker.class, NamespacedKey.minecraft("evoker_wololo_spell")); -+ GoalKey GHAST_LOOK = GoalKey.of(Ghast.class, NamespacedKey.minecraft("ghast_look")); -+ GoalKey GHAST_SHOOT_FIREBALL = GoalKey.of(Ghast.class, NamespacedKey.minecraft("ghast_shoot_fireball")); -+ GoalKey RANDOM_FLOAT_AROUND = GoalKey.of(Ghast.class, NamespacedKey.minecraft("random_float_around")); -+ GoalKey GUARDIAN_ATTACK = GoalKey.of(Guardian.class, NamespacedKey.minecraft("guardian_attack")); -+ GoalKey ILLUSIONER_BLINDNESS_SPELL = GoalKey.of(Illusioner.class, NamespacedKey.minecraft("illusioner_blindness_spell")); -+ GoalKey ILLUSIONER_MIRROR_SPELL = GoalKey.of(Illusioner.class, NamespacedKey.minecraft("illusioner_mirror_spell")); -+ GoalKey LONG_DISTANCE_PATROL = GoalKey.of(Raider.class, NamespacedKey.minecraft("long_distance_patrol")); -+ GoalKey PHANTOM_ATTACK_PLAYER = GoalKey.of(Phantom.class, NamespacedKey.minecraft("phantom_attack_player")); -+ GoalKey PHANTOM_ATTACK_STRATEGY = GoalKey.of(Phantom.class, NamespacedKey.minecraft("phantom_attack_strategy")); -+ GoalKey PHANTOM_CIRCLE_AROUND_ANCHOR = GoalKey.of(Phantom.class, NamespacedKey.minecraft("phantom_circle_around_anchor")); -+ GoalKey PHANTOM_SWEEP_ATTACK = GoalKey.of(Phantom.class, NamespacedKey.minecraft("phantom_sweep_attack")); -+ GoalKey RAVAGER_MELEE_ATTACK = GoalKey.of(Ravager.class, NamespacedKey.minecraft("ravager_melee_attack")); -+ GoalKey SHULKER_ATTACK = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_attack")); -+ GoalKey SHULKER_DEFENSE_ATTACK = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_defense_attack")); -+ GoalKey SHULKER_NEAREST_ATTACK = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_nearest_attack")); -+ GoalKey SHULKER_PEEK = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_peek")); -+ GoalKey SILVERFISH_MERGE_WITH_STONE = GoalKey.of(Silverfish.class, NamespacedKey.minecraft("silverfish_merge_with_stone")); -+ GoalKey SILVERFISH_WAKE_UP_FRIENDS = GoalKey.of(Silverfish.class, NamespacedKey.minecraft("silverfish_wake_up_friends")); -+ GoalKey SLIME_ATTACK = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_attack")); -+ GoalKey SLIME_FLOAT = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_float")); -+ GoalKey SLIME_KEEP_ON_JUMPING = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_keep_on_jumping")); -+ GoalKey SLIME_RANDOM_DIRECTION = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_random_direction")); -+ GoalKey SPELLCASTER_CASTING_SPELL = GoalKey.of(Spellcaster.class, NamespacedKey.minecraft("spellcaster_casting_spell")); -+ GoalKey SPIDER_ATTACK = GoalKey.of(Spider.class, NamespacedKey.minecraft("spider_attack")); -+ GoalKey SPIDER = GoalKey.of(Spider.class, NamespacedKey.minecraft("spider")); -+ GoalKey STRIDER_GO_TO_LAVA = GoalKey.of(Strider.class, NamespacedKey.minecraft("strider_go_to_lava")); -+ GoalKey VEX_CHARGE_ATTACK = GoalKey.of(Vex.class, NamespacedKey.minecraft("vex_charge_attack")); -+ GoalKey VEX_COPY_OWNER = GoalKey.of(Vex.class, NamespacedKey.minecraft("vex_copy_owner")); -+ GoalKey VEX_RANDOM_MOVE = GoalKey.of(Vex.class, NamespacedKey.minecraft("vex_random_move")); -+ GoalKey VINDICATOR_BREAK_DOOR = GoalKey.of(Mob.class, NamespacedKey.minecraft("vindicator_break_door")); -+ GoalKey VINDICATOR_JOHNNY_ATTACK = GoalKey.of(Vindicator.class, NamespacedKey.minecraft("vindicator_johnny_attack")); -+ GoalKey VINDICATOR_MELEE_ATTACK = GoalKey.of(Vindicator.class, NamespacedKey.minecraft("vindicator_melee_attack")); -+ GoalKey ZOMBIE_ATTACK_TURTLE_EGG = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_turtle_egg")); -+ GoalKey WANDER_TO_POSITION = GoalKey.of(WanderingTrader.class, NamespacedKey.minecraft("wander_to_position")); -+ GoalKey HOLD_GROUND_ATTACK = GoalKey.of(Raider.class, NamespacedKey.minecraft("hold_ground_attack")); -+ GoalKey OBTAIN_RAID_LEADER_BANNER = GoalKey.of(Raider.class, NamespacedKey.minecraft("obtain_raid_leader_banner")); -+ GoalKey RAIDER_CELEBRATION = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_celebration")); -+ GoalKey RAIDER_MOVE_THROUGH_VILLAGE = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_move_through_village")); -+ GoalKey PARROT_WANDER = GoalKey.of(Creature.class, NamespacedKey.minecraft("parrot_wander")); -+ GoalKey CLIMB_ON_TOP_OF_POWDER_SNOW = GoalKey.of(Mob.class, NamespacedKey.minecraft("climb_on_top_of_powder_snow")); -+ GoalKey WOLF_PANIC = GoalKey.of(Wolf.class, NamespacedKey.minecraft("wolf_panic")); -+ -+ /** -+ * @deprecated removed in 1.16 -+ */ -+ @Deprecated GoalKey ANGER = GoalKey.of(PigZombie.class, NamespacedKey.minecraft("anger")); -+ /** -+ * @deprecated removed in 1.16 -+ */ -+ @Deprecated GoalKey ANGER_OTHER = GoalKey.of(PigZombie.class, NamespacedKey.minecraft("anger_other")); -+ -+ // the constants below use spigot names, they no longer work -+ @Deprecated GoalKey BLAZE_FIREBALL = GoalKey.of(Blaze.class, NamespacedKey.minecraft("blaze_fireball")); -+ @Deprecated GoalKey TEMPT_CHANCE = GoalKey.of(Cat.class, NamespacedKey.minecraft("tempt_chance")); -+ @Deprecated GoalKey DOLPHIN_PLAY_WITH_ITEMS = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("dolphin_play_with_items")); -+ @Deprecated GoalKey DROWNED_GOTO_BEACH = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_goto_beach")); -+ @Deprecated GoalKey DROWNED_GOTO_WATER = GoalKey.of(Creature.class, NamespacedKey.minecraft("drowned_goto_water")); -+ @Deprecated GoalKey ENDERMAN_PICKUP_BLOCK = GoalKey.of(Enderman.class, NamespacedKey.minecraft("enderman_pickup_block")); -+ @Deprecated GoalKey ENDERMAN_PLACE_BLOCK = GoalKey.of(Enderman.class, NamespacedKey.minecraft("enderman_place_block")); -+ @Deprecated GoalKey PLAYER_WHO_LOOKED_AT_TARGET = GoalKey.of(Enderman.class, NamespacedKey.minecraft("player_who_looked_at_target")); -+ @Deprecated GoalKey EVOKER_CAST_SPELL = GoalKey.of(Evoker.class, NamespacedKey.minecraft("evoker_cast_spell")); -+ @Deprecated GoalKey FOX_DEFEND_TRUSTED = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_defend_trusted")); -+ @Deprecated GoalKey FOX_FACEPLANT = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_faceplant")); -+ @Deprecated GoalKey FOX_PERCH_AND_SEARCH = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_perch_and_search")); -+ @Deprecated GoalKey FOX_SLEEP = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_sleep")); -+ @Deprecated GoalKey FOX_SEEK_SHELTER = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_seek_shelter")); -+ @Deprecated GoalKey FOX_STALK_PREY = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_stalk_prey")); -+ @Deprecated GoalKey GHAST_ATTACK_TARGET = GoalKey.of(Ghast.class, NamespacedKey.minecraft("ghast_attack_target")); -+ @Deprecated GoalKey GHAST_IDLE_MOVE = GoalKey.of(Ghast.class, NamespacedKey.minecraft("ghast_idle_move")); -+ @Deprecated GoalKey GHAST_MOVE_TOWARDS_TARGET = GoalKey.of(Ghast.class, NamespacedKey.minecraft("ghast_move_towards_target")); -+ @Deprecated GoalKey SPELLCASTER_CAST_SPELL = GoalKey.of(Spellcaster.class, NamespacedKey.minecraft("spellcaster_cast_spell")); -+ @Deprecated GoalKey LLAMATRADER_DEFENDED_WANDERING_TRADER = GoalKey.of(TraderLlama.class, NamespacedKey.minecraft("llamatrader_defended_wandering_trader")); -+ @Deprecated GoalKey PANDA_HURT_BY_TARGET = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_hurt_by_target")); -+ @Deprecated GoalKey POLARBEAR_ATTACK_PLAYERS = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polarbear_attack_players")); -+ @Deprecated GoalKey POLARBEAR_HURT_BY = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polarbear_hurt_by")); -+ @Deprecated GoalKey POLARBEAR_MELEE = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polarbear_melee")); -+ @Deprecated GoalKey POLARBEAR_PANIC = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polarbear_panic")); -+ @Deprecated GoalKey EAT_CARROTS = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("eat_carrots")); -+ @Deprecated GoalKey KILLER_RABBIT_MELEE_ATTACK = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("killer_rabbit_melee_attack")); -+ @Deprecated GoalKey RABBIT_AVOID_TARGET = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("rabbit_avoid_target")); -+ @Deprecated GoalKey RAIDER_HOLD_GROUND = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_hold_ground")); -+ @Deprecated GoalKey RAIDER_OBTAIN_BANNER = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_obtain_banner")); -+ @Deprecated GoalKey SHULKER_DEFENSE = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_defense")); -+ @Deprecated GoalKey SHULKER_NEAREST = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_nearest")); -+ @Deprecated GoalKey SILVERFISH_HIDE_IN_BLOCK = GoalKey.of(Silverfish.class, NamespacedKey.minecraft("silverfish_hide_in_block")); -+ @Deprecated GoalKey SILVERFISH_WAKE_OTHERS = GoalKey.of(Silverfish.class, NamespacedKey.minecraft("silverfish_wake_others")); -+ @Deprecated GoalKey SLIME_IDLE = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_idle")); -+ @Deprecated GoalKey SLIME_NEAREST_PLAYER = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_nearest_player")); -+ @Deprecated GoalKey SLIME_RANDOM_JUMP = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_random_jump")); -+ @Deprecated GoalKey SPIDER_MELEE_ATTACK = GoalKey.of(Spider.class, NamespacedKey.minecraft("spider_melee_attack")); -+ @Deprecated GoalKey SPIDER_NEAREST_ATTACKABLE_TARGET = GoalKey.of(Spider.class, NamespacedKey.minecraft("spider_nearest_attackable_target")); -+ @Deprecated GoalKey SQUID = GoalKey.of(Squid.class, NamespacedKey.minecraft("squid")); -+ @Deprecated GoalKey TURTLE_GOTO_WATER = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_goto_water")); -+ @Deprecated GoalKey TURTLE_TEMPT = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_tempt")); -+ @Deprecated GoalKey VEX_COPY_TARGET_OF_OWNER = GoalKey.of(Vex.class, NamespacedKey.minecraft("vex_copy_target_of_owner")); -+ @Deprecated GoalKey VILLAGERTRADER_WANDER_TO_POSITION = GoalKey.of(WanderingTrader.class, NamespacedKey.minecraft("villagertrader_wander_to_position")); -+ @Deprecated GoalKey ARROW_ATTACK = GoalKey.of(RangedEntity.class, NamespacedKey.minecraft("arrow_attack")); -+ @Deprecated GoalKey AVOID_TARGET = GoalKey.of(Creature.class, NamespacedKey.minecraft("avoid_target")); -+ @Deprecated GoalKey BOW_SHOOT = GoalKey.of(Monster.class, NamespacedKey.minecraft("bow_shoot")); -+ @Deprecated GoalKey BREATH = GoalKey.of(Creature.class, NamespacedKey.minecraft("breath")); -+ @Deprecated GoalKey CAT_SIT_ON_BED = GoalKey.of(Cat.class, NamespacedKey.minecraft("cat_sit_on_bed")); -+ @Deprecated GoalKey CROSSBOW_ATTACK = GoalKey.of(Monster.class, NamespacedKey.minecraft("crossbow_attack")); -+ @Deprecated GoalKey DOOR_OPEN = GoalKey.of(Mob.class, NamespacedKey.minecraft("door_open")); -+ @Deprecated GoalKey EAT_TILE = GoalKey.of(Mob.class, NamespacedKey.minecraft("eat_tile")); -+ @Deprecated GoalKey FISH_SCHOOL = GoalKey.of(Fish.class, NamespacedKey.minecraft("fish_school")); -+ @Deprecated GoalKey FOLLOW_ENTITY = GoalKey.of(Mob.class, NamespacedKey.minecraft("follow_entity")); -+ @Deprecated GoalKey HORSE_TRAP = GoalKey.of(SkeletonHorse.class, NamespacedKey.minecraft("horse_trap")); -+ @Deprecated GoalKey HURT_BY_TARGET = GoalKey.of(Creature.class, NamespacedKey.minecraft("hurt_by_target")); -+ @Deprecated GoalKey JUMP_ON_BLOCK = GoalKey.of(Cat.class, NamespacedKey.minecraft("jump_on_block")); -+ @Deprecated GoalKey LEAP_AT_TARGET = GoalKey.of(Mob.class, NamespacedKey.minecraft("leap_at_target")); -+ @Deprecated GoalKey LLAMA_FOLLOW = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_follow")); -+ @Deprecated GoalKey MOVE_TOWARDS_TARGET = GoalKey.of(Creature.class, NamespacedKey.minecraft("move_towards_target")); -+ @Deprecated GoalKey NEAREST_ATTACKABLE_TARGET = GoalKey.of(Mob.class, NamespacedKey.minecraft("nearest_attackable_target")); -+ @Deprecated GoalKey NEAREST_ATTACKABLE_TARGET_WITCH = GoalKey.of(Raider.class, NamespacedKey.minecraft("nearest_attackable_target_witch")); -+ @Deprecated GoalKey NEAREST_VILLAGE = GoalKey.of(Creature.class, NamespacedKey.minecraft("nearest_village")); -+ @Deprecated GoalKey OWNER_HURT_BY_TARGET = GoalKey.of(Tameable.class, NamespacedKey.minecraft("owner_hurt_by_target")); -+ @Deprecated GoalKey OWNER_HURT_TARGET = GoalKey.of(Tameable.class, NamespacedKey.minecraft("owner_hurt_target")); -+ @Deprecated GoalKey PERCH = GoalKey.of(Parrot.class, NamespacedKey.minecraft("perch")); -+ @Deprecated GoalKey RAID = GoalKey.of(Raider.class, NamespacedKey.minecraft("raid")); -+ @Deprecated GoalKey RANDOM_FLY = GoalKey.of(Creature.class, NamespacedKey.minecraft("random_fly")); -+ @Deprecated GoalKey RANDOM_LOOKAROUND = GoalKey.of(Mob.class, NamespacedKey.minecraft("random_lookaround")); -+ @Deprecated GoalKey RANDOM_STROLL_LAND = GoalKey.of(Creature.class, NamespacedKey.minecraft("random_stroll_land")); -+ @Deprecated GoalKey RANDOM_SWIM = GoalKey.of(Creature.class, NamespacedKey.minecraft("random_swim")); -+ @Deprecated GoalKey RANDOM_TARGET_NON_TAMED = GoalKey.of(Tameable.class, NamespacedKey.minecraft("random_target_non_tamed")); -+ @Deprecated GoalKey SIT = GoalKey.of(Tameable.class, NamespacedKey.minecraft("sit")); -+ @Deprecated GoalKey STROLL_VILLAGE = GoalKey.of(Creature.class, NamespacedKey.minecraft("stroll_village")); -+ @Deprecated GoalKey TAME = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("tame")); -+ @Deprecated GoalKey WATER = GoalKey.of(Creature.class, NamespacedKey.minecraft("water")); -+ @Deprecated GoalKey WATER_JUMP = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("water_jump")); -+ @Deprecated GoalKey STROLL_VILLAGE_GOLEM = GoalKey.of(Creature.class, NamespacedKey.minecraft("stroll_village_golem")); -+ @Deprecated GoalKey UNIVERSAL_ANGER_RESET = GoalKey.of(Mob.class, NamespacedKey.minecraft("universal_anger_reset")); -+} -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index e9e7fdcb8b57d07d88c9e9694dd119b07fa5b823..1f2d25a48bfd67f770560e6284e0be27b6b4df38 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2320,6 +2320,16 @@ public final class Bukkit { - public static boolean isStopping() { - return server.isStopping(); - } -+ -+ /** -+ * Returns the {@link com.destroystokyo.paper.entity.ai.MobGoals} manager -+ * -+ * @return the mob goals manager -+ */ -+ @NotNull -+ public static com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { -+ return server.getMobGoals(); -+ } - // Paper end - - @NotNull -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index dd1bb341714d27c286b57f9410a690f754bd937b..88eab327d5854fd853b1adb5b4f04a2bcfd66849 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -2016,5 +2016,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * @return true if server is in the process of being shutdown - */ - boolean isStopping(); -+ -+ /** -+ * Returns the {@link com.destroystokyo.paper.entity.ai.MobGoals} manager -+ * -+ * @return the mob goals manager -+ */ -+ @NotNull -+ com.destroystokyo.paper.entity.ai.MobGoals getMobGoals(); - // Paper end - } diff --git a/patches/api/0201-Add-more-Evoker-API.patch b/patches/api/0201-Add-more-Evoker-API.patch new file mode 100644 index 000000000000..169d22854c7c --- /dev/null +++ b/patches/api/0201-Add-more-Evoker-API.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 23 Aug 2020 15:22:44 +0200 +Subject: [PATCH] Add more Evoker API + + +diff --git a/src/main/java/org/bukkit/entity/Evoker.java b/src/main/java/org/bukkit/entity/Evoker.java +index e9fffd8967e95d370c3e64b4558e41e5a9d580a8..a0a46e6e1114f9f5e2843347f835f3cbf5a75d1b 100644 +--- a/src/main/java/org/bukkit/entity/Evoker.java ++++ b/src/main/java/org/bukkit/entity/Evoker.java +@@ -64,4 +64,19 @@ public interface Evoker extends Spellcaster { + */ + @Deprecated(since = "1.11.2") + void setCurrentSpell(@Nullable Spell spell); ++ ++ // Paper start ++ /** ++ * @return the sheep being targeted by the {@link Spell#WOLOLO wololo spell}, or {@code null} if none ++ */ ++ @Nullable ++ Sheep getWololoTarget(); ++ ++ /** ++ * Set the sheep to be the target of the {@link Spell#WOLOLO wololo spell}, or {@code null} to clear. ++ * ++ * @param sheep new wololo target ++ */ ++ void setWololoTarget(@Nullable Sheep sheep); ++ // Paper end + } diff --git a/patches/api/0202-Add-methods-to-get-translation-keys.patch b/patches/api/0202-Add-methods-to-get-translation-keys.patch new file mode 100644 index 000000000000..9428781d3797 --- /dev/null +++ b/patches/api/0202-Add-methods-to-get-translation-keys.patch @@ -0,0 +1,582 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 11 Aug 2020 19:17:46 +0200 +Subject: [PATCH] Add methods to get translation keys + +Co-authored-by: MeFisto94 + +diff --git a/src/main/java/org/bukkit/Difficulty.java b/src/main/java/org/bukkit/Difficulty.java +index f35801783538d3377b04131b8bf6effd7eb8e1a5..427ce8cfd6f63e5c7ec7b264b15ab4111b947729 100644 +--- a/src/main/java/org/bukkit/Difficulty.java ++++ b/src/main/java/org/bukkit/Difficulty.java +@@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents the various difficulty levels that are available. + */ +-public enum Difficulty { ++public enum Difficulty implements net.kyori.adventure.translation.Translatable { // Paper - Adventure translations + /** + * Players regain health over time, hostile mobs don't spawn, the hunger + * bar does not deplete. +@@ -51,6 +51,12 @@ public enum Difficulty { + return value; + } + ++ // Paper start ++ @Override ++ public @org.jetbrains.annotations.NotNull String translationKey() { ++ return "options.difficulty." + this.name().toLowerCase(java.util.Locale.ENGLISH); ++ } ++ // Paper end + /** + * Gets the Difficulty represented by the specified value + * +diff --git a/src/main/java/org/bukkit/FireworkEffect.java b/src/main/java/org/bukkit/FireworkEffect.java +index bf7db5b3e7c2ac15016a48e520fba674726718ee..637fa73d4366c2d88e2716e5c8d3465706d788a7 100644 +--- a/src/main/java/org/bukkit/FireworkEffect.java ++++ b/src/main/java/org/bukkit/FireworkEffect.java +@@ -18,28 +18,44 @@ public final class FireworkEffect implements ConfigurationSerializable { + /** + * The type or shape of the effect. + */ +- public enum Type { ++ public enum Type implements net.kyori.adventure.translation.Translatable { // Paper - Adventure translations + /** + * A small ball effect. + */ +- BALL, ++ BALL("small_ball"), // Paper - add name + /** + * A large ball effect. + */ +- BALL_LARGE, ++ BALL_LARGE("large_ball"), // Paper - add name + /** + * A star-shaped effect. + */ +- STAR, ++ STAR("star"), // Paper - add name + /** + * A burst effect. + */ +- BURST, ++ BURST("burst"), // Paper - add name + /** + * A creeper-face effect. + */ +- CREEPER, ++ CREEPER("creeper"), // Paper - add name + ; ++ // Paper start ++ /** ++ * The name map. ++ */ ++ public static final net.kyori.adventure.util.Index NAMES = net.kyori.adventure.util.Index.create(Type.class, type -> type.name); ++ private final String name; ++ ++ Type(final String name) { ++ this.name = name; ++ } ++ ++ @Override ++ public @NotNull String translationKey() { ++ return "item.minecraft.firework_star.shape." + this.name; ++ } ++ // Paper end + } + + /** +diff --git a/src/main/java/org/bukkit/GameMode.java b/src/main/java/org/bukkit/GameMode.java +index 81e45984a88fc84acd0f76d825abf4ddaed0ac3b..fdc42a79c5af30fdade41ee99245e6641f353571 100644 +--- a/src/main/java/org/bukkit/GameMode.java ++++ b/src/main/java/org/bukkit/GameMode.java +@@ -9,7 +9,7 @@ import org.jetbrains.annotations.Nullable; + * Represents the various type of game modes that {@link HumanEntity}s may + * have + */ +-public enum GameMode { ++public enum GameMode implements net.kyori.adventure.translation.Translatable { // Paper - implement Translatable + /** + * Creative mode may fly, build instantly, become invulnerable and create + * free items. +@@ -35,9 +35,18 @@ public enum GameMode { + + private final int value; + private static final Map BY_ID = Maps.newHashMap(); ++ // Paper start - translation keys ++ private final String translationKey; ++ ++ @Override ++ public @org.jetbrains.annotations.NotNull String translationKey() { ++ return this.translationKey; ++ } ++ // Paper end + + private GameMode(final int value) { + this.value = value; ++ this.translationKey = "gameMode." + this.name().toLowerCase(java.util.Locale.ENGLISH); // Paper + } + + /** +diff --git a/src/main/java/org/bukkit/GameRule.java b/src/main/java/org/bukkit/GameRule.java +index b3211a705acc26449675727823aa42ae6bacac4f..8b6584fae0a9d5cccbe350d889fa8b4a14c78ca3 100644 +--- a/src/main/java/org/bukkit/GameRule.java ++++ b/src/main/java/org/bukkit/GameRule.java +@@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable; + * + * @param type of rule (Boolean or Integer) + */ +-public final class GameRule { ++public final class GameRule implements net.kyori.adventure.translation.Translatable { // Paper - Adventure translations + + private static Map> gameRules = new HashMap<>(); + // Boolean rules +@@ -366,4 +366,11 @@ public final class GameRule { + public static GameRule[] values() { + return gameRules.values().toArray(new GameRule[gameRules.size()]); + } ++ ++ // Paper start ++ @Override ++ public @NotNull String translationKey() { ++ return "gamerule." + this.name; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java +index fe63fef02ee208a5fc52d30a27519a0506c58f8c..8509519ec0d5509f45e43f28b5bb55d953cebb14 100644 +--- a/src/main/java/org/bukkit/Material.java ++++ b/src/main/java/org/bukkit/Material.java +@@ -136,7 +136,7 @@ import org.jetbrains.annotations.Nullable; + * An enum of all material IDs accepted by the official server and client + */ + @SuppressWarnings({"DeprecatedIsStillUsed", "deprecation"}) // Paper +-public enum Material implements Keyed, Translatable { ++public enum Material implements Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper + // + AIR(9648, 0), + STONE(22948), +@@ -4834,6 +4834,17 @@ public enum Material implements Keyed, Translatable { + } + // Paper end + ++ // Paper start - add Translatable ++ @Override ++ public @NotNull String translationKey() { ++ if (this.isItem()) { ++ return java.util.Objects.requireNonNull(this.asItemType()).translationKey(); ++ } else { ++ return java.util.Objects.requireNonNull(this.asBlockType()).translationKey(); ++ } ++ } ++ // Paper end - add Translatable ++ + /** + * Do not use for any reason. + * +@@ -5583,9 +5594,11 @@ public enum Material implements Keyed, Translatable { + * material + * @see #getBlockTranslationKey() + * @see #getItemTranslationKey() ++ * @deprecated use {@link #translationKey()} + */ + @Override + @NotNull ++ @Deprecated(forRemoval = true) // Paper + public String getTranslationKey() { + if (this.isItem()) { + return asItemType().getTranslationKey(); +diff --git a/src/main/java/org/bukkit/MusicInstrument.java b/src/main/java/org/bukkit/MusicInstrument.java +index 708286af95d39214f488bc19e58eee6c257d393a..3b107e35f006cb1a0745778d99dab0783c67d4d8 100644 +--- a/src/main/java/org/bukkit/MusicInstrument.java ++++ b/src/main/java/org/bukkit/MusicInstrument.java +@@ -6,7 +6,7 @@ import java.util.Collections; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +-public abstract class MusicInstrument implements Keyed { ++public abstract class MusicInstrument implements Keyed, net.kyori.adventure.translation.Translatable { // Paper - translation keys + + public static final MusicInstrument PONDER_GOAT_HORN = getInstrument("ponder_goat_horn"); + public static final MusicInstrument SING_GOAT_HORN = getInstrument("sing_goat_horn"); +@@ -46,4 +46,14 @@ public abstract class MusicInstrument implements Keyed { + private static MusicInstrument getInstrument(@NotNull String key) { + return Registry.INSTRUMENT.getOrThrow(NamespacedKey.minecraft(key)); + } ++ ++ // Paper start - mark translation key as deprecated ++ /** ++ * @deprecated this method assumes that the instrument description ++ * always be a translatable component which is not guaranteed. ++ */ ++ @Override ++ @Deprecated(forRemoval = true) ++ public abstract @NotNull String translationKey(); ++ // Paper end - mark translation key as deprecated + } +diff --git a/src/main/java/org/bukkit/Translatable.java b/src/main/java/org/bukkit/Translatable.java +index e3faa2c675c85a9cbdbbb1debec0ff81c58a1bbd..fd1629c2d2028a88fb3d56b0aeb833d17235080a 100644 +--- a/src/main/java/org/bukkit/Translatable.java ++++ b/src/main/java/org/bukkit/Translatable.java +@@ -5,14 +5,18 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents an object with a text representation that can be translated by the + * Minecraft client. ++ * @deprecated use {@link net.kyori.adventure.translation.Translatable} + */ ++@Deprecated(forRemoval = true) // Paper + public interface Translatable { + + /** + * Get the translation key, suitable for use in a translation component. + * + * @return the translation key ++ * @deprecated look for a {@code translationKey()} method instead + */ + @NotNull ++ @Deprecated(forRemoval = true) // Paper + String getTranslationKey(); + } +diff --git a/src/main/java/org/bukkit/attribute/Attribute.java b/src/main/java/org/bukkit/attribute/Attribute.java +index 951c23491390c2c8693d415598ef2de712189220..21f9998b472dc18eb308554f5cdf467f6675f2f0 100644 +--- a/src/main/java/org/bukkit/attribute/Attribute.java ++++ b/src/main/java/org/bukkit/attribute/Attribute.java +@@ -14,7 +14,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Types of attributes which may be present on an {@link Attributable}. + */ +-public interface Attribute extends OldEnum, Keyed, Translatable { ++public interface Attribute extends OldEnum, Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - Adventure translations + + /** + * Maximum health of an Entity. +diff --git a/src/main/java/org/bukkit/block/Biome.java b/src/main/java/org/bukkit/block/Biome.java +index f04aa0300b240f78b56c389fb2851aa4d16fc724..739fef949defca7b6bf4e6b3e079446c24d9b34c 100644 +--- a/src/main/java/org/bukkit/block/Biome.java ++++ b/src/main/java/org/bukkit/block/Biome.java +@@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull; + * There may be additional biomes present in the server, for example from a {@link DataPack} + * which can be accessed via {@link Registry#BIOME}. + */ +-public interface Biome extends OldEnum, Keyed { ++public interface Biome extends OldEnum, Keyed, net.kyori.adventure.translation.Translatable { // Paper - Adventure translations + + Biome OCEAN = getBiome("ocean"); + Biome PLAINS = getBiome("plains"); +@@ -127,4 +127,11 @@ public interface Biome extends OldEnum, Keyed { + static Biome[] values() { + return Lists.newArrayList(Registry.BIOME).toArray(new Biome[0]); + } ++ ++ // Paper start ++ @Override ++ default @NotNull String translationKey() { ++ return "biome.minecraft." + this.getKey().getKey(); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index 4e79dc21824e4b1f286c344b0733057be27fb6c5..afed7dfcbc878c19d3821dde77d6ade084ccf271 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable; + * (i.e. lighting and power) may not be able to be safely accessed during world + * generation when used in cases like BlockPhysicsEvent!!!! + */ +-public interface Block extends Metadatable, Translatable { ++public interface Block extends Metadatable, Translatable, net.kyori.adventure.translation.Translatable { // Paper - translatable + + /** + * Gets the metadata for this block +@@ -682,5 +682,12 @@ public interface Block extends Metadatable, Translatable { + * @return the sound group for this block + */ + @NotNull org.bukkit.SoundGroup getBlockSoundGroup(); ++ ++ /** ++ * @deprecated use {@link #translationKey()} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true) ++ String getTranslationKey(); + // Paper end + } +diff --git a/src/main/java/org/bukkit/block/BlockType.java b/src/main/java/org/bukkit/block/BlockType.java +index 95eb7d7718a74382289ac3a7b2d5fac4c9ec19a2..f0c3343e2006f244bb1f99c269bcbaa357feb25f 100644 +--- a/src/main/java/org/bukkit/block/BlockType.java ++++ b/src/main/java/org/bukkit/block/BlockType.java +@@ -129,7 +129,7 @@ import org.jetbrains.annotations.Nullable; + * changes may occur. Do not use this API in plugins. + */ + @ApiStatus.Internal +-public interface BlockType extends Keyed, Translatable { ++public interface BlockType extends Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - add translatable + + /** + * Typed represents a subtype of {@link BlockType}s that have a known block +@@ -3616,4 +3616,13 @@ public interface BlockType extends Keyed, Translatable { + @Nullable + @Deprecated(since = "1.20.6") + Material asMaterial(); ++ ++ // Paper start - add Translatable ++ /** ++ * @deprecated use {@link #translationKey()} and {@link net.kyori.adventure.text.Component#translatable(net.kyori.adventure.translation.Translatable)} ++ */ ++ @Deprecated(forRemoval = true) ++ @Override ++ @NotNull String getTranslationKey(); ++ // Paper end - add Translatable + } +diff --git a/src/main/java/org/bukkit/enchantments/Enchantment.java b/src/main/java/org/bukkit/enchantments/Enchantment.java +index 3ba81dc0e6bb907ca0ff2215ec1ac68ef0726352..72251952e771152016e32a3fe8bd06ec47c8ee6c 100644 +--- a/src/main/java/org/bukkit/enchantments/Enchantment.java ++++ b/src/main/java/org/bukkit/enchantments/Enchantment.java +@@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable; + /** + * The various type of enchantments that may be added to armour or weapons + */ +-public abstract class Enchantment implements Keyed, Translatable { ++public abstract class Enchantment implements Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - Adventure translations + /** + * Provides protection against environmental damage + */ +@@ -324,6 +324,16 @@ public abstract class Enchantment implements Keyed, Translatable { + public abstract net.kyori.adventure.text.@NotNull Component displayName(int level); + // Paper end + ++ // Paper start - mark translation key as deprecated ++ /** ++ * @deprecated this method assumes that the enchantments description ++ * always be a translatable component which is not guaranteed. ++ */ ++ @Override ++ @Deprecated(forRemoval = true) ++ public abstract @NotNull String translationKey(); ++ // Paper end - mark translation key as deprecated ++ + /** + * Gets the Enchantment at the specified key + * +diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java +index 865ab3d2015e114d3cac72e0e26e4086a3913b38..f4422da4ebb0dc6551305f3e8468817eb08bdbc9 100644 +--- a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java ++++ b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java +@@ -26,5 +26,10 @@ public abstract class EnchantmentWrapper extends Enchantment { + public net.kyori.adventure.text.Component displayName(int level) { + return getEnchantment().displayName(level); + } ++ ++ @Override ++ public @NotNull String translationKey() { ++ return getEnchantment().translationKey(); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java +index dc944ad75f04f5d2f72639615f64b5bb2d1b4117..459af298c4e149c3c96cca088f6a3d0db1cf6192 100644 +--- a/src/main/java/org/bukkit/entity/EntityType.java ++++ b/src/main/java/org/bukkit/entity/EntityType.java +@@ -43,7 +43,7 @@ import org.jetbrains.annotations.Contract; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +-public enum EntityType implements Keyed, Translatable { ++public enum EntityType implements Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - translatable + + // These strings MUST match the strings in nms.EntityTypes and are case sensitive. + /** +@@ -463,10 +463,22 @@ public enum EntityType implements Keyed, Translatable { + + @Override + @NotNull ++ @Deprecated(forRemoval = true) // Paper + public String getTranslationKey() { + return Bukkit.getUnsafe().getTranslationKey(this); + } + ++ // Paper start ++ /** ++ * @throws IllegalArgumentException if the entity does not have a translation key (is probably a custom entity) ++ */ ++ @Override ++ public @NotNull String translationKey() { ++ Preconditions.checkArgument(this != UNKNOWN, "UNKNOWN entities do not have translation keys"); ++ return org.bukkit.Bukkit.getUnsafe().getTranslationKey(this); ++ } ++ // Paper end ++ + /** + * Gets if this EntityType is enabled by feature in a world. + * +diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java +index 98a7c5c549e797100f6aaf440606ef31a2be1e3b..163f1afde2e04fdf4dddb894da62b301b52ed539 100644 +--- a/src/main/java/org/bukkit/entity/Villager.java ++++ b/src/main/java/org/bukkit/entity/Villager.java +@@ -181,7 +181,7 @@ public interface Villager extends AbstractVillager { + * Represents the various different Villager professions there may be. + * Villagers have different trading options depending on their profession, + */ +- interface Profession extends OldEnum, Keyed { ++ interface Profession extends OldEnum, Keyed, net.kyori.adventure.translation.Translatable { + + Profession NONE = getProfession("none"); + /** +@@ -282,6 +282,13 @@ public interface Villager extends AbstractVillager { + static Profession[] values() { + return Lists.newArrayList(Registry.VILLAGER_PROFESSION).toArray(new Profession[0]); + } ++ ++ // Paper start ++ @Override ++ default @NotNull String translationKey() { ++ return "entity.minecraft.villager." + this.getKey().getKey(); ++ } ++ // Paper end + } + + // Paper start - Add villager reputation API +diff --git a/src/main/java/org/bukkit/inventory/CreativeCategory.java b/src/main/java/org/bukkit/inventory/CreativeCategory.java +index 5bd252c0ae3b09fe141d131360c67bb9bfbf5422..78587d9fabe6371a23a7963917b054dbe7603694 100644 +--- a/src/main/java/org/bukkit/inventory/CreativeCategory.java ++++ b/src/main/java/org/bukkit/inventory/CreativeCategory.java +@@ -3,51 +3,64 @@ package org.bukkit.inventory; + /** + * Represents a category in the creative inventory. + */ +-public enum CreativeCategory { ++public enum CreativeCategory implements net.kyori.adventure.translation.Translatable { // Paper + + /** + * An assortment of building blocks including dirt, bricks, planks, ores + * slabs, etc. + */ +- BUILDING_BLOCKS, ++ BUILDING_BLOCKS("buildingBlocks"), // Paper + /** + * Blocks and items typically used for decorative purposes including + * candles, saplings, flora, fauna, fences, walls, carpets, etc. + */ +- DECORATIONS, ++ DECORATIONS("decorations"), // Paper + /** + * Blocks used and associated with redstone contraptions including buttons, + * levers, pressure plates, redstone components, pistons, etc. + */ +- REDSTONE, ++ REDSTONE("redstone"), // Paper + /** + * Items pertaining to transportation including minecarts, rails, boats, + * elytra, etc. + */ +- TRANSPORTATION, ++ TRANSPORTATION("transportation"), // Paper + /** + * Miscellaneous items and blocks that do not fit into other categories + * including gems, dyes, spawn eggs, discs, banner patterns, etc. + */ +- MISC, ++ MISC("misc"), // Paper + /** + * Food items consumable by the player including meats, berries, edible + * drops from creatures, etc. + */ +- FOOD, ++ FOOD("food"), // Paper + /** + * Equipment items meant for general utility including pickaxes, axes, hoes, + * flint and steel, and useful enchantment books for said tools. + */ +- TOOLS, ++ TOOLS("tools"), // Paper + /** + * Equipment items meant for combat including armor, swords, bows, tipped + * arrows, and useful enchantment books for said equipment. + */ +- COMBAT, ++ COMBAT("combat"), // Paper + /** + * All items related to brewing and potions including all types of potions, + * their variants, and ingredients to brew them. + */ +- BREWING; ++ BREWING("brewing"); // Paper ++ // Paper start ++ private final String translationKey; ++ ++ CreativeCategory(String translationKey) { ++ this.translationKey = "itemGroup." + translationKey; ++ } ++ ++ @Override ++ public @org.jetbrains.annotations.NotNull String translationKey() { ++ return this.translationKey; ++ } ++ // Paper end ++ + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index a919d50b31ed48a43bc47596eae44b3d05a417ee..665fe4b551abcd33a4c9bab69746200c3a150cae 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -27,7 +27,7 @@ import org.jetbrains.annotations.Nullable; + * use this class to encapsulate Materials for which {@link Material#isItem()} + * returns false. + */ +-public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource { // Paper ++public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource, net.kyori.adventure.translation.Translatable { // Paper + private Material type = Material.AIR; + private int amount = 0; + private MaterialData data = null; +@@ -628,6 +628,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + + @Override + @NotNull ++ @Deprecated(forRemoval = true) // Paper + public String getTranslationKey() { + return Bukkit.getUnsafe().getTranslationKey(this); + } +@@ -982,5 +983,16 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + ItemMeta itemMeta = getItemMeta(); + return itemMeta != null && itemMeta.hasItemFlag(flag); + } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * This is not the same as getting the translation key ++ * for the material of this itemstack. ++ */ ++ @Override ++ public @NotNull String translationKey() { ++ return Bukkit.getUnsafe().getTranslationKey(this); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/ItemType.java b/src/main/java/org/bukkit/inventory/ItemType.java +index 71c4f2cbf8310941b316357d0c799b1e31418d0f..ab5d544942b7a5387998353614a33ca692edb50e 100644 +--- a/src/main/java/org/bukkit/inventory/ItemType.java ++++ b/src/main/java/org/bukkit/inventory/ItemType.java +@@ -47,7 +47,7 @@ import org.jetbrains.annotations.Nullable; + * changes may occur. Do not use this API in plugins. + */ + @ApiStatus.Internal +-public interface ItemType extends Keyed, Translatable { ++public interface ItemType extends Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - add Translatable + + /** + * Typed represents a subtype of {@link ItemType}s that have a known item meta type +@@ -2409,4 +2409,13 @@ public interface ItemType extends Keyed, Translatable { + @Nullable + @Deprecated(since = "1.20.6") + Material asMaterial(); ++ ++ // Paper start - add Translatable ++ /** ++ * @deprecated use {@link #translationKey()} and {@link net.kyori.adventure.text.Component#translatable(net.kyori.adventure.translation.Translatable)} ++ */ ++ @Deprecated(forRemoval = true) ++ @Override ++ @NotNull String getTranslationKey(); ++ // Paper end - add Translatable + } diff --git a/patches/api/0202-Add-villager-reputation-API.patch b/patches/api/0202-Add-villager-reputation-API.patch deleted file mode 100644 index 14c6a88c1ce2..000000000000 --- a/patches/api/0202-Add-villager-reputation-API.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Wed, 22 Apr 2020 23:13:49 +0200 -Subject: [PATCH] Add villager reputation API - - -diff --git a/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java b/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1cc9ef255df888cb7dd7f7f2c5014e818d1be613 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/villager/Reputation.java -@@ -0,0 +1,54 @@ -+package com.destroystokyo.paper.entity.villager; -+ -+import com.google.common.base.Preconditions; -+import java.util.Map; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * A reputation score for a player on a villager. -+ */ -+public final class Reputation { -+ private static final ReputationType[] REPUTATION_TYPES = ReputationType.values(); // Avoid allocation -+ @NotNull -+ private final int[] reputation; -+ -+ public Reputation() { -+ this(new int[REPUTATION_TYPES.length]); -+ } -+ -+ // Package level to avoid plugins creating reputations with "magic values". -+ Reputation(@NotNull int[] reputation) { -+ this.reputation = reputation; -+ } -+ -+ public Reputation(@NotNull final Map reputation) { -+ this(); -+ Preconditions.checkNotNull(reputation, "reputation cannot be null"); -+ -+ for (Map.Entry entry : reputation.entrySet()) { -+ setReputation(entry.getKey(), entry.getValue()); -+ } -+ } -+ -+ /** -+ * Gets the reputation value for a specific {@link ReputationType}. -+ * -+ * @param type The {@link ReputationType type} of reputation to get. -+ * @return The value of the {@link ReputationType type}. -+ */ -+ public int getReputation(@NotNull ReputationType type) { -+ Preconditions.checkNotNull(type, "the reputation type cannot be null"); -+ return reputation[type.ordinal()]; -+ } -+ -+ /** -+ * Sets the reputation value for a specific {@link ReputationType}. -+ * -+ * @param type The {@link ReputationType type} of reputation to set. -+ * @param value The value of the {@link ReputationType type}. -+ */ -+ public void setReputation(@NotNull ReputationType type, int value) { -+ Preconditions.checkNotNull(type, "the reputation type cannot be null"); -+ reputation[type.ordinal()] = value; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/entity/villager/ReputationType.java b/src/main/java/com/destroystokyo/paper/entity/villager/ReputationType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5600fcdc9795a9f49091db48d73bbd4964b8b737 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/villager/ReputationType.java -@@ -0,0 +1,36 @@ -+package com.destroystokyo.paper.entity.villager; -+ -+/** -+ * A type of reputation gained with a {@link org.bukkit.entity.Villager Villager}. -+ *

      -+ * All types but {@link #MAJOR_POSITIVE} are shared to other villagers. -+ */ -+public enum ReputationType { -+ /** -+ * A gossip with a majorly negative effect. This is only gained through killing a nearby -+ * villager. -+ */ -+ MAJOR_NEGATIVE, -+ -+ /** -+ * A gossip with a minor negative effect. This is only gained through damaging a villager. -+ */ -+ MINOR_NEGATIVE, -+ -+ /** -+ * A gossip with a minor positive effect. This is only gained through curing a zombie -+ * villager. -+ */ -+ MINOR_POSITIVE, -+ -+ /** -+ * A gossip with a major positive effect. This is only gained through curing a zombie -+ * villager. -+ */ -+ MAJOR_POSITIVE, -+ -+ /** -+ * A gossip with a minor positive effect. This is only gained through trading with a villager. -+ */ -+ TRADING, -+} -diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java -index d8cf5e5921357ce9645f5dcb5a3bffcf3c10af7e..c799ac46dbe257d470d3b236cf55b41240f5fda8 100644 ---- a/src/main/java/org/bukkit/entity/Villager.java -+++ b/src/main/java/org/bukkit/entity/Villager.java -@@ -1,6 +1,8 @@ - package org.bukkit.entity; - - import java.util.Locale; -+import java.util.Map; // Paper -+import java.util.UUID; // Paper - import org.bukkit.Keyed; - import org.bukkit.Location; - import org.bukkit.NamespacedKey; -@@ -242,4 +244,50 @@ public interface Villager extends AbstractVillager { - return key; - } - } -+ -+ // Paper start - Add villager reputation API -+ /** -+ * Get the {@link com.destroystokyo.paper.entity.villager.Reputation reputation} -+ * for a specific player by {@link UUID}. -+ * -+ * @param uniqueId The {@link UUID} of the player to get the reputation of. -+ * @return The player's copied reputation with this villager. -+ */ -+ @Nullable -+ public com.destroystokyo.paper.entity.villager.Reputation getReputation(@NotNull UUID uniqueId); -+ -+ /** -+ * Get all {@link com.destroystokyo.paper.entity.villager.Reputation reputations} -+ * for all players mapped by their {@link UUID unique IDs}. -+ * -+ * @return All {@link com.destroystokyo.paper.entity.villager.Reputation reputations} for all players -+ * in a copied map. -+ */ -+ @NotNull -+ public Map getReputations(); -+ -+ /** -+ * Set the {@link com.destroystokyo.paper.entity.villager.Reputation reputation} -+ * for a specific player by {@link UUID}. -+ * -+ * @param uniqueId The {@link UUID} of the player to set the reputation of. -+ * @param reputation The {@link com.destroystokyo.paper.entity.villager.Reputation reputation} to set. -+ */ -+ public void setReputation(@NotNull UUID uniqueId, @NotNull com.destroystokyo.paper.entity.villager.Reputation reputation); -+ -+ /** -+ * Set all {@link com.destroystokyo.paper.entity.villager.Reputation reputations} -+ * for all players mapped by their {@link UUID unique IDs}. -+ * -+ * @param reputations All {@link com.destroystokyo.paper.entity.villager.Reputation reputations} -+ * for all players mapped by their {@link UUID unique IDs}. -+ */ -+ public void setReputations(@NotNull Map reputations); -+ -+ /** -+ * Clear all reputations from this villager. This removes every single -+ * reputation regardless of its impact and the player associated. -+ */ -+ public void clearReputations(); -+ // Paper end - } diff --git a/patches/api/0203-Create-HoverEvent-from-ItemStack-Entity.patch b/patches/api/0203-Create-HoverEvent-from-ItemStack-Entity.patch new file mode 100644 index 000000000000..27625797e0fe --- /dev/null +++ b/patches/api/0203-Create-HoverEvent-from-ItemStack-Entity.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: ysl3000 +Date: Mon, 6 Jul 2020 22:17:37 +0200 +Subject: [PATCH] Create HoverEvent from ItemStack Entity + + +diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java +index a1d8ef8eda3c0256e8c82b7a01c3e7b11454b250..579a9037b656bef9fb65c6da03611e981492074a 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFactory.java ++++ b/src/main/java/org/bukkit/inventory/ItemFactory.java +@@ -250,4 +250,65 @@ public interface ItemFactory { + @NotNull + ItemStack ensureServerConversions(@NotNull ItemStack item); + // Paper end - ensure server conversions API ++ ++ // Paper start - bungee hover events ++ /** ++ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that ItemStack for displaying. ++ * ++ * @param itemStack the itemstack ++ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that ItemStack ++ * @deprecated use {@link ItemStack#asHoverEvent()} ++ */ ++ @NotNull ++ @Deprecated // Paper ++ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull ItemStack itemStack); ++ ++ /** ++ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} for displaying. ++ * Uses the display name of the entity, if present. ++ * ++ * @param entity Entity to create the HoverEvent for ++ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} ++ * @deprecated use {@link org.bukkit.entity.Entity#asHoverEvent()} ++ */ ++ @NotNull ++ @Deprecated ++ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity); ++ ++ /** ++ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} for displaying. ++ * ++ * @param entity Entity to create the HoverEvent for ++ * @param customName a custom name that should be displayed, if not passed entity name will be displayed ++ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} ++ * @deprecated use {@link org.bukkit.entity.Entity#asHoverEvent(java.util.function.UnaryOperator)} ++ */ ++ @NotNull ++ @Deprecated ++ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity, @Nullable String customName); ++ ++ /** ++ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} for displaying. ++ * ++ * @param entity Entity to create the HoverEvent for ++ * @param customName a custom name that should be displayed, if not passed entity name will be displayed ++ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} ++ * @deprecated use {@link org.bukkit.entity.Entity#asHoverEvent(java.util.function.UnaryOperator)} ++ */ ++ @NotNull ++ @Deprecated ++ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity, @Nullable net.md_5.bungee.api.chat.BaseComponent customName); ++ ++ /** ++ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} for displaying. ++ * ++ * @param entity Entity to create the HoverEvent for ++ * @param customName a custom name that should be displayed, if not passed entity name will be displayed ++ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} ++ * @deprecated use {@link org.bukkit.entity.Entity#asHoverEvent(java.util.function.UnaryOperator)} ++ */ ++ @NotNull ++ @Deprecated ++ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity, @NotNull net.md_5.bungee.api.chat.BaseComponent[] customName); ++ // Paper end - bungee hover events + } diff --git a/patches/api/0203-Spawn-Reason-API.patch b/patches/api/0203-Spawn-Reason-API.patch deleted file mode 100644 index 60d33effef59..000000000000 --- a/patches/api/0203-Spawn-Reason-API.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 10 Apr 2014 23:18:28 -0400 -Subject: [PATCH] Spawn Reason API - - -diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java -index a89fff5c164881be0286ec2240e94dd5883ecc40..e55f6e2baf35dbd91c433ab9e62713eaac85435b 100644 ---- a/src/main/java/org/bukkit/RegionAccessor.java -+++ b/src/main/java/org/bukkit/RegionAccessor.java -@@ -10,6 +10,7 @@ import org.bukkit.block.data.BlockData; - import org.bukkit.entity.Entity; - import org.bukkit.entity.EntityType; - import org.bukkit.entity.LivingEntity; -+import org.bukkit.event.entity.CreatureSpawnEvent; - import org.bukkit.util.Consumer; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; -@@ -309,7 +310,34 @@ public interface RegionAccessor { - * {@link Entity} requested cannot be spawned - */ - @NotNull -- T spawn(@NotNull Location location, @NotNull Class clazz, @Nullable Consumer function) throws IllegalArgumentException; -+ // Paper start -+ public default T spawn(@NotNull Location location, @NotNull Class clazz, @Nullable Consumer function) throws IllegalArgumentException { -+ return spawn(location, clazz, CreatureSpawnEvent.SpawnReason.CUSTOM, function); -+ } -+ -+ @NotNull -+ public default T spawn(@NotNull Location location, @NotNull Class clazz, @NotNull CreatureSpawnEvent.SpawnReason reason) throws IllegalArgumentException { -+ return spawn(location, clazz, reason, null); -+ } -+ -+ @NotNull -+ public default T spawn(@NotNull Location location, @NotNull Class clazz, @NotNull CreatureSpawnEvent.SpawnReason reason, @Nullable Consumer function) throws IllegalArgumentException { -+ return spawn(location, clazz, function, reason); -+ } -+ -+ @NotNull -+ public default Entity spawnEntity(@NotNull Location loc, @NotNull org.bukkit.entity.EntityType type, @NotNull CreatureSpawnEvent.SpawnReason reason) { -+ return spawn(loc, (Class) type.getEntityClass(), reason, null); -+ } -+ -+ @NotNull -+ public default Entity spawnEntity(@NotNull Location loc, @NotNull org.bukkit.entity.EntityType type, @NotNull CreatureSpawnEvent.SpawnReason reason, @Nullable Consumer function) { -+ return spawn(loc, (Class) type.getEntityClass(), reason, function); -+ } -+ -+ @NotNull -+ public T spawn(@NotNull Location location, @NotNull Class clazz, @Nullable Consumer function, @NotNull CreatureSpawnEvent.SpawnReason reason) throws IllegalArgumentException; -+ // Paper end - - /** - * Creates a new entity at the given {@link Location} with the supplied diff --git a/patches/api/0204-Add-additional-open-container-api-to-HumanEntity.patch b/patches/api/0204-Add-additional-open-container-api-to-HumanEntity.patch new file mode 100644 index 000000000000..ada16dc286fd --- /dev/null +++ b/patches/api/0204-Add-additional-open-container-api-to-HumanEntity.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Wed, 26 Aug 2020 02:11:58 -0400 +Subject: [PATCH] Add additional open container api to HumanEntity + + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index d87261e0500d34696a50e9d6d136ca844c9a2cea..3859b12fad09cd181a914d152a9928d5bb720ca2 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -182,6 +182,92 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder + @Nullable + public InventoryView openMerchant(@NotNull Merchant merchant, boolean force); + ++ // Paper start - Add additional containers ++ /** ++ * Opens an empty anvil inventory window with the player's inventory ++ * on the bottom. ++ * ++ * @param location The location to attach it to. If null, the player's ++ * location is used. ++ * @param force If false, and there is no anvil block at the location, ++ * no inventory will be opened and null will be returned. ++ * @return The newly opened inventory view, or null if it could not be ++ * opened. ++ */ ++ @Nullable ++ public InventoryView openAnvil(@Nullable Location location, boolean force); ++ ++ /** ++ * Opens an empty cartography table inventory window with the player's inventory ++ * on the bottom. ++ * ++ * @param location The location to attach it to. If null, the player's ++ * location is used. ++ * @param force If false, and there is no cartography table block at the location, ++ * no inventory will be opened and null will be returned. ++ * @return The newly opened inventory view, or null if it could not be ++ * opened. ++ */ ++ @Nullable ++ public InventoryView openCartographyTable(@Nullable Location location, boolean force); ++ ++ /** ++ * Opens an empty grindstone inventory window with the player's inventory ++ * on the bottom. ++ * ++ * @param location The location to attach it to. If null, the player's ++ * location is used. ++ * @param force If false, and there is no grindstone block at the location, ++ * no inventory will be opened and null will be returned. ++ * @return The newly opened inventory view, or null if it could not be ++ * opened. ++ */ ++ @Nullable ++ public InventoryView openGrindstone(@Nullable Location location, boolean force); ++ ++ /** ++ * Opens an empty loom inventory window with the player's inventory ++ * on the bottom. ++ * ++ * @param location The location to attach it to. If null, the player's ++ * location is used. ++ * @param force If false, and there is no loom block at the location, ++ * no inventory will be opened and null will be returned. ++ * @return The newly opened inventory view, or null if it could not be ++ * opened. ++ */ ++ @Nullable ++ public InventoryView openLoom(@Nullable Location location, boolean force); ++ ++ /** ++ * Opens an empty smithing table inventory window with the player's inventory ++ * on the bottom. ++ * ++ * @param location The location to attach it to. If null, the player's ++ * location is used. ++ * @param force If false, and there is no smithing table block at the location, ++ * no inventory will be opened and null will be returned. ++ * @return The newly opened inventory view, or null if it could not be ++ * opened. ++ */ ++ @Nullable ++ public InventoryView openSmithingTable(@Nullable Location location, boolean force); ++ ++ /** ++ * Opens an empty stonecutter inventory window with the player's inventory ++ * on the bottom. ++ * ++ * @param location The location to attach it to. If null, the player's ++ * location is used. ++ * @param force If false, and there is no stonecutter block at the location, ++ * no inventory will be opened and null will be returned. ++ * @return The newly opened inventory view, or null if it could not be ++ * opened. ++ */ ++ @Nullable ++ public InventoryView openStonecutter(@Nullable Location location, boolean force); ++ // Paper end ++ + /** + * Force-closes the currently open inventory view for this player, if any. + */ diff --git a/patches/api/0204-Potential-bed-API.patch b/patches/api/0204-Potential-bed-API.patch deleted file mode 100644 index 597465801834..000000000000 --- a/patches/api/0204-Potential-bed-API.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Sun, 10 May 2020 23:06:41 -0400 -Subject: [PATCH] Potential bed API - -Adds a new method to fetch the location of a player's bed without generating any sync loads. - -getPotentialBedLocation - Gets the last known location of a player's bed. This does not preform any check if the bed is still valid and does not load any chunks. - -diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java -index b007b582d344b79ee67751fd1e21f6cef6a1a950..43ab3d1f96179a547630be3494d85642ab2ff029 100644 ---- a/src/main/java/org/bukkit/entity/HumanEntity.java -+++ b/src/main/java/org/bukkit/entity/HumanEntity.java -@@ -248,6 +248,19 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder - */ - public int getSleepTicks(); - -+ -+ // Paper start - Potential bed api -+ /** -+ * Gets the Location of the player's bed, null if they have not slept -+ * in one. This method will not attempt to validate if the current bed -+ * is still valid. -+ * -+ * @return Bed Location if has slept in one, otherwise null. -+ */ -+ @Nullable -+ public Location getPotentialBedLocation(); -+ // Paper end -+ - /** - * Attempts to make the entity sleep at the given location. - *
      diff --git a/patches/api/0205-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch b/patches/api/0205-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch new file mode 100644 index 000000000000..c2b3732d253c --- /dev/null +++ b/patches/api/0205-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MeFisto94 +Date: Fri, 28 Aug 2020 01:41:31 +0200 +Subject: [PATCH] Expose the Entity Counter to allow plugins to use valid and + non-conflicting Entity Ids + + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 739f117a0fd91ae98b5e5a39ae8e23feca0b741d..bd3567e9b0617c19a92090c8ab6baf17a715073a 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -168,5 +168,12 @@ public interface UnsafeValues { + byte[] serializeItem(ItemStack item); + + ItemStack deserializeItem(byte[] data); ++ ++ /** ++ * Creates and returns the next EntityId available. ++ *

      ++ * Use this when sending custom packets, so that there are no collisions on the client or server. ++ */ ++ public int nextEntityId(); + // Paper end + } diff --git a/patches/api/0205-Prioritise-own-classes-where-possible.patch b/patches/api/0205-Prioritise-own-classes-where-possible.patch deleted file mode 100644 index 948e2f95fa0e..000000000000 --- a/patches/api/0205-Prioritise-own-classes-where-possible.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Mon, 27 Apr 2020 12:31:59 +0200 -Subject: [PATCH] Prioritise own classes where possible - -This adds the server property `Paper.DisableClassPrioritization` to disable -prioritization of own classes for plugins' classloaders. - -This value is by default not present, and this will therefore break any -plugins which abuse behaviour related to not using their own classes -while still loading their own. This is often an issue with failing to -relocate or shade properly, such as when shading plugin APIs like Vault. - -A plugin's classloader will first look in the same jar as it is loading -in for a requested class, then load it. It does not re-use other -plugins' classes if it has the chance to avoid doing so. - -If a class is not found in the same jar as it is loading for and it does -find it elsewhere, it will still choose the class elsewhere. This is -intended behaviour, as it will only prioritise classes it has in its own -jar, no other plugins' classes will be prioritised in any other order -than the one they were registered in. - -The patch in general terms just loads the class in the plugin's jar -before it starts looking elsewhere for it. - -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index cf809eda2a3feb6abccf7286068280f430452135..4b54af83ef8fd18696d2d21ed52b61f13bff7988 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -51,6 +51,7 @@ import org.yaml.snakeyaml.error.YAMLException; - */ - public final class JavaPluginLoader implements PluginLoader { - final Server server; -+ private static final boolean DISABLE_CLASS_PRIORITIZATION = Boolean.getBoolean("Paper.DisableClassPrioritization"); // Paper - private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")}; - private final Map classLoadLock = new java.util.HashMap(); // Paper - private final Map classLoadLockCount = new java.util.HashMap(); // Paper -@@ -203,6 +204,11 @@ public final class JavaPluginLoader implements PluginLoader { - - @Nullable - Class getClassByName(final String name, boolean resolve, PluginDescriptionFile description) { -+ // Paper start - prioritize self -+ return getClassByName(name, resolve, description, null); -+ } -+ Class getClassByName(final String name, boolean resolve, PluginDescriptionFile description, PluginClassLoader requester) { -+ // Paper end - // Paper start - make MT safe - java.util.concurrent.locks.ReentrantReadWriteLock lock; - synchronized (classLoadLock) { -@@ -210,6 +216,13 @@ public final class JavaPluginLoader implements PluginLoader { - classLoadLockCount.compute(name, (x, prev) -> prev != null ? prev + 1 : 1); - } - lock.writeLock().lock();try { -+ // Paper start - prioritize self -+ if (!DISABLE_CLASS_PRIORITIZATION && requester != null) { -+ try { -+ return requester.loadClass0(name, false, false, ((SimplePluginManager) server.getPluginManager()).isTransitiveDepend(description, requester.getDescription())); -+ } catch (ClassNotFoundException cnfe) {} -+ } -+ // Paper end - // Paper end - for (PluginClassLoader loader : loaders) { - try { -diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -index 0db641f5d5e1293b236ad0d2e3a156802ffed839..064c758b19bc8c9a4e94769dd205a1bdcc972a89 100644 ---- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -@@ -33,7 +33,7 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot - public JavaPlugin getPlugin() { return plugin; } // Spigot - private final JavaPluginLoader loader; - private final Map> classes = new ConcurrentHashMap>(); -- private final PluginDescriptionFile description; -+ private final PluginDescriptionFile description; PluginDescriptionFile getDescription() { return description; } // Paper - private final File dataFolder; - private final File file; - private final JarFile jar; -@@ -123,7 +123,7 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot - - if (checkGlobal) { - // This ignores the libraries of other plugins, unless they are transitive dependencies. -- Class result = loader.getClassByName(name, resolve, description); -+ Class result = loader.getClassByName(name, resolve, description, this); // Paper - prioritize self - - if (result != null) { - // If the class was loaded from a library instead of a PluginClassLoader, we can assume that its associated plugin is a transitive dependency and can therefore skip this check. diff --git a/patches/api/0206-Entity-isTicking.patch b/patches/api/0206-Entity-isTicking.patch new file mode 100644 index 000000000000..994973cebaad --- /dev/null +++ b/patches/api/0206-Entity-isTicking.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 3 Oct 2020 21:39:07 -0500 +Subject: [PATCH] Entity#isTicking + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index c09064e066435f87fa108552ca7e87ccded0fccf..0342fbc83bf462017f86d0dda9f49e595a8066b3 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -898,5 +898,10 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + * Check if entity is in lava + */ + boolean isInLava(); ++ ++ /** ++ * Check if entity is inside a ticking chunk ++ */ ++ boolean isTicking(); + // Paper end + } diff --git a/patches/api/0206-Provide-a-useful-PluginClassLoader-toString.patch b/patches/api/0206-Provide-a-useful-PluginClassLoader-toString.patch deleted file mode 100644 index f780b485d657..000000000000 --- a/patches/api/0206-Provide-a-useful-PluginClassLoader-toString.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sun, 31 May 2020 15:26:17 +0100 -Subject: [PATCH] Provide a useful PluginClassLoader#toString - -There are several cases where the plugin classloader may be dumped to the logs, -however, this provides no indication of the owner of the classloader, making -these messages effectively useless, this patch rectifies this - -diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -index 064c758b19bc8c9a4e94769dd205a1bdcc972a89..fc5dc3b2f73e76976748eb013b39cae931072143 100644 ---- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -@@ -235,4 +235,16 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot - javaPlugin.logger = this.logger; // Paper - set logger - javaPlugin.init(loader, loader.server, description, dataFolder, file, this); - } -+ -+ // Paper start -+ @Override -+ public String toString() { -+ JavaPlugin currPlugin = plugin != null ? plugin : pluginInit; -+ return "PluginClassLoader{" + -+ "plugin=" + currPlugin + -+ ", pluginEnabled=" + (currPlugin == null ? "uninitialized" : currPlugin.isEnabled()) + -+ ", url=" + file + -+ '}'; -+ } -+ // Paper end - } diff --git a/patches/api/0207-Inventory-getHolder-method-without-block-snapshot.patch b/patches/api/0207-Inventory-getHolder-method-without-block-snapshot.patch deleted file mode 100644 index 5cb00f4606f4..000000000000 --- a/patches/api/0207-Inventory-getHolder-method-without-block-snapshot.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Wed, 10 Jun 2020 23:55:16 +0100 -Subject: [PATCH] Inventory getHolder method without block snapshot - - -diff --git a/src/main/java/org/bukkit/block/DoubleChest.java b/src/main/java/org/bukkit/block/DoubleChest.java -index 83a4642119c3f33749e04c774cf2b39839f797e2..a39d2f1acbbd84ae0e2cf29f85594e09e55e9355 100644 ---- a/src/main/java/org/bukkit/block/DoubleChest.java -+++ b/src/main/java/org/bukkit/block/DoubleChest.java -@@ -34,6 +34,18 @@ public class DoubleChest implements InventoryHolder { - return inventory.getRightSide().getHolder(); - } - -+ // Paper start - getHolder without snapshot -+ @Nullable -+ public InventoryHolder getLeftSide(boolean useSnapshot) { -+ return inventory.getLeftSide().getHolder(useSnapshot); -+ } -+ -+ @Nullable -+ public InventoryHolder getRightSide(boolean useSnapshot) { -+ return inventory.getRightSide().getHolder(useSnapshot); -+ } -+ // Paper end -+ - @NotNull - public Location getLocation() { - return getInventory().getLocation(); -diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/org/bukkit/inventory/Inventory.java -index 875c401153349b0f2468525e54cf10ca86430087..960626dd64ec9b0c5f4638c1ada463fd20c6b5fc 100644 ---- a/src/main/java/org/bukkit/inventory/Inventory.java -+++ b/src/main/java/org/bukkit/inventory/Inventory.java -@@ -382,6 +382,17 @@ public interface Inventory extends Iterable { - @Nullable - public InventoryHolder getHolder(); - -+ // Paper start - getHolder without snapshot -+ /** -+ * Gets the block or entity belonging to the open inventory -+ * -+ * @param useSnapshot Create a snapshot if the holder is a tile entity -+ * @return The holder of the inventory; null if it has no holder. -+ */ -+ @Nullable -+ public InventoryHolder getHolder(boolean useSnapshot); -+ // Paper end -+ - @NotNull - @Override - public ListIterator iterator(); diff --git a/patches/api/0227-Villager-resetOffers.patch b/patches/api/0207-Villager-resetOffers.patch similarity index 100% rename from patches/api/0227-Villager-resetOffers.patch rename to patches/api/0207-Villager-resetOffers.patch diff --git a/patches/api/0208-Improve-Arrow-API.patch b/patches/api/0208-Improve-Arrow-API.patch deleted file mode 100644 index 1c70418e9857..000000000000 --- a/patches/api/0208-Improve-Arrow-API.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nesaak <52047222+Nesaak@users.noreply.github.com> -Date: Fri, 22 May 2020 13:35:21 -0400 -Subject: [PATCH] Improve Arrow API - -Add method to get the arrow's itemstack and a method -to set the arrow's "noclip" status - -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/org/bukkit/entity/AbstractArrow.java b/src/main/java/org/bukkit/entity/AbstractArrow.java -index e8e56e89e32d84af0639fe2e9b0eeabd747b6007..225a24898acd25038ea2a8448f9f3b57643d3026 100644 ---- a/src/main/java/org/bukkit/entity/AbstractArrow.java -+++ b/src/main/java/org/bukkit/entity/AbstractArrow.java -@@ -143,6 +143,28 @@ public interface AbstractArrow extends Projectile { - } - - // Paper start -+ /** -+ * Gets the ItemStack for this arrow. -+ * -+ * @return The ItemStack, as if a player picked up the arrow -+ */ -+ @NotNull -+ org.bukkit.inventory.ItemStack getItemStack(); -+ -+ /** -+ * Sets this arrow to "noclip" status. -+ * -+ * @param noPhysics true to set "noclip" -+ */ -+ void setNoPhysics(boolean noPhysics); -+ -+ /** -+ * Gets if this arrow has "noclip". -+ * -+ * @return true if noclip is active -+ */ -+ boolean hasNoPhysics(); -+ - /** - * Gets the {@link PickupRule} for this arrow. - * diff --git a/patches/api/0208-Player-elytra-boost-API.patch b/patches/api/0208-Player-elytra-boost-API.patch new file mode 100644 index 000000000000..0d817a36f577 --- /dev/null +++ b/patches/api/0208-Player-elytra-boost-API.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Trigary +Date: Tue, 14 Apr 2020 12:06:14 +0200 +Subject: [PATCH] Player elytra boost API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 644c20bcf6bba3f581e15cec21a1295b3dc50d43..30d209eb19d891d32fa8dba36270a6bf7fba60b7 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3382,6 +3382,25 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + @NotNull T getClientOption(com.destroystokyo.paper.@NotNull ClientOption option); + // Paper end - client option API + ++ // Paper start - elytra boost API ++ /** ++ * Boost a Player that's {@link #isGliding()} using a {@link Firework}. ++ * If the creation of the entity is cancelled, no boosting is done. ++ * This method does not fire {@link com.destroystokyo.paper.event.player.PlayerElytraBoostEvent}. ++ * ++ * @param firework The {@link Material#FIREWORK_ROCKET} to boost the player with ++ * @return The {@link Firework} boosting the Player or null if the spawning of the entity was cancelled ++ * @throws IllegalArgumentException if {@link #isGliding()} is false ++ * or if the {@code firework} isn't a {@link Material#FIREWORK_ROCKET} ++ * @deprecated use {@link HumanEntity#fireworkBoost(ItemStack)} instead. Note that this method does not ++ * check if the player is gliding or not. ++ */ ++ default @Nullable Firework boostElytra(final @NotNull ItemStack firework) { ++ com.google.common.base.Preconditions.checkState(this.isGliding(), "Player must be gliding"); ++ return this.fireworkBoost(firework); ++ } ++ // Paper end - elytra boost API ++ + // Spigot start + public class Spigot extends Entity.Spigot { + diff --git a/patches/api/0209-Add-and-implement-PlayerRecipeBookClickEvent.patch b/patches/api/0209-Add-and-implement-PlayerRecipeBookClickEvent.patch deleted file mode 100644 index 93bd233b8579..000000000000 --- a/patches/api/0209-Add-and-implement-PlayerRecipeBookClickEvent.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LordKorea -Date: Mon, 11 May 2020 22:38:10 -0400 -Subject: [PATCH] Add and implement PlayerRecipeBookClickEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7fa937d339ee98ad308deebb523fead6522eb262 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerRecipeBookClickEvent.java -@@ -0,0 +1,84 @@ -+package com.destroystokyo.paper.event.player; -+ -+import org.bukkit.NamespacedKey; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player clicks a recipe in the recipe book -+ */ -+public class PlayerRecipeBookClickEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancel = false; -+ @NotNull private NamespacedKey recipe; -+ private boolean makeAll; -+ -+ public PlayerRecipeBookClickEvent(@NotNull Player player, @NotNull NamespacedKey recipe, boolean makeAll) { -+ super(player); -+ this.recipe = recipe; -+ this.makeAll = makeAll; -+ } -+ -+ /** -+ * Gets the namespaced key of the recipe that was clicked by the player -+ * -+ * @return The namespaced key of the recipe -+ */ -+ @NotNull -+ public NamespacedKey getRecipe() { -+ return recipe; -+ } -+ -+ /** -+ * Changes what recipe is requested. This sets the requested recipe to the recipe with the given key -+ * -+ * @param recipe The key of the recipe that should be requested -+ */ -+ public void setRecipe(@NotNull NamespacedKey recipe) { -+ this.recipe = recipe; -+ } -+ -+ /** -+ * Gets a boolean which indicates whether or not the player requested to make the maximum amount of results. This is -+ * true if shift is pressed while the recipe is clicked in the recipe book -+ * -+ * @return {@code true} if shift is pressed while the recipe is clicked -+ */ -+ public boolean isMakeAll() { -+ return makeAll; -+ } -+ -+ /** -+ * Sets whether or not the maximum amount of results should be made. If this is true, the request is handled as if -+ * the player had pressed shift while clicking on the recipe -+ * -+ * @param makeAll {@code true} if the request should attempt to make the maximum amount of results -+ */ -+ public void setMakeAll(boolean makeAll) { -+ this.makeAll = makeAll; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0209-Add-getOfflinePlayerIfCached-String.patch b/patches/api/0209-Add-getOfflinePlayerIfCached-String.patch new file mode 100644 index 000000000000..a2b786d66915 --- /dev/null +++ b/patches/api/0209-Add-getOfflinePlayerIfCached-String.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: oxygencraft <21054297+oxygencraft@users.noreply.github.com> +Date: Sun, 25 Oct 2020 18:35:58 +1100 +Subject: [PATCH] Add getOfflinePlayerIfCached(String) + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index aca049c29cc7397a830883a45b4b24a33863e533..0fdce89f60fd66613cf41d962358f530cf75b905 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -1374,6 +1374,27 @@ public final class Bukkit { + return server.getOfflinePlayer(name); + } + ++ // Paper start ++ /** ++ * Gets the player by the given name, regardless if they are offline or ++ * online. ++ *

      ++ * This will not make a web request to get the UUID for the given name, ++ * thus this method will not block. However this method will return ++ * {@code null} if the player is not cached. ++ *

      ++ * ++ * @param name the name of the player to retrieve ++ * @return an offline player if cached, {@code null} otherwise ++ * @see #getOfflinePlayer(String) ++ * @see #getOfflinePlayer(java.util.UUID) ++ */ ++ @Nullable ++ public static OfflinePlayer getOfflinePlayerIfCached(@NotNull String name) { ++ return server.getOfflinePlayerIfCached(name); ++ } ++ // Paper end ++ + /** + * Gets the player by the given UUID, regardless if they are offline or + * online. +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 89208165cc6b864a9273c364ba4b2d6d86e3c31f..f0e7333c33132d71069e9eccd9d32a39fac8596f 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1161,6 +1161,25 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @NotNull + public OfflinePlayer getOfflinePlayer(@NotNull String name); + ++ // Paper start ++ /** ++ * Gets the player by the given name, regardless if they are offline or ++ * online. ++ *

      ++ * This will not make a web request to get the UUID for the given name, ++ * thus this method will not block. However this method will return ++ * {@code null} if the player is not cached. ++ *

      ++ * ++ * @param name the name of the player to retrieve ++ * @return an offline player if cached, {@code null} otherwise ++ * @see #getOfflinePlayer(String) ++ * @see #getOfflinePlayer(java.util.UUID) ++ */ ++ @Nullable ++ public OfflinePlayer getOfflinePlayerIfCached(@NotNull String name); ++ // Paper end ++ + /** + * Gets the player by the given UUID, regardless if they are offline or + * online. diff --git a/patches/api/0230-Add-ignore-discounts-API.patch b/patches/api/0210-Add-ignore-discounts-API.patch similarity index 100% rename from patches/api/0230-Add-ignore-discounts-API.patch rename to patches/api/0210-Add-ignore-discounts-API.patch diff --git a/patches/api/0210-Support-components-in-ItemMeta.patch b/patches/api/0210-Support-components-in-ItemMeta.patch deleted file mode 100644 index d9bc5b4ade11..000000000000 --- a/patches/api/0210-Support-components-in-ItemMeta.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MiniDigger -Date: Sat, 6 Jun 2020 18:13:16 +0200 -Subject: [PATCH] Support components in ItemMeta - - -diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -index 5428aeb018c415f8e9bb46c84a627adf70829259..f1e9a7626c4efb99be78f1056dc04b06bbe13c87 100644 ---- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -+++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java -@@ -5,6 +5,7 @@ import java.util.Collection; - import java.util.List; - import java.util.Map; - import java.util.Set; -+import net.kyori.adventure.text.Component; - import org.bukkit.attribute.Attribute; - import org.bukkit.attribute.AttributeModifier; - import org.bukkit.configuration.serialization.ConfigurationSerializable; -@@ -62,6 +63,20 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - @NotNull - String getDisplayName(); - -+ // Paper start -+ /** -+ * Gets the display name that is set. -+ *

      -+ * Plugins should check that hasDisplayName() returns true -+ * before calling this method. -+ * -+ * @return the display name that is set -+ * @deprecated use {@link #displayName()} -+ */ -+ @NotNull -+ @Deprecated -+ net.md_5.bungee.api.chat.BaseComponent[] getDisplayNameComponent(); -+ // Paper end - /** - * Sets the display name. - * -@@ -71,6 +86,16 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - @Deprecated // Paper - void setDisplayName(@Nullable String name); - -+ // Paper start -+ /** -+ * Sets the display name. -+ * -+ * @param component the name component to set -+ * @deprecated use {@link #displayName(Component)} -+ */ -+ @Deprecated -+ void setDisplayNameComponent(@Nullable net.md_5.bungee.api.chat.BaseComponent[] component); -+ // Paper end - /** - * Checks for existence of a localized name. - * -@@ -140,6 +165,19 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - @Nullable - List getLore(); - -+ /** -+ * Gets the lore that is set. -+ *

      -+ * Plugins should check if hasLore() returns true before -+ * calling this method. -+ * -+ * @return a list of lore that is set -+ * @deprecated use {@link #lore()} -+ */ -+ @Nullable -+ @Deprecated -+ List getLoreComponents(); -+ - /** - * Sets the lore for this item. - * Removes lore when given null. -@@ -150,6 +188,16 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste - @Deprecated // Paper - void setLore(@Nullable List lore); - -+ /** -+ * Sets the lore for this item. -+ * Removes lore when given null. -+ * -+ * @param lore the lore that will be set -+ * @deprecated use {@link #lore(List)} -+ */ -+ @Deprecated -+ void setLoreComponents(@Nullable List lore); -+ - /** - * Checks for existence of custom model data. - *

      diff --git a/patches/api/0211-Item-no-age-no-player-pickup.patch b/patches/api/0211-Item-no-age-no-player-pickup.patch new file mode 100644 index 000000000000..d3be2301afa1 --- /dev/null +++ b/patches/api/0211-Item-no-age-no-player-pickup.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alfie Smith +Date: Sat, 7 Nov 2020 01:20:27 +0000 +Subject: [PATCH] Item no age & no player pickup + + +diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java +index bfecd0633458586c0352eeb1a95bb57b12f9101e..6239aec4f6c625a814fa4fd610cdc5ab1a9f6e0f 100644 +--- a/src/main/java/org/bukkit/entity/Item.java ++++ b/src/main/java/org/bukkit/entity/Item.java +@@ -104,5 +104,34 @@ public interface Item extends Entity { + * @param canMobPickup True to allow non-player entity pickup + */ + public void setCanMobPickup(boolean canMobPickup); ++ ++ /** ++ * Gets whether the player can pickup the item or not ++ * ++ * @return True if a player can pickup the item ++ */ ++ public boolean canPlayerPickup(); ++ ++ /** ++ * Sets whether the item can be picked up or not. Modifies the pickup delay value to do so. ++ * ++ * @param canPlayerPickup True if the player can pickup the item ++ */ ++ public void setCanPlayerPickup(boolean canPlayerPickup); ++ ++ /** ++ * Gets whether the item will age and despawn from being on the ground too long ++ * ++ * @return True if the item will age ++ */ ++ public boolean willAge(); ++ ++ /** ++ * Sets whether the item will age or not. If the item is not ageing, it will not despawn ++ * by being on the ground for too long. ++ * ++ * @param willAge True if the item should age ++ */ ++ public void setWillAge(boolean willAge); + // Paper end + } diff --git a/patches/api/0211-added-2-new-TargetReasons-for-1.16-mob-behavior.patch b/patches/api/0211-added-2-new-TargetReasons-for-1.16-mob-behavior.patch deleted file mode 100644 index 747470a546b5..000000000000 --- a/patches/api/0211-added-2-new-TargetReasons-for-1.16-mob-behavior.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 3 Jul 2020 15:05:54 -0700 -Subject: [PATCH] added 2 new TargetReasons for 1.16 mob behavior - - -diff --git a/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java b/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java -index dee186e99463a56394bbc2039d1e763d109125b9..601904150156d475c18286b485f3409307a75950 100644 ---- a/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java -+++ b/src/main/java/org/bukkit/event/entity/EntityTargetEvent.java -@@ -159,6 +159,14 @@ public class EntityTargetEvent extends EntityEvent implements Cancellable { - * as wheat in it's hand. - */ - TEMPT, -+ /** -+ * When the target is in a different dimension -+ */ -+ TARGET_OTHER_LEVEL, // Paper -+ /** -+ * When the target is in creative or spectator mode, or the gamemode is peaceful, or other reasons -+ */ -+ TARGET_INVALID, // Paper - /** - * A currently unknown reason for the entity changing target. - */ diff --git a/patches/api/0212-Add-entity-liquid-API.patch b/patches/api/0212-Add-entity-liquid-API.patch deleted file mode 100644 index 6c8a843dee40..000000000000 --- a/patches/api/0212-Add-entity-liquid-API.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 2 Jul 2020 18:11:33 -0500 -Subject: [PATCH] Add entity liquid API - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 634f3b5dd22bf439aaec7c3ecfb3477b66e994e8..1c9d0e6541d41972f9966b83cbba02f6b230a72c 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -733,5 +733,35 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - */ - @NotNull - org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason(); -+ -+ /** -+ * Check if entity is in rain -+ */ -+ public boolean isInRain(); -+ -+ /** -+ * Check if entity is in bubble column -+ */ -+ public boolean isInBubbleColumn(); -+ -+ /** -+ * Check if entity is in water or rain -+ */ -+ public boolean isInWaterOrRain(); -+ -+ /** -+ * Check if entity is in water or bubble column -+ */ -+ public boolean isInWaterOrBubbleColumn(); -+ -+ /** -+ * Check if entity is in water or rain or bubble column -+ */ -+ public boolean isInWaterOrRainOrBubbleColumn(); -+ -+ /** -+ * Check if entity is in lava -+ */ -+ public boolean isInLava(); - // Paper end - } diff --git a/patches/api/0212-Beacon-API-custom-effect-ranges.patch b/patches/api/0212-Beacon-API-custom-effect-ranges.patch new file mode 100644 index 000000000000..effd7b3ae938 --- /dev/null +++ b/patches/api/0212-Beacon-API-custom-effect-ranges.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 24 Jun 2020 12:38:15 -0600 +Subject: [PATCH] Beacon API - custom effect ranges + + +diff --git a/src/main/java/org/bukkit/block/Beacon.java b/src/main/java/org/bukkit/block/Beacon.java +index 6349fa9da3f96df3553fb9552c1cab95338cecb0..7d212c409035ccb8b22d4ffc322b4a1aea367627 100644 +--- a/src/main/java/org/bukkit/block/Beacon.java ++++ b/src/main/java/org/bukkit/block/Beacon.java +@@ -64,4 +64,26 @@ public interface Beacon extends TileState, Lockable, Nameable { + * @param effect desired secondary effect + */ + void setSecondaryEffect(@Nullable PotionEffectType effect); ++ ++ // Paper start - Custom effect ranges ++ /** ++ * Gets the effect range of this beacon. ++ * A negative range value means the beacon is using its default range based on tier. ++ * @return Either the custom range set with {@link #setEffectRange(double)} or the range based on the beacon tier. ++ */ ++ double getEffectRange(); ++ ++ /** ++ * Sets the effect range of the beacon ++ * A negative range value means the beacon is using its default range based on tier. ++ * @param range Radius of effect range. ++ */ ++ void setEffectRange(double range); ++ ++ /** ++ * Resets the custom range from this beacon and falls back to the range based on the beacon tier. ++ * Shortcut for setting the effect range to a negative number. ++ */ ++ void resetEffectRange(); ++ // Paper end + } diff --git a/patches/api/0213-Add-API-for-quit-reason.patch b/patches/api/0213-Add-API-for-quit-reason.patch new file mode 100644 index 000000000000..0350afaf928a --- /dev/null +++ b/patches/api/0213-Add-API-for-quit-reason.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 14 Nov 2020 16:19:58 +0100 +Subject: [PATCH] Add API for quit reason + + +diff --git a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +index 14b27eaaf744736b3e56bb1383481df98a218c43..84703b5d174625b1a4a995a244e6400d2675fbb5 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +@@ -11,16 +11,28 @@ import org.jetbrains.annotations.Nullable; + public class PlayerQuitEvent extends PlayerEvent { + private static final HandlerList handlers = new HandlerList(); + private net.kyori.adventure.text.Component quitMessage; // Paper ++ private final QuitReason reason; // Paper + + @Deprecated // Paper + public PlayerQuitEvent(@NotNull final Player who, @Nullable final String quitMessage) { ++ // Paper start ++ this(who, quitMessage, null); ++ } ++ @Deprecated // Paper ++ public PlayerQuitEvent(@NotNull final Player who, @Nullable final String quitMessage, @Nullable QuitReason quitReason) { + super(who); + this.quitMessage = quitMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(quitMessage) : null; // Paper ++ this.reason = quitReason == null ? QuitReason.DISCONNECTED : quitReason; + } + // Paper start ++ @Deprecated + public PlayerQuitEvent(@NotNull final Player who, @Nullable final net.kyori.adventure.text.Component quitMessage) { ++ this(who, quitMessage, null); ++ } ++ public PlayerQuitEvent(@NotNull final Player who, @Nullable final net.kyori.adventure.text.Component quitMessage, @Nullable QuitReason quitReason) { + super(who); + this.quitMessage = quitMessage; ++ this.reason = quitReason == null ? QuitReason.DISCONNECTED : quitReason; + } + + /** +@@ -75,4 +87,39 @@ public class PlayerQuitEvent extends PlayerEvent { + public static HandlerList getHandlerList() { + return handlers; + } ++ ++ // Paper start ++ @NotNull ++ public QuitReason getReason() { ++ return this.reason; ++ } ++ ++ public enum QuitReason { ++ /** ++ * The player left on their own behalf. ++ *

      ++ * This does not mean they pressed the disconnect button in their client, but rather that the client severed the ++ * connection themselves. This may occur if no keep-alive packet is received on their side, among other things. ++ */ ++ DISCONNECTED, ++ ++ /** ++ * The player was kicked from the server. ++ */ ++ KICKED, ++ ++ /** ++ * The player has timed out. ++ */ ++ TIMED_OUT, ++ ++ /** ++ * The player's connection has entered an erroneous state. ++ *

      ++ * Reasons for this may include invalid packets, invalid data, and uncaught exceptions in the packet handler, ++ * among others. ++ */ ++ ERRONEOUS_STATE, ++ } ++ // Paper end + } diff --git a/patches/api/0213-Add-PrepareResultEvent-PrepareGrindstoneEvent.patch b/patches/api/0213-Add-PrepareResultEvent-PrepareGrindstoneEvent.patch deleted file mode 100644 index 5dc61d601d07..000000000000 --- a/patches/api/0213-Add-PrepareResultEvent-PrepareGrindstoneEvent.patch +++ /dev/null @@ -1,211 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 3 Jul 2020 11:58:56 -0500 -Subject: [PATCH] Add PrepareResultEvent / PrepareGrindstoneEvent - -Adds a new event for all crafting stations that generate a result slot item - -Anvil, Grindstone and Smithing now extend this event - -Grindstone is a backwards compat from a previous PrepareGrindstoneEvent - -diff --git a/src/main/java/com/destroystokyo/paper/event/inventory/PrepareGrindstoneEvent.java b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareGrindstoneEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..449e8c06f8434b59d49a76481fa60c5c49e80579 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareGrindstoneEvent.java -@@ -0,0 +1,28 @@ -+package com.destroystokyo.paper.event.inventory; -+ -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.inventory.InventoryEvent; -+import org.bukkit.inventory.GrindstoneInventory; -+import org.bukkit.inventory.InventoryView; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when an item is put in a slot for grinding in a Grindstone -+ * @see com.destroystokyo.paper.event.inventory.PrepareResultEvent -+ */ -+@Deprecated -+public class PrepareGrindstoneEvent extends PrepareResultEvent { -+ -+ public PrepareGrindstoneEvent(@NotNull InventoryView inventory, @Nullable ItemStack result) { -+ super(inventory, result); -+ } -+ -+ @NotNull -+ @Override -+ public GrindstoneInventory getInventory() { -+ return (GrindstoneInventory) super.getInventory(); -+ } -+ -+} -diff --git a/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..045ce9ec3c9134aced5f5235b760ac85599d16c6 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/inventory/PrepareResultEvent.java -@@ -0,0 +1,48 @@ -+package com.destroystokyo.paper.event.inventory; -+ -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.inventory.InventoryEvent; -+import org.bukkit.event.inventory.InventoryType; -+import org.bukkit.inventory.InventoryView; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when an item is put in an inventory containing a result slot -+ */ -+public class PrepareResultEvent extends InventoryEvent { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ private ItemStack result; -+ -+ public PrepareResultEvent(@NotNull InventoryView inventory, @Nullable ItemStack result) { -+ super(inventory); -+ this.result = result; -+ } -+ -+ /** -+ * Get result item, may be null. -+ * -+ * @return result item -+ */ -+ @Nullable -+ public ItemStack getResult() { -+ return result; -+ } -+ -+ public void setResult(@Nullable ItemStack result) { -+ this.result = result; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java b/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java -index 77109a07f07aa6985106dc1a9ad5218f6c7f360f..f1f6f4ab4f81a3f21e757fef4a30b00e94371f8d 100644 ---- a/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java -+++ b/src/main/java/org/bukkit/event/inventory/PrepareAnvilEvent.java -@@ -1,5 +1,6 @@ - package org.bukkit.event.inventory; - -+import com.destroystokyo.paper.event.inventory.PrepareResultEvent; - import org.bukkit.event.HandlerList; - import org.bukkit.inventory.AnvilInventory; - import org.bukkit.inventory.InventoryView; -@@ -10,14 +11,16 @@ import org.jetbrains.annotations.Nullable; - /** - * Called when an item is put in a slot for repair by an anvil. - */ --public class PrepareAnvilEvent extends InventoryEvent { -+// Paper start - extend PrepareResultEvent -+public class PrepareAnvilEvent extends PrepareResultEvent { - -- private static final HandlerList handlers = new HandlerList(); -- private ItemStack result; -+ //private static final HandlerList handlers = new HandlerList(); -+ //private ItemStack result; - - public PrepareAnvilEvent(@NotNull InventoryView inventory, @Nullable ItemStack result) { -- super(inventory); -- this.result = result; -+ super(inventory, result); -+ //this.result = result; -+ // Paper end - } - - @NotNull -@@ -33,13 +36,14 @@ public class PrepareAnvilEvent extends InventoryEvent { - */ - @Nullable - public ItemStack getResult() { -- return result; -+ return super.getResult(); // Paper - } - - public void setResult(@Nullable ItemStack result) { -- this.result = result; -+ super.setResult(result); // Paper - } - -+ /* // Paper - comment out - @NotNull - @Override - public HandlerList getHandlers() { -@@ -50,4 +54,5 @@ public class PrepareAnvilEvent extends InventoryEvent { - public static HandlerList getHandlerList() { - return handlers; - } -+ */ // Paper - } -diff --git a/src/main/java/org/bukkit/event/inventory/PrepareSmithingEvent.java b/src/main/java/org/bukkit/event/inventory/PrepareSmithingEvent.java -index 99af1540324c4d68c5890ac40b591c5cbdd2e870..0bc0ca4f96c800e9c46c61710f44446691d8b93f 100644 ---- a/src/main/java/org/bukkit/event/inventory/PrepareSmithingEvent.java -+++ b/src/main/java/org/bukkit/event/inventory/PrepareSmithingEvent.java -@@ -1,5 +1,6 @@ - package org.bukkit.event.inventory; - -+import com.destroystokyo.paper.event.inventory.PrepareResultEvent; - import org.bukkit.event.HandlerList; - import org.bukkit.inventory.InventoryView; - import org.bukkit.inventory.ItemStack; -@@ -10,14 +11,16 @@ import org.jetbrains.annotations.Nullable; - /** - * Called when an item is put in a slot for upgrade by a Smithing Table. - */ --public class PrepareSmithingEvent extends InventoryEvent { -+// Paper start - extend PrepareResultEvent -+public class PrepareSmithingEvent extends PrepareResultEvent { - -- private static final HandlerList handlers = new HandlerList(); -- private ItemStack result; -+ //private static final HandlerList handlers = new HandlerList(); -+ //private ItemStack result; - - public PrepareSmithingEvent(@NotNull InventoryView inventory, @Nullable ItemStack result) { -- super(inventory); -- this.result = result; -+ super(inventory, result); -+ //this.result = result; -+ // Paper end - } - - @NotNull -@@ -33,13 +36,14 @@ public class PrepareSmithingEvent extends InventoryEvent { - */ - @Nullable - public ItemStack getResult() { -- return result; -+ return super.getResult(); // Paper - } - - public void setResult(@Nullable ItemStack result) { -- this.result = result; -+ super.setResult(result); // Paper - } - -+ /* // Paper - comment out - @NotNull - @Override - public HandlerList getHandlers() { -@@ -50,4 +54,5 @@ public class PrepareSmithingEvent extends InventoryEvent { - public static HandlerList getHandlerList() { - return handlers; - } -+ */ // Paper - } diff --git a/patches/api/0214-Add-Destroy-Speed-API.patch b/patches/api/0214-Add-Destroy-Speed-API.patch new file mode 100644 index 000000000000..b79ab15ff0b3 --- /dev/null +++ b/patches/api/0214-Add-Destroy-Speed-API.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ineusia +Date: Mon, 26 Oct 2020 11:37:48 -0500 +Subject: [PATCH] Add Destroy Speed API + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index afed7dfcbc878c19d3821dde77d6ade084ccf271..4666f47666ec50dc47e783f7bd4412148d3a5380 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -690,4 +690,31 @@ public interface Block extends Metadatable, Translatable, net.kyori.adventure.tr + @Deprecated(forRemoval = true) + String getTranslationKey(); + // Paper end ++ ++ // Paper start - destroy speed API ++ /** ++ * Gets the speed at which this block will be destroyed by a given {@link ItemStack} ++ *

      ++ * Default value is 1.0 ++ * ++ * @param itemStack {@link ItemStack} used to mine this Block ++ * @return the speed that this Block will be mined by the given {@link ItemStack} ++ */ ++ default float getDestroySpeed(final @NotNull ItemStack itemStack) { ++ return this.getBlockData().getDestroySpeed(itemStack); ++ } ++ ++ /** ++ * Gets the speed at which this block will be destroyed by a given {@link ItemStack} ++ *

      ++ * Default value is 1.0 ++ * ++ * @param itemStack {@link ItemStack} used to mine this Block ++ * @param considerEnchants true to look at enchants on the itemstack ++ * @return the speed that this Block will be mined by the given {@link ItemStack} ++ */ ++ default float getDestroySpeed(@NotNull ItemStack itemStack, boolean considerEnchants) { ++ return this.getBlockData().getDestroySpeed(itemStack, considerEnchants); ++ } ++ // Paper end - destroy speed API + } +diff --git a/src/main/java/org/bukkit/block/data/BlockData.java b/src/main/java/org/bukkit/block/data/BlockData.java +index cd3b3e05cc825cfedec07f9a2a1e0b7b2a8866d6..890a511355dd3f2aa9330fdc72c0fb4b3e44e5cb 100644 +--- a/src/main/java/org/bukkit/block/data/BlockData.java ++++ b/src/main/java/org/bukkit/block/data/BlockData.java +@@ -266,4 +266,33 @@ public interface BlockData extends Cloneable { + @NotNull + @ApiStatus.Experimental + BlockState createBlockState(); ++ ++ // Paper start - destroy speed API ++ /** ++ * Gets the speed at which this block will be destroyed by a given {@link ItemStack} ++ *

      ++ * Default value is 1.0 ++ * ++ * @param itemStack {@link ItemStack} used to mine this Block ++ * @return the speed that this Block will be mined by the given {@link ItemStack} ++ * @apiNote this method assumes default player state and hence, e.g., does not take into account changed ++ * player attributes or potion effects. ++ */ ++ default float getDestroySpeed(final @NotNull ItemStack itemStack) { ++ return this.getDestroySpeed(itemStack, false); ++ } ++ ++ /** ++ * Gets the speed at which this block will be destroyed by a given {@link ItemStack} ++ *

      ++ * Default value is 1.0 ++ * ++ * @param itemStack {@link ItemStack} used to mine this Block ++ * @param considerEnchants true to look at enchants on the itemstack ++ * @return the speed that this Block will be mined by the given {@link ItemStack} ++ * @apiNote this method assumes default player state and hence, e.g., does not take into account changed ++ * player attributes or potion effects. ++ */ ++ float getDestroySpeed(@NotNull ItemStack itemStack, boolean considerEnchants); ++ // Paper end - destroy speed API + } diff --git a/patches/api/0214-Brand-support.patch b/patches/api/0214-Brand-support.patch deleted file mode 100644 index fc68f4cecf4b..000000000000 --- a/patches/api/0214-Brand-support.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DigitalRegent -Date: Mon, 6 Apr 2020 20:30:09 +0200 -Subject: [PATCH] Brand support - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 797c49510a515b4423bb7b886726afaf63305227..73dbe57b872db6a0ff4812af9c359fb8e632fb9c 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -2613,6 +2613,16 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - // Paper end - } - -+ // Paper start - brand support -+ /** -+ * Returns player's client brand name. If the client didn't send this information, the brand name will be null.
      -+ * For the Notchian client this name defaults to vanilla. Some modified clients report other names such as forge.
      -+ * @return client brand name -+ */ -+ @Nullable -+ String getClientBrandName(); -+ // Paper end -+ - @NotNull - @Override - Spigot spigot(); diff --git a/patches/api/0215-Add-LivingEntity-clearActiveItem.patch b/patches/api/0215-Add-LivingEntity-clearActiveItem.patch new file mode 100644 index 000000000000..41ac39910a0b --- /dev/null +++ b/patches/api/0215-Add-LivingEntity-clearActiveItem.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Anrza +Date: Wed, 15 Jul 2020 12:07:58 +0200 +Subject: [PATCH] Add LivingEntity#clearActiveItem + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index e37ae6f7641c813c916618a60d97679125ebc16e..14a569f49a6fc1ff2d1c366516c09d3ba7da8fb0 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1071,6 +1071,11 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + org.bukkit.inventory.@NotNull ItemStack getActiveItem(); + ++ /** ++ * Interrupts any ongoing active "usage" or consumption or an item. ++ */ ++ void clearActiveItem(); ++ + /** + * Gets the remaining number of ticks for {@link #getActiveItem()}'s usage. + * diff --git a/patches/api/0215-Support-hex-colors-in-getLastColors.patch b/patches/api/0215-Support-hex-colors-in-getLastColors.patch deleted file mode 100644 index fec6bebf3caa..000000000000 --- a/patches/api/0215-Support-hex-colors-in-getLastColors.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Gerrygames -Date: Thu, 16 Jul 2020 10:40:10 +0200 -Subject: [PATCH] Support hex colors in getLastColors - - -diff --git a/src/main/java/org/bukkit/ChatColor.java b/src/main/java/org/bukkit/ChatColor.java -index 24ade174df77d75339b44bcd4b035e0c46d95dc3..f6eb30f53dad684f156102cf7147b2f00c82c71e 100644 ---- a/src/main/java/org/bukkit/ChatColor.java -+++ b/src/main/java/org/bukkit/ChatColor.java -@@ -363,6 +363,7 @@ public enum ChatColor { - return new String(b); - } - -+ private static final Pattern HEX_COLOR_PATTERN = Pattern.compile(COLOR_CHAR + "x(?>" + COLOR_CHAR + "[0-9a-f]){6}", Pattern.CASE_INSENSITIVE); // Paper - Support hex colors in getLastColors - /** - * Gets the ChatColors used at the end of the given input string. - * -@@ -380,6 +381,15 @@ public enum ChatColor { - for (int index = length - 1; index > -1; index--) { - char section = input.charAt(index); - if (section == COLOR_CHAR && index < length - 1) { -+ // Paper start - Support hex colors -+ if (index > 11 && input.charAt(index - 12) == COLOR_CHAR && (input.charAt(index - 11) == 'x' || input.charAt(index - 11) == 'X')) { -+ String color = input.substring(index - 12, index + 2); -+ if (HEX_COLOR_PATTERN.matcher(color).matches()) { -+ result = color + result; -+ break; -+ } -+ } -+ // Paper end - char c = input.charAt(index + 1); - ChatColor color = getByChar(c); - diff --git a/patches/api/0216-Add-PlayerItemCooldownEvent.patch b/patches/api/0216-Add-PlayerItemCooldownEvent.patch new file mode 100644 index 000000000000..13bfa89a28e1 --- /dev/null +++ b/patches/api/0216-Add-PlayerItemCooldownEvent.patch @@ -0,0 +1,133 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Tue, 25 Aug 2020 13:45:15 +0200 +Subject: [PATCH] Add PlayerItemCooldownEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerItemCooldownEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerItemCooldownEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..165dcf8b68da5dc01eaa83b3bffd7a2bbf0df526 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerItemCooldownEvent.java +@@ -0,0 +1,34 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.Material; ++import org.bukkit.NamespacedKey; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a player receives an item cooldown when using an item. ++ * ++ * @see PlayerItemGroupCooldownEvent for a more general event when applied to a group of items ++ */ ++@NullMarked ++public class PlayerItemCooldownEvent extends PlayerItemGroupCooldownEvent { ++ ++ private final Material type; ++ ++ @ApiStatus.Internal ++ public PlayerItemCooldownEvent(final Player player, final Material type, final NamespacedKey cooldownGroup, final int cooldown) { ++ super(player, cooldownGroup, cooldown); ++ this.type = type; ++ } ++ ++ /** ++ * Get the material of the item affected by the cooldown. ++ * ++ * @return material affected by the cooldown ++ */ ++ public Material getType() { ++ return this.type; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerItemGroupCooldownEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerItemGroupCooldownEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e66aed33b165b86cc5e51eb5c29159232be4a9ef +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerItemGroupCooldownEvent.java +@@ -0,0 +1,81 @@ ++package io.papermc.paper.event.player; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.NamespacedKey; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a player receives an item cooldown. ++ * ++ * @see PlayerItemCooldownEvent for a more specific event when applied to a specific item. ++ */ ++@NullMarked ++public class PlayerItemGroupCooldownEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final NamespacedKey cooldownGroup; ++ private int cooldown; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerItemGroupCooldownEvent(final Player player, final NamespacedKey cooldownGroup, final int cooldown) { ++ super(player); ++ this.cooldownGroup = cooldownGroup; ++ this.cooldown = cooldown; ++ } ++ ++ /** ++ * Get the cooldown group as defined by an item's {@link org.bukkit.inventory.meta.components.UseCooldownComponent}. ++ * ++ * @return cooldown group ++ */ ++ public NamespacedKey getCooldownGroup() { ++ return this.cooldownGroup; ++ } ++ ++ /** ++ * Gets the cooldown in ticks. ++ * ++ * @return cooldown in ticks ++ */ ++ public int getCooldown() { ++ return this.cooldown; ++ } ++ ++ /** ++ * Sets the cooldown of the material in ticks. ++ * Setting the cooldown to 0 results in removing an already existing cooldown for the material. ++ * ++ * @param cooldown cooldown in ticks, has to be a positive number ++ */ ++ public void setCooldown(final int cooldown) { ++ Preconditions.checkArgument(cooldown >= 0, "The cooldown has to be equal to or greater than 0!"); ++ this.cooldown = cooldown; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0216-Add-setMaxPlayers-API.patch b/patches/api/0216-Add-setMaxPlayers-API.patch deleted file mode 100644 index d4ded71a7932..000000000000 --- a/patches/api/0216-Add-setMaxPlayers-API.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 22 Aug 2020 23:59:25 +0200 -Subject: [PATCH] Add #setMaxPlayers API - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 3faefc48a2dca51f19d4289547f0ce875bb61e32..4b2f3e674e634efa42f6840933dd9ee9595d036b 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -207,6 +207,17 @@ public final class Bukkit { - return server.getMaxPlayers(); - } - -+ // Paper start -+ /** -+ * Set the maximum amount of players which can login to this server. -+ * -+ * @param maxPlayers the amount of players this server allows -+ */ -+ public static void setMaxPlayers(int maxPlayers) { -+ server.setMaxPlayers(maxPlayers); -+ } -+ // Paper end -+ - /** - * Get the game port that the server runs on. - * -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index c11d802408c793c6410118bd281a21e59394066f..a7ba813396fab77bed292422f881b5a0952972fb 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -159,6 +159,15 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - */ - public int getMaxPlayers(); - -+ // Paper start -+ /** -+ * Set the maximum amount of players which can login to this server. -+ * -+ * @param maxPlayers the amount of players this server allows -+ */ -+ public void setMaxPlayers(int maxPlayers); -+ // Paper end -+ - /** - * Get the game port that the server runs on. - * diff --git a/patches/api/0217-Add-BellRingEvent.patch b/patches/api/0217-Add-BellRingEvent.patch deleted file mode 100644 index 7862ad8c8885..000000000000 --- a/patches/api/0217-Add-BellRingEvent.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eearslya Sleiarion -Date: Mon, 24 Jun 2019 21:27:39 -0700 -Subject: [PATCH] Add BellRingEvent - -Add a new event, BellRingEvent, to trigger whenever a player rings a -village bell. Passes along the bell block and the player who rang it. - -diff --git a/src/main/java/io/papermc/paper/event/block/BellRingEvent.java b/src/main/java/io/papermc/paper/event/block/BellRingEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..881e545df51409e6101b4bb49f699655a744f13f ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/BellRingEvent.java -@@ -0,0 +1,55 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.entity.Entity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.bukkit.potion.PotionEffect; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when a bell is rung. -+ */ -+public class BellRingEvent extends BlockEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private final Entity entity; -+ -+ public BellRingEvent(@NotNull Block block, @Nullable Entity entity) { -+ super(block); -+ this.entity = entity; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancelled) { -+ this.cancelled = cancelled; -+ } -+ -+ /** -+ * Gets the entity that rang the bell. -+ * -+ * @return the ringer or null if none -+ */ -+ @Nullable -+ public Entity getEntity() { -+ return entity; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0217-More-lightning-API.patch b/patches/api/0217-More-lightning-API.patch new file mode 100644 index 000000000000..e96fd964b7f3 --- /dev/null +++ b/patches/api/0217-More-lightning-API.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Sun, 26 Jul 2020 14:44:16 +0200 +Subject: [PATCH] More lightning API + + +diff --git a/src/main/java/org/bukkit/entity/LightningStrike.java b/src/main/java/org/bukkit/entity/LightningStrike.java +index 608628b6328e4235fe2be0e4189babb5188361aa..fb2a9b10b7db074f275ef654643d9a5dd1284947 100644 +--- a/src/main/java/org/bukkit/entity/LightningStrike.java ++++ b/src/main/java/org/bukkit/entity/LightningStrike.java +@@ -22,7 +22,9 @@ public interface LightningStrike extends Entity { + * removed. By default this value is between 1 and 3. + * + * @return the flashes ++ * @deprecated use {@link #getFlashCount()} + */ ++ @Deprecated // Paper + public int getFlashes(); + + /** +@@ -31,7 +33,9 @@ public interface LightningStrike extends Entity { + * has reduced below 0. + * + * @param flashes the flashes ++ * @deprecated use {@link #setFlashCount(int)} + */ ++ @Deprecated // Paper + public void setFlashes(int flashes); + + /** +@@ -110,4 +114,42 @@ public interface LightningStrike extends Entity { + @Deprecated // Paper + Spigot spigot(); + // Spigot end ++ ++ // Paper start ++ /** ++ * Returns the amount of flash iterations that will be done before the lightning dies. ++ * ++ * @see #getLifeTicks() for how long the current flash will last ++ * @return amount of flashes that will be shown before the lightning dies ++ */ ++ int getFlashCount(); ++ ++ /** ++ * Sets the amount of life iterations that will be done before the lightning dies. ++ * Default number of flashes on creation is between 1-3. ++ * ++ * @param flashes amount of iterations that will be done before the lightning dies, must to be a positive number ++ */ ++ void setFlashCount(int flashes); ++ ++ /** ++ * Returns the potential entity that caused this lightning strike to spawn in the world. ++ *

      ++ * As of implementing this method, only {@link Player}s are capable of causing a lightning strike, however as this ++ * might change in future minecraft releases, this method does not guarantee a player as the cause of a lightning. ++ * Consumers of this method should hence validate whether or not the entity is a player if they want to use player ++ * specific methods through an {@code instanceOf} check. ++ *

      ++ *

      ++ * A player is, as of implementing this method, responsible for a lightning, and will hence be returned here as ++ * a cause, if they channeled a {@link Trident} to summon it or were explicitly defined as the cause of this ++ * lightning through {@link #setCausingPlayer(Player)}. ++ *

      ++ * ++ * @return the entity that caused this lightning or null if the lightning was not caused by a entity (e.g. normal ++ * weather) ++ */ ++ @org.jetbrains.annotations.Nullable ++ Entity getCausingEntity(); ++ // Paper end + } diff --git a/patches/api/0218-Add-PlayerShearBlockEvent.patch b/patches/api/0218-Add-PlayerShearBlockEvent.patch new file mode 100644 index 000000000000..74085cee3d56 --- /dev/null +++ b/patches/api/0218-Add-PlayerShearBlockEvent.patch @@ -0,0 +1,119 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Thu, 27 Aug 2020 12:32:35 -0400 +Subject: [PATCH] Add PlayerShearBlockEvent + + +diff --git a/src/main/java/io/papermc/paper/event/block/PlayerShearBlockEvent.java b/src/main/java/io/papermc/paper/event/block/PlayerShearBlockEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..33c6e1868e1bad4802bcadecebc2b46633690fce +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/PlayerShearBlockEvent.java +@@ -0,0 +1,107 @@ ++package io.papermc.paper.event.block; ++ ++import java.util.List; ++import org.bukkit.block.Block; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.EquipmentSlot; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player uses sheers on a block. ++ *

      ++ * This event is not called when breaking blocks with shears but instead only when a ++ * player uses the sheer item on a block to garner drops from said block and/or change its state. ++ *

      ++ * Examples include shearing a pumpkin to turn it into a carved pumpkin or shearing a beehive to get honeycomb. ++ */ ++@NullMarked ++public class PlayerShearBlockEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Block block; ++ private final ItemStack item; ++ private final EquipmentSlot hand; ++ private final List drops; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerShearBlockEvent(final Player player, final Block block, final ItemStack item, final EquipmentSlot hand, final List drops) { ++ super(player); ++ this.block = block; ++ this.item = item; ++ this.hand = hand; ++ this.drops = drops; ++ } ++ ++ /** ++ * Gets the block being sheared in this event. ++ * ++ * @return The {@link Block} which block is being sheared in this event. ++ */ ++ public Block getBlock() { ++ return this.block; ++ } ++ ++ /** ++ * Gets the item used to shear the block. ++ * ++ * @return The {@link ItemStack} of the shears. ++ */ ++ public ItemStack getItem() { ++ return this.item; ++ } ++ ++ /** ++ * Gets the hand used to shear the block. ++ * ++ * @return Either {@link EquipmentSlot#HAND} OR {@link EquipmentSlot#OFF_HAND}. ++ */ ++ public EquipmentSlot getHand() { ++ return this.hand; ++ } ++ ++ /** ++ * Gets the resulting drops of this event. ++ * ++ * @return A mutable {@link List list} of {@link ItemStack items} that will be dropped as result of this event. ++ */ ++ public List getDrops() { ++ return this.drops; ++ } ++ ++ /** ++ * Gets whether the shearing of the block should be cancelled or not. ++ * ++ * @return Whether the shearing of the block should be cancelled or not. ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * Sets whether the shearing of the block should be cancelled or not. ++ * ++ * @param cancel whether the shearing of the block should be cancelled or not. ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0218-Add-moon-phase-API.patch b/patches/api/0218-Add-moon-phase-API.patch deleted file mode 100644 index 1a307b07217e..000000000000 --- a/patches/api/0218-Add-moon-phase-API.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 23 Aug 2020 16:32:03 +0200 -Subject: [PATCH] Add moon phase API - - -diff --git a/src/main/java/io/papermc/paper/world/MoonPhase.java b/src/main/java/io/papermc/paper/world/MoonPhase.java -new file mode 100644 -index 0000000000000000000000000000000000000000..df05153397b42930cd53d37b30824c7e5f008f7e ---- /dev/null -+++ b/src/main/java/io/papermc/paper/world/MoonPhase.java -@@ -0,0 +1,36 @@ -+package io.papermc.paper.world; -+ -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.HashMap; -+import java.util.Map; -+ -+public enum MoonPhase { -+ FULL_MOON(0L), -+ WANING_GIBBOUS(1L), -+ LAST_QUARTER(2L), -+ WANING_CRESCENT(3L), -+ NEW_MOON(4L), -+ WAXING_CRESCENT(5L), -+ FIRST_QUARTER(6L), -+ WAXING_GIBBOUS(7L); -+ -+ private final long day; -+ -+ MoonPhase(long day) { -+ this.day = day; -+ } -+ -+ private static final Map BY_DAY = new HashMap<>(); -+ -+ static { -+ for (MoonPhase phase : values()) { -+ BY_DAY.put(phase.day, phase); -+ } -+ } -+ -+ @NotNull -+ public static MoonPhase getPhase(long day) { -+ return BY_DAY.get(day % 8L); -+ } -+} -diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java -index e55f6e2baf35dbd91c433ab9e62713eaac85435b..2fa3de66107162ccaa158b369e2c4a926ecaff92 100644 ---- a/src/main/java/org/bukkit/RegionAccessor.java -+++ b/src/main/java/org/bukkit/RegionAccessor.java -@@ -376,4 +376,12 @@ public interface RegionAccessor { - */ - @NotNull - public T spawn(@NotNull Location location, @NotNull Class clazz, boolean randomizeData, @Nullable Consumer function) throws IllegalArgumentException; -+ -+ // Paper start -+ /** -+ * @return the current moon phase at the current time in the world -+ */ -+ @NotNull -+ io.papermc.paper.world.MoonPhase getMoonPhase(); -+ // Paper end - } diff --git a/patches/api/0219-Add-playPickupItemAnimation-to-LivingEntity.patch b/patches/api/0219-Add-playPickupItemAnimation-to-LivingEntity.patch deleted file mode 100644 index 1245cd5bdb3d..000000000000 --- a/patches/api/0219-Add-playPickupItemAnimation-to-LivingEntity.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 23 Aug 2020 19:36:08 +0200 -Subject: [PATCH] Add playPickupItemAnimation to LivingEntity - - -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index c11de6fbaa6fce8b341ac6c4d9478c18481cc0ef..37bb2f8c0eba7713793ef51a16f7ca5981e39747 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -821,5 +821,28 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - * @param jumping entity jump state - */ - void setJumping(boolean jumping); -+ -+ /** -+ * Plays pickup item animation towards this entity. -+ *

      -+ * This will remove the item on the client. -+ *

      -+ * Quantity is inferred to be that of the {@link Item}. -+ * -+ * @param item item to pickup -+ */ -+ default void playPickupItemAnimation(@NotNull Item item) { -+ playPickupItemAnimation(item, item.getItemStack().getAmount()); -+ } -+ -+ /** -+ * Plays pickup item animation towards this entity. -+ *

      -+ * This will remove the item on the client. -+ * -+ * @param item item to pickup -+ * @param quantity quantity of item -+ */ -+ void playPickupItemAnimation(@NotNull Item item, int quantity); - // Paper end - } diff --git a/patches/api/0219-Player-Chunk-Load-Unload-Events.patch b/patches/api/0219-Player-Chunk-Load-Unload-Events.patch new file mode 100644 index 000000000000..bbfe5bf16966 --- /dev/null +++ b/patches/api/0219-Player-Chunk-Load-Unload-Events.patch @@ -0,0 +1,102 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: ysl3000 +Date: Mon, 5 Oct 2020 21:24:45 +0200 +Subject: [PATCH] Player Chunk Load/Unload Events + + +diff --git a/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java b/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2815c5802eb38e5a48f9db42b9247e24c27db134 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java +@@ -0,0 +1,43 @@ ++package io.papermc.paper.event.packet; ++ ++import org.bukkit.Chunk; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.world.ChunkEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Is called when a {@link Player} receives a {@link Chunk} ++ *

      ++ * Can for example be used for spawning a fake entity when the player receives a chunk. ++ *

      ++ * Should only be used for packet/clientside related stuff. ++ * Not intended for modifying server side state. ++ */ ++@NullMarked ++public class PlayerChunkLoadEvent extends ChunkEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Player player; ++ ++ @ApiStatus.Internal ++ public PlayerChunkLoadEvent(final Chunk chunk, final Player player) { ++ super(chunk); ++ this.player = player; ++ } ++ ++ public Player getPlayer() { ++ return this.player; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java b/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3ebb35b680193109cc751398675e935eed746750 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java +@@ -0,0 +1,41 @@ ++package io.papermc.paper.event.packet; ++ ++import org.bukkit.Chunk; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.world.ChunkEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Is called when a {@link Player} receives a chunk unload packet. ++ *

      ++ * Should only be used for packet/clientside related stuff. ++ * Not intended for modifying server side. ++ */ ++@NullMarked ++public class PlayerChunkUnloadEvent extends ChunkEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Player player; ++ ++ @ApiStatus.Internal ++ public PlayerChunkUnloadEvent(final Chunk chunk, final Player player) { ++ super(chunk); ++ this.player = player; ++ } ++ ++ public Player getPlayer() { ++ return this.player; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0220-Add-more-Evoker-API.patch b/patches/api/0220-Add-more-Evoker-API.patch deleted file mode 100644 index 0d6f0f73285b..000000000000 --- a/patches/api/0220-Add-more-Evoker-API.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 23 Aug 2020 15:22:44 +0200 -Subject: [PATCH] Add more Evoker API - - -diff --git a/src/main/java/org/bukkit/entity/Evoker.java b/src/main/java/org/bukkit/entity/Evoker.java -index f8d173adc09197418883dc7bc66dd8bfff8c5c72..76f81cd124090337876c9e5e469862a1c8da4ec8 100644 ---- a/src/main/java/org/bukkit/entity/Evoker.java -+++ b/src/main/java/org/bukkit/entity/Evoker.java -@@ -64,4 +64,19 @@ public interface Evoker extends Spellcaster { - */ - @Deprecated - void setCurrentSpell(@Nullable Spell spell); -+ -+ // Paper start -+ /** -+ * @return the sheep being targeted by the {@link Spell#WOLOLO wololo spell}, or {@code null} if none -+ */ -+ @Nullable -+ Sheep getWololoTarget(); -+ -+ /** -+ * Set the sheep to be the target of the {@link Spell#WOLOLO wololo spell}, or {@code null} to clear. -+ * -+ * @param sheep new wololo target -+ */ -+ void setWololoTarget(@Nullable Sheep sheep); -+ // Paper end - } diff --git a/patches/api/0220-Expose-LivingEntity-hurt-direction.patch b/patches/api/0220-Expose-LivingEntity-hurt-direction.patch new file mode 100644 index 000000000000..b1a91da4c293 --- /dev/null +++ b/patches/api/0220-Expose-LivingEntity-hurt-direction.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Vainomaa +Date: Sun, 13 Dec 2020 05:32:12 +0200 +Subject: [PATCH] Expose LivingEntity hurt direction + + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index 3859b12fad09cd181a914d152a9928d5bb720ca2..551b2a85745382ea6e0038088e6229260bfea067 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -356,6 +356,16 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder + */ + public void setCooldown(@NotNull Material material, int ticks); + ++ // Paper start ++ /** ++ * Sets player hurt direction ++ * ++ * @param hurtDirection hurt direction ++ */ ++ @Override ++ void setHurtDirection(float hurtDirection); ++ // Paper end ++ + /** + * Check whether a cooldown is active on the specified item. + * +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 14a569f49a6fc1ff2d1c366516c09d3ba7da8fb0..a50b0b83708794e86ba83d1d2337296deb351da6 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1211,4 +1211,22 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + void playPickupItemAnimation(@NotNull Item item, int quantity); + // Paper end - pickup animation API ++ ++ // Paper start - hurt direction API ++ /** ++ * Gets player hurt direction ++ * ++ * @return hurt direction ++ */ ++ float getHurtDirection(); ++ ++ /** ++ * Sets player hurt direction ++ * ++ * @param hurtDirection hurt direction ++ * @deprecated use {@link Player#setHurtDirection(float)} ++ */ ++ @Deprecated ++ void setHurtDirection(float hurtDirection); ++ // Paper end - hurt direction API + } diff --git a/patches/api/0221-Add-OBSTRUCTED-reason-to-BedEnterResult.patch b/patches/api/0221-Add-OBSTRUCTED-reason-to-BedEnterResult.patch new file mode 100644 index 000000000000..efae0208b43b --- /dev/null +++ b/patches/api/0221-Add-OBSTRUCTED-reason-to-BedEnterResult.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 24 Dec 2020 12:43:30 -0800 +Subject: [PATCH] Add OBSTRUCTED reason to BedEnterResult + + +diff --git a/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java b/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java +index 567e331f6c0e403cac1d6a7c2d86ed0cd540ca7d..dad760bbbcc7dd25143e0267318a6820f1d60a73 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java +@@ -42,6 +42,12 @@ public class PlayerBedEnterEvent extends PlayerEvent implements Cancellable { + * Entering the bed is prevented due to the player being too far away. + */ + TOO_FAR_AWAY, ++ // Paper start ++ /** ++ * Bed was obstructed. ++ */ ++ OBSTRUCTED, ++ // Paper end + /** + * Entering the bed is prevented due to there being monsters nearby. + */ diff --git a/patches/api/0221-Add-methods-to-get-translation-keys.patch b/patches/api/0221-Add-methods-to-get-translation-keys.patch deleted file mode 100644 index 80ce3016536f..000000000000 --- a/patches/api/0221-Add-methods-to-get-translation-keys.patch +++ /dev/null @@ -1,493 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 11 Aug 2020 19:17:46 +0200 -Subject: [PATCH] Add methods to get translation keys - -Co-authored-by: MeFisto94 - -diff --git a/src/main/java/org/bukkit/Difficulty.java b/src/main/java/org/bukkit/Difficulty.java -index 3f6cbefc2b1414ba2dad709e79288013b3ef73be..122884098f08c9aa5e144876746b5ce4e8f1a4b6 100644 ---- a/src/main/java/org/bukkit/Difficulty.java -+++ b/src/main/java/org/bukkit/Difficulty.java -@@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable; - /** - * Represents the various difficulty levels that are available. - */ --public enum Difficulty { -+public enum Difficulty implements net.kyori.adventure.translation.Translatable { // Paper - Adventure translations - /** - * Players regain health over time, hostile mobs don't spawn, the hunger - * bar does not deplete. -@@ -51,6 +51,12 @@ public enum Difficulty { - return value; - } - -+ // Paper start -+ @Override -+ public @org.jetbrains.annotations.NotNull String translationKey() { -+ return "options.difficulty." + this.name().toLowerCase(java.util.Locale.ENGLISH); -+ } -+ // Paper end - /** - * Gets the Difficulty represented by the specified value - * -diff --git a/src/main/java/org/bukkit/FireworkEffect.java b/src/main/java/org/bukkit/FireworkEffect.java -index bf7db5b3e7c2ac15016a48e520fba674726718ee..637fa73d4366c2d88e2716e5c8d3465706d788a7 100644 ---- a/src/main/java/org/bukkit/FireworkEffect.java -+++ b/src/main/java/org/bukkit/FireworkEffect.java -@@ -18,28 +18,44 @@ public final class FireworkEffect implements ConfigurationSerializable { - /** - * The type or shape of the effect. - */ -- public enum Type { -+ public enum Type implements net.kyori.adventure.translation.Translatable { // Paper - Adventure translations - /** - * A small ball effect. - */ -- BALL, -+ BALL("small_ball"), // Paper - add name - /** - * A large ball effect. - */ -- BALL_LARGE, -+ BALL_LARGE("large_ball"), // Paper - add name - /** - * A star-shaped effect. - */ -- STAR, -+ STAR("star"), // Paper - add name - /** - * A burst effect. - */ -- BURST, -+ BURST("burst"), // Paper - add name - /** - * A creeper-face effect. - */ -- CREEPER, -+ CREEPER("creeper"), // Paper - add name - ; -+ // Paper start -+ /** -+ * The name map. -+ */ -+ public static final net.kyori.adventure.util.Index NAMES = net.kyori.adventure.util.Index.create(Type.class, type -> type.name); -+ private final String name; -+ -+ Type(final String name) { -+ this.name = name; -+ } -+ -+ @Override -+ public @NotNull String translationKey() { -+ return "item.minecraft.firework_star.shape." + this.name; -+ } -+ // Paper end - } - - /** -diff --git a/src/main/java/org/bukkit/GameMode.java b/src/main/java/org/bukkit/GameMode.java -index 938c3217f92e6d3ef9a637269c469f8359af6347..ef49495909a37d718a87d5dfbcd644d46e27fa88 100644 ---- a/src/main/java/org/bukkit/GameMode.java -+++ b/src/main/java/org/bukkit/GameMode.java -@@ -9,7 +9,7 @@ import org.jetbrains.annotations.Nullable; - * Represents the various type of game modes that {@link HumanEntity}s may - * have - */ --public enum GameMode { -+public enum GameMode implements net.kyori.adventure.translation.Translatable { // Paper - implement Translatable - /** - * Creative mode may fly, build instantly, become invulnerable and create - * free items. -@@ -35,9 +35,18 @@ public enum GameMode { - - private final int value; - private static final Map BY_ID = Maps.newHashMap(); -+ // Paper start - translation keys -+ private final String translationKey; -+ -+ @Override -+ public @org.jetbrains.annotations.NotNull String translationKey() { -+ return this.translationKey; -+ } -+ // Paper end - - private GameMode(final int value) { - this.value = value; -+ this.translationKey = "gameMode." + this.name().toLowerCase(java.util.Locale.ENGLISH); // Paper - } - - /** -diff --git a/src/main/java/org/bukkit/GameRule.java b/src/main/java/org/bukkit/GameRule.java -index dddc450e1372409c513bbedc0acfc80d9f749333..38a1b02c006af766b0c10ee65e9fc28f5a922774 100644 ---- a/src/main/java/org/bukkit/GameRule.java -+++ b/src/main/java/org/bukkit/GameRule.java -@@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable; - * - * @param type of rule (Boolean or Integer) - */ --public final class GameRule { -+public final class GameRule implements net.kyori.adventure.translation.Translatable { // Paper - Adventure translations - - private static Map> gameRules = new HashMap<>(); - // Boolean rules -@@ -288,4 +288,11 @@ public final class GameRule { - public static GameRule[] values() { - return gameRules.values().toArray(new GameRule[gameRules.size()]); - } -+ -+ // Paper start -+ @Override -+ public @NotNull String translationKey() { -+ return "gamerule." + this.name; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index 80b79ffa10ce7eba30d1df4ffa0e928be42f445f..04e07abc29ed1c4eae27529307c4fa11b6fbc3f6 100644 ---- a/src/main/java/org/bukkit/Material.java -+++ b/src/main/java/org/bukkit/Material.java -@@ -107,7 +107,7 @@ import org.jetbrains.annotations.Nullable; - * An enum of all material IDs accepted by the official server and client - */ - @SuppressWarnings({"DeprecatedIsStillUsed", "deprecation"}) // Paper --public enum Material implements Keyed { -+public enum Material implements Keyed, net.kyori.adventure.translation.Translatable { // Paper - // - AIR(9648, 0), - STONE(22948), -@@ -4125,6 +4125,23 @@ public enum Material implements Keyed { - } - return false; - } -+ -+ /** -+ * Return the translation key for the Material, so the client can translate it into the active -+ * locale when using a TranslatableComponent. -+ * @return the translation key -+ * @deprecated use {@link #translationKey()} -+ */ -+ @NotNull -+ @Deprecated -+ public String getTranslationKey() { -+ return this.translationKey(); -+ } -+ -+ @Override -+ public @NotNull String translationKey() { -+ return Bukkit.getUnsafe().getTranslationKey(this); -+ } - // Paper end - - /** -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 1b5f36b78d81b688ded88ab91e36d9df8c5d64ee..e10edf17a87d18e9d9a22c6793d6ac78054d841b 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -111,5 +111,34 @@ public interface UnsafeValues { - byte[] serializeItem(ItemStack item); - - ItemStack deserializeItem(byte[] data); -+ -+ /** -+ * Return the translation key for the Material, so the client can translate it into the active -+ * locale when using a {@link net.kyori.adventure.text.TranslatableComponent}. -+ * @return the translation key -+ */ -+ String getTranslationKey(Material mat); -+ -+ /** -+ * Return the translation key for the Block, so the client can translate it into the active -+ * locale when using a {@link net.kyori.adventure.text.TranslatableComponent}. -+ * @return the translation key -+ */ -+ String getTranslationKey(org.bukkit.block.Block block); -+ -+ /** -+ * Return the translation key for the EntityType, so the client can translate it into the active -+ * locale when using a {@link net.kyori.adventure.text.TranslatableComponent}.
      -+ * This is null, when the EntityType isn't known to NMS (custom entities) -+ * @return the translation key -+ */ -+ String getTranslationKey(org.bukkit.entity.EntityType type); -+ -+ /** -+ * Return the translation key for the ItemStack, so the client can translate it into the active -+ * locale when using a {@link net.kyori.adventure.text.TranslatableComponent}.
      -+ * @return the translation key -+ */ -+ String getTranslationKey(ItemStack itemStack); - // Paper end - } -diff --git a/src/main/java/org/bukkit/attribute/Attribute.java b/src/main/java/org/bukkit/attribute/Attribute.java -index 13eac9ad2c1672051635d1c35cc49239252e7a61..107e36ef02a9481954bd770ce9a55a0b1e84be7a 100644 ---- a/src/main/java/org/bukkit/attribute/Attribute.java -+++ b/src/main/java/org/bukkit/attribute/Attribute.java -@@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull; - /** - * Types of attributes which may be present on an {@link Attributable}. - */ --public enum Attribute implements Keyed { -+public enum Attribute implements Keyed, net.kyori.adventure.translation.Translatable { // Paper - Adventure translations - - /** - * Maximum health of an Entity. -@@ -73,4 +73,10 @@ public enum Attribute implements Keyed { - public NamespacedKey getKey() { - return key; - } -+ // Paper start -+ @Override -+ public @NotNull String translationKey() { -+ return "attribute.name." + this.key.getKey(); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index 1e7ee68e56f8d4399c2cbf26aa45bf8b599b3b02..2c837ea822f3b0c4ec312f0c956fe1b778cbd5e9 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -31,7 +31,7 @@ import org.jetbrains.annotations.Nullable; - * (i.e. lighting and power) may not be able to be safely accessed during world - * generation when used in cases like BlockPhysicsEvent!!!! - */ --public interface Block extends Metadatable { -+public interface Block extends Metadatable, net.kyori.adventure.translation.Translatable { // Paper - translatable - - /** - * Gets the metadata for this block -@@ -646,5 +646,15 @@ public interface Block extends Metadatable { - * @return the sound group for this block - */ - @NotNull org.bukkit.SoundGroup getBlockSoundGroup(); -+ -+ /** -+ * Return the translation key for the Block, so the client can translate it into the active -+ * locale when using a TranslatableComponent. -+ * @return the translation key -+ * @deprecated use {@link #translationKey()} -+ */ -+ @NotNull -+ @Deprecated -+ String getTranslationKey(); - // Paper end - } -diff --git a/src/main/java/org/bukkit/enchantments/Enchantment.java b/src/main/java/org/bukkit/enchantments/Enchantment.java -index 5744a9f432ec75f6b6b1991ff488dffb9591c934..0264c2f9a3977b6d47994b1e1b0240b312e5bf65 100644 ---- a/src/main/java/org/bukkit/enchantments/Enchantment.java -+++ b/src/main/java/org/bukkit/enchantments/Enchantment.java -@@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable; - /** - * The various type of enchantments that may be added to armour or weapons - */ --public abstract class Enchantment implements Keyed { -+public abstract class Enchantment implements Keyed, net.kyori.adventure.translation.Translatable { // Paper - Adventure translations - /** - * Provides protection against environmental damage - */ -diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java -index 4d5f0837bd0e02a30c943d8969fb6b13452322e0..a39f9c078f42451bd122f3e3729d10ca299bee5f 100644 ---- a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java -+++ b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java -@@ -69,5 +69,10 @@ public class EnchantmentWrapper extends Enchantment { - public net.kyori.adventure.text.Component displayName(int level) { - return getEnchantment().displayName(level); - } -+ -+ @Override -+ public @NotNull String translationKey() { -+ return getEnchantment().translationKey(); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java -index e4a1dac898bb7f93e57c1fa35d0c29f5d95dfa66..032a252688b6dbefb05a0d4f91791e102bbae0cd 100644 ---- a/src/main/java/org/bukkit/entity/EntityType.java -+++ b/src/main/java/org/bukkit/entity/EntityType.java -@@ -20,7 +20,7 @@ import org.jetbrains.annotations.Contract; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; - --public enum EntityType implements Keyed { -+public enum EntityType implements Keyed, net.kyori.adventure.translation.Translatable { // Paper - translatable - - // These strings MUST match the strings in nms.EntityTypes and are case sensitive. - /** -@@ -424,4 +424,27 @@ public enum EntityType implements Keyed { - public boolean isAlive() { - return living; - } -+ // Paper start -+ /** -+ * Return the translation key for the EntityType, so the client can translate it into the active -+ * locale when using a TranslatableComponent.
      -+ * This is null, when the EntityType isn't known to NMS (custom entities) -+ * @return the translation key -+ * @deprecated use {@link #translationKey()} -+ */ -+ @Deprecated -+ @Nullable -+ public String getTranslationKey() { -+ return org.bukkit.Bukkit.getUnsafe().getTranslationKey(this); -+ } -+ -+ /** -+ * @throws IllegalArgumentException if the entity does not have a translation key (is probably a custom entity) -+ */ -+ @Override -+ public @NotNull String translationKey() { -+ Preconditions.checkArgument(this != UNKNOWN, "UNKNOWN entities do not have translation keys"); -+ return org.bukkit.Bukkit.getUnsafe().getTranslationKey(this); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java -index c799ac46dbe257d470d3b236cf55b41240f5fda8..d61855b83da0776fe910dee8cde184c720571a71 100644 ---- a/src/main/java/org/bukkit/entity/Villager.java -+++ b/src/main/java/org/bukkit/entity/Villager.java -@@ -160,7 +160,7 @@ public interface Villager extends AbstractVillager { - * Represents the various different Villager professions there may be. - * Villagers have different trading options depending on their profession, - */ -- public enum Profession implements Keyed { -+ public enum Profession implements Keyed, net.kyori.adventure.translation.Translatable { // Paper - NONE, - /** - * Armorer profession. Wears a black apron. Armorers primarily trade for -@@ -243,6 +243,13 @@ public interface Villager extends AbstractVillager { - public NamespacedKey getKey() { - return key; - } -+ -+ // Paper start -+ @Override -+ public @NotNull String translationKey() { -+ return "entity.minecraft.villager." + this.key.getKey(); -+ } -+ // Paper end - } - - // Paper start - Add villager reputation API -diff --git a/src/main/java/org/bukkit/inventory/CreativeCategory.java b/src/main/java/org/bukkit/inventory/CreativeCategory.java -index 5bd252c0ae3b09fe141d131360c67bb9bfbf5422..0ac1f47d1bea37630d1bb011e52eff90d7a31b41 100644 ---- a/src/main/java/org/bukkit/inventory/CreativeCategory.java -+++ b/src/main/java/org/bukkit/inventory/CreativeCategory.java -@@ -3,51 +3,64 @@ package org.bukkit.inventory; - /** - * Represents a category in the creative inventory. - */ --public enum CreativeCategory { -+public enum CreativeCategory implements net.kyori.adventure.translation.Translatable { // Paper - - /** - * An assortment of building blocks including dirt, bricks, planks, ores - * slabs, etc. - */ -- BUILDING_BLOCKS, -+ BUILDING_BLOCKS("buildingBlocks"), // Paper - /** - * Blocks and items typically used for decorative purposes including - * candles, saplings, flora, fauna, fences, walls, carpets, etc. - */ -- DECORATIONS, -+ DECORATIONS("decorations"), // Paper - /** - * Blocks used and associated with redstone contraptions including buttons, - * levers, pressure plates, redstone components, pistons, etc. - */ -- REDSTONE, -+ REDSTONE("redstone"), // Paper - /** - * Items pertaining to transportation including minecarts, rails, boats, - * elytra, etc. - */ -- TRANSPORTATION, -+ TRANSPORTATION("transportation"), // Paper - /** - * Miscellaneous items and blocks that do not fit into other categories - * including gems, dyes, spawn eggs, discs, banner patterns, etc. - */ -- MISC, -+ MISC("misc"), // Paper - /** - * Food items consumable by the player including meats, berries, edible - * drops from creatures, etc. - */ -- FOOD, -+ FOOD("food"), // Paper - /** - * Equipment items meant for general utility including pickaxes, axes, hoes, - * flint and steel, and useful enchantment books for said tools. - */ -- TOOLS, -+ TOOLS("tools"), // Paper - /** - * Equipment items meant for combat including armor, swords, bows, tipped - * arrows, and useful enchantment books for said equipment. - */ -- COMBAT, -+ COMBAT("combat"), // Paper - /** - * All items related to brewing and potions including all types of potions, - * their variants, and ingredients to brew them. - */ -- BREWING; -+ BREWING("brewing"); // Paper -+ // Paper start -+ private final String translationKey; -+ -+ CreativeCategory(String translationKey) { -+ this.translationKey = "itemGroup." + translationKey; -+ } -+ -+ @Override -+ public @org.jetbrains.annotations.NotNull String translationKey() { -+ return this.translationKey; -+ } -+ // Paper start -+ - } -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index d3334c62bf39abf17ee7f3e68e106fd637ffdf00..d6eafaa58b19ab44dfdef1baa58fa89c5b761b65 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -24,7 +24,7 @@ import org.jetbrains.annotations.Nullable; - * use this class to encapsulate Materials for which {@link Material#isItem()} - * returns false. - */ --public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyori.adventure.text.event.HoverEventSource { // Paper -+public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyori.adventure.text.event.HoverEventSource, net.kyori.adventure.translation.Translatable { // Paper - private Material type = Material.AIR; - private int amount = 0; - private MaterialData data = null; -@@ -858,5 +858,30 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - ItemMeta itemMeta = getItemMeta(); - return itemMeta != null && itemMeta.hasItemFlag(flag); - } -+ -+ /** -+ * Gets the translation key for this itemstack. -+ * This is not the same as getting the translation key -+ * for the material of this itemstack. -+ * -+ * @return the translation key -+ * @deprecated use {@link #translationKey()} -+ */ -+ @NotNull -+ @Deprecated -+ public String getTranslationKey() { -+ return this.translationKey(); -+ } -+ -+ /** -+ * {@inheritDoc} -+ *

      -+ * This is not the same as getting the translation key -+ * for the material of this itemstack. -+ */ -+ @Override -+ public @NotNull String translationKey() { -+ return Bukkit.getUnsafe().getTranslationKey(this); -+ } - // Paper end - } diff --git a/patches/api/0222-Added-PlayerTradeEvent.patch b/patches/api/0222-Added-PlayerTradeEvent.patch new file mode 100644 index 000000000000..92c8312a0142 --- /dev/null +++ b/patches/api/0222-Added-PlayerTradeEvent.patch @@ -0,0 +1,161 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 2 Jul 2020 16:10:10 -0700 +Subject: [PATCH] Added PlayerTradeEvent + +[Amendment: Alexander ] +PlayerTradeEvent is used for player purchases from villagers and wandering +traders, but not custom merchants created via Bukkit.createMerchant(). During +discussions in Discord it was decided that it'd be better to add a new event +that PlayerTradeEvent inherits from than change getVillager()'s annotation to +@Nullable, especially since that'd also infringe on the implication of the +event being about villager trades. + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerPurchaseEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerPurchaseEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1691b53f157f17117116e841cbfc769ea0e14364 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerPurchaseEvent.java +@@ -0,0 +1,104 @@ ++package io.papermc.paper.event.player; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.MerchantRecipe; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player trades with a standalone merchant GUI. ++ */ ++@NullMarked ++public class PlayerPurchaseEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private boolean rewardExp; ++ private boolean increaseTradeUses; ++ private MerchantRecipe trade; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerPurchaseEvent(final Player player, final MerchantRecipe trade, final boolean rewardExp, final boolean increaseTradeUses) { ++ super(player); ++ this.trade = trade; ++ this.rewardExp = rewardExp; ++ this.increaseTradeUses = increaseTradeUses; ++ } ++ ++ /** ++ * Gets the associated trade with this event ++ * ++ * @return the trade ++ */ ++ public MerchantRecipe getTrade() { ++ return this.trade; ++ } ++ ++ /** ++ * Sets the trade. This is then used to determine the next prices ++ * ++ * @param trade the trade to use ++ */ ++ public void setTrade(final MerchantRecipe trade) { ++ Preconditions.checkArgument(trade != null, "Trade cannot be null!"); ++ this.trade = trade; ++ } ++ ++ /** ++ * @return will trade try to reward exp ++ */ ++ public boolean isRewardingExp() { ++ return this.rewardExp; ++ } ++ ++ /** ++ * Sets whether the trade will try to reward exp ++ * ++ * @param rewardExp try to reward exp ++ */ ++ public void setRewardExp(final boolean rewardExp) { ++ this.rewardExp = rewardExp; ++ } ++ ++ /** ++ * @return whether the trade will count as a use of the trade ++ */ ++ public boolean willIncreaseTradeUses() { ++ return this.increaseTradeUses; ++ } ++ ++ /** ++ * Sets whether the trade will count as a use ++ * ++ * @param increaseTradeUses {@code true} to count, {@code false} otherwise ++ */ ++ public void setIncreaseTradeUses(final boolean increaseTradeUses) { ++ this.increaseTradeUses = increaseTradeUses; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerTradeEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerTradeEvent.java +new file mode 100755 +index 0000000000000000000000000000000000000000..46bdc178c19feb7dbb71eebee6d0774cf16c1042 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerTradeEvent.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.AbstractVillager; ++import org.bukkit.entity.Player; ++import org.bukkit.inventory.MerchantRecipe; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player trades with a villager or wandering trader ++ */ ++@NullMarked ++public class PlayerTradeEvent extends PlayerPurchaseEvent { ++ ++ private final AbstractVillager villager; ++ ++ @ApiStatus.Internal ++ public PlayerTradeEvent(final Player player, final AbstractVillager villager, final MerchantRecipe trade, final boolean rewardExp, final boolean increaseTradeUses) { ++ super(player, trade, rewardExp, increaseTradeUses); ++ this.villager = villager; ++ } ++ ++ /** ++ * Gets the Villager or Wandering trader associated with this event ++ * ++ * @return the villager or wandering trader ++ */ ++ public AbstractVillager getVillager() { ++ return this.villager; ++ } ++ ++} diff --git a/patches/api/0222-Create-HoverEvent-from-ItemStack-Entity.patch b/patches/api/0222-Create-HoverEvent-from-ItemStack-Entity.patch deleted file mode 100644 index eaeeffb57683..000000000000 --- a/patches/api/0222-Create-HoverEvent-from-ItemStack-Entity.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: ysl3000 -Date: Mon, 6 Jul 2020 22:17:37 +0200 -Subject: [PATCH] Create HoverEvent from ItemStack Entity - - -diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java -index 50fe28b48d885c782278bdb53a0bbae303f4a32d..34c13845f4916fb167fc9d83fe792975e5c52bdc 100644 ---- a/src/main/java/org/bukkit/inventory/ItemFactory.java -+++ b/src/main/java/org/bukkit/inventory/ItemFactory.java -@@ -204,5 +204,62 @@ public interface ItemFactory { - */ - @NotNull - ItemStack ensureServerConversions(@NotNull ItemStack item); -+ -+ /** -+ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that ItemStack for displaying. -+ * -+ * @param itemStack -+ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that ItemStack -+ */ -+ @NotNull -+ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull ItemStack itemStack); -+ -+ /** -+ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} for displaying. -+ * Uses the display name of the entity, if present. -+ * -+ * @param entity Entity to create the HoverEvent for -+ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} -+ * @deprecated use {@link org.bukkit.entity.Entity#asHoverEvent()} -+ */ -+ @NotNull -+ @Deprecated -+ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity); -+ -+ /** -+ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} for displaying. -+ * -+ * @param entity Entity to create the HoverEvent for -+ * @param customName a custom name that should be displayed, if not passed entity name will be displayed -+ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} -+ * @deprecated use {@link org.bukkit.entity.Entity#asHoverEvent(java.util.function.UnaryOperator)} -+ */ -+ @NotNull -+ @Deprecated -+ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity, @Nullable String customName); -+ -+ /** -+ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} for displaying. -+ * -+ * @param entity Entity to create the HoverEvent for -+ * @param customName a custom name that should be displayed, if not passed entity name will be displayed -+ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} -+ * @deprecated use {@link org.bukkit.entity.Entity#asHoverEvent(java.util.function.UnaryOperator)} -+ */ -+ @NotNull -+ @Deprecated -+ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity, @Nullable net.md_5.bungee.api.chat.BaseComponent customName); -+ -+ /** -+ * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} for displaying. -+ * -+ * @param entity Entity to create the HoverEvent for -+ * @param customName a custom name that should be displayed, if not passed entity name will be displayed -+ * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that {@link org.bukkit.entity.Entity} -+ * @deprecated use {@link org.bukkit.entity.Entity#asHoverEvent(java.util.function.UnaryOperator)} -+ */ -+ @NotNull -+ @Deprecated -+ net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity, @NotNull net.md_5.bungee.api.chat.BaseComponent[] customName); - // Paper end - } diff --git a/patches/api/0223-Add-TargetHitEvent-API.patch b/patches/api/0223-Add-TargetHitEvent-API.patch new file mode 100644 index 000000000000..fab5309b762d --- /dev/null +++ b/patches/api/0223-Add-TargetHitEvent-API.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Wed, 25 Nov 2020 23:21:32 -0800 +Subject: [PATCH] Add TargetHitEvent API + + +diff --git a/src/main/java/io/papermc/paper/event/block/TargetHitEvent.java b/src/main/java/io/papermc/paper/event/block/TargetHitEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6555bf7f4485eacd8d35113d5b21b73f0693a950 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/TargetHitEvent.java +@@ -0,0 +1,60 @@ ++package io.papermc.paper.event.block; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.block.Block; ++import org.bukkit.block.BlockFace; ++import org.bukkit.entity.Projectile; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.ProjectileHitEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Range; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a Target Block is hit by a projectile. ++ *

      ++ * Cancelling this event will stop the Target from emitting a redstone signal, ++ * and in the case that the shooter is a player, will stop them from receiving ++ * advancement criteria. ++ */ ++@NullMarked ++public class TargetHitEvent extends ProjectileHitEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private int signalStrength; ++ ++ @ApiStatus.Internal ++ public TargetHitEvent(final Projectile projectile, final Block block, final BlockFace blockFace, final int signalStrength) { ++ super(projectile, null, block, blockFace); ++ this.signalStrength = signalStrength; ++ } ++ ++ /** ++ * Gets the strength of the redstone signal to be emitted by the Target block ++ * ++ * @return the strength of the redstone signal to be emitted ++ */ ++ public @Range(from = 0, to = 15) int getSignalStrength() { ++ return this.signalStrength; ++ } ++ ++ /** ++ * Sets the strength of the redstone signal to be emitted by the Target block ++ * ++ * @param signalStrength the strength of the redstone signal to be emitted ++ */ ++ public void setSignalStrength(final @Range(from = 0, to = 15) int signalStrength) { ++ Preconditions.checkArgument(signalStrength >= 0 && signalStrength <= 15, "Signal strength out of range (%s), must be in range [0,15]", signalStrength); ++ this.signalStrength = signalStrength; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0223-Add-additional-open-container-api-to-HumanEntity.patch b/patches/api/0223-Add-additional-open-container-api-to-HumanEntity.patch deleted file mode 100644 index 18e8c63e13d3..000000000000 --- a/patches/api/0223-Add-additional-open-container-api-to-HumanEntity.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Wed, 26 Aug 2020 02:11:58 -0400 -Subject: [PATCH] Add additional open container api to HumanEntity - - -diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java -index 43ab3d1f96179a547630be3494d85642ab2ff029..ebbe3417369201df231060dd39f1fb200eb7ad48 100644 ---- a/src/main/java/org/bukkit/entity/HumanEntity.java -+++ b/src/main/java/org/bukkit/entity/HumanEntity.java -@@ -153,6 +153,92 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder - @Nullable - public InventoryView openMerchant(@NotNull Merchant merchant, boolean force); - -+ // Paper start - Add additional containers -+ /** -+ * Opens an empty anvil inventory window with the player's inventory -+ * on the bottom. -+ * -+ * @param location The location to attach it to. If null, the player's -+ * location is used. -+ * @param force If false, and there is no anvil block at the location, -+ * no inventory will be opened and null will be returned. -+ * @return The newly opened inventory view, or null if it could not be -+ * opened. -+ */ -+ @Nullable -+ public InventoryView openAnvil(@Nullable Location location, boolean force); -+ -+ /** -+ * Opens an empty cartography table inventory window with the player's inventory -+ * on the bottom. -+ * -+ * @param location The location to attach it to. If null, the player's -+ * location is used. -+ * @param force If false, and there is no cartography table block at the location, -+ * no inventory will be opened and null will be returned. -+ * @return The newly opened inventory view, or null if it could not be -+ * opened. -+ */ -+ @Nullable -+ public InventoryView openCartographyTable(@Nullable Location location, boolean force); -+ -+ /** -+ * Opens an empty grindstone inventory window with the player's inventory -+ * on the bottom. -+ * -+ * @param location The location to attach it to. If null, the player's -+ * location is used. -+ * @param force If false, and there is no grindstone block at the location, -+ * no inventory will be opened and null will be returned. -+ * @return The newly opened inventory view, or null if it could not be -+ * opened. -+ */ -+ @Nullable -+ public InventoryView openGrindstone(@Nullable Location location, boolean force); -+ -+ /** -+ * Opens an empty loom inventory window with the player's inventory -+ * on the bottom. -+ * -+ * @param location The location to attach it to. If null, the player's -+ * location is used. -+ * @param force If false, and there is no loom block at the location, -+ * no inventory will be opened and null will be returned. -+ * @return The newly opened inventory view, or null if it could not be -+ * opened. -+ */ -+ @Nullable -+ public InventoryView openLoom(@Nullable Location location, boolean force); -+ -+ /** -+ * Opens an empty smithing table inventory window with the player's inventory -+ * on the bottom. -+ * -+ * @param location The location to attach it to. If null, the player's -+ * location is used. -+ * @param force If false, and there is no smithing table block at the location, -+ * no inventory will be opened and null will be returned. -+ * @return The newly opened inventory view, or null if it could not be -+ * opened. -+ */ -+ @Nullable -+ public InventoryView openSmithingTable(@Nullable Location location, boolean force); -+ -+ /** -+ * Opens an empty stonecutter inventory window with the player's inventory -+ * on the bottom. -+ * -+ * @param location The location to attach it to. If null, the player's -+ * location is used. -+ * @param force If false, and there is no stonecutter block at the location, -+ * no inventory will be opened and null will be returned. -+ * @return The newly opened inventory view, or null if it could not be -+ * opened. -+ */ -+ @Nullable -+ public InventoryView openStonecutter(@Nullable Location location, boolean force); -+ // Paper end -+ - /** - * Force-closes the currently open inventory view for this player, if any. - */ diff --git a/patches/api/0224-Additional-Block-Material-API-s.patch b/patches/api/0224-Additional-Block-Material-API-s.patch new file mode 100644 index 000000000000..61083bcc66a2 --- /dev/null +++ b/patches/api/0224-Additional-Block-Material-API-s.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 30 Dec 2020 17:27:27 -0500 +Subject: [PATCH] Additional Block Material API's + +Faster version for isSolid() that utilizes NMS's state for isSolid instead of the slower +process to do this in the Bukkit API + +Adds API for buildable, replaceable, burnable too. + +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index 4666f47666ec50dc47e783f7bd4412148d3a5380..53b8bbe9717e64fa7f9acf3611121218ff92902b 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -439,6 +439,42 @@ public interface Block extends Metadatable, Translatable, net.kyori.adventure.tr + */ + boolean isLiquid(); + ++ // Paper start ++ /** ++ * Check if this block is solid ++ *

      ++ * Determined by Minecraft, typically a block a player can use to place a new block to build things. ++ * An example of a non buildable block would be liquids, flowers, or fire ++ * ++ * @return true if block is buildable ++ */ ++ boolean isBuildable(); ++ /** ++ * Check if this block is burnable ++ *

      ++ * Determined by Minecraft, typically a block that fire can destroy (Wool, Wood) ++ * ++ * @return true if block is burnable ++ */ ++ boolean isBurnable(); ++ /** ++ * Check if this block is replaceable ++ *

      ++ * Determined by Minecraft, representing a block that is not AIR that you can still place a new block at, such as flowers. ++ * @return true if block is replaceable ++ */ ++ boolean isReplaceable(); ++ /** ++ * Check if this block is solid ++ *

      ++ * Determined by Minecraft, typically a block a player can stand on and can't be passed through. ++ * ++ * This API is faster than accessing Material#isSolid as it avoids a material lookup and switch statement. ++ * @return true if block is solid ++ */ ++ boolean isSolid(); ++ // Paper end ++ + /** + * Gets the temperature of this block. + *

      diff --git a/patches/api/0224-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch b/patches/api/0224-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch deleted file mode 100644 index e88d196cc09c..000000000000 --- a/patches/api/0224-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MeFisto94 -Date: Fri, 28 Aug 2020 01:41:31 +0200 -Subject: [PATCH] Expose the Entity Counter to allow plugins to use valid and - non-conflicting Entity Ids - - -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index e10edf17a87d18e9d9a22c6793d6ac78054d841b..035dfcd9d483152a050e45409f15b015b135fb38 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -140,5 +140,12 @@ public interface UnsafeValues { - * @return the translation key - */ - String getTranslationKey(ItemStack itemStack); -+ -+ /** -+ * Creates and returns the next EntityId available. -+ *

      -+ * Use this when sending custom packets, so that there are no collisions on the client or server. -+ */ -+ public int nextEntityId(); - // Paper end - } diff --git a/patches/api/0225-Add-API-to-get-Material-from-Boats-and-Minecarts.patch b/patches/api/0225-Add-API-to-get-Material-from-Boats-and-Minecarts.patch new file mode 100644 index 000000000000..074017d57b11 --- /dev/null +++ b/patches/api/0225-Add-API-to-get-Material-from-Boats-and-Minecarts.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Madeline Miller +Date: Thu, 31 Dec 2020 12:48:38 +1000 +Subject: [PATCH] Add API to get Material from Boats and Minecarts + + +diff --git a/src/main/java/org/bukkit/entity/Boat.java b/src/main/java/org/bukkit/entity/Boat.java +index b77e4ed7f5aa98d0947bc5f626535341c4014d95..9e8224d7e0a83a6252a32d352b9db55a9079325e 100644 +--- a/src/main/java/org/bukkit/entity/Boat.java ++++ b/src/main/java/org/bukkit/entity/Boat.java +@@ -181,4 +181,14 @@ public interface Boat extends Vehicle { + ON_LAND, + IN_AIR; + } ++ ++ // Paper start ++ /** ++ * Gets the {@link Material} that represents this Boat type. ++ * ++ * @return the boat material. ++ */ ++ @NotNull ++ public Material getBoatMaterial(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Minecart.java b/src/main/java/org/bukkit/entity/Minecart.java +index d9ad5fd48eec569eb4aef2aaf527ba24d2db3254..c3c94a5694f1e8d79e5acc45af1cd2e0fa6a621f 100644 +--- a/src/main/java/org/bukkit/entity/Minecart.java ++++ b/src/main/java/org/bukkit/entity/Minecart.java +@@ -1,6 +1,7 @@ + package org.bukkit.entity; + + import org.bukkit.GameRule; ++import org.bukkit.Material; + import org.bukkit.block.data.BlockData; + import org.bukkit.material.MaterialData; + import org.bukkit.util.Vector; +@@ -148,4 +149,14 @@ public interface Minecart extends Vehicle { + * @return the current block offset for this minecart. + */ + public int getDisplayBlockOffset(); ++ ++ // Paper start ++ /** ++ * Gets the {@link Material} that represents this Minecart type. ++ * ++ * @return the minecart material. ++ */ ++ @NotNull ++ public Material getMinecartMaterial(); ++ // Paper end + } diff --git a/patches/api/0225-Entity-isTicking.patch b/patches/api/0225-Entity-isTicking.patch deleted file mode 100644 index ec39bc8a5031..000000000000 --- a/patches/api/0225-Entity-isTicking.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 3 Oct 2020 21:39:07 -0500 -Subject: [PATCH] Entity#isTicking - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 1c9d0e6541d41972f9966b83cbba02f6b230a72c..718af7c49ab8cc232bf72cecdef8a90e2595e835 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -763,5 +763,10 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - * Check if entity is in lava - */ - public boolean isInLava(); -+ -+ /** -+ * Check if entity is inside a ticking chunk -+ */ -+ public boolean isTicking(); - // Paper end - } diff --git a/patches/api/0226-Add-PlayerFlowerPotManipulateEvent.patch b/patches/api/0226-Add-PlayerFlowerPotManipulateEvent.patch new file mode 100644 index 000000000000..70a0b6ec31fa --- /dev/null +++ b/patches/api/0226-Add-PlayerFlowerPotManipulateEvent.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MisterVector +Date: Tue, 13 Aug 2019 19:44:19 -0700 +Subject: [PATCH] Add PlayerFlowerPotManipulateEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerFlowerPotManipulateEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerFlowerPotManipulateEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..03881ae56b3dd68a0aa600382b4689f213ec05f3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerFlowerPotManipulateEvent.java +@@ -0,0 +1,80 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.block.Block; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player places an item in or takes an item out of a flowerpot. ++ */ ++@NullMarked ++public class PlayerFlowerPotManipulateEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Block flowerpot; ++ private final ItemStack item; ++ private final boolean placing; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerFlowerPotManipulateEvent(final Player player, final Block flowerpot, final ItemStack item, final boolean placing) { ++ super(player); ++ this.flowerpot = flowerpot; ++ this.item = item; ++ this.placing = placing; ++ } ++ ++ /** ++ * Gets the flowerpot that is involved in this event. ++ * ++ * @return the flowerpot that is involved with this event ++ */ ++ public Block getFlowerpot() { ++ return this.flowerpot; ++ } ++ ++ /** ++ * Gets the item being placed, or taken from, the flower pot. ++ * Check if placing with {@link #isPlacing()}. ++ * ++ * @return the item placed, or taken from, the flowerpot ++ */ ++ public ItemStack getItem() { ++ return this.item; ++ } ++ ++ /** ++ * Gets if the item is being placed into the flowerpot. ++ * ++ * @return if the item is being placed into the flowerpot ++ */ ++ public boolean isPlacing() { ++ return this.placing; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0226-Clarify-the-Javadocs-for-Entity.getEntitySpawnReason.patch b/patches/api/0226-Clarify-the-Javadocs-for-Entity.getEntitySpawnReason.patch deleted file mode 100644 index 2ca22c295184..000000000000 --- a/patches/api/0226-Clarify-the-Javadocs-for-Entity.getEntitySpawnReason.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aurora -Date: Sat, 3 Oct 2020 16:28:41 +0200 -Subject: [PATCH] Clarify the Javadocs for Entity.getEntitySpawnReason() - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 718af7c49ab8cc232bf72cecdef8a90e2595e835..e3de56ffa7b3a554755a7401988945eca655d816 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -729,7 +729,7 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - } - - /** -- * @return The {@link org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason} that spawned this entity. -+ * @return The {@link org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason} that initially spawned this entity. - */ - @NotNull - org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason(); diff --git a/patches/api/0227-Zombie-API-breaking-doors.patch b/patches/api/0227-Zombie-API-breaking-doors.patch new file mode 100644 index 000000000000..3057ef796331 --- /dev/null +++ b/patches/api/0227-Zombie-API-breaking-doors.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 18 Nov 2020 11:32:15 -0800 +Subject: [PATCH] Zombie API - breaking doors + + +diff --git a/src/main/java/org/bukkit/entity/Zombie.java b/src/main/java/org/bukkit/entity/Zombie.java +index ec6d6052bfd0deb431e9a71329169c97fa498bcd..5b9e1af021a755f490b53952e5d0bc896971f928 100644 +--- a/src/main/java/org/bukkit/entity/Zombie.java ++++ b/src/main/java/org/bukkit/entity/Zombie.java +@@ -100,8 +100,10 @@ public interface Zombie extends Monster, Ageable { + + /** + * Sets whether this zombie can break doors +- * +- * This will be ignored if the entity is a Drowned. Will also stop the action if ++ *

      ++ * Check {@link #supportsBreakingDoors()} to see ++ * if this zombie type will even be affected by using ++ * this method. Will also stop the action if + * the entity is currently breaking a door. + * + * @param flag Whether this zombie can break doors +@@ -162,5 +164,17 @@ public interface Zombie extends Monster, Ageable { + * @param shouldBurnInDay True to burn in sunlight + */ + void setShouldBurnInDay(boolean shouldBurnInDay); ++ ++ /** ++ * Checks if this zombie type supports breaking doors. ++ * {@link Drowned} do not have support for breaking doors ++ * so using {@link #setCanBreakDoors(boolean)} on them has ++ * no effect. ++ * ++ * @return true if entity supports breaking doors ++ * @deprecated Since 1.21.2 all zombie types can break doors if instructed as MC-137053 was fixed. ++ */ ++ @Deprecated(since = "1.21.2", forRemoval = true) ++ boolean supportsBreakingDoors(); + // Paper end + } diff --git a/patches/api/0228-Add-EntityLoadCrossbowEvent.patch b/patches/api/0228-Add-EntityLoadCrossbowEvent.patch new file mode 100644 index 000000000000..d0cf6dbf2c1d --- /dev/null +++ b/patches/api/0228-Add-EntityLoadCrossbowEvent.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Wed, 7 Oct 2020 12:04:17 -0400 +Subject: [PATCH] Add EntityLoadCrossbowEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityLoadCrossbowEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityLoadCrossbowEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f7631a5ac0f2ccfa6b81bea9ab54b30fbb3278dd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityLoadCrossbowEvent.java +@@ -0,0 +1,92 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.inventory.EquipmentSlot; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a LivingEntity loads a crossbow with a projectile. ++ */ ++@NullMarked ++public class EntityLoadCrossbowEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ItemStack crossbow; ++ private final EquipmentSlot hand; ++ ++ private boolean consumeItem = true; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityLoadCrossbowEvent(final LivingEntity entity, final ItemStack crossbow, final EquipmentSlot hand) { ++ super(entity); ++ this.crossbow = crossbow; ++ this.hand = hand; ++ } ++ ++ @Override ++ public LivingEntity getEntity() { ++ return (LivingEntity) super.getEntity(); ++ } ++ ++ /** ++ * Gets the crossbow {@link ItemStack} being loaded. ++ * ++ * @return the crossbow involved in this event ++ */ ++ public ItemStack getCrossbow() { ++ return this.crossbow; ++ } ++ ++ /** ++ * Gets the hand from which the crossbow was loaded. ++ * ++ * @return the hand ++ */ ++ public EquipmentSlot getHand() { ++ return this.hand; ++ } ++ ++ /** ++ * @return should the itemstack be consumed ++ */ ++ public boolean shouldConsumeItem() { ++ return this.consumeItem; ++ } ++ ++ /** ++ * @param consume should the item be consumed ++ */ ++ public void setConsumeItem(final boolean consume) { ++ this.consumeItem = consume; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * Set whether to cancel the crossbow being loaded. If canceled, the ++ * projectile that would be loaded into the crossbow will not be consumed. ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0228-Player-elytra-boost-API.patch b/patches/api/0228-Player-elytra-boost-API.patch deleted file mode 100644 index 13332e33e58b..000000000000 --- a/patches/api/0228-Player-elytra-boost-API.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trigary -Date: Tue, 14 Apr 2020 12:06:14 +0200 -Subject: [PATCH] Player elytra boost API - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 73dbe57b872db6a0ff4812af9c359fb8e632fb9c..a097d060dc2a345406c3121b2aed038377148862 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -2485,6 +2485,19 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - */ - @NotNull - T getClientOption(@NotNull ClientOption option); -+ -+ /** -+ * Boost a Player that's {@link #isGliding()} using a {@link Firework}. -+ * If the creation of the entity is cancelled, no boosting is done. -+ * This method does not fire {@link com.destroystokyo.paper.event.player.PlayerElytraBoostEvent}. -+ * -+ * @param firework The {@link Material#FIREWORK_ROCKET} to boost the player with -+ * @return The {@link Firework} boosting the Player or null if the spawning of the entity was cancelled -+ * @throws IllegalArgumentException if {@link #isGliding()} is false -+ * or if the {@code firework} isn't a {@link Material#FIREWORK_ROCKET} -+ */ -+ @Nullable -+ Firework boostElytra(@NotNull ItemStack firework); - // Paper end - - // Spigot start diff --git a/patches/api/0229-Add-getOfflinePlayerIfCached-String.patch b/patches/api/0229-Add-getOfflinePlayerIfCached-String.patch deleted file mode 100644 index d6c96d45382a..000000000000 --- a/patches/api/0229-Add-getOfflinePlayerIfCached-String.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: oxygencraft <21054297+oxygencraft@users.noreply.github.com> -Date: Sun, 25 Oct 2020 18:35:58 +1100 -Subject: [PATCH] Add getOfflinePlayerIfCached(String) - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index b34866d6314ec783661e7a806b3d8c2a3b338dd7..20ff922fe9248b822d751a7edb7468cc023de71b 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -1227,6 +1227,27 @@ public final class Bukkit { - return server.getOfflinePlayer(name); - } - -+ // Paper start -+ /** -+ * Gets the player by the given name, regardless if they are offline or -+ * online. -+ *

      -+ * This will not make a web request to get the UUID for the given name, -+ * thus this method will not block. However this method will return -+ * {@code null} if the player is not cached. -+ *

      -+ * -+ * @param name the name of the player to retrieve -+ * @return an offline player if cached, {@code null} otherwise -+ * @see #getOfflinePlayer(String) -+ * @see #getOfflinePlayer(java.util.UUID) -+ */ -+ @Nullable -+ public static OfflinePlayer getOfflinePlayerIfCached(@NotNull String name) { -+ return server.getOfflinePlayerIfCached(name); -+ } -+ // Paper end -+ - /** - * Gets the player by the given UUID, regardless if they are offline or - * online. -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 8768f544ca3b197a6456bf948c05a4cfb8f776a1..a3ae5651718937bdefff1753b93c7c67aff7ef1d 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1022,6 +1022,25 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - @NotNull - public OfflinePlayer getOfflinePlayer(@NotNull String name); - -+ // Paper start -+ /** -+ * Gets the player by the given name, regardless if they are offline or -+ * online. -+ *

      -+ * This will not make a web request to get the UUID for the given name, -+ * thus this method will not block. However this method will return -+ * {@code null} if the player is not cached. -+ *

      -+ * -+ * @param name the name of the player to retrieve -+ * @return an offline player if cached, {@code null} otherwise -+ * @see #getOfflinePlayer(String) -+ * @see #getOfflinePlayer(java.util.UUID) -+ */ -+ @Nullable -+ public OfflinePlayer getOfflinePlayerIfCached(@NotNull String name); -+ // Paper end -+ - /** - * Gets the player by the given UUID, regardless if they are offline or - * online. diff --git a/patches/api/0229-Added-WorldGameRuleChangeEvent.patch b/patches/api/0229-Added-WorldGameRuleChangeEvent.patch new file mode 100644 index 000000000000..92d081900fe1 --- /dev/null +++ b/patches/api/0229-Added-WorldGameRuleChangeEvent.patch @@ -0,0 +1,100 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 20 Dec 2020 16:41:44 -0800 +Subject: [PATCH] Added WorldGameRuleChangeEvent + + +diff --git a/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java b/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4d259e31c4b1bb01318c727d8e340b6b23084067 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java +@@ -0,0 +1,88 @@ ++package io.papermc.paper.event.world; ++ ++import org.bukkit.GameRule; ++import org.bukkit.World; ++import org.bukkit.command.CommandSender; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.world.WorldEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when a world's gamerule is changed, either by command or by api. ++ */ ++@NullMarked ++public class WorldGameRuleChangeEvent extends WorldEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final @Nullable CommandSender commandSender; ++ private final GameRule gameRule; ++ private String value; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public WorldGameRuleChangeEvent(final World world, final @Nullable CommandSender commandSender, final GameRule gameRule, final String value) { ++ super(world); ++ this.commandSender = commandSender; ++ this.gameRule = gameRule; ++ this.value = value; ++ } ++ ++ /** ++ * Gets the command sender associated with this event. ++ * ++ * @return {@code null} if the gamerule was changed via api, otherwise the {@link CommandSender}. ++ */ ++ public @Nullable CommandSender getCommandSender() { ++ return this.commandSender; ++ } ++ ++ /** ++ * Gets the game rule associated with this event. ++ * ++ * @return the gamerule being changed. ++ */ ++ public GameRule getGameRule() { ++ return this.gameRule; ++ } ++ ++ /** ++ * Gets the new value of the gamerule. ++ * ++ * @return the new value of the gamerule. ++ */ ++ public String getValue() { ++ return this.value; ++ } ++ ++ /** ++ * Sets the new value of this gamerule. ++ * ++ * @param value the new value of the gamerule. ++ */ ++ public void setValue(final String value) { ++ this.value = value; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0230-Added-ServerResourcesReloadedEvent.patch b/patches/api/0230-Added-ServerResourcesReloadedEvent.patch new file mode 100644 index 000000000000..cec720bd2804 --- /dev/null +++ b/patches/api/0230-Added-ServerResourcesReloadedEvent.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Dec 2020 20:04:16 -0800 +Subject: [PATCH] Added ServerResourcesReloadedEvent + + +diff --git a/src/main/java/io/papermc/paper/event/server/ServerResourcesReloadedEvent.java b/src/main/java/io/papermc/paper/event/server/ServerResourcesReloadedEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..468bbfcaa3fed60dc73726f4e5ace93009f92507 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/server/ServerResourcesReloadedEvent.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.event.server; ++ ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.server.ServerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when resources such as datapacks are reloaded (e.g. /minecraft:reload) ++ *

      ++ * Intended for use to re-register custom recipes, advancements that may be lost during a reload like this. ++ */ ++@NullMarked ++public class ServerResourcesReloadedEvent extends ServerEvent { ++ ++ public static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Cause cause; ++ ++ @ApiStatus.Internal ++ public ServerResourcesReloadedEvent(final Cause cause) { ++ this.cause = cause; ++ } ++ ++ /** ++ * Gets the cause of the resource reload. ++ * ++ * @return the reload cause ++ */ ++ public Cause getCause() { ++ return this.cause; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public enum Cause { ++ COMMAND, ++ PLUGIN, ++ } ++} diff --git a/patches/api/0231-Add-BlockFailedDispenseEvent.patch b/patches/api/0231-Add-BlockFailedDispenseEvent.patch new file mode 100644 index 000000000000..738d2b32c53c --- /dev/null +++ b/patches/api/0231-Add-BlockFailedDispenseEvent.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TheViperShow <29604693+TheViperShow@users.noreply.github.com> +Date: Wed, 22 Apr 2020 09:40:23 +0200 +Subject: [PATCH] Add BlockFailedDispenseEvent + + +diff --git a/src/main/java/io/papermc/paper/event/block/BlockFailedDispenseEvent.java b/src/main/java/io/papermc/paper/event/block/BlockFailedDispenseEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..483139950f80588ae13204a624b9d60c44fac730 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BlockFailedDispenseEvent.java +@@ -0,0 +1,57 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.block.Block; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a block tries to dispense an item, but its inventory is empty. ++ */ ++@NullMarked ++public class BlockFailedDispenseEvent extends BlockEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private boolean shouldPlayEffect = true; ++ ++ @ApiStatus.Internal ++ public BlockFailedDispenseEvent(final Block theBlock) { ++ super(theBlock); ++ } ++ ++ /** ++ * @return if the effect should be played ++ */ ++ public boolean shouldPlayEffect() { ++ return this.shouldPlayEffect; ++ } ++ ++ /** ++ * Sets if the effect for empty dispensers should be played ++ * ++ * @param playEffect if the effect should be played ++ */ ++ public void shouldPlayEffect(final boolean playEffect) { ++ this.shouldPlayEffect = playEffect; ++ } ++ ++ /** ++ * @return {@link #shouldPlayEffect()} ++ */ ++ @Override ++ public boolean callEvent() { ++ super.callEvent(); ++ return this.shouldPlayEffect(); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0231-Item-no-age-no-player-pickup.patch b/patches/api/0231-Item-no-age-no-player-pickup.patch deleted file mode 100644 index 5dd7572120f2..000000000000 --- a/patches/api/0231-Item-no-age-no-player-pickup.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Alfie Smith -Date: Sat, 7 Nov 2020 01:20:27 +0000 -Subject: [PATCH] Item no age & no player pickup - - -diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java -index ab06c640cef1309ab44b0fae8d95df48cdc869a7..48858e1c58c13d786bbc935abedb0f059837833c 100644 ---- a/src/main/java/org/bukkit/entity/Item.java -+++ b/src/main/java/org/bukkit/entity/Item.java -@@ -104,5 +104,34 @@ public interface Item extends Entity { - * @param canMobPickup True to allow non-player entity pickup - */ - public void setCanMobPickup(boolean canMobPickup); -+ -+ /** -+ * Gets whether the player can pickup the item or not -+ * -+ * @return True if a player can pickup the item -+ */ -+ public boolean canPlayerPickup(); -+ -+ /** -+ * Sets whether the item can be picked up or not. Modifies the pickup delay value to do so. -+ * -+ * @param canPlayerPickup True if the player can pickup the item -+ */ -+ public void setCanPlayerPickup(boolean canPlayerPickup); -+ -+ /** -+ * Gets whether the item will age and despawn from being on the ground too long -+ * -+ * @return True if the item will age -+ */ -+ public boolean willAge(); -+ -+ /** -+ * Sets whether the item will age or not. If the item is not ageing, it will not despawn -+ * by being on the ground for too long. -+ * -+ * @param willAge True if the item should age -+ */ -+ public void setWillAge(boolean willAge); - // Paper end - } diff --git a/patches/api/0232-Added-PlayerLecternPageChangeEvent.patch b/patches/api/0232-Added-PlayerLecternPageChangeEvent.patch new file mode 100644 index 000000000000..43e273dba147 --- /dev/null +++ b/patches/api/0232-Added-PlayerLecternPageChangeEvent.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 23 Nov 2020 12:58:16 -0800 +Subject: [PATCH] Added PlayerLecternPageChangeEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerLecternPageChangeEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerLecternPageChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6126182db48dab1286924f9642fb259087efabb3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerLecternPageChangeEvent.java +@@ -0,0 +1,113 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.block.Lectern; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public class PlayerLecternPageChangeEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Lectern lectern; ++ private final ItemStack book; ++ private final PageChangeDirection pageChangeDirection; ++ private final int oldPage; ++ private int newPage; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerLecternPageChangeEvent(final Player player, final Lectern lectern, final ItemStack book, final PageChangeDirection pageChangeDirection, final int oldPage, final int newPage) { ++ super(player); ++ this.lectern = lectern; ++ this.book = book; ++ this.pageChangeDirection = pageChangeDirection; ++ this.oldPage = oldPage; ++ this.newPage = newPage; ++ } ++ ++ /** ++ * Gets the lectern involved. ++ * ++ * @return the Lectern ++ */ ++ public Lectern getLectern() { ++ return this.lectern; ++ } ++ ++ /** ++ * Gets the current ItemStack on the lectern. ++ * ++ * @return the ItemStack on the Lectern ++ */ ++ public ItemStack getBook() { ++ return this.book; ++ } ++ ++ /** ++ * Gets the page change direction. This is essentially returns which button the player clicked, left or right. ++ * ++ * @return the page change direction ++ */ ++ public PageChangeDirection getPageChangeDirection() { ++ return this.pageChangeDirection; ++ } ++ ++ /** ++ * Gets the page changed from. Pages are 0-indexed. ++ * ++ * @return the page changed from ++ */ ++ public int getOldPage() { ++ return this.oldPage; ++ } ++ ++ /** ++ * Gets the page changed to. Pages are 0-indexed. ++ * ++ * @return the page changed to ++ */ ++ public int getNewPage() { ++ return this.newPage; ++ } ++ ++ /** ++ * Sets the page changed to. Pages are 0-indexed. ++ * Page indices that are greater than the number of pages will show the last page. ++ * ++ * @param newPage the new paged changed to ++ */ ++ public void setNewPage(final int newPage) { ++ this.newPage = newPage; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum PageChangeDirection { ++ LEFT, ++ RIGHT, ++ } ++} diff --git a/patches/api/0232-Beacon-API-custom-effect-ranges.patch b/patches/api/0232-Beacon-API-custom-effect-ranges.patch deleted file mode 100644 index ff56b99ebfb1..000000000000 --- a/patches/api/0232-Beacon-API-custom-effect-ranges.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 24 Jun 2020 12:38:15 -0600 -Subject: [PATCH] Beacon API - custom effect ranges - - -diff --git a/src/main/java/org/bukkit/block/Beacon.java b/src/main/java/org/bukkit/block/Beacon.java -index 6349fa9da3f96df3553fb9552c1cab95338cecb0..78475fc6faff0f295828d7b53792001d51aa2889 100644 ---- a/src/main/java/org/bukkit/block/Beacon.java -+++ b/src/main/java/org/bukkit/block/Beacon.java -@@ -64,4 +64,26 @@ public interface Beacon extends TileState, Lockable, Nameable { - * @param effect desired secondary effect - */ - void setSecondaryEffect(@Nullable PotionEffectType effect); -+ -+ // Paper start - Custom effect ranges -+ /** -+ * Gets the effect range of this beacon. -+ * A negative range value means the beacon is using its default range based on tier. -+ * @return Either the custom range set with {@link #setEffectRange(double)} or the range based on the beacon tier. -+ */ -+ double getEffectRange(); -+ -+ /** -+ * Sets the effect range of the beacon -+ * A negative range value means the beacon is using its default range based on tier. -+ * @param range Radius of effect range. -+ */ -+ void setEffectRange(double range); -+ -+ /** -+ * Resets the custom range from this beacon and falls back to the range based on the the beacon tier. -+ * Shortcut for setting the effect range to a negative number. -+ */ -+ void resetEffectRange(); -+ // Paper end - } diff --git a/patches/api/0233-Add-API-for-quit-reason.patch b/patches/api/0233-Add-API-for-quit-reason.patch deleted file mode 100644 index 70e37ffc9b5d..000000000000 --- a/patches/api/0233-Add-API-for-quit-reason.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 14 Nov 2020 16:19:58 +0100 -Subject: [PATCH] Add API for quit reason - - -diff --git a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java -index 0395ca85a466f6356259078d3bad48b2ce6e57b7..6e9205024ca9d3000a371bd0eb723dcd6c662bce 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java -@@ -11,16 +11,28 @@ import org.jetbrains.annotations.Nullable; - public class PlayerQuitEvent extends PlayerEvent { - private static final HandlerList handlers = new HandlerList(); - private net.kyori.adventure.text.Component quitMessage; // Paper -+ private final QuitReason reason; // Paper - - @Deprecated // Paper - public PlayerQuitEvent(@NotNull final Player who, @Nullable final String quitMessage) { -+ // Paper start -+ this(who, quitMessage, null); -+ } -+ @Deprecated // Paper -+ public PlayerQuitEvent(@NotNull final Player who, @Nullable final String quitMessage, @Nullable QuitReason quitReason) { - super(who); - this.quitMessage = quitMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(quitMessage) : null; // Paper -+ this.reason = quitReason == null ? QuitReason.DISCONNECTED : quitReason; - } - // Paper start -+ @Deprecated - public PlayerQuitEvent(@NotNull final Player who, @Nullable final net.kyori.adventure.text.Component quitMessage) { -+ this(who, quitMessage, null); -+ } -+ public PlayerQuitEvent(@NotNull final Player who, @Nullable final net.kyori.adventure.text.Component quitMessage, @Nullable QuitReason quitReason) { - super(who); - this.quitMessage = quitMessage; -+ this.reason = quitReason == null ? QuitReason.DISCONNECTED : quitReason; - } - - /** -@@ -75,4 +87,39 @@ public class PlayerQuitEvent extends PlayerEvent { - public static HandlerList getHandlerList() { - return handlers; - } -+ -+ // Paper start -+ @NotNull -+ public QuitReason getReason() { -+ return this.reason; -+ } -+ -+ public enum QuitReason { -+ /** -+ * The player left on their own behalf. -+ *

      -+ * This does not mean they pressed the disconnect button in their client, but rather that the client severed the -+ * connection themselves. This may occur if no keep-alive packet is received on their side, among other things. -+ */ -+ DISCONNECTED, -+ -+ /** -+ * The player was kicked from the server. -+ */ -+ KICKED, -+ -+ /** -+ * The player has timed out. -+ */ -+ TIMED_OUT, -+ -+ /** -+ * The player's connection has entered an erroneous state. -+ *

      -+ * Reasons for this may include invalid packets, invalid data, and uncaught exceptions in the packet handler, -+ * among others. -+ */ -+ ERRONEOUS_STATE, -+ } -+ // Paper end - } diff --git a/patches/api/0233-Added-PlayerLoomPatternSelectEvent.patch b/patches/api/0233-Added-PlayerLoomPatternSelectEvent.patch new file mode 100644 index 000000000000..e5f19ed9269c --- /dev/null +++ b/patches/api/0233-Added-PlayerLoomPatternSelectEvent.patch @@ -0,0 +1,89 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 25 Nov 2020 16:33:42 -0800 +Subject: [PATCH] Added PlayerLoomPatternSelectEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerLoomPatternSelectEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerLoomPatternSelectEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5d4a334ba97cc0c17db8a157f2e2fd99dafbdbcc +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerLoomPatternSelectEvent.java +@@ -0,0 +1,77 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.block.banner.PatternType; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.LoomInventory; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player selects a banner patten in a loom inventory. ++ */ ++@NullMarked ++public class PlayerLoomPatternSelectEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final LoomInventory loomInventory; ++ private PatternType patternType; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerLoomPatternSelectEvent(final Player player, final LoomInventory loomInventory, final PatternType patternType) { ++ super(player); ++ this.loomInventory = loomInventory; ++ this.patternType = patternType; ++ } ++ ++ /** ++ * Gets the loom inventory involved. ++ * ++ * @return the loom inventory ++ */ ++ public LoomInventory getLoomInventory() { ++ return this.loomInventory; ++ } ++ ++ /** ++ * Gets the pattern type selected. ++ * ++ * @return the pattern type ++ */ ++ public PatternType getPatternType() { ++ return this.patternType; ++ } ++ ++ /** ++ * Sets the pattern type selected. ++ * ++ * @param patternType the pattern type ++ */ ++ public void setPatternType(final PatternType patternType) { ++ this.patternType = patternType; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0234-Add-API-to-get-exact-interaction-point-in-PlayerInte.patch b/patches/api/0234-Add-API-to-get-exact-interaction-point-in-PlayerInte.patch new file mode 100644 index 000000000000..6f5c58daeb59 --- /dev/null +++ b/patches/api/0234-Add-API-to-get-exact-interaction-point-in-PlayerInte.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Madeline Miller +Date: Mon, 4 Jan 2021 16:40:55 +1000 +Subject: [PATCH] Add API to get exact interaction point in PlayerInteractEvent + + +diff --git a/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java b/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java +index 35e0df9fc0338c7c6b8e178ee533cd7833ee66f1..69c800d367d36c8730781b89e3530a75487d000a 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java +@@ -1,5 +1,6 @@ + package org.bukkit.event.player; + ++import org.bukkit.Location; + import org.bukkit.Material; + import org.bukkit.block.Block; + import org.bukkit.block.BlockFace; +@@ -234,13 +235,30 @@ public class PlayerInteractEvent extends PlayerEvent implements Cancellable { + *

      + * All vector components are between 0.0 and 1.0 inclusive. + * ++ * @deprecated misleading, use {@link #getInteractionPoint()} + * @return the clicked position. May be null. + */ + @Nullable ++ @Deprecated // Paper + public Vector getClickedPosition() { + return clickedPosistion; + } + ++ // Paper start ++ /** ++ * The exact point at which the interaction occurred. May be null. ++ * ++ * @return the exact interaction point. May be null. ++ */ ++ @Nullable ++ public Location getInteractionPoint() { ++ if (this.blockClicked == null || this.clickedPosistion == null) { ++ return null; ++ } ++ return this.blockClicked.getLocation().add(this.clickedPosistion); ++ } ++ // Paper end ++ + @NotNull + @Override + public HandlerList getHandlers() { diff --git a/patches/api/0234-Add-Destroy-Speed-API.patch b/patches/api/0234-Add-Destroy-Speed-API.patch deleted file mode 100644 index dbca343b9b05..000000000000 --- a/patches/api/0234-Add-Destroy-Speed-API.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ineusia -Date: Mon, 26 Oct 2020 11:37:48 -0500 -Subject: [PATCH] Add Destroy Speed API - -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index 2c837ea822f3b0c4ec312f0c956fe1b778cbd5e9..4a408361ac86b8c490942686c2709817338f4f59 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -656,5 +656,29 @@ public interface Block extends Metadatable, net.kyori.adventure.translation.Tran - @NotNull - @Deprecated - String getTranslationKey(); -+ -+ /** -+ * Gets the speed at which this block will be destroyed by a given {@link ItemStack} -+ * -+ *

      Default value is 1.0

      -+ * -+ * @param itemStack {@link ItemStack} used to mine this Block -+ * @return the speed that this Block will be mined by the given {@link ItemStack} -+ */ -+ @NotNull -+ public default float getDestroySpeed(@NotNull ItemStack itemStack) { -+ return getDestroySpeed(itemStack, false); -+ } -+ -+ /** -+ * Gets the speed at which this blook will be destroyed by a given {@link org.bukkit.inventory.ItemStack} -+ *

      -+ * Default value is 1.0 -+ * @param itemStack {@link org.bukkit.inventory.ItemStack} used to mine this Block -+ * @param considerEnchants true to look at enchants on the itemstack -+ * @return the speed that this Block will be mined by the given {@link org.bukkit.inventory.ItemStack} -+ */ -+ @NotNull -+ float getDestroySpeed(@NotNull ItemStack itemStack, boolean considerEnchants); - // Paper end - } diff --git a/patches/api/0235-Add-LivingEntity-clearActiveItem.patch b/patches/api/0235-Add-LivingEntity-clearActiveItem.patch deleted file mode 100644 index 4788287931a0..000000000000 --- a/patches/api/0235-Add-LivingEntity-clearActiveItem.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Anrza -Date: Wed, 15 Jul 2020 12:07:58 +0200 -Subject: [PATCH] Add LivingEntity#clearActiveItem - - -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index 37bb2f8c0eba7713793ef51a16f7ca5981e39747..607696debd78e143b5a1de6e90a9b6d15dc98e96 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -772,6 +772,13 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - @NotNull - org.bukkit.inventory.ItemStack getActiveItem(); - -+ // Paper start -+ /** -+ * Interrupts any ongoing active "usage" or consumption or an item. -+ */ -+ void clearActiveItem(); -+ // Paper end -+ - /** - * Get's remaining time a player needs to keep hands raised with an item to finish using it. - * @return Remaining ticks to use the item diff --git a/patches/api/0235-Add-sendOpLevel-API.patch b/patches/api/0235-Add-sendOpLevel-API.patch new file mode 100644 index 000000000000..9ec83d648e39 --- /dev/null +++ b/patches/api/0235-Add-sendOpLevel-API.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Tue, 29 Dec 2020 15:02:57 +0100 +Subject: [PATCH] Add sendOpLevel API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 30d209eb19d891d32fa8dba36270a6bf7fba60b7..e827e8e6a346a6e4b33a9f155e92264955a4a496 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3401,6 +3401,19 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + } + // Paper end - elytra boost API + ++ // Paper start - sendOpLevel API ++ /** ++ * Send a packet to the player indicating its operator status level. ++ *

      ++ * Note: This will not persist across more than the current connection, and setting the player's operator ++ * status as a later point will override the effects of this. ++ * ++ * @param level The level to send to the player. Must be in {@code [0, 4]}. ++ * @throws IllegalArgumentException If the level is negative or greater than {@code 4} (i.e. not within {@code [0, 4]}). ++ */ ++ void sendOpLevel(byte level); ++ // Paper end - sendOpLevel API ++ + // Spigot start + public class Spigot extends Entity.Spigot { + diff --git a/patches/api/0236-Add-PlayerItemCooldownEvent.patch b/patches/api/0236-Add-PlayerItemCooldownEvent.patch deleted file mode 100644 index 82d9c9fc637e..000000000000 --- a/patches/api/0236-Add-PlayerItemCooldownEvent.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Tue, 25 Aug 2020 13:45:15 +0200 -Subject: [PATCH] Add PlayerItemCooldownEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerItemCooldownEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerItemCooldownEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..58d18f05af13d836ddc62fcd30befcb06f07c57c ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerItemCooldownEvent.java -@@ -0,0 +1,77 @@ -+package io.papermc.paper.event.player; -+ -+import com.google.common.base.Preconditions; -+import org.bukkit.Material; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Fired when a player receives an item cooldown. -+ */ -+public class PlayerItemCooldownEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull -+ private final Material type; -+ private boolean cancelled; -+ private int cooldown; -+ -+ public PlayerItemCooldownEvent(@NotNull Player player, @NotNull Material type, int cooldown) { -+ super(player); -+ this.type = type; -+ this.cooldown = cooldown; -+ } -+ -+ /** -+ * Get the material affected by the cooldown. -+ * -+ * @return material affected by the cooldown -+ */ -+ @NotNull -+ public Material getType() { -+ return type; -+ } -+ -+ /** -+ * Gets the cooldown in ticks. -+ * -+ * @return cooldown in ticks -+ */ -+ public int getCooldown() { -+ return cooldown; -+ } -+ -+ /** -+ * Sets the cooldown of the material in ticks. -+ * Setting the cooldown to 0 results in removing an already existing cooldown for the material. -+ * -+ * @param cooldown cooldown in ticks, has to be a positive number -+ */ -+ public void setCooldown(int cooldown) { -+ Preconditions.checkArgument(cooldown >= 0, "The cooldown has to be equal to or greater than 0!"); -+ this.cooldown = cooldown; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0236-Add-RegistryAccess-for-managing-registries.patch b/patches/api/0236-Add-RegistryAccess-for-managing-registries.patch new file mode 100644 index 000000000000..acf5d0ee29f5 --- /dev/null +++ b/patches/api/0236-Add-RegistryAccess-for-managing-registries.patch @@ -0,0 +1,599 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Mar 2022 13:36:21 -0800 +Subject: [PATCH] Add RegistryAccess for managing registries + + +diff --git a/src/main/java/io/papermc/paper/registry/Reference.java b/src/main/java/io/papermc/paper/registry/Reference.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d8656772e0c983df7c40ddc367a73ce473348339 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/Reference.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Represents a reference to a server-backed registry value that may ++ * change. ++ * ++ * @param type of the value ++ */ ++@Deprecated(forRemoval = true, since = "1.20.6") ++public interface Reference extends Keyed { ++ ++ /** ++ * Gets the value from the registry with the key. ++ * ++ * @return the value ++ * @throws java.util.NoSuchElementException if there is no value with this key ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ @NotNull T value(); ++ ++ /** ++ * Gets the value from the registry with the key. ++ * ++ * @return the value or null if it doesn't exist ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ @Nullable T valueOrNull(); ++ ++ /** ++ * Creates a reference to a registered value. ++ * ++ * @param registry the registry the value is located in ++ * @param key the key to the value ++ * @param the type of the value ++ * @return a reference ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ static @NotNull Reference create(@NotNull Registry registry, @NotNull NamespacedKey key) { ++ return new ReferenceImpl<>(registry, key); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/ReferenceImpl.java b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f29e76a6b66ddfec12ddf8db6dcb2df6083b5982 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.NoSuchElementException; ++ ++record ReferenceImpl(@NotNull Registry registry, @NotNull NamespacedKey key) implements Reference { ++ ++ @Override ++ public @NotNull T value() { ++ final T value = this.registry.get(this.key); ++ if (value == null) { ++ throw new NoSuchElementException("No such value with key " + this.key); ++ } ++ return value; ++ } ++ ++ @Override ++ public @Nullable T valueOrNull() { ++ return this.registry.get(this.key); ++ } ++ ++ @Override ++ public @NotNull NamespacedKey getKey() { ++ return this.key; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryAccess.java b/src/main/java/io/papermc/paper/registry/RegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..00a3a4a196808b4b5c84ecccbfb1ea0e3825146a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryAccess.java +@@ -0,0 +1,50 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Used for accessing different {@link Registry} instances ++ * by a {@link RegistryKey}. Get the main instance of {@link RegistryAccess} ++ * with {@link RegistryAccess#registryAccess()}. ++ */ ++@NullMarked ++@ApiStatus.NonExtendable ++public interface RegistryAccess { ++ ++ /** ++ * Get the {@link RegistryAccess} instance for the server. ++ * ++ * @return the RegistryAccess instance ++ */ ++ static RegistryAccess registryAccess() { ++ return RegistryAccessHolder.INSTANCE.orElseThrow(() -> new IllegalStateException("No RegistryAccess implementation found")); ++ } ++ ++ /** ++ * Gets the registry based on the type. ++ * ++ * @param type the type ++ * @return the registry or null if none found ++ * @param the type ++ * @deprecated use {@link #getRegistry(RegistryKey)} with keys from {@link RegistryKey} ++ */ ++ @Deprecated(since = "1.20.6", forRemoval = true) ++ @Nullable Registry getRegistry(Class type); ++ ++ /** ++ * Gets the registry with the specified key. ++ * ++ * @param registryKey the key ++ * @return the registry ++ * @param the type ++ * @throws java.util.NoSuchElementException if no registry with the key is found ++ * @throws IllegalArgumentException if the registry is not available yet ++ */ ++ // Future note: We should have no trouble removing this generic qualifier when ++ // registry types no longer have to be "keyed" as it shouldn't break ABI or API. ++ Registry getRegistry(RegistryKey registryKey); ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java b/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b89e19c070f97c9662f1e16309446494b30aa7c9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.registry; ++ ++import java.util.Optional; ++import java.util.ServiceLoader; ++ ++final class RegistryAccessHolder { ++ ++ static final Optional INSTANCE = ServiceLoader.load(RegistryAccess.class).findFirst(); ++ ++ private RegistryAccessHolder() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java +index 80e3e64f47ac55a4978c9e5b430e2f2d1c871d1b..ac68dfce754dc7e014bb31bba32d9b246ffd411c 100644 +--- a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java ++++ b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java +@@ -12,6 +12,17 @@ record RegistryKeyImpl(Key key) implements RegistryKey { + + static final Set> REGISTRY_KEYS = Sets.newIdentityHashSet(); + ++ // override equals and hashCode to this can be used to simulate an "identity" hashmap ++ @Override ++ public boolean equals(final @Nullable Object obj) { ++ return obj == this; ++ } ++ ++ @Override ++ public int hashCode() { ++ return System.identityHashCode(this); ++ } ++ + static RegistryKey create(@Subst("some_key") final String key) { + final RegistryKey registryKey = createInternal(key); + REGISTRY_KEYS.add(registryKey); +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 0fdce89f60fd66613cf41d962358f530cf75b905..4000d3484516f235c6e41eb5bb90c0420754ce23 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2434,8 +2434,11 @@ public final class Bukkit { + * @param tClass of the registry to get + * @param type of the registry + * @return the corresponding registry or null if not present ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} ++ * with keys from {@link io.papermc.paper.registry.RegistryKey} + */ + @Nullable ++ @Deprecated(since = "1.20.6") + public static Registry getRegistry(@NotNull Class tClass) { + return server.getRegistry(tClass); + } +diff --git a/src/main/java/org/bukkit/Particle.java b/src/main/java/org/bukkit/Particle.java +index 605588eb0613dedec9cba696503a85abf1a8b280..ddbcd977e3ac701a94679bdbfe632d5e8898df1a 100644 +--- a/src/main/java/org/bukkit/Particle.java ++++ b/src/main/java/org/bukkit/Particle.java +@@ -163,28 +163,23 @@ public enum Particle implements Keyed { + + private final NamespacedKey key; + private final Class dataType; +- final boolean register; ++ // Paper - all particles are registered + + Particle(String key) { + this(key, Void.class); + } + +- Particle(String key, boolean register) { +- this(key, Void.class, register); +- } ++ // Paper - all particles are registered + + Particle(String key, /*@NotNull*/ Class data) { +- this(key, data, true); +- } +- +- Particle(String key, /*@NotNull*/ Class data, boolean register) { ++ // Paper - all particles are registered + if (key != null) { + this.key = NamespacedKey.minecraft(key); + } else { + this.key = null; + } + dataType = data; +- this.register = register; ++ // Paper - all particles are registered + } + + /** +diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java +index b4f297f90e3c1deaa1fc3f4418418588ab19b6c5..d03bdf6617ce66950e335f0afb52c19b2e2a14e2 100644 +--- a/src/main/java/org/bukkit/Registry.java ++++ b/src/main/java/org/bukkit/Registry.java +@@ -86,26 +86,32 @@ public interface Registry extends Iterable { + * Server art. + * + * @see Art ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#PAINTING_VARIANT} + */ +- Registry ART = Objects.requireNonNull(Bukkit.getRegistry(Art.class), "No registry present for Art. This is a bug."); ++ @Deprecated(since = "1.21.3") // Paper ++ Registry ART = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Art.class), "No registry present for Art. This is a bug."); + /** + * Attribute. + * + * @see Attribute + */ +- Registry ATTRIBUTE = Objects.requireNonNull(Bukkit.getRegistry(Attribute.class), "No registry present for Attribute. This is a bug."); ++ Registry ATTRIBUTE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.ATTRIBUTE); // Paper + /** + * Server banner patterns. + * + * @see PatternType ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#BANNER_PATTERN} + */ +- Registry BANNER_PATTERN = Objects.requireNonNull(Bukkit.getRegistry(PatternType.class), "No registry present for Pattern Type. This is a bug."); ++ @Deprecated(since = "1.21") // Paper ++ Registry BANNER_PATTERN = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(PatternType.class), "No registry present for PatternType. This is a bug."); // Paper + /** + * Server biomes. + * + * @see Biome ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#BIOME} + */ +- Registry BIOME = Objects.requireNonNull(Bukkit.getRegistry(Biome.class), "No registry present for Biome. This is a bug."); ++ @Deprecated(since = "1.21.3") // Paper ++ Registry BIOME = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Biome.class), "No registry present for Biome. This is a bug."); + /** + * Server block types. + * +@@ -113,7 +119,7 @@ public interface Registry extends Iterable { + * @apiNote BlockType is not ready for public usage yet + */ + @ApiStatus.Internal +- Registry BLOCK = Objects.requireNonNull(Bukkit.getRegistry(BlockType.class), "No registry present for BlockType. This is a bug."); ++ Registry BLOCK = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.BLOCK); // Paper + /** + * Custom boss bars. + * +@@ -155,25 +161,29 @@ public interface Registry extends Iterable { + * + * @see Cat.Type + */ +- Registry CAT_VARIANT = Objects.requireNonNull(Bukkit.getRegistry(Cat.Type.class), "No registry present for Cat Type. This is a bug."); ++ Registry CAT_VARIANT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.CAT_VARIANT); // Paper + /** + * Server enchantments. + * + * @see Enchantment ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#ENCHANTMENT} + */ +- Registry ENCHANTMENT = Objects.requireNonNull(Bukkit.getRegistry(Enchantment.class), "No registry present for Enchantment. This is a bug."); ++ @Deprecated(since = "1.21") ++ Registry ENCHANTMENT = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Enchantment.class), "No registry present for Enchantment. This is a bug."); // Paper + /** + * Server entity types. + * + * @see EntityType + */ +- Registry ENTITY_TYPE = new SimpleRegistry<>(EntityType.class, (entity) -> entity != EntityType.UNKNOWN); ++ Registry ENTITY_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.ENTITY_TYPE); // Paper + /** + * Server instruments. + * + * @see MusicInstrument ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#INSTRUMENT} + */ +- Registry INSTRUMENT = Objects.requireNonNull(Bukkit.getRegistry(MusicInstrument.class), "No registry present for MusicInstrument. This is a bug."); ++ @Deprecated(since = "1.21.2") ++ Registry INSTRUMENT = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(MusicInstrument.class), "No registry present for Instruments. This is a bug."); // Paper + /** + * Server item types. + * +@@ -181,7 +191,7 @@ public interface Registry extends Iterable { + * @apiNote ItemType is not ready for public usage yet + */ + @ApiStatus.Internal +- Registry ITEM = Objects.requireNonNull(Bukkit.getRegistry(ItemType.class), "No registry present for ItemType. This is a bug."); ++ Registry ITEM = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.ITEM); // Paper + /** + * Default server loot tables. + * +@@ -200,25 +210,25 @@ public interface Registry extends Iterable { + * @see MenuType + */ + @ApiStatus.Experimental +- Registry MENU = Objects.requireNonNull(Bukkit.getRegistry(MenuType.class), "No registry present for MenuType. This is a bug."); ++ Registry MENU = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.MENU); // Paper + /** + * Server mob effects. + * + * @see PotionEffectType + */ +- Registry EFFECT = Objects.requireNonNull(Bukkit.getRegistry(PotionEffectType.class), "No registry present for PotionEffectType. This is a bug."); ++ Registry EFFECT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.MOB_EFFECT); // Paper + /** + * Server particles. + * + * @see Particle + */ +- Registry PARTICLE_TYPE = new SimpleRegistry<>(Particle.class, (par) -> par.register); ++ Registry PARTICLE_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.PARTICLE_TYPE); // Paper + /** + * Server potions. + * + * @see PotionType + */ +- Registry POTION = new SimpleRegistry<>(PotionType.class); ++ Registry POTION = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.POTION); // Paper + /** + * Server statistics. + * +@@ -229,58 +239,67 @@ public interface Registry extends Iterable { + * Server structures. + * + * @see Structure ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#STRUCTURE} + */ +- Registry STRUCTURE = Objects.requireNonNull(Bukkit.getRegistry(Structure.class), "No registry present for Structure. This is a bug."); ++ @Deprecated(since = "1.20.6") // Paper ++ Registry STRUCTURE = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Structure.class), "No registry present for Structure. This is a bug."); // Paper + /** + * Server structure types. + * + * @see StructureType + */ +- Registry STRUCTURE_TYPE = Objects.requireNonNull(Bukkit.getRegistry(StructureType.class), "No registry present for StructureType. This is a bug."); ++ Registry STRUCTURE_TYPE = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.STRUCTURE_TYPE), "No registry present for StructureType. This is a bug."); // Paper + /** + * Sound keys. + * + * @see Sound + */ +- Registry SOUNDS = Objects.requireNonNull(Bukkit.getRegistry(Sound.class), "No registry present for Sound. This is a bug."); ++ Registry SOUNDS = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.SOUND_EVENT); // Paper + /** + * Trim materials. + * + * @see TrimMaterial ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#TRIM_MATERIAL} + */ +- Registry TRIM_MATERIAL = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class), "No registry present for TrimMaterial. This is a bug."); ++ @Deprecated(since = "1.20.6") // Paper ++ Registry TRIM_MATERIAL = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(TrimMaterial.class), "No registry present for TrimMaterial. This is a bug."); // Paper + /** + * Trim patterns. + * + * @see TrimPattern ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#TRIM_PATTERN} + */ +- Registry TRIM_PATTERN = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class), "No registry present for TrimPattern. This is a bug."); ++ @Deprecated(since = "1.20.6") ++ Registry TRIM_PATTERN = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(TrimPattern.class), "No registry present for TrimPattern. This is a bug."); // Paper + /** + * Damage types. + * + * @see DamageType ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#DAMAGE_TYPE} + */ +- @ApiStatus.Experimental +- Registry DAMAGE_TYPE = Objects.requireNonNull(Bukkit.getRegistry(DamageType.class), "No registry present for DamageType. This is a bug."); ++ @Deprecated(since = "1.20.6") ++ Registry DAMAGE_TYPE = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(DamageType.class), "No registry present for DamageType. This is a bug."); // Paper + /** + * Jukebox songs. + * + * @see JukeboxSong ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#JUKEBOX_SONG} + */ + @ApiStatus.Experimental +- Registry JUKEBOX_SONG = Objects.requireNonNull(Bukkit.getRegistry(JukeboxSong.class), "No registry present for JukeboxSong. This is a bug."); ++ @Deprecated(since = "1.21") ++ Registry JUKEBOX_SONG = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(JukeboxSong.class), "No registry present for JukeboxSong. This is a bug."); // Paper + /** + * Villager profession. + * + * @see Villager.Profession + */ +- Registry VILLAGER_PROFESSION = Objects.requireNonNull(Bukkit.getRegistry(Villager.Profession.class), "No registry present for Villager Profession. This is a bug."); ++ Registry VILLAGER_PROFESSION = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.VILLAGER_PROFESSION); // Paper + /** + * Villager type. + * + * @see Villager.Type + */ +- Registry VILLAGER_TYPE = Objects.requireNonNull(Bukkit.getRegistry(Villager.Type.class), "No registry present for Villager Type. This is a bug."); ++ Registry VILLAGER_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.VILLAGER_TYPE); // Paper + /** + * Memory Keys. + * +@@ -321,31 +340,33 @@ public interface Registry extends Iterable { + * + * @see Fluid + */ +- Registry FLUID = Objects.requireNonNull(Bukkit.getRegistry(Fluid.class), "No registry present for Fluid. This is a bug."); ++ Registry FLUID = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.FLUID); // Paper + /** + * Frog variants. + * + * @see Frog.Variant + */ +- Registry FROG_VARIANT = Objects.requireNonNull(Bukkit.getRegistry(Frog.Variant.class), "No registry present for Frog Variant. This is a bug."); ++ Registry FROG_VARIANT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.FROG_VARIANT); // Paper + /** + * Wolf variants. + * + * @see Wolf.Variant ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#WOLF_VARIANT} + */ +- Registry WOLF_VARIANT = Objects.requireNonNull(Bukkit.getRegistry(Wolf.Variant.class), "No registry present for Wolf Variant. This is a bug."); ++ @Deprecated(since = "1.20.6") ++ Registry WOLF_VARIANT = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Wolf.Variant.class), "No registry present for Wolf$Variant. This is a bug."); // Paper + /** + * Map cursor types. + * + * @see MapCursor.Type + */ +- Registry MAP_DECORATION_TYPE = Objects.requireNonNull(Bukkit.getRegistry(MapCursor.Type.class), "No registry present for MapCursor Type. This is a bug."); ++ Registry MAP_DECORATION_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.MAP_DECORATION_TYPE); // Paper + /** + * Game events. + * + * @see GameEvent + */ +- Registry GAME_EVENT = Objects.requireNonNull(Bukkit.getRegistry(GameEvent.class), "No registry present for GameEvent. This is a bug."); ++ Registry GAME_EVENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.GAME_EVENT); // Paper + /** + * Get the object by its key. + * +@@ -396,7 +417,7 @@ public interface Registry extends Iterable { + return (namespacedKey != null) ? get(namespacedKey) : null; + } + +- static final class SimpleRegistry & Keyed> implements Registry { ++ class SimpleRegistry & Keyed> implements Registry { // Paper - remove final + + private final Class type; + private final Map map; +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index f0e7333c33132d71069e9eccd9d32a39fac8596f..7204e7046cb76f715f294822dff7deb069a3c802 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2077,8 +2077,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @param tClass of the registry to get + * @param type of the registry + * @return the corresponding registry or null if not present ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} ++ * with keys from {@link io.papermc.paper.registry.RegistryKey} + */ + @Nullable ++ @Deprecated(since = "1.20.6") // Paper + Registry getRegistry(@NotNull Class tClass); + + /** +diff --git a/src/test/java/io/papermc/paper/registry/TestRegistryAccess.java b/src/test/java/io/papermc/paper/registry/TestRegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f5ece852f97017f71bc129e194cb212979b2537b +--- /dev/null ++++ b/src/test/java/io/papermc/paper/registry/TestRegistryAccess.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class TestRegistryAccess implements RegistryAccess { ++ ++ @Override ++ @Deprecated(since = "1.20.6", forRemoval = true) ++ public @Nullable Registry getRegistry(final @NotNull Class type) { ++ throw new UnsupportedOperationException("Not supported"); ++ } ++ ++ @Override ++ public @NotNull Registry getRegistry(final @NotNull RegistryKey registryKey) { ++ throw new UnsupportedOperationException("Not supported"); ++ } ++} +diff --git a/src/test/java/org/bukkit/support/TestServer.java b/src/test/java/org/bukkit/support/TestServer.java +index 2a3ae4afef2716a5fdcefbb6d5e0e011d1db9934..494419922f11e494c9de6f757bb76f0cfe5d7c81 100644 +--- a/src/test/java/org/bukkit/support/TestServer.java ++++ b/src/test/java/org/bukkit/support/TestServer.java +@@ -38,46 +38,11 @@ public final class TestServer { + + when(instance.getBukkitVersion()).thenReturn("BukkitVersion_" + TestServer.class.getPackage().getImplementationVersion()); + +- Map, Registry> registers = new HashMap<>(); +- when(instance.getRegistry(any())).then(invocationOnMock -> registers.computeIfAbsent(invocationOnMock.getArgument(0), aClass -> new Registry<>() { +- private final Map cache = new HashMap<>(); +- +- @Override +- public Keyed get(NamespacedKey key) { +- Class theClass; +- // Some registries have extra Typed classes such as BlockType and ItemType. +- // To avoid class cast exceptions during init mock the Typed class. +- // To get the correct class, we just use the field type. +- try { +- theClass = (Class) aClass.getField(key.getKey().toUpperCase(Locale.ROOT).replace('.', '_')).getType(); +- } catch (ClassCastException | NoSuchFieldException e) { +- throw new RuntimeException(e); +- } +- +- return cache.computeIfAbsent(key, key2 -> mock(theClass, withSettings().stubOnly())); +- } +- +- @NotNull +- @Override +- public Keyed getOrThrow(@NotNull NamespacedKey key) { +- Keyed keyed = get(key); +- +- Preconditions.checkArgument(keyed != null, "No %s registry entry found for key %s.", aClass, key); +- +- return keyed; +- } +- +- @NotNull +- @Override +- public Stream stream() { +- throw new UnsupportedOperationException("Not supported"); +- } +- +- @Override +- public Iterator iterator() { +- throw new UnsupportedOperationException("Not supported"); +- } +- })); ++ // Paper start - RegistryAccess ++ when(instance.getRegistry(any())).then(invocationOnMock -> { ++ return io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(((Class)invocationOnMock.getArgument(0))); ++ }); ++ // Paper end - RegistryAccess + + UnsafeValues unsafeValues = mock(withSettings().stubOnly()); + when(instance.getUnsafe()).thenReturn(unsafeValues); +diff --git a/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess b/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +new file mode 100644 +index 0000000000000000000000000000000000000000..f0a5e6d6b99aeef349fe465080ef2ff7b58617a6 +--- /dev/null ++++ b/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +@@ -0,0 +1 @@ ++io.papermc.paper.registry.TestRegistryAccess diff --git a/patches/api/0237-Add-StructuresLocateEvent.patch b/patches/api/0237-Add-StructuresLocateEvent.patch new file mode 100644 index 000000000000..de27ef54731c --- /dev/null +++ b/patches/api/0237-Add-StructuresLocateEvent.patch @@ -0,0 +1,190 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dfsek +Date: Tue, 15 Sep 2020 21:59:16 -0700 +Subject: [PATCH] Add StructuresLocateEvent + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/io/papermc/paper/event/world/StructuresLocateEvent.java b/src/main/java/io/papermc/paper/event/world/StructuresLocateEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d39b3dc48079fc83f1fd8e7ecde0d4ae77b635ce +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/world/StructuresLocateEvent.java +@@ -0,0 +1,177 @@ ++package io.papermc.paper.event.world; ++ ++import io.papermc.paper.math.Position; ++import java.util.Collections; ++import java.util.List; ++import org.bukkit.Location; ++import org.bukkit.World; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.world.WorldEvent; ++import org.bukkit.generator.structure.Structure; ++import org.bukkit.generator.structure.StructureType; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.UnmodifiableView; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called before a set of configured structures is located. ++ * This happens when: ++ *

        ++ *
      • The /locate command is used.
      • ++ *
      • An Eye of Ender is used.
      • ++ *
      • An Explorer/Treasure Map is activated.
      • ++ *
      • A dolphin swims to a treasure location.
      • ++ *
      • A trade is done with a villager for a map.
      • ++ *
      • {@link World#locateNearestStructure(Location, StructureType, int, boolean)} is invoked.
      • ++ *
      • {@link World#locateNearestStructure(Location, Structure, int, boolean)} is invoked.
      • ++ *
      ++ */ ++@NullMarked ++public class StructuresLocateEvent extends WorldEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Location origin; ++ private @Nullable Result result; ++ private List structures; ++ private int radius; ++ private boolean findUnexplored; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public StructuresLocateEvent(final World world, final Location origin, final List structures, final int radius, final boolean findUnexplored) { ++ super(world); ++ this.origin = origin; ++ this.structures = structures; ++ this.radius = radius; ++ this.findUnexplored = findUnexplored; ++ } ++ ++ /** ++ * Gets the {@link Location} from which the search is to be conducted. ++ * ++ * @return {@link Location} where search begins ++ */ ++ public Location getOrigin() { ++ return this.origin.clone(); ++ } ++ ++ /** ++ * Gets the {@link Location} and {@link Structure} set as the result, if it was defined. ++ *

      ++ * Returns {@code null} if it has not been set by {@link StructuresLocateEvent#setResult(Result)}. ++ * Since this event fires before the search is done, the actual result is unknown at this point. ++ * ++ * @return The result location and structure, if it has been set. {@code null} if it has not. ++ * @see World#locateNearestStructure(Location, StructureType, int, boolean) ++ */ ++ public @Nullable Result getResult() { ++ return this.result; ++ } ++ ++ /** ++ * Sets the result {@link Location} and {@link Structure}. This causes the search to be ++ * skipped, and the result object passed here to be used as the result. ++ * ++ * @param result the {@link Location} and {@link Structure} of the search. ++ */ ++ public void setResult(final @Nullable Result result) { ++ this.result = result; ++ } ++ ++ /** ++ * Gets an unmodifiable list of Structures that are valid targets for the search. ++ * ++ * @return an unmodifiable list of Structures ++ */ ++ public @UnmodifiableView List getStructures() { ++ return Collections.unmodifiableList(this.structures); ++ } ++ ++ /** ++ * Sets the list of Structures that are valid targets for the search. ++ * ++ * @param structures a list of Structures targets ++ */ ++ public void setStructures(final List structures) { ++ this.structures = structures; ++ } ++ ++ /** ++ * Gets the search radius in which to attempt locating the structure. ++ *

      ++ * This radius may not always be obeyed during the structure search! ++ * ++ * @return the search radius (in chunks) ++ */ ++ public int getRadius() { ++ return this.radius; ++ } ++ ++ /** ++ * Sets the search radius in which to attempt locating the structure. ++ *

      ++ * This radius may not always be obeyed during the structure search! ++ * ++ * @param radius the search radius (in chunks) ++ */ ++ public void setRadius(final int radius) { ++ this.radius = radius; ++ } ++ ++ /** ++ * Gets whether to search exclusively for unexplored structures. ++ *

      ++ * As with the search radius, this value is not always obeyed. ++ * ++ * @return Whether to search for only unexplored structures. ++ */ ++ public boolean shouldFindUnexplored() { ++ return this.findUnexplored; ++ } ++ ++ /** ++ * Sets whether to search exclusively for unexplored structures. ++ *

      ++ * As with the search radius, this value is not always obeyed. ++ * ++ * @param findUnexplored Whether to search for only unexplored structures. ++ */ ++ public void setFindUnexplored(final boolean findUnexplored) { ++ this.findUnexplored = findUnexplored; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ /** ++ * Result for {@link StructuresLocateEvent}. ++ */ ++ public record Result(Position pos, Structure structure) { ++ ++ @Deprecated(forRemoval = true) ++ public Location position() { ++ //noinspection DataFlowIssue ++ return this.pos.toLocation(null); ++ } ++ } ++} diff --git a/patches/api/0237-More-lightning-API.patch b/patches/api/0237-More-lightning-API.patch deleted file mode 100644 index f253560abb33..000000000000 --- a/patches/api/0237-More-lightning-API.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Sun, 26 Jul 2020 14:44:16 +0200 -Subject: [PATCH] More lightning API - - -diff --git a/src/main/java/org/bukkit/entity/LightningStrike.java b/src/main/java/org/bukkit/entity/LightningStrike.java -index be347c3d0291f44036bae29a4e7e4645d6a4cdf6..6f5b6901032eb03606c4566b24459a03baac0c73 100644 ---- a/src/main/java/org/bukkit/entity/LightningStrike.java -+++ b/src/main/java/org/bukkit/entity/LightningStrike.java -@@ -31,4 +31,72 @@ public interface LightningStrike extends Entity { - @Override - Spigot spigot(); - // Spigot end -+ -+ // Paper start -+ /** -+ * Returns the amount of flash iterations that will be done before the lightning dies. -+ * -+ * @see #getLifeTicks() for how long the current flash will last -+ * @return amount of flashes that will be shown before the lightning dies -+ */ -+ int getFlashCount(); -+ -+ /** -+ * Sets the amount of life iterations that will be done before the lightning dies. -+ * Default number of flashes on creation is between 1-3. -+ * -+ * @param flashes amount of iterations that will be done before the lightning dies, must to be a positive number -+ */ -+ void setFlashCount(int flashes); -+ -+ /** -+ * Returns the amount of ticks the current flash will do damage for. -+ * Starts with 2 by default, will damage while it is equal to or above 0, with the next flash beginning somewhere between 0 and -9. -+ * -+ * @return ticks the current flash will do damage for -+ */ -+ int getLifeTicks(); -+ -+ /** -+ * Sets the amount of ticks the current flash will do damage/fire for. -+ * Default is 2 for each flash, on which the sound and effect will also be played. -+ * -+ * @param lifeTicks ticks the current flash will do damage for -+ */ -+ void setLifeTicks(int lifeTicks); -+ -+ /** -+ * Returns the potential entity that caused this lightning strike to spawn in the world. -+ *

      -+ * As of implementing this method, only {@link Player}s are capable of causing a lightning strike, however as this -+ * might change in future minecraft releases, this method does not guarantee a player as the cause of a lightning. -+ * Consumers of this method should hence validate whether or not the entity is a player if they want to use player -+ * specific methods through an {@code instanceOf} check. -+ *

      -+ *

      -+ * A player is, as of implementing this method, responsible for a lightning, and will hence be returned here as -+ * a cause, if they channeled a {@link Trident} to summon it or were explicitly defined as the cause of this -+ * lightning through {@link #setCausingPlayer(Player)}. -+ *

      -+ * -+ * @return the entity that caused this lightning or null if the lightning was not caused by a entity (e.g. normal -+ * weather) -+ */ -+ @org.jetbrains.annotations.Nullable -+ Entity getCausingEntity(); -+ -+ /** -+ * Updates the player that caused this lightning to be summoned into the world. -+ * By default, players that channel their {@link Trident} will be the cause of the respective lightning. -+ *

      -+ * While the respective getter method {@link #getCausingEntity()} does not guarantee a player as the cause of a -+ * lightning to stay as future proof as possible, as of implementing this method, players are the only entities -+ * that can cause a lightning strike and hence this setter is restricted to players. -+ *

      -+ * -+ * @param causingPlayer the player that should be the new cause of this lightning. {@code null} may be passed to -+ * indicate that no player is responsible for this lightning. -+ */ -+ void setCausingPlayer(@org.jetbrains.annotations.Nullable Player causingPlayer); -+ // Paper end - } diff --git a/patches/api/0238-Add-BlockPreDispenseEvent.patch b/patches/api/0238-Add-BlockPreDispenseEvent.patch new file mode 100644 index 000000000000..0467ecd66830 --- /dev/null +++ b/patches/api/0238-Add-BlockPreDispenseEvent.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Madeline Miller +Date: Sun, 17 Jan 2021 13:15:54 +1000 +Subject: [PATCH] Add BlockPreDispenseEvent + + +diff --git a/src/main/java/io/papermc/paper/event/block/BlockPreDispenseEvent.java b/src/main/java/io/papermc/paper/event/block/BlockPreDispenseEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2e13e18e2b8411dfb7886663de7125330a65fa62 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BlockPreDispenseEvent.java +@@ -0,0 +1,64 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.block.Block; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public class BlockPreDispenseEvent extends BlockEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ItemStack itemStack; ++ private final int slot; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public BlockPreDispenseEvent(final Block block, final ItemStack itemStack, final int slot) { ++ super(block); ++ this.itemStack = itemStack; ++ this.slot = slot; ++ } ++ ++ /** ++ * Gets the {@link ItemStack} to be dispensed. ++ * ++ * @return The item to be dispensed ++ */ ++ public ItemStack getItemStack() { ++ return this.itemStack; ++ } ++ ++ /** ++ * Gets the inventory slot of the dispenser to dispense from. ++ * ++ * @return The inventory slot ++ */ ++ public int getSlot() { ++ return this.slot; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0238-Add-PlayerShearBlockEvent.patch b/patches/api/0238-Add-PlayerShearBlockEvent.patch deleted file mode 100644 index 051544b4a90d..000000000000 --- a/patches/api/0238-Add-PlayerShearBlockEvent.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Thu, 27 Aug 2020 12:32:35 -0400 -Subject: [PATCH] Add PlayerShearBlockEvent - - -diff --git a/src/main/java/io/papermc/paper/event/block/PlayerShearBlockEvent.java b/src/main/java/io/papermc/paper/event/block/PlayerShearBlockEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..aa7d440b797eac9e62678d03cc87f42838758bfd ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/PlayerShearBlockEvent.java -@@ -0,0 +1,108 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.EquipmentSlot; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.List; -+ -+/** -+ * Called when a player uses sheers on a block. -+ *

      -+ * This event is not called when breaking blocks with shears but instead only when a -+ * player uses the sheer item on a block to garner drops from said block and/or change its state. -+ *

      -+ * Examples include shearing a pumpkin to turn it into a carved pumpkin or shearing a beehive to get honeycomb. -+ */ -+public class PlayerShearBlockEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled = false; -+ private final Block block; -+ private final ItemStack item; -+ private final EquipmentSlot hand; -+ private final List drops; -+ -+ public PlayerShearBlockEvent(@NotNull Player who, @NotNull Block block, @NotNull ItemStack item, @NotNull EquipmentSlot hand, @NotNull List drops) { -+ super(who); -+ this.block = block; -+ this.item = item; -+ this.hand = hand; -+ this.drops = drops; -+ } -+ -+ /** -+ * Gets the block being sheared in this event. -+ * -+ * @return The {@link Block} which block is being sheared in this event. -+ */ -+ @NotNull -+ public Block getBlock() { -+ return block; -+ } -+ -+ /** -+ * Gets the item used to shear the block. -+ * -+ * @return The {@link ItemStack} of the shears. -+ */ -+ @NotNull -+ public ItemStack getItem() { -+ return item; -+ } -+ -+ /** -+ * Gets the hand used to shear the block. -+ * -+ * @return Either {@link EquipmentSlot#HAND} OR {@link EquipmentSlot#OFF_HAND}. -+ */ -+ @NotNull -+ public EquipmentSlot getHand() { -+ return hand; -+ } -+ -+ /** -+ * Gets the resulting drops of this event. -+ * -+ * @return A {@link List list} of {@link ItemStack items} that will be dropped as result of this event. -+ */ -+ @NotNull -+ public List getDrops() { -+ return drops; -+ } -+ -+ /** -+ * Gets whether the shearing of the block should be cancelled or not. -+ * -+ * @return Whether the shearing of the block should be cancelled or not. -+ */ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * Sets whether the shearing of the block should be cancelled or not. -+ * -+ * @param cancel whether the shearing of the block should be cancelled or not. -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0239-Added-PlayerChangeBeaconEffectEvent.patch b/patches/api/0239-Added-PlayerChangeBeaconEffectEvent.patch new file mode 100644 index 000000000000..64504b12938a --- /dev/null +++ b/patches/api/0239-Added-PlayerChangeBeaconEffectEvent.patch @@ -0,0 +1,148 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 24 Jun 2020 15:12:18 -0600 +Subject: [PATCH] Added PlayerChangeBeaconEffectEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerChangeBeaconEffectEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerChangeBeaconEffectEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..580f01754ce082c926240b9bf4842cde1320f987 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerChangeBeaconEffectEvent.java +@@ -0,0 +1,136 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.block.Block; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.potion.PotionEffectType; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when a player sets the effect for a beacon ++ */ ++@NullMarked ++public class PlayerChangeBeaconEffectEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Block beacon; ++ private @Nullable PotionEffectType primary; ++ private @Nullable PotionEffectType secondary; ++ private boolean consumeItem = true; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerChangeBeaconEffectEvent(final Player player, final @Nullable PotionEffectType primary, final @Nullable PotionEffectType secondary, final Block beacon) { ++ super(player); ++ this.primary = primary; ++ this.secondary = secondary; ++ this.beacon = beacon; ++ } ++ ++ /** ++ * @return the primary effect ++ */ ++ public @Nullable PotionEffectType getPrimary() { ++ return this.primary; ++ } ++ ++ /** ++ * Sets the primary effect ++ *

      ++ * NOTE: The primary effect still has to be one of the valid effects for a beacon. ++ * ++ * @param primary the primary effect ++ */ ++ public void setPrimary(final @Nullable PotionEffectType primary) { ++ this.primary = primary; ++ } ++ ++ /** ++ * @return the secondary effect ++ */ ++ public @Nullable PotionEffectType getSecondary() { ++ return this.secondary; ++ } ++ ++ /** ++ * Sets the secondary effect ++ *

      ++ * This only has an effect when the beacon is able to accept a secondary effect. ++ * NOTE: The secondary effect still has to be a valid effect for a beacon. ++ * ++ * @param secondary the secondary effect ++ */ ++ public void setSecondary(final @Nullable PotionEffectType secondary) { ++ this.secondary = secondary; ++ } ++ ++ /** ++ * @return the beacon block associated with this event ++ */ ++ public Block getBeacon() { ++ return this.beacon; ++ } ++ ++ /** ++ * Gets if the item used to change the beacon will be consumed. ++ *

      ++ * Independent of {@link #isCancelled()}. If the event is cancelled ++ * the item will NOT be consumed. ++ * ++ * @return {@code true} if item will be consumed ++ */ ++ public boolean willConsumeItem() { ++ return this.consumeItem; ++ } ++ ++ /** ++ * Sets if the item used to change the beacon should be consumed. ++ *

      ++ * Independent of {@link #isCancelled()}. If the event is cancelled ++ * the item will NOT be consumed. ++ * ++ * @param consumeItem {@code true} if item should be consumed ++ */ ++ public void setConsumeItem(final boolean consumeItem) { ++ this.consumeItem = consumeItem; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * If a {@link PlayerChangeBeaconEffectEvent} is cancelled, the changes will ++ * not take effect ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * If cancelled, the item will NOT be consumed regardless of what {@link #willConsumeItem()} says ++ *

      ++ * If a {@link PlayerChangeBeaconEffectEvent} is cancelled, the changes will not be applied ++ * or saved. ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0239-Enable-multi-release-plugin-jars.patch b/patches/api/0239-Enable-multi-release-plugin-jars.patch deleted file mode 100644 index 40eb489f1db4..000000000000 --- a/patches/api/0239-Enable-multi-release-plugin-jars.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Kyle Wood -Date: Fri, 4 Dec 2020 15:53:19 -0800 -Subject: [PATCH] Enable multi-release plugin jars - - -diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -index fc5dc3b2f73e76976748eb013b39cae931072143..e39492e2544c39c5457f079a6baadf0b4074dd7e 100644 ---- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -@@ -58,7 +58,7 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot - this.description = description; - this.dataFolder = dataFolder; - this.file = file; -- this.jar = new JarFile(file); -+ this.jar = new JarFile(file, true, java.util.zip.ZipFile.OPEN_READ, JarFile.runtimeVersion()); // Paper - enable multi-release jars for Java 9+ - this.manifest = jar.getManifest(); - this.url = file.toURI().toURL(); - this.libraryLoader = libraryLoader; diff --git a/patches/api/0240-Added-PlayerStonecutterRecipeSelectEvent.patch b/patches/api/0240-Added-PlayerStonecutterRecipeSelectEvent.patch new file mode 100644 index 000000000000..ad389698649e --- /dev/null +++ b/patches/api/0240-Added-PlayerStonecutterRecipeSelectEvent.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 27 Nov 2020 17:13:59 -0800 +Subject: [PATCH] Added PlayerStonecutterRecipeSelectEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerStonecutterRecipeSelectEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerStonecutterRecipeSelectEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7f603310bff54b1c58334f21a6975bfe20812d72 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerStonecutterRecipeSelectEvent.java +@@ -0,0 +1,57 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.StonecutterInventory; ++import org.bukkit.inventory.StonecuttingRecipe; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public class PlayerStonecutterRecipeSelectEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final StonecutterInventory stonecutterInventory; ++ private StonecuttingRecipe stonecuttingRecipe; ++ ++ private boolean cancelled; ++ ++ public PlayerStonecutterRecipeSelectEvent(final Player player, final StonecutterInventory stonecutterInventory, final StonecuttingRecipe stonecuttingRecipe) { ++ super(player); ++ this.stonecutterInventory = stonecutterInventory; ++ this.stonecuttingRecipe = stonecuttingRecipe; ++ } ++ ++ public StonecutterInventory getStonecutterInventory() { ++ return this.stonecutterInventory; ++ } ++ ++ public StonecuttingRecipe getStonecuttingRecipe() { ++ return this.stonecuttingRecipe; ++ } ++ ++ public void setStonecuttingRecipe(final StonecuttingRecipe stonecuttingRecipe) { ++ this.stonecuttingRecipe = stonecuttingRecipe; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0240-Player-Chunk-Load-Unload-Events.patch b/patches/api/0240-Player-Chunk-Load-Unload-Events.patch deleted file mode 100644 index e2ce87ec9d2e..000000000000 --- a/patches/api/0240-Player-Chunk-Load-Unload-Events.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: ysl3000 -Date: Mon, 5 Oct 2020 21:24:45 +0200 -Subject: [PATCH] Player Chunk Load/Unload Events - - -diff --git a/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java b/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2c1cda1126e577a88f19071e958eddb5a38785af ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java -@@ -0,0 +1,42 @@ -+package io.papermc.paper.event.packet; -+ -+import org.bukkit.Chunk; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.world.ChunkEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Is called when a {@link org.bukkit.entity.Player} receives a {@link org.bukkit.Chunk} -+ *

      -+ * Can for example be used for spawning a fake entity when the player receives a chunk. -+ * -+ * Should only be used for packet/clientside related stuff. -+ * Not intended for modifying server side state. -+ */ -+public class PlayerChunkLoadEvent extends ChunkEvent { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ private final Player player; -+ -+ public PlayerChunkLoadEvent(@NotNull Chunk chunk, @NotNull Player player) { -+ super(chunk); -+ this.player = player; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public Player getPlayer() { -+ return player; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java b/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..12163a7b0591a7d022dc7eb9ee6608a1b6c39d9b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java -@@ -0,0 +1,40 @@ -+package io.papermc.paper.event.packet; -+ -+import org.bukkit.Chunk; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.world.ChunkEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Is called when a {@link Player} receives a chunk unload packet. -+ * -+ * Should only be used for packet/clientside related stuff. -+ * Not intended for modifying server side. -+ */ -+public class PlayerChunkUnloadEvent extends ChunkEvent { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ private final Player player; -+ -+ public PlayerChunkUnloadEvent(@NotNull Chunk chunk, @NotNull Player player) { -+ super(chunk); -+ this.player = player; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public Player getPlayer() { -+ return player; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0241-Add-dropLeash-variable-to-EntityUnleashEvent.patch b/patches/api/0241-Add-dropLeash-variable-to-EntityUnleashEvent.patch new file mode 100644 index 000000000000..40ce38551f8a --- /dev/null +++ b/patches/api/0241-Add-dropLeash-variable-to-EntityUnleashEvent.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Fri, 29 Jan 2021 15:13:04 +0100 +Subject: [PATCH] Add dropLeash variable to EntityUnleashEvent + + +diff --git a/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java b/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java +index a33986a0c437a673435206fc337031a7eebdab3b..e0e068799a1868c8e561869015f41f553ef4fbdb 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java +@@ -10,10 +10,19 @@ import org.jetbrains.annotations.NotNull; + public class EntityUnleashEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + private final UnleashReason reason; ++ private boolean dropLeash; // Paper + ++ // Paper start - drop leash variable ++ @Deprecated + public EntityUnleashEvent(@NotNull Entity entity, @NotNull UnleashReason reason) { ++ this(entity, reason, false); ++ } ++ ++ public EntityUnleashEvent(@NotNull Entity entity, @NotNull UnleashReason reason, boolean dropLeash) { + super(entity); ++ // Paper end + this.reason = reason; ++ this.dropLeash = dropLeash; // Paper + } + + /** +@@ -26,6 +35,26 @@ public class EntityUnleashEvent extends EntityEvent { + return reason; + } + ++ // Paper start ++ /** ++ * Returns whether a leash item will be dropped. ++ * ++ * @return Whether the leash item will be dropped ++ */ ++ public boolean isDropLeash() { ++ return dropLeash; ++ } ++ ++ /** ++ * Sets whether a leash item should be dropped. ++ * ++ * @param dropLeash Whether the leash item should be dropped ++ */ ++ public void setDropLeash(boolean dropLeash) { ++ this.dropLeash = dropLeash; ++ } ++ // Paper end ++ + @NotNull + @Override + public HandlerList getHandlers() { +diff --git a/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java b/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java +index e6b4ffea8835e248431fe8594eac136c11bf6be0..ade7b268934019e9134a660d88e977f8146ecbc0 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java +@@ -17,8 +17,15 @@ public class PlayerUnleashEntityEvent extends EntityUnleashEvent implements Canc + private final Player player; + private final EquipmentSlot hand; + ++ // Paper start - drop leash variable ++ @Deprecated + public PlayerUnleashEntityEvent(@NotNull Entity entity, @NotNull Player player, @NotNull EquipmentSlot hand) { +- super(entity, UnleashReason.PLAYER_UNLEASH); ++ this(entity, player, hand, false); ++ } ++ ++ public PlayerUnleashEntityEvent(@NotNull Entity entity, @NotNull Player player, @NotNull EquipmentSlot hand, boolean dropLeash) { ++ super(entity, UnleashReason.PLAYER_UNLEASH, dropLeash); ++ // Paper end + this.player = player; + this.hand = hand; + } diff --git a/patches/api/0241-Expose-LivingEntity-hurt-direction.patch b/patches/api/0241-Expose-LivingEntity-hurt-direction.patch deleted file mode 100644 index af634a8cf48d..000000000000 --- a/patches/api/0241-Expose-LivingEntity-hurt-direction.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Sun, 13 Dec 2020 05:32:12 +0200 -Subject: [PATCH] Expose LivingEntity hurt direction - - -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index 607696debd78e143b5a1de6e90a9b6d15dc98e96..087a9c54bc11d5d87aa90bf9d8e66fdac2c44457 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -851,5 +851,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - * @param quantity quantity of item - */ - void playPickupItemAnimation(@NotNull Item item, int quantity); -+ -+ /** -+ * Gets player hurt direction -+ * -+ * @return hurt direction -+ */ -+ float getHurtDirection(); -+ -+ /** -+ * Sets player hurt direction -+ * -+ * @param hurtDirection hurt direction -+ */ -+ void setHurtDirection(float hurtDirection); - // Paper end - } diff --git a/patches/api/0242-Add-OBSTRUCTED-reason-to-BedEnterResult.patch b/patches/api/0242-Add-OBSTRUCTED-reason-to-BedEnterResult.patch deleted file mode 100644 index 00552e9137f4..000000000000 --- a/patches/api/0242-Add-OBSTRUCTED-reason-to-BedEnterResult.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 24 Dec 2020 12:43:30 -0800 -Subject: [PATCH] Add OBSTRUCTED reason to BedEnterResult - - -diff --git a/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java b/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java -index fd6b83f1f9bb2e25613e3f88e497b9d57d393937..ced77de350fa53889439e945336343a1cca5b9ba 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerBedEnterEvent.java -@@ -42,6 +42,12 @@ public class PlayerBedEnterEvent extends PlayerEvent implements Cancellable { - * Entering the bed is prevented due to the player being too far away. - */ - TOO_FAR_AWAY, -+ // Paper start -+ /** -+ * Bed was obstructed. -+ */ -+ OBSTRUCTED, -+ // Paper end - /** - * Entering the bed is prevented due to there being monsters nearby. - */ diff --git a/patches/api/0242-add-DragonEggFormEvent.patch b/patches/api/0242-add-DragonEggFormEvent.patch new file mode 100644 index 000000000000..42db98133ac7 --- /dev/null +++ b/patches/api/0242-add-DragonEggFormEvent.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Trigary +Date: Mon, 25 Jan 2021 14:53:49 +0100 +Subject: [PATCH] add DragonEggFormEvent + + +diff --git a/src/main/java/io/papermc/paper/event/block/DragonEggFormEvent.java b/src/main/java/io/papermc/paper/event/block/DragonEggFormEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d0549d95985ff08af1fc1e6291e0124b766bf99d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/DragonEggFormEvent.java +@@ -0,0 +1,53 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.Material; ++import org.bukkit.block.Block; ++import org.bukkit.block.BlockState; ++import org.bukkit.boss.DragonBattle; ++import org.bukkit.entity.EnderDragon; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockFormEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when the {@link EnderDragon} is defeated (killed) in a {@link DragonBattle}, ++ * causing a {@link Material#DRAGON_EGG} (more formally: {@link #getNewState()}) ++ * to possibly appear depending on {@link #isCancelled()}. ++ *

      ++ * This event might be cancelled by default depending on ++ * e.g. {@link DragonBattle#hasBeenPreviouslyKilled()} and server configuration. ++ */ ++@NullMarked ++public class DragonEggFormEvent extends BlockFormEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final DragonBattle dragonBattle; ++ ++ @ApiStatus.Internal ++ public DragonEggFormEvent(final Block block, final BlockState newState, final DragonBattle dragonBattle) { ++ super(block, newState); ++ this.dragonBattle = dragonBattle; ++ } ++ ++ /** ++ * Gets the {@link DragonBattle} associated with this event. ++ * Keep in mind that the {@link EnderDragon} is already dead ++ * when this event is called. ++ * ++ * @return the dragon battle ++ */ ++ public DragonBattle getDragonBattle() { ++ return this.dragonBattle; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0243-Added-PlayerTradeEvent.patch b/patches/api/0243-Added-PlayerTradeEvent.patch deleted file mode 100644 index e09b088160e3..000000000000 --- a/patches/api/0243-Added-PlayerTradeEvent.patch +++ /dev/null @@ -1,166 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 2 Jul 2020 16:10:10 -0700 -Subject: [PATCH] Added PlayerTradeEvent - -[Amendment: Alexander ] -PlayerTradeEvent is used for player purchases from villagers and wandering -traders, but not custom merchants created via Bukkit.createMerchant(). During -discussions in Discord it was decided that it'd be better to add a new event -that PlayerTradeEvent inherits from than change getVillager()'s annotation to -@Nullable, especially since that'd also infringe on the implication of the -event being about villager trades. - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerPurchaseEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerPurchaseEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c5648055c5e815474bf1e564a5c192ff5c0624fb ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerPurchaseEvent.java -@@ -0,0 +1,112 @@ -+package io.papermc.paper.event.player; -+ -+import java.util.Objects; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.MerchantRecipe; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player trades with a standalone merchant GUI. -+ */ -+public class PlayerPurchaseEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ -+ private boolean increaseTradeUses; -+ private boolean rewardExp; -+ private MerchantRecipe trade; -+ -+ public PlayerPurchaseEvent(@NotNull Player player, -+ @NotNull MerchantRecipe trade, -+ boolean rewardExp, -+ boolean increaseTradeUses) { -+ super(Objects.requireNonNull(player, "Player cannot be null!")); -+ setTrade(trade); -+ this.rewardExp = rewardExp; -+ this.increaseTradeUses = increaseTradeUses; -+ } -+ -+ /** -+ * Gets the associated trade with this event -+ * @return the trade -+ */ -+ @NotNull -+ public MerchantRecipe getTrade() { -+ return this.trade; -+ } -+ -+ /** -+ * Sets the trade. This is then used to determine the next prices -+ * @param trade the trade to use -+ */ -+ public void setTrade(@NotNull MerchantRecipe trade) { -+ this.trade = Objects.requireNonNull(trade, "Trade cannot be null!"); -+ } -+ -+ /** -+ * @return will trade try to reward exp -+ */ -+ public boolean isRewardingExp() { -+ return this.rewardExp; -+ } -+ -+ /** -+ * Sets whether the trade will try to reward exp -+ * @param rewardExp try to reward exp -+ */ -+ public void setRewardExp(boolean rewardExp) { -+ this.rewardExp = rewardExp; -+ } -+ -+ /** -+ * @return whether or not the trade will count as a use of the trade -+ */ -+ public boolean willIncreaseTradeUses() { -+ return this.increaseTradeUses; -+ } -+ -+ /** -+ * Sets whether or not the trade will count as a use -+ * @param increaseTradeUses true to count/false to not count -+ */ -+ public void setIncreaseTradeUses(boolean increaseTradeUses) { -+ this.increaseTradeUses = increaseTradeUses; -+ } -+ -+ /** -+ * Gets the cancellation state of this event. A cancelled event will not -+ * be executed in the server, but will still pass to other plugins -+ * -+ * @return true if this event is cancelled -+ */ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ /** -+ * Sets the cancellation state of this event. A cancelled event will not -+ * be executed in the server, but will still pass to other plugins. -+ * -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+} -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerTradeEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerTradeEvent.java -new file mode 100755 -index 0000000000000000000000000000000000000000..a41fc186746b87f76347dfcc1f80d0969398322b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerTradeEvent.java -@@ -0,0 +1,29 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.entity.AbstractVillager; -+import org.bukkit.entity.Player; -+import org.bukkit.inventory.MerchantRecipe; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player trades with a villager or wandering trader -+ */ -+public class PlayerTradeEvent extends PlayerPurchaseEvent { -+ -+ private final AbstractVillager villager; -+ -+ public PlayerTradeEvent(@NotNull Player player, @NotNull AbstractVillager villager, @NotNull MerchantRecipe trade, boolean rewardExp, boolean increaseTradeUses) { -+ super(player, trade, rewardExp, increaseTradeUses); -+ this.villager = villager; -+ } -+ -+ /** -+ * Gets the Villager or Wandering trader associated with this event -+ * @return the villager or wandering trader -+ */ -+ @NotNull -+ public AbstractVillager getVillager() { -+ return this.villager; -+ } -+ -+} diff --git a/patches/api/0243-EntityMoveEvent.patch b/patches/api/0243-EntityMoveEvent.patch new file mode 100644 index 000000000000..a915e7580e17 --- /dev/null +++ b/patches/api/0243-EntityMoveEvent.patch @@ -0,0 +1,158 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 11 Feb 2020 21:56:38 -0600 +Subject: [PATCH] EntityMoveEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..49ace395393839b3652a537207b4cf5b24beeac0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java +@@ -0,0 +1,146 @@ ++package io.papermc.paper.event.entity; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.Location; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.event.player.PlayerMoveEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Holds information for living entity movement events ++ *

      ++ * Does not fire for players; use {@link PlayerMoveEvent} for player movement. ++ */ ++@NullMarked ++public class EntityMoveEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private Location from; ++ private Location to; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityMoveEvent(final LivingEntity entity, final Location from, final Location to) { ++ super(entity); ++ this.from = from; ++ this.to = to; ++ } ++ ++ @Override ++ public LivingEntity getEntity() { ++ return (LivingEntity) super.getEntity(); ++ } ++ ++ /** ++ * Gets the location this entity moved from ++ * ++ * @return Location the entity moved from ++ */ ++ public Location getFrom() { ++ return this.from; ++ } ++ ++ /** ++ * Sets the location to mark as where the entity moved from ++ * ++ * @param from New location to mark as the entity's previous location ++ */ ++ public void setFrom(final Location from) { ++ this.validateLocation(from); ++ this.from = from; ++ } ++ ++ /** ++ * Gets the location this entity moved to ++ * ++ * @return Location the entity moved to ++ */ ++ public Location getTo() { ++ return this.to; ++ } ++ ++ /** ++ * Sets the location that this entity will move to ++ * ++ * @param to New Location this entity will move to ++ */ ++ public void setTo(final Location to) { ++ this.validateLocation(to); ++ this.to = to; ++ } ++ ++ /** ++ * Check if the entity has changed position (even within the same block) in the event ++ * ++ * @return whether the entity has changed position or not ++ */ ++ public boolean hasChangedPosition() { ++ return this.hasExplicitlyChangedPosition() || !this.from.getWorld().equals(this.to.getWorld()); ++ } ++ ++ /** ++ * Check if the entity has changed position (even within the same block) in the event, disregarding a possible world change ++ * ++ * @return whether the entity has changed position or not ++ */ ++ public boolean hasExplicitlyChangedPosition() { ++ return this.from.getX() != this.to.getX() || this.from.getY() != this.to.getY() || this.from.getZ() != this.to.getZ(); ++ } ++ ++ /** ++ * Check if the entity has moved to a new block in the event ++ * ++ * @return whether the entity has moved to a new block or not ++ */ ++ public boolean hasChangedBlock() { ++ return this.hasExplicitlyChangedBlock() || !this.from.getWorld().equals(this.to.getWorld()); ++ } ++ ++ /** ++ * Check if the entity has moved to a new block in the event, disregarding a possible world change ++ * ++ * @return whether the entity has moved to a new block or not ++ */ ++ public boolean hasExplicitlyChangedBlock() { ++ return this.from.getBlockX() != this.to.getBlockX() || this.from.getBlockY() != this.to.getBlockY() || this.from.getBlockZ() != this.to.getBlockZ(); ++ } ++ ++ /** ++ * Check if the entity has changed orientation in the event ++ * ++ * @return whether the entity has changed orientation or not ++ */ ++ public boolean hasChangedOrientation() { ++ return this.from.getPitch() != this.to.getPitch() || this.from.getYaw() != this.to.getYaw(); ++ } ++ ++ private void validateLocation(final Location loc) { ++ Preconditions.checkArgument(loc != null, "Cannot use null location!"); ++ Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!"); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0244-Add-TargetHitEvent-API.patch b/patches/api/0244-Add-TargetHitEvent-API.patch deleted file mode 100644 index 247421fb61b4..000000000000 --- a/patches/api/0244-Add-TargetHitEvent-API.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Wed, 25 Nov 2020 23:21:32 -0800 -Subject: [PATCH] Add TargetHitEvent API - - -diff --git a/src/main/java/io/papermc/paper/event/block/TargetHitEvent.java b/src/main/java/io/papermc/paper/event/block/TargetHitEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cc067ae118af9957b1b9f5c8d45f63f9154f4942 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/TargetHitEvent.java -@@ -0,0 +1,69 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.block.BlockFace; -+import org.bukkit.entity.Projectile; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.ProjectileHitEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a Target Block is hit by a projectile. -+ *

      -+ * Cancelling this event will stop the Target from emitting a redstone signal, -+ * and in the case that the shooter is a player, will stop them from receiving -+ * advancement criteria. -+ */ -+public class TargetHitEvent extends ProjectileHitEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private int signalStrength; -+ -+ public TargetHitEvent(@NotNull Projectile projectile, @NotNull Block block, @NotNull BlockFace blockFace, int signalStrength) { -+ super(projectile, null, block, blockFace); -+ this.signalStrength = signalStrength; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancelled) { -+ this.cancelled = cancelled; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ /** -+ * Gets the strength of the redstone signal to be emitted by the Target block -+ * -+ * @return the strength of the redstone signal to be emitted -+ */ -+ public int getSignalStrength() { -+ return signalStrength; -+ } -+ -+ /** -+ * Sets the strength of the redstone signal to be emitted by the Target block -+ * -+ * @param signalStrength the strength of the redstone signal to be emitted -+ */ -+ public void setSignalStrength(int signalStrength) { -+ if (signalStrength < 0 || signalStrength > 15) { -+ throw new IllegalArgumentException("Signal strength out of range (" + signalStrength + "), must be in range [0,15]"); -+ } -+ this.signalStrength = signalStrength; -+ } -+} diff --git a/patches/api/0244-Allow-adding-items-to-BlockDropItemEvent.patch b/patches/api/0244-Allow-adding-items-to-BlockDropItemEvent.patch new file mode 100644 index 000000000000..c6b7565fe47b --- /dev/null +++ b/patches/api/0244-Allow-adding-items-to-BlockDropItemEvent.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Wed, 20 Jan 2021 14:25:26 -0600 +Subject: [PATCH] Allow adding items to BlockDropItemEvent + + +diff --git a/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java b/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java +index 7e21548cac8515c281ec86853e9272ab7695b24f..4c5ee91de162b202c2db8bf68259ad41a430125d 100644 +--- a/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java +@@ -68,7 +68,7 @@ public class BlockDropItemEvent extends BlockEvent implements Cancellable { + * Gets list of the Item drops caused by the block break. + * + * This list is mutable - removing an item from it will cause it to not +- * drop. It is not legal however to add new items to the list. ++ * drop. Adding to the list is allowed. + * + * @return The Item the block caused to drop + */ diff --git a/patches/api/0245-Add-getMainThreadExecutor-to-BukkitScheduler.patch b/patches/api/0245-Add-getMainThreadExecutor-to-BukkitScheduler.patch new file mode 100644 index 000000000000..6e95b3eb2392 --- /dev/null +++ b/patches/api/0245-Add-getMainThreadExecutor-to-BukkitScheduler.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aleksander Jagiello +Date: Sun, 24 Jan 2021 22:17:29 +0100 +Subject: [PATCH] Add getMainThreadExecutor to BukkitScheduler + + +diff --git a/src/main/java/org/bukkit/scheduler/BukkitScheduler.java b/src/main/java/org/bukkit/scheduler/BukkitScheduler.java +index 0a0e9461909c6c0bc4a8519483ec05d9c59e67cc..5c277ac7a61df8106f7c13a1ad8ccb1509338699 100644 +--- a/src/main/java/org/bukkit/scheduler/BukkitScheduler.java ++++ b/src/main/java/org/bukkit/scheduler/BukkitScheduler.java +@@ -457,4 +457,15 @@ public interface BukkitScheduler { + @Deprecated(since = "1.7.10") + @NotNull + public BukkitTask runTaskTimerAsynchronously(@NotNull Plugin plugin, @NotNull BukkitRunnable task, long delay, long period) throws IllegalArgumentException; ++ ++ // Paper start - add getMainThreadExecutor ++ /** ++ * Returns an executor that will run tasks on the next server tick. ++ * ++ * @param plugin the reference to the plugin scheduling tasks ++ * @return an executor associated with the given plugin ++ */ ++ @NotNull ++ public java.util.concurrent.Executor getMainThreadExecutor(@NotNull Plugin plugin); ++ // Paper end + } diff --git a/patches/api/0245-Additional-Block-Material-API-s.patch b/patches/api/0245-Additional-Block-Material-API-s.patch deleted file mode 100644 index fe8d819d32a5..000000000000 --- a/patches/api/0245-Additional-Block-Material-API-s.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 30 Dec 2020 17:27:27 -0500 -Subject: [PATCH] Additional Block Material API's - -Faster version for isSolid() that utilizes NMS's state for isSolid instead of the slower -process to do this in the Bukkit API - -Adds API for buildable, replaceable, burnable too. - -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index 4a408361ac86b8c490942686c2709817338f4f59..43a0e57a6db702b2a40e151f151bfaa63b9d95d5 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -438,6 +438,42 @@ public interface Block extends Metadatable, net.kyori.adventure.translation.Tran - */ - boolean isLiquid(); - -+ // Paper start -+ /** -+ * Check if this block is solid -+ *

      -+ * Determined by Minecraft, typically a block a player can use to place a new block to build things. -+ * An example of a non buildable block would be liquids, flowers, or fire -+ * -+ * @return true if block is buildable -+ */ -+ boolean isBuildable(); -+ /** -+ * Check if this block is burnable -+ *

      -+ * Determined by Minecraft, typically a block that fire can destroy (Wool, Wood) -+ * -+ * @return true if block is burnable -+ */ -+ boolean isBurnable(); -+ /** -+ * Check if this block is replaceable -+ *

      -+ * Determined by Minecraft, representing a block that is not AIR that you can still place a new block at, such as flowers. -+ * @return true if block is replaceable -+ */ -+ boolean isReplaceable(); -+ /** -+ * Check if this block is solid -+ *

      -+ * Determined by Minecraft, typically a block a player can stand on and can't be passed through. -+ * -+ * This API is faster than accessing Material#isSolid as it avoids a material lookup and switch statement. -+ * @return true if block is solid -+ */ -+ boolean isSolid(); -+ // Paper end -+ - /** - * Gets the temperature of this block. - *

      diff --git a/patches/api/0246-Add-API-to-get-Material-from-Boats-and-Minecarts.patch b/patches/api/0246-Add-API-to-get-Material-from-Boats-and-Minecarts.patch deleted file mode 100644 index a2eff2fae30b..000000000000 --- a/patches/api/0246-Add-API-to-get-Material-from-Boats-and-Minecarts.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Madeline Miller -Date: Thu, 31 Dec 2020 12:48:38 +1000 -Subject: [PATCH] Add API to get Material from Boats and Minecarts - - -diff --git a/src/main/java/org/bukkit/entity/Boat.java b/src/main/java/org/bukkit/entity/Boat.java -index 24751b5c4e3bc24bdfa85af8f6fcba37413aa002..e0d0537606d4f9a3fe588ebf7d02f314c0359335 100644 ---- a/src/main/java/org/bukkit/entity/Boat.java -+++ b/src/main/java/org/bukkit/entity/Boat.java -@@ -1,5 +1,6 @@ - package org.bukkit.entity; - -+import org.bukkit.Material; - import org.bukkit.TreeSpecies; - import org.jetbrains.annotations.NotNull; - -@@ -103,4 +104,14 @@ public interface Boat extends Vehicle { - */ - @Deprecated - public void setWorkOnLand(boolean workOnLand); -+ -+ // Paper start -+ /** -+ * Gets the {@link Material} that represents this Boat type. -+ * -+ * @return the boat material. -+ */ -+ @NotNull -+ public Material getBoatMaterial(); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Minecart.java b/src/main/java/org/bukkit/entity/Minecart.java -index 7f9c4d4b430a3f0276461346ff2621bacf864075..bc1e62759c995a1463ebcd10d73c7d502c9acc45 100644 ---- a/src/main/java/org/bukkit/entity/Minecart.java -+++ b/src/main/java/org/bukkit/entity/Minecart.java -@@ -1,5 +1,6 @@ - package org.bukkit.entity; - -+import org.bukkit.Material; - import org.bukkit.block.data.BlockData; - import org.bukkit.material.MaterialData; - import org.bukkit.util.Vector; -@@ -147,4 +148,14 @@ public interface Minecart extends Vehicle { - * @return the current block offset for this minecart. - */ - public int getDisplayBlockOffset(); -+ -+ // Paper start -+ /** -+ * Gets the {@link Material} that represents this Minecart type. -+ * -+ * @return the minecart material. -+ */ -+ @NotNull -+ public Material getMinecartMaterial(); -+ // Paper end - } diff --git a/patches/api/0269-living-entity-allow-attribute-registration.patch b/patches/api/0246-living-entity-allow-attribute-registration.patch similarity index 100% rename from patches/api/0269-living-entity-allow-attribute-registration.patch rename to patches/api/0246-living-entity-allow-attribute-registration.patch diff --git a/patches/api/0247-Add-PlayerFlowerPotManipulateEvent.patch b/patches/api/0247-Add-PlayerFlowerPotManipulateEvent.patch deleted file mode 100644 index d9cd5a9f0160..000000000000 --- a/patches/api/0247-Add-PlayerFlowerPotManipulateEvent.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MisterVector -Date: Tue, 13 Aug 2019 19:44:19 -0700 -Subject: [PATCH] Add PlayerFlowerPotManipulateEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerFlowerPotManipulateEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerFlowerPotManipulateEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4c141f3d8f668cdf9c75865a8e3ecbd012d9e521 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerFlowerPotManipulateEvent.java -@@ -0,0 +1,82 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.block.Block; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player places an item in or takes an item out of a flowerpot. -+ */ -+public class PlayerFlowerPotManipulateEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ private final Block flowerpot; -+ @NotNull -+ private final ItemStack item; -+ private final boolean placing; -+ -+ private boolean cancel = false; -+ -+ public PlayerFlowerPotManipulateEvent(@NotNull final Player player, @NotNull final Block flowerpot, @NotNull final ItemStack item, final boolean placing) { -+ super(player); -+ this.flowerpot = flowerpot; -+ this.item = item; -+ this.placing = placing; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ /** -+ * Gets the flowerpot that is involved in this event. -+ * -+ * @return the flowerpot that is involved with this event -+ */ -+ @NotNull -+ public Block getFlowerpot() { -+ return flowerpot; -+ } -+ -+ /** -+ * Gets the item being placed, or taken from, the flower pot. -+ * Check if placing with {@link #isPlacing()}. -+ * -+ * @return the item placed, or taken from, the flowerpot -+ */ -+ @NotNull -+ public ItemStack getItem() { -+ return item; -+ } -+ -+ /** -+ * Gets if the item is being placed into the flowerpot. -+ * -+ * @return if the item is being placed into the flowerpot -+ */ -+ public boolean isPlacing() { -+ return placing; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0247-Add-missing-effects.patch b/patches/api/0247-Add-missing-effects.patch new file mode 100644 index 000000000000..dfd7ffb6edf2 --- /dev/null +++ b/patches/api/0247-Add-missing-effects.patch @@ -0,0 +1,288 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ivan Pekov +Date: Tue, 5 Jan 2021 10:19:11 +0200 +Subject: [PATCH] Add missing effects + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/org/bukkit/Effect.java b/src/main/java/org/bukkit/Effect.java +index d63395e588ec0d2ce7303379c9bee56cf7c33064..e013d83fb31469e1579510c0a661360823bedee7 100644 +--- a/src/main/java/org/bukkit/Effect.java ++++ b/src/main/java/org/bukkit/Effect.java +@@ -97,7 +97,7 @@ public enum Effect { + */ + EXTINGUISH(1009, Type.SOUND), + /** +- * A song from a record. Needs the record item ID as additional info ++ * A song from a record. Needs the record {@link Material} as additional info. + */ + RECORD_PLAY(1010, Type.SOUND, Material.class), + /** +@@ -125,20 +125,20 @@ public enum Effect { + */ + ZOMBIE_DESTROY_DOOR(1021, Type.SOUND), + /** +- * A visual smoke effect. Needs direction as additional info. ++ * A visual smoke effect. Needs a {@link BlockFace} direction as additional info. + */ + SMOKE(2000, Type.VISUAL, BlockFace.class), + /** +- * Sound of a block breaking. Needs block ID as additional info. ++ * Sound of a block breaking. Needs {@link org.bukkit.block.data.BlockData} as additional info. + */ +- STEP_SOUND(2001, Type.SOUND, Material.class), ++ STEP_SOUND(2001, Type.SOUND, org.bukkit.block.data.BlockData.class, Material.class), // Paper - block data is more correct, but the impl of the mtehods will still work with Material + /** +- * Visual effect of a splash potion breaking. Needs potion data value as ++ * Visual effect of a splash potion breaking. Needs {@link Color} data value as + * additional info. + */ + POTION_BREAK(2002, Type.VISUAL, Color.class), + /** +- * Visual effect of an instant splash potion breaking. Needs color data ++ * Visual effect of an instant splash potion breaking. Needs {@link Color} data + * value as additional info. + */ + INSTANT_POTION_BREAK(2007, Type.VISUAL, Color.class), +@@ -168,7 +168,9 @@ public enum Effect { + PORTAL_TRAVEL(1032, Type.SOUND), + /** + * The sound played when launching an endereye ++ * @deprecated No longer exists + */ ++ @Deprecated(forRemoval = true, since = "1.21") // Paper + ENDEREYE_LAUNCH(1003, Type.SOUND), + /** + * The sound played when launching a firework +@@ -177,7 +179,9 @@ public enum Effect { + /** + * Particles displayed when a villager grows a plant, data + * is the number of particles ++ * @deprecated partially replaced by {@link #BEE_GROWTH} + */ ++ @Deprecated(forRemoval = true, since = "1.20.5") // Paper + VILLAGER_PLANT_GROW(2005, Type.VISUAL, Integer.class), + /** + * The sound/particles used by the enderdragon's breath +@@ -319,7 +323,7 @@ public enum Effect { + * The particles shown when a lightning hits a lightning rod or oxidized + * copper. + * +- * Data is the axis at which the particle should be shown. If no data is ++ * Data is the {@link Axis} at which the particle should be shown. If no data is + * provided it will show the particles at the block faces. + */ + ELECTRIC_SPARK(3002, Type.VISUAL, Axis.class), +@@ -336,21 +340,124 @@ public enum Effect { + * block. + */ + OXIDISED_COPPER_SCRAPE(3005, Type.VISUAL), ++ // Paper start - add missing effects ++ /** ++ * The sound of a wither spawning ++ */ ++ WITHER_SPAWNED(1023, Type.SOUND), ++ /** ++ * The sound of an ender dragon dying ++ */ ++ ENDER_DRAGON_DEATH(1028, Type.SOUND), ++ /** ++ * The sound of an ender portal being created in the overworld ++ */ ++ END_PORTAL_CREATED_IN_OVERWORLD(1038, Type.SOUND), ++ ++ SOUND_STOP_JUKEBOX_SONG(1011, Type.SOUND), ++ ++ CRAFTER_CRAFT(1049, Type.SOUND), ++ ++ CRAFTER_FAIL(1050, Type.SOUND), ++ ++ /** ++ * {@link BlockFace} param is the direction to shoot ++ */ ++ SHOOT_WHITE_SMOKE(2010, Type.VISUAL, BlockFace.class), ++ ++ /** ++ * {@link Integer} param is the number of particles ++ */ ++ BEE_GROWTH(2011, Type.VISUAL, Integer.class), ++ ++ /** ++ * {@link Integer} param is the number of particles ++ */ ++ TURTLE_EGG_PLACEMENT(2012, Type.VISUAL, Integer.class), ++ ++ /** ++ * {@link Integer} param is relative to the number of particles ++ */ ++ SMASH_ATTACK(2013, Type.VISUAL, Integer.class), ++ ++ PARTICLES_SCULK_CHARGE(3006, Type.VISUAL, Integer.class), ++ ++ PARTICLES_SCULK_SHRIEK(3007, Type.SOUND), ++ ++ /** ++ * Requires a {@link org.bukkit.block.data.BlockData} param ++ */ ++ PARTICLES_AND_SOUND_BRUSH_BLOCK_COMPLETE(3008, Type.VISUAL, org.bukkit.block.data.BlockData.class), ++ ++ PARTICLES_EGG_CRACK(3009, Type.VISUAL), ++ ++ @Deprecated(forRemoval = true, since = "1.20.5") ++ GUST_DUST(3010, Type.VISUAL), ++ ++ /** ++ * {@link Boolean} param is true for "ominous" vaults ++ */ ++ TRIAL_SPAWNER_SPAWN(3011, Type.VISUAL, Boolean.class), ++ ++ /** ++ * {@link Boolean} param is true for "ominous" vaults ++ */ ++ TRIAL_SPAWNER_SPAWN_MOB_AT(3012, Type.VISUAL, Boolean.class), ++ ++ /** ++ * {@link Integer} param is the number of players ++ */ ++ TRIAL_SPAWNER_DETECT_PLAYER(3013, Type.VISUAL, Integer.class), ++ ++ TRIAL_SPAWNER_EJECT_ITEM(3014, Type.VISUAL), ++ ++ /** ++ * {@link Boolean} param is true for "ominous" vaults ++ */ ++ VAULT_ACTIVATE(3015, Type.VISUAL, Boolean.class), ++ ++ /** ++ * {@link Boolean} param is true for "ominous" vaults ++ */ ++ VAULT_DEACTIVATE(3016, Type.VISUAL, Boolean.class), ++ ++ VAULT_EJECT_ITEM(3017, Type.VISUAL), ++ ++ SPAWN_COBWEB(3018, Type.VISUAL), ++ ++ /** ++ * {@link Integer} param is the number of players ++ */ ++ TRIAL_SPAWNER_DETECT_PLAYER_OMINOUS(3019, Type.VISUAL, Integer.class), ++ ++ /** ++ * {@link Boolean} param is true for changing to "ominous" ++ */ ++ TRIAL_SPAWNER_BECOME_OMINOUS(3020, Type.VISUAL, Boolean.class), ++ ++ /** ++ * {@link Boolean} param is true for "ominous" vaults ++ */ ++ TRIAL_SPAWNER_SPAWN_ITEM(3021, Type.VISUAL, Boolean.class), ++ ++ SOUND_WITH_CHARGE_SHOT(1051, Type.SOUND), + ; ++ private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger(); ++ // Paper end + + private final int id; + private final Type type; +- private final Class data; ++ private final java.util.List> data; // Paper - support multiple data types + private static final Map BY_ID = Maps.newHashMap(); + + Effect(int id, /*@NotNull*/ Type type) { +- this(id, type, null); ++ this(id, type, (Class[]) null); // Paper - support multiple data types + } + +- Effect(int id, /*@NotNull*/ Type type, /*@Nullable*/ Class data) { ++ Effect(int id, /*@NotNull*/ Type type, /*@Nullable*/ Class...data) { // Paper - support multiple data types + this.id = id; + this.type = type; +- this.data = data; ++ this.data = data != null ? java.util.List.of(data) : null; // Paper - support multiple data types + } + + /** +@@ -366,8 +473,10 @@ public enum Effect { + + /** + * @return The type of the effect. ++ * @deprecated some effects can be both or neither + */ + @NotNull ++ @Deprecated // Paper - both + public Type getType() { + return this.type; + } +@@ -378,8 +487,15 @@ public enum Effect { + */ + @Nullable + public Class getData() { +- return this.data; ++ return this.data == null ? null : this.data.get(0); // Paper ++ } ++ ++ // Paper start - support deprecated data types ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public boolean isApplicable(Object obj) { ++ return this.data != null && com.google.common.collect.Iterables.any(this.data, aClass -> aClass.isAssignableFrom(obj.getClass())); + } ++ // Paper end - support deprecated data types + + /** + * Gets the Effect associated with the given ID. +@@ -396,12 +512,26 @@ public enum Effect { + + static { + for (Effect effect : values()) { ++ if (!isDeprecated(effect)) // Paper + BY_ID.put(effect.id, effect); + } + } + ++ // Paper start ++ private static boolean isDeprecated(Effect effect) { ++ try { ++ return Effect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class); ++ } catch (NoSuchFieldException e) { ++ LOGGER.error("Error getting effect enum field {}", effect.name(), e); ++ return false; ++ } ++ } ++ // Paper end ++ + /** + * Represents the type of an effect. ++ * @deprecated not representative of what Effect does + */ ++ @Deprecated // Paper + public enum Type { SOUND, VISUAL } + } +diff --git a/src/test/java/org/bukkit/EffectTest.java b/src/test/java/org/bukkit/EffectTest.java +index 4344512fa84a2f97a750e06761d8e160c0959f6a..615a4583ef8e70a7c86c28e648d0b57e8e6b9674 100644 +--- a/src/test/java/org/bukkit/EffectTest.java ++++ b/src/test/java/org/bukkit/EffectTest.java +@@ -5,10 +5,24 @@ import static org.hamcrest.CoreMatchers.*; + import org.junit.jupiter.api.Test; + + public class EffectTest { ++ private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger(); // Paper ++ + @Test + public void getById() { + for (Effect effect : Effect.values()) { ++ if (!isDeprecated(effect)) // Paper + assertThat(Effect.getById(effect.getId()), is(effect)); + } + } ++ ++ // Paper start ++ private static boolean isDeprecated(Effect effect) { ++ try { ++ return Effect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class); ++ } catch (NoSuchFieldException e) { ++ LOGGER.error("Error getting effect enum field {}", effect.name(), e); ++ return false; ++ } ++ } ++ // Paper end + } diff --git a/patches/api/0248-Expose-Tracked-Players.patch b/patches/api/0248-Expose-Tracked-Players.patch new file mode 100644 index 000000000000..9279703d0dc0 --- /dev/null +++ b/patches/api/0248-Expose-Tracked-Players.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tom +Date: Fri, 26 Feb 2021 16:24:25 -0600 +Subject: [PATCH] Expose Tracked Players + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 0342fbc83bf462017f86d0dda9f49e595a8066b3..8521a9ae4d4427ef9cdbb1b8c67dd6ba81d1f5d9 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -903,5 +903,14 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + * Check if entity is inside a ticking chunk + */ + boolean isTicking(); ++ ++ /** ++ * Returns a set of {@link Player Players} within this entity's tracking range (players that can "see" this entity). ++ * ++ * @return players in tracking range ++ * @deprecated slightly misleading name, use {@link #getTrackedBy()} ++ */ ++ @Deprecated ++ @NotNull Set getTrackedPlayers(); + // Paper end + } diff --git a/patches/api/0248-Zombie-API-breaking-doors.patch b/patches/api/0248-Zombie-API-breaking-doors.patch deleted file mode 100644 index c064453dfc28..000000000000 --- a/patches/api/0248-Zombie-API-breaking-doors.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 18 Nov 2020 11:32:15 -0800 -Subject: [PATCH] Zombie API - breaking doors - - -diff --git a/src/main/java/org/bukkit/entity/Zombie.java b/src/main/java/org/bukkit/entity/Zombie.java -index 1217576e6f08abf0175ab800cfca058d5deda116..6eeab75e985ece3fb606551bc42b05f958da4d60 100644 ---- a/src/main/java/org/bukkit/entity/Zombie.java -+++ b/src/main/java/org/bukkit/entity/Zombie.java -@@ -140,5 +140,32 @@ public interface Zombie extends Monster, Ageable { - * @param shouldBurnInDay True to burn in sunlight - */ - void setShouldBurnInDay(boolean shouldBurnInDay); -+ -+ /** -+ * Check if this zombie can break doors -+ * -+ * @return True if zombie can break doors -+ */ -+ boolean canBreakDoors(); -+ -+ /** -+ * Sets if this zombie can break doors. -+ * Check {@link #supportsBreakingDoors()} to see -+ * if this zombie type will even be affected by using -+ * this method. -+ * -+ * @param canBreakDoors True if zombie can break doors -+ */ -+ void setCanBreakDoors(boolean canBreakDoors); -+ -+ /** -+ * Checks if this zombie type supports breaking doors. -+ * {@link Drowned} do not have support for breaking doors -+ * so using {@link #setCanBreakDoors(boolean)} on them has -+ * no effect. -+ * -+ * @return -+ */ -+ boolean supportsBreakingDoors(); - // Paper end - } diff --git a/patches/api/0249-Add-EntityLoadCrossbowEvent.patch b/patches/api/0249-Add-EntityLoadCrossbowEvent.patch deleted file mode 100644 index 1e0386a9aa4d..000000000000 --- a/patches/api/0249-Add-EntityLoadCrossbowEvent.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Wed, 7 Oct 2020 12:04:17 -0400 -Subject: [PATCH] Add EntityLoadCrossbowEvent - - -diff --git a/src/main/java/io/papermc/paper/event/entity/EntityLoadCrossbowEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityLoadCrossbowEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..aa9ccd7c806e864455ecd5f15ddb17c0fa8728c4 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/EntityLoadCrossbowEvent.java -@@ -0,0 +1,97 @@ -+package io.papermc.paper.event.entity; -+ -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.inventory.EquipmentSlot; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when a LivingEntity loads a crossbow with a projectile. -+ */ -+public class EntityLoadCrossbowEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private final ItemStack crossbow; -+ private final EquipmentSlot hand; -+ private boolean cancelled; -+ private boolean consumeItem = true; -+ -+ public EntityLoadCrossbowEvent(@NotNull LivingEntity entity, @Nullable ItemStack crossbow, @NotNull EquipmentSlot hand) { -+ super(entity); -+ this.crossbow = crossbow; -+ this.hand = hand; -+ } -+ -+ @NotNull -+ @Override -+ public LivingEntity getEntity() { -+ return (LivingEntity) entity; -+ } -+ -+ /** -+ * Gets the crossbow {@link ItemStack} being loaded. -+ * -+ * @return the crossbow involved in this event -+ */ -+ @Nullable -+ public ItemStack getCrossbow() { -+ return crossbow; -+ } -+ -+ /** -+ * Gets the hand from which the crossbow was loaded. -+ * -+ * @return the hand -+ */ -+ @NotNull -+ public EquipmentSlot getHand() { -+ return hand; -+ } -+ -+ /** -+ * -+ * @return should the itemstack be consumed -+ */ -+ public boolean shouldConsumeItem() { -+ return consumeItem; -+ } -+ -+ /** -+ * -+ * @param consume should the item be consumed -+ */ -+ public void setConsumeItem(boolean consume) { -+ this.consumeItem = consume; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * Set whether or not to cancel the crossbow being loaded. If canceled, the -+ * projectile that would be loaded into the crossbow will not be consumed. -+ * -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0249-Add-worldborder-events.patch b/patches/api/0249-Add-worldborder-events.patch new file mode 100644 index 000000000000..f67333262d72 --- /dev/null +++ b/patches/api/0249-Add-worldborder-events.patch @@ -0,0 +1,310 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 4 Jan 2021 22:40:26 -0800 +Subject: [PATCH] Add worldborder events + + +diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3c168b3522c538c1576238738d48eaef6559450d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java +@@ -0,0 +1,115 @@ ++package io.papermc.paper.event.world.border; ++ ++import org.bukkit.World; ++import org.bukkit.WorldBorder; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a world border changes its bounds, either over time, or instantly. ++ */ ++@NullMarked ++public class WorldBorderBoundsChangeEvent extends WorldBorderEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private Type type; ++ private final double oldSize; ++ private double newSize; ++ private long duration; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public WorldBorderBoundsChangeEvent(final World world, final WorldBorder worldBorder, final Type type, final double oldSize, final double newSize, final long duration) { ++ super(world, worldBorder); ++ this.type = type; ++ this.oldSize = oldSize; ++ this.newSize = newSize; ++ this.duration = duration; ++ } ++ ++ /** ++ * Gets if this change is an instant change or over-time change. ++ * ++ * @return the change type ++ */ ++ public Type getType() { ++ return this.type; ++ } ++ ++ /** ++ * Gets the old size or the world border. ++ * ++ * @return the old size ++ */ ++ public double getOldSize() { ++ return this.oldSize; ++ } ++ ++ /** ++ * Gets the new size of the world border. ++ * ++ * @return the new size ++ */ ++ public double getNewSize() { ++ return this.newSize; ++ } ++ ++ /** ++ * Sets the new size of the world border. ++ * ++ * @param newSize the new size ++ */ ++ public void setNewSize(final double newSize) { ++ this.newSize = Math.min(this.worldBorder.getMaxSize(), Math.max(1.0D, newSize)); ++ } ++ ++ /** ++ * Gets the time in milliseconds for the change. Will be 0 if instant. ++ * ++ * @return the time in milliseconds for the change ++ */ ++ public long getDuration() { ++ return this.duration; ++ } ++ ++ /** ++ * Sets the time in milliseconds for the change. Will change {@link #getType()} to return ++ * {@link Type#STARTED_MOVE}. ++ * ++ * @param duration the time in milliseconds for the change ++ */ ++ public void setDuration(final long duration) { ++ // PAIL: TODO: Magic Values ++ this.duration = Math.min(9223372036854775L, Math.max(0L, duration)); ++ if (duration >= 0 && this.type == Type.INSTANT_MOVE) { ++ this.type = Type.STARTED_MOVE; ++ } ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum Type { ++ STARTED_MOVE, ++ INSTANT_MOVE ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeFinishEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeFinishEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6a264660897f0b621e3fb112e6056d98bb510f52 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeFinishEvent.java +@@ -0,0 +1,66 @@ ++package io.papermc.paper.event.world.border; ++ ++import org.bukkit.World; ++import org.bukkit.WorldBorder; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a moving world border has finished its move. ++ */ ++@NullMarked ++public class WorldBorderBoundsChangeFinishEvent extends WorldBorderEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final double oldSize; ++ private final double newSize; ++ private final double duration; ++ ++ @ApiStatus.Internal ++ public WorldBorderBoundsChangeFinishEvent(final World world, final WorldBorder worldBorder, final double oldSize, final double newSize, final double duration) { ++ super(world, worldBorder); ++ this.oldSize = oldSize; ++ this.newSize = newSize; ++ this.duration = duration; ++ } ++ ++ /** ++ * Gets the old size of the worldborder. ++ * ++ * @return the old size ++ */ ++ public double getOldSize() { ++ return this.oldSize; ++ } ++ ++ /** ++ * Gets the new size of the worldborder. ++ * ++ * @return the new size ++ */ ++ public double getNewSize() { ++ return this.newSize; ++ } ++ ++ /** ++ * Gets the duration this worldborder took to make the change. ++ *

      ++ * Can be 0 if handlers for {@link WorldBorderCenterChangeEvent} set the duration to 0. ++ * ++ * @return the duration of the transition ++ */ ++ public double getDuration() { ++ return this.duration; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderCenterChangeEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderCenterChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..74fe5ad50517374631fa3009249833e2b99a55f0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderCenterChangeEvent.java +@@ -0,0 +1,76 @@ ++package io.papermc.paper.event.world.border; ++ ++import org.bukkit.Location; ++import org.bukkit.World; ++import org.bukkit.WorldBorder; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a world border's center is changed. ++ */ ++@NullMarked ++public class WorldBorderCenterChangeEvent extends WorldBorderEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Location oldCenter; ++ private Location newCenter; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public WorldBorderCenterChangeEvent(final World world, final WorldBorder worldBorder, final Location oldCenter, final Location newCenter) { ++ super(world, worldBorder); ++ this.oldCenter = oldCenter; ++ this.newCenter = newCenter; ++ } ++ ++ /** ++ * Gets the original center location of the world border. ++ * ++ * @return the old center ++ */ ++ public Location getOldCenter() { ++ return this.oldCenter.clone(); ++ } ++ ++ /** ++ * Gets the new center location for the world border. ++ * ++ * @return the new center ++ */ ++ public Location getNewCenter() { ++ return this.newCenter; ++ } ++ ++ /** ++ * Sets the new center location for the world border. Y coordinate is ignored. ++ * ++ * @param newCenter the new center ++ */ ++ public void setNewCenter(final Location newCenter) { ++ this.newCenter = newCenter; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1f260e4d693903361d54c0af42144faa66adf4ea +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderEvent.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.event.world.border; ++ ++import org.bukkit.World; ++import org.bukkit.WorldBorder; ++import org.bukkit.event.world.WorldEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public abstract class WorldBorderEvent extends WorldEvent { ++ ++ protected final WorldBorder worldBorder; ++ ++ @ApiStatus.Internal ++ protected WorldBorderEvent(final World world, final WorldBorder worldBorder) { ++ super(world); ++ this.worldBorder = worldBorder; ++ } ++ ++ public WorldBorder getWorldBorder() { ++ return this.worldBorder; ++ } ++} diff --git a/patches/api/0250-Added-WorldGameRuleChangeEvent.patch b/patches/api/0250-Added-WorldGameRuleChangeEvent.patch deleted file mode 100644 index 8ef5f7efcdb3..000000000000 --- a/patches/api/0250-Added-WorldGameRuleChangeEvent.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 20 Dec 2020 16:41:44 -0800 -Subject: [PATCH] Added WorldGameRuleChangeEvent - - -diff --git a/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java b/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..20c25a0f9d65188402e8bb3981348bc6462904bf ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java -@@ -0,0 +1,91 @@ -+package io.papermc.paper.event.world; -+ -+import org.bukkit.GameRule; -+import org.bukkit.World; -+import org.bukkit.command.CommandSender; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.world.WorldEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when a world's gamerule is changed, either by command or by api. -+ */ -+public class WorldGameRuleChangeEvent extends WorldEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final CommandSender commandSender; -+ private final GameRule gameRule; -+ private String value; -+ private boolean cancelled; -+ -+ public WorldGameRuleChangeEvent(@NotNull World world, @Nullable CommandSender commandSender, @NotNull GameRule gameRule, @NotNull String value) { -+ super(world); -+ this.commandSender = commandSender; -+ this.gameRule = gameRule; -+ this.value = value; -+ } -+ -+ /** -+ * Gets the command sender associated with this event. -+ * -+ * @return {@code null} if the gamerule was changed via api, otherwise the {@link CommandSender}. -+ */ -+ @Nullable -+ public CommandSender getCommandSender() { -+ return commandSender; -+ } -+ -+ /** -+ * Gets the game rule associated with this event. -+ * -+ * @return the gamerule being changed. -+ */ -+ @NotNull -+ public GameRule getGameRule() { -+ return gameRule; -+ } -+ -+ /** -+ * Gets the new value of the gamerule. -+ * -+ * @return the new value of the gamerule. -+ */ -+ @NotNull -+ public String getValue() { -+ return value; -+ } -+ -+ /** -+ * Sets the new value of this gamerule. -+ * -+ * @param value the new value of the gamerule. -+ */ -+ public void setValue(@NotNull String value) { -+ this.value = value; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} diff --git a/patches/api/0250-added-PlayerNameEntityEvent.patch b/patches/api/0250-added-PlayerNameEntityEvent.patch new file mode 100644 index 000000000000..d7b2294c6dfe --- /dev/null +++ b/patches/api/0250-added-PlayerNameEntityEvent.patch @@ -0,0 +1,119 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 5 Jul 2020 00:34:24 -0700 +Subject: [PATCH] added PlayerNameEntityEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerNameEntityEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerNameEntityEvent.java +new file mode 100755 +index 0000000000000000000000000000000000000000..fb990180d9958fe2bbe44e86aa360102f37be9ed +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerNameEntityEvent.java +@@ -0,0 +1,107 @@ ++package io.papermc.paper.event.player; ++ ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when the player is attempting to rename a mob ++ */ ++@NullMarked ++public class PlayerNameEntityEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private LivingEntity entity; ++ private @Nullable Component name; ++ private boolean persistent; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerNameEntityEvent(final Player player, final LivingEntity entity, final Component name, final boolean persistent) { ++ super(player); ++ this.entity = entity; ++ this.name = name; ++ this.persistent = persistent; ++ } ++ ++ /** ++ * Gets the name to be given to the entity. ++ * ++ * @return the name ++ */ ++ public @Nullable Component getName() { ++ return this.name; ++ } ++ ++ /** ++ * Sets the name to be given to the entity. ++ * ++ * @param name the name ++ */ ++ public void setName(final @Nullable Component name) { ++ this.name = name; ++ } ++ ++ /** ++ * Gets the entity involved in this event. ++ * ++ * @return the entity ++ */ ++ public LivingEntity getEntity() { ++ return this.entity; ++ } ++ ++ /** ++ * Sets the entity involved in this event. ++ * ++ * @param entity the entity ++ */ ++ public void setEntity(final LivingEntity entity) { ++ this.entity = entity; ++ } ++ ++ /** ++ * Gets whether this will set the mob to be persistent. ++ * ++ * @return persistent ++ */ ++ public boolean isPersistent() { ++ return this.persistent; ++ } ++ ++ /** ++ * Sets whether this will set the mob to be persistent. ++ * ++ * @param persistent persistent ++ */ ++ public void setPersistent(final boolean persistent) { ++ this.persistent = persistent; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0251-Add-recipe-to-cook-events.patch b/patches/api/0251-Add-recipe-to-cook-events.patch new file mode 100644 index 000000000000..8c8712541e49 --- /dev/null +++ b/patches/api/0251-Add-recipe-to-cook-events.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> +Date: Wed, 6 Jan 2021 12:05:29 -0800 +Subject: [PATCH] Add recipe to cook events + + +diff --git a/src/main/java/org/bukkit/event/block/BlockCookEvent.java b/src/main/java/org/bukkit/event/block/BlockCookEvent.java +index be7af5440bf9923f0c9c84efa4d70a89337a2f96..a3f1c9cb36c9069ed622985a525bfc2a7a27ab91 100644 +--- a/src/main/java/org/bukkit/event/block/BlockCookEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockCookEvent.java +@@ -14,12 +14,21 @@ public class BlockCookEvent extends BlockEvent implements Cancellable { + private final ItemStack source; + private ItemStack result; + private boolean cancelled; ++ private final org.bukkit.inventory.CookingRecipe recipe; // Paper + ++ @Deprecated // Paper + public BlockCookEvent(@NotNull final Block block, @NotNull final ItemStack source, @NotNull final ItemStack result) { ++ // Paper start ++ this(block, source, result, null); ++ } ++ ++ public BlockCookEvent(@NotNull final Block block, @NotNull final ItemStack source, @NotNull final ItemStack result, @org.jetbrains.annotations.Nullable org.bukkit.inventory.CookingRecipe recipe) { ++ // Paper end + super(block); + this.source = source; + this.result = result; + this.cancelled = false; ++ this.recipe = recipe; // Paper + } + + /** +@@ -61,6 +70,18 @@ public class BlockCookEvent extends BlockEvent implements Cancellable { + this.cancelled = cancel; + } + ++ // Paper start ++ /** ++ * Gets the cooking recipe associated with this event. ++ * ++ * @return the recipe ++ */ ++ @org.jetbrains.annotations.Nullable ++ public org.bukkit.inventory.CookingRecipe getRecipe() { ++ return recipe; ++ } ++ // Paper end ++ + @NotNull + @Override + public HandlerList getHandlers() { +diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java +index f8f9b08a0bd82a2667ae4e0c99dae9103f0db3f0..25478725bef34153bca204c815a167913b9cd389 100644 +--- a/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java +@@ -12,7 +12,13 @@ import org.jetbrains.annotations.NotNull; + */ + public class FurnaceSmeltEvent extends BlockCookEvent { + ++ @Deprecated // Paper + public FurnaceSmeltEvent(@NotNull final Block furnace, @NotNull final ItemStack source, @NotNull final ItemStack result) { + super(furnace, source, result); + } ++ // Paper start ++ public FurnaceSmeltEvent(@NotNull final Block furnace, @NotNull final ItemStack source, @NotNull final ItemStack result, @org.jetbrains.annotations.Nullable org.bukkit.inventory.CookingRecipe recipe) { ++ super(furnace, source, result, recipe); ++ } ++ // Paper end + } diff --git a/patches/api/0251-Added-ServerResourcesReloadedEvent.patch b/patches/api/0251-Added-ServerResourcesReloadedEvent.patch deleted file mode 100644 index de081bbae793..000000000000 --- a/patches/api/0251-Added-ServerResourcesReloadedEvent.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 2 Dec 2020 20:04:16 -0800 -Subject: [PATCH] Added ServerResourcesReloadedEvent - - -diff --git a/src/main/java/io/papermc/paper/event/server/ServerResourcesReloadedEvent.java b/src/main/java/io/papermc/paper/event/server/ServerResourcesReloadedEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7a8d6815c17a107039399298f7ac9f0612faee02 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/server/ServerResourcesReloadedEvent.java -@@ -0,0 +1,48 @@ -+package io.papermc.paper.event.server; -+ -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.server.ServerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when resources such as datapacks are reloaded (e.g. /minecraft:reload) -+ *

      -+ * Intended for use to re-register custom recipes, advancements that may be lost during a reload like this. -+ *

      -+ */ -+public class ServerResourcesReloadedEvent extends ServerEvent { -+ -+ public static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final Cause cause; -+ -+ public ServerResourcesReloadedEvent(@NotNull Cause cause) { -+ this.cause = cause; -+ } -+ -+ /** -+ * Gets the cause of the resource reload. -+ * -+ * @return the reload cause -+ */ -+ @NotNull -+ public Cause getCause() { -+ return cause; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ public enum Cause { -+ COMMAND, -+ PLUGIN, -+ } -+} diff --git a/patches/api/0252-Add-Block-isValidTool.patch b/patches/api/0252-Add-Block-isValidTool.patch new file mode 100644 index 000000000000..871c1ca2ea4a --- /dev/null +++ b/patches/api/0252-Add-Block-isValidTool.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 6 Jul 2020 12:44:23 -0700 +Subject: [PATCH] Add Block#isValidTool + +Deprecated for removal + +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index 53b8bbe9717e64fa7f9acf3611121218ff92902b..bd50ec2a93800af9ce663fd10ecf74ae011a6715 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -232,6 +232,19 @@ public interface Block extends Metadatable, Translatable, net.kyori.adventure.tr + } + // Paper end + ++ // Paper start - add isValidTool ++ /** ++ * Checks if the itemstack is a valid tool to ++ * break the block with ++ * ++ * @param itemStack The (tool) itemstack ++ * @return whether the block will drop items ++ * @deprecated partially replaced by {@link Block#isPreferredTool(ItemStack)} ++ */ ++ @Deprecated(since = "1.21", forRemoval = true) // Paper ++ boolean isValidTool(@NotNull ItemStack itemStack); ++ // Paper end - add isValidTool ++ + /** + * Gets the Location of the block + * diff --git a/patches/api/0252-Add-BlockFailedDispenseEvent.patch b/patches/api/0252-Add-BlockFailedDispenseEvent.patch deleted file mode 100644 index 126714b965c3..000000000000 --- a/patches/api/0252-Add-BlockFailedDispenseEvent.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TheViperShow <29604693+TheViperShow@users.noreply.github.com> -Date: Wed, 22 Apr 2020 09:40:23 +0200 -Subject: [PATCH] Add BlockFailedDispenseEvent - - -diff --git a/src/main/java/io/papermc/paper/event/block/BlockFailedDispenseEvent.java b/src/main/java/io/papermc/paper/event/block/BlockFailedDispenseEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..dab794341170ed10d5a05c1b4c180d164e0f70e2 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/BlockFailedDispenseEvent.java -@@ -0,0 +1,57 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a block tries to dispense an item, but its inventory is empty. -+ */ -+public class BlockFailedDispenseEvent extends BlockEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ private boolean shouldPlayEffect = true; -+ -+ public BlockFailedDispenseEvent(@NotNull Block theBlock) { -+ super(theBlock); -+ } -+ -+ /** -+ * @return if the effect should be played -+ */ -+ public boolean shouldPlayEffect() { -+ return this.shouldPlayEffect; -+ } -+ -+ /** -+ * Sets if the effect for empty dispensers should be played -+ * -+ * @param playEffect if the effect should be played -+ */ -+ public void shouldPlayEffect(boolean playEffect) { -+ this.shouldPlayEffect = playEffect; -+ } -+ -+ /** -+ * {@inheritDoc} -+ * -+ * @return {@link #shouldPlayEffect()} -+ */ -+ @Override -+ public boolean callEvent() { -+ super.callEvent(); -+ return this.shouldPlayEffect(); -+ } -+ -+ @Override -+ public @NotNull -+ HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ public static @NotNull -+ HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0253-Added-PlayerLecternPageChangeEvent.patch b/patches/api/0253-Added-PlayerLecternPageChangeEvent.patch deleted file mode 100644 index 2b65c3a24526..000000000000 --- a/patches/api/0253-Added-PlayerLecternPageChangeEvent.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 23 Nov 2020 12:58:16 -0800 -Subject: [PATCH] Added PlayerLecternPageChangeEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerLecternPageChangeEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerLecternPageChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..26370e46e4a12e3470e9bb747fac5786a7305810 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerLecternPageChangeEvent.java -@@ -0,0 +1,115 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.block.Lectern; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class PlayerLecternPageChangeEvent extends PlayerEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private boolean cancelled; -+ private final Lectern lectern; -+ private final ItemStack book; -+ private final PageChangeDirection pageChangeDirection; -+ private final int oldPage; -+ private int newPage; -+ -+ public PlayerLecternPageChangeEvent(@NotNull Player player, @NotNull Lectern lectern, @NotNull ItemStack book, @NotNull PageChangeDirection pageChangeDirection, int oldPage, int newPage) { -+ super(player); -+ this.lectern = lectern; -+ this.book = book; -+ this.pageChangeDirection = pageChangeDirection; -+ this.oldPage = oldPage; -+ this.newPage = newPage; -+ } -+ -+ /** -+ * Gets the lectern involved. -+ * -+ * @return the Lectern -+ */ -+ @NotNull -+ public Lectern getLectern() { -+ return lectern; -+ } -+ -+ /** -+ * Gets the current ItemStack on the lectern. -+ * -+ * @return the ItemStack on the Lectern -+ */ -+ @NotNull -+ public ItemStack getBook() { -+ return this.book; -+ } -+ -+ /** -+ * Gets the page change direction. This is essentially returns which button the player clicked, left or right. -+ * -+ * @return the page change direction -+ */ -+ @NotNull -+ public PageChangeDirection getPageChangeDirection() { -+ return pageChangeDirection; -+ } -+ -+ /** -+ * Gets the page changed from. Pages are 0-indexed. -+ * -+ * @return the page changed from -+ */ -+ public int getOldPage() { -+ return oldPage; -+ } -+ -+ /** -+ * Gets the page changed to. Pages are 0-indexed. -+ * -+ * @return the page changed to -+ */ -+ public int getNewPage() { -+ return newPage; -+ } -+ -+ /** -+ * Sets the page changed to. Pages are 0-indexed. -+ * Page indices that are greater than the number of pages will show the last page. -+ * -+ * @param newPage the new paged changed to -+ */ -+ public void setNewPage(int newPage) { -+ this.newPage = newPage; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+ -+ public enum PageChangeDirection { -+ LEFT, -+ RIGHT, -+ } -+} diff --git a/patches/api/0253-Expand-world-key-API.patch b/patches/api/0253-Expand-world-key-API.patch new file mode 100644 index 000000000000..65b04a5871f9 --- /dev/null +++ b/patches/api/0253-Expand-world-key-API.patch @@ -0,0 +1,211 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 6 Jan 2021 00:34:10 -0800 +Subject: [PATCH] Expand world key API + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 4000d3484516f235c6e41eb5bb90c0420754ce23..34e4493286c36a27715ad72201751c692abc9481 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -865,6 +865,29 @@ public final class Bukkit { + public static World getWorld(@NotNull UUID uid) { + return server.getWorld(uid); + } ++ // Paper start ++ /** ++ * Gets the world from the given NamespacedKey ++ * ++ * @param worldKey the NamespacedKey of the world to retrieve ++ * @return a world with the given NamespacedKey, or null if none exists ++ */ ++ @Nullable ++ public static World getWorld(@NotNull NamespacedKey worldKey) { ++ return server.getWorld(worldKey); ++ } ++ ++ /** ++ * Gets the world from the given Key ++ * ++ * @param worldKey the Key of the world to retrieve ++ * @return a world with the given Key, or null if none exists ++ */ ++ @Nullable ++ public static World getWorld(@NotNull net.kyori.adventure.key.Key worldKey) { ++ return server.getWorld(worldKey); ++ } ++ // Paper end + + /** + * Create a new virtual {@link WorldBorder}. +diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java +index 27eff0826d5b5b48697fefd9571886e7bbce74b1..d8b1fa79dc24138dc71e32c14bda71c1d570ed88 100644 +--- a/src/main/java/org/bukkit/RegionAccessor.java ++++ b/src/main/java/org/bukkit/RegionAccessor.java +@@ -18,7 +18,7 @@ import org.jetbrains.annotations.Nullable; + * A RegionAccessor gives access to getting, modifying and spawning {@link Biome}, {@link BlockState} and {@link Entity}, + * as well as generating some basic structures. + */ +-public interface RegionAccessor { ++public interface RegionAccessor extends Keyed { // Paper + + /** + * Gets the {@link Biome} at the given {@link Location}. +@@ -452,5 +452,14 @@ public interface RegionAccessor { + */ + @NotNull + io.papermc.paper.world.MoonPhase getMoonPhase(); ++ ++ /** ++ * Get the world's key ++ * ++ * @return the world's key ++ */ ++ @NotNull ++ @Override ++ NamespacedKey getKey(); + // Paper end + } +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 7204e7046cb76f715f294822dff7deb069a3c802..db7aa3a1967d6c093f5fd22443238b566a035835 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -726,6 +726,28 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @Nullable + public World getWorld(@NotNull UUID uid); + ++ // Paper start ++ /** ++ * Gets the world from the given NamespacedKey ++ * ++ * @param worldKey the NamespacedKey of the world to retrieve ++ * @return a world with the given NamespacedKey, or null if none exists ++ */ ++ @Nullable ++ default World getWorld(@NotNull NamespacedKey worldKey) { ++ return getWorld((net.kyori.adventure.key.Key) worldKey); ++ } ++ ++ /** ++ * Gets the world from the given Key ++ * ++ * @param worldKey the Key of the world to retrieve ++ * @return a world with the given Key, or null if none exists ++ */ ++ @Nullable ++ World getWorld(@NotNull net.kyori.adventure.key.Key worldKey); ++ // Paper end ++ + /** + * Create a new virtual {@link WorldBorder}. + *

      +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index bd3567e9b0617c19a92090c8ab6baf17a715073a..1dea15bc75b2de1aadb7e769394df5160fc079e5 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -175,5 +175,10 @@ public interface UnsafeValues { + * Use this when sending custom packets, so that there are no collisions on the client or server. + */ + public int nextEntityId(); ++ ++ /** ++ * Just don't use it. ++ */ ++ @org.jetbrains.annotations.NotNull String getMainLevelName(); + // Paper end + } +diff --git a/src/main/java/org/bukkit/WorldCreator.java b/src/main/java/org/bukkit/WorldCreator.java +index 27537aeabd3bd1b5383e6ecf775aa89e033aa2bc..afc0ce2eaa7cf48d1255fec7377103b1f7a99734 100644 +--- a/src/main/java/org/bukkit/WorldCreator.java ++++ b/src/main/java/org/bukkit/WorldCreator.java +@@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; + * Represents various types of options that may be used to create a world. + */ + public class WorldCreator { ++ private final NamespacedKey key; // Paper + private final String name; + private long seed; + private World.Environment environment = World.Environment.NORMAL; +@@ -30,11 +31,80 @@ public class WorldCreator { + * @param name Name of the world that will be created + */ + public WorldCreator(@NotNull String name) { +- Preconditions.checkArgument(name != null, "World name cannot be null"); ++ // Paper start ++ this(name, getWorldKey(name)); ++ } ++ ++ private static NamespacedKey getWorldKey(String name) { ++ final String mainLevelName = Bukkit.getUnsafe().getMainLevelName(); ++ if (name.equals(mainLevelName)) { ++ return NamespacedKey.minecraft("overworld"); ++ } else if (name.equals(mainLevelName + "_nether")) { ++ return NamespacedKey.minecraft("the_nether"); ++ } else if (name.equals(mainLevelName + "_the_end")) { ++ return NamespacedKey.minecraft("the_end"); ++ } else { ++ return NamespacedKey.minecraft(name.toLowerCase(java.util.Locale.ENGLISH).replace(" ", "_")); ++ } ++ } + +- this.name = name; ++ /** ++ * Creates an empty WorldCreator for the given world name and key ++ * ++ * @param levelName LevelName of the world that will be created ++ * @param worldKey NamespacedKey of the world that will be created ++ */ ++ public WorldCreator(@NotNull String levelName, @NotNull NamespacedKey worldKey) { ++ if (levelName == null || worldKey == null) { ++ throw new IllegalArgumentException("World name and key cannot be null"); ++ } ++ this.name = levelName; + this.seed = (new Random()).nextLong(); ++ this.key = worldKey; ++ } ++ ++ /** ++ * Creates an empty WorldCreator for the given key. ++ * LevelName will be the Key part of the NamespacedKey. ++ * ++ * @param worldKey NamespacedKey of the world that will be created ++ */ ++ public WorldCreator(@NotNull NamespacedKey worldKey) { ++ this(worldKey.getKey(), worldKey); ++ } ++ ++ /** ++ * Gets the key for this WorldCreator ++ * ++ * @return the key ++ */ ++ @NotNull ++ public NamespacedKey key() { ++ return key; ++ } ++ ++ /** ++ * Creates an empty WorldCreator for the given world name and key ++ * ++ * @param levelName LevelName of the world that will be created ++ * @param worldKey NamespacedKey of the world that will be created ++ */ ++ @NotNull ++ public static WorldCreator ofNameAndKey(@NotNull String levelName, @NotNull NamespacedKey worldKey) { ++ return new WorldCreator(levelName, worldKey); ++ } ++ ++ /** ++ * Creates an empty WorldCreator for the given key. ++ * LevelName will be the Key part of the NamespacedKey. ++ * ++ * @param worldKey NamespacedKey of the world that will be created ++ */ ++ @NotNull ++ public static WorldCreator ofKey(@NotNull NamespacedKey worldKey) { ++ return new WorldCreator(worldKey); + } ++ // Paper end + + /** + * Copies the options from the specified world diff --git a/patches/api/0254-Added-PlayerLoomPatternSelectEvent.patch b/patches/api/0254-Added-PlayerLoomPatternSelectEvent.patch deleted file mode 100644 index 567702695669..000000000000 --- a/patches/api/0254-Added-PlayerLoomPatternSelectEvent.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 25 Nov 2020 16:33:42 -0800 -Subject: [PATCH] Added PlayerLoomPatternSelectEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerLoomPatternSelectEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerLoomPatternSelectEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8cb05709f7cb5dee993ff6fea1626c41b90a7d8b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerLoomPatternSelectEvent.java -@@ -0,0 +1,77 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.block.banner.PatternType; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.LoomInventory; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player selects a banner patten in a loom inventory. -+ */ -+public class PlayerLoomPatternSelectEvent extends PlayerEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private boolean cancelled; -+ private final LoomInventory loomInventory; -+ private PatternType patternType; -+ -+ public PlayerLoomPatternSelectEvent(@NotNull Player player, @NotNull LoomInventory loomInventory, @NotNull PatternType patternType) { -+ super(player); -+ this.loomInventory = loomInventory; -+ this.patternType = patternType; -+ } -+ -+ /** -+ * Gets the loom inventory involved. -+ * -+ * @return the loom inventory -+ */ -+ @NotNull -+ public LoomInventory getLoomInventory() { -+ return loomInventory; -+ } -+ -+ /** -+ * Gets the pattern type selected. -+ * -+ * @return the pattern type -+ */ -+ @NotNull -+ public PatternType getPatternType() { -+ return patternType; -+ } -+ -+ /** -+ * Sets the pattern type selected. -+ * -+ * @param patternType the pattern type -+ */ -+ public void setPatternType(@NotNull PatternType patternType) { -+ this.patternType = patternType; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} diff --git a/patches/api/0254-Improve-Item-Rarity-API.patch b/patches/api/0254-Improve-Item-Rarity-API.patch new file mode 100644 index 000000000000..7152f31b0773 --- /dev/null +++ b/patches/api/0254-Improve-Item-Rarity-API.patch @@ -0,0 +1,151 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 12 Mar 2021 17:09:40 -0800 +Subject: [PATCH] Improve Item Rarity API + + +diff --git a/src/main/java/io/papermc/paper/inventory/ItemRarity.java b/src/main/java/io/papermc/paper/inventory/ItemRarity.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f1cd5a4f37eee8975ac3d0421b524afcf644fafd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/inventory/ItemRarity.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.inventory; ++ ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.format.TextColor; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * @deprecated use {@link org.bukkit.inventory.ItemRarity} with {@link org.bukkit.inventory.meta.ItemMeta#getRarity()} ++ */ ++@Deprecated(forRemoval = true, since = "1.20.5") ++public enum ItemRarity { ++ ++ COMMON(NamedTextColor.WHITE), ++ UNCOMMON(NamedTextColor.YELLOW), ++ RARE(NamedTextColor.AQUA), ++ EPIC(NamedTextColor.LIGHT_PURPLE); ++ ++ TextColor color; ++ ++ ItemRarity(TextColor color) { ++ this.color = color; ++ } ++ ++ /** ++ * Gets the color formatting associated with the rarity. ++ * @return ++ */ ++ @NotNull ++ public TextColor getColor() { ++ return color; ++ } ++} +diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java +index 8509519ec0d5509f45e43f28b5bb55d953cebb14..efeda14f1caebd6be8695cf9a2a8d920a3db45a2 100644 +--- a/src/main/java/org/bukkit/Material.java ++++ b/src/main/java/org/bukkit/Material.java +@@ -4845,6 +4845,21 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla + } + // Paper end - add Translatable + ++ // Paper start - item rarity API ++ /** ++ * Returns the item rarity for the item. The Material MUST be an Item not a block. ++ * Use {@link #isItem()} before this. ++ * ++ * @return the item rarity ++ * @deprecated use {@link org.bukkit.inventory.meta.ItemMeta#hasRarity()} and {@link org.bukkit.inventory.meta.ItemMeta#getRarity()} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.20.5") ++ public io.papermc.paper.inventory.ItemRarity getItemRarity() { ++ return new org.bukkit.inventory.ItemStack(this).getRarity(); ++ } ++ // Paper end - item rarity API ++ + /** + * Do not use for any reason. + * +diff --git a/src/main/java/org/bukkit/inventory/ItemRarity.java b/src/main/java/org/bukkit/inventory/ItemRarity.java +index e7931f73f10fe35ebd5fe4a04b036d53bb117ebd..cbce835ed6d44e5b8c9aaae4e36a77f8e5bed45f 100644 +--- a/src/main/java/org/bukkit/inventory/ItemRarity.java ++++ b/src/main/java/org/bukkit/inventory/ItemRarity.java +@@ -9,17 +9,32 @@ public enum ItemRarity { + /** + * White item name. + */ +- COMMON, ++ COMMON(net.kyori.adventure.text.format.NamedTextColor.WHITE), // Paper + /** + * Yellow item name. + */ +- UNCOMMON, ++ UNCOMMON(net.kyori.adventure.text.format.NamedTextColor.YELLOW), // Paper + /** + * Aqua item name. + */ +- RARE, ++ RARE(net.kyori.adventure.text.format.NamedTextColor.AQUA), // Paper + /** + * Light purple item name. + */ +- EPIC; ++ EPIC(net.kyori.adventure.text.format.NamedTextColor.LIGHT_PURPLE); // Paper ++ // Paper start - improve ItemRarity ++ private final net.kyori.adventure.text.format.NamedTextColor color; ++ ItemRarity(final net.kyori.adventure.text.format.NamedTextColor color) { ++ this.color = color; ++ } ++ ++ /** ++ * Gets the color formatting associated with this rarity. ++ * ++ * @return the color ++ */ ++ public net.kyori.adventure.text.format.@org.jetbrains.annotations.NotNull TextColor color() { ++ return this.color; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index 665fe4b551abcd33a4c9bab69746200c3a150cae..06207f1527e8afe8bb786410c9659bb92792ea6f 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -994,5 +994,17 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + public @NotNull String translationKey() { + return Bukkit.getUnsafe().getTranslationKey(this); + } ++ ++ /** ++ * Gets the item rarity of the itemstack. The rarity can change based on enchantments. ++ * ++ * @return the itemstack rarity ++ * @deprecated Use {@link ItemMeta#hasRarity()} and {@link ItemMeta#getRarity()} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.20.5") ++ public io.papermc.paper.inventory.ItemRarity getRarity() { ++ return io.papermc.paper.inventory.ItemRarity.valueOf(this.getItemMeta().getRarity().name()); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/ItemType.java b/src/main/java/org/bukkit/inventory/ItemType.java +index ab5d544942b7a5387998353614a33ca692edb50e..9f0f788cc81e8fc0b45bdd97e284d5a9785e7e8c 100644 +--- a/src/main/java/org/bukkit/inventory/ItemType.java ++++ b/src/main/java/org/bukkit/inventory/ItemType.java +@@ -2418,4 +2418,13 @@ public interface ItemType extends Keyed, Translatable, net.kyori.adventure.trans + @Override + @NotNull String getTranslationKey(); + // Paper end - add Translatable ++ ++ // Paper start - expand ItemRarity API ++ /** ++ * Returns the item rarity for the item. ++ * ++ * @return the item rarity (or null if none is set) ++ */ ++ @Nullable ItemRarity getItemRarity(); ++ // Paper end - expand ItemRarity API + } diff --git a/patches/api/0255-Add-API-to-get-exact-interaction-point-in-PlayerInte.patch b/patches/api/0255-Add-API-to-get-exact-interaction-point-in-PlayerInte.patch deleted file mode 100644 index afc3f45d2893..000000000000 --- a/patches/api/0255-Add-API-to-get-exact-interaction-point-in-PlayerInte.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Madeline Miller -Date: Mon, 4 Jan 2021 16:40:55 +1000 -Subject: [PATCH] Add API to get exact interaction point in PlayerInteractEvent - - -diff --git a/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java b/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java -index 1208e1f8c2163d83c5b12bbb9b7ac044c72380e0..a01f86e6aba8b66ecc713da0787cd861e2930a2a 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerInteractEvent.java -@@ -1,5 +1,6 @@ - package org.bukkit.event.player; - -+import org.bukkit.Location; - import org.bukkit.Material; - import org.bukkit.block.Block; - import org.bukkit.block.BlockFace; -@@ -34,22 +35,30 @@ public class PlayerInteractEvent extends PlayerEvent implements Cancellable { - private Result useClickedBlock; - private Result useItemInHand; - private EquipmentSlot hand; -+ private Location interactionPoint; // Paper - - public PlayerInteractEvent(@NotNull final Player who, @NotNull final Action action, @Nullable final ItemStack item, @Nullable final Block clickedBlock, @NotNull final BlockFace clickedFace) { - this(who, action, item, clickedBlock, clickedFace, EquipmentSlot.HAND); - } - - public PlayerInteractEvent(@NotNull final Player who, @NotNull final Action action, @Nullable final ItemStack item, @Nullable final Block clickedBlock, @NotNull final BlockFace clickedFace, @Nullable final EquipmentSlot hand) { -+ // Paper start - Add interactionPoint -+ this(who, action, item, clickedBlock, clickedFace, hand, null); -+ } -+ -+ public PlayerInteractEvent(@NotNull final Player who, @NotNull final Action action, @Nullable final ItemStack item, @Nullable final Block clickedBlock, @NotNull final BlockFace clickedFace, @Nullable final EquipmentSlot hand, @Nullable final Location interactionPoint) { - super(who); - this.action = action; - this.item = item; - this.blockClicked = clickedBlock; - this.blockFace = clickedFace; - this.hand = hand; -+ this.interactionPoint = interactionPoint; - - useItemInHand = Result.DEFAULT; - useClickedBlock = clickedBlock == null ? Result.DENY : Result.ALLOW; - } -+ // Paper end - - /** - * Returns the action type -@@ -221,6 +230,18 @@ public class PlayerInteractEvent extends PlayerEvent implements Cancellable { - return hand; - } - -+ // Paper start -+ /** -+ * The exact point at which the interaction occurred. May be null. -+ * -+ * @return the exact interaction point. May be null. -+ */ -+ @Nullable -+ public Location getInteractionPoint() { -+ return interactionPoint; -+ } -+ // Paper end -+ - @NotNull - @Override - public HandlerList getHandlers() { diff --git a/patches/api/0255-Expose-protocol-version.patch b/patches/api/0255-Expose-protocol-version.patch new file mode 100644 index 000000000000..810f5b30041c --- /dev/null +++ b/patches/api/0255-Expose-protocol-version.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Fri, 26 Mar 2021 11:23:27 +0100 +Subject: [PATCH] Expose protocol version + + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 1dea15bc75b2de1aadb7e769394df5160fc079e5..989a7e624dca442f1c989bb766e4c16a75e87333 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -180,5 +180,12 @@ public interface UnsafeValues { + * Just don't use it. + */ + @org.jetbrains.annotations.NotNull String getMainLevelName(); ++ ++ /** ++ * Returns the server's protocol version. ++ * ++ * @return the server's protocol version ++ */ ++ int getProtocolVersion(); + // Paper end + } diff --git a/patches/api/0256-Add-sendOpLevel-API.patch b/patches/api/0256-Add-sendOpLevel-API.patch deleted file mode 100644 index 80abd8945e75..000000000000 --- a/patches/api/0256-Add-sendOpLevel-API.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Tue, 29 Dec 2020 15:02:57 +0100 -Subject: [PATCH] Add sendOpLevel API - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index a097d060dc2a345406c3121b2aed038377148862..701b34b02886dcef2837f00a945f813165d914f5 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -2498,6 +2498,17 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - */ - @Nullable - Firework boostElytra(@NotNull ItemStack firework); -+ -+ /** -+ * Send a packet to the player indicating its operator status level. -+ *

      -+ * Note: This will not persist across more than the current connection, and setting the player's operator -+ * status as a later point will override the effects of this. -+ * -+ * @param level The level to send to the player. Must be in {@code [0, 4]}. -+ * @throws IllegalArgumentException If the level is negative or greater than {@code 4} (i.e. not within {@code [0, 4]}). -+ */ -+ void sendOpLevel(byte level); - // Paper end - - // Spigot start diff --git a/patches/api/0256-add-isDeeplySleeping-to-HumanEntity.patch b/patches/api/0256-add-isDeeplySleeping-to-HumanEntity.patch new file mode 100644 index 000000000000..b86f5d0885e2 --- /dev/null +++ b/patches/api/0256-add-isDeeplySleeping-to-HumanEntity.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 8 Apr 2021 17:36:15 -0700 +Subject: [PATCH] add isDeeplySleeping to HumanEntity + + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index 551b2a85745382ea6e0038088e6229260bfea067..10576d39e019c0ca6bbd07b889a4580b2883d875 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -366,6 +366,15 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder + void setHurtDirection(float hurtDirection); + // Paper end + ++ // Paper start ++ /** ++ * If the player has slept enough to count towards passing the night. ++ * ++ * @return true if the player has slept enough ++ */ ++ public boolean isDeeplySleeping(); ++ // Paper end ++ + /** + * Check whether a cooldown is active on the specified item. + * diff --git a/patches/api/0257-Add-PaperRegistry.patch b/patches/api/0257-Add-PaperRegistry.patch deleted file mode 100644 index 1a1ca3cc2448..000000000000 --- a/patches/api/0257-Add-PaperRegistry.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 2 Mar 2022 13:36:21 -0800 -Subject: [PATCH] Add PaperRegistry - - -diff --git a/src/main/java/io/papermc/paper/registry/Reference.java b/src/main/java/io/papermc/paper/registry/Reference.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d880810cbf05bc45051fe29515054211572e33b4 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/Reference.java -@@ -0,0 +1,43 @@ -+package io.papermc.paper.registry; -+ -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Registry; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Represents a reference to a server-backed registry value that may -+ * change. -+ * -+ * @param type of the value -+ */ -+public interface Reference extends Keyed { -+ -+ /** -+ * Gets the value from the registry with the key. -+ * -+ * @return the value -+ * @throws java.util.NoSuchElementException if there is no value with this key -+ */ -+ @NotNull T value(); -+ -+ /** -+ * Gets the value from the registry with the key. -+ * -+ * @return the value or null if it doesn't exist -+ */ -+ @Nullable T valueOrNull(); -+ -+ /** -+ * Creates a reference to a registered value. -+ * -+ * @param registry the registry the value is located in -+ * @param key the key to the value -+ * @param the type of the value -+ * @return a reference -+ */ -+ static @NotNull Reference create(@NotNull Registry registry, @NotNull NamespacedKey key) { -+ return new ReferenceImpl<>(registry, key); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/ReferenceImpl.java b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f29e76a6b66ddfec12ddf8db6dcb2df6083b5982 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java -@@ -0,0 +1,31 @@ -+package io.papermc.paper.registry; -+ -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Registry; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.NoSuchElementException; -+ -+record ReferenceImpl(@NotNull Registry registry, @NotNull NamespacedKey key) implements Reference { -+ -+ @Override -+ public @NotNull T value() { -+ final T value = this.registry.get(this.key); -+ if (value == null) { -+ throw new NoSuchElementException("No such value with key " + this.key); -+ } -+ return value; -+ } -+ -+ @Override -+ public @Nullable T valueOrNull() { -+ return this.registry.get(this.key); -+ } -+ -+ @Override -+ public @NotNull NamespacedKey getKey() { -+ return this.key; -+ } -+} -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 035dfcd9d483152a050e45409f15b015b135fb38..abe79e4a2233341d0030742b823a0cfb5af97f41 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -147,5 +147,15 @@ public interface UnsafeValues { - * Use this when sending custom packets, so that there are no collisions on the client or server. - */ - public int nextEntityId(); -+ -+ /** -+ * Gets the server-backed registry for a type. -+ * -+ * @param classOfT type -+ * @param type -+ * @return the server-backed registry -+ * @throws IllegalArgumentException if there isn't a registry for that type -+ */ -+ @org.jetbrains.annotations.NotNull Registry registryFor(Class classOfT); - // Paper end - } diff --git a/patches/api/0257-add-consumeFuel-to-FurnaceBurnEvent.patch b/patches/api/0257-add-consumeFuel-to-FurnaceBurnEvent.patch new file mode 100644 index 000000000000..07036efb4399 --- /dev/null +++ b/patches/api/0257-add-consumeFuel-to-FurnaceBurnEvent.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 22 Apr 2021 16:45:15 -0700 +Subject: [PATCH] add consumeFuel to FurnaceBurnEvent + + +diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java +index 24077da8e6a7937f66eafc6779206055cf82e8d2..ba4dc8aed85169e55cac276bdd51116919305019 100644 +--- a/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java +@@ -18,6 +18,7 @@ public class FurnaceBurnEvent extends BlockEvent implements Cancellable { + private int burnTime; + private boolean cancelled; + private boolean burning; ++ private boolean consumeFuel = true; // Paper + + public FurnaceBurnEvent(@NotNull final Block furnace, @NotNull final ItemStack fuel, final int burnTime) { + super(furnace); +@@ -72,6 +73,25 @@ public class FurnaceBurnEvent extends BlockEvent implements Cancellable { + public void setBurning(boolean burning) { + this.burning = burning; + } ++ // Paper start ++ /** ++ * Gets whether the furnace's fuel will be consumed or not. ++ * ++ * @return whether the furnace's fuel will be consumed ++ */ ++ public boolean willConsumeFuel() { ++ return consumeFuel; ++ } ++ ++ /** ++ * Sets whether the furnace's fuel will be consumed or not. ++ * ++ * @param consumeFuel true to consume the fuel ++ */ ++ public void setConsumeFuel(boolean consumeFuel) { ++ this.consumeFuel = consumeFuel; ++ } ++ // Paper end + + @Override + public boolean isCancelled() { diff --git a/patches/api/0258-Add-StructuresLocateEvent.patch b/patches/api/0258-Add-StructuresLocateEvent.patch deleted file mode 100644 index 267a1b804500..000000000000 --- a/patches/api/0258-Add-StructuresLocateEvent.patch +++ /dev/null @@ -1,462 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: dfsek -Date: Tue, 15 Sep 2020 21:59:16 -0700 -Subject: [PATCH] Add StructuresLocateEvent - -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/io/papermc/paper/event/world/StructureLocateEvent.java b/src/main/java/io/papermc/paper/event/world/StructureLocateEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0c83a02059d65672ff191c42932d850950e9ea00 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/world/StructureLocateEvent.java -@@ -0,0 +1,157 @@ -+package io.papermc.paper.event.world; -+ -+import org.bukkit.Location; -+import org.bukkit.StructureType; -+import org.bukkit.World; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.world.WorldEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called before a structure/feature is located. -+ * This happens when: -+ *

        -+ *
      • The /locate command is used.
      • -+ *
      • An Eye of Ender is used.
      • -+ *
      • An Explorer/Treasure Map is activated.
      • -+ *
      • {@link World#locateNearestStructure(Location, StructureType, int, boolean)} is invoked.
      • -+ *
      -+ * @deprecated no longer used, see {@link StructuresLocateEvent} -+ */ -+@Deprecated(forRemoval = true) -+public class StructureLocateEvent extends WorldEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private final Location origin; -+ private Location result = null; -+ private StructureType type; -+ private int radius; -+ private boolean findUnexplored; -+ private boolean cancelled = false; -+ -+ public StructureLocateEvent(@NotNull World world, @NotNull Location origin, @NotNull StructureType structureType, int radius, boolean findUnexplored) { -+ super(world); -+ this.origin = origin; -+ this.type = structureType; -+ this.radius = radius; -+ this.findUnexplored = findUnexplored; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ /** -+ * Gets the location set as the structure location, if it was defined. -+ *

      -+ * Returns {@code null} if it has not been set by {@link StructureLocateEvent#setResult(Location)}. -+ * Since this event fires before the search is done, the actual location is unknown at this point. -+ * -+ * @return The result location, if it has been set. null if it has not. -+ * @see World#locateNearestStructure(Location, StructureType, int, boolean) -+ */ -+ @Nullable -+ public Location getResult() { -+ return result; -+ } -+ -+ /** -+ * Sets the result {@link Location}. This causes the search to be skipped, and the location passed here to be used as the result. -+ * -+ * @param result the {@link Location} of the structure. -+ */ -+ public void setResult(@Nullable Location result) { -+ this.result = result; -+ } -+ -+ /** -+ * Gets the {@link StructureType} that is to be located. -+ * -+ * @return the structure type. -+ */ -+ @NotNull -+ public StructureType getType() { -+ return type; -+ } -+ -+ /** -+ * Sets the {@link StructureType} that is to be located. -+ * -+ * @param type the structure type. -+ */ -+ public void setType(@NotNull StructureType type) { -+ this.type = type; -+ } -+ -+ /** -+ * Gets the {@link Location} from which the search is to be conducted. -+ * -+ * @return {@link Location} where search begins -+ */ -+ @NotNull -+ public Location getOrigin() { -+ return origin; -+ } -+ -+ /** -+ * Gets the search radius in which to attempt locating the structure. -+ *

      -+ * This radius may not always be obeyed during the structure search! -+ * -+ * @return the search radius. -+ */ -+ public int getRadius() { -+ return radius; -+ } -+ -+ /** -+ * Sets the search radius in which to attempt locating the structure. -+ *

      -+ * This radius may not always be obeyed during the structure search! -+ * -+ * @param radius the search radius. -+ */ -+ public void setRadius(int radius) { -+ this.radius = radius; -+ } -+ -+ /** -+ * Gets whether to search exclusively for unexplored structures. -+ *

      -+ * As with the search radius, this value is not always obeyed. -+ * -+ * @return Whether to search for only unexplored structures. -+ */ -+ public boolean shouldFindUnexplored() { -+ return findUnexplored; -+ } -+ -+ /** -+ * Sets whether to search exclusively for unexplored structures. -+ *

      -+ * As with the search radius, this value is not always obeyed. -+ * -+ * @param findUnexplored Whether to search for only unexplored structures. -+ */ -+ public void setFindUnexplored(boolean findUnexplored) { -+ this.findUnexplored = findUnexplored; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/event/world/StructuresLocateEvent.java b/src/main/java/io/papermc/paper/event/world/StructuresLocateEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..566f9df8f615142e14330965f3491f4e83846783 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/world/StructuresLocateEvent.java -@@ -0,0 +1,164 @@ -+package io.papermc.paper.event.world; -+ -+import io.papermc.paper.world.structure.ConfiguredStructure; -+import org.bukkit.Location; -+import org.bukkit.World; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.world.WorldEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.ArrayList; -+import java.util.List; -+ -+/** -+ * Called before a set of configured structures is located. -+ * This happens when: -+ *

        -+ *
      • The /locate command is used.
      • -+ *
      • An Eye of Ender is used.
      • -+ *
      • An Explorer/Treasure Map is activated.
      • -+ *
      • A dolphin swims to a treasure location.
      • -+ *
      • A trade is done with a villager for a map.
      • -+ *
      • {@link World#locateNearestStructure(Location, org.bukkit.StructureType, int, boolean)} is invoked.
      • -+ *
      -+ */ -+public class StructuresLocateEvent extends WorldEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final Location origin; -+ private Result result; -+ private List configuredStructures; -+ private int radius; -+ private boolean findUnexplored; -+ private boolean cancelled; -+ -+ public StructuresLocateEvent(@NotNull World world, @NotNull Location origin, @NotNull List configuredStructures, int radius, boolean findUnexplored) { -+ super(world); -+ this.origin = origin; -+ this.configuredStructures = configuredStructures; -+ this.radius = radius; -+ this.findUnexplored = findUnexplored; -+ } -+ -+ /** -+ * Gets the {@link Location} from which the search is to be conducted. -+ * -+ * @return {@link Location} where search begins -+ */ -+ public @NotNull Location getOrigin() { -+ return this.origin; -+ } -+ -+ /** -+ * Gets the {@link Location} and {@link ConfiguredStructure} set as the result, if it was defined. -+ *

      -+ * Returns {@code null} if it has not been set by {@link StructuresLocateEvent#setResult(Result)}. -+ * Since this event fires before the search is done, the actual result is unknown at this point. -+ * -+ * @return The result location and structure, if it has been set. null if it has not. -+ * @see World#locateNearestStructure(Location, org.bukkit.StructureType, int, boolean) -+ */ -+ public @Nullable Result getResult() { -+ return this.result; -+ } -+ -+ /** -+ * Sets the result {@link Location} and {@link ConfiguredStructure}. This causes the search to be -+ * skipped, and the result object passed here to be used as the result. -+ * -+ * @param result the {@link Location} and {@link ConfiguredStructure} of the search. -+ */ -+ public void setResult(@Nullable Result result) { -+ this.result = result; -+ } -+ -+ /** -+ * Gets a mutable list of ConfiguredStructures that are valid targets for the search. -+ * -+ * @return a mutable list of ConfiguredStructures -+ */ -+ public @NotNull List getConfiguredStructures() { -+ return this.configuredStructures; -+ } -+ -+ /** -+ * Sets the list of ConfiguredStructures that are valid targets for the search. -+ * -+ * @param configuredStructures a list of ConfiguredStructure targets -+ */ -+ public void setConfiguredStructures(@NotNull List configuredStructures) { -+ this.configuredStructures = new ArrayList<>(configuredStructures); -+ } -+ -+ /** -+ * Gets the search radius in which to attempt locating the structure. -+ *

      -+ * This radius may not always be obeyed during the structure search! -+ * -+ * @return the search radius. -+ */ -+ public int getRadius() { -+ return this.radius; -+ } -+ -+ /** -+ * Sets the search radius in which to attempt locating the structure. -+ *

      -+ * This radius may not always be obeyed during the structure search! -+ * -+ * @param radius the search radius. -+ */ -+ public void setRadius(int radius) { -+ this.radius = radius; -+ } -+ -+ /** -+ * Gets whether to search exclusively for unexplored structures. -+ *

      -+ * As with the search radius, this value is not always obeyed. -+ * -+ * @return Whether to search for only unexplored structures. -+ */ -+ public boolean shouldFindUnexplored() { -+ return this.findUnexplored; -+ } -+ -+ /** -+ * Sets whether to search exclusively for unexplored structures. -+ *

      -+ * As with the search radius, this value is not always obeyed. -+ * -+ * @param findUnexplored Whether to search for only unexplored structures. -+ */ -+ public void setFindUnexplored(boolean findUnexplored) { -+ this.findUnexplored = findUnexplored; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ public static @NotNull HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+ -+ /** -+ * Result for {@link StructuresLocateEvent}. -+ */ -+ public record Result(@NotNull Location position, @NotNull ConfiguredStructure configuredStructure) { -+ } -+} -diff --git a/src/main/java/io/papermc/paper/world/structure/ConfiguredStructure.java b/src/main/java/io/papermc/paper/world/structure/ConfiguredStructure.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5a43e40b7311ed2acb51f6ba8b12d1f34569ff2e ---- /dev/null -+++ b/src/main/java/io/papermc/paper/world/structure/ConfiguredStructure.java -@@ -0,0 +1,98 @@ -+package io.papermc.paper.world.structure; -+ -+import io.papermc.paper.registry.Reference; -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Registry; -+import org.bukkit.StructureType; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.Objects; -+ -+/** -+ * Represents a configured structure each with a -+ * {@link StructureType}. Multiple ConfiguredStructures can have -+ * the same {@link StructureType}. -+ */ -+public final class ConfiguredStructure implements Keyed { -+ -+ public static final Reference PILLAGER_OUTPOST = create("pillager_outpost"); -+ public static final Reference MINESHAFT = create("mineshaft"); -+ public static final Reference MINESHAFT_MESA = create("mineshaft_mesa"); -+ public static final Reference WOODLAND_MANSION = create("mansion"); -+ public static final Reference JUNGLE_TEMPLE = create("jungle_pyramid"); -+ public static final Reference DESERT_PYRAMID = create("desert_pyramid"); -+ public static final Reference IGLOO = create("igloo"); -+ public static final Reference SHIPWRECK = create("shipwreck"); -+ public static final Reference SHIPWRECK_BEACHED = create("shipwreck_beached"); -+ public static final Reference SWAMP_HUT = create("swamp_hut"); -+ public static final Reference STRONGHOLD = create("stronghold"); -+ public static final Reference OCEAN_MONUMENT = create("monument"); -+ public static final Reference OCEAN_RUIN_COLD = create("ocean_ruin_cold"); -+ public static final Reference OCEAN_RUIN_WARM = create("ocean_ruin_warm"); -+ public static final Reference FORTRESS = create("fortress"); -+ public static final Reference NETHER_FOSSIL = create("nether_fossil"); -+ public static final Reference END_CITY = create("end_city"); -+ public static final Reference BURIED_TREASURE = create("buried_treasure"); -+ public static final Reference BASTION_REMNANT = create("bastion_remnant"); -+ public static final Reference VILLAGE_PLAINS = create("village_plains"); -+ public static final Reference VILLAGE_DESERT = create("village_desert"); -+ public static final Reference VILLAGE_SAVANNA = create("village_savanna"); -+ public static final Reference VILLAGE_SNOWY = create("village_snowy"); -+ public static final Reference VILLAGE_TAIGA = create("village_taiga"); -+ public static final Reference RUINED_PORTAL_STANDARD = create("ruined_portal"); -+ public static final Reference RUINED_PORTAL_DESERT = create("ruined_portal_desert"); -+ public static final Reference RUINED_PORTAL_JUNGLE = create("ruined_portal_jungle"); -+ public static final Reference RUINED_PORTAL_SWAMP = create("ruined_portal_swamp"); -+ public static final Reference RUINED_PORTAL_MOUNTAIN = create("ruined_portal_mountain"); -+ public static final Reference RUINED_PORTAL_OCEAN = create("ruined_portal_ocean"); -+ public static final Reference RUINED_PORTAL_NETHER = create("ruined_portal_nether"); -+ // public static final Reference ANCIENT_CITY = create("ancient_city"); // TODO remove when upstream adds "jigsaw" StructureType -+ -+ private final NamespacedKey key; -+ private final StructureType structureType; -+ -+ ConfiguredStructure(@NotNull NamespacedKey key, @NotNull StructureType structureType) { -+ this.key = key; -+ this.structureType = structureType; -+ } -+ -+ @Override -+ public @NotNull NamespacedKey getKey() { -+ return this.key; -+ } -+ -+ /** -+ * Gets the structure type for this configure structure. -+ * -+ * @return the structure type -+ */ -+ public @NotNull StructureType getStructureType() { -+ return this.structureType; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (this == o) return true; -+ if (o == null || getClass() != o.getClass()) return false; -+ ConfiguredStructure structure = (ConfiguredStructure) o; -+ return this.key.equals(structure.key) && this.structureType.equals(structure.structureType); -+ } -+ -+ @Override -+ public int hashCode() { -+ return Objects.hash(this.key, this.structureType); -+ } -+ -+ @Override -+ public String toString() { -+ return "ConfiguredStructure{" + -+ "key=" + this.key + -+ ", structureType=" + this.structureType + -+ '}'; -+ } -+ -+ private static @NotNull Reference create(@NotNull String name) { -+ return Reference.create(Registry.CONFIGURED_STRUCTURE, NamespacedKey.minecraft(name)); -+ } -+} -diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java -index a77320257b691c3a380f7c59c350382c0c0fe863..ec59aa76488a1500ab3df46c98ba7b1d4179df4e 100644 ---- a/src/main/java/org/bukkit/Registry.java -+++ b/src/main/java/org/bukkit/Registry.java -@@ -210,6 +210,13 @@ public interface Registry extends Iterable { - return GameEvent.getByKey(key); - } - }; -+ // Paper start -+ /** -+ * Configured structures. -+ * @see io.papermc.paper.world.structure.ConfiguredStructure -+ */ -+ Registry CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); -+ // Paper end - - /** - * Get the object by its key. diff --git a/patches/api/0258-add-get-set-drop-chance-to-EntityEquipment.patch b/patches/api/0258-add-get-set-drop-chance-to-EntityEquipment.patch new file mode 100644 index 000000000000..45f3bf6ed5fa --- /dev/null +++ b/patches/api/0258-add-get-set-drop-chance-to-EntityEquipment.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 22 Apr 2021 00:28:20 -0700 +Subject: [PATCH] add get-set drop chance to EntityEquipment + + +diff --git a/src/main/java/org/bukkit/inventory/EntityEquipment.java b/src/main/java/org/bukkit/inventory/EntityEquipment.java +index 97c8b338f83f409a652fbaec5105e98b8af751e2..6a94bdba82e183b6509b4bff711dbbeed245a9ba 100644 +--- a/src/main/java/org/bukkit/inventory/EntityEquipment.java ++++ b/src/main/java/org/bukkit/inventory/EntityEquipment.java +@@ -527,4 +527,34 @@ public interface EntityEquipment { + */ + @NotNull // Paper + Entity getHolder(); ++ // Paper start ++ /** ++ * Gets the drop chance of specified slot. ++ * ++ *

        ++ *
      • A drop chance of 0.0F will never drop ++ *
      • A drop chance of 1.0F will always drop if killed by a player ++ *
      • A drop chance of greater than 1.0F will always drop if killed by anything ++ *
      ++ * ++ * @param slot the slot to get the drop chance of ++ * @return the drop chance for the slot ++ */ ++ float getDropChance(@NotNull EquipmentSlot slot); ++ ++ /** ++ * Sets the drop chance of the specified slot. ++ * ++ *
        ++ *
      • A drop chance of 0.0F will never drop ++ *
      • A drop chance of 1.0F will always drop if killed by a player ++ *
      • A drop chance of greater than 1.0F will always drop if killed by anything ++ *
      ++ * ++ * @param slot the slot to set the drop chance of ++ * @param chance the drop chance for the slot ++ * @throws UnsupportedOperationException when called on non-{@link Mob} entities ++ */ ++ void setDropChance(@NotNull EquipmentSlot slot, float chance); ++ // Paper end + } diff --git a/patches/api/0259-Added-PlayerDeepSleepEvent.patch b/patches/api/0259-Added-PlayerDeepSleepEvent.patch new file mode 100644 index 000000000000..73c3ea9004fa --- /dev/null +++ b/patches/api/0259-Added-PlayerDeepSleepEvent.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 21 Apr 2021 15:58:25 -0700 +Subject: [PATCH] Added PlayerDeepSleepEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerDeepSleepEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerDeepSleepEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2d4b15ded1e9aa00f21ca0b412e6b6ac333e5e02 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerDeepSleepEvent.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player has slept long enough ++ * to count as passing the night/storm. ++ *

      ++ * Cancelling this event will prevent the player from being counted as deeply sleeping ++ * unless they exit and re-enter the bed. ++ */ ++@NullMarked ++public class PlayerDeepSleepEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerDeepSleepEvent(final Player player) { ++ super(player); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0259-Return-chat-component-with-empty-text-instead-of-thr.patch b/patches/api/0259-Return-chat-component-with-empty-text-instead-of-thr.patch deleted file mode 100644 index ae5787045ff0..000000000000 --- a/patches/api/0259-Return-chat-component-with-empty-text-instead-of-thr.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: CDFN -Date: Tue, 7 Jul 2020 17:53:23 +0200 -Subject: [PATCH] Return chat component with empty text instead of throwing - exception - - -diff --git a/src/main/java/org/bukkit/inventory/InventoryView.java b/src/main/java/org/bukkit/inventory/InventoryView.java -index a4e3d526db2d17dc923cbe82e53d3c902d61e1f3..2448e70d75ae7a678c6befac4506c103edb78875 100644 ---- a/src/main/java/org/bukkit/inventory/InventoryView.java -+++ b/src/main/java/org/bukkit/inventory/InventoryView.java -@@ -450,7 +450,7 @@ public abstract class InventoryView { - /** - * Get the title of this inventory window. - * -- * @return The title. -+ * @return The title or empty string when title is {@code null}. - */ - @NotNull - public /*abstract*/ net.kyori.adventure.text.Component title() { diff --git a/patches/api/0260-Add-BlockPreDispenseEvent.patch b/patches/api/0260-Add-BlockPreDispenseEvent.patch deleted file mode 100644 index fb0b89a4ee80..000000000000 --- a/patches/api/0260-Add-BlockPreDispenseEvent.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Madeline Miller -Date: Sun, 17 Jan 2021 13:15:54 +1000 -Subject: [PATCH] Add BlockPreDispenseEvent - - -diff --git a/src/main/java/io/papermc/paper/event/block/BlockPreDispenseEvent.java b/src/main/java/io/papermc/paper/event/block/BlockPreDispenseEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..07aad3f4ff60a6a6de69634b0d31926e9c00e77b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/BlockPreDispenseEvent.java -@@ -0,0 +1,60 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+public class BlockPreDispenseEvent extends BlockEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled = false; -+ private final ItemStack itemStack; -+ private final int slot; -+ -+ public BlockPreDispenseEvent(@NotNull Block block, @NotNull ItemStack itemStack, int slot) { -+ super(block); -+ this.itemStack = itemStack; -+ this.slot = slot; -+ } -+ -+ /** -+ * Gets the {@link ItemStack} to be dispensed. -+ * -+ * @return The item to be dispensed -+ */ -+ @NotNull -+ public ItemStack getItemStack() { -+ return itemStack; -+ } -+ -+ /** -+ * Gets the inventory slot of the dispenser to dispense from. -+ * -+ * @return The inventory slot -+ */ -+ public int getSlot() { -+ return slot; -+ } -+ -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+} diff --git a/patches/api/0260-More-World-API.patch b/patches/api/0260-More-World-API.patch new file mode 100644 index 000000000000..7efbed6e0240 --- /dev/null +++ b/patches/api/0260-More-World-API.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 7 Jul 2020 10:53:22 -0700 +Subject: [PATCH] More World API + + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 85900b9f41379d9c8366ae9f2f9e94f54f504ffb..8084bb2d8f3983e10de9123b74627ed04d8b5255 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -3848,6 +3848,72 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @Nullable + StructureSearchResult locateNearestStructure(@NotNull Location origin, @NotNull Structure structure, int radius, boolean findUnexplored); + ++ // Paper start ++ /** ++ * Locates the nearest biome based on an origin, biome type, and radius to search. ++ * Step defaults to {@code 8}. ++ * ++ * @param origin Origin location ++ * @param biome Biome to find ++ * @param radius radius to search ++ * @return Location of biome or null if not found in specified radius ++ * @deprecated use {@link #locateNearestBiome(Location, int, Biome...)} ++ */ ++ @Deprecated ++ @Nullable ++ default Location locateNearestBiome(@NotNull Location origin, @NotNull Biome biome, int radius) { ++ return java.util.Optional.ofNullable(this.locateNearestBiome(origin, radius, 8, 8, biome)).map(BiomeSearchResult::getLocation).orElse(null); ++ } ++ ++ /** ++ * Locates the nearest biome based on an origin, biome type, and radius to search ++ * and step ++ * ++ * @param origin Origin location ++ * @param biome Biome to find ++ * @param radius radius to search ++ * @param step Search step 1 would mean checking every block, 8 would be every 8th block ++ * @return Location of biome or null if not found in specified radius ++ * @deprecated use {@link #locateNearestBiome(Location, int, int, int, Biome...)} ++ */ ++ @Deprecated ++ @Nullable ++ default Location locateNearestBiome(@NotNull Location origin, @NotNull Biome biome, int radius, int step) { ++ return java.util.Optional.ofNullable(this.locateNearestBiome(origin, radius, step, step, biome)).map(BiomeSearchResult::getLocation).orElse(null); ++ } ++ ++ /** ++ * Gets the coordinate scaling of this world. ++ * ++ * @return the coordinate scale ++ */ ++ double getCoordinateScale(); ++ ++ /** ++ * Checks if this world has a fixed time ++ * ++ * @return whether this world has fixed time ++ */ ++ boolean isFixedTime(); ++ ++ /** ++ * Gets the collection of materials that burn infinitely in this world. ++ * ++ * @return the materials that will forever stay lit by fire ++ */ ++ @NotNull ++ Collection getInfiniburn(); ++ ++ /** ++ * Posts a specified game event at a location ++ * ++ * @param sourceEntity optional source entity ++ * @param gameEvent the game event to post ++ * @param position the position in the world where to post the event to listeners ++ */ ++ void sendGameEvent(@Nullable Entity sourceEntity, @NotNull GameEvent gameEvent, @NotNull Vector position); ++ // Paper end ++ + // Spigot start + @Deprecated(forRemoval = true) // Paper + public class Spigot { diff --git a/patches/api/0261-Added-PlayerBedFailEnterEvent.patch b/patches/api/0261-Added-PlayerBedFailEnterEvent.patch new file mode 100644 index 000000000000..c324a7202bfd --- /dev/null +++ b/patches/api/0261-Added-PlayerBedFailEnterEvent.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 24 Dec 2020 12:27:49 -0800 +Subject: [PATCH] Added PlayerBedFailEnterEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerBedFailEnterEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerBedFailEnterEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..393d127463a6b396f6bd953f538828da23572f33 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerBedFailEnterEvent.java +@@ -0,0 +1,115 @@ ++package io.papermc.paper.event.player; ++ ++import net.kyori.adventure.text.Component; ++import org.bukkit.block.Block; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@NullMarked ++public class PlayerBedFailEnterEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final FailReason failReason; ++ private final Block bed; ++ private boolean willExplode; ++ private @Nullable Component message; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerBedFailEnterEvent(final Player player, final FailReason failReason, final Block bed, final boolean willExplode, final @Nullable Component message) { ++ super(player); ++ this.failReason = failReason; ++ this.bed = bed; ++ this.willExplode = willExplode; ++ this.message = message; ++ } ++ ++ public FailReason getFailReason() { ++ return this.failReason; ++ } ++ ++ public Block getBed() { ++ return this.bed; ++ } ++ ++ public boolean getWillExplode() { ++ return this.willExplode; ++ } ++ ++ public void setWillExplode(final boolean willExplode) { ++ this.willExplode = willExplode; ++ } ++ ++ public @Nullable Component getMessage() { ++ return this.message; ++ } ++ ++ public void setMessage(final @Nullable Component message) { ++ this.message = message; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * NOTE: This does not cancel the player getting in the bed, but any messages/explosions ++ * that may occur because of the interaction. ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum FailReason { ++ /** ++ * The world doesn't allow sleeping (ex. Nether or The End). Entering ++ * the bed is prevented and the bed explodes. ++ */ ++ NOT_POSSIBLE_HERE, ++ /** ++ * Entering the bed is prevented due to it not being night nor ++ * thundering currently. ++ *

      ++ * If the event is forcefully allowed during daytime, the player will ++ * enter the bed (and set its bed location), but might get immediately ++ * thrown out again. ++ */ ++ NOT_POSSIBLE_NOW, ++ /** ++ * Entering the bed is prevented due to the player being too far away. ++ */ ++ TOO_FAR_AWAY, ++ /** ++ * Bed is obstructed. ++ */ ++ OBSTRUCTED, ++ /** ++ * Entering the bed is prevented due to there being some other problem. ++ */ ++ OTHER_PROBLEM, ++ /** ++ * Entering the bed is prevented due to there being monsters nearby. ++ */ ++ NOT_SAFE ++ } ++} diff --git a/patches/api/0261-Added-Vanilla-Entity-Tags.patch b/patches/api/0261-Added-Vanilla-Entity-Tags.patch deleted file mode 100644 index 42d3ec287568..000000000000 --- a/patches/api/0261-Added-Vanilla-Entity-Tags.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 3 Jan 2021 20:03:40 -0800 -Subject: [PATCH] Added Vanilla Entity Tags - - -diff --git a/src/main/java/org/bukkit/Tag.java b/src/main/java/org/bukkit/Tag.java -index 33f022a01e44e6b806e6d38eef003da161b6be53..9694b862d62afbaa831735a6f6d095315bcdf37c 100644 ---- a/src/main/java/org/bukkit/Tag.java -+++ b/src/main/java/org/bukkit/Tag.java -@@ -811,6 +811,44 @@ public interface Tag extends Keyed { - * Vanilla tag representing entities which can be eaten by frogs. - */ - Tag ENTITY_TYPES_FROG_FOOD = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("frog_food"), EntityType.class); -+ // Paper start -+ /** -+ * Key for the built-in entity registry -+ * @deprecated use {@link #REGISTRY_ENTITY_TYPES} -+ */ -+ @Deprecated(forRemoval = true) -+ String REGISTRY_ENTITIES = REGISTRY_ENTITY_TYPES; -+ /** -+ * Vanilla entity tag representing arrow entities. -+ * @deprecated use {@link #ENTITY_TYPES_ARROWS} -+ */ -+ @Deprecated(forRemoval = true) -+ Tag ARROWS = ENTITY_TYPES_ARROWS; -+ /** -+ * Vanilla entity tag representing entities that live in beehives -+ * @deprecated use {@link #ENTITY_TYPES_BEEHIVE_INHABITORS} -+ */ -+ @Deprecated(forRemoval = true) -+ Tag BEEHIVE_INHABITORS = ENTITY_TYPES_BEEHIVE_INHABITORS; -+ /** -+ * Vanilla entity tag representing projectiles that impact -+ * @deprecated use {@link #ENTITY_TYPES_IMPACT_PROJECTILES} -+ */ -+ @Deprecated(forRemoval = true) -+ Tag IMPACT_PROJECTILES = ENTITY_TYPES_IMPACT_PROJECTILES; -+ /** -+ * Vanilla entity tag for village raiders -+ * @deprecated use {@link #ENTITY_TYPES_RAIDERS} -+ */ -+ @Deprecated(forRemoval = true) -+ Tag RAIDERS = ENTITY_TYPES_RAIDERS; -+ /** -+ * Vanilla entity tag for skeleton types -+ * @deprecated use {@link #ENTITY_TYPES_SKELETONS} -+ */ -+ @Deprecated(forRemoval = true) -+ Tag SKELETONS = ENTITY_TYPES_SKELETONS; -+ // Paper end - - /** - * Returns whether or not this tag has an entry for the specified item. diff --git a/patches/api/0262-Added-PlayerChangeBeaconEffectEvent.patch b/patches/api/0262-Added-PlayerChangeBeaconEffectEvent.patch deleted file mode 100644 index 4331e880bb9a..000000000000 --- a/patches/api/0262-Added-PlayerChangeBeaconEffectEvent.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 24 Jun 2020 15:12:18 -0600 -Subject: [PATCH] Added PlayerChangeBeaconEffectEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerChangeBeaconEffectEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerChangeBeaconEffectEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c80183a79713b1e73549911e474a8c585cfdeb52 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerChangeBeaconEffectEvent.java -@@ -0,0 +1,141 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.block.Block; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.potion.PotionEffectType; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when a player sets the effect for a beacon -+ */ -+public class PlayerChangeBeaconEffectEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ private PotionEffectType primary; -+ private PotionEffectType secondary; -+ private final Block beacon; -+ private boolean consumeItem = true; -+ -+ private boolean isCancelled; -+ -+ public PlayerChangeBeaconEffectEvent(@NotNull Player player, @Nullable PotionEffectType primary, @Nullable PotionEffectType secondary, @Nullable Block beacon) { -+ super(player); -+ this.primary = primary; -+ this.secondary = secondary; -+ this.isCancelled = false; -+ this.beacon = beacon; -+ } -+ -+ /** -+ * @return the primary effect -+ */ -+ @Nullable public PotionEffectType getPrimary() { -+ return primary; -+ } -+ -+ /** -+ * Sets the primary effect -+ *

      -+ * NOTE: The primary effect still has to be one of the valid effects for a beacon. -+ * -+ * @param primary the primary effect -+ */ -+ public void setPrimary(@Nullable PotionEffectType primary) { -+ this.primary = primary; -+ } -+ -+ /** -+ * @return the secondary effect -+ */ -+ @Nullable public PotionEffectType getSecondary() { -+ return secondary; -+ } -+ -+ /** -+ * Sets the secondary effect -+ *

      -+ * This only has an effect when the beacon is able to accept a secondary effect. -+ * NOTE: The secondary effect still has to be a valid effect for a beacon. -+ * -+ * @param secondary the secondary effect -+ */ -+ public void setSecondary(@Nullable PotionEffectType secondary) { -+ this.secondary = secondary; -+ } -+ -+ /** -+ * @return the beacon block associated with this event, or null if not found -+ */ -+ @Nullable -+ public Block getBeacon() { -+ return beacon; -+ } -+ -+ /** -+ * Gets if the item used to change the beacon will be consume. -+ *

      -+ * Independant of {@link #isCancelled()}. If the event is cancelled -+ * the item will NOT be consumed. -+ * -+ * @return true if item will be consumed -+ */ -+ public boolean willConsumeItem() { -+ return consumeItem; -+ } -+ -+ /** -+ * Sets if the item used to change the beacon should be consumed. -+ *

      -+ * Independant of {@link #isCancelled()}. If the event is cancelled -+ * the item will NOT be consumed. -+ * -+ * @param consumeItem true if item should be consumed -+ */ -+ public void setConsumeItem(boolean consumeItem) { -+ this.consumeItem = consumeItem; -+ } -+ -+ /** -+ * Gets the cancellation state of this event. A cancelled event will not -+ * be executed in the server, but will still pass to other plugins -+ *

      -+ * If a {@link PlayerChangeBeaconEffectEvent} is cancelled, the changes will -+ * not take effect -+ * -+ * @return true if this event is cancelled -+ */ -+ @Override -+ public boolean isCancelled() { -+ return this.isCancelled; -+ } -+ -+ /** -+ * Sets the cancellation state of this event. A cancelled event will not -+ * be executed in the server, but will still pass to other plugins -+ *

      -+ * If cancelled, the item will NOT be consumed regardless of what {@link #willConsumeItem()} says -+ *

      -+ * If a {@link PlayerChangeBeaconEffectEvent} is cancelled, the changes will not be applied -+ * or saved. -+ * -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.isCancelled = cancel; -+ } -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0262-Introduce-beacon-activation-deactivation-events.patch b/patches/api/0262-Introduce-beacon-activation-deactivation-events.patch new file mode 100644 index 000000000000..a108599dc99c --- /dev/null +++ b/patches/api/0262-Introduce-beacon-activation-deactivation-events.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spyridon Pagkalos +Date: Thu, 25 Mar 2021 20:25:47 +0200 +Subject: [PATCH] Introduce beacon activation/deactivation events + + +diff --git a/src/main/java/io/papermc/paper/event/block/BeaconActivatedEvent.java b/src/main/java/io/papermc/paper/event/block/BeaconActivatedEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..380538656e675fdfaf9077da8ff48dc5c427a657 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BeaconActivatedEvent.java +@@ -0,0 +1,41 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.block.Beacon; ++import org.bukkit.block.Block; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a beacon is activated. ++ * Activation occurs when the beacon beam becomes visible. ++ */ ++@NullMarked ++public class BeaconActivatedEvent extends BlockEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ @ApiStatus.Internal ++ public BeaconActivatedEvent(final Block block) { ++ super(block); ++ } ++ ++ /** ++ * Returns the beacon that was activated. ++ * ++ * @return the beacon that was activated. ++ */ ++ public Beacon getBeacon() { ++ return (Beacon) this.block.getState(); ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/block/BeaconDeactivatedEvent.java b/src/main/java/io/papermc/paper/event/block/BeaconDeactivatedEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4e5b2b2413e2aae03132ecd76123cd93dfbd77ce +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BeaconDeactivatedEvent.java +@@ -0,0 +1,44 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.Material; ++import org.bukkit.block.Beacon; ++import org.bukkit.block.Block; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when a beacon is deactivated, either because its base block(s) or itself were destroyed. ++ */ ++@NullMarked ++public class BeaconDeactivatedEvent extends BlockEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ @ApiStatus.Internal ++ public BeaconDeactivatedEvent(final Block block) { ++ super(block); ++ } ++ ++ /** ++ * Returns the beacon that was deactivated. ++ * This will return {@code null} if the beacon does not exist. ++ * (which can occur after the deactivation of a now broken beacon) ++ * ++ * @return The beacon that got deactivated, or {@code null} if it does not exist. ++ */ ++ public @Nullable Beacon getBeacon() { ++ return this.block.getType() == Material.BEACON ? (Beacon) this.block.getState() : null; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0263-Added-PlayerStonecutterRecipeSelectEvent.patch b/patches/api/0263-Added-PlayerStonecutterRecipeSelectEvent.patch deleted file mode 100644 index ce446c46fe27..000000000000 --- a/patches/api/0263-Added-PlayerStonecutterRecipeSelectEvent.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 27 Nov 2020 17:13:59 -0800 -Subject: [PATCH] Added PlayerStonecutterRecipeSelectEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerStonecutterRecipeSelectEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerStonecutterRecipeSelectEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fb1bca3a9d12096c9a2b2663f466a8ff5f2b4319 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerStonecutterRecipeSelectEvent.java -@@ -0,0 +1,59 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.StonecutterInventory; -+import org.bukkit.inventory.StonecuttingRecipe; -+import org.jetbrains.annotations.NotNull; -+ -+public class PlayerStonecutterRecipeSelectEvent extends PlayerEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private boolean cancelled; -+ private final StonecutterInventory stonecutterInventory; -+ private StonecuttingRecipe stonecuttingRecipe; -+ -+ public PlayerStonecutterRecipeSelectEvent(@NotNull Player player, @NotNull StonecutterInventory stonecutterInventory, @NotNull StonecuttingRecipe stonecuttingRecipe) { -+ super(player); -+ this.stonecutterInventory = stonecutterInventory; -+ this.stonecuttingRecipe = stonecuttingRecipe; -+ } -+ -+ @NotNull -+ public StonecutterInventory getStonecutterInventory() { -+ return stonecutterInventory; -+ } -+ -+ @NotNull -+ public StonecuttingRecipe getStonecuttingRecipe() { -+ return stonecuttingRecipe; -+ } -+ -+ public void setStonecuttingRecipe(@NotNull StonecuttingRecipe stonecuttingRecipe) { -+ this.stonecuttingRecipe = stonecuttingRecipe; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} diff --git a/patches/api/0288-PlayerMoveEvent-Improvements.patch b/patches/api/0263-PlayerMoveEvent-Improvements.patch similarity index 100% rename from patches/api/0288-PlayerMoveEvent-Improvements.patch rename to patches/api/0263-PlayerMoveEvent-Improvements.patch diff --git a/patches/api/0264-Add-dropLeash-variable-to-EntityUnleashEvent.patch b/patches/api/0264-Add-dropLeash-variable-to-EntityUnleashEvent.patch deleted file mode 100644 index 75aa7581402e..000000000000 --- a/patches/api/0264-Add-dropLeash-variable-to-EntityUnleashEvent.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Fri, 29 Jan 2021 15:13:04 +0100 -Subject: [PATCH] Add dropLeash variable to EntityUnleashEvent - - -diff --git a/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java b/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java -index a33986a0c437a673435206fc337031a7eebdab3b..e0e068799a1868c8e561869015f41f553ef4fbdb 100644 ---- a/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java -+++ b/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java -@@ -10,10 +10,19 @@ import org.jetbrains.annotations.NotNull; - public class EntityUnleashEvent extends EntityEvent { - private static final HandlerList handlers = new HandlerList(); - private final UnleashReason reason; -+ private boolean dropLeash; // Paper - -+ // Paper start - drop leash variable -+ @Deprecated - public EntityUnleashEvent(@NotNull Entity entity, @NotNull UnleashReason reason) { -+ this(entity, reason, false); -+ } -+ -+ public EntityUnleashEvent(@NotNull Entity entity, @NotNull UnleashReason reason, boolean dropLeash) { - super(entity); -+ // Paper end - this.reason = reason; -+ this.dropLeash = dropLeash; // Paper - } - - /** -@@ -26,6 +35,26 @@ public class EntityUnleashEvent extends EntityEvent { - return reason; - } - -+ // Paper start -+ /** -+ * Returns whether a leash item will be dropped. -+ * -+ * @return Whether the leash item will be dropped -+ */ -+ public boolean isDropLeash() { -+ return dropLeash; -+ } -+ -+ /** -+ * Sets whether a leash item should be dropped. -+ * -+ * @param dropLeash Whether the leash item should be dropped -+ */ -+ public void setDropLeash(boolean dropLeash) { -+ this.dropLeash = dropLeash; -+ } -+ // Paper end -+ - @NotNull - @Override - public HandlerList getHandlers() { -diff --git a/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java b/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java -index cf78950b56d4977f6c4d9d98d183bfc5ba3bacc0..68eab1563caba1ee4f52b308f390e4e172667fc5 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java -@@ -13,8 +13,15 @@ public class PlayerUnleashEntityEvent extends EntityUnleashEvent implements Canc - private final Player player; - private boolean cancelled = false; - -+ // Paper start - drop leash variable -+ @Deprecated - public PlayerUnleashEntityEvent(@NotNull Entity entity, @NotNull Player player) { -- super(entity, UnleashReason.PLAYER_UNLEASH); -+ this(entity, player, false); -+ } -+ -+ public PlayerUnleashEntityEvent(@NotNull Entity entity, @NotNull Player player, boolean dropLeash) { -+ super(entity, UnleashReason.PLAYER_UNLEASH, dropLeash); -+ // Paper end - this.player = player; - } - diff --git a/patches/api/0264-add-RespawnFlags-to-PlayerRespawnEvent.patch b/patches/api/0264-add-RespawnFlags-to-PlayerRespawnEvent.patch new file mode 100644 index 000000000000..c849e73f5666 --- /dev/null +++ b/patches/api/0264-add-RespawnFlags-to-PlayerRespawnEvent.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 22 Apr 2021 17:17:54 -0700 +Subject: [PATCH] add RespawnFlags to PlayerRespawnEvent + + +diff --git a/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java +index 7e765886179b08d6b2edb5319aeacc9e7db5b8c2..4d925774f75e8982a8141a28de71e568834e1433 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java +@@ -18,6 +18,7 @@ public class PlayerRespawnEvent extends PlayerEvent { + private final boolean isBedSpawn; + private final boolean isAnchorSpawn; + private final RespawnReason respawnReason; ++ private final java.util.Set respawnFlags; // Paper + + @Deprecated(since = "1.16.1") + public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn) { +@@ -29,12 +30,24 @@ public class PlayerRespawnEvent extends PlayerEvent { + this(respawnPlayer, respawnLocation, isBedSpawn, false, RespawnReason.PLUGIN); + } + ++ @Deprecated // Paper + public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn, final boolean isAnchorSpawn, @NotNull final RespawnReason respawnReason) { ++ // Paper start ++ this(respawnPlayer, respawnLocation, isBedSpawn, isAnchorSpawn, respawnReason, com.google.common.collect.ImmutableSet.builder()); ++ } ++ ++ public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn, final boolean isAnchorSpawn, @NotNull final RespawnReason respawnReason, @NotNull final com.google.common.collect.ImmutableSet.Builder respawnFlags) { ++ // Paper end + super(respawnPlayer); + this.respawnLocation = respawnLocation; + this.isBedSpawn = isBedSpawn; + this.isAnchorSpawn = isAnchorSpawn; + this.respawnReason = respawnReason; ++ // Paper start ++ if (this.isBedSpawn) { respawnFlags.add(RespawnFlag.BED_SPAWN); } ++ if (this.isAnchorSpawn) { respawnFlags.add(RespawnFlag.ANCHOR_SPAWN); } ++ this.respawnFlags = respawnFlags.build(); ++ // Paper end + } + + /** +@@ -116,4 +129,31 @@ public class PlayerRespawnEvent extends PlayerEvent { + */ + PLUGIN; + } ++ ++ // Paper start ++ /** ++ * Get the set of flags that apply to this respawn. ++ * ++ * @return an immutable set of the flags that apply to this respawn ++ */ ++ @NotNull ++ public java.util.Set getRespawnFlags() { ++ return respawnFlags; ++ } ++ ++ public enum RespawnFlag { ++ /** ++ * Will use the bed spawn location ++ */ ++ BED_SPAWN, ++ /** ++ * Will use the respawn anchor location ++ */ ++ ANCHOR_SPAWN, ++ /** ++ * Is caused by going to the end portal in the end. ++ */ ++ END_PORTAL, ++ } ++ // Paper end + } diff --git a/patches/api/0290-Add-more-WanderingTrader-API.patch b/patches/api/0265-Add-more-WanderingTrader-API.patch similarity index 100% rename from patches/api/0290-Add-more-WanderingTrader-API.patch rename to patches/api/0265-Add-more-WanderingTrader-API.patch diff --git a/patches/api/0265-add-DragonEggFormEvent.patch b/patches/api/0265-add-DragonEggFormEvent.patch deleted file mode 100644 index c465295e880b..000000000000 --- a/patches/api/0265-add-DragonEggFormEvent.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trigary -Date: Mon, 25 Jan 2021 14:53:49 +0100 -Subject: [PATCH] add DragonEggFormEvent - - -diff --git a/src/main/java/io/papermc/paper/event/block/DragonEggFormEvent.java b/src/main/java/io/papermc/paper/event/block/DragonEggFormEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5495b87330518363498e1ac5d8f0a832be35fefb ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/DragonEggFormEvent.java -@@ -0,0 +1,63 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.Material; -+import org.bukkit.block.Block; -+import org.bukkit.block.BlockState; -+import org.bukkit.boss.DragonBattle; -+import org.bukkit.entity.EnderDragon; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockFormEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when the {@link EnderDragon} is defeated (killed) in a {@link DragonBattle}, -+ * causing a {@link Material#DRAGON_EGG} (more formally: {@link #getNewState()}) -+ * to possibly appear depending on {@link #isCancelled()}. -+ * This event might be cancelled by default depending on -+ * eg. {@link DragonBattle#hasBeenPreviouslyKilled()} and server configuration. -+ */ -+public class DragonEggFormEvent extends BlockFormEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private final DragonBattle dragonBattle; -+ private boolean cancelled; -+ -+ public DragonEggFormEvent(@NotNull Block block, @NotNull BlockState newState, -+ @NotNull DragonBattle dragonBattle) { -+ super(block, newState); -+ this.dragonBattle = dragonBattle; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancelled) { -+ this.cancelled = cancelled; -+ } -+ -+ /** -+ * Gets the {@link DragonBattle} associated with this event. -+ * Keep in mind that the {@link EnderDragon} is already dead -+ * when this event is called. -+ * -+ * @return the dragon battle -+ */ -+ @NotNull -+ public DragonBattle getDragonBattle() { -+ return dragonBattle; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0291-Add-EntityBlockStorage-clearEntities.patch b/patches/api/0266-Add-EntityBlockStorage-clearEntities.patch similarity index 100% rename from patches/api/0291-Add-EntityBlockStorage-clearEntities.patch rename to patches/api/0266-Add-EntityBlockStorage-clearEntities.patch diff --git a/patches/api/0266-EntityMoveEvent.patch b/patches/api/0266-EntityMoveEvent.patch deleted file mode 100644 index 2855c3bdef88..000000000000 --- a/patches/api/0266-EntityMoveEvent.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 11 Feb 2020 21:56:38 -0600 -Subject: [PATCH] EntityMoveEvent - - -diff --git a/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..245d56ba7e8e37e3555b606f5e85fc663897f62b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java -@@ -0,0 +1,143 @@ -+package io.papermc.paper.event.entity; -+ -+import com.google.common.base.Preconditions; -+import org.bukkit.Location; -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.event.player.PlayerMoveEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Holds information for living entity movement events -+ *

      -+ * Does not fire for players; use {@link PlayerMoveEvent} for player movement. -+ */ -+public class EntityMoveEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean canceled; -+ private Location from; -+ private Location to; -+ -+ public EntityMoveEvent(@NotNull LivingEntity entity, @NotNull Location from, @NotNull Location to) { -+ super(entity); -+ this.from = from; -+ this.to = to; -+ } -+ -+ @Override -+ @NotNull -+ public LivingEntity getEntity() { -+ return (LivingEntity) entity; -+ } -+ -+ public boolean isCancelled() { -+ return canceled; -+ } -+ -+ public void setCancelled(boolean cancel) { -+ canceled = cancel; -+ } -+ -+ /** -+ * Gets the location this entity moved from -+ * -+ * @return Location the entity moved from -+ */ -+ @NotNull -+ public Location getFrom() { -+ return from; -+ } -+ -+ /** -+ * Sets the location to mark as where the entity moved from -+ * -+ * @param from New location to mark as the entity's previous location -+ */ -+ public void setFrom(@NotNull Location from) { -+ validateLocation(from); -+ this.from = from; -+ } -+ -+ /** -+ * Gets the location this entity moved to -+ * -+ * @return Location the entity moved to -+ */ -+ @NotNull -+ public Location getTo() { -+ return to; -+ } -+ -+ /** -+ * Sets the location that this entity will move to -+ * -+ * @param to New Location this entity will move to -+ */ -+ public void setTo(@NotNull Location to) { -+ validateLocation(to); -+ this.to = to; -+ } -+ -+ /** -+ * Check if the entity has changed position (even within the same block) in the event -+ * -+ * @return whether the entity has changed position or not -+ */ -+ public boolean hasChangedPosition() { -+ return hasExplicitlyChangedPosition() || !from.getWorld().equals(to.getWorld()); -+ } -+ -+ /** -+ * Check if the entity has changed position (even within the same block) in the event, disregarding a possible world change -+ * -+ * @return whether the entity has changed position or not -+ */ -+ public boolean hasExplicitlyChangedPosition() { -+ return from.getX() != to.getX() || from.getY() != to.getY() || from.getZ() != to.getZ(); -+ } -+ -+ /** -+ * Check if the entity has moved to a new block in the event -+ * -+ * @return whether the entity has moved to a new block or not -+ */ -+ public boolean hasChangedBlock() { -+ return hasExplicitlyChangedBlock() || !from.getWorld().equals(to.getWorld()); -+ } -+ -+ /** -+ * Check if the entity has moved to a new block in the event, disregarding a possible world change -+ * -+ * @return whether the entity has moved to a new block or not -+ */ -+ public boolean hasExplicitlyChangedBlock() { -+ return from.getBlockX() != to.getBlockX() || from.getBlockY() != to.getBlockY() || from.getBlockZ() != to.getBlockZ(); -+ } -+ -+ /** -+ * Check if the entity has changed orientation in the event -+ * -+ * @return whether the entity has changed orientation or not -+ */ -+ public boolean hasChangedOrientation() { -+ return from.getPitch() != to.getPitch() || from.getYaw() != to.getYaw(); -+ } -+ -+ private void validateLocation(@NotNull Location loc) { -+ Preconditions.checkArgument(loc != null, "Cannot use null location!"); -+ Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!"); -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0292-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch b/patches/api/0267-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch similarity index 100% rename from patches/api/0292-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch rename to patches/api/0267-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch diff --git a/patches/api/0267-Allow-adding-items-to-BlockDropItemEvent.patch b/patches/api/0267-Allow-adding-items-to-BlockDropItemEvent.patch deleted file mode 100644 index 984da00f52a2..000000000000 --- a/patches/api/0267-Allow-adding-items-to-BlockDropItemEvent.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Wed, 20 Jan 2021 14:25:26 -0600 -Subject: [PATCH] Allow adding items to BlockDropItemEvent - - -diff --git a/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java b/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java -index a0f6f1af304190b4c5db4b284d460f625eeb7801..3dd4bd38e72c04e74e5787fb38ca9abd10bad06b 100644 ---- a/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java -+++ b/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java -@@ -64,7 +64,7 @@ public class BlockDropItemEvent extends BlockEvent implements Cancellable { - * Gets list of the Item drops caused by the block break. - * - * This list is mutable - removing an item from it will cause it to not -- * drop. It is not legal however to add new items to the list. -+ * drop. Adding to the list is allowed. - * - * @return The Item the block caused to drop - */ diff --git a/patches/api/0268-Add-getMainThreadExecutor-to-BukkitScheduler.patch b/patches/api/0268-Add-getMainThreadExecutor-to-BukkitScheduler.patch deleted file mode 100644 index bbb81fdcf6a2..000000000000 --- a/patches/api/0268-Add-getMainThreadExecutor-to-BukkitScheduler.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aleksander Jagiello -Date: Sun, 24 Jan 2021 22:17:29 +0100 -Subject: [PATCH] Add getMainThreadExecutor to BukkitScheduler - - -diff --git a/src/main/java/org/bukkit/scheduler/BukkitScheduler.java b/src/main/java/org/bukkit/scheduler/BukkitScheduler.java -index 5aefb7f2de890673aea275e85dbae9a2422b59b1..d2ab2ee1e1e8fbaac4edef5b3ee313ee4ceb6991 100644 ---- a/src/main/java/org/bukkit/scheduler/BukkitScheduler.java -+++ b/src/main/java/org/bukkit/scheduler/BukkitScheduler.java -@@ -457,4 +457,15 @@ public interface BukkitScheduler { - @Deprecated - @NotNull - public BukkitTask runTaskTimerAsynchronously(@NotNull Plugin plugin, @NotNull BukkitRunnable task, long delay, long period) throws IllegalArgumentException; -+ -+ // Paper start - add getMainThreadExecutor -+ /** -+ * Returns an executor that will run tasks on the next server tick. -+ * -+ * @param plugin the reference to the plugin scheduling tasks -+ * @return an executor associated with the given plugin -+ */ -+ @NotNull -+ public java.util.concurrent.Executor getMainThreadExecutor(@NotNull Plugin plugin); -+ // Paper end - } diff --git a/patches/api/0268-Inventory-close.patch b/patches/api/0268-Inventory-close.patch new file mode 100644 index 000000000000..87dfa1a0832a --- /dev/null +++ b/patches/api/0268-Inventory-close.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 11 May 2021 14:54:20 -0700 +Subject: [PATCH] Inventory#close + + +diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/org/bukkit/inventory/Inventory.java +index 129b5ab5062beeb9bb52465a788bc3a3aee9c49e..0d519813c12d98b28d62e6d01d7ec6e8c2dba3c3 100644 +--- a/src/main/java/org/bukkit/inventory/Inventory.java ++++ b/src/main/java/org/bukkit/inventory/Inventory.java +@@ -355,6 +355,15 @@ public interface Inventory extends Iterable { + */ + public void clear(); + ++ // Paper start ++ /** ++ * Closes the inventory for all viewers. ++ * ++ * @return the number of viewers the inventory was closed for ++ */ ++ public int close(); ++ // Paper end ++ + /** + * Gets a list of players viewing the inventory. Note that a player is + * considered to be viewing their own inventory and internal crafting diff --git a/patches/api/0269-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch b/patches/api/0269-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch new file mode 100644 index 000000000000..12888ca2f414 --- /dev/null +++ b/patches/api/0269-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MeFisto94 +Date: Tue, 11 May 2021 00:48:51 +0200 +Subject: [PATCH] Add a "should burn in sunlight" API for Phantoms and + Skeletons + + +diff --git a/src/main/java/org/bukkit/entity/AbstractSkeleton.java b/src/main/java/org/bukkit/entity/AbstractSkeleton.java +index 2d81d077015fff47c5a5b64e2e1c74f962b4ceee..db101017a0d25910632dcbdf80b3724c3b2cf65b 100644 +--- a/src/main/java/org/bukkit/entity/AbstractSkeleton.java ++++ b/src/main/java/org/bukkit/entity/AbstractSkeleton.java +@@ -32,4 +32,24 @@ public interface AbstractSkeleton extends Monster, com.destroystokyo.paper.entit + @Deprecated(since = "1.17") + @Contract("_ -> fail") + public void setSkeletonType(Skeleton.SkeletonType type); ++ ++ // Paper start ++ /** ++ * Check if this skeleton will burn in the sunlight. This ++ * does not take into account an entity's natural fire ++ * immunity. ++ * ++ * @return True if skeleton will burn in sunlight ++ */ ++ boolean shouldBurnInDay(); ++ ++ /** ++ * Set if this skeleton should burn in the sunlight. This ++ * will not override an entity's natural fire ++ * immunity. ++ * ++ * @param shouldBurnInDay True to burn in sunlight ++ */ ++ void setShouldBurnInDay(boolean shouldBurnInDay); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Phantom.java b/src/main/java/org/bukkit/entity/Phantom.java +index 082601f349ae2cebbffd1012c19c521241696a09..3dafdf14ced991ae1179ef1ca455da62f8c3243e 100644 +--- a/src/main/java/org/bukkit/entity/Phantom.java ++++ b/src/main/java/org/bukkit/entity/Phantom.java +@@ -26,5 +26,19 @@ public interface Phantom extends Flying, Enemy { + */ + @Nullable + public java.util.UUID getSpawningEntity(); ++ ++ /** ++ * Check if this phantom will burn in the sunlight ++ * ++ * @return True if phantom will burn in sunlight ++ */ ++ public boolean shouldBurnInDay(); ++ ++ /** ++ * Set if this phantom should burn in the sunlight ++ * ++ * @param shouldBurnInDay True to burn in sunlight ++ */ ++ public void setShouldBurnInDay(boolean shouldBurnInDay); + // Paper end + } diff --git a/patches/api/0270-Add-basic-Datapack-API.patch b/patches/api/0270-Add-basic-Datapack-API.patch new file mode 100644 index 000000000000..7b503aebe5a7 --- /dev/null +++ b/patches/api/0270-Add-basic-Datapack-API.patch @@ -0,0 +1,318 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Connor Linfoot +Date: Sun, 16 May 2021 15:07:34 +0100 +Subject: [PATCH] Add basic Datapack API + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/io/papermc/paper/datapack/Datapack.java b/src/main/java/io/papermc/paper/datapack/Datapack.java +new file mode 100644 +index 0000000000000000000000000000000000000000..95039ec90f81993cb2e36f82b7d13e9e7a30220e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datapack/Datapack.java +@@ -0,0 +1,99 @@ ++package io.papermc.paper.datapack; ++ ++import java.util.Set; ++import net.kyori.adventure.text.Component; ++import org.bukkit.FeatureFlag; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.Unmodifiable; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * This is a snapshot of a datapack on the server. It ++ * won't be updated as datapacks are updated. ++ */ ++@NullMarked ++public interface Datapack { ++ ++ /** ++ * Gets the name/id of this datapack. ++ * ++ * @return the name of the pack ++ */ ++ @Contract(pure = true) ++ String getName(); ++ ++ /** ++ * Gets the title component of this datapack. ++ * ++ * @return the title ++ */ ++ Component getTitle(); ++ ++ /** ++ * Gets the description component of this datapack. ++ * ++ * @return the description ++ */ ++ Component getDescription(); ++ ++ /** ++ * Gets if this datapack is required to be enabled. ++ * ++ * @return true if the pack is required ++ */ ++ boolean isRequired(); ++ ++ /** ++ * Gets the compatibility status of this pack. ++ * ++ * @return the compatibility of the pack ++ */ ++ Compatibility getCompatibility(); ++ ++ /** ++ * Gets the set of required features for this datapack. ++ * ++ * @return the set of required features ++ */ ++ @Unmodifiable Set getRequiredFeatures(); ++ ++ /** ++ * Gets the enabled state of this pack. ++ * ++ * @return whether the pack is currently enabled ++ */ ++ boolean isEnabled(); ++ ++ /** ++ * Changes the enabled state of this pack. Will ++ * cause a reload of resources ({@code /minecraft:reload}) if ++ * any change happens. ++ * ++ * @param enabled true to enable, false to disable ++ * @apiNote This method may be deprecated in the future as setters on a "snapshot" type are undesirable. ++ */ ++ void setEnabled(boolean enabled); ++ ++ /** ++ * Gets the source for this datapack. ++ * ++ * @return the pack source ++ */ ++ DatapackSource getSource(); ++ ++ /** ++ * Computes the component vanilla Minecraft uses ++ * to display this datapack. Includes the {@link #getSource()}, ++ * {@link #getDescription()}, {@link #getName()}, and the enabled state. ++ * ++ * @return a new component ++ */ ++ @Contract(pure = true, value = "-> new") ++ Component computeDisplayName(); ++ ++ enum Compatibility { ++ TOO_OLD, ++ TOO_NEW, ++ COMPATIBLE, ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datapack/DatapackManager.java b/src/main/java/io/papermc/paper/datapack/DatapackManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4f758a781612bb14c8f2ee41b2b6f40a074e6359 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datapack/DatapackManager.java +@@ -0,0 +1,43 @@ ++package io.papermc.paper.datapack; ++ ++import java.util.Collection; ++import org.jetbrains.annotations.Unmodifiable; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@NullMarked ++public interface DatapackManager { ++ ++ /** ++ * Triggers a refresh of the available and selected datapacks. This ++ * can find new datapacks, remove old ones, and update the metadata for ++ * existing datapacks. Some of these changes will only take effect ++ * after the next {@link org.bukkit.Server#reloadData()} or {@code /minecraft:reload}. ++ */ ++ void refreshPacks(); ++ ++ /** ++ * Gets a datapack by name. May require calling {@link #refreshPacks()} before ++ * to get the latest pack information. ++ * ++ * @param name the name/id of the datapack ++ * @return the datapack, or null if not found ++ */ ++ @Nullable Datapack getPack(String name); ++ ++ /** ++ * Gets the available datapacks. May require calling {@link #refreshPacks()} before ++ * to get the latest pack information. ++ * ++ * @return all the packs known to the server ++ */ ++ @Unmodifiable Collection getPacks(); ++ ++ /** ++ * Gets the enabled datapacks. May require calling {@link #refreshPacks()} before ++ * to get the latest pack information. ++ * ++ * @return all the packs which are currently enabled ++ */ ++ @Unmodifiable Collection getEnabledPacks(); ++} +diff --git a/src/main/java/io/papermc/paper/datapack/DatapackSource.java b/src/main/java/io/papermc/paper/datapack/DatapackSource.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b9b81cd974c2df501fef55bd8d9b78406c073038 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datapack/DatapackSource.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.datapack; ++ ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Source of a datapack. ++ */ ++@NullMarked ++public sealed interface DatapackSource permits DatapackSourceImpl { ++ ++ DatapackSource DEFAULT = create("default"); ++ DatapackSource BUILT_IN = create("built_in"); ++ DatapackSource FEATURE = create("feature"); ++ DatapackSource WORLD = create("world"); ++ DatapackSource SERVER = create("server"); ++ ++ private static DatapackSource create(final String name) { ++ return new DatapackSourceImpl(name); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datapack/DatapackSourceImpl.java b/src/main/java/io/papermc/paper/datapack/DatapackSourceImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0dfd101f01d16cc38f21831ca873633453dc6c9e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datapack/DatapackSourceImpl.java +@@ -0,0 +1,14 @@ ++package io.papermc.paper.datapack; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@ApiStatus.Internal ++@NullMarked ++record DatapackSourceImpl(String name) implements DatapackSource { ++ ++ @Override ++ public String toString() { ++ return this.name; ++ } ++} +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 34e4493286c36a27715ad72201751c692abc9481..46b678da746fb8ff65e77811499ee341093a65e8 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -328,9 +328,11 @@ public final class Bukkit { + /** + * Get the DataPack Manager. + * ++ * @deprecated use {@link #getDatapackManager()} + * @return the manager + */ + @NotNull ++ @Deprecated(forRemoval = true, since = "1.20") + public static DataPackManager getDataPackManager() { + return server.getDataPackManager(); + } +@@ -2641,6 +2643,14 @@ public final class Bukkit { + public static com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { + return server.getMobGoals(); + } ++ ++ /** ++ * @return the datapack manager ++ */ ++ @NotNull ++ public static io.papermc.paper.datapack.DatapackManager getDatapackManager() { ++ return server.getDatapackManager(); ++ } + // Paper end + + @NotNull +diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java +index efeda14f1caebd6be8695cf9a2a8d920a3db45a2..5ae5c59f9375f10f2f035567b1bba8d3645f71fa 100644 +--- a/src/main/java/org/bukkit/Material.java ++++ b/src/main/java/org/bukkit/Material.java +@@ -5654,6 +5654,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla + * @param world the world to check + * @return true if this material can be used in this World. + */ ++ @Deprecated(forRemoval = true, since = "1.20") // Paper + public boolean isEnabledByFeature(@NotNull World world) { + if (isItem()) { + return Bukkit.getDataPackManager().isEnabledByFeature(asItemType(), world); +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index db7aa3a1967d6c093f5fd22443238b566a035835..5ca4543587043f964175435654b9e00c9dadffd5 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -267,9 +267,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + /** + * Get the DataPack Manager. + * ++ * @deprecated use {@link #getDatapackManager()} + * @return the manager + */ + @NotNull ++ @Deprecated(forRemoval = true, since = "1.20") // Paper + public DataPackManager getDataPackManager(); + + /** +@@ -2302,5 +2304,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + @NotNull + com.destroystokyo.paper.entity.ai.MobGoals getMobGoals(); ++ ++ /** ++ * @return the datapack manager ++ */ ++ @NotNull ++ io.papermc.paper.datapack.DatapackManager getDatapackManager(); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java +index 459af298c4e149c3c96cca088f6a3d0db1cf6192..fd5d1ad0334b574fca951555ce647436257d9b19 100644 +--- a/src/main/java/org/bukkit/entity/EntityType.java ++++ b/src/main/java/org/bukkit/entity/EntityType.java +@@ -485,6 +485,7 @@ public enum EntityType implements Keyed, Translatable, net.kyori.adventure.trans + * @param world the world to check + * @return true if this EntityType can be used to spawn an Entity for this World. + */ ++ @Deprecated(forRemoval = true, since = "1.20") // Paper + public boolean isEnabledByFeature(@NotNull World world) { + return Bukkit.getDataPackManager().isEnabledByFeature(this, world); + } +diff --git a/src/main/java/org/bukkit/packs/DataPack.java b/src/main/java/org/bukkit/packs/DataPack.java +index ea03c51d51e015e69d3aaa795547033ceabff9e0..f51d59e6369c76e333fd9e58e711c2b6f245882d 100644 +--- a/src/main/java/org/bukkit/packs/DataPack.java ++++ b/src/main/java/org/bukkit/packs/DataPack.java +@@ -9,7 +9,9 @@ import org.jetbrains.annotations.NotNull; + * Represents a data pack. + * + * @see Minecraft wiki ++ * @deprecated use {@link io.papermc.paper.datapack.Datapack} + */ ++@Deprecated(forRemoval = true, since = "1.20") // Paper + public interface DataPack extends Keyed { + + /** +diff --git a/src/main/java/org/bukkit/packs/DataPackManager.java b/src/main/java/org/bukkit/packs/DataPackManager.java +index aee6e828c6fac9b010356af1239a58b4579c1773..1b850e76a885f0da653d4b48db72e5f85ae72805 100644 +--- a/src/main/java/org/bukkit/packs/DataPackManager.java ++++ b/src/main/java/org/bukkit/packs/DataPackManager.java +@@ -13,7 +13,9 @@ import org.jetbrains.annotations.Nullable; + + /** + * Manager of data packs. ++ * @deprecated use {@link io.papermc.paper.datapack.DatapackManager} + */ ++@Deprecated(forRemoval = true, since = "1.20") // Paper + public interface DataPackManager { + + /** diff --git a/patches/api/0270-Add-missing-effects.patch b/patches/api/0270-Add-missing-effects.patch deleted file mode 100644 index 8f72589e1e13..000000000000 --- a/patches/api/0270-Add-missing-effects.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ivan Pekov -Date: Tue, 5 Jan 2021 10:19:11 +0200 -Subject: [PATCH] Add missing effects - - -diff --git a/src/main/java/org/bukkit/Effect.java b/src/main/java/org/bukkit/Effect.java -index cf6b94a52d7638a52337045c1b4e7677a3fbd824..5072c5ed2635f92a6d8048b6e019c8f36338b93c 100644 ---- a/src/main/java/org/bukkit/Effect.java -+++ b/src/main/java/org/bukkit/Effect.java -@@ -307,7 +307,100 @@ public enum Effect { - * block. - */ - OXIDISED_COPPER_SCRAPE(3005, Type.VISUAL), -+ // Paper start - add missing effects -+ /** -+ * The sound of a wither spawning -+ */ -+ WITHER_SPAWNED(1023, Type.SOUND), -+ /** -+ * The sound of an ender dragon dying -+ */ -+ ENDER_DRAGON_DEATH(1028, Type.SOUND), -+ /** -+ * The sound of an ender portal being created in the overworld -+ */ -+ END_PORTAL_CREATED_IN_OVERWORLD(1038, Type.SOUND), -+ /** -+ * The sound of phantom's bites -+ * -+ * @deprecated use {@link #PHANTOM_BITE} -+ */ -+ @Deprecated(forRemoval = true) -+ PHANTOM_BITES(1039, Type.SOUND), -+ /** -+ * The sound of zombie converting to drowned zombie -+ * -+ * @deprecated use {@link #ZOMBIE_CONVERTED_TO_DROWNED} -+ */ -+ @Deprecated(forRemoval = true) -+ ZOMBIE_CONVERTS_TO_DROWNED(1040, Type.SOUND), -+ /** -+ * The sound of a husk converting to zombie by drowning -+ * -+ * @deprecated use {@link #HUSK_CONVERTED_TO_ZOMBIE} -+ */ -+ @Deprecated(forRemoval = true) -+ HUSK_CONVERTS_TO_ZOMBIE(1041, Type.SOUND), -+ /** -+ * The sound of a grindstone being used -+ * -+ * @deprecated use {@link #GRINDSTONE_USE} -+ */ -+ @Deprecated(forRemoval = true) -+ GRINDSTONE_USED(1042, Type.SOUND), -+ /** -+ * The sound of a book page being turned -+ * -+ * @deprecated use {@link #BOOK_PAGE_TURN} -+ */ -+ @Deprecated(forRemoval = true) -+ BOOK_PAGE_TURNED(1043, Type.SOUND), -+ /** -+ * Particles displayed when a composter composts -+ * -+ * @deprecated use {@link #COMPOSTER_FILL_ATTEMPT} -+ */ -+ @Deprecated(forRemoval = true) -+ COMPOSTER_COMPOSTS(1500, Type.VISUAL), -+ /** -+ * Particles displayed when lava converts a block (either water to stone, or -+ * removing existing blocks such as torches) -+ * -+ * @deprecated use {@link #LAVA_INTERACT} -+ */ -+ @Deprecated(forRemoval = true) -+ LAVA_CONVERTS_BLOCK(1501, Type.VISUAL), -+ /** -+ * Particles displayd when a redstone torch burns out -+ * -+ * @deprecated use {@link #REDSTONE_TORCH_BURNOUT} -+ */ -+ @Deprecated(forRemoval = true) -+ REDSTONE_TORCH_BURNS_OUT(1502, Type.VISUAL), -+ /** -+ * Particles displayed when an ender eye is placed -+ * -+ * @deprecated use {@link #END_PORTAL_FRAME_FILL} -+ */ -+ @Deprecated(forRemoval = true) -+ ENDER_EYE_PLACED(1503, Type.VISUAL), -+ /** -+ * Particles displayed when an ender dragon destroys block -+ * -+ * @deprecated use {@link #ENDER_DRAGON_DESTROY_BLOCK} -+ */ -+ @Deprecated(forRemoval = true) -+ ENDER_DRAGON_DESTROYS_BLOCK(2008, Type.VISUAL), -+ /** -+ * Particles displayed when a wet sponge vaporizes in nether. -+ * -+ * @deprecated use {@link #SPONGE_DRY} -+ */ -+ @Deprecated(forRemoval = true) -+ WET_SPONGE_VAPORIZES_IN_NETHER(2009, Type.VISUAL), - ; -+ private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger(); -+ // Paper end - - private final int id; - private final Type type; -@@ -367,10 +460,22 @@ public enum Effect { - - static { - for (Effect effect : values()) { -+ if (!isDeprecated(effect)) // Paper - BY_ID.put(effect.id, effect); - } - } - -+ // Paper start -+ private static boolean isDeprecated(Effect effect) { -+ try { -+ return Effect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class); -+ } catch (NoSuchFieldException e) { -+ LOGGER.error("Error getting effect enum field {}", effect.name(), e); -+ return false; -+ } -+ } -+ // Paper end -+ - /** - * Represents the type of an effect. - */ -diff --git a/src/test/java/org/bukkit/EffectTest.java b/src/test/java/org/bukkit/EffectTest.java -index 54e621e86e8fe3414099494d419929b282b33489..759081f15992e07271567d65250f27f14f6c99c3 100644 ---- a/src/test/java/org/bukkit/EffectTest.java -+++ b/src/test/java/org/bukkit/EffectTest.java -@@ -5,10 +5,24 @@ import static org.junit.Assert.*; - import org.junit.Test; - - public class EffectTest { -+ private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger(); // Paper -+ - @Test - public void getById() { - for (Effect effect : Effect.values()) { -+ if (!isDeprecated(effect)) // Paper - assertThat(Effect.getById(effect.getId()), is(effect)); - } - } -+ -+ // Paper start -+ private static boolean isDeprecated(Effect effect) { -+ try { -+ return Effect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class); -+ } catch (NoSuchFieldException e) { -+ LOGGER.error("Error getting effect enum field {}", effect.name(), e); -+ return false; -+ } -+ } -+ // Paper end - } diff --git a/patches/api/0271-Expose-Tracked-Players.patch b/patches/api/0271-Expose-Tracked-Players.patch deleted file mode 100644 index a66875419dfc..000000000000 --- a/patches/api/0271-Expose-Tracked-Players.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Tom -Date: Fri, 26 Feb 2021 16:24:25 -0600 -Subject: [PATCH] Expose Tracked Players - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index e3de56ffa7b3a554755a7401988945eca655d816..898c005cb715235df8d7ed6a98faa8191af2fd91 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -768,5 +768,12 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - * Check if entity is inside a ticking chunk - */ - public boolean isTicking(); -+ -+ /** -+ * Returns a set of {@link Player Players} within this entity's tracking range (players that can "see" this entity). -+ * -+ * @return players in tracking range -+ */ -+ @NotNull Set getTrackedPlayers(); - // Paper end - } diff --git a/patches/api/0297-additions-to-PlayerGameModeChangeEvent.patch b/patches/api/0271-additions-to-PlayerGameModeChangeEvent.patch similarity index 100% rename from patches/api/0297-additions-to-PlayerGameModeChangeEvent.patch rename to patches/api/0271-additions-to-PlayerGameModeChangeEvent.patch diff --git a/patches/api/0272-Cache-the-result-of-Material-isBlock.patch b/patches/api/0272-Cache-the-result-of-Material-isBlock.patch deleted file mode 100644 index 12980bd8803e..000000000000 --- a/patches/api/0272-Cache-the-result-of-Material-isBlock.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Tue, 2 Mar 2021 15:24:58 -0800 -Subject: [PATCH] Cache the result of Material#isBlock - - -diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index 04e07abc29ed1c4eae27529307c4fa11b6fbc3f6..4c8c21982f825bb70ff5e14098836215bdb0cd17 100644 ---- a/src/main/java/org/bukkit/Material.java -+++ b/src/main/java/org/bukkit/Material.java -@@ -4069,6 +4069,7 @@ public enum Material implements Keyed, net.kyori.adventure.translation.Translata - public final Class data; - private final boolean legacy; - private final NamespacedKey key; -+ private boolean isBlock; // Paper - - private Material(final int id) { - this(id, 64); -@@ -4275,6 +4276,11 @@ public enum Material implements Keyed, net.kyori.adventure.translation.Translata - * @return true if this material is a block - */ - public boolean isBlock() { -+ // Paper start - cache isBlock -+ return this.isBlock; -+ } -+ private boolean isBlock0() { -+ // Paper end - switch (this) { - // - case ACACIA_BUTTON: -@@ -5391,6 +5397,7 @@ public enum Material implements Keyed, net.kyori.adventure.translation.Translata - static { - for (Material material : values()) { - BY_NAME.put(material.name(), material); -+ material.isBlock = material.isBlock0(); // Paper - } - } - diff --git a/patches/api/0272-ItemStack-repair-check-API.patch b/patches/api/0272-ItemStack-repair-check-API.patch new file mode 100644 index 000000000000..b23413a9201e --- /dev/null +++ b/patches/api/0272-ItemStack-repair-check-API.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 15 May 2021 22:10:50 -0700 +Subject: [PATCH] ItemStack repair check API + + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 989a7e624dca442f1c989bb766e4c16a75e87333..218adc63a0c0037f764942af184b30ebabff697d 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -187,5 +187,15 @@ public interface UnsafeValues { + * @return the server's protocol version + */ + int getProtocolVersion(); ++ ++ /** ++ * Checks if an itemstack can be repaired with another itemstack. ++ * Returns false if either argument's type is not an item ({@link Material#isItem()}). ++ * ++ * @param itemToBeRepaired the itemstack to be repaired ++ * @param repairMaterial the repair material ++ * @return true if valid repair, false if not ++ */ ++ public boolean isValidRepairItemStack(@org.jetbrains.annotations.NotNull ItemStack itemToBeRepaired, @org.jetbrains.annotations.NotNull ItemStack repairMaterial); + // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index 06207f1527e8afe8bb786410c9659bb92792ea6f..c33a866a03cc8e6235dd8bff6259dcb1e1bbb11f 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -1006,5 +1006,27 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + public io.papermc.paper.inventory.ItemRarity getRarity() { + return io.papermc.paper.inventory.ItemRarity.valueOf(this.getItemMeta().getRarity().name()); + } ++ ++ /** ++ * Checks if an itemstack can repair this itemstack. ++ * Returns false if {@code this} or {@code repairMaterial}'s type is not an item ({@link Material#isItem()}). ++ * ++ * @param repairMaterial the repair material ++ * @return true if it is repairable by, false if not ++ */ ++ public boolean isRepairableBy(@NotNull ItemStack repairMaterial) { ++ return Bukkit.getUnsafe().isValidRepairItemStack(this, repairMaterial); ++ } ++ ++ /** ++ * Checks if this itemstack can repair another. ++ * Returns false if {@code this} or {@code toBeRepaired}'s type is not an item ({@link Material#isItem()}). ++ * ++ * @param toBeRepaired the itemstack to be repaired ++ * @return true if it can repair, false if not ++ */ ++ public boolean canRepair(@NotNull ItemStack toBeRepaired) { ++ return Bukkit.getUnsafe().isValidRepairItemStack(toBeRepaired, this); ++ } + // Paper end + } diff --git a/patches/api/0273-Add-worldborder-events.patch b/patches/api/0273-Add-worldborder-events.patch deleted file mode 100644 index 09c3770e1628..000000000000 --- a/patches/api/0273-Add-worldborder-events.patch +++ /dev/null @@ -1,308 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 4 Jan 2021 22:40:26 -0800 -Subject: [PATCH] Add worldborder events - - -diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..126fe50b519a8d7cd158f799058cb235f9c4cbdb ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java -@@ -0,0 +1,114 @@ -+package io.papermc.paper.event.world.border; -+ -+import org.bukkit.World; -+import org.bukkit.WorldBorder; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a world border changes its bounds, either over time, or instantly. -+ */ -+public class WorldBorderBoundsChangeEvent extends WorldBorderEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private Type type; -+ private final double oldSize; -+ private double newSize; -+ private long duration; -+ private boolean cancelled; -+ -+ public WorldBorderBoundsChangeEvent(@NotNull World world, @NotNull WorldBorder worldBorder, @NotNull Type type, double oldSize, double newSize, long duration) { -+ super(world, worldBorder); -+ this.type = type; -+ this.oldSize = oldSize; -+ this.newSize = newSize; -+ this.duration = duration; -+ } -+ -+ /** -+ * Gets if this change is an instant change or over-time change. -+ * -+ * @return the change type -+ */ -+ @NotNull -+ public Type getType() { -+ return type; -+ } -+ -+ /** -+ * Gets the old size or the world border. -+ * -+ * @return the old size -+ */ -+ public double getOldSize() { -+ return oldSize; -+ } -+ -+ /** -+ * Gets the new size of the world border. -+ * -+ * @return the new size -+ */ -+ public double getNewSize() { -+ return newSize; -+ } -+ -+ /** -+ * Sets the new size of the world border. -+ * -+ * @param newSize the new size -+ */ -+ public void setNewSize(double newSize) { -+ // PAIL: TODO: Magic Values -+ this.newSize = Math.min(6.0E7D, Math.max(1.0D, newSize)); -+ } -+ -+ /** -+ * Gets the time in milliseconds for the change. Will be 0 if instant. -+ * -+ * @return the time in milliseconds for the change -+ */ -+ public long getDuration() { -+ return duration; -+ } -+ -+ /** -+ * Sets the time in milliseconds for the change. Will change {@link #getType()} to return -+ * {@link Type#STARTED_MOVE}. -+ * -+ * @param duration the time in milliseconds for the change -+ */ -+ public void setDuration(long duration) { -+ // PAIL: TODO: Magic Values -+ this.duration = Math.min(9223372036854775L, Math.max(0L, duration)); -+ if (duration >= 0 && type == Type.INSTANT_MOVE) type = Type.STARTED_MOVE; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+ -+ public enum Type { -+ STARTED_MOVE, -+ INSTANT_MOVE -+ } -+} -diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeFinishEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeFinishEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c3d578ae2c5615b0ebace99d9bacf100b086c971 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeFinishEvent.java -@@ -0,0 +1,65 @@ -+package io.papermc.paper.event.world.border; -+ -+import org.bukkit.World; -+import org.bukkit.WorldBorder; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a moving world border has finished it's move. -+ */ -+public class WorldBorderBoundsChangeFinishEvent extends WorldBorderEvent { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final double oldSize; -+ private final double newSize; -+ private final double duration; -+ -+ public WorldBorderBoundsChangeFinishEvent(@NotNull World world, @NotNull WorldBorder worldBorder, double oldSize, double newSize, double duration) { -+ super(world, worldBorder); -+ this.oldSize = oldSize; -+ this.newSize = newSize; -+ this.duration = duration; -+ } -+ -+ /** -+ * Gets the old size of the worldborder. -+ * -+ * @return the old size -+ */ -+ public double getOldSize() { -+ return oldSize; -+ } -+ -+ /** -+ * Gets the new size of the worldborder. -+ * -+ * @return the new size -+ */ -+ public double getNewSize() { -+ return newSize; -+ } -+ -+ /** -+ * Gets the duration this worldborder took to make the change. -+ *

      -+ * Can be 0 if handlers for {@link io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent} set the duration to 0. -+ * -+ * @return the duration of the transition -+ */ -+ public double getDuration() { -+ return duration; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderCenterChangeEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderCenterChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4a10c773a8d05a596066e63306dead74c1363fd7 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderCenterChangeEvent.java -@@ -0,0 +1,77 @@ -+package io.papermc.paper.event.world.border; -+ -+import org.bukkit.Location; -+import org.bukkit.World; -+import org.bukkit.WorldBorder; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.world.WorldEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a world border's center is changed. -+ */ -+public class WorldBorderCenterChangeEvent extends WorldBorderEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final Location oldCenter; -+ private Location newCenter; -+ private boolean cancelled; -+ -+ public WorldBorderCenterChangeEvent(@NotNull World world, @NotNull WorldBorder worldBorder, @NotNull Location oldCenter, @NotNull Location newCenter) { -+ super(world, worldBorder); -+ this.oldCenter = oldCenter; -+ this.newCenter = newCenter; -+ } -+ -+ /** -+ * Gets the original center location of the world border. -+ * -+ * @return the old center -+ */ -+ @NotNull -+ public Location getOldCenter() { -+ return oldCenter; -+ } -+ -+ /** -+ * Gets the new center location for the world border. -+ * -+ * @return the new center -+ */ -+ @NotNull -+ public Location getNewCenter() { -+ return newCenter; -+ } -+ -+ /** -+ * Sets the new center location for the world border. Y coordinate is ignored. -+ * -+ * @param newCenter the new center -+ */ -+ public void setNewCenter(@NotNull Location newCenter) { -+ this.newCenter = newCenter; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/event/world/border/WorldBorderEvent.java b/src/main/java/io/papermc/paper/event/world/border/WorldBorderEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..67bd469d3680c9554ce6c1d5493826a252682835 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/world/border/WorldBorderEvent.java -@@ -0,0 +1,22 @@ -+package io.papermc.paper.event.world.border; -+ -+import org.bukkit.World; -+import org.bukkit.WorldBorder; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.world.WorldEvent; -+import org.jetbrains.annotations.NotNull; -+ -+public abstract class WorldBorderEvent extends WorldEvent { -+ -+ private final WorldBorder worldBorder; -+ -+ public WorldBorderEvent(@NotNull World world, @NotNull WorldBorder worldBorder) { -+ super(world); -+ this.worldBorder = worldBorder; -+ } -+ -+ @NotNull -+ public WorldBorder getWorldBorder() { -+ return worldBorder; -+ } -+} diff --git a/patches/api/0273-More-Enchantment-API.patch b/patches/api/0273-More-Enchantment-API.patch new file mode 100644 index 000000000000..810ee1b78a33 --- /dev/null +++ b/patches/api/0273-More-Enchantment-API.patch @@ -0,0 +1,224 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 6 May 2021 19:58:03 -0700 +Subject: [PATCH] More Enchantment API + +Co-authored-by: Luis +Co-authored-by: Janet Blackquill + +diff --git a/src/main/java/io/papermc/paper/enchantments/EnchantmentRarity.java b/src/main/java/io/papermc/paper/enchantments/EnchantmentRarity.java +new file mode 100644 +index 0000000000000000000000000000000000000000..aec3b41d7c3388e26fa203e3c062f1e6a6d0ba41 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/enchantments/EnchantmentRarity.java +@@ -0,0 +1,28 @@ ++package io.papermc.paper.enchantments; ++ ++/** ++ * @deprecated Enchantments do not have a "rarity" since 1.20.5 ++ */ ++@Deprecated(forRemoval = true, since = "1.20.5") ++public enum EnchantmentRarity { ++ ++ COMMON(10), ++ UNCOMMON(5), ++ RARE(2), ++ VERY_RARE(1); ++ ++ private final int weight; ++ ++ EnchantmentRarity(int weight) { ++ this.weight = weight; ++ } ++ ++ /** ++ * Gets the weight for the rarity. ++ * ++ * @return the weight ++ */ ++ public int getWeight() { ++ return weight; ++ } ++} +diff --git a/src/main/java/org/bukkit/enchantments/Enchantment.java b/src/main/java/org/bukkit/enchantments/Enchantment.java +index 72251952e771152016e32a3fe8bd06ec47c8ee6c..fa20a0f13bb91955e2928b46c99ddaf0c4418d15 100644 +--- a/src/main/java/org/bukkit/enchantments/Enchantment.java ++++ b/src/main/java/org/bukkit/enchantments/Enchantment.java +@@ -284,11 +284,7 @@ public abstract class Enchantment implements Keyed, Translatable, net.kyori.adve + * Cursed enchantments are found the same way treasure enchantments are + * + * @return true if the enchantment is cursed +- * @deprecated cursed enchantments are no longer special. Will return true +- * only for {@link Enchantment#BINDING_CURSE} and +- * {@link Enchantment#VANISHING_CURSE}. + */ +- @Deprecated(since = "1.13") + public abstract boolean isCursed(); + + /** +@@ -324,6 +320,118 @@ public abstract class Enchantment implements Keyed, Translatable, net.kyori.adve + public abstract net.kyori.adventure.text.@NotNull Component displayName(int level); + // Paper end + ++ // Paper start - more Enchantment API ++ /** ++ * Checks if this enchantment can be found in villager trades. ++ * ++ * @return true if the enchantment can be found in trades ++ */ ++ public abstract boolean isTradeable(); ++ ++ /** ++ * Checks if this enchantment can be found in an enchanting table ++ * or use to enchant items generated by loot tables. ++ * ++ * @return true if the enchantment can be found in a table or by loot tables ++ */ ++ public abstract boolean isDiscoverable(); ++ ++ /** ++ * Gets the minimum modified cost of this enchantment at a specific level. ++ *

      ++ * Note this is not the number of experience levels needed, and does not directly translate to the levels shown in an enchanting table. ++ * This value is used in combination with factors such as tool enchantability to determine a final cost. ++ * See https://minecraft.wiki/w/Enchanting/Levels for more information. ++ *

      ++ * @param level The level of the enchantment ++ * @return The modified cost of this enchantment ++ */ ++ public abstract int getMinModifiedCost(int level); ++ ++ /** ++ * Gets the maximum modified cost of this enchantment at a specific level. ++ *

      ++ * Note this is not the number of experience levels needed, and does not directly translate to the levels shown in an enchanting table. ++ * This value is used in combination with factors such as tool enchantability to determine a final cost. ++ * See https://minecraft.wiki/w/Enchanting/Levels for more information. ++ *

      ++ * @param level The level of the enchantment ++ * @return The modified cost of this enchantment ++ */ ++ public abstract int getMaxModifiedCost(int level); ++ ++ /** ++ * Gets cost of applying this enchantment using an anvil. ++ *

      ++ * Note that this is halved when using an enchantment book, and is multiplied by the level of the enchantment. ++ * See https://minecraft.wiki/w/Anvil_mechanics for more information. ++ *

      ++ * @return The anvil cost of this enchantment ++ */ ++ public abstract int getAnvilCost(); ++ ++ /** ++ * Gets the rarity of this enchantment. ++ * ++ * @return the rarity ++ * @deprecated As of 1.20.5 enchantments do not have a rarity. ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.20.5") ++ @Contract("-> fail") ++ public abstract io.papermc.paper.enchantments.EnchantmentRarity getRarity(); ++ ++ /** ++ * Gets the damage increase as a result of the level and entity category specified ++ * ++ * @param level the level of enchantment ++ * @param entityCategory the category of entity ++ * @return the damage increase ++ * @deprecated Enchantments now have a complex effect systems that cannot be reduced to a simple damage increase. ++ */ ++ @Contract("_, _ -> fail") ++ @Deprecated(forRemoval = true, since = "1.20.5") ++ public abstract float getDamageIncrease(int level, @NotNull org.bukkit.entity.EntityCategory entityCategory); ++ ++ /** ++ * Gets the damage increase as a result of the level and entity type specified ++ * ++ * @param level the level of enchantment ++ * @param entityType the type of entity. ++ * @return the damage increase ++ * @deprecated Enchantments now have a complex effect systems that cannot be reduced to a simple damage increase. ++ */ ++ @Contract("_, _ -> fail") ++ @Deprecated(forRemoval = true, since = "1.21") ++ public abstract float getDamageIncrease(int level, @NotNull org.bukkit.entity.EntityType entityType); ++ ++ /** ++ * Gets the equipment slots where this enchantment is considered "active". ++ * ++ * @return the equipment slots ++ * @deprecated Use {@link #getActiveSlotGroups()} instead as enchantments are now applicable to a group of equipment slots. ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.21") ++ public java.util.Set getActiveSlots() { ++ final java.util.Set slots = this.getActiveSlotGroups(); ++ return java.util.Arrays.stream(org.bukkit.inventory.EquipmentSlot.values()).filter(e -> { ++ for (final org.bukkit.inventory.EquipmentSlotGroup group : slots) { ++ if (group.test(e)) return true; ++ } ++ return false; ++ }).collect(java.util.stream.Collectors.toSet()); ++ } ++ ++ /** ++ * Gets the equipment slots where this enchantment is considered "active". ++ * ++ * @return the equipment slots ++ */ ++ @NotNull ++ public abstract java.util.Set getActiveSlotGroups(); ++ // Paper end - more Enchantment API ++ + // Paper start - mark translation key as deprecated + /** + * @deprecated this method assumes that the enchantments description +diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java +index f4422da4ebb0dc6551305f3e8468817eb08bdbc9..ca3b2f9be7802f94bacc46e28e396054089f2737 100644 +--- a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java ++++ b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java +@@ -31,5 +31,42 @@ public abstract class EnchantmentWrapper extends Enchantment { + public @NotNull String translationKey() { + return getEnchantment().translationKey(); + } ++ ++ @Override ++ public boolean isTradeable() { ++ return getEnchantment().isTradeable(); ++ } ++ ++ @Override ++ public boolean isDiscoverable() { ++ return getEnchantment().isDiscoverable(); ++ } ++ ++ @Override ++ public int getMinModifiedCost(int level) { ++ return getEnchantment().getMinModifiedCost(level); ++ } ++ ++ @Override ++ public int getMaxModifiedCost(int level) { ++ return getEnchantment().getMaxModifiedCost(level); ++ } ++ ++ @NotNull ++ @Override ++ public io.papermc.paper.enchantments.EnchantmentRarity getRarity() { ++ return getEnchantment().getRarity(); ++ } ++ ++ @Override ++ public float getDamageIncrease(int level, @NotNull org.bukkit.entity.EntityCategory entityCategory) { ++ return getEnchantment().getDamageIncrease(level, entityCategory); ++ } ++ ++ @NotNull ++ @Override ++ public java.util.Set getActiveSlots() { ++ return getEnchantment().getActiveSlots(); ++ } + // Paper end + } diff --git a/patches/api/0274-Add-Mob-lookAt-API.patch b/patches/api/0274-Add-Mob-lookAt-API.patch new file mode 100644 index 000000000000..e1164a0f3e0a --- /dev/null +++ b/patches/api/0274-Add-Mob-lookAt-API.patch @@ -0,0 +1,99 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 14 May 2021 13:42:06 -0500 +Subject: [PATCH] Add Mob#lookAt API + + +diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java +index ef89a82669a6c5bf911827b90facf36a2ff26e91..5fd723c9fdda81595db8b150d967ff3bd5cea608 100644 +--- a/src/main/java/org/bukkit/entity/Mob.java ++++ b/src/main/java/org/bukkit/entity/Mob.java +@@ -27,6 +27,88 @@ public interface Mob extends LivingEntity, Lootable { + * @return True if mob is exposed to daylight + */ + boolean isInDaylight(); ++ ++ /** ++ * Instruct this Mob to look at a specific Location ++ *

      ++ * Useful when implementing custom mob goals ++ * ++ * @param location location to look at ++ */ ++ void lookAt(@NotNull org.bukkit.Location location); ++ ++ /** ++ * Instruct this Mob to look at a specific Location ++ *

      ++ * Useful when implementing custom mob goals ++ * ++ * @param location location to look at ++ * @param headRotationSpeed head rotation speed ++ * @param maxHeadPitch max head pitch rotation ++ */ ++ void lookAt(@NotNull org.bukkit.Location location, float headRotationSpeed, float maxHeadPitch); ++ ++ /** ++ * Instruct this Mob to look at a specific Entity ++ *

      ++ * If a LivingEntity, look at eye location ++ *

      ++ * Useful when implementing custom mob goals ++ * ++ * @param entity entity to look at ++ */ ++ void lookAt(@NotNull Entity entity); ++ ++ /** ++ * Instruct this Mob to look at a specific Entity ++ *

      ++ * If a LivingEntity, look at eye location ++ *

      ++ * Useful when implementing custom mob goals ++ * ++ * @param entity entity to look at ++ * @param headRotationSpeed head rotation speed ++ * @param maxHeadPitch max head pitch rotation ++ */ ++ void lookAt(@NotNull Entity entity, float headRotationSpeed, float maxHeadPitch); ++ ++ /** ++ * Instruct this Mob to look at a specific position ++ *

      ++ * Useful when implementing custom mob goals ++ * ++ * @param x x coordinate ++ * @param y y coordinate ++ * @param z z coordinate ++ */ ++ void lookAt(double x, double y, double z); ++ ++ /** ++ * Instruct this Mob to look at a specific position ++ *

      ++ * Useful when implementing custom mob goals ++ * ++ * @param x x coordinate ++ * @param y y coordinate ++ * @param z z coordinate ++ * @param headRotationSpeed head rotation speed ++ * @param maxHeadPitch max head pitch rotation ++ */ ++ void lookAt(double x, double y, double z, float headRotationSpeed, float maxHeadPitch); ++ ++ /** ++ * Gets the head rotation speed ++ * ++ * @return the head rotation speed ++ */ ++ int getHeadRotationSpeed(); ++ ++ /** ++ * Gets the max head pitch rotation ++ * ++ * @return the max head pitch rotation ++ */ ++ int getMaxHeadPitch(); + // Paper end + /** + * Instructs this Mob to set the specified LivingEntity as its target. diff --git a/patches/api/0274-added-PlayerNameEntityEvent.patch b/patches/api/0274-added-PlayerNameEntityEvent.patch deleted file mode 100644 index a38082f8e8d1..000000000000 --- a/patches/api/0274-added-PlayerNameEntityEvent.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 5 Jul 2020 00:34:24 -0700 -Subject: [PATCH] added PlayerNameEntityEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerNameEntityEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerNameEntityEvent.java -new file mode 100755 -index 0000000000000000000000000000000000000000..ef9e53a73eff469bbaa8fb20c634297acb9d1986 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerNameEntityEvent.java -@@ -0,0 +1,118 @@ -+package io.papermc.paper.event.player; -+ -+import net.kyori.adventure.text.Component; -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when the player is attempting to rename a mob -+ */ -+public class PlayerNameEntityEvent extends PlayerEvent implements Cancellable { -+ -+ private LivingEntity entity; -+ private Component name; -+ private boolean persistent; -+ private boolean cancelled; -+ -+ public PlayerNameEntityEvent(@NotNull Player player, @NotNull LivingEntity entity, @NotNull Component name, boolean persistent) { -+ super(player); -+ this.entity = entity; -+ this.name = name; -+ this.persistent = persistent; -+ } -+ -+ /** -+ * Gets the name to be given to the entity. -+ * @return the name -+ */ -+ @Nullable -+ public Component getName() { -+ return name; -+ } -+ -+ /** -+ * Sets the name to be given to the entity. -+ * -+ * @param name the name -+ */ -+ public void setName(@Nullable Component name) { -+ this.name = name; -+ } -+ -+ /** -+ * Gets the entity involved in this event. -+ * -+ * @return the entity -+ */ -+ @NotNull -+ public LivingEntity getEntity() { -+ return entity; -+ } -+ -+ /** -+ * Sets the entity involved in this event. -+ * -+ * @param entity the entity -+ */ -+ public void setEntity(@NotNull LivingEntity entity) { -+ this.entity = entity; -+ } -+ -+ /** -+ * Gets whether this will set the mob to be persistent. -+ * -+ * @return persistent -+ */ -+ public boolean isPersistent() { -+ return persistent; -+ } -+ -+ /** -+ * Sets whether this will set the mob to be persistent. -+ * -+ * @param persistent persistent -+ */ -+ public void setPersistent(boolean persistent) { -+ this.persistent = persistent; -+ } -+ -+ /** -+ * Gets the cancellation state of this event. A cancelled event will not -+ * be executed in the server, but will still pass to other plugins -+ * -+ * @return true if this event is cancelled -+ */ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * Sets the cancellation state of this event. A cancelled event will not -+ * be executed in the server, but will still pass to other plugins. -+ * -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} diff --git a/patches/api/0275-Add-recipe-to-cook-events.patch b/patches/api/0275-Add-recipe-to-cook-events.patch deleted file mode 100644 index b0b34773c0f9..000000000000 --- a/patches/api/0275-Add-recipe-to-cook-events.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> -Date: Wed, 6 Jan 2021 12:05:29 -0800 -Subject: [PATCH] Add recipe to cook events - - -diff --git a/src/main/java/org/bukkit/event/block/BlockCookEvent.java b/src/main/java/org/bukkit/event/block/BlockCookEvent.java -index be7af5440bf9923f0c9c84efa4d70a89337a2f96..a3f1c9cb36c9069ed622985a525bfc2a7a27ab91 100644 ---- a/src/main/java/org/bukkit/event/block/BlockCookEvent.java -+++ b/src/main/java/org/bukkit/event/block/BlockCookEvent.java -@@ -14,12 +14,21 @@ public class BlockCookEvent extends BlockEvent implements Cancellable { - private final ItemStack source; - private ItemStack result; - private boolean cancelled; -+ private final org.bukkit.inventory.CookingRecipe recipe; // Paper - -+ @Deprecated // Paper - public BlockCookEvent(@NotNull final Block block, @NotNull final ItemStack source, @NotNull final ItemStack result) { -+ // Paper start -+ this(block, source, result, null); -+ } -+ -+ public BlockCookEvent(@NotNull final Block block, @NotNull final ItemStack source, @NotNull final ItemStack result, @org.jetbrains.annotations.Nullable org.bukkit.inventory.CookingRecipe recipe) { -+ // Paper end - super(block); - this.source = source; - this.result = result; - this.cancelled = false; -+ this.recipe = recipe; // Paper - } - - /** -@@ -61,6 +70,18 @@ public class BlockCookEvent extends BlockEvent implements Cancellable { - this.cancelled = cancel; - } - -+ // Paper start -+ /** -+ * Gets the cooking recipe associated with this event. -+ * -+ * @return the recipe -+ */ -+ @org.jetbrains.annotations.Nullable -+ public org.bukkit.inventory.CookingRecipe getRecipe() { -+ return recipe; -+ } -+ // Paper end -+ - @NotNull - @Override - public HandlerList getHandlers() { -diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java -index 066e7dd9a34d35c8b643a5efcf95d6a5ef47c7ee..16b3ab8f525c4e863f804cc8460a330407d85478 100644 ---- a/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java -+++ b/src/main/java/org/bukkit/event/inventory/FurnaceSmeltEvent.java -@@ -10,7 +10,13 @@ import org.jetbrains.annotations.NotNull; - */ - public class FurnaceSmeltEvent extends BlockCookEvent { - -+ @Deprecated // Paper - public FurnaceSmeltEvent(@NotNull final Block furnace, @NotNull final ItemStack source, @NotNull final ItemStack result) { - super(furnace, source, result); - } -+ // Paper start -+ public FurnaceSmeltEvent(@NotNull final Block furnace, @NotNull final ItemStack source, @NotNull final ItemStack result, @org.jetbrains.annotations.Nullable org.bukkit.inventory.CookingRecipe recipe) { -+ super(furnace, source, result, recipe); -+ } -+ // Paper end - } diff --git a/patches/api/0275-ItemStack-editMeta.patch b/patches/api/0275-ItemStack-editMeta.patch new file mode 100644 index 000000000000..b90aa42dc094 --- /dev/null +++ b/patches/api/0275-ItemStack-editMeta.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Riley Park +Date: Sun, 23 May 2021 05:04:28 -0700 +Subject: [PATCH] ItemStack#editMeta + + +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index c33a866a03cc8e6235dd8bff6259dcb1e1bbb11f..86404d3b8b4862cd1f140617cae93aa69df122ca 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -574,6 +574,50 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + return result.ensureServerConversions(); // Paper + } + ++ // Paper start ++ /** ++ * Edits the {@link ItemMeta} of this stack. ++ *

      ++ * The {@link java.util.function.Consumer} must only interact ++ * with this stack's {@link ItemMeta} through the provided {@link ItemMeta} instance. ++ * Calling this method or any other meta-related method of the {@link ItemStack} class ++ * (such as {@link #getItemMeta()}, {@link #addItemFlags(ItemFlag...)}, {@link #lore()}, etc.) ++ * from inside the consumer is disallowed and will produce undefined results or exceptions. ++ *

      ++ * ++ * @param consumer the meta consumer ++ * @return {@code true} if the edit was successful, {@code false} otherwise ++ */ ++ public boolean editMeta(final @NotNull java.util.function.Consumer consumer) { ++ return editMeta(ItemMeta.class, consumer); ++ } ++ ++ /** ++ * Edits the {@link ItemMeta} of this stack if the meta is of the specified type. ++ *

      ++ * The {@link java.util.function.Consumer} must only interact ++ * with this stack's {@link ItemMeta} through the provided {@link ItemMeta} instance. ++ * Calling this method or any other meta-related method of the {@link ItemStack} class ++ * (such as {@link #getItemMeta()}, {@link #addItemFlags(ItemFlag...)}, {@link #lore()}, etc.) ++ * from inside the consumer is disallowed and will produce undefined results or exceptions. ++ *

      ++ * ++ * @param metaClass the type of meta to edit ++ * @param consumer the meta consumer ++ * @param the meta type ++ * @return {@code true} if the edit was successful, {@code false} otherwise ++ */ ++ public boolean editMeta(final @NotNull Class metaClass, final @NotNull java.util.function.Consumer<@NotNull ? super M> consumer) { ++ final @Nullable ItemMeta meta = this.getItemMeta(); ++ if (metaClass.isInstance(meta)) { ++ consumer.accept((M) meta); ++ this.setItemMeta(meta); ++ return true; ++ } ++ return false; ++ } ++ // Paper end ++ + /** + * Get a copy of this ItemStack's {@link ItemMeta}. + * diff --git a/patches/api/0276-Add-Block-isValidTool.patch b/patches/api/0276-Add-Block-isValidTool.patch deleted file mode 100644 index 1ba9ed8d9a06..000000000000 --- a/patches/api/0276-Add-Block-isValidTool.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 6 Jul 2020 12:44:23 -0700 -Subject: [PATCH] Add Block#isValidTool - - -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index 43a0e57a6db702b2a40e151f151bfaa63b9d95d5..c847bc83c0911007d226f1a8c6f1d0cefa9a1689 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -229,6 +229,15 @@ public interface Block extends Metadatable, net.kyori.adventure.translation.Tran - public static int getBlockKeyZ(long packed) { - return (int) ((packed << 10) >> 37); - } -+ -+ /** -+ * Checks if the itemstack is a valid tool to -+ * break the block with -+ * -+ * @param itemStack The (tool) itemstack -+ * @return whether the block will drop items -+ */ -+ boolean isValidTool(@NotNull ItemStack itemStack); - // Paper End - - /** diff --git a/patches/api/0276-Add-EntityInsideBlockEvent.patch b/patches/api/0276-Add-EntityInsideBlockEvent.patch new file mode 100644 index 000000000000..dafb3010dcbc --- /dev/null +++ b/patches/api/0276-Add-EntityInsideBlockEvent.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 8 May 2021 18:02:06 -0700 +Subject: [PATCH] Add EntityInsideBlockEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityInsideBlockEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityInsideBlockEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a1a7a0af23e8833b9f127335950a0e5649d5f11b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityInsideBlockEvent.java +@@ -0,0 +1,86 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.block.Block; ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when an entity enters the hitbox of a block. ++ * Only called for blocks that react when an entity is inside. ++ * If cancelled, any action that would have resulted from that entity ++ * being in the block will not happen (such as extinguishing an entity in a cauldron). ++ *

      ++ * Blocks this is currently called for: ++ *

        ++ *
      • Big dripleaf
      • ++ *
      • Bubble column
      • ++ *
      • Buttons
      • ++ *
      • Cactus
      • ++ *
      • Campfire
      • ++ *
      • Cauldron
      • ++ *
      • Crops
      • ++ *
      • End Gateway
      • ++ *
      • Ender Portal
      • ++ *
      • Eye blossom
      • ++ *
      • Fires
      • ++ *
      • Frogspawn
      • ++ *
      • Honey
      • ++ *
      • Hopper
      • ++ *
      • Detector rails
      • ++ *
      • Nether portals
      • ++ *
      • Pitcher crop
      • ++ *
      • Powdered snow
      • ++ *
      • Pressure plates
      • ++ *
      • Sweet berry bush
      • ++ *
      • Tripwire
      • ++ *
      • Waterlily
      • ++ *
      • Web
      • ++ *
      • Wither rose
      • ++ *
      ++ */ ++@NullMarked ++public class EntityInsideBlockEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Block block; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityInsideBlockEvent(final Entity entity, final Block block) { ++ super(entity); ++ this.block = block; ++ } ++ ++ /** ++ * Gets the block. ++ * ++ * @return the block ++ */ ++ public Block getBlock() { ++ return this.block; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0277-Expand-world-key-API.patch b/patches/api/0277-Expand-world-key-API.patch deleted file mode 100644 index 7ee3077c311b..000000000000 --- a/patches/api/0277-Expand-world-key-API.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 6 Jan 2021 00:34:10 -0800 -Subject: [PATCH] Expand world key API - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 7e422716841d3736cce4f0968121231f9c6c33d3..4c6780dd1375f5d2c6e60229cc05c4af9d480b8a 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -810,6 +810,18 @@ public final class Bukkit { - public static World getWorld(@NotNull UUID uid) { - return server.getWorld(uid); - } -+ // Paper start -+ /** -+ * Gets the world from the given NamespacedKey -+ * -+ * @param worldKey the NamespacedKey of the world to retrieve -+ * @return a world with the given NamespacedKey, or null if none exists -+ */ -+ @Nullable -+ public static World getWorld(@NotNull NamespacedKey worldKey) { -+ return server.getWorld(worldKey); -+ } -+ // Paper end - - /** - * Create a new virtual {@link WorldBorder}. -diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java -index 2fa3de66107162ccaa158b369e2c4a926ecaff92..aa534b1a9a1fb84a2fbd4b372f313bb4b63325fa 100644 ---- a/src/main/java/org/bukkit/RegionAccessor.java -+++ b/src/main/java/org/bukkit/RegionAccessor.java -@@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable; - * A RegionAccessor gives access to getting, modifying and spawning {@link Biome}, {@link BlockState} and {@link Entity}, - * as well as generating some basic structures. - */ --public interface RegionAccessor { -+public interface RegionAccessor extends Keyed { // Paper - - /** - * Gets the {@link Biome} at the given {@link Location}. -@@ -383,5 +383,14 @@ public interface RegionAccessor { - */ - @NotNull - io.papermc.paper.world.MoonPhase getMoonPhase(); -+ -+ /** -+ * Get the world's key -+ * -+ * @return the world's key -+ */ -+ @NotNull -+ @Override -+ NamespacedKey getKey(); - // Paper end - } -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index afed6bcf923166065ac9f63dd96191cd42eefcb9..181493def187f72b6ff89c3849598428f35d31f3 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -670,6 +670,17 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - @Nullable - public World getWorld(@NotNull UUID uid); - -+ // Paper start -+ /** -+ * Gets the world from the given NamespacedKey -+ * -+ * @param worldKey the NamespacedKey of the world to retrieve -+ * @return a world with the given NamespacedKey, or null if none exists -+ */ -+ @Nullable -+ public World getWorld(@NotNull NamespacedKey worldKey); -+ // Paper end -+ - /** - * Create a new virtual {@link WorldBorder}. - *

      -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index abe79e4a2233341d0030742b823a0cfb5af97f41..204ab103eeff976d3da4f5694c31beafab6e1fdd 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -157,5 +157,10 @@ public interface UnsafeValues { - * @throws IllegalArgumentException if there isn't a registry for that type - */ - @org.jetbrains.annotations.NotNull Registry registryFor(Class classOfT); -+ -+ /** -+ * Just don't use it. -+ */ -+ @org.jetbrains.annotations.NotNull String getMainLevelName(); - // Paper end - } -diff --git a/src/main/java/org/bukkit/WorldCreator.java b/src/main/java/org/bukkit/WorldCreator.java -index cbe6b3a1ba7b04826d97c3558e8eb4e5ba11f92f..cbdcac688afb7c13dd7058fa522bbd2c5adc445e 100644 ---- a/src/main/java/org/bukkit/WorldCreator.java -+++ b/src/main/java/org/bukkit/WorldCreator.java -@@ -12,6 +12,7 @@ import org.jetbrains.annotations.Nullable; - * Represents various types of options that may be used to create a world. - */ - public class WorldCreator { -+ private final NamespacedKey key; // Paper - private final String name; - private long seed; - private World.Environment environment = World.Environment.NORMAL; -@@ -28,13 +29,80 @@ public class WorldCreator { - * @param name Name of the world that will be created - */ - public WorldCreator(@NotNull String name) { -- if (name == null) { -- throw new IllegalArgumentException("World name cannot be null"); -+ // Paper start -+ this(name, getWorldKey(name)); -+ } -+ -+ private static NamespacedKey getWorldKey(String name) { -+ final String mainLevelName = Bukkit.getUnsafe().getMainLevelName(); -+ if (name.equals(mainLevelName)) { -+ return NamespacedKey.minecraft("overworld"); -+ } else if (name.equals(mainLevelName + "_nether")) { -+ return NamespacedKey.minecraft("the_nether"); -+ } else if (name.equals(mainLevelName + "_the_end")) { -+ return NamespacedKey.minecraft("the_end"); -+ } else { -+ return NamespacedKey.minecraft(name.toLowerCase(java.util.Locale.ENGLISH).replace(" ", "_")); - } -+ } - -- this.name = name; -+ /** -+ * Creates an empty WorldCreator for the given world name and key -+ * -+ * @param levelName LevelName of the world that will be created -+ * @param worldKey NamespacedKey of the world that will be created -+ */ -+ public WorldCreator(@NotNull String levelName, @NotNull NamespacedKey worldKey) { -+ if (levelName == null || worldKey == null) { -+ throw new IllegalArgumentException("World name and key cannot be null"); -+ } -+ this.name = levelName; - this.seed = (new Random()).nextLong(); -+ this.key = worldKey; -+ } -+ -+ /** -+ * Creates an empty WorldCreator for the given key. -+ * LevelName will be the Key part of the NamespacedKey. -+ * -+ * @param worldKey NamespacedKey of the world that will be created -+ */ -+ public WorldCreator(@NotNull NamespacedKey worldKey) { -+ this(worldKey.getKey(), worldKey); -+ } -+ -+ /** -+ * Gets the key for this WorldCreator -+ * -+ * @return the key -+ */ -+ @NotNull -+ public NamespacedKey key() { -+ return key; -+ } -+ -+ /** -+ * Creates an empty WorldCreator for the given world name and key -+ * -+ * @param levelName LevelName of the world that will be created -+ * @param worldKey NamespacedKey of the world that will be created -+ */ -+ @NotNull -+ public static WorldCreator ofNameAndKey(@NotNull String levelName, @NotNull NamespacedKey worldKey) { -+ return new WorldCreator(levelName, worldKey); -+ } -+ -+ /** -+ * Creates an empty WorldCreator for the given key. -+ * LevelName will be the Key part of the NamespacedKey. -+ * -+ * @param worldKey NamespacedKey of the world that will be created -+ */ -+ @NotNull -+ public static WorldCreator ofKey(@NotNull NamespacedKey worldKey) { -+ return new WorldCreator(worldKey); - } -+ // Paper end - - /** - * Copies the options from the specified world diff --git a/patches/api/0277-Improve-item-default-attribute-API.patch b/patches/api/0277-Improve-item-default-attribute-API.patch new file mode 100644 index 000000000000..1499e68a9a3a --- /dev/null +++ b/patches/api/0277-Improve-item-default-attribute-API.patch @@ -0,0 +1,99 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 8 May 2021 15:02:00 -0700 +Subject: [PATCH] Improve item default attribute API + + +diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java +index 5ae5c59f9375f10f2f035567b1bba8d3645f71fa..e8985981deb7d23ec624781725c4a05cc9cc94e7 100644 +--- a/src/main/java/org/bukkit/Material.java ++++ b/src/main/java/org/bukkit/Material.java +@@ -4860,6 +4860,23 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla + } + // Paper end - item rarity API + ++ // Paper start - item default attributes API ++ /** ++ * Returns an immutable multimap of attributes for the slot. ++ * {@link #isItem()} must be true for this material. ++ * ++ * @param equipmentSlot the slot to get the attributes for ++ * @throws IllegalArgumentException if {@link #isItem()} is false ++ * @return an immutable multimap of attributes ++ * @deprecated use {@link #getDefaultAttributeModifiers(EquipmentSlot)} ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.20.5") ++ public Multimap getItemAttributes(@NotNull EquipmentSlot equipmentSlot) { ++ return this.getDefaultAttributeModifiers(equipmentSlot); ++ } ++ // Paper end - item default attributes API ++ + /** + * Do not use for any reason. + * +@@ -5567,13 +5584,34 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla + } + } + ++ // Paper start - improve default item attribute API ++ /** ++ * Return an immutable copy of all default {@link Attribute}s and their {@link AttributeModifier}s. ++ *

      ++ * Default attributes are those that are always preset on some items, unless ++ * they are specifically overridden on that {@link ItemStack}. Examples include ++ * the attack damage on weapons or the armor value on armor. ++ *

      ++ * Only available when {@link #isItem()} is true. ++ * ++ * @return the immutable {@link Multimap} with the respective default ++ * Attributes and modifiers, or an empty map if no attributes are set. ++ */ ++ public @NotNull @org.jetbrains.annotations.Unmodifiable Multimap getDefaultAttributeModifiers() { ++ final ItemType type = this.asItemType(); ++ Preconditions.checkArgument(type != null, "The Material is not an item!"); ++ return type.getDefaultAttributeModifiers(); ++ } ++ // Paper end - improve default item attribute API ++ + /** + * Return an immutable copy of all default {@link Attribute}s and their + * {@link AttributeModifier}s for a given {@link EquipmentSlot}. +- * +- * Default attributes are those that are always preset on some items, such +- * as the attack damage on weapons or the armor value on armor. +- * ++ *

      ++ * Default attributes are those that are always preset on some items, unless ++ * they are specifically overridden on that {@link ItemStack}. Examples include ++ * the attack damage on weapons or the armor value on armor. ++ *

      + * Only available when {@link #isItem()} is true. + * + * @param slot the {@link EquipmentSlot} to check +diff --git a/src/main/java/org/bukkit/inventory/ItemType.java b/src/main/java/org/bukkit/inventory/ItemType.java +index 9f0f788cc81e8fc0b45bdd97e284d5a9785e7e8c..af30d6e619ae3c3556611a36229f676b34baeb0e 100644 +--- a/src/main/java/org/bukkit/inventory/ItemType.java ++++ b/src/main/java/org/bukkit/inventory/ItemType.java +@@ -2368,6 +2368,21 @@ public interface ItemType extends Keyed, Translatable, net.kyori.adventure.trans + // @NotNull + // EquipmentSlot getEquipmentSlot(); + ++ // Paper start - improve default item attribute API ++ /** ++ * Return an immutable copy of all default {@link Attribute}s and their ++ * {@link AttributeModifier}s. ++ *

      ++ * Default attributes are those that are always preset on some items, unless ++ * they are specifically overridden on that {@link ItemStack}. Examples include ++ * the attack damage on weapons or the armor value on armor. ++ * ++ * @return the immutable {@link Multimap} with the respective default ++ * Attributes and modifiers, or an empty map if no attributes are set. ++ */ ++ @NotNull @org.jetbrains.annotations.Unmodifiable Multimap getDefaultAttributeModifiers(); ++ // Paper end - improve default item attribute API ++ + /** + * Return an immutable copy of all default {@link Attribute}s and their + * {@link AttributeModifier}s for a given {@link EquipmentSlot}. diff --git a/patches/api/0305-Add-cause-to-Weather-ThunderChangeEvents.patch b/patches/api/0278-Add-cause-to-Weather-ThunderChangeEvents.patch similarity index 100% rename from patches/api/0305-Add-cause-to-Weather-ThunderChangeEvents.patch rename to patches/api/0278-Add-cause-to-Weather-ThunderChangeEvents.patch diff --git a/patches/api/0278-Item-Rarity-API.patch b/patches/api/0278-Item-Rarity-API.patch deleted file mode 100644 index a628e0f45f5b..000000000000 --- a/patches/api/0278-Item-Rarity-API.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 12 Mar 2021 17:09:40 -0800 -Subject: [PATCH] Item Rarity API - - -diff --git a/src/main/java/io/papermc/paper/inventory/ItemRarity.java b/src/main/java/io/papermc/paper/inventory/ItemRarity.java -new file mode 100644 -index 0000000000000000000000000000000000000000..74ef8395cc040ce488c2acaa416db20272cc2734 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/inventory/ItemRarity.java -@@ -0,0 +1,28 @@ -+package io.papermc.paper.inventory; -+ -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.format.TextColor; -+import org.jetbrains.annotations.NotNull; -+ -+public enum ItemRarity { -+ -+ COMMON(NamedTextColor.WHITE), -+ UNCOMMON(NamedTextColor.YELLOW), -+ RARE(NamedTextColor.AQUA), -+ EPIC(NamedTextColor.LIGHT_PURPLE); -+ -+ TextColor color; -+ -+ ItemRarity(TextColor color) { -+ this.color = color; -+ } -+ -+ /** -+ * Gets the color formatting associated with the rarity. -+ * @return -+ */ -+ @NotNull -+ public TextColor getColor() { -+ return color; -+ } -+} -diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index 4c8c21982f825bb70ff5e14098836215bdb0cd17..663452b8009d2899f8a196a20b6337024ce3caf0 100644 ---- a/src/main/java/org/bukkit/Material.java -+++ b/src/main/java/org/bukkit/Material.java -@@ -4143,6 +4143,17 @@ public enum Material implements Keyed, net.kyori.adventure.translation.Translata - public @NotNull String translationKey() { - return Bukkit.getUnsafe().getTranslationKey(this); - } -+ -+ /** -+ * Returns the item rarity for the item. The Material MUST be an Item not a block. -+ * Use {@link #isItem()} before this. -+ * -+ * @return the item rarity -+ */ -+ @NotNull -+ public io.papermc.paper.inventory.ItemRarity getItemRarity() { -+ return Bukkit.getUnsafe().getItemRarity(this); -+ } - // Paper end - - /** -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 204ab103eeff976d3da4f5694c31beafab6e1fdd..9616630817a3a302636a0d2fe8076cb7244b7996 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -162,5 +162,22 @@ public interface UnsafeValues { - * Just don't use it. - */ - @org.jetbrains.annotations.NotNull String getMainLevelName(); -+ -+ /** -+ * Gets the item rarity of a material. The material MUST be an item. -+ * Use {@link Material#isItem()} before this. -+ * -+ * @param material the material to get the rarity of -+ * @return the item rarity -+ */ -+ public io.papermc.paper.inventory.ItemRarity getItemRarity(Material material); -+ -+ /** -+ * Gets the item rarity of the itemstack. The rarity can change based on enchantements. -+ * -+ * @param itemStack the itemstack to get the rarity of -+ * @return the itemstack rarity -+ */ -+ public io.papermc.paper.inventory.ItemRarity getItemStackRarity(ItemStack itemStack); - // Paper end - } -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index d6eafaa58b19ab44dfdef1baa58fa89c5b761b65..75bd1f7a5a30d21ae61836072ec057a95b7c288b 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -883,5 +883,15 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - public @NotNull String translationKey() { - return Bukkit.getUnsafe().getTranslationKey(this); - } -+ -+ /** -+ * Gets the item rarity of the itemstack. The rarity can change based on enchantements. -+ * -+ * @return the itemstack rarity -+ */ -+ @NotNull -+ public io.papermc.paper.inventory.ItemRarity getRarity() { -+ return Bukkit.getUnsafe().getItemStackRarity(this); -+ } - // Paper end - } diff --git a/patches/api/0279-Expose-protocol-version.patch b/patches/api/0279-Expose-protocol-version.patch deleted file mode 100644 index 79071d45af6e..000000000000 --- a/patches/api/0279-Expose-protocol-version.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Fri, 26 Mar 2021 11:23:27 +0100 -Subject: [PATCH] Expose protocol version - - -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 9616630817a3a302636a0d2fe8076cb7244b7996..eadba6454530724619872034f6e680b4603b8a69 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -179,5 +179,12 @@ public interface UnsafeValues { - * @return the itemstack rarity - */ - public io.papermc.paper.inventory.ItemRarity getItemStackRarity(ItemStack itemStack); -+ -+ /** -+ * Returns the server's protocol version. -+ * -+ * @return the server's protocol version -+ */ -+ int getProtocolVersion(); - // Paper end - } diff --git a/patches/api/0306-More-Lidded-Block-API.patch b/patches/api/0279-More-Lidded-Block-API.patch similarity index 100% rename from patches/api/0306-More-Lidded-Block-API.patch rename to patches/api/0279-More-Lidded-Block-API.patch diff --git a/patches/api/0280-Add-PlayerKickEvent-causes.patch b/patches/api/0280-Add-PlayerKickEvent-causes.patch new file mode 100644 index 000000000000..b4e2db753a4a --- /dev/null +++ b/patches/api/0280-Add-PlayerKickEvent-causes.patch @@ -0,0 +1,144 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 15 May 2021 20:30:34 -0700 +Subject: [PATCH] Add PlayerKickEvent causes + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index e827e8e6a346a6e4b33a9f155e92264955a4a496..68c470b9504a8b731606a1d297de223235b55cb9 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -335,6 +335,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param message kick message + */ + void kick(final net.kyori.adventure.text.@Nullable Component message); ++ ++ /** ++ * Kicks player with custom kick message and cause. ++ * ++ * @param message kick message ++ * @param cause kick cause ++ */ ++ void kick(final net.kyori.adventure.text.@Nullable Component message, org.bukkit.event.player.PlayerKickEvent.@NotNull Cause cause); + // Paper end + + /** +diff --git a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java +index 997b06c19a5277656521e0e298f2958c209f1da1..b8bf61bea73086c61dce6230686e627dc324ebe0 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java +@@ -12,6 +12,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private net.kyori.adventure.text.Component leaveMessage; // Paper + private net.kyori.adventure.text.Component kickReason; // Paper ++ private final Cause cause; // Paper + private boolean cancel; + + @Deprecated // Paper +@@ -19,14 +20,26 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + super(playerKicked); + this.kickReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(kickReason); // Paper + this.leaveMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(leaveMessage); // Paper ++ this.cause = Cause.UNKNOWN; // Paper + this.cancel = false; + } + // Paper start ++ @Deprecated + public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final net.kyori.adventure.text.Component kickReason, @NotNull final net.kyori.adventure.text.Component leaveMessage) { + super(playerKicked); + this.kickReason = kickReason; + this.leaveMessage = leaveMessage; + this.cancel = false; ++ this.cause = Cause.UNKNOWN; ++ } ++ ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final net.kyori.adventure.text.Component kickReason, @NotNull final net.kyori.adventure.text.Component leaveMessage, @NotNull final Cause cause) { ++ super(playerKicked); ++ this.kickReason = kickReason; ++ this.leaveMessage = leaveMessage; ++ this.cancel = false; ++ this.cause = cause; + } + + /** +@@ -132,4 +145,79 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + public static HandlerList getHandlerList() { + return handlers; + } ++ // Paper start ++ /** ++ * Gets the cause of this kick ++ * ++ * @return ++ */ ++ @NotNull ++ public org.bukkit.event.player.PlayerKickEvent.Cause getCause() { ++ return cause; ++ } ++ ++ public enum Cause { ++ ++ PLUGIN, ++ ++ WHITELIST, ++ ++ BANNED, ++ ++ IP_BANNED, ++ ++ KICK_COMMAND, ++ ++ FLYING_PLAYER, ++ ++ FLYING_VEHICLE, ++ ++ TIMEOUT, ++ ++ IDLING, ++ ++ INVALID_VEHICLE_MOVEMENT, ++ ++ INVALID_PLAYER_MOVEMENT, ++ ++ INVALID_ENTITY_ATTACKED, ++ ++ INVALID_PAYLOAD, ++ ++ INVALID_COOKIE, ++ ++ SPAM, ++ ++ ILLEGAL_ACTION, ++ ++ ILLEGAL_CHARACTERS, ++ ++ OUT_OF_ORDER_CHAT, ++ ++ UNSIGNED_CHAT, ++ ++ CHAT_VALIDATION_FAILED, ++ ++ EXPIRED_PROFILE_PUBLIC_KEY, ++ ++ INVALID_PUBLIC_KEY_SIGNATURE, ++ ++ TOO_MANY_PENDING_CHATS, ++ ++ SELF_INTERACTION, ++ ++ DUPLICATE_LOGIN, ++ ++ RESOURCE_PACK_REJECTION, ++ ++ /** ++ * Spigot's restart command ++ */ ++ RESTART_COMMAND, ++ /** ++ * Fallback cause ++ */ ++ UNKNOWN, ++ } ++ // Paper end + } diff --git a/patches/api/0280-Allow-for-Component-suggestion-tooltips-in-AsyncTabC.patch b/patches/api/0280-Allow-for-Component-suggestion-tooltips-in-AsyncTabC.patch deleted file mode 100644 index 3649c64a0915..000000000000 --- a/patches/api/0280-Allow-for-Component-suggestion-tooltips-in-AsyncTabC.patch +++ /dev/null @@ -1,407 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Thu, 1 Apr 2021 00:34:41 -0700 -Subject: [PATCH] Allow for Component suggestion tooltips in - AsyncTabCompleteEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java -index a135a9bfb2ccc8842baa9d5760fa05b7b1a529b1..9be64a95c2345433b6142d611077dedadcef9f5d 100644 ---- a/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java -+++ b/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java -@@ -24,6 +24,11 @@ - package com.destroystokyo.paper.event.server; - - import com.google.common.base.Preconditions; -+import io.papermc.paper.util.TransformingRandomAccessList; -+import net.kyori.adventure.text.Component; -+import net.kyori.examination.Examinable; -+import net.kyori.examination.ExaminableProperty; -+import net.kyori.examination.string.StringExaminer; - import org.bukkit.Location; - import org.bukkit.command.Command; - import org.bukkit.command.CommandSender; -@@ -33,6 +38,7 @@ import org.bukkit.event.HandlerList; - - import java.util.ArrayList; - import java.util.List; -+import java.util.stream.Stream; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; - -@@ -47,15 +53,29 @@ public class AsyncTabCompleteEvent extends Event implements Cancellable { - private final boolean isCommand; - @Nullable - private final Location loc; -- @NotNull private List completions; -+ private final List completions = new ArrayList<>(); -+ private final List stringCompletions = new TransformingRandomAccessList<>( -+ this.completions, -+ Completion::suggestion, -+ Completion::completion -+ ); - private boolean cancelled; - private boolean handled = false; - private boolean fireSyncHandler = true; - -+ public AsyncTabCompleteEvent(@NotNull CommandSender sender, @NotNull String buffer, boolean isCommand, @Nullable Location loc) { -+ super(true); -+ this.sender = sender; -+ this.buffer = buffer; -+ this.isCommand = isCommand; -+ this.loc = loc; -+ } -+ -+ @Deprecated - public AsyncTabCompleteEvent(@NotNull CommandSender sender, @NotNull List completions, @NotNull String buffer, boolean isCommand, @Nullable Location loc) { - super(true); - this.sender = sender; -- this.completions = completions; -+ this.completions.addAll(fromStrings(completions)); - this.buffer = buffer; - this.isCommand = isCommand; - this.loc = loc; -@@ -83,7 +103,7 @@ public class AsyncTabCompleteEvent extends Event implements Cancellable { - */ - @NotNull - public List getCompletions() { -- return completions; -+ return this.stringCompletions; - } - - /** -@@ -97,8 +117,42 @@ public class AsyncTabCompleteEvent extends Event implements Cancellable { - * @param completions the new completions - */ - public void setCompletions(@NotNull List completions) { -+ if (completions == this.stringCompletions) { -+ return; -+ } - Preconditions.checkNotNull(completions); -- this.completions = new ArrayList<>(completions); -+ this.completions.clear(); -+ this.completions.addAll(fromStrings(completions)); -+ } -+ -+ /** -+ * The list of {@link Completion completions} which will be offered to the sender, in order. -+ * This list is mutable and reflects what will be offered. -+ *

      -+ * If this collection is not empty after the event is fired, then -+ * the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} -+ * or current player names will not be called. -+ * -+ * @return a list of offered completions -+ */ -+ public @NotNull List completions() { -+ return this.completions; -+ } -+ -+ /** -+ * Set the {@link Completion completions} offered, overriding any already set. -+ * If this collection is not empty after the event is fired, then -+ * the standard process of calling {@link Command#tabComplete(CommandSender, String, String[])} -+ * or current player names will not be called. -+ *

      -+ * The passed collection will be cloned to a new List. You must call {{@link #completions()}} to mutate from here -+ * -+ * @param newCompletions the new completions -+ */ -+ public void completions(final @NotNull List newCompletions) { -+ Preconditions.checkNotNull(newCompletions, "new completions"); -+ this.completions.clear(); -+ this.completions.addAll(newCompletions); - } - - /** -@@ -173,4 +227,102 @@ public class AsyncTabCompleteEvent extends Event implements Cancellable { - public static HandlerList getHandlerList() { - return handlers; - } -+ -+ private static @NotNull List fromStrings(final @NotNull List strings) { -+ final List list = new ArrayList<>(); -+ for (final String it : strings) { -+ list.add(new CompletionImpl(it, null)); -+ } -+ return list; -+ } -+ -+ /** -+ * A rich tab completion, consisting of a string suggestion, and a nullable {@link Component} tooltip. -+ */ -+ public interface Completion extends Examinable { -+ /** -+ * Get the suggestion string for this {@link Completion}. -+ * -+ * @return suggestion string -+ */ -+ @NotNull String suggestion(); -+ -+ /** -+ * Get the suggestion tooltip for this {@link Completion}. -+ * -+ * @return tooltip component -+ */ -+ @Nullable Component tooltip(); -+ -+ @Override -+ default @NotNull Stream examinableProperties() { -+ return Stream.of(ExaminableProperty.of("suggestion", this.suggestion()), ExaminableProperty.of("tooltip", this.tooltip())); -+ } -+ -+ /** -+ * Create a new {@link Completion} from a suggestion string. -+ * -+ * @param suggestion suggestion string -+ * @return new completion instance -+ */ -+ static @NotNull Completion completion(final @NotNull String suggestion) { -+ return new CompletionImpl(suggestion, null); -+ } -+ -+ /** -+ * Create a new {@link Completion} from a suggestion string and a tooltip {@link Component}. -+ * -+ *

      If the provided component is null, the suggestion will not have a tooltip.

      -+ * -+ * @param suggestion suggestion string -+ * @param tooltip tooltip component, or null -+ * @return new completion instance -+ */ -+ static @NotNull Completion completion(final @NotNull String suggestion, final @Nullable Component tooltip) { -+ return new CompletionImpl(suggestion, tooltip); -+ } -+ } -+ -+ static final class CompletionImpl implements Completion { -+ private final String suggestion; -+ private final Component tooltip; -+ -+ CompletionImpl(final @NotNull String suggestion, final @Nullable Component tooltip) { -+ this.suggestion = suggestion; -+ this.tooltip = tooltip; -+ } -+ -+ @Override -+ public @NotNull String suggestion() { -+ return this.suggestion; -+ } -+ -+ @Override -+ public @Nullable Component tooltip() { -+ return this.tooltip; -+ } -+ -+ @Override -+ public boolean equals(final @Nullable Object o) { -+ if (this == o) { -+ return true; -+ } -+ if (o == null || this.getClass() != o.getClass()) { -+ return false; -+ } -+ final CompletionImpl that = (CompletionImpl) o; -+ return this.suggestion.equals(that.suggestion) -+ && java.util.Objects.equals(this.tooltip, that.tooltip); -+ } -+ -+ @Override -+ public int hashCode() { -+ return java.util.Objects.hash(this.suggestion, this.tooltip); -+ } -+ -+ @Override -+ public @NotNull String toString() { -+ return StringExaminer.simpleEscaping().examine(this); -+ } -+ } - } -diff --git a/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java b/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6f560a51277ccbd46a9142cfa057d276118c1c7b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java -@@ -0,0 +1,169 @@ -+package io.papermc.paper.util; -+ -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.AbstractList; -+import java.util.Iterator; -+import java.util.List; -+import java.util.ListIterator; -+import java.util.RandomAccess; -+import java.util.function.Function; -+import java.util.function.Predicate; -+ -+import static com.google.common.base.Preconditions.checkNotNull; -+ -+/** -+ * Modified version of the Guava class with the same name to support add operations. -+ * -+ * @param backing list element type -+ * @param transformed list element type -+ */ -+public final class TransformingRandomAccessList extends AbstractList implements RandomAccess { -+ final List fromList; -+ final Function toFunction; -+ final Function fromFunction; -+ -+ /** -+ * Create a new {@link TransformingRandomAccessList}. -+ * -+ * @param fromList backing list -+ * @param toFunction function mapping backing list element type to transformed list element type -+ * @param fromFunction function mapping transformed list element type to backing list element type -+ */ -+ public TransformingRandomAccessList( -+ final @NonNull List fromList, -+ final @NonNull Function toFunction, -+ final @NonNull Function fromFunction -+ ) { -+ this.fromList = checkNotNull(fromList); -+ this.toFunction = checkNotNull(toFunction); -+ this.fromFunction = checkNotNull(fromFunction); -+ } -+ -+ @Override -+ public void clear() { -+ this.fromList.clear(); -+ } -+ -+ @Override -+ public T get(int index) { -+ return this.toFunction.apply(this.fromList.get(index)); -+ } -+ -+ @Override -+ public @NotNull Iterator iterator() { -+ return this.listIterator(); -+ } -+ -+ @Override -+ public @NotNull ListIterator listIterator(int index) { -+ return new TransformedListIterator(this.fromList.listIterator(index)) { -+ @Override -+ T transform(F from) { -+ return TransformingRandomAccessList.this.toFunction.apply(from); -+ } -+ -+ @Override -+ F transformBack(T from) { -+ return TransformingRandomAccessList.this.fromFunction.apply(from); -+ } -+ }; -+ } -+ -+ @Override -+ public boolean isEmpty() { -+ return this.fromList.isEmpty(); -+ } -+ -+ @Override -+ public boolean removeIf(Predicate filter) { -+ checkNotNull(filter); -+ return this.fromList.removeIf(element -> filter.test(this.toFunction.apply(element))); -+ } -+ -+ @Override -+ public T remove(int index) { -+ return this.toFunction.apply(this.fromList.remove(index)); -+ } -+ -+ @Override -+ public int size() { -+ return this.fromList.size(); -+ } -+ -+ @Override -+ public T set(int i, T t) { -+ return this.toFunction.apply(this.fromList.set(i, this.fromFunction.apply(t))); -+ } -+ -+ @Override -+ public void add(int i, T t) { -+ this.fromList.add(i, this.fromFunction.apply(t)); -+ } -+ -+ static abstract class TransformedListIterator implements ListIterator, Iterator { -+ final Iterator backingIterator; -+ -+ TransformedListIterator(ListIterator backingIterator) { -+ this.backingIterator = checkNotNull((Iterator) backingIterator); -+ } -+ -+ private ListIterator backingIterator() { -+ return cast(this.backingIterator); -+ } -+ -+ static ListIterator cast(Iterator iterator) { -+ return (ListIterator) iterator; -+ } -+ -+ @Override -+ public final boolean hasPrevious() { -+ return this.backingIterator().hasPrevious(); -+ } -+ -+ @Override -+ public final T previous() { -+ return this.transform(this.backingIterator().previous()); -+ } -+ -+ @Override -+ public final int nextIndex() { -+ return this.backingIterator().nextIndex(); -+ } -+ -+ @Override -+ public final int previousIndex() { -+ return this.backingIterator().previousIndex(); -+ } -+ -+ @Override -+ public void set(T element) { -+ this.backingIterator().set(this.transformBack(element)); -+ } -+ -+ @Override -+ public void add(T element) { -+ this.backingIterator().add(this.transformBack(element)); -+ } -+ -+ abstract T transform(F from); -+ -+ abstract F transformBack(T to); -+ -+ @Override -+ public final boolean hasNext() { -+ return this.backingIterator.hasNext(); -+ } -+ -+ @Override -+ public final T next() { -+ return this.transform(this.backingIterator.next()); -+ } -+ -+ @Override -+ public final void remove() { -+ this.backingIterator.remove(); -+ } -+ } -+} -diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java -index 93498307004b68b934fbfa1aeb3aaf0e97cbdac7..bbe81f7a420f913ffdcad913a3c43ff41ead41f5 100644 ---- a/src/test/java/org/bukkit/AnnotationTest.java -+++ b/src/test/java/org/bukkit/AnnotationTest.java -@@ -48,6 +48,8 @@ public class AnnotationTest { - // Generic functional interface - "org/bukkit/util/Consumer", - // Paper start -+ "io/papermc/paper/util/TransformingRandomAccessList", -+ "io/papermc/paper/util/TransformingRandomAccessList$TransformedListIterator", - // Timings history is broken in terms of nullability due to guavas Function defining that the param is NonNull - "co/aikar/timings/TimingHistory$2", - "co/aikar/timings/TimingHistory$2$1", diff --git a/patches/api/0281-Add-PufferFishStateChangeEvent.patch b/patches/api/0281-Add-PufferFishStateChangeEvent.patch new file mode 100644 index 000000000000..30808a75a1f3 --- /dev/null +++ b/patches/api/0281-Add-PufferFishStateChangeEvent.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: HexedHero <6012891+HexedHero@users.noreply.github.com> +Date: Mon, 10 May 2021 16:58:38 +0100 +Subject: [PATCH] Add PufferFishStateChangeEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/PufferFishStateChangeEvent.java b/src/main/java/io/papermc/paper/event/entity/PufferFishStateChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b4521d64eefd8f871f8ce78734e6626896e8b0d0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/PufferFishStateChangeEvent.java +@@ -0,0 +1,85 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.entity.PufferFish; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called just before a {@link PufferFish} inflates or deflates. ++ */ ++@NullMarked ++public class PufferFishStateChangeEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final int newPuffState; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PufferFishStateChangeEvent(final PufferFish entity, final int newPuffState) { ++ super(entity); ++ this.newPuffState = newPuffState; ++ } ++ ++ @Override ++ public PufferFish getEntity() { ++ return (PufferFish) super.getEntity(); ++ } ++ ++ /** ++ * Get the new puff state of the {@link PufferFish}. ++ *

      ++ * This is what the {@link PufferFish}'s new puff state will be after this event if it isn't cancelled.
      ++ * Refer to {@link PufferFish#getPuffState()} to get the current puff state. ++ * ++ * @return The new puff state, 0 being not inflated, 1 being slightly inflated and 2 being fully inflated ++ */ ++ public int getNewPuffState() { ++ return this.newPuffState; ++ } ++ ++ /** ++ * Get if the {@link PufferFish} is going to inflate. ++ * ++ * @return If it's going to inflate ++ */ ++ public boolean isInflating() { ++ return this.newPuffState > this.getEntity().getPuffState(); ++ } ++ ++ /** ++ * Get if the {@link PufferFish} is going to deflate. ++ * ++ * @return If it's going to deflate ++ */ ++ public boolean isDeflating() { ++ return this.newPuffState < this.getEntity().getPuffState(); ++ } ++ ++ /** ++ * Set whether to cancel the {@link PufferFish} (in/de)flating. ++ * ++ * @param cancel {@code true} if you wish to cancel the (in/de)flation ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0281-add-isDeeplySleeping-to-HumanEntity.patch b/patches/api/0281-add-isDeeplySleeping-to-HumanEntity.patch deleted file mode 100644 index cf7ca8b27cf6..000000000000 --- a/patches/api/0281-add-isDeeplySleeping-to-HumanEntity.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 8 Apr 2021 17:36:15 -0700 -Subject: [PATCH] add isDeeplySleeping to HumanEntity - - -diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java -index ebbe3417369201df231060dd39f1fb200eb7ad48..e8b6cfe7e454c666b4d60b702a3b211dab238830 100644 ---- a/src/main/java/org/bukkit/entity/HumanEntity.java -+++ b/src/main/java/org/bukkit/entity/HumanEntity.java -@@ -327,6 +327,15 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder - */ - public void setCooldown(@NotNull Material material, int ticks); - -+ // Paper start -+ /** -+ * If the player has slept enough to count towards passing the night. -+ * -+ * @return true if the player has slept enough -+ */ -+ public boolean isDeeplySleeping(); -+ // Paper end -+ - /** - * Get the sleep ticks of the player. This value may be capped. - * diff --git a/patches/api/0282-Add-BellRevealRaiderEvent.patch b/patches/api/0282-Add-BellRevealRaiderEvent.patch new file mode 100644 index 000000000000..28a1acab6091 --- /dev/null +++ b/patches/api/0282-Add-BellRevealRaiderEvent.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 26 May 2021 17:08:57 -0400 +Subject: [PATCH] Add BellRevealRaiderEvent + + +diff --git a/src/main/java/io/papermc/paper/event/block/BellRevealRaiderEvent.java b/src/main/java/io/papermc/paper/event/block/BellRevealRaiderEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4781529aaa4b2ea104df3b9cd055668278344df7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BellRevealRaiderEvent.java +@@ -0,0 +1,63 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.block.Block; ++import org.bukkit.entity.Raider; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Called when a {@link Raider} is revealed by a bell. ++ * ++ * @deprecated use {@link org.bukkit.event.block.BellResonateEvent} ++ */ ++@Deprecated(since = "1.19.4") ++public class BellRevealRaiderEvent extends BlockEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Raider raider; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public BellRevealRaiderEvent(@NotNull Block theBlock, @NotNull Raider raider) { ++ super(theBlock); ++ this.raider = raider; ++ } ++ ++ /** ++ * Gets the raider that the bell revealed. ++ * ++ * @return The raider ++ */ ++ @NotNull ++ public Raider getEntity() { ++ return this.raider; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * {@inheritDoc} ++ *

      ++ * This does not cancel the particle effects shown on the bell, only the entity. ++ */ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public @NotNull HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static @NotNull HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0282-add-consumeFuel-to-FurnaceBurnEvent.patch b/patches/api/0282-add-consumeFuel-to-FurnaceBurnEvent.patch deleted file mode 100644 index 6c8b681cd94c..000000000000 --- a/patches/api/0282-add-consumeFuel-to-FurnaceBurnEvent.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 22 Apr 2021 16:45:15 -0700 -Subject: [PATCH] add consumeFuel to FurnaceBurnEvent - - -diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java -index bc71bc2d3ace0d19d730c09f05f9e0655bcee8f5..caef53d0f6546516fa7aabb2cb3abed70808b3ba 100644 ---- a/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java -+++ b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java -@@ -16,6 +16,7 @@ public class FurnaceBurnEvent extends BlockEvent implements Cancellable { - private int burnTime; - private boolean cancelled; - private boolean burning; -+ private boolean consumeFuel = true; // Paper - - public FurnaceBurnEvent(@NotNull final Block furnace, @NotNull final ItemStack fuel, final int burnTime) { - super(furnace); -@@ -70,6 +71,25 @@ public class FurnaceBurnEvent extends BlockEvent implements Cancellable { - public void setBurning(boolean burning) { - this.burning = burning; - } -+ // Paper start -+ /** -+ * Gets whether the furnace's fuel will be consumed or not. -+ * -+ * @return whether the furnace's fuel will be consumed -+ */ -+ public boolean willConsumeFuel() { -+ return consumeFuel; -+ } -+ -+ /** -+ * Sets whether the furnace's fuel will be consumed or not. -+ * -+ * @param consumeFuel true to consume the fuel -+ */ -+ public void setConsumeFuel(boolean consumeFuel) { -+ this.consumeFuel = consumeFuel; -+ } -+ // Paper end - - @Override - public boolean isCancelled() { diff --git a/patches/api/0283-Add-ElderGuardianAppearanceEvent.patch b/patches/api/0283-Add-ElderGuardianAppearanceEvent.patch new file mode 100644 index 000000000000..ae955211a95e --- /dev/null +++ b/patches/api/0283-Add-ElderGuardianAppearanceEvent.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Fri, 19 Mar 2021 23:39:21 -0400 +Subject: [PATCH] Add ElderGuardianAppearanceEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/ElderGuardianAppearanceEvent.java b/src/main/java/io/papermc/paper/event/entity/ElderGuardianAppearanceEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..027e70a1085a84669af0bb10e7f11ad3ca1ad299 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/ElderGuardianAppearanceEvent.java +@@ -0,0 +1,65 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.entity.ElderGuardian; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Is called when an {@link ElderGuardian} appears in front of a {@link Player}. ++ */ ++@NullMarked ++public class ElderGuardianAppearanceEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Player affectedPlayer; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public ElderGuardianAppearanceEvent(final ElderGuardian guardian, final Player affectedPlayer) { ++ super(guardian); ++ this.affectedPlayer = affectedPlayer; ++ } ++ ++ /** ++ * Get the player affected by the guardian appearance. ++ * ++ * @return Player affected by the appearance ++ */ ++ public Player getAffectedPlayer() { ++ return this.affectedPlayer; ++ } ++ ++ /** ++ * The elder guardian playing the effect. ++ * ++ * @return The elder guardian ++ */ ++ @Override ++ public ElderGuardian getEntity() { ++ return (ElderGuardian) super.getEntity(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0283-add-get-set-drop-chance-to-EntityEquipment.patch b/patches/api/0283-add-get-set-drop-chance-to-EntityEquipment.patch deleted file mode 100644 index c42542a19542..000000000000 --- a/patches/api/0283-add-get-set-drop-chance-to-EntityEquipment.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 22 Apr 2021 00:28:20 -0700 -Subject: [PATCH] add get-set drop chance to EntityEquipment - - -diff --git a/src/main/java/org/bukkit/inventory/EntityEquipment.java b/src/main/java/org/bukkit/inventory/EntityEquipment.java -index 42f76751ec414648ee719c341d471d947bf85be6..58d52f6e1660ebdb098566a2ae6b50c8b44dc0d9 100644 ---- a/src/main/java/org/bukkit/inventory/EntityEquipment.java -+++ b/src/main/java/org/bukkit/inventory/EntityEquipment.java -@@ -513,4 +513,32 @@ public interface EntityEquipment { - */ - @NotNull // Paper - Entity getHolder(); -+ // Paper start -+ /** -+ * Gets the drop chance of specified slot. -+ * -+ *

        -+ *
      • A drop chance of 0.0F will never drop -+ *
      • A drop chance of 1.0F will always drop -+ *
      -+ * -+ * @param slot the slot to get the drop chance of -+ * @return the drop chance for the slot -+ */ -+ float getDropChance(@NotNull EquipmentSlot slot); -+ -+ /** -+ * Sets the drop chance of the specified slot. -+ * -+ *
        -+ *
      • A drop chance of 0.0F will never drop -+ *
      • A drop chance of 1.0F will always drop -+ *
      -+ * -+ * @param slot the slot to set the drop chance of -+ * @param chance the drop chance for the slot -+ * @throws UnsupportedOperationException when called on non-{@link Mob} entities -+ */ -+ void setDropChance(@NotNull EquipmentSlot slot, float chance); -+ // Paper end - } diff --git a/patches/api/0284-Add-more-line-of-sight-methods.patch b/patches/api/0284-Add-more-line-of-sight-methods.patch new file mode 100644 index 000000000000..f5c861f8ae0b --- /dev/null +++ b/patches/api/0284-Add-more-line-of-sight-methods.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TwoLeggedCat <80929284+TwoLeggedCat@users.noreply.github.com> +Date: Sat, 29 May 2021 14:33:18 -0500 +Subject: [PATCH] Add more line of sight methods + + +diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java +index d8b1fa79dc24138dc71e32c14bda71c1d570ed88..b68367f123f029c3ff47eab6bfabd7a894a99da4 100644 +--- a/src/main/java/org/bukkit/RegionAccessor.java ++++ b/src/main/java/org/bukkit/RegionAccessor.java +@@ -461,5 +461,13 @@ public interface RegionAccessor extends Keyed { // Paper + @NotNull + @Override + NamespacedKey getKey(); ++ ++ /** ++ * Tell whether a line of sight exists between the given locations ++ * @param from Location to start at ++ * @param to target Location ++ * @return whether a line of sight exists between {@code from} and {@code to} ++ */ ++ public boolean lineOfSightExists(@NotNull Location from, @NotNull Location to); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index a50b0b83708794e86ba83d1d2337296deb351da6..5db673a0572163574c41bd7827572372411142ed 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -622,6 +622,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + public boolean hasLineOfSight(@NotNull Entity other); + ++ // Paper start ++ /** ++ * Checks whether the living entity has block line of sight to the given block. ++ *

      ++ * This uses the same algorithm that hostile mobs use to find the closest ++ * player. ++ * ++ * @param location the location to determine line of sight to ++ * @return true if there is a line of sight, false if not ++ */ ++ public boolean hasLineOfSight(@NotNull Location location); ++ // Paper end ++ + /** + * Returns if the living entity despawns when away from players or not. + *

      diff --git a/patches/api/0284-Added-PlayerDeepSleepEvent.patch b/patches/api/0284-Added-PlayerDeepSleepEvent.patch deleted file mode 100644 index d8dccca755a1..000000000000 --- a/patches/api/0284-Added-PlayerDeepSleepEvent.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 21 Apr 2021 15:58:25 -0700 -Subject: [PATCH] Added PlayerDeepSleepEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerDeepSleepEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerDeepSleepEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e3ee540bb0a5bc578b148fbcf8b5e39ab9c8575c ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerDeepSleepEvent.java -@@ -0,0 +1,46 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player has slept long enough -+ * to count as passing the night/storm. -+ *

      -+ * Cancelling this event will prevent the player from being counted as deeply sleeping -+ * unless they exit and re-enter the bed. -+ */ -+public class PlayerDeepSleepEvent extends PlayerEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private boolean cancelled; -+ -+ public PlayerDeepSleepEvent(@NotNull Player player) { -+ super(player); -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} diff --git a/patches/api/0285-Add-WaterBottleSplashEvent.patch b/patches/api/0285-Add-WaterBottleSplashEvent.patch new file mode 100644 index 000000000000..8eda8d586d8f --- /dev/null +++ b/patches/api/0285-Add-WaterBottleSplashEvent.patch @@ -0,0 +1,160 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Thu, 8 Dec 2022 10:12:23 -0700 +Subject: [PATCH] Add WaterBottleSplashEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/WaterBottleSplashEvent.java b/src/main/java/io/papermc/paper/event/entity/WaterBottleSplashEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1f74ea11c726273c3c2a7fc6f381716e230ef5c9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/WaterBottleSplashEvent.java +@@ -0,0 +1,135 @@ ++package io.papermc.paper.event.entity; ++ ++import java.util.Collection; ++import java.util.Map; ++import java.util.Set; ++import java.util.stream.Collectors; ++import org.bukkit.block.Block; ++import org.bukkit.block.BlockFace; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.entity.ThrownPotion; ++import org.bukkit.event.entity.PotionSplashEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Unmodifiable; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when a splash water potion "splashes" and affects ++ * different entities in different ways. ++ */ ++@NullMarked ++public class WaterBottleSplashEvent extends PotionSplashEvent { ++ ++ private final Set rehydrate; ++ private final Set extinguish; ++ ++ @ApiStatus.Internal ++ public WaterBottleSplashEvent( ++ final ThrownPotion potion, ++ final @Nullable Entity hitEntity, ++ final @Nullable Block hitBlock, ++ final @Nullable BlockFace hitFace, ++ final Map affectedEntities, ++ final Set rehydrate, ++ final Set extinguish ++ ) { ++ super(potion, hitEntity, hitBlock, hitFace, affectedEntities); ++ this.rehydrate = rehydrate; ++ this.extinguish = extinguish; ++ } ++ ++ /** ++ * Gets an immutable collection of entities that ++ * will take damage as a result of this event. Use ++ * other methods on this class to modify which entities ++ * take damage. ++ * ++ * @return an immutable collection of entities ++ * @see #doNotDamageAsWaterSensitive(LivingEntity) ++ * @see #damageAsWaterSensitive(LivingEntity) ++ */ ++ public @Unmodifiable Collection getToDamage() { ++ return this.affectedEntities.entrySet().stream().filter(entry -> entry.getValue() > 0).map(Map.Entry::getKey).collect(Collectors.toUnmodifiableSet()); ++ } ++ ++ /** ++ * Removes this entity from the group that ++ * will be damaged. ++ * ++ * @param entity entity to remove ++ */ ++ public void doNotDamageAsWaterSensitive(final LivingEntity entity) { ++ this.affectedEntities.remove(entity); ++ } ++ ++ /** ++ * Adds this entity to the group that ++ * will be damaged ++ * ++ * @param entity entity to add ++ */ ++ public void damageAsWaterSensitive(final LivingEntity entity) { ++ this.affectedEntities.put(entity, 1.0); ++ } ++ ++ /** ++ * Get a mutable collection of entities ++ * that will be rehydrated by this. ++ *

      ++ * As of 1.19.3 this only will contain Axolotls as they ++ * are the only entity type that can be rehydrated, but ++ * it may change in the future. ++ * ++ * @return the entities ++ */ ++ public Collection getToRehydrate() { ++ return this.rehydrate; ++ } ++ ++ /** ++ * Get a mutable collection of entities that will ++ * be extinguished as a result of this event. ++ * ++ * @return entities to be extinguished ++ */ ++ public Collection getToExtinguish() { ++ return this.extinguish; ++ } ++ ++ /** ++ * @return a confusing collection, don't use it ++ * @deprecated Use {@link #getToDamage()} ++ */ ++ @Deprecated(since = "1.19.3") ++ @Override ++ public Collection getAffectedEntities() { ++ return super.getAffectedEntities(); ++ } ++ ++ /** ++ * Doesn't make sense for this event as intensity doesn't vary. ++ * ++ * @return a confusing value ++ * @deprecated check if {@link #getToDamage()} contains an entity ++ */ ++ @Deprecated(since = "1.19.3") ++ @Override ++ public double getIntensity(final LivingEntity entity) { ++ return super.getIntensity(entity); ++ } ++ ++ /** ++ * Doesn't make sense for this event as intensity doesn't vary. ++ * ++ * @deprecated use {@link #damageAsWaterSensitive(LivingEntity)} ++ * or {@link #doNotDamageAsWaterSensitive(LivingEntity)} to change which entities are ++ * damaged ++ */ ++ @Deprecated(since = "1.19.3") ++ @Override ++ public void setIntensity(final LivingEntity entity, final double intensity) { ++ super.setIntensity(entity, intensity); ++ } ++} +diff --git a/src/main/java/org/bukkit/event/entity/PotionSplashEvent.java b/src/main/java/org/bukkit/event/entity/PotionSplashEvent.java +index ef6b3a5f6a2c5238f04072cd0bd0c421c9da07ca..f079cd30b2117a0c120bd0e196dca09f7b6eb7f2 100644 +--- a/src/main/java/org/bukkit/event/entity/PotionSplashEvent.java ++++ b/src/main/java/org/bukkit/event/entity/PotionSplashEvent.java +@@ -20,7 +20,7 @@ import org.jetbrains.annotations.Nullable; + public class PotionSplashEvent extends ProjectileHitEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; +- private final Map affectedEntities; ++ protected final Map affectedEntities; // Paper + + @Deprecated(since = "1.20.2") + public PotionSplashEvent(@NotNull final ThrownPotion potion, @NotNull final Map affectedEntities) { diff --git a/patches/api/0285-More-World-API.patch b/patches/api/0285-More-World-API.patch deleted file mode 100644 index e7575201c007..000000000000 --- a/patches/api/0285-More-World-API.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 7 Jul 2020 10:53:22 -0700 -Subject: [PATCH] More World API - - -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 352a20da402b3b0182b7a0c69d94397f42054053..8b88146908288e7290952a6d8a9db1dbb3307f66 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -3709,6 +3709,114 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - @Nullable - StructureSearchResult locateNearestStructure(@NotNull Location origin, @NotNull Structure structure, int radius, boolean findUnexplored); - -+ // Paper start -+ /** -+ * Locates the nearest biome based on an origin, biome type, and radius to search. -+ * Step defaults to {@code 8}. -+ * -+ * @param origin Origin location -+ * @param biome Biome to find -+ * @param radius radius to search -+ * @return Location of biome or null if not found in specified radius -+ */ -+ @Nullable -+ Location locateNearestBiome(@NotNull Location origin, @NotNull Biome biome, int radius); -+ -+ /** -+ * Locates the nearest biome based on an origin, biome type, and radius to search -+ * and step -+ * -+ * @param origin Origin location -+ * @param biome Biome to find -+ * @param radius radius to search -+ * @param step Search step 1 would mean checking every block, 8 would be every 8th block -+ * @return Location of biome or null if not found in specified radius -+ */ -+ @Nullable -+ Location locateNearestBiome(@NotNull Location origin, @NotNull Biome biome, int radius, int step); -+ -+ /** -+ * Checks if the world: -+ *

        -+ *
      • evaporates water
      • -+ *
      • dries sponges
      • -+ *
      • has lava spread faster and further
      • -+ *
      -+ * -+ * @return true if ultrawarm, false if not -+ * @deprecated use {@link #isUltraWarm()} -+ */ -+ @Deprecated -+ boolean isUltrawarm(); -+ -+ /** -+ * Gets the coordinate scaling of this world. -+ * -+ * @return the coordinate scale -+ */ -+ double getCoordinateScale(); -+ -+ /** -+ * Checks if the world has skylight access -+ * -+ * @return whether there is skylight -+ * @deprecated use {@link #hasSkyLight()} -+ */ -+ @Deprecated -+ boolean hasSkylight(); -+ -+ /** -+ * Checks if the world has a bedrock ceiling -+ * -+ * @return whether the world has a bedrock ceiling -+ * @deprecated use {@link #hasCeiling()} -+ */ -+ @Deprecated -+ boolean hasBedrockCeiling(); -+ -+ /** -+ * Checks if beds work -+ * -+ * @return whether beds work -+ * @deprecated use {@link #isBedWorks()} -+ */ -+ @Deprecated -+ boolean doesBedWork(); -+ -+ /** -+ * Checks if respawn anchors work -+ * -+ * @return whether respawn anchors work -+ * @deprecated use {@link #isRespawnAnchorWorks()} -+ */ -+ @Deprecated -+ boolean doesRespawnAnchorWork(); -+ -+ /** -+ * Checks if this world has a fixed time -+ * -+ * @return whether this world has fixed time -+ */ -+ boolean isFixedTime(); -+ -+ /** -+ * Gets the collection of materials that burn infinitely in this world. -+ * -+ * @return the materials that will forever stay lit by fire -+ */ -+ @NotNull -+ Collection getInfiniburn(); -+ -+ /** -+ * Posts a specified game event at a location -+ * -+ * @param sourceEntity optional source entity -+ * @param gameEvent the game event to post -+ * @param position the position in the world where to post the event to listeners -+ */ -+ void sendGameEvent(@Nullable Entity sourceEntity, @NotNull GameEvent gameEvent, @NotNull Vector position); -+ // Paper end -+ - // Spigot start - /** - * Returns the view distance used for this world. diff --git a/patches/api/0312-Add-more-LimitedRegion-API.patch b/patches/api/0286-Add-more-LimitedRegion-API.patch similarity index 100% rename from patches/api/0312-Add-more-LimitedRegion-API.patch rename to patches/api/0286-Add-more-LimitedRegion-API.patch diff --git a/patches/api/0286-Added-PlayerBedFailEnterEvent.patch b/patches/api/0286-Added-PlayerBedFailEnterEvent.patch deleted file mode 100644 index a622f2b98fff..000000000000 --- a/patches/api/0286-Added-PlayerBedFailEnterEvent.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 24 Dec 2020 12:27:49 -0800 -Subject: [PATCH] Added PlayerBedFailEnterEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerBedFailEnterEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerBedFailEnterEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e0028733615ddc9e34359f673ca1c3cadb133948 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerBedFailEnterEvent.java -@@ -0,0 +1,119 @@ -+package io.papermc.paper.event.player; -+ -+import net.kyori.adventure.text.Component; -+import org.bukkit.block.Block; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class PlayerBedFailEnterEvent extends PlayerEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final FailReason failReason; -+ private final Block bed; -+ private boolean willExplode; -+ private Component message; -+ private boolean cancelled; -+ -+ public PlayerBedFailEnterEvent(@NotNull Player player, @NotNull FailReason failReason, @NotNull Block bed, boolean willExplode, @Nullable Component message) { -+ super(player); -+ this.failReason = failReason; -+ this.bed = bed; -+ this.willExplode = willExplode; -+ this.message = message; -+ } -+ -+ @NotNull -+ public FailReason getFailReason() { -+ return failReason; -+ } -+ -+ @NotNull -+ public Block getBed() { -+ return bed; -+ } -+ -+ public boolean getWillExplode() { -+ return willExplode; -+ } -+ -+ public void setWillExplode(boolean willExplode) { -+ this.willExplode = willExplode; -+ } -+ -+ @Nullable -+ public Component getMessage() { -+ return message; -+ } -+ -+ public void setMessage(@Nullable Component message) { -+ this.message = message; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * Cancel this event. -+ *

      -+ * NOTE: This does not cancel the player getting in the bed, but any messages/explosions -+ * that may occur because of the interaction. -+ * @param cancel true if you wish to cancel this event -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+ -+ public static enum FailReason { -+ /** -+ * The world doesn't allow sleeping (ex. Nether or The End). Entering -+ * the bed is prevented and the bed explodes. -+ */ -+ NOT_POSSIBLE_HERE, -+ /** -+ * Entering the bed is prevented due to it not being night nor -+ * thundering currently. -+ *

      -+ * If the event is forcefully allowed during daytime, the player will -+ * enter the bed (and set its bed location), but might get immediately -+ * thrown out again. -+ */ -+ NOT_POSSIBLE_NOW, -+ /** -+ * Entering the bed is prevented due to the player being too far away. -+ */ -+ TOO_FAR_AWAY, -+ /** -+ * Bed is obstructed. -+ */ -+ OBSTRUCTED, -+ /** -+ * Entering the bed is prevented due to there being some other problem. -+ */ -+ OTHER_PROBLEM, -+ /** -+ * Entering the bed is prevented due to there being monsters nearby. -+ */ -+ NOT_SAFE; -+ -+ public static final FailReason[] VALUES = values(); -+ } -+} diff --git a/patches/api/0287-Introduce-beacon-activation-deactivation-events.patch b/patches/api/0287-Introduce-beacon-activation-deactivation-events.patch deleted file mode 100644 index c2f057719175..000000000000 --- a/patches/api/0287-Introduce-beacon-activation-deactivation-events.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spyridon Pagkalos -Date: Thu, 25 Mar 2021 20:25:47 +0200 -Subject: [PATCH] Introduce beacon activation/deactivation events - - -diff --git a/src/main/java/io/papermc/paper/event/block/BeaconActivatedEvent.java b/src/main/java/io/papermc/paper/event/block/BeaconActivatedEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7575ca7dd84dee89528ec2e5e5f99f97d8a10f58 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/BeaconActivatedEvent.java -@@ -0,0 +1,40 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.block.Beacon; -+import org.bukkit.block.Block; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a beacon is activated. -+ * Activation occurs when the beacon beam becomes visible. -+ */ -+public class BeaconActivatedEvent extends BlockEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ public BeaconActivatedEvent(@NotNull Block block) { -+ super(block); -+ } -+ -+ /** -+ * Returns the beacon that was activated. -+ * -+ * @return the beacon that was activated. -+ */ -+ @NotNull -+ public Beacon getBeacon() { -+ return (Beacon) block.getState(); -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/event/block/BeaconDeactivatedEvent.java b/src/main/java/io/papermc/paper/event/block/BeaconDeactivatedEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..34f18468b4cfc08717cc3442778c9e85124e5a22 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/BeaconDeactivatedEvent.java -@@ -0,0 +1,43 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.Material; -+import org.bukkit.block.Beacon; -+import org.bukkit.block.Block; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when a beacon is deactivated, either because its base block(s) or itself were destroyed. -+ */ -+public class BeaconDeactivatedEvent extends BlockEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ public BeaconDeactivatedEvent(@NotNull Block block) { -+ super(block); -+ } -+ -+ /** -+ * Returns the beacon that was deactivated. -+ * This will return null if the beacon does not exist. -+ * (which can occur after the deactivation of a now broken beacon) -+ * -+ * @return The beacon that got deactivated, or null if it does not exist. -+ */ -+ @Nullable -+ public Beacon getBeacon() { -+ return block.getType() == Material.BEACON ? (Beacon) block.getState() : null; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0287-Missing-Entity-API.patch b/patches/api/0287-Missing-Entity-API.patch new file mode 100644 index 000000000000..9a69c042f925 --- /dev/null +++ b/patches/api/0287-Missing-Entity-API.patch @@ -0,0 +1,1521 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Fri, 28 May 2021 21:06:59 -0400 +Subject: [PATCH] Missing Entity API + +Co-authored-by: Nassim Jahnke +Co-authored-by: Jake Potrebic +Co-authored-by: William Blake Galbreath +Co-authored-by: SoSeDiK +Co-authored-by: booky10 +Co-authored-by: Amin +Co-authored-by: TrollyLoki +Co-authored-by: FireInstall +Co-authored-by: maxcom1 <46265094+maxcom1@users.noreply.github.com> +Co-authored-by: TotalledZebra + +diff --git a/src/main/java/io/papermc/paper/entity/SchoolableFish.java b/src/main/java/io/papermc/paper/entity/SchoolableFish.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a16329a8d08c74ce58960ff9dcc0af098b8543e9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/SchoolableFish.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.entity; ++ ++import org.bukkit.entity.Fish; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Represents a fish that can school with other fish. ++ */ ++@NullMarked ++public interface SchoolableFish extends Fish { ++ ++ /** ++ * Forces this fish to follow the given fish. ++ * ++ * @param leader fish to follow ++ */ ++ void startFollowing(SchoolableFish leader); ++ ++ /** ++ * Causes the fish to stop following their current ++ * leader. ++ */ ++ void stopFollowing(); ++ ++ /** ++ * Gets the amount of fish currently following this fish. ++ * ++ * @return school size ++ */ ++ int getSchoolSize(); ++ ++ /** ++ * Gets the maximum number of fish that will naturally follow this fish. ++ * ++ * @return max school size ++ */ ++ int getMaxSchoolSize(); ++ ++ /** ++ * Gets the fish that this entity is currently following. ++ * ++ * @return following fish ++ */ ++ @Nullable SchoolableFish getSchoolLeader(); ++ ++} +diff --git a/src/main/java/org/bukkit/entity/AbstractHorse.java b/src/main/java/org/bukkit/entity/AbstractHorse.java +index 161af8bc4fe817ec628168dd5bdce47b76ddba56..2e9d6e6023b7c952c48a70152c55b1747561052b 100644 +--- a/src/main/java/org/bukkit/entity/AbstractHorse.java ++++ b/src/main/java/org/bukkit/entity/AbstractHorse.java +@@ -106,17 +106,71 @@ public interface AbstractHorse extends Vehicle, InventoryHolder, Tameable { + * Gets whether the horse is currently grazing hay. + * + * @return true if eating hay ++ * @deprecated use {@link #isEatingGrass()}, this name is incorrect + */ ++ @Deprecated // Paper - Horse API + boolean isEatingHaystack(); + + /** + * Sets whether the horse is grazing hay. + * + * @param eatingHaystack new hay grazing status ++ * @deprecated use {@link #setEatingGrass(boolean)}, this name is incorrect + */ ++ @Deprecated // Paper - Horse API + void setEatingHaystack(boolean eatingHaystack); + + @NotNull + @Override + public AbstractHorseInventory getInventory(); ++ ++ // Paper start - Horse API ++ /** ++ * Gets if a horse is in their eating grass animation. ++ * ++ * @return eating grass animation is active ++ */ ++ public boolean isEatingGrass(); ++ ++ /** ++ * Sets if a horse is in their eating grass animation. ++ * ++ *

      When true, the horse will lower its neck.

      ++ * ++ * @param eating eating grass animation is active ++ */ ++ public void setEatingGrass(boolean eating); ++ ++ /** ++ * Gets if a horse is in their rearing animation. ++ * ++ * @return rearing animation is active ++ */ ++ public boolean isRearing(); ++ ++ /** ++ * Sets if a horse is in their rearing animation. ++ * ++ *

      When true, the horse will stand on its hind legs.

      ++ * ++ * @param rearing rearing animation is active ++ */ ++ public void setRearing(boolean rearing); ++ ++ /** ++ * Gets if a horse is in their eating animation. ++ * ++ * @return eating animation is active ++ */ ++ public boolean isEating(); ++ ++ /** ++ * Sets if a horse is in their eating animation. ++ * ++ *

      When true, the horse will bob its head.

      ++ * ++ * @param eating eating animation is active ++ */ ++ public void setEating(boolean eating); ++ // Paper end - Horse API + } +diff --git a/src/main/java/org/bukkit/entity/AreaEffectCloud.java b/src/main/java/org/bukkit/entity/AreaEffectCloud.java +index 9d99a67014ba48c371be232dd05299582b3aaec1..c4b3ab4b9ca9b4eb064f52fc8ad059b3513fca36 100644 +--- a/src/main/java/org/bukkit/entity/AreaEffectCloud.java ++++ b/src/main/java/org/bukkit/entity/AreaEffectCloud.java +@@ -259,4 +259,20 @@ public interface AreaEffectCloud extends Entity { + * @param source the {@link ProjectileSource} that threw the LingeringPotion + */ + public void setSource(@Nullable ProjectileSource source); ++ ++ // Paper start - owner API ++ /** ++ * Get the entity UUID for the owner of this area effect cloud. ++ * ++ * @return the entity owner uuid or null ++ */ ++ @Nullable java.util.UUID getOwnerUniqueId(); ++ ++ /** ++ * Sets the entity UUID for the owner of this area effect cloud. ++ * ++ * @param ownerUuid the entity owner uuid or null to clear ++ */ ++ void setOwnerUniqueId(@Nullable java.util.UUID ownerUuid); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Bat.java b/src/main/java/org/bukkit/entity/Bat.java +index bd73f22ef7e79e1ade69e860e7ae1d3dcd6fc858..b9f8b14d90a758672642222675d2f5664d4f67b4 100644 +--- a/src/main/java/org/bukkit/entity/Bat.java ++++ b/src/main/java/org/bukkit/entity/Bat.java +@@ -24,4 +24,23 @@ public interface Bat extends Ambient { + * @param state the new state + */ + void setAwake(boolean state); ++ ++ // Paper start ++ /** ++ * Gets the location that this bat is currently trying to move towards. ++ * ++ * @return target location, or null if it's going to find a new location ++ */ ++ @org.jetbrains.annotations.Nullable ++ org.bukkit.Location getTargetLocation(); ++ ++ /** ++ * Sets the location that this bat is currently trying to move towards. ++ *

      ++ * This can be set to null to cause the bat to recalculate its target location ++ * ++ * @param location location to move towards (world is ignored, will always use the entity's world) ++ */ ++ void setTargetLocation(@org.jetbrains.annotations.Nullable org.bukkit.Location location); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Bee.java b/src/main/java/org/bukkit/entity/Bee.java +index adb20a9abba33c32d553f620fa82b27dff64ab5f..1f6702b0de00b87dbed7f6d93e911655e8667b0b 100644 +--- a/src/main/java/org/bukkit/entity/Bee.java ++++ b/src/main/java/org/bukkit/entity/Bee.java +@@ -93,4 +93,56 @@ public interface Bee extends Animals { + * @param ticks Ticks the bee cannot enter a hive for + */ + void setCannotEnterHiveTicks(int ticks); ++ ++ // Paper start ++ /** ++ * Sets the override for if the bee is currently rolling. ++ * ++ * @param rolling is rolling, or unset for vanilla behavior ++ */ ++ void setRollingOverride(@org.jetbrains.annotations.NotNull net.kyori.adventure.util.TriState rolling); ++ ++ /** ++ * Gets the plugin set override for if the bee is currently rolling. ++ * ++ * @return plugin set rolling override ++ */ ++ @org.jetbrains.annotations.NotNull ++ net.kyori.adventure.util.TriState getRollingOverride(); ++ ++ /** ++ * Gets if the bee is currently rolling. ++ * ++ * @return is rolling ++ */ ++ boolean isRolling(); ++ ++ /** ++ * Sets how many crops this bee has grown since it last ++ * pollinated. ++ * @param crops number of crops ++ */ ++ void setCropsGrownSincePollination(int crops); ++ ++ /** ++ * Gets how many crops this bee has grown since it last ++ * pollinated. ++ * @return number of crops ++ */ ++ int getCropsGrownSincePollination(); ++ ++ /** ++ * Sets how many ticks this bee has gone without pollinating. ++ * ++ * @param ticks number of ticks ++ */ ++ void setTicksSincePollination(int ticks); ++ ++ /** ++ * Gets how many ticks this bee has gone without pollinating ++ * ++ * @return number of ticks ++ */ ++ int getTicksSincePollination(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Bogged.java b/src/main/java/org/bukkit/entity/Bogged.java +index 8b75a505a55a96a5795ac31a2d37307add12cd9e..0e5aaf54df0a5d0995147a905daef52442b070c5 100644 +--- a/src/main/java/org/bukkit/entity/Bogged.java ++++ b/src/main/java/org/bukkit/entity/Bogged.java +@@ -7,4 +7,18 @@ import org.jetbrains.annotations.ApiStatus; + */ + @ApiStatus.Experimental + public interface Bogged extends AbstractSkeleton, Shearable { ++ ++ /** ++ * Gets whether the bogged is in its sheared state. ++ * ++ * @return Whether the bogged is sheared. ++ */ ++ boolean isSheared(); ++ ++ /** ++ * Sets whether the bogged is in its sheared state. ++ * ++ * @param flag Whether to shear the bogged ++ */ ++ void setSheared(boolean flag); + } +diff --git a/src/main/java/org/bukkit/entity/Cat.java b/src/main/java/org/bukkit/entity/Cat.java +index 104b9c8a28ddbab8f47dbf3a0ac06bec35d7c003..5101553bb71d60fee7ac234f7ef2863781dd7742 100644 +--- a/src/main/java/org/bukkit/entity/Cat.java ++++ b/src/main/java/org/bukkit/entity/Cat.java +@@ -90,4 +90,36 @@ public interface Cat extends Tameable, Sittable { + return Lists.newArrayList(Registry.CAT_VARIANT).toArray(new Type[0]); + } + } ++ ++ // Paper start - More cat api ++ /** ++ * Sets if the cat is lying down. ++ * This is visual and does not affect the behaviour of the cat. ++ * ++ * @param lyingDown whether the cat should lie down ++ */ ++ public void setLyingDown(boolean lyingDown); ++ ++ /** ++ * Gets if the cat is lying down. ++ * ++ * @return whether the cat is lying down ++ */ ++ public boolean isLyingDown(); ++ ++ /** ++ * Sets if the cat has its head up. ++ * This is visual and does not affect the behaviour of the cat. ++ * ++ * @param headUp head is up ++ */ ++ public void setHeadUp(boolean headUp); ++ ++ /** ++ * Gets if the cat has its head up. ++ * ++ * @return head is up ++ */ ++ public boolean isHeadUp(); ++ // Paper end - More cat api + } +diff --git a/src/main/java/org/bukkit/entity/Chicken.java b/src/main/java/org/bukkit/entity/Chicken.java +index cb3ec6ef6c38c2071cb6ad91da094fca2de8d5c6..b4c1a262602d4ca5ffc9fcc21d6aa79af8c040a7 100644 +--- a/src/main/java/org/bukkit/entity/Chicken.java ++++ b/src/main/java/org/bukkit/entity/Chicken.java +@@ -3,4 +3,35 @@ package org.bukkit.entity; + /** + * Represents a Chicken. + */ +-public interface Chicken extends Animals {} ++// Paper start ++public interface Chicken extends Animals { ++ ++ /** ++ * Gets if this chicken was spawned as a chicken jockey. ++ * ++ * @return is chicken jockey ++ */ ++ boolean isChickenJockey(); ++ ++ /** ++ * Sets if this chicken was spawned as a chicken jockey. ++ * ++ * @param isChickenJockey is chicken jockey ++ */ ++ void setIsChickenJockey(boolean isChickenJockey); ++ ++ /** ++ * Gets the number of ticks till this chicken lays an egg. ++ * ++ * @return ticks till the chicken lays an egg ++ */ ++ int getEggLayTime(); ++ ++ /** ++ * Sets the number of ticks till this chicken lays an egg. ++ * ++ * @param eggLayTime ticks till the chicken lays an egg ++ */ ++ void setEggLayTime(int eggLayTime); ++} ++// Paper end +diff --git a/src/main/java/org/bukkit/entity/Cod.java b/src/main/java/org/bukkit/entity/Cod.java +index 191ce6c0e32ab3d05b1376e0fa56d1292c2d442c..8de09075e14a08a6c68f9c24e8960cc04a018036 100644 +--- a/src/main/java/org/bukkit/entity/Cod.java ++++ b/src/main/java/org/bukkit/entity/Cod.java +@@ -4,4 +4,4 @@ package org.bukkit.entity; + /** + * Represents a cod fish. + */ +-public interface Cod extends Fish { } ++public interface Cod extends io.papermc.paper.entity.SchoolableFish { } // Paper - Schooling Fish API +diff --git a/src/main/java/org/bukkit/entity/Damageable.java b/src/main/java/org/bukkit/entity/Damageable.java +index 1d2447a28b370e2346fb099de52e2beed5fd3e42..4b94f1ed620c57bebca7cf0a5a0d478a93952d36 100644 +--- a/src/main/java/org/bukkit/entity/Damageable.java ++++ b/src/main/java/org/bukkit/entity/Damageable.java +@@ -53,6 +53,25 @@ public interface Damageable extends Entity { + */ + void setHealth(double health); + ++ // Paper start - entity heal API ++ /** ++ * Heal this entity by the given amount. This will call {@link org.bukkit.event.entity.EntityRegainHealthEvent}. ++ * ++ * @param amount heal amount ++ */ ++ default void heal(final double amount) { ++ this.heal(amount, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.CUSTOM); ++ } ++ ++ /** ++ * Heal this entity by the given amount. This will call {@link org.bukkit.event.entity.EntityRegainHealthEvent}. ++ * ++ * @param amount heal amount ++ * @param reason heal reason ++ */ ++ void heal(double amount, @NotNull org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason reason); ++ // Paper end - entity heal API ++ + /** + * Gets the entity's absorption amount. + * +diff --git a/src/main/java/org/bukkit/entity/Enderman.java b/src/main/java/org/bukkit/entity/Enderman.java +index 875817b807c9f515eb07b03cc85d368955388dc3..db01cc952f0a0efd799454d6c86ee4c250e852d8 100644 +--- a/src/main/java/org/bukkit/entity/Enderman.java ++++ b/src/main/java/org/bukkit/entity/Enderman.java +@@ -86,4 +86,36 @@ public interface Enderman extends Monster { + * @return true if the teleport succeeded. + */ + public boolean teleportTowards(@NotNull Entity entity); ++ ++ // Paper start ++ /** ++ * Returns whether the enderman is screaming/angry. ++ * ++ * @return whether the enderman is screaming ++ */ ++ boolean isScreaming(); ++ ++ /** ++ * Sets whether the enderman is screaming/angry. ++ * ++ * @param screaming whether the enderman is screaming ++ */ ++ void setScreaming(boolean screaming); ++ ++ /** ++ * Returns whether the enderman has been stared at. ++ * If set to true, players will hear an ambient sound. ++ * ++ * @return whether the enderman has been stared at ++ */ ++ boolean hasBeenStaredAt(); ++ ++ /** ++ * Sets whether the enderman has been stared at. ++ * If set to true, players will hear an ambient sound. ++ * ++ * @param hasBeenStaredAt whether the enderman has been stared at ++ */ ++ void setHasBeenStaredAt(boolean hasBeenStaredAt); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Endermite.java b/src/main/java/org/bukkit/entity/Endermite.java +index c77d1a4ea7efad489659122b34ddb19199b52b95..7b379fb21e800a766ad022705a12dff6d42279ab 100644 +--- a/src/main/java/org/bukkit/entity/Endermite.java ++++ b/src/main/java/org/bukkit/entity/Endermite.java +@@ -23,4 +23,22 @@ public interface Endermite extends Monster { + */ + @Deprecated(since = "1.17") + void setPlayerSpawned(boolean playerSpawned); ++ // Paper start ++ /** ++ * Sets how many ticks this endermite has been living for. ++ * If this value is greater than 2400, this endermite will despawn. ++ * ++ * @param ticks lifetime ticks ++ */ ++ void setLifetimeTicks(int ticks); ++ ++ /** ++ * Gets how long this endermite has been living for. ++ * This value will tick up while {@link LivingEntity#getRemoveWhenFarAway()} is false. ++ * If this value is greater than 2400, this endermite will despawn. ++ * ++ * @return lifetime ticks ++ */ ++ int getLifetimeTicks(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 8521a9ae4d4427ef9cdbb1b8c67dd6ba81d1f5d9..3b40c63a380e519ecae2e272754a53aff5aebd9a 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -293,6 +293,40 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + boolean isFrozen(); + ++ // Paper start - missing entity api ++ /** ++ * Sets whether the entity is invisible or not. ++ *

      ++ * This setting is undefined for non-living entities like boats or paintings. ++ * Non-living entities that are marked as invisible through this method may e.g. only hide their shadow. ++ * To hide such entities from players completely, see {@link Player#hideEntity(org.bukkit.plugin.Plugin, Entity)}. ++ * ++ * @param invisible If the entity is invisible ++ */ ++ void setInvisible(boolean invisible); // Paper - moved up from LivingEntity ++ ++ /** ++ * Gets whether the entity is invisible or not. ++ * ++ * @return Whether the entity is invisible ++ */ ++ boolean isInvisible(); // Paper - moved up from LivingEntity ++ ++ /** ++ * Sets this entities no physics status. ++ * ++ * @param noPhysics boolean indicating if the entity should not have physics. ++ */ ++ void setNoPhysics(boolean noPhysics); ++ ++ /** ++ * Gets if this entity has no physics. ++ * ++ * @return true if the entity does not have physics. ++ */ ++ boolean hasNoPhysics(); ++ // Paper end - missing entity api ++ + /** + * Mark the entity's removal. + * +diff --git a/src/main/java/org/bukkit/entity/Fireball.java b/src/main/java/org/bukkit/entity/Fireball.java +index d7ebb33e946d7c5c5ee682f2dc9cf8e4e9f7049f..252e3d35c0478ff4132d33c5caf65aa27911b675 100644 +--- a/src/main/java/org/bukkit/entity/Fireball.java ++++ b/src/main/java/org/bukkit/entity/Fireball.java +@@ -62,4 +62,25 @@ public interface Fireball extends Projectile, Explosive { + */ + @NotNull + Vector getAcceleration(); ++ ++ // Paper start - Expose power on fireball projectiles ++ /** ++ * Sets the power of a fireball. The power determines the direction and magnitude of its acceleration. ++ * ++ * @param power the power ++ * @deprecated use #setAcceleration(Vector) instead. ++ */ ++ @Deprecated ++ public void setPower(@NotNull Vector power); ++ ++ /** ++ * Gets the power of a fireball. The power determines the direction and magnitude of its acceleration. ++ * ++ * @return the power ++ * @deprecated Use #getAcceleration instead. ++ */ ++ @Deprecated ++ @NotNull ++ public Vector getPower(); ++ // Paper end - Expose power on fireball projectiles + } +diff --git a/src/main/java/org/bukkit/entity/Fox.java b/src/main/java/org/bukkit/entity/Fox.java +index c61a473453f33f9d10c330fc46cfa9d52251fe49..473a7e36ad64f866d1d2e09e2ecb2e9881668faf 100644 +--- a/src/main/java/org/bukkit/entity/Fox.java ++++ b/src/main/java/org/bukkit/entity/Fox.java +@@ -92,4 +92,55 @@ public interface Fox extends Animals, Sittable { + RED, + SNOW; + } ++ ++ // Paper start - Add more fox behavior API ++ /** ++ * Sets if the fox is interested. ++ * ++ * @param interested is interested ++ */ ++ public void setInterested(boolean interested); ++ ++ /** ++ * Gets if the fox is interested. ++ * ++ * @return fox is interested ++ */ ++ public boolean isInterested(); ++ ++ /** ++ * Sets if the fox is leaping. ++ * ++ * @param leaping is leaping ++ */ ++ public void setLeaping(boolean leaping); ++ ++ /** ++ * Gets if the fox is leaping. ++ * ++ * @return fox is leaping ++ */ ++ public boolean isLeaping(); ++ ++ /** ++ * Sets if the fox is defending. ++ * ++ * @param defending is defending ++ */ ++ public void setDefending(boolean defending); ++ ++ /** ++ * Gets if the fox is defending. ++ * ++ * @return fox is defending ++ */ ++ public boolean isDefending(); ++ ++ /** ++ * Sets if the fox face planted. ++ * ++ * @param faceplanted face planted ++ */ ++ public void setFaceplanted(boolean faceplanted); ++ // Paper end - Add more fox behavior API + } +diff --git a/src/main/java/org/bukkit/entity/Ghast.java b/src/main/java/org/bukkit/entity/Ghast.java +index 6b3c9bef9a8a34ddc6ff42cf358541a2665bf5e3..9c618a27d590f186f29c5d9094fc565efd40ca49 100644 +--- a/src/main/java/org/bukkit/entity/Ghast.java ++++ b/src/main/java/org/bukkit/entity/Ghast.java +@@ -18,4 +18,21 @@ public interface Ghast extends Flying, Enemy { + * @param flag Whether the Ghast is charging + */ + void setCharging(boolean flag); ++ ++ // Paper start ++ /** ++ * Returns the explosion power of shot fireballs. ++ * ++ * @return explosion power of shot fireballs ++ */ ++ int getExplosionPower(); ++ ++ /** ++ * Sets the explosion power of shot fireballs. ++ * ++ * @param explosionPower explosion power of shot fireballs ++ * @throws IllegalArgumentException if the explosion power is less than 0 or greater than 127 ++ */ ++ void setExplosionPower(int explosionPower); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 5db673a0572163574c41bd7827572372411142ed..c2ed2245604fcb638450d4aa00d8045685ce294d 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1004,6 +1004,7 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + * + * @param invisible If the entity is invisible + */ ++ @Override // Paper - move invisibility up to Entity + public void setInvisible(boolean invisible); + + /** +@@ -1011,6 +1012,7 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + * + * @return Whether the entity is invisible + */ ++ @Override // Paper - move invisibility up to Entity + public boolean isInvisible(); + + // Paper start +@@ -1047,6 +1049,57 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + void setShieldBlockingDelay(int delay); + // Paper end + ++ // Paper start - missing entity API ++ /** ++ * Retrieves the sideways movement direction of the entity. ++ *

      ++ * The returned value ranges from -1 to 1, where: ++ * - Positive 1 represents movement to the left. ++ * - Negative 1 represents movement to the right. ++ *

      ++ * Please note that for entities of type {@link Player}, this value is updated only when riding another entity. ++ *

      ++ * This method specifically provides information about the entity's sideways movement, whereas {@link #getVelocity()} returns ++ * a vector representing the entity's overall current momentum. ++ * ++ * @return Sideways movement direction, ranging from -1 (right) to 1 (left). ++ */ ++ float getSidewaysMovement(); ++ ++ /** ++ * Retrieves the upwards movement direction of the entity. ++ *

      ++ * The returned value ranges from -1 to 1, where: ++ * - Positive 1 represents upward movement. ++ * - Negative 1 represents downward movement. ++ *

      ++ * Please note that for entities of type {@link Player}, this value is never updated. ++ *

      ++ * This method specifically provides information about the entity's vertical movement, ++ * whereas {@link #getVelocity()} returns a vector representing the entity's overall ++ * current momentum. ++ * ++ * @return Upwards movement direction, ranging from -1 (downward) to 1 (upward). ++ */ ++ float getUpwardsMovement(); ++ ++ /** ++ * Retrieves the forwards movement direction of the entity. ++ *

      ++ * The returned value ranges from -1 to 1, where: ++ * - Positive 1 represents movement forwards. ++ * - Negative 1 represents movement backwards. ++ *

      ++ * Please note that for entities of type {@link Player}, this value is updated only when riding another entity. ++ *

      ++ * This method specifically provides information about the entity's forward and backward movement, ++ * whereas {@link #getVelocity()} returns a vector representing the entity's overall current momentum. ++ * ++ * @return Forwards movement direction, ranging from -1 (backward) to 1 (forward). ++ */ ++ float getForwardsMovement(); ++ // Paper end - missing entity API ++ + // Paper start - active item API + /** + * Starts using the item in the specified hand, making it the +diff --git a/src/main/java/org/bukkit/entity/Llama.java b/src/main/java/org/bukkit/entity/Llama.java +index d23226ccb0f6c25028f000ce31346cd0a8898e6a..bc84b892cae5fe7019a3ad481e9da79956efa1fe 100644 +--- a/src/main/java/org/bukkit/entity/Llama.java ++++ b/src/main/java/org/bukkit/entity/Llama.java +@@ -67,4 +67,56 @@ public interface Llama extends ChestedHorse, RangedEntity { // Paper + @NotNull + @Override + LlamaInventory getInventory(); ++ ++ // Paper start ++ /** ++ * Checks if this llama is in a caravan. ++ * This means that this llama is currently following ++ * another llama. ++ * ++ * @return is in caravan ++ */ ++ boolean inCaravan(); ++ ++ /** ++ * Joins a caravan, with the provided llama being the leader ++ * of the caravan. ++ * This llama will then follow the provided llama. ++ * ++ * @param llama head of caravan to join ++ */ ++ void joinCaravan(@NotNull Llama llama); ++ ++ /** ++ * Leaves the current caravan that they are in. ++ */ ++ void leaveCaravan(); ++ ++ /** ++ * Get the llama that this llama is following. ++ *

      ++ * Does not necessarily mean the leader of the entire caravan. ++ * ++ * @return the llama currently being followed ++ */ ++ @org.jetbrains.annotations.Nullable ++ Llama getCaravanHead(); ++ ++ /** ++ * Checks if another llama is currently following behind ++ * this llama. ++ * ++ * @return true if being followed in the caravan ++ */ ++ boolean hasCaravanTail(); ++ ++ /** ++ * Gets the llama that is currently following behind ++ * this llama. ++ * ++ * @return the llama following this llama, or null if none is following them ++ */ ++ @org.jetbrains.annotations.Nullable ++ Llama getCaravanTail(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java +index 5fd723c9fdda81595db8b150d967ff3bd5cea608..91d31e5418a5ab7cefd7c02a41bbec8464fe7ab1 100644 +--- a/src/main/java/org/bukkit/entity/Mob.java ++++ b/src/main/java/org/bukkit/entity/Mob.java +@@ -170,4 +170,38 @@ public interface Mob extends LivingEntity, Lootable { + this.setSeed(seed); + } + // Paper end - LootTable API ++ ++ // Paper start - Missing Entity API ++ /** ++ * Some mobs will raise their arm(s) when aggressive: ++ *

        ++ *
      • {@link Drowned}
      • ++ *
      • {@link Piglin}
      • ++ *
      • {@link Skeleton}
      • ++ *
      • {@link Zombie}
      • ++ *
      • {@link ZombieVillager}
      • ++ *
      • {@link Illusioner}
      • ++ *
      • {@link Vindicator}
      • ++ *
      • {@link Panda}
      • ++ *
      • {@link Pillager}
      • ++ *
      • {@link PiglinBrute}
      • ++ *
      ++ *

      ++ * Note: This doesn't always show the actual aggressive state as ++ * set by {@link #setAggressive(boolean)}. {@link Panda}'s are always ++ * aggressive if their combined {@link Panda.Gene} is {@link Panda.Gene#AGGRESSIVE}. ++ * ++ * @return wether the mob is aggressive or not ++ */ ++ boolean isAggressive(); ++ ++ /** ++ * Some mobs will raise their arm(s) when aggressive, ++ * see {@link #isAggressive()} for full list. ++ * ++ * @param aggressive wether the mob should be aggressive or not ++ * @see #isAggressive() ++ */ ++ void setAggressive(boolean aggressive); ++ // Paper end - Missing Entity API + } +diff --git a/src/main/java/org/bukkit/entity/Panda.java b/src/main/java/org/bukkit/entity/Panda.java +index 1f027927a1194f4f8e86c1375a2772e6e261c151..4f06870cc8d8aab93aa83b1b8165e6714884372c 100644 +--- a/src/main/java/org/bukkit/entity/Panda.java ++++ b/src/main/java/org/bukkit/entity/Panda.java +@@ -107,6 +107,98 @@ public interface Panda extends Animals, Sittable { + */ + int getUnhappyTicks(); + ++ // Paper start - Panda API ++ /** ++ * Sets the sneeze progress in this animation. ++ * This value counts up only if {@link Panda#isSneezing()} is true ++ * ++ * @param ticks sneeze progress ++ */ ++ void setSneezeTicks(int ticks); ++ ++ /** ++ * Gets the current sneeze progress, or how many ticks this panda will sneeze for. ++ * ++ * @return sneeze progress ++ */ ++ int getSneezeTicks(); ++ ++ /** ++ * Sets the eating ticks for this panda. ++ *

      ++ * ++ * This starts counting up as long as it is greater than 0. ++ * ++ * @param ticks eating ticks ++ */ ++ void setEatingTicks(int ticks); ++ ++ /** ++ * Gets the current eating progress, or how many ticks this panda has been eating for. ++ * ++ * @return eating progress ++ */ ++ int getEatingTicks(); ++ ++ /** ++ * Sets the number of ticks this panda will be unhappy for. ++ *

      ++ * This value counts down. ++ * ++ * @param ticks unhappy ticks ++ */ ++ void setUnhappyTicks(int ticks); ++ ++ /** ++ * Sets if this panda is currently on its back. ++ * ++ * @param onBack is on its back ++ * @deprecated use {@link #setOnBack(boolean)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19") ++ default void setIsOnBack(boolean onBack) { ++ this.setOnBack(onBack); ++ } ++ ++ /** ++ * Sets if this panda is currently sitting. ++ * ++ * @param sitting is currently sitting ++ * @deprecated use {@link #setSitting(boolean)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.19") ++ default void setIsSitting(boolean sitting) { ++ this.setSitting(sitting); ++ } ++ ++ /** ++ * Sets if this panda is currently sitting. ++ * ++ * @param sitting is currently sitting ++ */ ++ @Override ++ void setSitting(boolean sitting); ++ ++ /** ++ * Gets if this panda is sitting. ++ * ++ * @return is sitting ++ */ ++ @Override ++ boolean isSitting(); ++ ++ /** ++ * Gets this Panda's combined gene. ++ *

      ++ * The combined gene can be modified using ++ * {@link #setMainGene(Gene)} or {@link #setHiddenGene(Gene)}. ++ * ++ * @return combined gene ++ */ ++ @NotNull ++ Gene getCombinedGene(); ++ // Paper end - Panda API ++ + public enum Gene { + + NORMAL(false), +diff --git a/src/main/java/org/bukkit/entity/Phantom.java b/src/main/java/org/bukkit/entity/Phantom.java +index 3dafdf14ced991ae1179ef1ca455da62f8c3243e..2fe8e8868f12bd9e846baf8858cd2c333c00a0d8 100644 +--- a/src/main/java/org/bukkit/entity/Phantom.java ++++ b/src/main/java/org/bukkit/entity/Phantom.java +@@ -40,5 +40,21 @@ public interface Phantom extends Flying, Enemy { + * @param shouldBurnInDay True to burn in sunlight + */ + public void setShouldBurnInDay(boolean shouldBurnInDay); ++ ++ /** ++ * Gets the location that this phantom circles around when not attacking a player ++ * This will be changed after attacking a player. ++ * ++ * @return circling location ++ */ ++ @org.jetbrains.annotations.NotNull ++ org.bukkit.Location getAnchorLocation(); ++ ++ /** ++ * Sets the location that this phantom circles around when not attacking a player ++ * ++ * @param location circling location (world is ignored, will always use the entity's world) ++ */ ++ void setAnchorLocation(@org.jetbrains.annotations.NotNull org.bukkit.Location location); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Piglin.java b/src/main/java/org/bukkit/entity/Piglin.java +index 6fdc0e0bb62189dbf3cf9ce7a87b7fbb995956a3..eb0b7c18c1266748ff1e8e18e49b6c4f6e078b83 100644 +--- a/src/main/java/org/bukkit/entity/Piglin.java ++++ b/src/main/java/org/bukkit/entity/Piglin.java +@@ -90,4 +90,47 @@ public interface Piglin extends PiglinAbstract, InventoryHolder, com.destroystok + */ + @NotNull + public Set getBarterList(); ++ ++ // Paper start ++ /** ++ * Causes the piglin to appear as if they are charging ++ * a crossbow. ++ *

      ++ * This works with any item currently held in the piglin's hand. ++ * ++ * @param chargingCrossbow is charging ++ */ ++ void setChargingCrossbow(boolean chargingCrossbow); ++ ++ /** ++ * Gets if the piglin is currently charging the ++ * item in their hand. ++ * ++ * @return is charging ++ */ ++ boolean isChargingCrossbow(); ++ ++ /** ++ * Sets whether the Piglin is dancing or not ++ * ++ * @param dancing is dancing ++ */ ++ void setDancing(boolean dancing); ++ ++ /** ++ * Causes the piglin to dance for a ++ * specified amount of time ++ * ++ * @param duration duration of the dance in ticks ++ */ ++ void setDancing(long duration); ++ ++ /** ++ * Gets if the piglin is currently dancing ++ * ++ * @return is dancing ++ */ ++ boolean isDancing(); ++ // Paper end ++ + } +diff --git a/src/main/java/org/bukkit/entity/PolarBear.java b/src/main/java/org/bukkit/entity/PolarBear.java +index 479f7a7c54c85cb685f56e60906650d1989c03ff..4e526ba6aa462a484984fb9f0512b8db113086fe 100644 +--- a/src/main/java/org/bukkit/entity/PolarBear.java ++++ b/src/main/java/org/bukkit/entity/PolarBear.java +@@ -3,4 +3,22 @@ package org.bukkit.entity; + /** + * Represents a polar bear. + */ +-public interface PolarBear extends Animals {} ++// Paper start ++public interface PolarBear extends Animals { ++ ++ /** ++ * Returns whether the polar bear is standing. ++ * ++ * @return whether the polar bear is standing ++ */ ++ boolean isStanding(); ++ ++ /** ++ * Sets whether the polar bear is standing. ++ * ++ * @param standing whether the polar bear should be standing ++ */ ++ void setStanding(boolean standing); ++ ++} ++// Paper end +diff --git a/src/main/java/org/bukkit/entity/Rabbit.java b/src/main/java/org/bukkit/entity/Rabbit.java +index e88154283a8ef594e160d25005870053de15568a..979062aa476e3bd75166458d8831894fba8778cd 100644 +--- a/src/main/java/org/bukkit/entity/Rabbit.java ++++ b/src/main/java/org/bukkit/entity/Rabbit.java +@@ -14,6 +14,23 @@ public interface Rabbit extends Animals { + * @param type Sets the type of rabbit for this entity. + */ + public void setRabbitType(@NotNull Type type); ++ // Paper start ++ /** ++ * Sets how many ticks this rabbit will wait ++ * until trying to find more carrots. ++ * ++ * @param ticks ticks ++ */ ++ void setMoreCarrotTicks(int ticks); ++ ++ /** ++ * Returns how many ticks this rabbit ++ * will wait until trying to find more carrots. ++ * ++ * @return ticks ++ */ ++ int getMoreCarrotTicks(); ++ // Paper end + + /** + * Represents the various types a Rabbit might be. +diff --git a/src/main/java/org/bukkit/entity/Ravager.java b/src/main/java/org/bukkit/entity/Ravager.java +index 4374d5206d4d15a4d8d228c137ed9a96821a1f02..0eb7214472f3a43641a3526000af6beeefb7b36f 100644 +--- a/src/main/java/org/bukkit/entity/Ravager.java ++++ b/src/main/java/org/bukkit/entity/Ravager.java +@@ -3,4 +3,61 @@ package org.bukkit.entity; + /** + * Illager beast. + */ +-public interface Ravager extends Raider { } ++// Paper start - Missing Entity Behavior ++public interface Ravager extends Raider { ++ ++ /** ++ * Gets how many ticks this ravager is attacking for. ++ * When attacking, the ravager cannot move. ++ * ++ * @return ticks attacking or -1 if they are currently not attacking ++ */ ++ int getAttackTicks(); ++ ++ /** ++ * Sets how many ticks this ravager is attacking for. ++ * When attacking, the ravager cannot move. ++ * This will tick down till it gets to -1, where this ravager will no longer be attacking. ++ * ++ * @param ticks ticks attacking or -1 if they should no longer be attacking ++ */ ++ void setAttackTicks(int ticks); ++ ++ /** ++ * Gets how many ticks the ravager is stunned for. ++ * The ravager cannot move or attack while stunned. ++ * At 0, this will cause the ravager to roar. ++ * ++ * @return ticks stunned or -1 if they are currently not stunned ++ */ ++ int getStunnedTicks(); ++ ++ /** ++ * Sets how many ticks the ravager is stunned for. ++ * The ravager cannot move or attack while stunned. ++ * At 0, this will cause the ravager to roar. ++ * ++ * @param ticks ticks stunned or -1 if they should no longer be stunned ++ */ ++ void setStunnedTicks(int ticks); ++ ++ /** ++ * Gets how many ticks the ravager is roaring for. ++ * While roaring, the ravager cannot move ++ * ++ * @return ticks roaring or -1 if they are currently not roaring ++ */ ++ int getRoarTicks(); ++ ++ /** ++ * Sets how many ticks the ravager is roaring for. ++ * While roaring, the ravager cannot move ++ * This will tick down till it gets to -1, where it is no longer active. ++ * If set to 11, this will play a sound and hurt nearby players. ++ * ++ * @param ticks ticks roaring or -1 if they should no longer be roaring ++ */ ++ void setRoarTicks(int ticks); ++ ++} ++// Paper end +diff --git a/src/main/java/org/bukkit/entity/Salmon.java b/src/main/java/org/bukkit/entity/Salmon.java +index 407aa5de170a3f0160c197a2b228f2e3b3269387..d8a2d44fe50a9ab24d8916aad270dfba0bd84e5e 100644 +--- a/src/main/java/org/bukkit/entity/Salmon.java ++++ b/src/main/java/org/bukkit/entity/Salmon.java +@@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents a salmon fish. + */ +-public interface Salmon extends Fish { ++public interface Salmon extends io.papermc.paper.entity.SchoolableFish { // Paper - Schooling Fish API + + /** + * Get the variant of this salmon. +diff --git a/src/main/java/org/bukkit/entity/Sheep.java b/src/main/java/org/bukkit/entity/Sheep.java +index 46bc1a0ed9ee320c68a38362c1fa1f31319f01d8..9ed473e5e993ef2d9558fe18bbcea7dad9b42994 100644 +--- a/src/main/java/org/bukkit/entity/Sheep.java ++++ b/src/main/java/org/bukkit/entity/Sheep.java +@@ -6,4 +6,18 @@ import org.bukkit.material.Colorable; + * Represents a Sheep. + */ + public interface Sheep extends Animals, Colorable, Shearable { ++ ++ /** ++ * Gets whether the sheep is in its sheared state. ++ * ++ * @return Whether the sheep is sheared. ++ */ ++ boolean isSheared(); ++ ++ /** ++ * Sets whether the sheep is in its sheared state. ++ * ++ * @param flag Whether to shear the sheep ++ */ ++ void setSheared(boolean flag); + } +diff --git a/src/main/java/org/bukkit/entity/TNTPrimed.java b/src/main/java/org/bukkit/entity/TNTPrimed.java +index 0813bd913c8fdb2001963ce3e82c07c2af105418..87e717c9ea61b0cbf536bc62fa829ddcfae5ad8c 100644 +--- a/src/main/java/org/bukkit/entity/TNTPrimed.java ++++ b/src/main/java/org/bukkit/entity/TNTPrimed.java +@@ -64,4 +64,26 @@ public interface TNTPrimed extends Explosive { + default org.bukkit.Location getSourceLoc() { + return this.getOrigin(); + } ++ ++ // Paper start ++ /** ++ * Sets the visual block data of this ++ * primed tnt. ++ *
      ++ * The explosion of the tnt stays the ++ * same and is not affected by this change. ++ * ++ * @param data the visual block data ++ */ ++ void setBlockData(@org.jetbrains.annotations.NotNull org.bukkit.block.data.BlockData data); ++ ++ /** ++ * Gets the visual block data of this ++ * primed tnt. ++ * ++ * @return the visual block data ++ */ ++ @org.jetbrains.annotations.NotNull ++ org.bukkit.block.data.BlockData getBlockData(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Tadpole.java b/src/main/java/org/bukkit/entity/Tadpole.java +index d64979ebdd018f0f63b6115809b48374ba454249..8e097ad55d208a6980c320e2a849efdcc504cff1 100644 +--- a/src/main/java/org/bukkit/entity/Tadpole.java ++++ b/src/main/java/org/bukkit/entity/Tadpole.java +@@ -18,4 +18,21 @@ public interface Tadpole extends Fish { + * @param age New age + */ + public void setAge(int age); ++ ++ // Paper start - Tadpole age lock api ++ /** ++ * Lock the age of the animal, setting this will prevent the animal from ++ * maturing. ++ * ++ * @param lock new lock ++ */ ++ void setAgeLock(boolean lock); ++ ++ /** ++ * Gets the current agelock. ++ * ++ * @return the current agelock ++ */ ++ boolean getAgeLock(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Trident.java b/src/main/java/org/bukkit/entity/Trident.java +index 28cdb3b544572ba7aeb9061e3163e3895ac7d4e6..c8015ff610e3c1222cb368ea1d8a0c2f3785d9c7 100644 +--- a/src/main/java/org/bukkit/entity/Trident.java ++++ b/src/main/java/org/bukkit/entity/Trident.java +@@ -3,4 +3,40 @@ package org.bukkit.entity; + /** + * Represents a thrown trident. + */ +-public interface Trident extends AbstractArrow, ThrowableProjectile { } ++// Paper start ++public interface Trident extends AbstractArrow, ThrowableProjectile { ++ ++ /** ++ * Returns whether the trident has an enchanted glow. ++ * This can be separate from the underlying item having any enchantments. ++ * ++ * @return whether the trident has an enchanted glow ++ */ ++ boolean hasGlint(); ++ ++ /** ++ * Sets whether the trident has an enchanted glow. ++ * This is separate from the underlying item having any enchantments. ++ * ++ * @param glint whether the trident should have an enchanted glow ++ */ ++ void setGlint(boolean glint); ++ ++ /** ++ * Returns the loyalty level of the trident. ++ * This can be separate from the underlying item's enchantments. ++ * ++ * @return loyalty level of the trident ++ */ ++ int getLoyaltyLevel(); ++ ++ /** ++ * Sets the loyalty level of the trident. ++ * This is separate from the underlying item's enchantments. ++ * ++ * @param loyaltyLevel loyalty level ++ * @throws IllegalArgumentException if the loyalty level is lower than 0 or greater than 127 ++ */ ++ void setLoyaltyLevel(int loyaltyLevel); ++} ++// Paper end +diff --git a/src/main/java/org/bukkit/entity/TropicalFish.java b/src/main/java/org/bukkit/entity/TropicalFish.java +index ab31289bb0f9c8e581537a88e1db22bcdbd3d484..84bba32e80d755f094975b667f1bf2a132087f4f 100644 +--- a/src/main/java/org/bukkit/entity/TropicalFish.java ++++ b/src/main/java/org/bukkit/entity/TropicalFish.java +@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Tropical fish. + */ +-public interface TropicalFish extends Fish { ++public interface TropicalFish extends io.papermc.paper.entity.SchoolableFish { // Paper - Schooling Fish API + + /** + * Gets the color of the fish's pattern. +diff --git a/src/main/java/org/bukkit/entity/Vex.java b/src/main/java/org/bukkit/entity/Vex.java +index 627e3c1a96ae3331f5aa2dd7803dd2a31c7204be..3c447d2300c866ae605eeca97bd869f400d6be6f 100644 +--- a/src/main/java/org/bukkit/entity/Vex.java ++++ b/src/main/java/org/bukkit/entity/Vex.java +@@ -57,21 +57,30 @@ public interface Vex extends Monster { + * Gets the remaining lifespan of this entity. + * + * @return life in ticks ++ * @deprecated This API duplicates existing API which uses the more ++ * preferable name due to mirroring internals better + */ ++ @Deprecated + int getLifeTicks(); + + /** + * Sets the remaining lifespan of this entity. + * + * @param lifeTicks life in ticks, or negative for unlimited lifepan ++ * @deprecated This API duplicates existing API which uses the more ++ * preferable name due to mirroring internals better + */ ++ @Deprecated + void setLifeTicks(int lifeTicks); + + /** + * Gets if the entity has a limited life. + * + * @return true if the entity has limited life ++ * @deprecated This API duplicates existing API which uses the more ++ * preferable name due to mirroring internals better + */ ++ @Deprecated + boolean hasLimitedLife(); + // Paper start + +@@ -89,5 +98,37 @@ public interface Vex extends Monster { + * @param summoner New summoner + */ + void setSummoner(@Nullable Mob summoner); ++ ++ /** ++ * Gets if this vex should start to take damage ++ * once {@link Vex#getLimitedLifetimeTicks()} is less than or equal to 0. ++ * ++ * @return will take damage ++ */ ++ boolean hasLimitedLifetime(); ++ ++ /** ++ * Sets if this vex should start to take damage ++ * once {@link Vex#getLimitedLifetimeTicks()} is less than or equal to 0. ++ * ++ * @param hasLimitedLifetime should take damage ++ */ ++ void setLimitedLifetime(boolean hasLimitedLifetime); ++ ++ /** ++ * Gets the number of ticks remaining until the vex will start ++ * to take damage. ++ * ++ * @return ticks until the vex will start to take damage ++ */ ++ int getLimitedLifetimeTicks(); ++ ++ /** ++ * Sets the number of ticks remaining until the vex takes damage. ++ * This number is ticked down only if {@link Vex#hasLimitedLifetime()} is true. ++ * ++ * @param ticks ticks remaining ++ */ ++ void setLimitedLifetimeTicks(int ticks); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/WanderingTrader.java b/src/main/java/org/bukkit/entity/WanderingTrader.java +index da76e1ed5406322073dd8c7a89ca55aa68620ac4..9f25774659b29d8fcca3eb9d9487edff42dbad13 100644 +--- a/src/main/java/org/bukkit/entity/WanderingTrader.java ++++ b/src/main/java/org/bukkit/entity/WanderingTrader.java +@@ -53,5 +53,26 @@ public interface WanderingTrader extends AbstractVillager { + * @return whether the mob will drink + */ + public boolean canDrinkMilk(); ++ ++ /** ++ * Gets the location that this wandering trader is currently ++ * wandering towards. ++ *

      ++ * This will return null if the wandering trader has finished ++ * wandering towards the given location. ++ * ++ * @return the location currently wandering towards, or null if not wandering ++ */ ++ @org.jetbrains.annotations.Nullable ++ org.bukkit.Location getWanderingTowards(); ++ ++ /** ++ * Sets the location that this wandering trader is currently wandering towards. ++ *

      ++ * This can be set to null to prevent the wandering trader from wandering further. ++ * ++ * @param location location to wander towards (world is ignored, will always use the entity's world) ++ */ ++ void setWanderingTowards(@org.jetbrains.annotations.Nullable org.bukkit.Location location); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Warden.java b/src/main/java/org/bukkit/entity/Warden.java +index 3794db8867b53f3b3735ad82fdd8765a26df2bfb..efaa45f41bc1dc8df6665c55b4e5ade343d60d4c 100644 +--- a/src/main/java/org/bukkit/entity/Warden.java ++++ b/src/main/java/org/bukkit/entity/Warden.java +@@ -30,6 +30,18 @@ public interface Warden extends Monster { + */ + int getAnger(@NotNull Entity entity); + ++ // Paper start ++ /** ++ * Gets the highest anger level of this warden. ++ *

      ++ * Anger is an integer from 0 to 150. Once a Warden reaches 80 anger at a ++ * target it will actively pursue it. ++ * ++ * @return highest anger level ++ */ ++ int getHighestAnger(); ++ // Paper end ++ + /** + * Increases the anger level of this warden. + * +diff --git a/src/main/java/org/bukkit/entity/Wither.java b/src/main/java/org/bukkit/entity/Wither.java +index 87a814f63c3f35be35bfa210c9248ad211c0dd8f..14543c2238b45c526dd9aebea2aa5c22f5df54dc 100644 +--- a/src/main/java/org/bukkit/entity/Wither.java ++++ b/src/main/java/org/bukkit/entity/Wither.java +@@ -43,7 +43,9 @@ public interface Wither extends Monster, Boss, com.destroystokyo.paper.entity.Ra + * Returns the wither's current invulnerability ticks. + * + * @return amount of invulnerability ticks ++ * @deprecated Duplicate api, use {@link #getInvulnerableTicks()} + */ ++ @Deprecated(forRemoval = true) // Paper + int getInvulnerabilityTicks(); + + /** +@@ -52,7 +54,9 @@ public interface Wither extends Monster, Boss, com.destroystokyo.paper.entity.Ra + * When invulnerability ticks reach 0, the wither will trigger an explosion. + * + * @param ticks amount of invulnerability ticks ++ * @deprecated Duplicate api, use {@link #setInvulnerableTicks(int)} + */ ++ @Deprecated(forRemoval = true) // Paper + void setInvulnerabilityTicks(int ticks); + + /** +@@ -64,4 +68,43 @@ public interface Wither extends Monster, Boss, com.destroystokyo.paper.entity.Ra + LEFT, + RIGHT + } ++ ++ // Paper start ++ /** ++ * @return whether the wither is charged ++ */ ++ boolean isCharged(); ++ ++ /** ++ * @return ticks the wither is invulnerable for ++ */ ++ int getInvulnerableTicks(); ++ ++ /** ++ * Sets for how long in the future, the wither should be invulnerable. ++ * ++ * @param ticks ticks the wither is invulnerable for ++ */ ++ void setInvulnerableTicks(int ticks); ++ ++ /** ++ * @return whether the wither can travel through portals ++ */ ++ boolean canTravelThroughPortals(); ++ ++ /** ++ * Sets whether the wither can travel through portals. ++ * ++ * @param value whether the wither can travel through portals ++ */ ++ void setCanTravelThroughPortals(boolean value); ++ ++ /** ++ * Makes the wither invulnerable for 11 seconds and ++ * sets the health to one third of the max health. ++ *
      ++ * This is called in vanilla directly after spawning the wither. ++ */ ++ void enterInvulnerabilityPhase(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/ZombieVillager.java b/src/main/java/org/bukkit/entity/ZombieVillager.java +index e38f38ebfc6e85f29b09c4bb3e2ea79639078ad0..e647c6b933be8234c6ef8726724a7e1198f24f31 100644 +--- a/src/main/java/org/bukkit/entity/ZombieVillager.java ++++ b/src/main/java/org/bukkit/entity/ZombieVillager.java +@@ -90,4 +90,22 @@ public interface ZombieVillager extends Zombie { + * @param conversionPlayer the player + */ + void setConversionPlayer(@Nullable OfflinePlayer conversionPlayer); ++ ++ // Paper start - missing entity behaviour api - converting without entity event ++ /** ++ * Sets the amount of ticks until this entity will be converted to a ++ * Villager as a result of being cured. ++ *

      ++ * When this reaches 0, the entity will be converted. A value of less than 0 ++ * will stop the current conversion process without converting the current ++ * entity. ++ * ++ * @param time new conversion time ++ * @param broadcastEntityEvent whether this conversion time mutation should broadcast the ++ * org.bukkit.{@link org.bukkit.EntityEffect#ZOMBIE_TRANSFORM} entity event to the ++ * world. If false, no entity event is published, preventing for example the ++ * org.bukkit.{@link org.bukkit.Sound#ENTITY_ZOMBIE_VILLAGER_CURE} from playing. ++ */ ++ void setConversionTime(int time, boolean broadcastEntityEvent); ++ // Paper end - missing entity behaviour api - converting without entity event + } +diff --git a/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java b/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java +index db69687a7ad4b18d17ab1677cae5d8dd4dcd3678..261bacee2a48580f781876683efea68c32ed7282 100644 +--- a/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java ++++ b/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java +@@ -24,4 +24,23 @@ public interface HopperMinecart extends Minecart, InventoryHolder, LootableEntit + * @param enabled new enabled state + */ + void setEnabled(boolean enabled); ++ // Paper start ++ /** ++ * Gets the number of ticks that this hopper minecart cannot pickup items up for. ++ * ++ * @return ticks left on cooldown ++ * @deprecated Hopper minecarts don't have cooldowns anymore ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.4") ++ int getPickupCooldown(); ++ ++ /** ++ * Sets the number of ticks that this hopper minecart cannot pickup items for. ++ * ++ * @param cooldown cooldown length in ticks ++ * @deprecated Hopper minecarts don't have cooldowns anymore ++ */ ++ @Deprecated(forRemoval = true, since = "1.19.4") ++ void setPickupCooldown(int cooldown); ++ // Paper end + } diff --git a/patches/api/0288-Adds-PlayerArmSwingEvent.patch b/patches/api/0288-Adds-PlayerArmSwingEvent.patch new file mode 100644 index 000000000000..339856843169 --- /dev/null +++ b/patches/api/0288-Adds-PlayerArmSwingEvent.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 12 Mar 2021 19:20:03 -0800 +Subject: [PATCH] Adds PlayerArmSwingEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerArmSwingEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerArmSwingEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..84dfb8da90c5f21d0f8899eca57bcb8b58614ca9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerArmSwingEvent.java +@@ -0,0 +1,29 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.event.player.PlayerAnimationEvent; ++import org.bukkit.event.player.PlayerAnimationType; ++import org.bukkit.inventory.EquipmentSlot; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public class PlayerArmSwingEvent extends PlayerAnimationEvent { ++ ++ private final EquipmentSlot equipmentSlot; ++ ++ @ApiStatus.Internal ++ public PlayerArmSwingEvent(final Player player, final EquipmentSlot equipmentSlot) { ++ super(player, equipmentSlot == EquipmentSlot.HAND ? PlayerAnimationType.ARM_SWING : PlayerAnimationType.OFF_ARM_SWING); ++ this.equipmentSlot = equipmentSlot; ++ } ++ ++ /** ++ * Returns the hand of the arm swing. ++ * ++ * @return the hand ++ */ ++ public EquipmentSlot getHand() { ++ return this.equipmentSlot; ++ } ++} +diff --git a/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java b/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java +index 1f2d3b3e9748eec04b5514376599c9233f65b736..0c7e3a0c4d77a8e11f96b9c498dbf2917ad2d981 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java +@@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull; + + /** + * Represents a player animation event ++ *
      Use {@link io.papermc.paper.event.player.PlayerArmSwingEvent} for determining which arm was swung. + */ + public class PlayerAnimationEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); diff --git a/patches/api/0289-Add-PlayerSignCommandPreprocessEvent.patch b/patches/api/0289-Add-PlayerSignCommandPreprocessEvent.patch new file mode 100644 index 000000000000..730b7af658f0 --- /dev/null +++ b/patches/api/0289-Add-PlayerSignCommandPreprocessEvent.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 9 Jul 2021 17:44:33 -0700 +Subject: [PATCH] Add PlayerSignCommandPreprocessEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerSignCommandPreprocessEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerSignCommandPreprocessEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..220f950ab804d756e89760c341aafe868b2b6ad0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerSignCommandPreprocessEvent.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.event.player; ++ ++import java.util.Set; ++import org.bukkit.block.Sign; ++import org.bukkit.block.sign.Side; ++import org.bukkit.entity.Player; ++import org.bukkit.event.player.PlayerCommandPreprocessEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a {@link Player} clicks a side on a sign that causes a command to run. ++ *

      ++ * This command is run with elevated permissions which allows players to access commands on signs they wouldn't ++ * normally be able to run. ++ */ ++@NullMarked ++public class PlayerSignCommandPreprocessEvent extends PlayerCommandPreprocessEvent { ++ ++ private final Sign sign; ++ private final Side side; ++ ++ @ApiStatus.Internal ++ public PlayerSignCommandPreprocessEvent(final Player player, final String message, final Set recipients, final Sign sign, final Side side) { ++ super(player, message, recipients); ++ this.sign = sign; ++ this.side = side; ++ } ++ ++ /** ++ * Gets the sign that the command originated from. ++ * ++ * @return the sign ++ */ ++ public Sign getSign() { ++ return this.sign; ++ } ++ ++ /** ++ * Gets the side of the sign that the command originated from. ++ * ++ * @return the sign side ++ */ ++ public Side getSide() { ++ return this.side; ++ } ++} diff --git a/patches/api/0289-add-RespawnFlags-to-PlayerRespawnEvent.patch b/patches/api/0289-add-RespawnFlags-to-PlayerRespawnEvent.patch deleted file mode 100644 index 3b5d058fccaa..000000000000 --- a/patches/api/0289-add-RespawnFlags-to-PlayerRespawnEvent.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 22 Apr 2021 17:17:54 -0700 -Subject: [PATCH] add RespawnFlags to PlayerRespawnEvent - - -diff --git a/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java -index f5bdb5244c8d993c624f938c8fb7ccff74655d75..3715584a8289200ffb968e384e359ab574aaec5c 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerRespawnEvent.java -@@ -17,17 +17,30 @@ public class PlayerRespawnEvent extends PlayerEvent { - private Location respawnLocation; - private final boolean isBedSpawn; - private final boolean isAnchorSpawn; -+ private final java.util.Set respawnFlags; // Paper - - @Deprecated - public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn) { - this(respawnPlayer, respawnLocation, isBedSpawn, false); - } - -+ @Deprecated // Paper - public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn, final boolean isAnchorSpawn) { -+ // Paper start -+ this(respawnPlayer, respawnLocation, isBedSpawn, isAnchorSpawn, com.google.common.collect.ImmutableSet.builder()); -+ } -+ -+ public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn, final boolean isAnchorSpawn, @NotNull final com.google.common.collect.ImmutableSet.Builder respawnFlags) { -+ // Paper end - super(respawnPlayer); - this.respawnLocation = respawnLocation; - this.isBedSpawn = isBedSpawn; - this.isAnchorSpawn = isAnchorSpawn; -+ // Paper start -+ if (this.isBedSpawn) { respawnFlags.add(RespawnFlag.BED_SPAWN); } -+ if (this.isAnchorSpawn) { respawnFlags.add(RespawnFlag.ANCHOR_SPAWN); } -+ this.respawnFlags = respawnFlags.build(); -+ // Paper end - } - - /** -@@ -80,4 +93,31 @@ public class PlayerRespawnEvent extends PlayerEvent { - public static HandlerList getHandlerList() { - return handlers; - } -+ -+ // Paper start -+ /** -+ * Get the set of flags that apply to this respawn. -+ * -+ * @return an immutable set of the flags that apply to this respawn -+ */ -+ @NotNull -+ public java.util.Set getRespawnFlags() { -+ return respawnFlags; -+ } -+ -+ public enum RespawnFlag { -+ /** -+ * Will use the bed spawn location -+ */ -+ BED_SPAWN, -+ /** -+ * Will use the respawn anchor location -+ */ -+ ANCHOR_SPAWN, -+ /** -+ * Is caused by going to the end portal in the end. -+ */ -+ END_PORTAL, -+ } -+ // Paper end - } diff --git a/patches/api/0290-fix-empty-array-elements-in-command-arguments.patch b/patches/api/0290-fix-empty-array-elements-in-command-arguments.patch new file mode 100644 index 000000000000..83bcf0fec05c --- /dev/null +++ b/patches/api/0290-fix-empty-array-elements-in-command-arguments.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Trigary +Date: Sat, 5 Jun 2021 10:29:39 +0200 +Subject: [PATCH] fix empty array elements in command arguments + +Adjacent spaces caused empty array elements due to how String#split works. +This change removes those empty array elements without modifying anything else. +Adjacent spaces sent by players are removed in PlayerConnection, so this change doesn't affect players. +But it does affect the console, command blocks, Bukkit.dispatchCommand, etc. + +diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java +index 27243a1214bc4d7dbb46f0b9b254c8e3f8128419..b5f9cd2bd191f8b071c6c95706ddbef97d3c244e 100644 +--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java ++++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java +@@ -131,7 +131,7 @@ public class SimpleCommandMap implements CommandMap { + */ + @Override + public boolean dispatch(@NotNull CommandSender sender, @NotNull String commandLine) throws CommandException { +- String[] args = commandLine.split(" "); ++ String[] args = org.apache.commons.lang3.StringUtils.split(commandLine, ' '); // Paper - fix adjacent spaces (from console/plugins) causing empty array elements + + if (args.length == 0) { + return false; diff --git a/patches/api/0291-Stinger-API.patch b/patches/api/0291-Stinger-API.patch new file mode 100644 index 000000000000..7d015b5c3dfe --- /dev/null +++ b/patches/api/0291-Stinger-API.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Tue, 22 Jun 2021 23:16:11 -0400 +Subject: [PATCH] Stinger API + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index c2ed2245604fcb638450d4aa00d8045685ce294d..292b8d0370723f019fb90a8b86300fa631bee683 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -451,6 +451,52 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + int getNextArrowRemoval(); + // Paper end - Add methods for working with arrows stuck in living entities + ++ // Paper start - Bee Stinger API ++ /** ++ * Gets the time in ticks until the next bee stinger leaves the entity's body. ++ * ++ * @return ticks until bee stinger leaves ++ */ ++ public int getBeeStingerCooldown(); ++ ++ /** ++ * Sets the time in ticks until the next stinger leaves the entity's body. ++ * ++ * @param ticks time until bee stinger leaves ++ */ ++ public void setBeeStingerCooldown(int ticks); ++ ++ /** ++ * Gets the amount of bee stingers in an entity's body. ++ * ++ * @return amount of bee stingers in body ++ */ ++ public int getBeeStingersInBody(); ++ ++ /** ++ * Set the amount of bee stingers in the entity's body. ++ * ++ * @param count amount of bee stingers in entity's body ++ */ ++ public void setBeeStingersInBody(int count); ++ ++ /** ++ * Sets the amount of ticks before the next bee stinger gets removed from the entities body. ++ *

      ++ * A value of 0 will cause the server to re-calculate the amount of ticks on the next tick. ++ * ++ * @param ticks Amount of ticks ++ */ ++ void setNextBeeStingerRemoval(@org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE) int ticks); ++ ++ /** ++ * Gets the amount of ticks before the next bee stinger gets removed from the entities body. ++ * ++ * @return ticks Amount of ticks ++ */ ++ int getNextBeeStingerRemoval(); ++ // Paper end - Stinger API ++ + /** + * Returns the living entity's current maximum no damage ticks. + *

      diff --git a/patches/api/0292-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch b/patches/api/0292-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch new file mode 100644 index 000000000000..aefa20a2d9cf --- /dev/null +++ b/patches/api/0292-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SirYwell +Date: Sat, 10 Jul 2021 11:11:43 +0200 +Subject: [PATCH] Rewrite LogEvents to contain the source jars in stack traces + + +diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +index 8c5597e02d71c8db66e9cd11f0a41776eb471c46..de017d10db19ca7ca7f73ff0ac08fe6e1773d7dc 100644 +--- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +@@ -56,7 +56,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm + + @org.jetbrains.annotations.ApiStatus.Internal // Paper + public PluginClassLoader(@Nullable final ClassLoader parent, @NotNull final PluginDescriptionFile description, @NotNull final File dataFolder, @NotNull final File file, @Nullable ClassLoader libraryLoader, JarFile jarFile, io.papermc.paper.plugin.provider.entrypoint.DependencyContext dependencyContext) throws IOException, InvalidPluginException, MalformedURLException { // Paper - use JarFile provided by SpigotPluginProvider +- super(new URL[] {file.toURI().toURL()}, parent); ++ super(file.getName(), new URL[] {file.toURI().toURL()}, parent); + this.loader = null; // Paper - pass null into loader field + + this.description = description; diff --git a/patches/api/0293-Add-PlayerSetSpawnEvent.patch b/patches/api/0293-Add-PlayerSetSpawnEvent.patch new file mode 100644 index 000000000000..a979a6b7fd38 --- /dev/null +++ b/patches/api/0293-Add-PlayerSetSpawnEvent.patch @@ -0,0 +1,201 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 19 May 2021 18:58:24 -0700 +Subject: [PATCH] Add PlayerSetSpawnEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerSetSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerSetSpawnEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..41d42d73cf65e9b8acac9d0b2dfd6537b532be74 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerSetSpawnEvent.java +@@ -0,0 +1,175 @@ ++package com.destroystokyo.paper.event.player; ++ ++import net.kyori.adventure.text.Component; ++import org.bukkit.Location; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when a player's spawn is set, either by themselves or otherwise. ++ *
      ++ * Cancelling this event will prevent the spawn from being set. ++ */ ++@NullMarked ++public class PlayerSetSpawnEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Cause cause; ++ private @Nullable Location location; ++ private boolean forced; ++ private boolean notifyPlayer; ++ private @Nullable Component notification; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerSetSpawnEvent(final Player player, final Cause cause, final @Nullable Location location, final boolean forced, final boolean notifyPlayer, final @Nullable Component notification) { ++ super(player); ++ this.cause = cause; ++ this.location = location; ++ this.forced = forced; ++ this.notifyPlayer = notifyPlayer; ++ this.notification = notification; ++ } ++ ++ /** ++ * Gets the cause of this event. ++ * ++ * @return the cause ++ */ ++ public Cause getCause() { ++ return this.cause; ++ } ++ ++ /** ++ * Gets the location that the spawn is set to. The yaw ++ * of this location is the spawn angle. Mutating this location ++ * will change the resulting spawn point of the player. Use ++ * {@link Location#clone()} to get a copy of this location. ++ * ++ * @return the spawn location, or {@code null} if removing the location ++ */ ++ public @Nullable Location getLocation() { ++ return this.location; ++ } ++ ++ /** ++ * Sets the location to be set as the spawn location. The yaw ++ * of this location is the spawn angle. ++ * ++ * @param location the spawn location, or {@code null} to remove the spawn location ++ */ ++ public void setLocation(final @Nullable Location location) { ++ this.location = location; ++ } ++ ++ /** ++ * Gets if this is a force spawn location ++ * ++ * @return {@code true} if forced ++ */ ++ public boolean isForced() { ++ return this.forced; ++ } ++ ++ /** ++ * Sets if this is a forced spawn location ++ * ++ * @param forced {@code true} to force ++ */ ++ public void setForced(final boolean forced) { ++ this.forced = forced; ++ } ++ ++ /** ++ * Gets if this action will notify the player their spawn ++ * has been set. ++ * ++ * @return {@code true} to notify ++ */ ++ public boolean willNotifyPlayer() { ++ return this.notifyPlayer; ++ } ++ ++ /** ++ * Sets if this action will notify the player that their spawn ++ * has been set. ++ * ++ * @param notifyPlayer {@code true} to notify ++ */ ++ public void setNotifyPlayer(final boolean notifyPlayer) { ++ this.notifyPlayer = notifyPlayer; ++ } ++ ++ /** ++ * Gets the notification message that will be sent to the player ++ * if {@link #willNotifyPlayer()} returns true. ++ * ++ * @return {@code null} if no notification ++ */ ++ public @Nullable Component getNotification() { ++ return this.notification; ++ } ++ ++ /** ++ * Sets the notification message that will be sent to the player. ++ * ++ * @param notification {@code null} to send no message ++ */ ++ public void setNotification(final @Nullable Component notification) { ++ this.notification = notification; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum Cause { ++ /** ++ * When a player interacts successfully with a bed. ++ */ ++ BED, ++ /** ++ * When a player interacts successfully with a respawn anchor. ++ */ ++ RESPAWN_ANCHOR, ++ /** ++ * When a player respawns. ++ */ ++ PLAYER_RESPAWN, ++ /** ++ * When the {@code /spawnpoint} command is used on a player. ++ */ ++ COMMAND, ++ /** ++ * When a plugin uses {@link Player#setRespawnLocation(Location)} or ++ * {@link Player#setRespawnLocation(Location, boolean)}. ++ */ ++ PLUGIN, ++ /** ++ * Fallback cause. ++ */ ++ UNKNOWN, ++ } ++} +diff --git a/src/main/java/org/bukkit/event/player/PlayerSpawnChangeEvent.java b/src/main/java/org/bukkit/event/player/PlayerSpawnChangeEvent.java +index b22feeda89df7a40d9e684923030230d1dd0a0fb..a57aaf09a2ce29aaeb29f8587509170dbcad24e9 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerSpawnChangeEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerSpawnChangeEvent.java +@@ -10,7 +10,9 @@ import org.jetbrains.annotations.Nullable; + + /** + * This event is fired when the spawn point of the player is changed. ++ * @deprecated use {@link com.destroystokyo.paper.event.player.PlayerSetSpawnEvent} + */ ++@Deprecated(forRemoval = true) // Paper + public class PlayerSpawnChangeEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); diff --git a/patches/api/0293-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch b/patches/api/0293-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch deleted file mode 100644 index bf487b87b127..000000000000 --- a/patches/api/0293-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Connor Linfoot -Date: Wed, 12 May 2021 08:09:19 +0100 -Subject: [PATCH] Add raw address to AsyncPlayerPreLoginEvent - - -diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -index 9acf1fb404ccf9b3bc06a448c3099ca2e838facf..baee5038ec7c3e190a328016d9ab290ae48badf6 100644 ---- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -+++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -@@ -20,6 +20,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - private net.kyori.adventure.text.Component message; // Paper - //private String name; // Paper - Not used anymore - private final InetAddress ipAddress; -+ private final InetAddress rawAddress; // Paper - //private UUID uniqueId; // Paper - Not used anymore - - @Deprecated -@@ -49,7 +50,23 @@ public class AsyncPlayerPreLoginEvent extends Event { - this.profile = profile; - } - -+ // Paper Start -+ /** -+ * Gets the raw address of the player logging in -+ * @return The address -+ */ -+ @NotNull -+ public InetAddress getRawAddress() { -+ return rawAddress; -+ } -+ // Paper end -+ -+ @Deprecated - public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId, @NotNull PlayerProfile profile) { -+ this(name, ipAddress, ipAddress, uniqueId, profile); -+ } -+ -+ public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, @NotNull PlayerProfile profile) { - super(true); - this.profile = profile; - // Paper end -@@ -57,6 +74,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - this.message = net.kyori.adventure.text.Component.empty(); // Paper - //this.name = name; // Paper - Not used anymore - this.ipAddress = ipAddress; -+ this.rawAddress = rawAddress; // Paper - //this.uniqueId = uniqueId; // Paper - Not used anymore - } - diff --git a/patches/api/0294-Added-EntityDamageItemEvent.patch b/patches/api/0294-Added-EntityDamageItemEvent.patch new file mode 100644 index 000000000000..fb5265e9e796 --- /dev/null +++ b/patches/api/0294-Added-EntityDamageItemEvent.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 22 Dec 2020 13:51:06 -0800 +Subject: [PATCH] Added EntityDamageItemEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityDamageItemEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityDamageItemEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c4cc0931892f949b7314d241dbe80caeceab4331 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityDamageItemEvent.java +@@ -0,0 +1,79 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when an item on or used by an entity takes durability damage as a result of being hit/used. ++ *

      ++ * NOTE: default vanilla behaviour dictates that armor/tools picked up by ++ * mobs do not take damage (except via Thorns). ++ */ ++@NullMarked ++public class EntityDamageItemEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ItemStack item; ++ private int damage; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityDamageItemEvent(final Entity entity, final ItemStack item, final int damage) { ++ super(entity); ++ this.item = item; ++ this.damage = damage; ++ } ++ ++ /** ++ * Gets the item being damaged. ++ * ++ * @return the item ++ */ ++ public ItemStack getItem() { ++ return this.item; ++ } ++ ++ /** ++ * Gets the amount of durability damage this item will be taking. ++ * ++ * @return durability change ++ */ ++ public int getDamage() { ++ return this.damage; ++ } ++ ++ /** ++ * Sets the amount of durability damage this item will be taking. ++ * ++ * @param damage the damage amount to cause ++ */ ++ public void setDamage(final int damage) { ++ this.damage = damage; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0294-Inventory-close.patch b/patches/api/0294-Inventory-close.patch deleted file mode 100644 index 9b5cbb7dfe8e..000000000000 --- a/patches/api/0294-Inventory-close.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 11 May 2021 14:54:20 -0700 -Subject: [PATCH] Inventory#close - - -diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/org/bukkit/inventory/Inventory.java -index 960626dd64ec9b0c5f4638c1ada463fd20c6b5fc..1b577c03c3152d22b70f8bdb321b28ad8fbbc3af 100644 ---- a/src/main/java/org/bukkit/inventory/Inventory.java -+++ b/src/main/java/org/bukkit/inventory/Inventory.java -@@ -352,6 +352,15 @@ public interface Inventory extends Iterable { - */ - public void clear(); - -+ // Paper start -+ /** -+ * Closes the inventory for all viewers. -+ * -+ * @return the number if viewers the inventory was closed for -+ */ -+ public int close(); -+ // Paper end -+ - /** - * Gets a list of players viewing the inventory. Note that a player is - * considered to be viewing their own inventory and internal crafting diff --git a/patches/api/0295-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch b/patches/api/0295-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch deleted file mode 100644 index 16cdba801629..000000000000 --- a/patches/api/0295-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MeFisto94 -Date: Tue, 11 May 2021 00:48:51 +0200 -Subject: [PATCH] Add a "should burn in sunlight" API for Phantoms and - Skeletons - - -diff --git a/src/main/java/org/bukkit/entity/AbstractSkeleton.java b/src/main/java/org/bukkit/entity/AbstractSkeleton.java -index 4f4f1e48cdaee0d845f60666569e48731be3fbb9..504fd761e5863c09fe785300a5c3e68e00baf2b0 100644 ---- a/src/main/java/org/bukkit/entity/AbstractSkeleton.java -+++ b/src/main/java/org/bukkit/entity/AbstractSkeleton.java -@@ -32,4 +32,24 @@ public interface AbstractSkeleton extends Monster, com.destroystokyo.paper.entit - @Deprecated - @Contract("_ -> fail") - public void setSkeletonType(Skeleton.SkeletonType type); -+ -+ // Paper start -+ /** -+ * Check if this skeleton will burn in the sunlight. This -+ * does not take into account an entity's natural fire -+ * immunity. -+ * -+ * @return True if skeleton will burn in sunlight -+ */ -+ boolean shouldBurnInDay(); -+ -+ /** -+ * Set if this skeleton should burn in the sunlight. This -+ * will not override an entity's natural fire -+ * immunity. -+ * -+ * @param shouldBurnInDay True to burn in sunlight -+ */ -+ void setShouldBurnInDay(boolean shouldBurnInDay); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Phantom.java b/src/main/java/org/bukkit/entity/Phantom.java -index ed4d417c2deefb78807cb61b01df5afcd334d754..a40b045f08b85e22e75459b547e7e7c0b95103ed 100644 ---- a/src/main/java/org/bukkit/entity/Phantom.java -+++ b/src/main/java/org/bukkit/entity/Phantom.java -@@ -26,5 +26,19 @@ public interface Phantom extends Flying { - */ - @Nullable - public java.util.UUID getSpawningEntity(); -+ -+ /** -+ * Check if this phantom will burn in the sunlight -+ * -+ * @return True if phantom will burn in sunlight -+ */ -+ public boolean shouldBurnInDay(); -+ -+ /** -+ * Set if this phantom should burn in the sunlight -+ * -+ * @param shouldBurnInDay True to burn in sunlight -+ */ -+ public void setShouldBurnInDay(boolean shouldBurnInDay); - // Paper end - } diff --git a/patches/api/0321-Make-EntityUnleashEvent-cancellable.patch b/patches/api/0295-Make-EntityUnleashEvent-cancellable.patch similarity index 100% rename from patches/api/0321-Make-EntityUnleashEvent-cancellable.patch rename to patches/api/0295-Make-EntityUnleashEvent-cancellable.patch diff --git a/patches/api/0296-Add-basic-Datapack-API.patch b/patches/api/0296-Add-basic-Datapack-API.patch deleted file mode 100644 index 4ceba1ef458f..000000000000 --- a/patches/api/0296-Add-basic-Datapack-API.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Connor Linfoot -Date: Sun, 16 May 2021 15:07:34 +0100 -Subject: [PATCH] Add basic Datapack API - - -diff --git a/src/main/java/io/papermc/paper/datapack/Datapack.java b/src/main/java/io/papermc/paper/datapack/Datapack.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7b2ab0be10a21e0496ad1d485ff8cb2c0b92a2cb ---- /dev/null -+++ b/src/main/java/io/papermc/paper/datapack/Datapack.java -@@ -0,0 +1,32 @@ -+package io.papermc.paper.datapack; -+ -+import org.checkerframework.checker.nullness.qual.NonNull; -+ -+public interface Datapack { -+ -+ /** -+ * @return the name of the pack -+ */ -+ @NonNull -+ String getName(); -+ -+ /** -+ * @return the compatibility of the pack -+ */ -+ @NonNull -+ Compatibility getCompatibility(); -+ -+ /** -+ * @return whether or not the pack is currently enabled -+ */ -+ boolean isEnabled(); -+ -+ void setEnabled(boolean enabled); -+ -+ enum Compatibility { -+ TOO_OLD, -+ TOO_NEW, -+ COMPATIBLE, -+ } -+ -+} -diff --git a/src/main/java/io/papermc/paper/datapack/DatapackManager.java b/src/main/java/io/papermc/paper/datapack/DatapackManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..58f78d5e91beacaf710f62461cf869f70d08b2a2 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/datapack/DatapackManager.java -@@ -0,0 +1,21 @@ -+package io.papermc.paper.datapack; -+ -+import org.checkerframework.checker.nullness.qual.NonNull; -+ -+import java.util.Collection; -+ -+public interface DatapackManager { -+ -+ /** -+ * @return all the packs known to the server -+ */ -+ @NonNull -+ Collection getPacks(); -+ -+ /** -+ * @return all the packs which are currently enabled -+ */ -+ @NonNull -+ Collection getEnabledPacks(); -+ -+} -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 0ddad5d32494495bb797559a10336a401e445fef..05186443e25706ed77f7187eea6ac84666613a88 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2374,6 +2374,14 @@ public final class Bukkit { - public static com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { - return server.getMobGoals(); - } -+ -+ /** -+ * @return the datapack manager -+ */ -+ @NotNull -+ public static io.papermc.paper.datapack.DatapackManager getDatapackManager() { -+ return server.getDatapackManager(); -+ } - // Paper end - - @NotNull -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 80d762390a42070f1953a388c896cd93640b506e..3d78e555725b48cb7e5750e8b4b3f1f0463bddc2 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -2063,5 +2063,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - */ - @NotNull - com.destroystokyo.paper.entity.ai.MobGoals getMobGoals(); -+ -+ /** -+ * @return the datapack manager -+ */ -+ @NotNull -+ io.papermc.paper.datapack.DatapackManager getDatapackManager(); - // Paper end - } diff --git a/patches/api/0322-Change-EnderEye-target-without-changing-other-things.patch b/patches/api/0296-Change-EnderEye-target-without-changing-other-things.patch similarity index 100% rename from patches/api/0322-Change-EnderEye-target-without-changing-other-things.patch rename to patches/api/0296-Change-EnderEye-target-without-changing-other-things.patch diff --git a/patches/api/0297-Add-BlockBreakBlockEvent.patch b/patches/api/0297-Add-BlockBreakBlockEvent.patch new file mode 100644 index 000000000000..522d22a4def2 --- /dev/null +++ b/patches/api/0297-Add-BlockBreakBlockEvent.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 3 Jan 2021 17:58:25 -0800 +Subject: [PATCH] Add BlockBreakBlockEvent + + +diff --git a/src/main/java/io/papermc/paper/event/block/BlockBreakBlockEvent.java b/src/main/java/io/papermc/paper/event/block/BlockBreakBlockEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3b130d145f54939ad02e30b15c81120aac2078c2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BlockBreakBlockEvent.java +@@ -0,0 +1,57 @@ ++package io.papermc.paper.event.block; ++ ++import java.util.List; ++import org.bukkit.block.Block; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockExpEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a block forces another block to break and drop items. ++ *

      ++ * Currently called for piston's and liquid flows. ++ */ ++@NullMarked ++public class BlockBreakBlockEvent extends BlockExpEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Block source; ++ private final List drops; ++ ++ @ApiStatus.Internal ++ public BlockBreakBlockEvent(final Block block, final Block source, final List drops) { ++ super(block, 0); ++ this.source = source; ++ this.drops = drops; ++ } ++ ++ /** ++ * Gets a mutable list of drops for this event ++ * ++ * @return the drops ++ */ ++ public List getDrops() { ++ return this.drops; ++ } ++ ++ /** ++ * Gets the block that cause this (e.g. a piston, or adjacent liquid) ++ * ++ * @return the source ++ */ ++ public Block getSource() { ++ return this.source; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0324-Add-helpers-for-left-right-click-to-Action.patch b/patches/api/0298-Add-helpers-for-left-right-click-to-Action.patch similarity index 100% rename from patches/api/0324-Add-helpers-for-left-right-click-to-Action.patch rename to patches/api/0298-Add-helpers-for-left-right-click-to-Action.patch diff --git a/patches/api/0298-ItemStack-repair-check-API.patch b/patches/api/0298-ItemStack-repair-check-API.patch deleted file mode 100644 index 4fb4ae3ebd1c..000000000000 --- a/patches/api/0298-ItemStack-repair-check-API.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 15 May 2021 22:10:50 -0700 -Subject: [PATCH] ItemStack repair check API - - -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index eadba6454530724619872034f6e680b4603b8a69..248453b259781aa45516133a0ed824f4e6f6a369 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -180,6 +180,16 @@ public interface UnsafeValues { - */ - public io.papermc.paper.inventory.ItemRarity getItemStackRarity(ItemStack itemStack); - -+ /** -+ * Checks if an itemstack can be repaired with another itemstack. -+ * Returns false if either argument's type is not an item ({@link Material#isItem()}). -+ * -+ * @param itemToBeRepaired the itemstack to be repaired -+ * @param repairMaterial the repair material -+ * @return true if valid repair, false if not -+ */ -+ public boolean isValidRepairItemStack(@org.jetbrains.annotations.NotNull ItemStack itemToBeRepaired, @org.jetbrains.annotations.NotNull ItemStack repairMaterial); -+ - /** - * Returns the server's protocol version. - * -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 75bd1f7a5a30d21ae61836072ec057a95b7c288b..0d0d7bda2d4fafffd3e80a359019626ab44031d0 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -893,5 +893,27 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - public io.papermc.paper.inventory.ItemRarity getRarity() { - return Bukkit.getUnsafe().getItemStackRarity(this); - } -+ -+ /** -+ * Checks if an itemstack can repair this itemstack. -+ * Returns false if {@code this} or {@code repairMaterial}'s type is not an item ({@link Material#isItem()}). -+ * -+ * @param repairMaterial the repair material -+ * @return true if it is repairable by, false if not -+ */ -+ public boolean isRepairableBy(@NotNull ItemStack repairMaterial) { -+ return Bukkit.getUnsafe().isValidRepairItemStack(this, repairMaterial); -+ } -+ -+ /** -+ * Checks if this itemstack can repair another. -+ * Returns false if {@code this} or {@code toBeRepaired}'s type is not an item ({@link Material#isItem()}). -+ * -+ * @param toBeRepaired the itemstack to be repaired -+ * @return true if it can repair, false if not -+ */ -+ public boolean canRepair(@NotNull ItemStack toBeRepaired) { -+ return Bukkit.getUnsafe().isValidRepairItemStack(toBeRepaired, this); -+ } - // Paper end - } diff --git a/patches/api/0299-More-Enchantment-API.patch b/patches/api/0299-More-Enchantment-API.patch deleted file mode 100644 index 50fae967aee1..000000000000 --- a/patches/api/0299-More-Enchantment-API.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 6 May 2021 19:58:03 -0700 -Subject: [PATCH] More Enchantment API - - -diff --git a/src/main/java/io/papermc/paper/enchantments/EnchantmentRarity.java b/src/main/java/io/papermc/paper/enchantments/EnchantmentRarity.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e6a40c1fcea761bd66743b50e3da3d14797d05b0 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/enchantments/EnchantmentRarity.java -@@ -0,0 +1,24 @@ -+package io.papermc.paper.enchantments; -+ -+public enum EnchantmentRarity { -+ -+ COMMON(10), -+ UNCOMMON(5), -+ RARE(2), -+ VERY_RARE(1); -+ -+ private final int weight; -+ -+ EnchantmentRarity(int weight) { -+ this.weight = weight; -+ } -+ -+ /** -+ * Gets the weight for the rarity. -+ * -+ * @return the weight -+ */ -+ public int getWeight() { -+ return weight; -+ } -+} -diff --git a/src/main/java/org/bukkit/enchantments/Enchantment.java b/src/main/java/org/bukkit/enchantments/Enchantment.java -index 0264c2f9a3977b6d47994b1e1b0240b312e5bf65..69a048eb4e48c92db70c3d6b6aa4ae96326b9705 100644 ---- a/src/main/java/org/bukkit/enchantments/Enchantment.java -+++ b/src/main/java/org/bukkit/enchantments/Enchantment.java -@@ -273,11 +273,7 @@ public abstract class Enchantment implements Keyed, net.kyori.adventure.translat - * Cursed enchantments are found the same way treasure enchantments are - * - * @return true if the enchantment is cursed -- * @deprecated cursed enchantments are no longer special. Will return true -- * only for {@link Enchantment#BINDING_CURSE} and -- * {@link Enchantment#VANISHING_CURSE}. - */ -- @Deprecated - public abstract boolean isCursed(); - - /** -@@ -311,6 +307,46 @@ public abstract class Enchantment implements Keyed, net.kyori.adventure.translat - * @return the name of the enchantment with {@code level} applied - */ - public abstract @NotNull net.kyori.adventure.text.Component displayName(int level); -+ -+ /** -+ * Checks if this enchantment can be found in villager trades. -+ * -+ * @return true if the enchantment can be found in trades -+ */ -+ public abstract boolean isTradeable(); -+ -+ /** -+ * Checks if this enchantment can be found in an enchanting table -+ * or use to enchant items generated by loot tables. -+ * -+ * @return true if the enchantment can be found in a table or by loot tables -+ */ -+ public abstract boolean isDiscoverable(); -+ -+ /** -+ * Gets the rarity of this enchantment. -+ * -+ * @return the rarity -+ */ -+ @NotNull -+ public abstract io.papermc.paper.enchantments.EnchantmentRarity getRarity(); -+ -+ /** -+ * Gets the damage increase as a result of the level and entity category specified -+ * -+ * @param level the level of enchantment -+ * @param entityCategory the category of entity -+ * @return the damage increase -+ */ -+ public abstract float getDamageIncrease(int level, @NotNull org.bukkit.entity.EntityCategory entityCategory); -+ -+ /** -+ * Gets the equipment slots where this enchantment is considered "active". -+ * -+ * @return the equipment slots -+ */ -+ @NotNull -+ public abstract java.util.Set getActiveSlots(); - // Paper end - - @Override -diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java -index a39f9c078f42451bd122f3e3729d10ca299bee5f..5f42a9c0c43ced10b754170d7c83793a99fce81b 100644 ---- a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java -+++ b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java -@@ -74,5 +74,32 @@ public class EnchantmentWrapper extends Enchantment { - public @NotNull String translationKey() { - return getEnchantment().translationKey(); - } -+ -+ @Override -+ public boolean isTradeable() { -+ return getEnchantment().isTradeable(); -+ } -+ -+ @Override -+ public boolean isDiscoverable() { -+ return getEnchantment().isDiscoverable(); -+ } -+ -+ @NotNull -+ @Override -+ public io.papermc.paper.enchantments.EnchantmentRarity getRarity() { -+ return getEnchantment().getRarity(); -+ } -+ -+ @Override -+ public float getDamageIncrease(int level, @NotNull org.bukkit.entity.EntityCategory entityCategory) { -+ return getEnchantment().getDamageIncrease(level, entityCategory); -+ } -+ -+ @NotNull -+ @Override -+ public java.util.Set getActiveSlots() { -+ return getEnchantment().getActiveSlots(); -+ } - // Paper end - } diff --git a/patches/api/0299-Option-to-prevent-data-components-copy-in-smithing-r.patch b/patches/api/0299-Option-to-prevent-data-components-copy-in-smithing-r.patch new file mode 100644 index 000000000000..db16d372fa09 --- /dev/null +++ b/patches/api/0299-Option-to-prevent-data-components-copy-in-smithing-r.patch @@ -0,0 +1,122 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 26 Sep 2021 12:57:35 -0700 +Subject: [PATCH] Option to prevent data components copy in smithing recipes + + +diff --git a/src/main/java/org/bukkit/inventory/SmithingRecipe.java b/src/main/java/org/bukkit/inventory/SmithingRecipe.java +index 6ad1f37372cd77c0f0534deae53125ad148caa7f..eb1c83455e198ff9d6334499be1a865db8e03a2c 100644 +--- a/src/main/java/org/bukkit/inventory/SmithingRecipe.java ++++ b/src/main/java/org/bukkit/inventory/SmithingRecipe.java +@@ -14,6 +14,7 @@ public class SmithingRecipe implements Recipe, Keyed { + private final ItemStack result; + private final RecipeChoice base; + private final RecipeChoice addition; ++ private final boolean copyDataComponents; // Paper + + /** + * Create a smithing recipe to produce the specified result ItemStack. +@@ -29,6 +30,23 @@ public class SmithingRecipe implements Recipe, Keyed { + */ + @Deprecated(since = "1.20.1") + public SmithingRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result, @Nullable RecipeChoice base, @Nullable RecipeChoice addition) { ++ // Paper start ++ this(key, result, base, addition, true); ++ } ++ /** ++ * Create a smithing recipe to produce the specified result ItemStack. ++ * ++ * @param key The unique recipe key ++ * @param result The item you want the recipe to create. ++ * @param base The base ingredient ++ * @param addition The addition ingredient ++ * @param copyDataComponents whether to copy the data components from the input base item to the output ++ * @deprecated use {@link SmithingTrimRecipe} or {@link SmithingTransformRecipe} ++ */ ++ @Deprecated ++ public SmithingRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result, @Nullable RecipeChoice base, @Nullable RecipeChoice addition, boolean copyDataComponents) { ++ this.copyDataComponents = copyDataComponents; ++ // Paper end + this.key = key; + this.result = result; + this.base = base; +@@ -66,4 +84,26 @@ public class SmithingRecipe implements Recipe, Keyed { + public NamespacedKey getKey() { + return this.key; + } ++ ++ // Paper start ++ /** ++ * Whether to copy the NBT of the input base item to the output. ++ * ++ * @return true to copy the NBT (default for vanilla smithing recipes) ++ * @apiNote use {@link #willCopyDataComponents()} ++ */ ++ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.20.5") ++ public boolean willCopyNbt() { ++ return this.willCopyDataComponents(); ++ } ++ ++ /** ++ * Whether to copy the data components of the input base item to the output. ++ * ++ * @return true to copy the data components (default for vanilla smithing recipes) ++ */ ++ public boolean willCopyDataComponents() { ++ return this.copyDataComponents; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/SmithingTransformRecipe.java b/src/main/java/org/bukkit/inventory/SmithingTransformRecipe.java +index 7a9d77a0cd1c287a3f940f94d4398f84720488aa..e5726da0507ee70cb9dd76c57da6a8442e771307 100644 +--- a/src/main/java/org/bukkit/inventory/SmithingTransformRecipe.java ++++ b/src/main/java/org/bukkit/inventory/SmithingTransformRecipe.java +@@ -24,6 +24,22 @@ public class SmithingTransformRecipe extends SmithingRecipe { + super(key, result, base, addition); + this.template = template; + } ++ // Paper start ++ /** ++ * Create a smithing recipe to produce the specified result ItemStack. ++ * ++ * @param key The unique recipe key ++ * @param result The item you want the recipe to create. ++ * @param template The template item. ++ * @param base The base ingredient ++ * @param addition The addition ingredient ++ * @param copyDataComponents whether to copy the data components from the input base item to the output ++ */ ++ public SmithingTransformRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result, @Nullable RecipeChoice template, @Nullable RecipeChoice base, @Nullable RecipeChoice addition, boolean copyDataComponents) { ++ super(key, result, base, addition, copyDataComponents); ++ this.template = template; ++ } ++ // Paper end + + /** + * Get the template recipe item. +diff --git a/src/main/java/org/bukkit/inventory/SmithingTrimRecipe.java b/src/main/java/org/bukkit/inventory/SmithingTrimRecipe.java +index 4271c54cfbb0fabd241794d8aea31374d7efe45a..232aa8aeef9e34146e413e56b3681919c8850687 100644 +--- a/src/main/java/org/bukkit/inventory/SmithingTrimRecipe.java ++++ b/src/main/java/org/bukkit/inventory/SmithingTrimRecipe.java +@@ -24,6 +24,21 @@ public class SmithingTrimRecipe extends SmithingRecipe implements ComplexRecipe + super(key, new ItemStack(Material.AIR), base, addition); + this.template = template; + } ++ // Paper start ++ /** ++ * Create a smithing recipe to produce the specified result ItemStack. ++ * ++ * @param key The unique recipe key ++ * @param template The template item. ++ * @param base The base ingredient ++ * @param addition The addition ingredient ++ * @param copyDataComponents whether to copy the data components from the input base item to the output ++ */ ++ public SmithingTrimRecipe(@NotNull NamespacedKey key, @NotNull RecipeChoice template, @NotNull RecipeChoice base, @NotNull RecipeChoice addition, boolean copyDataComponents) { ++ super(key, new ItemStack(Material.AIR), base, addition, copyDataComponents); ++ this.template = template; ++ } ++ // Paper end + + /** + * Get the template recipe item. diff --git a/patches/api/0300-List-all-missing-hard-depends-not-just-first.patch b/patches/api/0300-List-all-missing-hard-depends-not-just-first.patch deleted file mode 100644 index 4aee9b23ef4b..000000000000 --- a/patches/api/0300-List-all-missing-hard-depends-not-just-first.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 18 May 2021 10:38:10 -0700 -Subject: [PATCH] List all missing hard depends not just first - - -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index 9654f4fb230945086a88f64b09a46a5b10e8d1d7..35aa6dff52944019510f16180e36da0088654432 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -257,6 +257,7 @@ public final class SimplePluginManager implements PluginManager { - - if (dependencies.containsKey(plugin)) { - Iterator dependencyIterator = dependencies.get(plugin).iterator(); -+ final Set missingHardDependencies = new HashSet<>(dependencies.get(plugin).size()); // Paper - list all missing hard depends - - while (dependencyIterator.hasNext()) { - String dependency = dependencyIterator.next(); -@@ -267,6 +268,12 @@ public final class SimplePluginManager implements PluginManager { - - // We have a dependency not found - } else if (!plugins.containsKey(dependency) && !pluginsProvided.containsKey(dependency)) { -+ // Paper start -+ missingHardDependencies.add(dependency); -+ } -+ } -+ if (!missingHardDependencies.isEmpty()) { -+ // Paper end - missingDependency = false; - pluginIterator.remove(); - softDependencies.remove(plugin); -@@ -275,9 +282,7 @@ public final class SimplePluginManager implements PluginManager { - server.getLogger().log( - Level.SEVERE, - "Could not load '" + entry.getValue().getPath() + "' in folder '" + entry.getValue().getParentFile().getPath() + "'", // Paper -- new UnknownDependencyException("Unknown dependency " + dependency + ". Please download and install " + dependency + " to run this plugin.")); -- break; -- } -+ new UnknownDependencyException(missingHardDependencies, plugin)); // Paper - } - - if (dependencies.containsKey(plugin) && dependencies.get(plugin).isEmpty()) { -diff --git a/src/main/java/org/bukkit/plugin/UnknownDependencyException.java b/src/main/java/org/bukkit/plugin/UnknownDependencyException.java -index a80251eff75430863b37db1c131e22593f3fcd5e..7b2e607a21f1173d98ee84581881411176380625 100644 ---- a/src/main/java/org/bukkit/plugin/UnknownDependencyException.java -+++ b/src/main/java/org/bukkit/plugin/UnknownDependencyException.java -@@ -26,6 +26,19 @@ public class UnknownDependencyException extends RuntimeException { - super(message); - } - -+ // Paper start -+ /** -+ * Create a new {@link UnknownDependencyException} with a message informing -+ * about which dependencies are missing for what plugin. -+ * -+ * @param missingDependencies missing dependencies -+ * @param pluginName plugin which is missing said dependencies -+ */ -+ public UnknownDependencyException(final @org.jetbrains.annotations.NotNull java.util.Collection missingDependencies, final @org.jetbrains.annotations.NotNull String pluginName) { -+ this("Unknown/missing dependency plugins: [" + String.join(", ", missingDependencies) + "]. Please download and install these plugins to run '" + pluginName + "'."); -+ } -+ // Paper end -+ - /** - * Constructs a new UnknownDependencyException based on the given - * Exception -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index 4b54af83ef8fd18696d2d21ed52b61f13bff7988..8ff78fad47f6086aa289e32590f4fbec24b3d500 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -132,13 +132,19 @@ public final class JavaPluginLoader implements PluginLoader { - )); - } - -+ Set missingHardDependencies = new HashSet<>(description.getDepend().size()); // Paper - list all missing hard depends - for (final String pluginName : description.getDepend()) { - Plugin current = server.getPluginManager().getPlugin(pluginName); - - if (current == null) { -- throw new UnknownDependencyException("Unknown dependency " + pluginName + ". Please download and install " + pluginName + " to run this plugin."); -+ missingHardDependencies.add(pluginName); // Paper - list all missing hard depends - } - } -+ // Paper start - list all missing hard depends -+ if (!missingHardDependencies.isEmpty()) { -+ throw new UnknownDependencyException(missingHardDependencies, description.getFullName()); -+ } -+ // Paper end - - server.getUnsafe().checkSupported(description); - diff --git a/patches/api/0300-More-CommandBlock-API.patch b/patches/api/0300-More-CommandBlock-API.patch new file mode 100644 index 000000000000..077206eca6e0 --- /dev/null +++ b/patches/api/0300-More-CommandBlock-API.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 28 May 2021 21:47:39 -0700 +Subject: [PATCH] More CommandBlock API + + +diff --git a/src/main/java/io/papermc/paper/command/CommandBlockHolder.java b/src/main/java/io/papermc/paper/command/CommandBlockHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8dc061e38a1728ec4d9dddcb3564ed1b1da746c8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/CommandBlockHolder.java +@@ -0,0 +1,57 @@ ++package io.papermc.paper.command; ++ ++import net.kyori.adventure.text.Component; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@NullMarked ++public interface CommandBlockHolder { ++ ++ /** ++ * Gets the command that this CommandBlock will run when powered. ++ * This will never return null. If the CommandBlock does not have a ++ * command, an empty String will be returned instead. ++ * ++ * @return Command that this CommandBlock will run when activated. ++ */ ++ String getCommand(); ++ ++ /** ++ * Sets the command that this CommandBlock will run when powered. ++ * Setting the command to null is the same as setting it to an empty ++ * String. ++ * ++ * @param command Command that this CommandBlock will run when activated. ++ */ ++ void setCommand(@Nullable String command); ++ ++ /** ++ * Gets the last output from this command block. ++ * ++ * @return the last output ++ */ ++ Component lastOutput(); ++ ++ /** ++ * Sets the last output from this command block. ++ * ++ * @param lastOutput the last output ++ */ ++ void lastOutput(@Nullable Component lastOutput); ++ ++ /** ++ * Gets the success count from this command block. ++ * @see Command_Block#Success_count ++ * ++ * @return the success count ++ */ ++ int getSuccessCount(); ++ ++ /** ++ * Sets the success count from this command block. ++ * @see Command_Block#Success_count ++ * ++ * @param successCount the success count ++ */ ++ void setSuccessCount(int successCount); ++} +diff --git a/src/main/java/org/bukkit/block/CommandBlock.java b/src/main/java/org/bukkit/block/CommandBlock.java +index 9c88be68b4f403d0500cb607394b3a1646675ef7..02bf0f8c12052dd5c17422153228083f56bea75b 100644 +--- a/src/main/java/org/bukkit/block/CommandBlock.java ++++ b/src/main/java/org/bukkit/block/CommandBlock.java +@@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a captured state of a command block. + */ +-public interface CommandBlock extends TileState { ++public interface CommandBlock extends TileState, io.papermc.paper.command.CommandBlockHolder { // Paper + + /** + * Gets the command that this CommandBlock will run when powered. +diff --git a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java +index 91cab8b13d5bba34007f124838b32a1df58c5ac7..6a6021ad3a0e6aaf51f5144fa126e81bada9cfcf 100644 +--- a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java ++++ b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java +@@ -4,7 +4,7 @@ import org.bukkit.entity.Minecart; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +-public interface CommandMinecart extends Minecart { ++public interface CommandMinecart extends Minecart, io.papermc.paper.command.CommandBlockHolder { // Paper + + /** + * Gets the command that this CommandMinecart will run when activated. diff --git a/patches/api/0301-Add-Mob-lookAt-API.patch b/patches/api/0301-Add-Mob-lookAt-API.patch deleted file mode 100644 index 26177f2369cc..000000000000 --- a/patches/api/0301-Add-Mob-lookAt-API.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 14 May 2021 13:42:06 -0500 -Subject: [PATCH] Add Mob#lookAt API - - -diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java -index 55c5227a340e34621160afc9fae3ea843492881d..07bedbc15ba2463d3c629ae68d229286d4033f79 100644 ---- a/src/main/java/org/bukkit/entity/Mob.java -+++ b/src/main/java/org/bukkit/entity/Mob.java -@@ -26,6 +26,88 @@ public interface Mob extends LivingEntity, Lootable { - * @return True if mob is exposed to daylight - */ - boolean isInDaylight(); -+ -+ /** -+ * Instruct this Mob to look at a specific Location -+ *

      -+ * Useful when implementing custom mob goals -+ * -+ * @param location location to look at -+ */ -+ void lookAt(@NotNull org.bukkit.Location location); -+ -+ /** -+ * Instruct this Mob to look at a specific Location -+ *

      -+ * Useful when implementing custom mob goals -+ * -+ * @param location location to look at -+ * @param headRotationSpeed head rotation speed -+ * @param maxHeadPitch max head pitch rotation -+ */ -+ void lookAt(@NotNull org.bukkit.Location location, float headRotationSpeed, float maxHeadPitch); -+ -+ /** -+ * Instruct this Mob to look at a specific Entity -+ *

      -+ * If a LivingEntity, look at eye location -+ *

      -+ * Useful when implementing custom mob goals -+ * -+ * @param entity entity to look at -+ */ -+ void lookAt(@NotNull Entity entity); -+ -+ /** -+ * Instruct this Mob to look at a specific Entity -+ *

      -+ * If a LivingEntity, look at eye location -+ *

      -+ * Useful when implementing custom mob goals -+ * -+ * @param entity entity to look at -+ * @param headRotationSpeed head rotation speed -+ * @param maxHeadPitch max head pitch rotation -+ */ -+ void lookAt(@NotNull Entity entity, float headRotationSpeed, float maxHeadPitch); -+ -+ /** -+ * Instruct this Mob to look at a specific position -+ *

      -+ * Useful when implementing custom mob goals -+ * -+ * @param x x coordinate -+ * @param y y coordinate -+ * @param z z coordinate -+ */ -+ void lookAt(double x, double y, double z); -+ -+ /** -+ * Instruct this Mob to look at a specific position -+ *

      -+ * Useful when implementing custom mob goals -+ * -+ * @param x x coordinate -+ * @param y y coordinate -+ * @param z z coordinate -+ * @param headRotationSpeed head rotation speed -+ * @param maxHeadPitch max head pitch rotation -+ */ -+ void lookAt(double x, double y, double z, float headRotationSpeed, float maxHeadPitch); -+ -+ /** -+ * Gets the head rotation speed -+ * -+ * @return the head rotation speed -+ */ -+ int getHeadRotationSpeed(); -+ -+ /** -+ * Gets the max head pitch rotation -+ * -+ * @return the max head pitch rotation -+ */ -+ int getMaxHeadPitch(); - // Paper end - /** - * Instructs this Mob to set the specified LivingEntity as its target. diff --git a/patches/api/0301-Add-missing-team-sidebar-display-slots.patch b/patches/api/0301-Add-missing-team-sidebar-display-slots.patch new file mode 100644 index 000000000000..cdecbd1764fe --- /dev/null +++ b/patches/api/0301-Add-missing-team-sidebar-display-slots.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 1 Oct 2021 08:04:43 -0700 +Subject: [PATCH] Add missing team sidebar display slots + + +diff --git a/src/main/java/org/bukkit/scoreboard/DisplaySlot.java b/src/main/java/org/bukkit/scoreboard/DisplaySlot.java +index 4959bec21d152a17fe4ca9d3f448aef482a05b5e..21cd2ba659504c3a1eb95226539a5701d0c324db 100644 +--- a/src/main/java/org/bukkit/scoreboard/DisplaySlot.java ++++ b/src/main/java/org/bukkit/scoreboard/DisplaySlot.java +@@ -1,26 +1,55 @@ + package org.bukkit.scoreboard; + ++import net.kyori.adventure.text.format.NamedTextColor; // Paper + /** + * Locations for displaying objectives to the player + */ + public enum DisplaySlot { +- BELOW_NAME, +- PLAYER_LIST, +- SIDEBAR, +- SIDEBAR_BLACK, +- SIDEBAR_DARK_BLUE, +- SIDEBAR_DARK_GREEN, +- SIDEBAR_DARK_AQUA, +- SIDEBAR_DARK_RED, +- SIDEBAR_DARK_PURPLE, +- SIDEBAR_GOLD, +- SIDEBAR_GRAY, +- SIDEBAR_DARK_GRAY, +- SIDEBAR_BLUE, +- SIDEBAR_GREEN, +- SIDEBAR_AQUA, +- SIDEBAR_RED, +- SIDEBAR_LIGHT_PURPLE, +- SIDEBAR_YELLOW, +- SIDEBAR_WHITE; ++ // Paper start ++ BELOW_NAME("below_name"), ++ PLAYER_LIST("list"), ++ SIDEBAR("sidebar"), ++ SIDEBAR_TEAM_BLACK(NamedTextColor.BLACK), ++ SIDEBAR_TEAM_DARK_BLUE(NamedTextColor.DARK_BLUE), ++ SIDEBAR_TEAM_DARK_GREEN(NamedTextColor.DARK_GREEN), ++ SIDEBAR_TEAM_DARK_AQUA(NamedTextColor.DARK_AQUA), ++ SIDEBAR_TEAM_DARK_RED(NamedTextColor.DARK_RED), ++ SIDEBAR_TEAM_DARK_PURPLE(NamedTextColor.DARK_PURPLE), ++ SIDEBAR_TEAM_GOLD(NamedTextColor.GOLD), ++ SIDEBAR_TEAM_GRAY(NamedTextColor.GRAY), ++ SIDEBAR_TEAM_DARK_GRAY(NamedTextColor.DARK_GRAY), ++ SIDEBAR_TEAM_BLUE(NamedTextColor.BLUE), ++ SIDEBAR_TEAM_GREEN(NamedTextColor.GREEN), ++ SIDEBAR_TEAM_AQUA(NamedTextColor.AQUA), ++ SIDEBAR_TEAM_RED(NamedTextColor.RED), ++ SIDEBAR_TEAM_LIGHT_PURPLE(NamedTextColor.LIGHT_PURPLE), ++ SIDEBAR_TEAM_YELLOW(NamedTextColor.YELLOW), ++ SIDEBAR_TEAM_WHITE(NamedTextColor.WHITE); ++ ++ public static final net.kyori.adventure.util.Index NAMES = net.kyori.adventure.util.Index.create(DisplaySlot.class, DisplaySlot::getId); ++ ++ private final String id; ++ ++ DisplaySlot(@org.jetbrains.annotations.NotNull String id) { ++ this.id = id; ++ } ++ ++ DisplaySlot(@org.jetbrains.annotations.NotNull NamedTextColor color) { ++ this.id = "sidebar.team." + color; ++ } ++ ++ /** ++ * Get the string id of this display slot. ++ * ++ * @return the string id ++ */ ++ public @org.jetbrains.annotations.NotNull String getId() { ++ return id; ++ } ++ ++ @Override ++ public String toString() { ++ return this.id; ++ } ++ // Paper end + } diff --git a/patches/api/0302-ItemStack-editMeta.patch b/patches/api/0302-ItemStack-editMeta.patch deleted file mode 100644 index a6b2d88a10c9..000000000000 --- a/patches/api/0302-ItemStack-editMeta.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Riley Park -Date: Sun, 23 May 2021 05:04:28 -0700 -Subject: [PATCH] ItemStack#editMeta - - -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 0d0d7bda2d4fafffd3e80a359019626ab44031d0..77ef41527a05e2d7899633ef7fa813774dd15bd9 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -546,6 +546,50 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - return result.ensureServerConversions(); // Paper - } - -+ // Paper start -+ /** -+ * Edits the {@link ItemMeta} of this stack. -+ *

      -+ * The {@link java.util.function.Consumer} must only interact -+ * with this stack's {@link ItemMeta} through the provided {@link ItemMeta} instance. -+ * Calling this method or any other meta-related method of the {@link ItemStack} class -+ * (such as {@link #getItemMeta()}, {@link #addItemFlags(ItemFlag...)}, {@link #lore()}, etc.) -+ * from inside the consumer is disallowed and will produce undefined results or exceptions. -+ *

      -+ * -+ * @param consumer the meta consumer -+ * @return {@code true} if the edit was successful, {@code false} otherwise -+ */ -+ public boolean editMeta(final @NotNull java.util.function.Consumer consumer) { -+ return editMeta(ItemMeta.class, consumer); -+ } -+ -+ /** -+ * Edits the {@link ItemMeta} of this stack if the meta is of the specified type. -+ *

      -+ * The {@link java.util.function.Consumer} must only interact -+ * with this stack's {@link ItemMeta} through the provided {@link ItemMeta} instance. -+ * Calling this method or any other meta-related method of the {@link ItemStack} class -+ * (such as {@link #getItemMeta()}, {@link #addItemFlags(ItemFlag...)}, {@link #lore()}, etc.) -+ * from inside the consumer is disallowed and will produce undefined results or exceptions. -+ *

      -+ * -+ * @param metaClass the type of meta to edit -+ * @param consumer the meta consumer -+ * @param the meta type -+ * @return {@code true} if the edit was successful, {@code false} otherwise -+ */ -+ public boolean editMeta(final @NotNull Class metaClass, final @NotNull java.util.function.Consumer<@NotNull ? super M> consumer) { -+ final @Nullable ItemMeta meta = this.getItemMeta(); -+ if (metaClass.isInstance(meta)) { -+ consumer.accept((M) meta); -+ this.setItemMeta(meta); -+ return true; -+ } -+ return false; -+ } -+ // Paper end -+ - /** - * Get a copy of this ItemStack's {@link ItemMeta}. - * diff --git a/patches/api/0329-add-back-EntityPortalExitEvent.patch b/patches/api/0302-add-back-EntityPortalExitEvent.patch similarity index 100% rename from patches/api/0329-add-back-EntityPortalExitEvent.patch rename to patches/api/0302-add-back-EntityPortalExitEvent.patch diff --git a/patches/api/0303-Add-EntityInsideBlockEvent.patch b/patches/api/0303-Add-EntityInsideBlockEvent.patch deleted file mode 100644 index 26c188e7a0a6..000000000000 --- a/patches/api/0303-Add-EntityInsideBlockEvent.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 8 May 2021 18:02:06 -0700 -Subject: [PATCH] Add EntityInsideBlockEvent - - -diff --git a/src/main/java/io/papermc/paper/event/entity/EntityInsideBlockEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityInsideBlockEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..94e8b6f6501c92711bd0bc9ee0f67e28f85a605f ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/EntityInsideBlockEvent.java -@@ -0,0 +1,80 @@ -+package io.papermc.paper.event.entity; -+ -+import org.bukkit.block.Block; -+import org.bukkit.entity.Entity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when an entity enters the hitbox of a block. -+ * Only called for blocks that react when an entity is inside. -+ * If cancelled, any action that would have resulted from that entity -+ * being in the block will not happen (such as extinguishing an entity in a cauldron). -+ *

      -+ * Blocks this is currently called for: -+ *

        -+ *
      • Bubble column
      • -+ *
      • Buttons
      • -+ *
      • Cactus
      • -+ *
      • Campfire
      • -+ *
      • Cauldron
      • -+ *
      • Crops
      • -+ *
      • Ender Portal
      • -+ *
      • Fires
      • -+ *
      • Honey
      • -+ *
      • Hopper
      • -+ *
      • Detector rails
      • -+ *
      • Nether portals
      • -+ *
      • Pressure plates
      • -+ *
      • Sweet berry bush
      • -+ *
      • Tripwire
      • -+ *
      • Waterlily
      • -+ *
      • Web
      • -+ *
      • Wither rose
      • -+ *
      -+ */ -+public class EntityInsideBlockEvent extends EntityEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final Block block; -+ private boolean cancelled; -+ -+ public EntityInsideBlockEvent(@NotNull Entity entity, @NotNull Block block) { -+ super(entity); -+ this.block = block; -+ } -+ -+ /** -+ * Gets the block. -+ * -+ * @return the block -+ */ -+ @NotNull -+ public Block getBlock() { -+ return block; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} diff --git a/patches/api/0303-Add-methods-to-find-targets-for-lightning-strikes.patch b/patches/api/0303-Add-methods-to-find-targets-for-lightning-strikes.patch new file mode 100644 index 000000000000..ffb2f027aacb --- /dev/null +++ b/patches/api/0303-Add-methods-to-find-targets-for-lightning-strikes.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jakub Zacek +Date: Mon, 4 Oct 2021 08:29:36 +0200 +Subject: [PATCH] Add methods to find targets for lightning strikes + + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 8084bb2d8f3983e10de9123b74627ed04d8b5255..a8939bb5815fbc2926907bb3e8921f86255abd93 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -692,6 +692,37 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @NotNull + public LightningStrike strikeLightningEffect(@NotNull Location loc); + ++ // Paper start ++ /** ++ * Finds the location of the nearest unobstructed Lightning Rod in a 128-block ++ * radius around the given location. Returns {@code null} if no Lightning Rod is found. ++ * ++ *

      Note: To activate a Lightning Rod, the position one block above it must be struck by lightning.

      ++ * ++ * @param location {@link Location} to search for Lightning Rod around ++ * @return {@link Location} of Lightning Rod or {@code null} ++ */ ++ @Nullable ++ public Location findLightningRod(@NotNull Location location); ++ ++ /** ++ * Finds a target {@link Location} for lightning to strike. ++ *

      It selects from (in the following order):

      ++ *
        ++ *
      1. the block above the nearest Lightning Rod, found using {@link World#findLightningRod(Location)}
      2. ++ *
      3. a random {@link LivingEntity} that can see the sky in a 6x6 cuboid ++ * around input X/Z coordinates. Y ranges from the highest motion-blocking ++ * block at the input X/Z - 3 to the height limit + 3
      4. ++ *
      ++ *

      Returns {@code null} if no target is found.

      ++ * ++ * @param location {@link Location} to search for target around ++ * @return lightning target or {@code null} ++ */ ++ @Nullable ++ public Location findLightningTarget(@NotNull Location location); ++ // Paper end ++ + /** + * Get a list of all entities in this World + * diff --git a/patches/api/0304-Attributes-API-for-item-defaults.patch b/patches/api/0304-Attributes-API-for-item-defaults.patch deleted file mode 100644 index 2a59affc0cab..000000000000 --- a/patches/api/0304-Attributes-API-for-item-defaults.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 8 May 2021 15:02:00 -0700 -Subject: [PATCH] Attributes API for item defaults - - -diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index 663452b8009d2899f8a196a20b6337024ce3caf0..12ed298cb585107370d4400902a651f43bd05d78 100644 ---- a/src/main/java/org/bukkit/Material.java -+++ b/src/main/java/org/bukkit/Material.java -@@ -4154,6 +4154,21 @@ public enum Material implements Keyed, net.kyori.adventure.translation.Translata - public io.papermc.paper.inventory.ItemRarity getItemRarity() { - return Bukkit.getUnsafe().getItemRarity(this); - } -+ -+ /** -+ * Returns an immutable multimap of attributes for the slot. -+ * {@link #isItem()} must be true for this material. -+ * -+ * @param equipmentSlot the slot to get the attributes for -+ * @throws IllegalArgumentException if {@link #isItem()} is false -+ * @return an immutable multimap of attributes -+ * @deprecated use {@link #getDefaultAttributeModifiers(EquipmentSlot)} -+ */ -+ @NotNull -+ @Deprecated -+ public Multimap getItemAttributes(@NotNull EquipmentSlot equipmentSlot) { -+ return Bukkit.getUnsafe().getItemAttributes(this, equipmentSlot); -+ } - // Paper end - - /** -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 248453b259781aa45516133a0ed824f4e6f6a369..a3045b63c4e63f8eac902beb0f48367a5e3e5d20 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -190,6 +190,18 @@ public interface UnsafeValues { - */ - public boolean isValidRepairItemStack(@org.jetbrains.annotations.NotNull ItemStack itemToBeRepaired, @org.jetbrains.annotations.NotNull ItemStack repairMaterial); - -+ /** -+ * Returns an immutable multimap of attributes for the material and slot. -+ * {@link Material#isItem()} must be true for this material. -+ * -+ * @param material the material -+ * @param equipmentSlot the slot to get the attributes for -+ * @throws IllegalArgumentException if {@link Material#isItem()} is false -+ * @return an immutable multimap of attributes -+ */ -+ @org.jetbrains.annotations.NotNull -+ public Multimap getItemAttributes(@org.jetbrains.annotations.NotNull Material material, @org.jetbrains.annotations.NotNull EquipmentSlot equipmentSlot); -+ - /** - * Returns the server's protocol version. - * diff --git a/patches/api/0304-Get-entity-default-attributes.patch b/patches/api/0304-Get-entity-default-attributes.patch new file mode 100644 index 000000000000..92815605ef87 --- /dev/null +++ b/patches/api/0304-Get-entity-default-attributes.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 20 Aug 2021 13:03:55 -0700 +Subject: [PATCH] Get entity default attributes + + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 218adc63a0c0037f764942af184b30ebabff697d..4cd43815c317cfa1dd0ac15fb469d601aee42e60 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -197,5 +197,22 @@ public interface UnsafeValues { + * @return true if valid repair, false if not + */ + public boolean isValidRepairItemStack(@org.jetbrains.annotations.NotNull ItemStack itemToBeRepaired, @org.jetbrains.annotations.NotNull ItemStack repairMaterial); ++ ++ /** ++ * Checks if the entity represented by the namespaced key has default attributes. ++ * ++ * @param entityKey the entity's key ++ * @return true if it has default attributes ++ */ ++ boolean hasDefaultEntityAttributes(@org.jetbrains.annotations.NotNull NamespacedKey entityKey); ++ ++ /** ++ * Gets the default attributes for the entity represented by the namespaced key. ++ * ++ * @param entityKey the entity's key ++ * @return an unmodifiable instance of Attributable for reading default attributes. ++ * @throws IllegalArgumentException if the entity does not exist of have default attributes (use {@link #hasDefaultEntityAttributes(NamespacedKey)} first) ++ */ ++ @org.jetbrains.annotations.NotNull org.bukkit.attribute.Attributable getDefaultEntityAttributes(@org.jetbrains.annotations.NotNull NamespacedKey entityKey); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java +index fd5d1ad0334b574fca951555ce647436257d9b19..6bc514af551374a9c6f2f2a8dbcb35a0a543a23f 100644 +--- a/src/main/java/org/bukkit/entity/EntityType.java ++++ b/src/main/java/org/bukkit/entity/EntityType.java +@@ -477,6 +477,25 @@ public enum EntityType implements Keyed, Translatable, net.kyori.adventure.trans + Preconditions.checkArgument(this != UNKNOWN, "UNKNOWN entities do not have translation keys"); + return org.bukkit.Bukkit.getUnsafe().getTranslationKey(this); + } ++ ++ /** ++ * Checks if the entity has default attributes. ++ * ++ * @return true if it has default attributes ++ */ ++ public boolean hasDefaultAttributes() { ++ return org.bukkit.Bukkit.getUnsafe().hasDefaultEntityAttributes(this.key); ++ } ++ ++ /** ++ * Gets the default attributes for the entity. ++ * ++ * @return an unmodifiable instance of Attributable for reading default attributes. ++ * @throws IllegalArgumentException if the entity does not exist of have default attributes (use {@link #hasDefaultAttributes()} first) ++ */ ++ public @NotNull org.bukkit.attribute.Attributable getDefaultAttributes() { ++ return org.bukkit.Bukkit.getUnsafe().getDefaultEntityAttributes(this.key); ++ } + // Paper end + + /** diff --git a/patches/api/0305-Left-handed-API.patch b/patches/api/0305-Left-handed-API.patch new file mode 100644 index 000000000000..ea746f73d47b --- /dev/null +++ b/patches/api/0305-Left-handed-API.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 14 Oct 2021 12:36:46 -0500 +Subject: [PATCH] Left handed API + + +diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java +index 91d31e5418a5ab7cefd7c02a41bbec8464fe7ab1..d55250d820b02f3a23b99a59e68d3361698baddf 100644 +--- a/src/main/java/org/bukkit/entity/Mob.java ++++ b/src/main/java/org/bukkit/entity/Mob.java +@@ -204,4 +204,20 @@ public interface Mob extends LivingEntity, Lootable { + */ + void setAggressive(boolean aggressive); + // Paper end - Missing Entity API ++ ++ // Paper start - left-handed API ++ /** ++ * Check if Mob is left-handed ++ * ++ * @return True if left-handed ++ */ ++ public boolean isLeftHanded(); ++ ++ /** ++ * Set if Mob is left-handed ++ * ++ * @param leftHanded True if left-handed ++ */ ++ public void setLeftHanded(boolean leftHanded); ++ // Paper end - left-handed API + } diff --git a/patches/api/0306-Add-critical-damage-API.patch b/patches/api/0306-Add-critical-damage-API.patch new file mode 100644 index 000000000000..419d0d892f0c --- /dev/null +++ b/patches/api/0306-Add-critical-damage-API.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dodison +Date: Mon, 26 Jul 2021 17:35:20 +0200 +Subject: [PATCH] Add critical damage API + + +diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java +index ca6f0fa51f7f0133dabb912508b6f4d2eeea0927..341f99550d077c60306e8a246a254b768ebbeb48 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java +@@ -5,6 +5,7 @@ import java.util.Map; + import org.bukkit.damage.DamageSource; + import org.bukkit.damage.DamageType; + import org.bukkit.entity.Entity; ++import org.jetbrains.annotations.ApiStatus; + import org.jetbrains.annotations.NotNull; + + /** +@@ -12,15 +13,18 @@ import org.jetbrains.annotations.NotNull; + */ + public class EntityDamageByEntityEvent extends EntityDamageEvent { + private final Entity damager; ++ private final boolean critical; // Paper + + @Deprecated(since = "1.20.4", forRemoval = true) + public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, final double damage) { + this(damager, damagee, cause, DamageSource.builder(DamageType.GENERIC).withCausingEntity(damager).withDirectEntity(damager).build(), damage); + } + ++ @Deprecated + public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, final double damage) { + super(damagee, cause, damageSource, damage); + this.damager = damager; ++ this.critical = false; // Paper - add critical damage API + } + + @Deprecated(since = "1.20.4", forRemoval = true) +@@ -28,11 +32,34 @@ public class EntityDamageByEntityEvent extends EntityDamageEvent { + this(damager, damagee, cause, DamageSource.builder(DamageType.GENERIC).withCausingEntity(damager).withDirectEntity(damager).build(), modifiers, modifierFunctions); + } + ++ @Deprecated + public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { + super(damagee, cause, damageSource, modifiers, modifierFunctions); + this.damager = damager; ++ // Paper start ++ this.critical = false; + } + ++ @ApiStatus.Internal ++ public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions, boolean critical) { ++ super(damagee, cause, damageSource, modifiers, modifierFunctions); ++ this.damager = damager; ++ this.critical = critical; ++ } ++ ++ /** ++ * Shows this damage instance was critical. ++ * The damage instance can be critical if the attacking player met the respective conditions. ++ * Furthermore, arrows may also cause a critical damage event if the arrow {@link org.bukkit.entity.AbstractArrow#isCritical()}. ++ * ++ * @return if the hit was critical. ++ * @see https://minecraft.wiki/wiki/Damage#Critical_hit ++ */ ++ public boolean isCritical() { ++ return this.critical; ++ } ++ // Paper end ++ + /** + * Returns the entity that damaged the defender. + * diff --git a/patches/api/0307-Add-PlayerKickEvent-causes.patch b/patches/api/0307-Add-PlayerKickEvent-causes.patch deleted file mode 100644 index 348009297717..000000000000 --- a/patches/api/0307-Add-PlayerKickEvent-causes.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 15 May 2021 20:30:34 -0700 -Subject: [PATCH] Add PlayerKickEvent causes - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 015252e0fbb705c48b2c1e497d4ffd263739b125..40e365e6dad1dfead4d0253d0b4c011bc71b1e71 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -243,6 +243,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @param message kick message - */ - void kick(final @Nullable net.kyori.adventure.text.Component message); -+ -+ /** -+ * Kicks player with custom kick message and cause. -+ * -+ * @param message kick message -+ * @param cause kick cause -+ */ -+ void kick(final @Nullable Component message, @NotNull org.bukkit.event.player.PlayerKickEvent.Cause cause); - // Paper end - - /** -diff --git a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java -index efbf4b657c99ce3a5096d041d275af9ccaea7911..b76966953753dabcb31293846d39a4b4d5ef472a 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java -@@ -12,6 +12,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); - private net.kyori.adventure.text.Component leaveMessage; // Paper - private net.kyori.adventure.text.Component kickReason; // Paper -+ private final Cause cause; // Paper - private boolean cancel; - - @Deprecated // Paper -@@ -19,14 +20,25 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { - super(playerKicked); - this.kickReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(kickReason); // Paper - this.leaveMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(leaveMessage); // Paper -+ this.cause = Cause.UNKNOWN; // Paper - this.cancel = false; - } - // Paper start -+ @Deprecated - public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final net.kyori.adventure.text.Component kickReason, @NotNull final net.kyori.adventure.text.Component leaveMessage) { - super(playerKicked); - this.kickReason = kickReason; - this.leaveMessage = leaveMessage; - this.cancel = false; -+ this.cause = Cause.UNKNOWN; -+ } -+ -+ public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final net.kyori.adventure.text.Component kickReason, @NotNull final net.kyori.adventure.text.Component leaveMessage, @NotNull final Cause cause) { -+ super(playerKicked); -+ this.kickReason = kickReason; -+ this.leaveMessage = leaveMessage; -+ this.cancel = false; -+ this.cause = cause; - } - - /** -@@ -132,4 +144,65 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { - public static HandlerList getHandlerList() { - return handlers; - } -+ // Paper start -+ /** -+ * Gets the cause of this kick -+ * -+ * @return -+ */ -+ @NotNull -+ public org.bukkit.event.player.PlayerKickEvent.Cause getCause() { -+ return cause; -+ } -+ -+ public enum Cause { -+ -+ PLUGIN, -+ -+ WHITELIST, -+ -+ BANNED, -+ -+ IP_BANNED, -+ -+ KICK_COMMAND, -+ -+ FLYING_PLAYER, -+ -+ FLYING_VEHICLE, -+ -+ TIMEOUT, -+ -+ IDLING, -+ -+ INVALID_VEHICLE_MOVEMENT, -+ -+ INVALID_PLAYER_MOVEMENT, -+ -+ INVALID_ENTITY_ATTACKED, -+ -+ INVALID_PAYLOAD, -+ -+ SPAM, -+ -+ ILLEGAL_ACTION, -+ -+ ILLEGAL_CHARACTERS, -+ -+ SELF_INTERACTION, -+ -+ DUPLICATE_LOGIN, -+ -+ RESOURCE_PACK_REJECTION, -+ -+ /** -+ * Spigot's restart command -+ */ -+ RESTART_COMMAND, -+ /** -+ * Fallback cause -+ */ -+ UNKNOWN, -+ } -+ // Paper end - } diff --git a/patches/api/0307-Add-more-advancement-API.patch b/patches/api/0307-Add-more-advancement-API.patch new file mode 100644 index 000000000000..1f051ac4c445 --- /dev/null +++ b/patches/api/0307-Add-more-advancement-API.patch @@ -0,0 +1,264 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: syldium +Date: Fri, 9 Jul 2021 18:49:40 +0200 +Subject: [PATCH] Add more advancement API + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/io/papermc/paper/advancement/AdvancementDisplay.java b/src/main/java/io/papermc/paper/advancement/AdvancementDisplay.java +new file mode 100644 +index 0000000000000000000000000000000000000000..59228f2e66e982feca77d9f962004ceacb648783 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancement/AdvancementDisplay.java +@@ -0,0 +1,160 @@ ++package io.papermc.paper.advancement; ++ ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.format.TextColor; ++import net.kyori.adventure.translation.Translatable; ++import net.kyori.adventure.util.Index; ++import org.bukkit.NamespacedKey; ++import org.bukkit.inventory.ItemStack; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Describes the display of an advancement. ++ *

      ++ * The display is used in the chat, in the toast messages and the advancements ++ * screen. ++ */ ++@NullMarked ++public interface AdvancementDisplay { ++ ++ /** ++ * Gets the {@link Frame}. ++ *

      ++ * This defines the appearance of the tile in the advancements screen and ++ * the text when it's completed. ++ * ++ * @return the frame type ++ */ ++ Frame frame(); ++ ++ /** ++ * Gets the advancement title. ++ * ++ * @return the title ++ */ ++ Component title(); ++ ++ /** ++ * Gets the description. ++ * ++ * @return the description ++ */ ++ Component description(); ++ ++ /** ++ * Gets the icon shown in the frame in the advancements screen. ++ * ++ * @return a copy of the icon ++ */ ++ ItemStack icon(); ++ ++ /** ++ * Gets whether a toast should be displayed. ++ *

      ++ * A toast is a notification that will be displayed in the top right corner ++ * of the screen. ++ * ++ * @return {@code true} if a toast should be shown ++ */ ++ boolean doesShowToast(); ++ ++ /** ++ * Gets whether a message should be sent in the chat. ++ * ++ * @return {@code true} if a message should be sent ++ * @see org.bukkit.event.player.PlayerAdvancementDoneEvent#message() to edit ++ * the message ++ */ ++ boolean doesAnnounceToChat(); ++ ++ /** ++ * Gets whether this advancement is hidden. ++ *

      ++ * Hidden advancements cannot be viewed by the player until they have been ++ * unlocked. ++ * ++ * @return {@code true} if hidden ++ */ ++ boolean isHidden(); ++ ++ /** ++ * Gets the texture displayed behind the advancement tree when selected. ++ *

      ++ * This only affects root advancements without any parent. If the background ++ * is not specified or doesn't exist, the tab background will be the missing ++ * texture. ++ * ++ * @return the background texture path ++ */ ++ @Nullable NamespacedKey backgroundPath(); ++ ++ /** ++ * Gets the formatted display name for this display. This ++ * is a part of the component that would be shown in chat when a player ++ * completes the advancement. ++ * ++ * @return the display name ++ * @see org.bukkit.advancement.Advancement#displayName() ++ */ ++ Component displayName(); ++ ++ /** ++ * Defines how the {@link #icon()} appears in the advancements screen and ++ * the color used with the {@link #title() advancement name}. ++ */ ++ enum Frame implements Translatable { ++ ++ /** ++ * "Challenge complete" advancement. ++ *

      ++ * The client will play the {@code ui.toast.challenge_complete} sound ++ * when the challenge is completed and the toast is shown. ++ */ ++ CHALLENGE("challenge", NamedTextColor.DARK_PURPLE), ++ ++ /** ++ * "Goal reached" advancement. ++ */ ++ GOAL("goal", NamedTextColor.GREEN), ++ ++ /** ++ * "Advancement made" advancement. ++ */ ++ TASK("task", NamedTextColor.GREEN); ++ ++ /** ++ * The name map. ++ */ ++ public static final Index NAMES = Index.create(Frame.class, frame -> frame.name); ++ private final String name; ++ private final TextColor color; ++ ++ Frame(final String name, final TextColor color) { ++ this.name = name; ++ this.color = color; ++ } ++ ++ /** ++ * Gets the {@link TextColor} used for the advancement name. ++ * ++ * @return the text color ++ */ ++ public TextColor color() { ++ return this.color; ++ } ++ ++ /** ++ * Gets the translation key used when an advancement is completed. ++ *

      ++ * This is the first line of the toast displayed by the client. ++ * ++ * @return the toast message key ++ */ ++ @Override ++ public String translationKey() { ++ return "advancements.toast." + this.name; ++ } ++ } ++} +diff --git a/src/main/java/org/bukkit/advancement/Advancement.java b/src/main/java/org/bukkit/advancement/Advancement.java +index e683af5eb1d08179acd69c521f8f387dc8051e32..5d7ab518dc6be39965cc8925e5df6792456c6658 100644 +--- a/src/main/java/org/bukkit/advancement/Advancement.java ++++ b/src/main/java/org/bukkit/advancement/Advancement.java +@@ -27,13 +27,53 @@ public interface Advancement extends Keyed { + @NotNull + AdvancementRequirements getRequirements(); + ++ // Paper start + /** +- * Returns the display information for this advancement. ++ * Get the display info of this advancement. ++ *

      ++ * Will be {@code null} when totally hidden, for example with crafting ++ * recipes. + * +- * This includes it's name, description and other visible tags. ++ * @return the display info ++ */ ++ @Nullable ++ io.papermc.paper.advancement.AdvancementDisplay getDisplay(); ++ ++ /** ++ * Gets the formatted display name for this display. This ++ * is part of the component that would be shown in chat when a player ++ * completes the advancement. Will return the same as ++ * {@link io.papermc.paper.advancement.AdvancementDisplay#displayName()} when an ++ * {@link io.papermc.paper.advancement.AdvancementDisplay} is present. + * +- * @return a AdvancementDisplay object, or null if not set. ++ * @return the display name ++ * @see io.papermc.paper.advancement.AdvancementDisplay#displayName() ++ */ ++ @NotNull net.kyori.adventure.text.Component displayName(); ++ ++ /** ++ * Gets the parent advancement, if any. ++ * ++ * @return the parent advancement + */ + @Nullable +- AdvancementDisplay getDisplay(); ++ Advancement getParent(); ++ ++ /** ++ * Gets all the direct children advancements. ++ * ++ * @return the children advancements ++ */ ++ @NotNull ++ @org.jetbrains.annotations.Unmodifiable ++ Collection getChildren(); ++ ++ /** ++ * Gets the root advancement of the tree this is located in. ++ * ++ * @return the root advancement ++ */ ++ @NotNull ++ Advancement getRoot(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/advancement/AdvancementDisplay.java b/src/main/java/org/bukkit/advancement/AdvancementDisplay.java +index 0ff86a39025a94ca128364a45bf171728cb81027..aec6be7e121da3eb8a464b6934da29ab6b473885 100644 +--- a/src/main/java/org/bukkit/advancement/AdvancementDisplay.java ++++ b/src/main/java/org/bukkit/advancement/AdvancementDisplay.java +@@ -5,7 +5,10 @@ import org.jetbrains.annotations.NotNull; + + /** + * Holds information about how the advancement is displayed by the game. ++ * ++ * @deprecated use {@link io.papermc.paper.advancement.AdvancementDisplay} + */ ++@Deprecated(forRemoval = true) // Paper + public interface AdvancementDisplay { + + /** +diff --git a/src/main/java/org/bukkit/advancement/AdvancementDisplayType.java b/src/main/java/org/bukkit/advancement/AdvancementDisplayType.java +index de767efb9f55448df061e166c66a2cf3439d57ec..06d8b72dd54becc13f40bd6e505115405462cd73 100644 +--- a/src/main/java/org/bukkit/advancement/AdvancementDisplayType.java ++++ b/src/main/java/org/bukkit/advancement/AdvancementDisplayType.java +@@ -8,7 +8,9 @@ import org.jetbrains.annotations.NotNull; + * + * This enum contains information about these types and how they are + * represented. ++ * @deprecated use {@link io.papermc.paper.advancement.AdvancementDisplay.Frame} + */ ++@Deprecated(forRemoval = true) + public enum AdvancementDisplayType { + + /** diff --git a/patches/api/0308-Add-PufferFishStateChangeEvent.patch b/patches/api/0308-Add-PufferFishStateChangeEvent.patch deleted file mode 100644 index c3014534d315..000000000000 --- a/patches/api/0308-Add-PufferFishStateChangeEvent.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: HexedHero <6012891+HexedHero@users.noreply.github.com> -Date: Mon, 10 May 2021 16:58:38 +0100 -Subject: [PATCH] Add PufferFishStateChangeEvent - - -diff --git a/src/main/java/io/papermc/paper/event/entity/PufferFishStateChangeEvent.java b/src/main/java/io/papermc/paper/event/entity/PufferFishStateChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3585457b21aca2a2f1779868a0fa91f8011ad3c9 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/PufferFishStateChangeEvent.java -@@ -0,0 +1,80 @@ -+package io.papermc.paper.event.entity; -+ -+import org.bukkit.entity.PufferFish; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called just before a {@link PufferFish} inflates or deflates. -+ */ -+public class PufferFishStateChangeEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private int newPuffState; -+ -+ public PufferFishStateChangeEvent(@NotNull PufferFish entity, int newPuffState) { -+ super(entity); -+ this.newPuffState = newPuffState; -+ } -+ -+ @NotNull -+ @Override -+ public PufferFish getEntity() { -+ return (PufferFish) entity; -+ } -+ -+ /** -+ * Get the new puff state of the {@link PufferFish}. -+ *

      -+ * This is what the {@link PufferFish}'s new puff state will be after this event if it isn't cancelled.
      -+ * Refer to {@link PufferFish#getPuffState()} to get the current puff state. -+ * @return The new puff state, 0 being not inflated, 1 being slightly inflated and 2 being fully inflated -+ */ -+ public int getNewPuffState() { -+ return this.newPuffState; -+ } -+ -+ /** -+ * Get if the {@link PufferFish} is going to inflate. -+ * @return If its going to inflate -+ */ -+ public boolean isInflating() { -+ return getNewPuffState() > getEntity().getPuffState(); -+ } -+ -+ /** -+ * Get if the {@link PufferFish} is going to deflate. -+ * @return If its going to deflate -+ */ -+ public boolean isDeflating() { -+ return getNewPuffState() < getEntity().getPuffState(); -+ } -+ -+ /** -+ * Set whether or not to cancel the {@link PufferFish} (in/de)flating. -+ * -+ * @param cancel true if you wish to cancel the (in/de)flation -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0308-Fix-issues-with-mob-conversion.patch b/patches/api/0308-Fix-issues-with-mob-conversion.patch new file mode 100644 index 000000000000..75899f33463a --- /dev/null +++ b/patches/api/0308-Fix-issues-with-mob-conversion.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 24 Oct 2021 20:29:27 -0700 +Subject: [PATCH] Fix issues with mob conversion + + +diff --git a/src/main/java/org/bukkit/entity/Hoglin.java b/src/main/java/org/bukkit/entity/Hoglin.java +index 83a9e06fe91bdfe74e771b170966c70e4c47893c..452a8e73fa084f29f3b96793d642bd8ec0bc8aac 100644 +--- a/src/main/java/org/bukkit/entity/Hoglin.java ++++ b/src/main/java/org/bukkit/entity/Hoglin.java +@@ -44,13 +44,17 @@ public interface Hoglin extends Animals, Enemy { + public int getConversionTime(); + + /** +- * Sets the amount of ticks until this entity will be converted to a Zoglin. ++ * Sets the conversion counter value. The counter is incremented ++ * every tick the method {@link #isConverting()} returns true. Setting ++ * this value will not start the conversion if the {@link Hoglin} is ++ * not in a valid environment ({@link org.bukkit.World#isPiglinSafe}) ++ * to convert, is immune to zombification ({@link #isImmuneToZombification()}) ++ * or has no AI ({@link #hasAI}). + * +- * When this reaches 0, the entity will be converted. A value of less than 0 +- * will stop the current conversion process without converting the current +- * entity. ++ * When this reaches 300, the entity will be converted. To stop the ++ * conversion use {@link #setImmuneToZombification(boolean)}. + * +- * @param time new conversion time ++ * @param time new conversion counter + */ + public void setConversionTime(int time); + +diff --git a/src/main/java/org/bukkit/entity/PiglinAbstract.java b/src/main/java/org/bukkit/entity/PiglinAbstract.java +index 9c4c1a4ab37403303c395db2764134abb10206d5..41aeb01f75380f5f40a8c0eb3f52ec3d9cade04d 100644 +--- a/src/main/java/org/bukkit/entity/PiglinAbstract.java ++++ b/src/main/java/org/bukkit/entity/PiglinAbstract.java +@@ -31,14 +31,17 @@ public interface PiglinAbstract extends Monster, Ageable { + public int getConversionTime(); + + /** +- * Sets the amount of ticks until this entity will be converted to a +- * Zombified Piglin. ++ * Sets the conversion counter value. The counter is incremented ++ * every tick the method {@link #isConverting()} returns true. Setting ++ * this value will not start the conversion if the {@link PiglinAbstract} is ++ * not in a valid environment ({@link org.bukkit.World#isPiglinSafe}) ++ * to convert, is immune to zombification ({@link #isImmuneToZombification()}) ++ * or has no AI ({@link #hasAI}). + * +- * When this reaches 0, the entity will be converted. A value of less than 0 +- * will stop the current conversion process without converting the current +- * entity. ++ * When this reaches 300, the entity will be converted. To stop the ++ * conversion use {@link #setImmuneToZombification(boolean)}. + * +- * @param time new conversion time ++ * @param time new conversion counter + */ + public void setConversionTime(int time); + diff --git a/patches/api/0309-Add-BellRevealRaiderEvent.patch b/patches/api/0309-Add-BellRevealRaiderEvent.patch deleted file mode 100644 index 8b0ee3e5b432..000000000000 --- a/patches/api/0309-Add-BellRevealRaiderEvent.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Wed, 26 May 2021 17:08:57 -0400 -Subject: [PATCH] Add BellRevealRaiderEvent - - -diff --git a/src/main/java/io/papermc/paper/event/block/BellRevealRaiderEvent.java b/src/main/java/io/papermc/paper/event/block/BellRevealRaiderEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..03dae5be7dba8ab550d03f365c05af4ba73e4224 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/BellRevealRaiderEvent.java -@@ -0,0 +1,58 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.Raider; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a {@link org.bukkit.entity.Raider} is revealed by a bell. -+ */ -+public class BellRevealRaiderEvent extends BlockEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ private boolean cancelled = false; -+ private final Raider raider; -+ -+ public BellRevealRaiderEvent(@NotNull Block theBlock, @NotNull Entity raider) { -+ super(theBlock); -+ this.raider = (Raider) raider; -+ } -+ -+ /** -+ * Gets the raider that the bell revealed. -+ * -+ * @return The raider -+ */ -+ @NotNull -+ public Raider getEntity() { -+ return raider; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ /** -+ * {@inheritDoc} -+ *

      -+ * This does not cancel the particle effects shown on the bell, only the entity. -+ */ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ public static @NotNull HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0309-Add-hasCollision-methods-to-various-places.patch b/patches/api/0309-Add-hasCollision-methods-to-various-places.patch new file mode 100644 index 000000000000..09f465abcc2b --- /dev/null +++ b/patches/api/0309-Add-hasCollision-methods-to-various-places.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 4 Nov 2021 11:50:35 -0700 +Subject: [PATCH] Add hasCollision methods to various places + + +diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java +index e8985981deb7d23ec624781725c4a05cc9cc94e7..b28ab97ff80c9e7af85d8830f26fd0f252082541 100644 +--- a/src/main/java/org/bukkit/Material.java ++++ b/src/main/java/org/bukkit/Material.java +@@ -4877,6 +4877,21 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla + } + // Paper end - item default attributes API + ++ // Paper start - isCollidable API ++ /** ++ * Checks if this material is collidable. ++ * ++ * @return true if collidable ++ * @throws IllegalArgumentException if {@link #isBlock()} is false ++ */ ++ public boolean isCollidable() { ++ if (this.isBlock()) { ++ return this.asBlockType().hasCollision(); ++ } ++ throw new IllegalArgumentException(this + " isn't a block type"); ++ } ++ // Paper end - isCollidable API ++ + /** + * Do not use for any reason. + * +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index bd50ec2a93800af9ce663fd10ecf74ae011a6715..7f9acd155c1b275145ba53a41b7513dc8cc00531 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -486,6 +486,13 @@ public interface Block extends Metadatable, Translatable, net.kyori.adventure.tr + * @return true if block is solid + */ + boolean isSolid(); ++ ++ /** ++ * Checks if this block is collidable. ++ * ++ * @return true if collidable ++ */ ++ boolean isCollidable(); + // Paper end + + /** +diff --git a/src/main/java/org/bukkit/block/BlockState.java b/src/main/java/org/bukkit/block/BlockState.java +index 555d0492c2fcf85c1e2f95f145b974cb75bc5ecc..ee4cbbc584ec1a10c62464a7abb3ea5da656ffc0 100644 +--- a/src/main/java/org/bukkit/block/BlockState.java ++++ b/src/main/java/org/bukkit/block/BlockState.java +@@ -245,4 +245,13 @@ public interface BlockState extends Metadatable { + * or 'virtual' (e.g. on an itemstack) + */ + boolean isPlaced(); ++ ++ // Paper start ++ /** ++ * Checks if this block state is collidable. ++ * ++ * @return true if collidable ++ */ ++ boolean isCollidable(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/block/BlockType.java b/src/main/java/org/bukkit/block/BlockType.java +index f0c3343e2006f244bb1f99c269bcbaa357feb25f..a2376f08c836d727995987a640a47f8f3a7b0c11 100644 +--- a/src/main/java/org/bukkit/block/BlockType.java ++++ b/src/main/java/org/bukkit/block/BlockType.java +@@ -3625,4 +3625,13 @@ public interface BlockType extends Keyed, Translatable, net.kyori.adventure.tran + @Override + @NotNull String getTranslationKey(); + // Paper end - add Translatable ++ ++ // Paper start - hasCollision API ++ /** ++ * Checks if this block type has collision. ++ *

      ++ * @return false if this block never has collision, true if it might have collision ++ */ ++ boolean hasCollision(); ++ // Paper end - hasCollision API + } diff --git a/patches/api/0310-Add-ElderGuardianAppearanceEvent.patch b/patches/api/0310-Add-ElderGuardianAppearanceEvent.patch deleted file mode 100644 index 8d925d10acd6..000000000000 --- a/patches/api/0310-Add-ElderGuardianAppearanceEvent.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Fri, 19 Mar 2021 23:39:21 -0400 -Subject: [PATCH] Add ElderGuardianAppearanceEvent - - -diff --git a/src/main/java/io/papermc/paper/event/entity/ElderGuardianAppearanceEvent.java b/src/main/java/io/papermc/paper/event/entity/ElderGuardianAppearanceEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4cd551c8311ff8f7321ed2dc6a4efc87162dadfe ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/ElderGuardianAppearanceEvent.java -@@ -0,0 +1,69 @@ -+package io.papermc.paper.event.entity; -+ -+import org.bukkit.entity.ElderGuardian; -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.Collections; -+import java.util.List; -+ -+/** -+ * Is called when an {@link org.bukkit.entity.ElderGuardian} appears in front of a {@link org.bukkit.entity.Player}. -+ */ -+public class ElderGuardianAppearanceEvent extends EntityEvent implements Cancellable { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ -+ private boolean cancelled; -+ private final Player affectedPlayer; -+ -+ public ElderGuardianAppearanceEvent(@NotNull Entity what, @NotNull Player affectedPlayer) { -+ super(what); -+ this.affectedPlayer = affectedPlayer; -+ } -+ -+ /** -+ * Get the player affected by the guardian appearance. -+ * -+ * @return Player affected by the appearance -+ */ -+ @NotNull -+ public Player getAffectedPlayer() { -+ return affectedPlayer; -+ } -+ -+ /** -+ * The elder guardian playing the effect. -+ * -+ * @return The elder guardian -+ */ -+ @NotNull -+ public ElderGuardian getEntity() { -+ return (ElderGuardian) entity; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0338-Goat-ram-API.patch b/patches/api/0310-Goat-ram-API.patch similarity index 100% rename from patches/api/0338-Goat-ram-API.patch rename to patches/api/0310-Goat-ram-API.patch diff --git a/patches/api/0311-Add-API-for-resetting-a-single-score.patch b/patches/api/0311-Add-API-for-resetting-a-single-score.patch new file mode 100644 index 000000000000..a071aa88f79f --- /dev/null +++ b/patches/api/0311-Add-API-for-resetting-a-single-score.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: booky10 +Date: Fri, 5 Nov 2021 21:01:36 +0100 +Subject: [PATCH] Add API for resetting a single score + +It was only possible to reset all scores for a specific entry, instead of resetting only specific scores. + +diff --git a/src/main/java/org/bukkit/scoreboard/Score.java b/src/main/java/org/bukkit/scoreboard/Score.java +index 787bb91b48e3ed798e85ba57c8b218c0082bc85c..48a1654a2dd8da82cb91bcfa4b3a523f88323568 100644 +--- a/src/main/java/org/bukkit/scoreboard/Score.java ++++ b/src/main/java/org/bukkit/scoreboard/Score.java +@@ -73,4 +73,14 @@ public interface Score { + */ + @Nullable + Scoreboard getScoreboard(); ++ ++ // Paper start ++ /** ++ * Resets this score, if a value has been set. ++ * ++ * @throws IllegalStateException if the associated objective has been ++ * unregistered ++ */ ++ void resetScore() throws IllegalStateException; ++ // Paper end + } diff --git a/patches/api/0311-Add-more-line-of-sight-methods.patch b/patches/api/0311-Add-more-line-of-sight-methods.patch deleted file mode 100644 index adfd70e67687..000000000000 --- a/patches/api/0311-Add-more-line-of-sight-methods.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TwoLeggedCat <80929284+TwoLeggedCat@users.noreply.github.com> -Date: Sat, 29 May 2021 14:33:18 -0500 -Subject: [PATCH] Add more line of sight methods - - -diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java -index aa534b1a9a1fb84a2fbd4b372f313bb4b63325fa..43b53c21af01e0f496c8aaacff82dfdfadaf40f6 100644 ---- a/src/main/java/org/bukkit/RegionAccessor.java -+++ b/src/main/java/org/bukkit/RegionAccessor.java -@@ -392,5 +392,13 @@ public interface RegionAccessor extends Keyed { // Paper - @NotNull - @Override - NamespacedKey getKey(); -+ -+ /** -+ * Tell whether a line of sight exists between the given locations -+ * @param from Location to start at -+ * @param to target Location -+ * @return whether a line of sight exists between {@code from} and {@code to} -+ */ -+ public boolean lineOfSightExists(@NotNull Location from, @NotNull Location to); - // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index 087a9c54bc11d5d87aa90bf9d8e66fdac2c44457..5238d83788ef39db1f86c22a0b27648cc47a215b 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -482,6 +482,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - */ - public boolean hasLineOfSight(@NotNull Entity other); - -+ // Paper start -+ /** -+ * Checks whether the living entity has block line of sight to the given block. -+ *

      -+ * This uses the same algorithm that hostile mobs use to find the closest -+ * player. -+ * -+ * @param location the location to determine line of sight to -+ * @return true if there is a line of sight, false if not -+ */ -+ public boolean hasLineOfSight(@NotNull Location location); -+ // Paper end -+ - /** - * Returns if the living entity despawns when away from players or not. - *

      diff --git a/patches/api/0312-Add-Raw-Byte-Entity-Serialization.patch b/patches/api/0312-Add-Raw-Byte-Entity-Serialization.patch new file mode 100644 index 000000000000..381f5dd0d5f8 --- /dev/null +++ b/patches/api/0312-Add-Raw-Byte-Entity-Serialization.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sun, 24 Oct 2021 16:19:26 -0400 +Subject: [PATCH] Add Raw Byte Entity Serialization + + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 4cd43815c317cfa1dd0ac15fb469d601aee42e60..5be89089da4e8230dc7aa078712428189f38d9f9 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -169,6 +169,14 @@ public interface UnsafeValues { + + ItemStack deserializeItem(byte[] data); + ++ byte[] serializeEntity(org.bukkit.entity.Entity entity); ++ ++ default org.bukkit.entity.Entity deserializeEntity(byte[] data, World world) { ++ return deserializeEntity(data, world, false); ++ } ++ ++ org.bukkit.entity.Entity deserializeEntity(byte[] data, World world, boolean preserveUUID); ++ + /** + * Creates and returns the next EntityId available. + *

      +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 3b40c63a380e519ecae2e272754a53aff5aebd9a..464668496f5a611ae78bd5f6392915ec384862ac 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -946,5 +946,32 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + @Deprecated + @NotNull Set getTrackedPlayers(); ++ ++ /** ++ * Spawns the entity in the world at the given {@link Location} with the default spawn reason. ++ *

      ++ * This will not spawn the entity if the entity is already spawned or has previously been despawned. ++ *

      ++ * Also, this method will fire the same events as a normal entity spawn. ++ * ++ * @param location The location to spawn the entity at. ++ * @return Whether the entity was successfully spawned. ++ */ ++ public default boolean spawnAt(@NotNull Location location) { ++ return spawnAt(location, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); ++ } ++ ++ /** ++ * Spawns the entity in the world at the given {@link Location} with the reason given. ++ *

      ++ * This will not spawn the entity if the entity is already spawned or has previously been despawned. ++ *

      ++ * Also, this method will fire the same events as a normal entity spawn. ++ * ++ * @param location The location to spawn the entity at. ++ * @param reason The reason for the entity being spawned. ++ * @return Whether the entity was successfully spawned. ++ */ ++ public boolean spawnAt(@NotNull Location location, @NotNull org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason); + // Paper end + } diff --git a/patches/api/0313-Add-PlayerItemFrameChangeEvent.patch b/patches/api/0313-Add-PlayerItemFrameChangeEvent.patch new file mode 100644 index 000000000000..2231459fbb60 --- /dev/null +++ b/patches/api/0313-Add-PlayerItemFrameChangeEvent.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SamB440 +Date: Mon, 15 Nov 2021 18:09:46 +0000 +Subject: [PATCH] Add PlayerItemFrameChangeEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerItemFrameChangeEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerItemFrameChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f387477da45a44cc7788ed5342104f535cf3cb98 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerItemFrameChangeEvent.java +@@ -0,0 +1,99 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.ItemFrame; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when an {@link ItemFrame} is having an item rotated, added, or removed from it. ++ */ ++@NullMarked ++public class PlayerItemFrameChangeEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ItemFrame itemFrame; ++ private final ItemFrameChangeAction action; ++ private ItemStack itemStack; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerItemFrameChangeEvent(final Player player, final ItemFrame itemFrame, final ItemStack itemStack, final ItemFrameChangeAction action) { ++ super(player); ++ this.itemFrame = itemFrame; ++ this.itemStack = itemStack; ++ this.action = action; ++ } ++ ++ /** ++ * Gets the {@link ItemFrame} involved in this event. ++ * ++ * @return the {@link ItemFrame} ++ */ ++ public ItemFrame getItemFrame() { ++ return this.itemFrame; ++ } ++ ++ /** ++ * Gets the {@link ItemStack} involved in this event. ++ * This is the item being added, rotated, or removed from the {@link ItemFrame}. ++ *

      ++ * If this method returns air, then the resulting item in the ItemFrame will be empty. ++ * ++ * @return the {@link ItemStack} being added, rotated, or removed ++ */ ++ public ItemStack getItemStack() { ++ return this.itemStack; ++ } ++ ++ /** ++ * Sets the {@link ItemStack} that this {@link ItemFrame} holds. ++ * If {@code null} is provided, the ItemStack will become air and the result in the ItemFrame will be empty. ++ * ++ * @param itemStack {@link ItemFrame} item ++ */ ++ public void setItemStack(final @Nullable ItemStack itemStack) { ++ this.itemStack = itemStack == null ? ItemStack.empty() : itemStack; ++ } ++ ++ /** ++ * Gets the action that was performed on this {@link ItemFrame}. ++ * ++ * @return action performed on the item frame in this event ++ */ ++ public ItemFrameChangeAction getAction() { ++ return this.action; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum ItemFrameChangeAction { ++ PLACE, ++ REMOVE, ++ ROTATE ++ } ++} diff --git a/patches/api/0313-Missing-Entity-Behavior-API.patch b/patches/api/0313-Missing-Entity-Behavior-API.patch deleted file mode 100644 index 9868eeaf5df2..000000000000 --- a/patches/api/0313-Missing-Entity-Behavior-API.patch +++ /dev/null @@ -1,703 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Fri, 28 May 2021 21:06:59 -0400 -Subject: [PATCH] Missing Entity Behavior API - -Co-authored-by: Nassim Jahnke -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/org/bukkit/entity/AbstractHorse.java b/src/main/java/org/bukkit/entity/AbstractHorse.java -index 0d88dce9978243a1f995c5fb448c5d71b01136eb..cad47139de57642fb3bb483e7a5acaa7fea78cb4 100644 ---- a/src/main/java/org/bukkit/entity/AbstractHorse.java -+++ b/src/main/java/org/bukkit/entity/AbstractHorse.java -@@ -119,4 +119,58 @@ public interface AbstractHorse extends Vehicle, InventoryHolder, Tameable { - @NotNull - @Override - public AbstractHorseInventory getInventory(); -+ -+ // Paper start - Horse API -+ /** -+ * Gets if a horse is in their eating grass animation. -+ * -+ * @return eating grass animation is active -+ * @deprecated use {@link #isEatingHaystack()} -+ */ -+ @Deprecated -+ public boolean isEatingGrass(); -+ -+ /** -+ * Sets if a horse is in their eating grass animation. -+ * -+ *

      When true, the horse will lower its neck.

      -+ * -+ * @param eating eating grass animation is active -+ * @deprecated use {@link #setEatingHaystack(boolean)} -+ */ -+ @Deprecated -+ public void setEatingGrass(boolean eating); -+ -+ /** -+ * Gets if a horse is in their rearing animation. -+ * -+ * @return rearing animation is active -+ */ -+ public boolean isRearing(); -+ -+ /** -+ * Sets if a horse is in their rearing animation. -+ * -+ *

      When true, the horse will stand on its hind legs.

      -+ * -+ * @param rearing rearing animation is active -+ */ -+ public void setRearing(boolean rearing); -+ -+ /** -+ * Gets if a horse is in their eating animation. -+ * -+ * @return eating animation is active -+ */ -+ public boolean isEating(); -+ -+ /** -+ * Sets if a horse is in their eating animation. -+ * -+ *

      When true, the horse will bob its head.

      -+ * -+ * @param eating eating animation is active -+ */ -+ public void setEating(boolean eating); -+ // Paper end - Horse API - } -diff --git a/src/main/java/org/bukkit/entity/Bee.java b/src/main/java/org/bukkit/entity/Bee.java -index adb20a9abba33c32d553f620fa82b27dff64ab5f..ca6baec5ce00b4d169ab4ff416f616db32615010 100644 ---- a/src/main/java/org/bukkit/entity/Bee.java -+++ b/src/main/java/org/bukkit/entity/Bee.java -@@ -93,4 +93,28 @@ public interface Bee extends Animals { - * @param ticks Ticks the bee cannot enter a hive for - */ - void setCannotEnterHiveTicks(int ticks); -+ -+ // Paper start -+ /** -+ * Sets the override for if the bee is currently rolling. -+ * -+ * @param rolling is rolling, or unset for vanilla behavior -+ */ -+ void setRollingOverride(@org.jetbrains.annotations.NotNull net.kyori.adventure.util.TriState rolling); -+ -+ /** -+ * Gets the plugin set override for if the bee is currently rolling. -+ * -+ * @return plugin set rolling override -+ */ -+ @org.jetbrains.annotations.NotNull -+ net.kyori.adventure.util.TriState getRollingOverride(); -+ -+ /** -+ * Gets if the bee is currently rolling. -+ * -+ * @return is rolling -+ */ -+ boolean isRolling(); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Cat.java b/src/main/java/org/bukkit/entity/Cat.java -index c2a566b864c82ffb094b7334d9e6e25a1bfc87d1..c340fecb61bac66baf0f44189d21bc85289b1269 100644 ---- a/src/main/java/org/bukkit/entity/Cat.java -+++ b/src/main/java/org/bukkit/entity/Cat.java -@@ -54,4 +54,36 @@ public interface Cat extends Tameable, Sittable { - JELLIE, - ALL_BLACK; - } -+ -+ // Paper Start - More cat api -+ /** -+ * Sets if the cat is lying down. -+ * This is visual and does not affect the behaviour of the cat. -+ * -+ * @param lyingDown whether the cat should lie down -+ */ -+ public void setLyingDown(boolean lyingDown); -+ -+ /** -+ * Gets if the cat is lying down. -+ * -+ * @return whether the cat is lying down -+ */ -+ public boolean isLyingDown(); -+ -+ /** -+ * Sets if the cat has its head up. -+ * This is visual and does not affect the behaviour of the cat. -+ * -+ * @param headUp head is up -+ */ -+ public void setHeadUp(boolean headUp); -+ -+ /** -+ * Gets if the cat has its head up. -+ * -+ * @return head is up -+ */ -+ public boolean isHeadUp(); -+ // Paper End - More cat api - } -diff --git a/src/main/java/org/bukkit/entity/Enderman.java b/src/main/java/org/bukkit/entity/Enderman.java -index 94f3a8c4bf8cf14263d34d866db66728e98dfdb0..7937a0e082199554d3e8db1f9811be29abc9b3fd 100644 ---- a/src/main/java/org/bukkit/entity/Enderman.java -+++ b/src/main/java/org/bukkit/entity/Enderman.java -@@ -54,4 +54,36 @@ public interface Enderman extends Monster { - * @param blockData data to set the carried block to, or null to remove - */ - public void setCarriedBlock(@Nullable BlockData blockData); -+ -+ // Paper start -+ /** -+ * Returns whether the enderman is screaming/angry. -+ * -+ * @return whether the enderman is screaming -+ */ -+ boolean isScreaming(); -+ -+ /** -+ * Sets whether the enderman is screaming/angry. -+ * -+ * @param screaming whether the enderman is screaming -+ */ -+ void setScreaming(boolean screaming); -+ -+ /** -+ * Returns whether the enderman has been stared at. -+ * If set to true, players will hear an ambient sound. -+ * -+ * @return whether the enderman has been stared at -+ */ -+ boolean hasBeenStaredAt(); -+ -+ /** -+ * Sets whether the enderman has been stared at. -+ * If set to true, players will hear an ambient sound. -+ * -+ * @param hasBeenStaredAt whether the enderman has been stared at -+ */ -+ void setHasBeenStaredAt(boolean hasBeenStaredAt); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Fox.java b/src/main/java/org/bukkit/entity/Fox.java -index 498e182846b81d50b3a594254e8b341fb23e8763..3826363a1954afcddaadec7f96ac18300f8e89e9 100644 ---- a/src/main/java/org/bukkit/entity/Fox.java -+++ b/src/main/java/org/bukkit/entity/Fox.java -@@ -85,4 +85,62 @@ public interface Fox extends Animals, Sittable { - RED, - SNOW; - } -+ -+ // Paper start - Add more fox behavior API -+ /** -+ * Sets if the fox is interested. -+ * -+ * @param interested is interested -+ */ -+ public void setInterested(boolean interested); -+ -+ /** -+ * Gets if the fox is interested. -+ * -+ * @return fox is interested -+ */ -+ public boolean isInterested(); -+ -+ /** -+ * Sets if the fox is leaping. -+ * -+ * @param leaping is leaping -+ */ -+ public void setLeaping(boolean leaping); -+ -+ /** -+ * Gets if the fox is leaping. -+ * -+ * @return fox is leaping -+ */ -+ public boolean isLeaping(); -+ -+ /** -+ * Sets if the fox is defending. -+ * -+ * @param defending is defending -+ */ -+ public void setDefending(boolean defending); -+ -+ /** -+ * Gets if the fox is defending. -+ * -+ * @return fox is defending -+ */ -+ public boolean isDefending(); -+ -+ /** -+ * Sets if the fox face planted. -+ * -+ * @param faceplanted face planted -+ */ -+ public void setFaceplanted(boolean faceplanted); -+ -+ /** -+ * Gets if the fox face planted. -+ * -+ * @return fox face planted -+ */ -+ public boolean isFaceplanted(); -+ // Paper end - Add more fox behavior API - } -diff --git a/src/main/java/org/bukkit/entity/Ghast.java b/src/main/java/org/bukkit/entity/Ghast.java -index 3f5edf76ce303502cf4eeeb76f22f21f568dad5a..5930dc682c5c9273c748595e487b364b818a2fac 100644 ---- a/src/main/java/org/bukkit/entity/Ghast.java -+++ b/src/main/java/org/bukkit/entity/Ghast.java -@@ -3,4 +3,37 @@ package org.bukkit.entity; - /** - * Represents a Ghast. - */ --public interface Ghast extends Flying {} -+// Paper start -+public interface Ghast extends Flying { -+ -+ /** -+ * Returns whether the ghast is charging an attack. -+ * -+ * @return whether the ghast is charging an attack -+ */ -+ boolean isCharging(); -+ -+ /** -+ * Sets whether the ghast is charging an attack. -+ * This determines whether the client displays the charging animation. -+ * -+ * @param charging whether the ghast is charging an attack -+ */ -+ void setCharging(boolean charging); -+ -+ /** -+ * Returns the explosion power of shot fireballs. -+ * -+ * @return explosion power of shot fireballs -+ */ -+ int getExplosionPower(); -+ -+ /** -+ * Sets the explosion power of shot fireballs. -+ * -+ * @param explosionPower explosion power of shot fireballs -+ * @throws IllegalArgumentException if the explosion power is less than 0 or greater than 127 -+ */ -+ void setExplosionPower(int explosionPower); -+ // Paper end -+} -diff --git a/src/main/java/org/bukkit/entity/Panda.java b/src/main/java/org/bukkit/entity/Panda.java -index a6a7429ed2e1eefb2b12b7480ed74fcc3963a864..1dcc2c8f4899da029af8b1c1b2ff1b5e368e82c1 100644 ---- a/src/main/java/org/bukkit/entity/Panda.java -+++ b/src/main/java/org/bukkit/entity/Panda.java -@@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; - /** - * Panda entity. - */ --public interface Panda extends Animals { -+public interface Panda extends Animals, Sittable { // Paper - - /** - * Gets this Panda's main gene. -@@ -63,4 +63,125 @@ public interface Panda extends Animals { - return recessive; - } - } -+ -+ // Paper start - Panda API -+ /** -+ * Sets the sneeze progress in this animation. -+ * This value counts up only if {@link Panda#isSneezing()} is true -+ * -+ * @param ticks sneeze progress -+ */ -+ void setSneezeTicks(int ticks); -+ -+ /** -+ * Gets the current sneeze progress, or how many ticks this panda will sneeze for. -+ * -+ * @return sneeze progress -+ */ -+ int getSneezeTicks(); -+ -+ /** -+ * Sets if the panda is sneezing, which causes the sneeze counter to count. -+ *

      -+ * When false, this will automatically set the sneeze ticks to 0. -+ * -+ * @param sneeze if the panda is sneezing or not -+ */ -+ void setSneezing(boolean sneeze); -+ -+ /** -+ * Gets if the panda is sneezing -+ * -+ * @return is sneezing -+ */ -+ boolean isSneezing(); -+ -+ /** -+ * Sets the eating ticks for this panda. -+ *

      -+ * -+ * This starts counting up as long as it is greater than 0. -+ * -+ * @param ticks eating ticks -+ */ -+ void setEatingTicks(int ticks); -+ -+ /** -+ * Gets the current eating progress, or how many ticks this panda has been eating for. -+ * -+ * @return eating progress -+ */ -+ int getEatingTicks(); -+ -+ /** -+ * Sets the number of ticks this panda will be unhappy for. -+ *

      -+ * This value counts down. -+ * -+ * @param ticks unhappy ticks -+ */ -+ void setUnhappyTicks(int ticks); -+ -+ /** -+ * Gets how many ticks this panda will be unhappy for. -+ * -+ * @return unhappy ticks -+ */ -+ int getUnhappyTicks(); -+ -+ /** -+ * Sets if this panda is currently rolling. -+ * -+ * @param rolling should roll -+ */ -+ void setRolling(boolean rolling); -+ -+ /** -+ * Gets if this panda is currently rolling on the ground. -+ * -+ * @return is rolling -+ */ -+ boolean isRolling(); -+ -+ /** -+ * Sets if this panda is currently on its back. -+ * -+ * @param onBack is on its back -+ */ -+ void setIsOnBack(boolean onBack); -+ -+ /** -+ * Gets if this panda is currently on its back. -+ * -+ * @return is on back -+ */ -+ boolean isOnBack(); -+ -+ /** -+ * Sets if this panda is currently sitting. -+ * -+ * @param sitting is currently sitting -+ * @deprecated use {@link #setSitting(boolean)} -+ */ -+ @Deprecated(forRemoval = true) -+ default void setIsSitting(boolean sitting) { -+ this.setSitting(sitting); -+ } -+ -+ /** -+ * Sets if this panda is currently sitting. -+ * -+ * @param sitting is currently sitting -+ */ -+ @Override -+ void setSitting(boolean sitting); -+ -+ /** -+ * Gets if this panda is sitting. -+ * -+ * @return is sitting -+ */ -+ @Override -+ boolean isSitting(); -+ // Paper end - Panda API - } -diff --git a/src/main/java/org/bukkit/entity/Piglin.java b/src/main/java/org/bukkit/entity/Piglin.java -index 6fdc0e0bb62189dbf3cf9ce7a87b7fbb995956a3..d4cb4b0ed1d9766a87867dcf1a3a839526ba9332 100644 ---- a/src/main/java/org/bukkit/entity/Piglin.java -+++ b/src/main/java/org/bukkit/entity/Piglin.java -@@ -90,4 +90,25 @@ public interface Piglin extends PiglinAbstract, InventoryHolder, com.destroystok - */ - @NotNull - public Set getBarterList(); -+ -+ // Paper start -+ /** -+ * Causes the piglin to appear as if they are charging -+ * a crossbow. -+ *

      -+ * This works with any item currently held in the piglin's hand. -+ * -+ * @param chargingCrossbow is charging -+ */ -+ void setChargingCrossbow(boolean chargingCrossbow); -+ -+ /** -+ * Gets if the piglin is currently charging the -+ * item in their hand. -+ * -+ * @return is charging -+ */ -+ boolean isChargingCrossbow(); -+ // Paper end -+ - } -diff --git a/src/main/java/org/bukkit/entity/PolarBear.java b/src/main/java/org/bukkit/entity/PolarBear.java -index 479f7a7c54c85cb685f56e60906650d1989c03ff..60267ee382de80fab86b440ff72a2455f427d148 100644 ---- a/src/main/java/org/bukkit/entity/PolarBear.java -+++ b/src/main/java/org/bukkit/entity/PolarBear.java -@@ -3,4 +3,21 @@ package org.bukkit.entity; - /** - * Represents a polar bear. - */ --public interface PolarBear extends Animals {} -+// Paper start -+public interface PolarBear extends Animals { -+ -+ /** -+ * Returns whether the polar bear is standing. -+ * -+ * @return whether the polar bear is standing -+ */ -+ boolean isStanding(); -+ -+ /** -+ * Sets whether the polar bear is standing. -+ * -+ * @param standing whether the polar bear should be standing -+ */ -+ void setStanding(boolean standing); -+} -+// Paper end -diff --git a/src/main/java/org/bukkit/entity/Raider.java b/src/main/java/org/bukkit/entity/Raider.java -index 9a99b8ca1ec9c3c88b29275c88b1221e1b22bcef..756b4a7794ea0905abd4e4fe777f69ffe36658f5 100644 ---- a/src/main/java/org/bukkit/entity/Raider.java -+++ b/src/main/java/org/bukkit/entity/Raider.java -@@ -47,4 +47,20 @@ public interface Raider extends Monster { - * @param join CanJoinRaid status - */ - void setCanJoinRaid(boolean join); -+ -+ // Paper start -+ /** -+ * Returns whether the raider is celebrating a raid victory. -+ * -+ * @return whether the raider is celebrating a raid victory -+ */ -+ boolean isCelebrating(); -+ -+ /** -+ * Sets whether the raider is celebrating a raid victory. -+ * -+ * @param celebrating whether the raider is celebrating a raid victory -+ */ -+ void setCelebrating(boolean celebrating); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Trident.java b/src/main/java/org/bukkit/entity/Trident.java -index 28cdb3b544572ba7aeb9061e3163e3895ac7d4e6..c8015ff610e3c1222cb368ea1d8a0c2f3785d9c7 100644 ---- a/src/main/java/org/bukkit/entity/Trident.java -+++ b/src/main/java/org/bukkit/entity/Trident.java -@@ -3,4 +3,40 @@ package org.bukkit.entity; - /** - * Represents a thrown trident. - */ --public interface Trident extends AbstractArrow, ThrowableProjectile { } -+// Paper start -+public interface Trident extends AbstractArrow, ThrowableProjectile { -+ -+ /** -+ * Returns whether the trident has an enchanted glow. -+ * This can be separate from the underlying item having any enchantments. -+ * -+ * @return whether the trident has an enchanted glow -+ */ -+ boolean hasGlint(); -+ -+ /** -+ * Sets whether the trident has an enchanted glow. -+ * This is separate from the underlying item having any enchantments. -+ * -+ * @param glint whether the trident should have an enchanted glow -+ */ -+ void setGlint(boolean glint); -+ -+ /** -+ * Returns the loyalty level of the trident. -+ * This can be separate from the underlying item's enchantments. -+ * -+ * @return loyalty level of the trident -+ */ -+ int getLoyaltyLevel(); -+ -+ /** -+ * Sets the loyalty level of the trident. -+ * This is separate from the underlying item's enchantments. -+ * -+ * @param loyaltyLevel loyalty level -+ * @throws IllegalArgumentException if the loyalty level is lower than 0 or greater than 127 -+ */ -+ void setLoyaltyLevel(int loyaltyLevel); -+} -+// Paper end -diff --git a/src/main/java/org/bukkit/entity/Vex.java b/src/main/java/org/bukkit/entity/Vex.java -index 627e3c1a96ae3331f5aa2dd7803dd2a31c7204be..3c447d2300c866ae605eeca97bd869f400d6be6f 100644 ---- a/src/main/java/org/bukkit/entity/Vex.java -+++ b/src/main/java/org/bukkit/entity/Vex.java -@@ -57,21 +57,30 @@ public interface Vex extends Monster { - * Gets the remaining lifespan of this entity. - * - * @return life in ticks -+ * @deprecated This API duplicates existing API which uses the more -+ * preferable name due to mirroring internals better - */ -+ @Deprecated - int getLifeTicks(); - - /** - * Sets the remaining lifespan of this entity. - * - * @param lifeTicks life in ticks, or negative for unlimited lifepan -+ * @deprecated This API duplicates existing API which uses the more -+ * preferable name due to mirroring internals better - */ -+ @Deprecated - void setLifeTicks(int lifeTicks); - - /** - * Gets if the entity has a limited life. - * - * @return true if the entity has limited life -+ * @deprecated This API duplicates existing API which uses the more -+ * preferable name due to mirroring internals better - */ -+ @Deprecated - boolean hasLimitedLife(); - // Paper start - -@@ -89,5 +98,37 @@ public interface Vex extends Monster { - * @param summoner New summoner - */ - void setSummoner(@Nullable Mob summoner); -+ -+ /** -+ * Gets if this vex should start to take damage -+ * once {@link Vex#getLimitedLifetimeTicks()} is less than or equal to 0. -+ * -+ * @return will take damage -+ */ -+ boolean hasLimitedLifetime(); -+ -+ /** -+ * Sets if this vex should start to take damage -+ * once {@link Vex#getLimitedLifetimeTicks()} is less than or equal to 0. -+ * -+ * @param hasLimitedLifetime should take damage -+ */ -+ void setLimitedLifetime(boolean hasLimitedLifetime); -+ -+ /** -+ * Gets the number of ticks remaining until the vex will start -+ * to take damage. -+ * -+ * @return ticks until the vex will start to take damage -+ */ -+ int getLimitedLifetimeTicks(); -+ -+ /** -+ * Sets the number of ticks remaining until the vex takes damage. -+ * This number is ticked down only if {@link Vex#hasLimitedLifetime()} is true. -+ * -+ * @param ticks ticks remaining -+ */ -+ void setLimitedLifetimeTicks(int ticks); - // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Wither.java b/src/main/java/org/bukkit/entity/Wither.java -index b86f0196e6eb8070830f63a94f732522c2a6c2f1..a1b42ae35dda2da90ba00a2d6666514f7c5b11dd 100644 ---- a/src/main/java/org/bukkit/entity/Wither.java -+++ b/src/main/java/org/bukkit/entity/Wither.java -@@ -48,4 +48,35 @@ public interface Wither extends Monster, Boss, com.destroystokyo.paper.entity.Ra - LEFT, - RIGHT - } -+ -+ // Paper start -+ /** -+ * @return whether the wither is charged -+ */ -+ boolean isCharged(); -+ -+ /** -+ * @return ticks the wither is invulnerable for -+ */ -+ int getInvulnerableTicks(); -+ -+ /** -+ * Sets for how long in the future, the wither should be invulnerable. -+ * -+ * @param ticks ticks the wither is invulnerable for -+ */ -+ void setInvulnerableTicks(int ticks); -+ -+ /** -+ * @return whether the wither can travel through portals -+ */ -+ boolean canTravelThroughPortals(); -+ -+ /** -+ * Sets whether the wither can travel through portals. -+ * -+ * @param value whether the wither can travel through portals -+ */ -+ void setCanTravelThroughPortals(boolean value); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Wolf.java b/src/main/java/org/bukkit/entity/Wolf.java -index 0e5decadf31140d6cb121c298f935ccc12c7a7e7..490395f38c4d9977d30a6f48585a4ea0e7faff0f 100644 ---- a/src/main/java/org/bukkit/entity/Wolf.java -+++ b/src/main/java/org/bukkit/entity/Wolf.java -@@ -39,4 +39,22 @@ public interface Wolf extends Tameable, Sittable { - * @param color the color to apply - */ - public void setCollarColor(@NotNull DyeColor color); -+ -+ // Paper start -+ /** -+ * Sets if the wolf is interested. -+ *

      -+ * This causes the wolf to tilt its head to the side. -+ * -+ * @param interested is interested -+ */ -+ void setInterested(boolean interested); -+ -+ /** -+ * Gets if the wolf is interested. -+ * -+ * @return is interested -+ */ -+ boolean isInterested(); -+ // Paper end - } diff --git a/patches/api/0344-Add-more-Campfire-API.patch b/patches/api/0314-Add-more-Campfire-API.patch similarity index 100% rename from patches/api/0344-Add-more-Campfire-API.patch rename to patches/api/0314-Add-more-Campfire-API.patch diff --git a/patches/api/0314-Adds-PlayerArmSwingEvent.patch b/patches/api/0314-Adds-PlayerArmSwingEvent.patch deleted file mode 100644 index 0a501495feb7..000000000000 --- a/patches/api/0314-Adds-PlayerArmSwingEvent.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 12 Mar 2021 19:20:03 -0800 -Subject: [PATCH] Adds PlayerArmSwingEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerArmSwingEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerArmSwingEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ce76b07cfaa9173c78e2844add2bc5bb437b1106 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerArmSwingEvent.java -@@ -0,0 +1,27 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.player.PlayerAnimationEvent; -+import org.bukkit.event.player.PlayerAnimationType; -+import org.bukkit.inventory.EquipmentSlot; -+import org.jetbrains.annotations.NotNull; -+ -+public class PlayerArmSwingEvent extends PlayerAnimationEvent { -+ -+ private final EquipmentSlot equipmentSlot; -+ -+ public PlayerArmSwingEvent(@NotNull Player player, @NotNull EquipmentSlot equipmentSlot) { -+ super(player, equipmentSlot == EquipmentSlot.HAND ? PlayerAnimationType.ARM_SWING : PlayerAnimationType.OFF_ARM_SWING); -+ this.equipmentSlot = equipmentSlot; -+ } -+ -+ /** -+ * Returns the hand of the arm swing. -+ * -+ * @return the hand -+ */ -+ @NotNull -+ public EquipmentSlot getHand() { -+ return this.equipmentSlot; -+ } -+} -diff --git a/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java b/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java -index eb722a1e3b987b86fae2fa8346606fa15fada26f..11c27b1a4a749e129ed4b2d906c315d97a4b66e7 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerAnimationEvent.java -@@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull; - - /** - * Represents a player animation event -+ *
      Use {@link io.papermc.paper.event.player.PlayerArmSwingEvent} for determining which arm was swung. - */ - public class PlayerAnimationEvent extends PlayerEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); diff --git a/patches/api/0315-Add-PlayerSignCommandPreprocessEvent.patch b/patches/api/0315-Add-PlayerSignCommandPreprocessEvent.patch deleted file mode 100644 index fd095653a3e8..000000000000 --- a/patches/api/0315-Add-PlayerSignCommandPreprocessEvent.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 9 Jul 2021 17:44:33 -0700 -Subject: [PATCH] Add PlayerSignCommandPreprocessEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerSignCommandPreprocessEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerSignCommandPreprocessEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a51a2288bf812e7d8845a6ec70274d625ff793b6 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerSignCommandPreprocessEvent.java -@@ -0,0 +1,34 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.block.Sign; -+import org.bukkit.entity.Player; -+import org.bukkit.event.player.PlayerCommandPreprocessEvent; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.Set; -+ -+/** -+ * Called when a {@link Player} clicks a sign that causes a command to run. -+ *

      -+ * This command is run with elevated permissions which allows players to access commands on signs they wouldn't -+ * normally be able to run. -+ */ -+public class PlayerSignCommandPreprocessEvent extends PlayerCommandPreprocessEvent { -+ -+ private final Sign sign; -+ -+ public PlayerSignCommandPreprocessEvent(@NotNull Player player, @NotNull String message, @NotNull Set recipients, @NotNull Sign sign) { -+ super(player, message, recipients); -+ this.sign = sign; -+ } -+ -+ /** -+ * Gets the sign that the command originated from. -+ * -+ * @return the sign -+ */ -+ @NotNull -+ public Sign getSign() { -+ return sign; -+ } -+} diff --git a/patches/api/0315-Extend-VehicleCollisionEvent-move-HandlerList-up.patch b/patches/api/0315-Extend-VehicleCollisionEvent-move-HandlerList-up.patch new file mode 100644 index 000000000000..5f5a4f414001 --- /dev/null +++ b/patches/api/0315-Extend-VehicleCollisionEvent-move-HandlerList-up.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 13 Dec 2021 14:35:27 -0800 +Subject: [PATCH] Extend VehicleCollisionEvent, move HandlerList up + +Co-authored-by: SoSeDiK + +diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java +index 316f625aa595d2ada16529b16d09f013fc4daeac..d0a437bd8aeec18f800893f51ece06deb0c8972c 100644 +--- a/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java ++++ b/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java +@@ -9,13 +9,31 @@ import org.jetbrains.annotations.NotNull; + * Raised when a vehicle collides with a block. + */ + public class VehicleBlockCollisionEvent extends VehicleCollisionEvent { +- private static final HandlerList handlers = new HandlerList(); + private final Block block; ++ private final org.bukkit.util.Vector velocity; // Paper + ++ // Paper start - Add pre-collision velocity ++ @Deprecated + public VehicleBlockCollisionEvent(@NotNull final Vehicle vehicle, @NotNull final Block block) { ++ this(vehicle, block, vehicle.getVelocity()); ++ } ++ ++ public VehicleBlockCollisionEvent(@NotNull final Vehicle vehicle, @NotNull final Block block, @NotNull final org.bukkit.util.Vector velocity) { // Paper - Added velocity + super(vehicle); + this.block = block; ++ this.velocity = velocity; ++ } ++ ++ /** ++ * Gets velocity at which the vehicle collided with the block ++ * ++ * @return pre-collision moving velocity ++ */ ++ @NotNull ++ public org.bukkit.util.Vector getVelocity() { ++ return velocity; + } ++ // Paper end + + /** + * Gets the block the vehicle collided with +@@ -26,15 +44,4 @@ public class VehicleBlockCollisionEvent extends VehicleCollisionEvent { + public Block getBlock() { + return block; + } +- +- @NotNull +- @Override +- public HandlerList getHandlers() { +- return handlers; +- } +- +- @NotNull +- public static HandlerList getHandlerList() { +- return handlers; +- } + } +diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java +index 9d493c155ad5c26430c1e404fcf0db5f734679e4..aa1d74eade479195bde8095aafcc91a83635102d 100644 +--- a/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java ++++ b/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java +@@ -7,7 +7,18 @@ import org.jetbrains.annotations.NotNull; + * Raised when a vehicle collides. + */ + public abstract class VehicleCollisionEvent extends VehicleEvent { ++ private static final org.bukkit.event.HandlerList HANDLER_LIST = new org.bukkit.event.HandlerList(); // Paper + public VehicleCollisionEvent(@NotNull final Vehicle vehicle) { + super(vehicle); + } ++ // Paper start ++ @Override ++ public org.bukkit.event.@org.jetbrains.annotations.NotNull HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static org.bukkit.event.@NotNull HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java +index 50c762d777ac90a05772501a28cacff8fd3f5126..77fb04bdf5b1a6d94693a7374a750e020131dc3d 100644 +--- a/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java ++++ b/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java +@@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull; + * Raised when a vehicle collides with an entity. + */ + public class VehicleEntityCollisionEvent extends VehicleCollisionEvent implements Cancellable { +- private static final HandlerList handlers = new HandlerList(); + private final Entity entity; + private boolean cancelled = false; + private boolean cancelledPickup = false; +@@ -55,15 +54,4 @@ public class VehicleEntityCollisionEvent extends VehicleCollisionEvent implement + public void setCollisionCancelled(boolean cancel) { + cancelledCollision = cancel; + } +- +- @NotNull +- @Override +- public HandlerList getHandlers() { +- return handlers; +- } +- +- @NotNull +- public static HandlerList getHandlerList() { +- return handlers; +- } + } diff --git a/patches/api/0316-Improve-scoreboard-entries.patch b/patches/api/0316-Improve-scoreboard-entries.patch new file mode 100644 index 000000000000..26f03310e988 --- /dev/null +++ b/patches/api/0316-Improve-scoreboard-entries.patch @@ -0,0 +1,191 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 4 Nov 2021 12:31:45 -0700 +Subject: [PATCH] Improve scoreboard entries + + +diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java +index 35755c9165c1b48eaacfff86a50a7973476fe04b..d6d52bc9185e8a1581ccfa57df3550bc12d9872a 100644 +--- a/src/main/java/org/bukkit/scoreboard/Objective.java ++++ b/src/main/java/org/bukkit/scoreboard/Objective.java +@@ -148,9 +148,8 @@ public interface Objective { + * @return Score tracking the Objective and player specified + * @throws IllegalStateException if this objective has been unregistered + * @see #getScore(String) +- * @deprecated Scoreboards can contain entries that aren't players + */ +- @Deprecated(since = "1.7.8") ++ // @Deprecated(since = "1.7.8") // Paper + @NotNull + Score getScore(@NotNull OfflinePlayer player); + +@@ -164,4 +163,16 @@ public interface Objective { + */ + @NotNull + Score getScore(@NotNull String entry); ++ ++ // Paper start - improve scoreboard entries ++ /** ++ * Gets an entity's Score for an Objective on this Scoreboard. ++ * ++ * @param entity Entity for the Score ++ * @return Score tracking the Objective and entity specified ++ * @throws IllegalArgumentException if entity is null ++ * @throws IllegalStateException if this objective has been unregistered ++ */ ++ @NotNull Score getScoreFor(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException; ++ // Paper end - improve scoreboard entries + } +diff --git a/src/main/java/org/bukkit/scoreboard/Scoreboard.java b/src/main/java/org/bukkit/scoreboard/Scoreboard.java +index 1cba9a96cc7efce2a4394add33e4c0369f94be31..81ca0c62ce32204681fcb8fd751d12b4fb0aeb97 100644 +--- a/src/main/java/org/bukkit/scoreboard/Scoreboard.java ++++ b/src/main/java/org/bukkit/scoreboard/Scoreboard.java +@@ -215,9 +215,8 @@ public interface Scoreboard { + * @param player the player whose scores are being retrieved + * @return immutable set of all scores tracked for the player + * @see #getScores(String) +- * @deprecated Scoreboards can contain entries that aren't players + */ +- @Deprecated(since = "1.7.8") ++ // @Deprecated(since = "1.7.8") // Paper + @NotNull + Set getScores(@NotNull OfflinePlayer player); + +@@ -235,9 +234,8 @@ public interface Scoreboard { + * + * @param player the player to drop all current scores for + * @see #resetScores(String) +- * @deprecated Scoreboards can contain entries that aren't players + */ +- @Deprecated(since = "1.7.8") ++ // @Deprecated(since = "1.7.8") // Paper + void resetScores(@NotNull OfflinePlayer player); + + /** +@@ -253,9 +251,8 @@ public interface Scoreboard { + * @param player the player to search for + * @return the player's Team or null if the player is not on a team + * @see #getEntryTeam(String) +- * @deprecated Scoreboards can contain entries that aren't players + */ +- @Deprecated(since = "1.8.6") ++ // @Deprecated(since = "1.8.6") // Paper + @Nullable + Team getPlayerTeam(@NotNull OfflinePlayer player); + +@@ -320,4 +317,35 @@ public interface Scoreboard { + * @param slot the slot to remove objectives + */ + void clearSlot(@NotNull DisplaySlot slot); ++ ++ // Paper start - improve scoreboard entries ++ /** ++ * Gets all scores for an entity on this Scoreboard ++ * ++ * @param entity the entity whose scores are being retrieved ++ * @return immutable set of all scores tracked for the entity ++ * @throws IllegalArgumentException if entity is null ++ * @see #getScores(String) ++ */ ++ @NotNull Set getScoresFor(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException; ++ ++ /** ++ * Removes all scores for an entity on this Scoreboard ++ * ++ * @param entity the entity to drop all current scores for ++ * @throws IllegalArgumentException if entity is null ++ * @see #resetScores(String) ++ */ ++ void resetScoresFor(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException; ++ ++ /** ++ * Gets an entity's Team on this Scoreboard ++ * ++ * @param entity the entity to search for ++ * @return the entity's Team or null if the entity is not on a team ++ * @throws IllegalArgumentException if entity is null ++ * @see #getEntryTeam(String) ++ */ ++ @Nullable Team getEntityTeam(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException; ++ // Paper end - improve scoreboard entries + } +diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java +index 38deee00cfe2f6803070e98cd9ded95d859bf8e1..c500de6ed19bdf732f7bedbedb19a4b37ca343f8 100644 +--- a/src/main/java/org/bukkit/scoreboard/Team.java ++++ b/src/main/java/org/bukkit/scoreboard/Team.java +@@ -295,9 +295,8 @@ public interface Team extends net.kyori.adventure.audience.ForwardingAudience { + * @param player the player to add + * @throws IllegalStateException if this team has been unregistered + * @see #addEntry(String) +- * @deprecated Teams can contain entries that aren't players + */ +- @Deprecated(since = "1.8.6") ++ // @Deprecated(since = "1.8.6") // Paper + void addPlayer(@NotNull OfflinePlayer player); + + /** +@@ -317,9 +316,8 @@ public interface Team extends net.kyori.adventure.audience.ForwardingAudience { + * @return if the player was on this team + * @throws IllegalStateException if this team has been unregistered + * @see #removeEntry(String) +- * @deprecated Teams can contain entries that aren't players + */ +- @Deprecated(since = "1.8.6") ++ // @Deprecated(since = "1.8.6") // Paper + boolean removePlayer(@NotNull OfflinePlayer player); + + /** +@@ -345,9 +343,8 @@ public interface Team extends net.kyori.adventure.audience.ForwardingAudience { + * @return true if the player is a member of this team + * @throws IllegalStateException if this team has been unregistered + * @see #hasEntry(String) +- * @deprecated Teams can contain entries that aren't players + */ +- @Deprecated(since = "1.8.6") ++ // @Deprecated(since = "1.8.6") // Paper + boolean hasPlayer(@NotNull OfflinePlayer player); + /** + * Checks to see if the specified entry is a member of this team. +@@ -377,6 +374,42 @@ public interface Team extends net.kyori.adventure.audience.ForwardingAudience { + */ + void setOption(@NotNull Option option, @NotNull OptionStatus status); + ++ // Paper start - improve scoreboard entries ++ /** ++ * This puts the specified entity onto this team for the scoreboard. ++ *

      ++ * This will remove the entity from any other team on the scoreboard. ++ * ++ * @param entity the entity to add ++ * @throws IllegalArgumentException if entity is null ++ * @throws IllegalStateException if this team has been unregistered ++ * @see #addEntry(String) ++ */ ++ void addEntity(@NotNull org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException; ++ ++ /** ++ * Removes the entity from this team. ++ * ++ * @param entity the entity to remove ++ * @return if the entity was on this team ++ * @throws IllegalArgumentException if entity is null ++ * @throws IllegalStateException if this team has been unregistered ++ * @see #removeEntry(String) ++ */ ++ boolean removeEntity(@NotNull org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException; ++ ++ /** ++ * Checks to see if the specified entity is a member of this team. ++ * ++ * @param entity the entity to search for ++ * @return true if the entity is a member of this team ++ * @throws IllegalArgumentException if entity is null ++ * @throws IllegalStateException if this team has been unregistered ++ * @see #hasEntry(String) ++ */ ++ boolean hasEntity(@NotNull org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException; ++ // Paper end - improve scoreboard entries ++ + /** + * Represents an option which may be applied to this team. + */ diff --git a/patches/api/0316-fix-empty-array-elements-in-command-arguments.patch b/patches/api/0316-fix-empty-array-elements-in-command-arguments.patch deleted file mode 100644 index b6512f8f2946..000000000000 --- a/patches/api/0316-fix-empty-array-elements-in-command-arguments.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trigary -Date: Sat, 5 Jun 2021 10:29:39 +0200 -Subject: [PATCH] fix empty array elements in command arguments - -Adjacent spaces caused empty array elements due to how String#split works. -This change removes those empty array elements without modifying anything else. -Adjacent spaces sent by players are removed in PlayerConnection, so this change doesn't affect players. -But it does affect the console, command blocks, Bukkit.dispatchCommand, etc. - -diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java -index 950a2d0b3b583c6b9a703190874bbc4df2783ab7..b8623575b1c1b565560c2dd6438190716845a652 100644 ---- a/src/main/java/org/bukkit/command/SimpleCommandMap.java -+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java -@@ -130,7 +130,7 @@ public class SimpleCommandMap implements CommandMap { - */ - @Override - public boolean dispatch(@NotNull CommandSender sender, @NotNull String commandLine) throws CommandException { -- String[] args = commandLine.split(" "); -+ String[] args = org.apache.commons.lang3.StringUtils.split(commandLine, ' '); // Paper - fix adjacent spaces (from console/plugins) causing empty array elements - - if (args.length == 0) { - return false; diff --git a/patches/api/0317-Entity-powdered-snow-API.patch b/patches/api/0317-Entity-powdered-snow-API.patch new file mode 100644 index 000000000000..ca7af1d0e573 --- /dev/null +++ b/patches/api/0317-Entity-powdered-snow-API.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 24 Oct 2021 20:58:52 -0700 +Subject: [PATCH] Entity powdered snow API + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 464668496f5a611ae78bd5f6392915ec384862ac..97b8ac9ae8ebe0f074f5f1f806d9415b8122400c 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -973,5 +973,12 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + * @return Whether the entity was successfully spawned. + */ + public boolean spawnAt(@NotNull Location location, @NotNull org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason); ++ ++ /** ++ * Check if entity is inside powdered snow. ++ * ++ * @return true if in powdered snow. ++ */ ++ boolean isInPowderedSnow(); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Skeleton.java b/src/main/java/org/bukkit/entity/Skeleton.java +index 0944d920301d8cd5ec3960454129f7d1c15ee6d4..ce04c03ba5f67e02faf10ed8aaef4d51fbf2b190 100644 +--- a/src/main/java/org/bukkit/entity/Skeleton.java ++++ b/src/main/java/org/bukkit/entity/Skeleton.java +@@ -41,6 +41,16 @@ public interface Skeleton extends AbstractSkeleton { + */ + void setConversionTime(int time); + ++ // Paper start ++ /** ++ * Gets the time the skeleton ++ * has been inside powdered snow. ++ * ++ * @return time in ticks ++ */ ++ int inPowderedSnowTime(); ++ // Paper end ++ + /** + * A legacy enum that defines the different variances of skeleton-like + * entities on the server. diff --git a/patches/api/0317-Stinger-API.patch b/patches/api/0317-Stinger-API.patch deleted file mode 100644 index fdd5a623a9c7..000000000000 --- a/patches/api/0317-Stinger-API.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Tue, 22 Jun 2021 23:16:11 -0400 -Subject: [PATCH] Stinger API - - -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index 5238d83788ef39db1f86c22a0b27648cc47a215b..8fa8922ad2fb0ea8f770368faff61e56e9761df9 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -335,6 +335,36 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - */ - public void setArrowsInBody(int count); - -+ // Paper Start - Bee Stinger API -+ /** -+ * Gets the time in ticks until the next bee stinger leaves the entity's body. -+ * -+ * @return ticks until bee stinger leaves -+ */ -+ public int getBeeStingerCooldown(); -+ -+ /** -+ * Sets the time in ticks until the next stinger leaves the entity's body. -+ * -+ * @param ticks time until bee stinger leaves -+ */ -+ public void setBeeStingerCooldown(int ticks); -+ -+ /** -+ * Gets the amount of bee stingers in an entity's body. -+ * -+ * @return amount of bee stingers in body -+ */ -+ public int getBeeStingersInBody(); -+ -+ /** -+ * Set the amount of bee stingers in the entity's body. -+ * -+ * @param count amount of bee stingers in entity's body -+ */ -+ public void setBeeStingersInBody(int count); -+ // Paper End - Stinger API -+ - /** - * Returns the living entity's current maximum no damage ticks. - *

      diff --git a/patches/api/0318-Add-API-for-item-entity-health.patch b/patches/api/0318-Add-API-for-item-entity-health.patch new file mode 100644 index 000000000000..572034e55714 --- /dev/null +++ b/patches/api/0318-Add-API-for-item-entity-health.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 28 Aug 2021 09:00:35 -0700 +Subject: [PATCH] Add API for item entity health + + +diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java +index 6239aec4f6c625a814fa4fd610cdc5ab1a9f6e0f..ced419f8655bff72f0257b639d5f7d73afe3c2e2 100644 +--- a/src/main/java/org/bukkit/entity/Item.java ++++ b/src/main/java/org/bukkit/entity/Item.java +@@ -133,5 +133,24 @@ public interface Item extends Entity { + * @param willAge True if the item should age + */ + public void setWillAge(boolean willAge); ++ ++ /** ++ * Gets the health of item stack. ++ *

      ++ * Currently the default max health is 5. ++ * ++ * @return the health ++ */ ++ public int getHealth(); ++ ++ /** ++ * Sets the health of the item stack. If the value is non-positive ++ * the itemstack's normal "on destroy" functionality will be run. ++ *

      ++ * Currently, the default max health is 5. ++ * ++ * @param health the health, a non-positive value will destroy the entity ++ */ ++ public void setHealth(int health); + // Paper end + } diff --git a/patches/api/0318-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch b/patches/api/0318-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch deleted file mode 100644 index a9319418e460..000000000000 --- a/patches/api/0318-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SirYwell -Date: Sat, 10 Jul 2021 11:11:43 +0200 -Subject: [PATCH] Rewrite LogEvents to contain the source jars in stack traces - - -diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -index e39492e2544c39c5457f079a6baadf0b4074dd7e..345394132df70593800127d34a38f8f8a4dafe00 100644 ---- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -@@ -51,7 +51,7 @@ public final class PluginClassLoader extends URLClassLoader { // Spigot - } - - PluginClassLoader(@NotNull final JavaPluginLoader loader, @Nullable final ClassLoader parent, @NotNull final PluginDescriptionFile description, @NotNull final File dataFolder, @NotNull final File file, @Nullable ClassLoader libraryLoader) throws IOException, InvalidPluginException, MalformedURLException { -- super(new URL[] {file.toURI().toURL()}, parent); -+ super(file.getName(), new URL[] {file.toURI().toURL()}, parent); // Paper - rewrite LogEvents to contain source jar info - Preconditions.checkArgument(loader != null, "Loader cannot be null"); - - this.loader = loader; diff --git a/patches/api/0319-Add-PlayerSetSpawnEvent.patch b/patches/api/0319-Add-PlayerSetSpawnEvent.patch deleted file mode 100644 index 74772fd9d83e..000000000000 --- a/patches/api/0319-Add-PlayerSetSpawnEvent.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 19 May 2021 18:58:24 -0700 -Subject: [PATCH] Add PlayerSetSpawnEvent - - -diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerSetSpawnEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerSetSpawnEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c615dbe6ca1289bb090b8e28e98b9ad7b0af8b2a ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerSetSpawnEvent.java -@@ -0,0 +1,175 @@ -+package com.destroystokyo.paper.event.player; -+ -+import net.kyori.adventure.text.Component; -+import org.bukkit.Location; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when a player's spawn is set, either by themselves or otherwise.
      -+ * Cancelling this event will prevent the spawn from being set. -+ */ -+public class PlayerSetSpawnEvent extends PlayerEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final Cause cause; -+ private Location location; -+ private boolean forced; -+ private boolean notifyPlayer; -+ private Component notification; -+ -+ private boolean cancelled; -+ -+ public PlayerSetSpawnEvent(@NotNull Player who, @NotNull Cause cause, @Nullable Location location, boolean forced, boolean notifyPlayer, @Nullable Component notification) { -+ super(who); -+ this.cause = cause; -+ this.location = location; -+ this.forced = forced; -+ this.notifyPlayer = notifyPlayer; -+ this.notification = notification; -+ } -+ -+ /** -+ * Gets the cause of this event. -+ * -+ * @return the cause -+ */ -+ @NotNull -+ public Cause getCause() { -+ return cause; -+ } -+ -+ /** -+ * Gets the location that the spawn is set to. The yaw -+ * of this location is the spawn angle. Mutating this location -+ * will change the resulting spawn point of the player. Use -+ * {@link Location#clone()} to get a copy of this location. -+ * -+ * @return the spawn location, or null if removing the location -+ */ -+ @Nullable -+ public Location getLocation() { -+ return location; -+ } -+ -+ /** -+ * Sets the location to be set as the spawn location. The yaw -+ * of this location is the spawn angle. -+ * -+ * @param location the spawn location, or null to remove the spawn location -+ */ -+ public void setLocation(@Nullable Location location) { -+ this.location = location; -+ } -+ -+ /** -+ * Gets if this is a force spawn location -+ * -+ * @return true if forced -+ */ -+ public boolean isForced() { -+ return forced; -+ } -+ -+ /** -+ * Sets if this is a forced spawn location -+ * -+ * @param forced true to force -+ */ -+ public void setForced(boolean forced) { -+ this.forced = forced; -+ } -+ -+ /** -+ * Gets if this action will notify the player their spawn -+ * has been set. -+ * -+ * @return true to notify -+ */ -+ public boolean willNotifyPlayer() { -+ return notifyPlayer; -+ } -+ -+ /** -+ * Sets if this action will notify the player that their spawn -+ * has been set. -+ * -+ * @param notifyPlayer true to notify -+ */ -+ public void setNotifyPlayer(boolean notifyPlayer) { -+ this.notifyPlayer = notifyPlayer; -+ } -+ -+ /** -+ * Gets the notification message that will be sent to the player -+ * if {@link #willNotifyPlayer()} returns true. -+ * -+ * @return null if no notification -+ */ -+ @Nullable -+ public Component getNotification() { -+ return notification; -+ } -+ -+ /** -+ * Sets the notification message that will be sent to the player. -+ * -+ * @param notification null to send no message -+ */ -+ public void setNotification(@Nullable Component notification) { -+ this.notification = notification; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+ -+ public enum Cause { -+ /** -+ * When a player interacts successfully with a bed. -+ */ -+ BED, -+ /** -+ * When a player interacts successfully with a respawn anchor. -+ */ -+ RESPAWN_ANCHOR, -+ /** -+ * When a player respawns. -+ */ -+ PLAYER_RESPAWN, -+ /** -+ * When the {@code /spawnpoint} command is used on a player. -+ */ -+ COMMAND, -+ /** -+ * When a plugin uses {@link Player#setBedSpawnLocation(Location)} or -+ * {@link Player#setBedSpawnLocation(Location, boolean)}. -+ */ -+ PLUGIN, -+ /** -+ * Fallback cause. -+ */ -+ UNKNOWN, -+ } -+} diff --git a/patches/api/0349-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch b/patches/api/0319-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch similarity index 100% rename from patches/api/0349-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch rename to patches/api/0319-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch diff --git a/patches/api/0320-Added-EntityDamageItemEvent.patch b/patches/api/0320-Added-EntityDamageItemEvent.patch deleted file mode 100644 index 8bbe79f9f38b..000000000000 --- a/patches/api/0320-Added-EntityDamageItemEvent.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 22 Dec 2020 13:51:06 -0800 -Subject: [PATCH] Added EntityDamageItemEvent - - -diff --git a/src/main/java/io/papermc/paper/event/entity/EntityDamageItemEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityDamageItemEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..13862939d7b633f08d5c70bfd2097c47278efcce ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/EntityDamageItemEvent.java -@@ -0,0 +1,77 @@ -+package io.papermc.paper.event.entity; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when an item on or used by an entity takes durability damage as a result of being hit/used. -+ *

      -+ * NOTE: default vanilla behaviour dictates that armor/tools picked up by -+ * mobs do not take damage (except via Thorns). -+ */ -+public class EntityDamageItemEvent extends EntityEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ private final ItemStack item; -+ private int damage; -+ private boolean cancelled; -+ -+ public EntityDamageItemEvent(@NotNull Entity entity, @NotNull ItemStack item, int damage) { -+ super(entity); -+ this.item = item; -+ this.damage = damage; -+ } -+ -+ /** -+ * Gets the item being damaged. -+ * -+ * @return the item -+ */ -+ @NotNull -+ public ItemStack getItem() { -+ return item; -+ } -+ -+ /** -+ * Gets the amount of durability damage this item will be taking. -+ * -+ * @return durability change -+ */ -+ public int getDamage() { -+ return damage; -+ } -+ -+ /** -+ * Sets the amount of durability damage this item will be taking. -+ * -+ * @param damage the damage amount to cause -+ */ -+ public void setDamage(int damage) { -+ this.damage = damage; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} diff --git a/patches/api/0320-Bucketable-API.patch b/patches/api/0320-Bucketable-API.patch new file mode 100644 index 000000000000..b954c4c6983a --- /dev/null +++ b/patches/api/0320-Bucketable-API.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 26 Dec 2021 14:03:11 -0500 +Subject: [PATCH] Bucketable API + + +diff --git a/src/main/java/io/papermc/paper/entity/Bucketable.java b/src/main/java/io/papermc/paper/entity/Bucketable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a63c3d0fe50f5808215ed169b81269112f76ec1b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/Bucketable.java +@@ -0,0 +1,41 @@ ++package io.papermc.paper.entity; ++ ++import org.bukkit.Sound; ++import org.bukkit.entity.Entity; ++import org.bukkit.inventory.ItemStack; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents an entity that can be bucketed. ++ */ ++@NullMarked ++public interface Bucketable extends Entity { ++ ++ /** ++ * Gets if this entity originated from a bucket. ++ * ++ * @return originated from bucket ++ */ ++ boolean isFromBucket(); ++ ++ /** ++ * Sets if this entity originated from a bucket. ++ * ++ * @param fromBucket is from a bucket ++ */ ++ void setFromBucket(boolean fromBucket); ++ ++ /** ++ * Gets the base itemstack of this entity in a bucket form. ++ * ++ * @return bucket form ++ */ ++ ItemStack getBaseBucketItem(); ++ ++ /** ++ * Gets the sound that is played when this entity ++ * is picked up in a bucket. ++ * @return bucket pickup sound ++ */ ++ Sound getPickupSound(); ++} +diff --git a/src/main/java/org/bukkit/entity/Axolotl.java b/src/main/java/org/bukkit/entity/Axolotl.java +index 9763f3b9ac8f32c082a476f4b50a32622b2720a0..c8c738b1b72e9ad89d97b7a1f5450d58045a72ca 100644 +--- a/src/main/java/org/bukkit/entity/Axolotl.java ++++ b/src/main/java/org/bukkit/entity/Axolotl.java +@@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; + /** + * An Axolotl. + */ +-public interface Axolotl extends Animals { ++public interface Axolotl extends Animals, io.papermc.paper.entity.Bucketable { // Paper - Bucketable API + + /** + * Gets if this axolotl is playing dead. +diff --git a/src/main/java/org/bukkit/entity/Fish.java b/src/main/java/org/bukkit/entity/Fish.java +index 82e390b2152e7c881006ca30f2527d160c01f8a1..86da8dc401ed7db19a39bc682721055cd341ccde 100644 +--- a/src/main/java/org/bukkit/entity/Fish.java ++++ b/src/main/java/org/bukkit/entity/Fish.java +@@ -3,4 +3,4 @@ package org.bukkit.entity; + /** + * Represents a fish entity. + */ +-public interface Fish extends WaterMob { } ++public interface Fish extends WaterMob, io.papermc.paper.entity.Bucketable { } // Paper - Bucketable API diff --git a/patches/api/0321-System-prop-for-default-config-comment-parsing.patch b/patches/api/0321-System-prop-for-default-config-comment-parsing.patch new file mode 100644 index 000000000000..9b8176aef854 --- /dev/null +++ b/patches/api/0321-System-prop-for-default-config-comment-parsing.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 30 Dec 2021 16:35:56 -0800 +Subject: [PATCH] System prop for default config comment parsing + +Allows for certain legacy plugins to continue to work without changing +by setting `Paper.parseYamlCommentsByDefault` to false + +diff --git a/src/main/java/org/bukkit/configuration/file/FileConfigurationOptions.java b/src/main/java/org/bukkit/configuration/file/FileConfigurationOptions.java +index 4bff5d18d9ae62c6c55869c66efc2bc481a0cc18..800a34710c2b85dc2a58f2e15ba910c7ee717c08 100644 +--- a/src/main/java/org/bukkit/configuration/file/FileConfigurationOptions.java ++++ b/src/main/java/org/bukkit/configuration/file/FileConfigurationOptions.java +@@ -15,7 +15,10 @@ import org.jetbrains.annotations.Nullable; + public class FileConfigurationOptions extends MemoryConfigurationOptions { + private List header = Collections.emptyList(); + private List footer = Collections.emptyList(); +- private boolean parseComments = true; ++ // Paper start - add system prop for comment parsing ++ private static final boolean PAPER_PARSE_COMMENTS_BY_DEFAULT = Boolean.parseBoolean(System.getProperty("Paper.parseYamlCommentsByDefault", "true")); ++ private boolean parseComments = PAPER_PARSE_COMMENTS_BY_DEFAULT; ++ // Paper end + + protected FileConfigurationOptions(@NotNull MemoryConfiguration configuration) { + super(configuration); diff --git a/patches/api/0352-Expose-vanilla-BiomeProvider-from-WorldInfo.patch b/patches/api/0322-Expose-vanilla-BiomeProvider-from-WorldInfo.patch similarity index 100% rename from patches/api/0352-Expose-vanilla-BiomeProvider-from-WorldInfo.patch rename to patches/api/0322-Expose-vanilla-BiomeProvider-from-WorldInfo.patch diff --git a/patches/api/0323-Add-BlockBreakBlockEvent.patch b/patches/api/0323-Add-BlockBreakBlockEvent.patch deleted file mode 100644 index dfd13b135501..000000000000 --- a/patches/api/0323-Add-BlockBreakBlockEvent.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 3 Jan 2021 17:58:25 -0800 -Subject: [PATCH] Add BlockBreakBlockEvent - - -diff --git a/src/main/java/io/papermc/paper/event/block/BlockBreakBlockEvent.java b/src/main/java/io/papermc/paper/event/block/BlockBreakBlockEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ac7a60403a9e51fc194f2cc92b0bd60d8879a661 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/block/BlockBreakBlockEvent.java -@@ -0,0 +1,59 @@ -+package io.papermc.paper.event.block; -+ -+import org.bukkit.block.Block; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.List; -+ -+/** -+ * Called when a block forces another block to break and drop items. -+ *

      -+ * Currently called for piston's and liquid flows. -+ */ -+public class BlockBreakBlockEvent extends BlockEvent { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private final List drops; -+ private final Block source; -+ -+ public BlockBreakBlockEvent(@NotNull Block block, @NotNull Block source, @NotNull List drops) { -+ super(block); -+ this.source = source; -+ this.drops = drops; -+ } -+ -+ /** -+ * Get the drops of this event -+ * -+ * @return the drops -+ */ -+ @NotNull -+ public List getDrops() { -+ return drops; -+ } -+ -+ /** -+ * Gets the block that cause this (e.g. a piston, or adjacent liquid) -+ * -+ * @return the source -+ */ -+ @NotNull -+ public Block getSource() { -+ return source; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} diff --git a/patches/api/0323-Multiple-Entries-with-Scoreboards.patch b/patches/api/0323-Multiple-Entries-with-Scoreboards.patch new file mode 100644 index 000000000000..a1e9b23e68e2 --- /dev/null +++ b/patches/api/0323-Multiple-Entries-with-Scoreboards.patch @@ -0,0 +1,128 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Tue, 21 Sep 2021 18:17:34 -0500 +Subject: [PATCH] Multiple Entries with Scoreboards + + +diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java +index c500de6ed19bdf732f7bedbedb19a4b37ca343f8..c34d9ab72928d5f58339025d717ec840a4d8cf2c 100644 +--- a/src/main/java/org/bukkit/scoreboard/Team.java ++++ b/src/main/java/org/bukkit/scoreboard/Team.java +@@ -309,6 +309,60 @@ public interface Team extends net.kyori.adventure.audience.ForwardingAudience { + */ + void addEntry(@NotNull String entry); + ++ // Paper start ++ /** ++ * This puts a collection of entities onto this team for the scoreboard which results in one ++ * packet for the updates rather than a packet-per-entity. ++ *

      ++ * Entities on other teams will be removed from their respective teams. ++ * ++ * @param entities the entities to add ++ * @throws IllegalArgumentException if entities are null ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ default void addEntities(@NotNull org.bukkit.entity.Entity @NotNull ...entities) { ++ this.addEntities(java.util.List.of(entities)); ++ } ++ ++ /** ++ * This puts a collection of entities onto this team for the scoreboard which results in one ++ * packet for the updates rather than a packet-per-entity. ++ *

      ++ * Entities on other teams will be removed from their respective teams. ++ * ++ * @param entities the entities to add ++ * @throws IllegalArgumentException if entities are null ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ void addEntities(@NotNull java.util.Collection entities) throws IllegalStateException, IllegalArgumentException; ++ ++ /** ++ * This puts a collection of entries onto this team for the scoreboard which results in one ++ * packet for the updates rather than a packet-per-entry. ++ *

      ++ * Entries on other teams will be removed from their respective teams. ++ * ++ * @param entries the entries to add ++ * @throws IllegalArgumentException if entries are null ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ default void addEntries(@NotNull String... entries) throws IllegalStateException, IllegalArgumentException { ++ this.addEntries(java.util.List.of(entries)); ++ } ++ ++ /** ++ * This puts a collection of entries onto this team for the scoreboard which results in one ++ * packet for the updates rather than a packet-per-entry. ++ *

      ++ * Entries on other teams will be removed from their respective teams. ++ * ++ * @param entries the entries to add ++ * @throws IllegalArgumentException if entries are null ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ void addEntries(@NotNull java.util.Collection entries) throws IllegalStateException, IllegalArgumentException; ++ // Paper end ++ + /** + * Removes the player from this team. + * +@@ -329,6 +383,56 @@ public interface Team extends net.kyori.adventure.audience.ForwardingAudience { + */ + boolean removeEntry(@NotNull String entry); + ++ // Paper start ++ /** ++ * Removes a collection of entities from this team which results in one ++ * packet for the updates rather than a packet-per-entity. ++ * ++ * @param entities the entries to remove ++ * @return if any of the entities were a part of this team ++ * @throws IllegalArgumentException if entities is null ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ default boolean removeEntities(@NotNull org.bukkit.entity.Entity @NotNull ... entities) throws IllegalStateException, IllegalArgumentException { ++ return this.removeEntities(java.util.List.of(entities)); ++ } ++ ++ /** ++ * Removes a collection of entities from this team which results in one ++ * packet for the updates rather than a packet-per-entity. ++ * ++ * @param entities the entries to remove ++ * @return if any of the entities were a part of this team ++ * @throws IllegalArgumentException if entities is null ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ boolean removeEntities(@NotNull java.util.Collection entities) throws IllegalStateException, IllegalArgumentException; ++ ++ /** ++ * Removes a collection of entries from this team which results in one ++ * packet for the updates rather than a packet-per-entry. ++ * ++ * @param entries the entries to remove ++ * @return if any of the entries were a part of this team ++ * @throws IllegalArgumentException if entries is null ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ default boolean removeEntries(@NotNull String... entries) throws IllegalStateException, IllegalArgumentException { ++ return this.removeEntries(java.util.List.of(entries)); ++ } ++ ++ /** ++ * Removes a collection of entries from this team which results in one ++ * packet for the updates rather than a packet-per-entry. ++ * ++ * @param entries the entries to remove ++ * @return if any of the entries were a part of this team ++ * @throws IllegalArgumentException if entries is null ++ * @throws IllegalStateException if this team has been unregistered ++ */ ++ boolean removeEntries(@NotNull java.util.Collection entries) throws IllegalStateException, IllegalArgumentException; ++ // Paper end ++ + /** + * Unregisters this team from the Scoreboard + * diff --git a/patches/api/0324-Warn-on-strange-EventHandler-return-types.patch b/patches/api/0324-Warn-on-strange-EventHandler-return-types.patch new file mode 100644 index 000000000000..c7807b823b91 --- /dev/null +++ b/patches/api/0324-Warn-on-strange-EventHandler-return-types.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Tue, 18 Jan 2022 11:07:54 -0700 +Subject: [PATCH] Warn on strange @EventHandler return types + + +diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java +index 9026e108ccd3a88aee1267ee275137befa646455..5fa52419f21d8e8b3d8f9aafd248b05774a28348 100644 +--- a/src/main/java/org/bukkit/plugin/EventExecutor.java ++++ b/src/main/java/org/bukkit/plugin/EventExecutor.java +@@ -51,6 +51,12 @@ public interface EventExecutor { + Preconditions.checkArgument(m.getParameterCount() != 0, "Incorrect number of arguments %s", m.getParameterCount()); + Preconditions.checkArgument(m.getParameterTypes()[0] == eventClass, "First parameter %s doesn't match event class %s", m.getParameterTypes()[0], eventClass); + ClassDefiner definer = ClassDefiner.getInstance(); ++ if (m.getReturnType() != Void.TYPE) { ++ final org.bukkit.plugin.java.JavaPlugin plugin = org.bukkit.plugin.java.JavaPlugin.getProvidingPlugin(m.getDeclaringClass()); ++ org.bukkit.Bukkit.getLogger().warning("@EventHandler method " + m.getDeclaringClass().getName() + (Modifier.isStatic(m.getModifiers()) ? '.' : '#') + m.getName() ++ + " returns non-void type " + m.getReturnType().getName() + ". This is unsupported behavior and will no longer work in a future version of Paper." ++ + " This should be reported to the developers of " + plugin.getPluginMeta().getDisplayName() + " (" + String.join(",", plugin.getPluginMeta().getAuthors()) + ')'); ++ } + if (Modifier.isStatic(m.getModifiers())) { + return new StaticMethodHandleEventExecutor(eventClass, m); + } else if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) { diff --git a/patches/api/0325-Multi-Block-Change-API.patch b/patches/api/0325-Multi-Block-Change-API.patch new file mode 100644 index 000000000000..5b0180c266bf --- /dev/null +++ b/patches/api/0325-Multi-Block-Change-API.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brody Beckwith +Date: Fri, 14 Jan 2022 00:40:42 -0500 +Subject: [PATCH] Multi Block Change API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 68c470b9504a8b731606a1d297de223235b55cb9..db3a1e9170aeada5fe738975124861d79e82e2d1 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -977,6 +977,29 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public void sendBlockDamage(@NotNull Location loc, float progress); + ++ // Paper start ++ /** ++ * Send multiple block changes. This fakes a multi block change packet for each ++ * chunk section that a block change occurs. This will not actually change the world in any way. ++ * ++ * @param blockChanges A map of the positions you want to change to their new block data ++ */ ++ void sendMultiBlockChange(@NotNull Map blockChanges); ++ ++ /** ++ * Send multiple block changes. This fakes a multi block change packet for each ++ * chunk section that a block change occurs. This will not actually change the world in any way. ++ * ++ * @param blockChanges A map of the positions you want to change to their new block data ++ * @param suppressLightUpdates Whether to suppress light updates or not ++ * @deprecated suppressLightUpdates is no longer available in 1.20+, use {@link #sendMultiBlockChange(Map)} ++ */ ++ @Deprecated ++ default void sendMultiBlockChange(@NotNull Map blockChanges, boolean suppressLightUpdates) { ++ this.sendMultiBlockChange(blockChanges); ++ } ++ // Paper end ++ + /** + * Send block damage. This fakes block break progress at a certain location + * sourced by the provided entity. This will not actually change the block's diff --git a/patches/api/0325-Option-to-prevent-NBT-copy-in-smithing-recipes.patch b/patches/api/0325-Option-to-prevent-NBT-copy-in-smithing-recipes.patch deleted file mode 100644 index 0a0b5515e3f7..000000000000 --- a/patches/api/0325-Option-to-prevent-NBT-copy-in-smithing-recipes.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 26 Sep 2021 12:57:35 -0700 -Subject: [PATCH] Option to prevent NBT copy in smithing recipes - - -diff --git a/src/main/java/org/bukkit/inventory/SmithingRecipe.java b/src/main/java/org/bukkit/inventory/SmithingRecipe.java -index af04071d37e70b8cc9837d57477c8493be8afb9f..00000f1399b053bb3c7b6d4792559b630d414b81 100644 ---- a/src/main/java/org/bukkit/inventory/SmithingRecipe.java -+++ b/src/main/java/org/bukkit/inventory/SmithingRecipe.java -@@ -13,6 +13,7 @@ public class SmithingRecipe implements Recipe, Keyed { - private final ItemStack result; - private final RecipeChoice base; - private final RecipeChoice addition; -+ private final boolean copyNbt; // Paper - - /** - * Create a smithing recipe to produce the specified result ItemStack. -@@ -23,6 +24,21 @@ public class SmithingRecipe implements Recipe, Keyed { - * @param addition The addition ingredient - */ - public SmithingRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result, @NotNull RecipeChoice base, @NotNull RecipeChoice addition) { -+ // Paper start -+ this(key, result, base, addition, true); -+ } -+ /** -+ * Create a smithing recipe to produce the specified result ItemStack. -+ * -+ * @param key The unique recipe key -+ * @param result The item you want the recipe to create. -+ * @param base The base ingredient -+ * @param addition The addition ingredient -+ * @param copyNbt whether to copy the nbt from the input base item to the output -+ */ -+ public SmithingRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result, @NotNull RecipeChoice base, @NotNull RecipeChoice addition, boolean copyNbt) { -+ this.copyNbt = copyNbt; -+ // Paper end - this.key = key; - this.result = result; - this.base = base; -@@ -60,4 +76,15 @@ public class SmithingRecipe implements Recipe, Keyed { - public NamespacedKey getKey() { - return this.key; - } -+ -+ // Paper start -+ /** -+ * Whether or not to copy the NBT of the input base item to the output. -+ * -+ * @return true to copy the NBT (default for vanilla smithing recipes) -+ */ -+ public boolean willCopyNbt() { -+ return copyNbt; -+ } -+ // Paper end - } diff --git a/patches/api/0326-Fix-NotePlayEvent.patch b/patches/api/0326-Fix-NotePlayEvent.patch new file mode 100644 index 000000000000..0159992c04af --- /dev/null +++ b/patches/api/0326-Fix-NotePlayEvent.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kieran Wallbanks +Date: Mon, 21 Jun 2021 12:33:45 +0100 +Subject: [PATCH] Fix NotePlayEvent + + +diff --git a/src/main/java/org/bukkit/event/block/NotePlayEvent.java b/src/main/java/org/bukkit/event/block/NotePlayEvent.java +index c9ecbebbc27f27734d35f496783706f702dccb29..ea7cb75ba3ecbe40e0390fd5568db77de56c4f16 100644 +--- a/src/main/java/org/bukkit/event/block/NotePlayEvent.java ++++ b/src/main/java/org/bukkit/event/block/NotePlayEvent.java +@@ -56,11 +56,13 @@ public class NotePlayEvent extends BlockEvent implements Cancellable { + + /** + * Overrides the {@link Instrument} to be used. ++ *

      ++ * Only works when the note block isn't under a player head. ++ * For this specific case the 'note_block_sound' property of the ++ * player head state takes the priority. + * + * @param instrument the Instrument. Has no effect if null. +- * @deprecated no effect on newer Minecraft versions + */ +- @Deprecated(since = "1.13") + public void setInstrument(@NotNull Instrument instrument) { + if (instrument != null) { + this.instrument = instrument; +@@ -71,9 +73,7 @@ public class NotePlayEvent extends BlockEvent implements Cancellable { + * Overrides the {@link Note} to be played. + * + * @param note the Note. Has no effect if null. +- * @deprecated no effect on newer Minecraft versions + */ +- @Deprecated(since = "1.13") + public void setNote(@NotNull Note note) { + if (note != null) { + this.note = note; diff --git a/patches/api/0326-More-CommandBlock-API.patch b/patches/api/0326-More-CommandBlock-API.patch deleted file mode 100644 index 242270eb1296..000000000000 --- a/patches/api/0326-More-CommandBlock-API.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 28 May 2021 21:47:39 -0700 -Subject: [PATCH] More CommandBlock API - - -diff --git a/src/main/java/io/papermc/paper/command/CommandBlockHolder.java b/src/main/java/io/papermc/paper/command/CommandBlockHolder.java -new file mode 100644 -index 0000000000000000000000000000000000000000..09e57f495e3cbf3c6f434d12ab34830862faeb88 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/CommandBlockHolder.java -@@ -0,0 +1,58 @@ -+package io.papermc.paper.command; -+ -+import net.kyori.adventure.text.Component; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public interface CommandBlockHolder { -+ -+ /** -+ * Gets the command that this CommandBlock will run when powered. -+ * This will never return null. If the CommandBlock does not have a -+ * command, an empty String will be returned instead. -+ * -+ * @return Command that this CommandBlock will run when activated. -+ */ -+ @NotNull -+ String getCommand(); -+ -+ /** -+ * Sets the command that this CommandBlock will run when powered. -+ * Setting the command to null is the same as setting it to an empty -+ * String. -+ * -+ * @param command Command that this CommandBlock will run when activated. -+ */ -+ void setCommand(@Nullable String command); -+ -+ /** -+ * Gets the last output from this command block. -+ * -+ * @return the last output -+ */ -+ @NotNull -+ Component lastOutput(); -+ -+ /** -+ * Sets the last output from this command block. -+ * -+ * @param lastOutput the last output -+ */ -+ void lastOutput(@Nullable Component lastOutput); -+ -+ /** -+ * Gets the success count from this command block. -+ * @see Command_Block#Success_count -+ * -+ * @return the success count -+ */ -+ int getSuccessCount(); -+ -+ /** -+ * Sets the success count from this command block. -+ * @see Command_Block#Success_count -+ * -+ * @param successCount the success count -+ */ -+ void setSuccessCount(int successCount); -+} -diff --git a/src/main/java/org/bukkit/block/CommandBlock.java b/src/main/java/org/bukkit/block/CommandBlock.java -index 73dce588d1f7a5048300073bf8c2b14d6da1e857..d63da691fb8cfa04bb699adb2eb55278e8b76200 100644 ---- a/src/main/java/org/bukkit/block/CommandBlock.java -+++ b/src/main/java/org/bukkit/block/CommandBlock.java -@@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable; - /** - * Represents a captured state of a command block. - */ --public interface CommandBlock extends TileState { -+public interface CommandBlock extends TileState, io.papermc.paper.command.CommandBlockHolder { // Paper - - /** - * Gets the command that this CommandBlock will run when powered. -diff --git a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java -index 91cab8b13d5bba34007f124838b32a1df58c5ac7..6a6021ad3a0e6aaf51f5144fa126e81bada9cfcf 100644 ---- a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java -+++ b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java -@@ -4,7 +4,7 @@ import org.bukkit.entity.Minecart; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; - --public interface CommandMinecart extends Minecart { -+public interface CommandMinecart extends Minecart, io.papermc.paper.command.CommandBlockHolder { // Paper - - /** - * Gets the command that this CommandMinecart will run when activated. diff --git a/patches/api/0327-Fix-plugin-provides-load-order.patch b/patches/api/0327-Fix-plugin-provides-load-order.patch deleted file mode 100644 index 3e24fb59ba3b..000000000000 --- a/patches/api/0327-Fix-plugin-provides-load-order.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Fri, 1 Oct 2021 09:47:00 +0200 -Subject: [PATCH] Fix plugin provides load order - -Fixes https://hub.spigotmc.org/jira/browse/SPIGOT-6740 - -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index 35aa6dff52944019510f16180e36da0088654432..34c3df7570479d4f045897fe4e26dfa3f27479c4 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -276,6 +276,7 @@ public final class SimplePluginManager implements PluginManager { - // Paper end - missingDependency = false; - pluginIterator.remove(); -+ pluginsProvided.values().removeIf(s -> s.equals(plugin)); // Paper - remove provided plugins - softDependencies.remove(plugin); - dependencies.remove(plugin); - -@@ -309,6 +310,7 @@ public final class SimplePluginManager implements PluginManager { - // We're clear to load, no more soft or hard dependencies left - File file = plugins.get(plugin); - pluginIterator.remove(); -+ pluginsProvided.values().removeIf(s -> s.equals(plugin)); // Paper - remove provided plugins - missingDependency = false; - - try { diff --git a/patches/api/0327-Freeze-Tick-Lock-API.patch b/patches/api/0327-Freeze-Tick-Lock-API.patch new file mode 100644 index 000000000000..7e573b5966b2 --- /dev/null +++ b/patches/api/0327-Freeze-Tick-Lock-API.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 26 Dec 2021 20:27:49 -0500 +Subject: [PATCH] Freeze Tick Lock API + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 97b8ac9ae8ebe0f074f5f1f806d9415b8122400c..fe3f59390ee45a289ae6dbb398ce7954fab717d5 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -327,6 +327,26 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + boolean hasNoPhysics(); + // Paper end - missing entity api + ++ // Paper start - Freeze Tick Lock API ++ /** ++ * Gets if the entity currently has its freeze ticks locked ++ * to a set amount. ++ *

      ++ * This is only set by plugins ++ * ++ * @return locked or not ++ */ ++ boolean isFreezeTickingLocked(); ++ ++ /** ++ * Sets if the entity currently has its freeze ticks locked, ++ * preventing default vanilla freeze tick modification. ++ * ++ * @param locked prevent vanilla modification or not ++ */ ++ void lockFreezeTicks(boolean locked); ++ // Paper end - Freeze Tick Lock API ++ + /** + * Mark the entity's removal. + * diff --git a/patches/api/0328-Add-missing-team-sidebar-display-slots.patch b/patches/api/0328-Add-missing-team-sidebar-display-slots.patch deleted file mode 100644 index 1d400fa49eec..000000000000 --- a/patches/api/0328-Add-missing-team-sidebar-display-slots.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 1 Oct 2021 08:04:43 -0700 -Subject: [PATCH] Add missing team sidebar display slots - - -diff --git a/src/main/java/org/bukkit/scoreboard/DisplaySlot.java b/src/main/java/org/bukkit/scoreboard/DisplaySlot.java -index 5d58a18b3625fd01ea34969200edc3bc80cbb587..fe7d0a19f970ac5b4e0c4bef4ff7c4ceae60bb86 100644 ---- a/src/main/java/org/bukkit/scoreboard/DisplaySlot.java -+++ b/src/main/java/org/bukkit/scoreboard/DisplaySlot.java -@@ -1,10 +1,55 @@ - package org.bukkit.scoreboard; - -+import net.kyori.adventure.text.format.NamedTextColor; // Paper - /** - * Locations for displaying objectives to the player - */ - public enum DisplaySlot { -- BELOW_NAME, -- PLAYER_LIST, -- SIDEBAR; -+ // Paper start -+ BELOW_NAME("belowName"), -+ PLAYER_LIST("list"), -+ SIDEBAR("sidebar"), -+ SIDEBAR_TEAM_BLACK(NamedTextColor.BLACK), -+ SIDEBAR_TEAM_DARK_BLUE(NamedTextColor.DARK_BLUE), -+ SIDEBAR_TEAM_DARK_GREEN(NamedTextColor.DARK_GREEN), -+ SIDEBAR_TEAM_DARK_AQUA(NamedTextColor.DARK_AQUA), -+ SIDEBAR_TEAM_DARK_RED(NamedTextColor.DARK_RED), -+ SIDEBAR_TEAM_DARK_PURPLE(NamedTextColor.DARK_PURPLE), -+ SIDEBAR_TEAM_GOLD(NamedTextColor.GOLD), -+ SIDEBAR_TEAM_GRAY(NamedTextColor.GRAY), -+ SIDEBAR_TEAM_DARK_GRAY(NamedTextColor.DARK_GRAY), -+ SIDEBAR_TEAM_BLUE(NamedTextColor.BLUE), -+ SIDEBAR_TEAM_GREEN(NamedTextColor.GREEN), -+ SIDEBAR_TEAM_AQUA(NamedTextColor.AQUA), -+ SIDEBAR_TEAM_RED(NamedTextColor.RED), -+ SIDEBAR_TEAM_LIGHT_PURPLE(NamedTextColor.LIGHT_PURPLE), -+ SIDEBAR_TEAM_YELLOW(NamedTextColor.YELLOW), -+ SIDEBAR_TEAM_WHITE(NamedTextColor.WHITE); -+ -+ public static final net.kyori.adventure.util.Index NAMES = net.kyori.adventure.util.Index.create(DisplaySlot.class, DisplaySlot::getId); -+ -+ private final String id; -+ -+ DisplaySlot(@org.jetbrains.annotations.NotNull String id) { -+ this.id = id; -+ } -+ -+ DisplaySlot(@org.jetbrains.annotations.NotNull NamedTextColor color) { -+ this.id = "sidebar.team." + color; -+ } -+ -+ /** -+ * Get the string id of this display slot. -+ * -+ * @return the string id -+ */ -+ public @org.jetbrains.annotations.NotNull String getId() { -+ return id; -+ } -+ -+ @Override -+ public String toString() { -+ return this.id; -+ } -+ // Paper end - } diff --git a/patches/api/0328-Dolphin-API.patch b/patches/api/0328-Dolphin-API.patch new file mode 100644 index 000000000000..8c3706b8706c --- /dev/null +++ b/patches/api/0328-Dolphin-API.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Tue, 7 Dec 2021 19:34:11 -0500 +Subject: [PATCH] Dolphin API + + +diff --git a/src/main/java/org/bukkit/entity/Dolphin.java b/src/main/java/org/bukkit/entity/Dolphin.java +index fcf09afd38277180aa299703000e46dd2482c372..d3d3f8b20769eec65a81d9a59195625cb2be8579 100644 +--- a/src/main/java/org/bukkit/entity/Dolphin.java ++++ b/src/main/java/org/bukkit/entity/Dolphin.java +@@ -1,3 +1,52 @@ + package org.bukkit.entity; + +-public interface Dolphin extends Ageable, WaterMob { } ++import org.bukkit.Location; ++ ++public interface Dolphin extends Ageable, WaterMob { // Paper start - Dolphin API ++ ++ /** ++ * Gets the moistness level of this dolphin ++ */ ++ int getMoistness(); ++ ++ /** ++ * Sets the moistness of this dolphin, once this is less than 0 the dolphin will start to take damage. ++ * ++ * @param moistness moistness level ++ */ ++ void setMoistness(int moistness); ++ ++ /** ++ * Sets if this dolphin was fed a fish. ++ * ++ * @param hasFish has a fish ++ */ ++ void setHasFish(boolean hasFish); ++ ++ /** ++ * Gets if this dolphin has a fish. ++ * ++ * @return has a fish ++ */ ++ boolean hasFish(); ++ ++ /** ++ * Gets the treasure location this dolphin tries to guide players to. ++ *

      ++ * This value is calculated if the player has fed the dolphin a fish, and it tries to start the {@link com.destroystokyo.paper.entity.ai.VanillaGoal#DOLPHIN_SWIM_TO_TREASURE} goal. ++ * ++ * @return calculated closest treasure location ++ */ ++ @org.jetbrains.annotations.NotNull ++ Location getTreasureLocation(); ++ ++ /** ++ * Sets the treasure location that this dolphin will try to lead the player to. ++ * This only has an effect if the dolphin is currently leading a player, as this value is recalculated next time it leads a player. ++ *

      ++ * The world of the location does not matter, as the dolphin will always use the world it is currently in. ++ * ++ * @param location location to guide to ++ */ ++ void setTreasureLocation(@org.jetbrains.annotations.NotNull Location location); ++} // Paper end - Dolphin API diff --git a/patches/api/0329-More-PotionEffectType-API.patch b/patches/api/0329-More-PotionEffectType-API.patch new file mode 100644 index 000000000000..736dc6f9a86c --- /dev/null +++ b/patches/api/0329-More-PotionEffectType-API.patch @@ -0,0 +1,143 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 27 May 2021 21:58:33 -0700 +Subject: [PATCH] More PotionEffectType API + + +diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java +index d03bdf6617ce66950e335f0afb52c19b2e2a14e2..b2bd12736d08fe72128142af4ca2022da8309f6d 100644 +--- a/src/main/java/org/bukkit/Registry.java ++++ b/src/main/java/org/bukkit/Registry.java +@@ -367,6 +367,15 @@ public interface Registry extends Iterable { + * @see GameEvent + */ + Registry GAME_EVENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.GAME_EVENT); // Paper ++ ++ // Paper start - potion effect type registry ++ /** ++ * Potion effect types. ++ * ++ * @see org.bukkit.potion.PotionEffectType ++ */ ++ Registry POTION_EFFECT_TYPE = EFFECT; ++ // Paper end - potion effect type registry + /** + * Get the object by its key. + * +diff --git a/src/main/java/org/bukkit/potion/PotionEffectType.java b/src/main/java/org/bukkit/potion/PotionEffectType.java +index 6375eed0ef4f8e897a00b4f77fb45b354888e74e..5f32728fad44c3c5f3f5382b0ad6fd9b1ef5e0fd 100644 +--- a/src/main/java/org/bukkit/potion/PotionEffectType.java ++++ b/src/main/java/org/bukkit/potion/PotionEffectType.java +@@ -17,7 +17,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a type of potion and its effect on an entity. + */ +-public abstract class PotionEffectType implements Keyed, Translatable { ++public abstract class PotionEffectType implements Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - implement Translatable + private static final BiMap ID_MAP = HashBiMap.create(); + + /** +@@ -360,4 +360,57 @@ public abstract class PotionEffectType implements Keyed, Translatable { + public static PotionEffectType[] values() { + return Lists.newArrayList(Registry.EFFECT).toArray(new PotionEffectType[0]); + } ++ ++ // Paper start ++ /** ++ * Gets the effect attributes in an immutable map. ++ * ++ * @return the attribute map ++ */ ++ public abstract @NotNull java.util.Map getEffectAttributes(); ++ ++ /** ++ * Gets the true modifier amount based on the effect amplifier. ++ * ++ * @param attribute the attribute ++ * @param effectAmplifier the effect amplifier (0 indexed) ++ * @return the modifier amount ++ * @throws IllegalArgumentException if the supplied attribute is not present in the map from {@link #getEffectAttributes()} ++ */ ++ public abstract double getAttributeModifierAmount(@NotNull org.bukkit.attribute.Attribute attribute, int effectAmplifier); ++ ++ /** ++ * Gets the category of this effect ++ * ++ * @return the category ++ */ ++ public abstract @NotNull PotionEffectType.Category getEffectCategory(); ++ ++ /** ++ * Category of {@link PotionEffectType}s ++ */ ++ public enum Category { ++ ++ BENEFICIAL(net.kyori.adventure.text.format.NamedTextColor.BLUE), ++ HARMFUL(net.kyori.adventure.text.format.NamedTextColor.RED), ++ NEUTRAL(net.kyori.adventure.text.format.NamedTextColor.BLUE); ++ ++ private final net.kyori.adventure.text.format.TextColor color; ++ ++ Category(net.kyori.adventure.text.format.TextColor color) { ++ this.color = color; ++ } ++ ++ /** ++ * Gets the text color used when displaying potions ++ * of this category. ++ * ++ * @return the text color ++ */ ++ @NotNull ++ public net.kyori.adventure.text.format.TextColor getColor() { ++ return color; ++ } ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java b/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java +index 6861d1cfcedb6d72c2c425bad205342aac8e33a1..7acdeb9054e128c452ea8610d8b39a35627c56bf 100644 +--- a/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java ++++ b/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java +@@ -19,4 +19,41 @@ public abstract class PotionEffectTypeWrapper extends PotionEffectType { + public PotionEffectType getType() { + return this; + } ++ ++ @Override ++ public boolean isInstant() { ++ return getType().isInstant(); ++ } ++ ++ @NotNull ++ @Override ++ public org.bukkit.Color getColor() { ++ return getType().getColor(); ++ } ++ // Paper start ++ @Override ++ public @NotNull org.bukkit.NamespacedKey getKey() { ++ return this.getType().getKey(); ++ } ++ ++ @Override ++ public @NotNull java.util.Map getEffectAttributes() { ++ return this.getType().getEffectAttributes(); ++ } ++ ++ @Override ++ public double getAttributeModifierAmount(@NotNull org.bukkit.attribute.Attribute attribute, int effectAmplifier) { ++ return this.getType().getAttributeModifierAmount(attribute, effectAmplifier); ++ } ++ ++ @Override ++ public @NotNull PotionEffectType.Category getEffectCategory() { ++ return this.getType().getEffectCategory(); ++ } ++ ++ @Override ++ public @NotNull String translationKey() { ++ return this.getType().translationKey(); ++ } ++ // Paper end + } diff --git a/patches/api/0330-API-for-creating-command-sender-which-forwards-feedb.patch b/patches/api/0330-API-for-creating-command-sender-which-forwards-feedb.patch new file mode 100644 index 000000000000..5c606e2d0b44 --- /dev/null +++ b/patches/api/0330-API-for-creating-command-sender-which-forwards-feedb.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Tue, 1 Feb 2022 15:51:44 -0700 +Subject: [PATCH] API for creating command sender which forwards feedback + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 46b678da746fb8ff65e77811499ee341093a65e8..a9d1a9a5223148ea134ed146d059ec9edb922f03 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -1595,6 +1595,20 @@ public final class Bukkit { + return server.getConsoleSender(); + } + ++ // Paper start ++ /** ++ * Creates a special {@link CommandSender} which redirects command feedback (in the form of chat messages) to the ++ * specified listener. The returned sender will have the same effective permissions as {@link #getConsoleSender()}. ++ * ++ * @param feedback feedback listener ++ * @return a command sender ++ */ ++ @NotNull ++ public static CommandSender createCommandSender(final @NotNull java.util.function.Consumer feedback) { ++ return server.createCommandSender(feedback); ++ } ++ // Paper end ++ + /** + * Gets the folder that contains all of the various {@link World}s. + * +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 5ca4543587043f964175435654b9e00c9dadffd5..06cc09298abcefaacd7a6987c32e5bd86653e719 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1349,6 +1349,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @NotNull + public ConsoleCommandSender getConsoleSender(); + ++ // Paper start ++ /** ++ * Creates a special {@link CommandSender} which redirects command feedback (in the form of chat messages) to the ++ * specified listener. The returned sender will have the same effective permissions as {@link #getConsoleSender()}. ++ * ++ * @param feedback feedback listener ++ * @return a command sender ++ */ ++ @NotNull ++ public CommandSender createCommandSender(final @NotNull java.util.function.Consumer feedback); ++ // Paper end ++ + /** + * Gets the folder that contains all of the various {@link World}s. + * diff --git a/patches/api/0330-Add-methods-to-find-targets-for-lightning-strikes.patch b/patches/api/0330-Add-methods-to-find-targets-for-lightning-strikes.patch deleted file mode 100644 index 90130a24dad8..000000000000 --- a/patches/api/0330-Add-methods-to-find-targets-for-lightning-strikes.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jakub Zacek -Date: Mon, 4 Oct 2021 08:29:36 +0200 -Subject: [PATCH] Add methods to find targets for lightning strikes - - -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 8b88146908288e7290952a6d8a9db1dbb3307f66..e47d0663d42fa38e5c6cd2611f99e23f8187c28f 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -749,6 +749,37 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - @NotNull - public LightningStrike strikeLightningEffect(@NotNull Location loc); - -+ // Paper start -+ /** -+ * Finds the location of the nearest unobstructed Lightning Rod in a 128-block -+ * radius around the given location. Returns {@code null} if no Lightning Rod is found. -+ * -+ *

      Note: To activate a Lightning Rod, the position one block above it must be struck by lightning.

      -+ * -+ * @param location {@link Location} to search for Lightning Rod around -+ * @return {@link Location} of Lightning Rod or {@code null} -+ */ -+ @Nullable -+ public Location findLightningRod(@NotNull Location location); -+ -+ /** -+ * Finds a target {@link Location} for lightning to strike. -+ *

      It selects from (in the following order):

      -+ *
        -+ *
      1. the block above the nearest Lightning Rod, found using {@link World#findLightningRod(Location)}
      2. -+ *
      3. a random {@link LivingEntity} that can see the sky in a 6x6 cuboid -+ * around input X/Z coordinates. Y ranges from the highest motion-blocking -+ * block at the input X/Z - 3 to the height limit + 3
      4. -+ *
      -+ *

      Returns {@code null} if no target is found.

      -+ * -+ * @param location {@link Location} to search for target around -+ * @return lightning target or {@code null} -+ */ -+ @Nullable -+ public Location findLightningTarget(@NotNull Location location); -+ // Paper end -+ - /** - * Get a list of all entities in this World - * diff --git a/patches/api/0331-Get-entity-default-attributes.patch b/patches/api/0331-Get-entity-default-attributes.patch deleted file mode 100644 index 72795452c039..000000000000 --- a/patches/api/0331-Get-entity-default-attributes.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 20 Aug 2021 13:03:55 -0700 -Subject: [PATCH] Get entity default attributes - - -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index a3045b63c4e63f8eac902beb0f48367a5e3e5d20..0a9a50251093e1ea605a748eb8d899f34b26ef7b 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -208,5 +208,22 @@ public interface UnsafeValues { - * @return the server's protocol version - */ - int getProtocolVersion(); -+ -+ /** -+ * Checks if the entity represented by the namespaced key has default attributes. -+ * -+ * @param entityKey the entity's key -+ * @return true if it has default attributes -+ */ -+ boolean hasDefaultEntityAttributes(@org.jetbrains.annotations.NotNull NamespacedKey entityKey); -+ -+ /** -+ * Gets the default attributes for the entity represented by the namespaced key. -+ * -+ * @param entityKey the entity's key -+ * @return an unmodifiable instance of Attributable for reading default attributes. -+ * @throws IllegalArgumentException if the entity does not exist of have default attributes (use {@link #hasDefaultEntityAttributes(NamespacedKey)} first) -+ */ -+ @org.jetbrains.annotations.NotNull org.bukkit.attribute.Attributable getDefaultEntityAttributes(@org.jetbrains.annotations.NotNull NamespacedKey entityKey); - // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java -index 032a252688b6dbefb05a0d4f91791e102bbae0cd..4aa2d483b706fbf6ba0dc5126de74ee532e12382 100644 ---- a/src/main/java/org/bukkit/entity/EntityType.java -+++ b/src/main/java/org/bukkit/entity/EntityType.java -@@ -446,5 +446,24 @@ public enum EntityType implements Keyed, net.kyori.adventure.translation.Transla - Preconditions.checkArgument(this != UNKNOWN, "UNKNOWN entities do not have translation keys"); - return org.bukkit.Bukkit.getUnsafe().getTranslationKey(this); - } -+ -+ /** -+ * Checks if the entity has default attributes. -+ * -+ * @return true if it has default attributes -+ */ -+ public boolean hasDefaultAttributes() { -+ return org.bukkit.Bukkit.getUnsafe().hasDefaultEntityAttributes(this.key); -+ } -+ -+ /** -+ * Gets the default attributes for the entity. -+ * -+ * @return an unmodifiable instance of Attributable for reading default attributes. -+ * @throws IllegalArgumentException if the entity does not exist of have default attributes (use {@link #hasDefaultAttributes()} first) -+ */ -+ public @NotNull org.bukkit.attribute.Attributable getDefaultAttributes() { -+ return org.bukkit.Bukkit.getUnsafe().getDefaultEntityAttributes(this.key); -+ } - // Paper end - } diff --git a/patches/api/0331-Implement-regenerateChunk.patch b/patches/api/0331-Implement-regenerateChunk.patch new file mode 100644 index 000000000000..ba17a9e629d4 --- /dev/null +++ b/patches/api/0331-Implement-regenerateChunk.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Sat, 5 Feb 2022 20:25:28 +0100 +Subject: [PATCH] Implement regenerateChunk + + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index a8939bb5815fbc2926907bb3e8921f86255abd93..0f01e87c1f09f2291d12eaac7f12b32ca543c82f 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -405,8 +405,8 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + * @return Whether the chunk was actually regenerated + * + * @deprecated regenerating a single chunk is not likely to produce the same +- * chunk as before as terrain decoration may be spread across chunks. Use of +- * this method should be avoided as it is known to produce buggy results. ++ * chunk as before as terrain decoration may be spread across chunks. It may ++ * or may not change blocks in the adjacent chunks as well. + */ + @Deprecated(since = "1.13") + public boolean regenerateChunk(int x, int z); diff --git a/patches/api/0332-Add-GameEvent-tags.patch b/patches/api/0332-Add-GameEvent-tags.patch new file mode 100644 index 000000000000..961174f6e825 --- /dev/null +++ b/patches/api/0332-Add-GameEvent-tags.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 18 Dec 2021 10:34:21 -0800 +Subject: [PATCH] Add GameEvent tags + + +diff --git a/src/main/java/org/bukkit/Tag.java b/src/main/java/org/bukkit/Tag.java +index 8420fb1c6059ea9f782a47d18c465ba515765085..961a36e03df968898590c95573cee04083988e32 100644 +--- a/src/main/java/org/bukkit/Tag.java ++++ b/src/main/java/org/bukkit/Tag.java +@@ -1427,6 +1427,25 @@ public interface Tag extends Keyed { + */ + Tag ENTITY_TYPES_REDIRECTABLE_PROJECTILE = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("redirectable_projectile"), EntityType.class); + ++ // Paper start ++ String REGISTRY_GAME_EVENTS = "game_events"; ++ ++ /** ++ * Tag for game events that trigger sculk sensors ++ */ ++ Tag GAME_EVENT_VIBRATIONS = Bukkit.getTag(REGISTRY_GAME_EVENTS, NamespacedKey.minecraft("vibrations"), GameEvent.class); ++ ++ /** ++ * Tag for game events that are ignored if the entity is sneaking ++ */ ++ Tag GAME_EVENT_IGNORE_VIBRATIONS_SNEAKING = Bukkit.getTag(REGISTRY_GAME_EVENTS, NamespacedKey.minecraft("ignore_vibrations_sneaking"), GameEvent.class); ++ ++ /** ++ * Tag for game events that an allay can listen to ++ */ ++ Tag GAME_EVENT_ALLAY_CAN_LISTEN = Bukkit.getTag(REGISTRY_GAME_EVENTS, NamespacedKey.minecraft("allay_can_listen"), GameEvent.class); ++ // Paper end ++ + /** + * Returns whether or not this tag has an entry for the specified item. + * diff --git a/patches/api/0332-Left-handed-API.patch b/patches/api/0332-Left-handed-API.patch deleted file mode 100644 index c6c9f1b39f8b..000000000000 --- a/patches/api/0332-Left-handed-API.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 14 Oct 2021 12:36:46 -0500 -Subject: [PATCH] Left handed API - - -diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java -index 07bedbc15ba2463d3c629ae68d229286d4033f79..984ad873f36c3dcc73703eb6902c4eab5f1e72b6 100644 ---- a/src/main/java/org/bukkit/entity/Mob.java -+++ b/src/main/java/org/bukkit/entity/Mob.java -@@ -148,4 +148,20 @@ public interface Mob extends LivingEntity, Lootable { - * @return whether the mob is aware - */ - public boolean isAware(); -+ -+ // Paper start -+ /** -+ * Check if Mob is left-handed -+ * -+ * @return True if left-handed -+ */ -+ public boolean isLeftHanded(); -+ -+ /** -+ * Set if Mob is left-handed -+ * -+ * @param leftHanded True if left-handed -+ */ -+ public void setLeftHanded(boolean leftHanded); -+ // Paper end - } diff --git a/patches/api/0333-Add-advancement-display-API.patch b/patches/api/0333-Add-advancement-display-API.patch deleted file mode 100644 index e335bdcf9667..000000000000 --- a/patches/api/0333-Add-advancement-display-API.patch +++ /dev/null @@ -1,248 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: syldium -Date: Fri, 9 Jul 2021 18:49:40 +0200 -Subject: [PATCH] Add advancement display API - - -diff --git a/src/main/java/io/papermc/paper/advancement/AdvancementDisplay.java b/src/main/java/io/papermc/paper/advancement/AdvancementDisplay.java -new file mode 100644 -index 0000000000000000000000000000000000000000..67341bb70762a2326030abd2548372b92474f544 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/advancement/AdvancementDisplay.java -@@ -0,0 +1,156 @@ -+package io.papermc.paper.advancement; -+ -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.format.TextColor; -+import net.kyori.adventure.translation.Translatable; -+import net.kyori.adventure.util.Index; -+import org.bukkit.NamespacedKey; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Describes the display of an advancement. -+ *

      -+ * The display is used in the chat, in the toast messages and the advancements -+ * screen. -+ */ -+public interface AdvancementDisplay { -+ -+ /** -+ * Gets the {@link Frame}. -+ *

      -+ * This defines the appearance of the tile in the advancements screen and -+ * the text when it's completed. -+ * -+ * @return the frame type -+ */ -+ @NotNull -+ Frame frame(); -+ -+ /** -+ * Gets the advancement title. -+ * -+ * @return the title -+ */ -+ @NotNull -+ Component title(); -+ -+ /** -+ * Gets the description. -+ * -+ * @return the description -+ */ -+ @NotNull -+ Component description(); -+ -+ /** -+ * Gets the icon shown in the frame in the advancements screen. -+ * -+ * @return a copy of the icon -+ */ -+ @NotNull -+ ItemStack icon(); -+ -+ /** -+ * Gets whether a toast should be displayed. -+ *

      -+ * A toast is a notification that will be displayed in the top right corner -+ * of the screen. -+ * -+ * @return {@code true} if a toast should be shown -+ */ -+ boolean doesShowToast(); -+ -+ /** -+ * Gets whether a message should be sent in the chat. -+ * -+ * @return {@code true} if a message should be sent -+ * @see org.bukkit.event.player.PlayerAdvancementDoneEvent#message() to edit -+ * the message -+ */ -+ boolean doesAnnounceToChat(); -+ -+ /** -+ * Gets whether this advancement is hidden. -+ *

      -+ * Hidden advancements cannot be viewed by the player until they have been -+ * unlocked. -+ * -+ * @return {@code true} if hidden -+ */ -+ boolean isHidden(); -+ -+ /** -+ * Gets the texture displayed behind the advancement tree when selected. -+ *

      -+ * This only affects root advancements without any parent. If the background -+ * is not specified or doesn't exist, the tab background will be the missing -+ * texture. -+ * -+ * @return the background texture path -+ */ -+ @Nullable -+ NamespacedKey backgroundPath(); -+ -+ /** -+ * Defines how the {@link #icon()} appears in the advancements screen and -+ * the color used with the {@link #title() advancement name}. -+ */ -+ enum Frame implements Translatable { -+ -+ /** -+ * "Challenge complete" advancement. -+ *

      -+ * The client will play the {@code ui.toast.challenge_complete} sound -+ * when the challenge is completed and the toast is shown. -+ */ -+ CHALLENGE("challenge", NamedTextColor.DARK_PURPLE), -+ -+ /** -+ * "Goal reached" advancement. -+ */ -+ GOAL("goal", NamedTextColor.GREEN), -+ -+ /** -+ * "Advancement made" advancement. -+ */ -+ TASK("task", NamedTextColor.GREEN); -+ -+ /** -+ * The name map. -+ */ -+ public static final Index NAMES = Index.create(Frame.class, frame -> frame.name); -+ private final String name; -+ private final TextColor color; -+ -+ Frame(String name, TextColor color) { -+ this.name = name; -+ this.color = color; -+ } -+ -+ /** -+ * Gets the {@link TextColor} used for the advancement name. -+ * -+ * @return the text color -+ */ -+ @NotNull -+ public TextColor color() { -+ return this.color; -+ } -+ -+ /** -+ * Gets the translation key used when an advancement is completed. -+ *

      -+ * This is the first line of the toast displayed by the client. -+ * -+ * @return the toast message key -+ */ -+ @Override -+ @NotNull -+ public String translationKey() { -+ return "advancements.toast." + this.name; -+ } -+ } -+} -diff --git a/src/main/java/org/bukkit/advancement/Advancement.java b/src/main/java/org/bukkit/advancement/Advancement.java -index 17527c2f7bd5b8a5528388a53f2472bc1869c7f3..792d5ab90e9252b4f660434f72f004fade14a84c 100644 ---- a/src/main/java/org/bukkit/advancement/Advancement.java -+++ b/src/main/java/org/bukkit/advancement/Advancement.java -@@ -19,13 +19,41 @@ public interface Advancement extends Keyed { - @NotNull - Collection getCriteria(); - -+ // Paper start - /** -- * Returns the display information for this advancement. -+ * Get the display info of this advancement. -+ *

      -+ * Will be {@code null} when totally hidden, for example with crafting -+ * recipes. - * -- * This includes it's name, description and other visible tags. -+ * @return the display info -+ */ -+ @org.jetbrains.annotations.Nullable -+ io.papermc.paper.advancement.AdvancementDisplay getDisplay(); -+ -+ /** -+ * Gets the parent advancement, if any. -+ * -+ * @return the parent advancement -+ */ -+ @org.jetbrains.annotations.Nullable -+ Advancement getParent(); -+ -+ /** -+ * Gets all the direct children advancements. - * -- * @return a AdvancementDisplay object, or null if not set. -+ * @return the children advancements - */ -- @Nullable -- AdvancementDisplay getDisplay(); -+ @NotNull -+ @org.jetbrains.annotations.Unmodifiable -+ Collection getChildren(); -+ -+ /** -+ * Gets the root advancement of the tree this is located in. -+ * -+ * @return the root advancement -+ */ -+ @NotNull -+ Advancement getRoot(); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/advancement/AdvancementDisplay.java b/src/main/java/org/bukkit/advancement/AdvancementDisplay.java -index 0ff86a39025a94ca128364a45bf171728cb81027..aec6be7e121da3eb8a464b6934da29ab6b473885 100644 ---- a/src/main/java/org/bukkit/advancement/AdvancementDisplay.java -+++ b/src/main/java/org/bukkit/advancement/AdvancementDisplay.java -@@ -5,7 +5,10 @@ import org.jetbrains.annotations.NotNull; - - /** - * Holds information about how the advancement is displayed by the game. -+ * -+ * @deprecated use {@link io.papermc.paper.advancement.AdvancementDisplay} - */ -+@Deprecated(forRemoval = true) // Paper - public interface AdvancementDisplay { - - /** -diff --git a/src/main/java/org/bukkit/advancement/AdvancementDisplayType.java b/src/main/java/org/bukkit/advancement/AdvancementDisplayType.java -index d6640a9ebb30195abf4570dfd30a320fa4636995..f6e1a6c1bb7b99a391dec73c9707840214988fc6 100644 ---- a/src/main/java/org/bukkit/advancement/AdvancementDisplayType.java -+++ b/src/main/java/org/bukkit/advancement/AdvancementDisplayType.java -@@ -8,7 +8,9 @@ import org.jetbrains.annotations.NotNull; - * - * This enum contains information about these types and how they are - * represented. -+ * @deprecated use {@link io.papermc.paper.advancement.AdvancementDisplay.Frame} - */ -+@Deprecated(forRemoval = true) - public enum AdvancementDisplayType { - - /** diff --git a/patches/api/0367-Furnace-RecipesUsed-API.patch b/patches/api/0333-Furnace-RecipesUsed-API.patch similarity index 100% rename from patches/api/0367-Furnace-RecipesUsed-API.patch rename to patches/api/0333-Furnace-RecipesUsed-API.patch diff --git a/patches/api/0334-Add-ItemFactory-getMonsterEgg-API.patch b/patches/api/0334-Add-ItemFactory-getMonsterEgg-API.patch deleted file mode 100644 index 972e376f186d..000000000000 --- a/patches/api/0334-Add-ItemFactory-getMonsterEgg-API.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 14 Oct 2021 12:09:28 -0500 -Subject: [PATCH] Add ItemFactory#getMonsterEgg API - - -diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java -index 34c13845f4916fb167fc9d83fe792975e5c52bdc..2acafae468fcbb7213d6b6c30803a3924a3bbc30 100644 ---- a/src/main/java/org/bukkit/inventory/ItemFactory.java -+++ b/src/main/java/org/bukkit/inventory/ItemFactory.java -@@ -261,5 +261,14 @@ public interface ItemFactory { - @NotNull - @Deprecated - net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity, @NotNull net.md_5.bungee.api.chat.BaseComponent[] customName); -+ -+ /** -+ * Get a spawn egg ItemStack from an EntityType -+ * -+ * @param type EntityType -+ * @return ItemStack spawner egg -+ */ -+ @Nullable -+ ItemStack getSpawnEgg(@Nullable org.bukkit.entity.EntityType type); - // Paper end - } diff --git a/patches/api/0368-Configurable-sculk-sensor-listener-range.patch b/patches/api/0334-Configurable-sculk-sensor-listener-range.patch similarity index 100% rename from patches/api/0368-Configurable-sculk-sensor-listener-range.patch rename to patches/api/0334-Configurable-sculk-sensor-listener-range.patch diff --git a/patches/api/0335-Add-critical-damage-API.patch b/patches/api/0335-Add-critical-damage-API.patch deleted file mode 100644 index 3a9d1f8070a5..000000000000 --- a/patches/api/0335-Add-critical-damage-API.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: dodison -Date: Mon, 26 Jul 2021 17:35:20 +0200 -Subject: [PATCH] Add critical damage API - - -diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java -index 869bad7405ec7fa67728e90d8b9f2e11b542611f..7ce8f1a26c1b33dd0eb6e6435952fd73abf49879 100644 ---- a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java -+++ b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java -@@ -11,15 +11,40 @@ import org.jetbrains.annotations.NotNull; - public class EntityDamageByEntityEvent extends EntityDamageEvent { - private final Entity damager; - -+ @Deprecated // Paper - add critical damage API - public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, final double damage) { - super(damagee, cause, damage); - this.damager = damager; -+ this.critical = false; // Paper - add critical damage API - } - -+ @Deprecated // Paper - add critical damage API - public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { -+ // Paper start - add critical damage API -+ this(damager, damagee, cause, modifiers, modifierFunctions, false); -+ } -+ -+ private final boolean critical; -+ public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions, boolean critical) { -+ // Paper end - super(damagee, cause, modifiers, modifierFunctions); - this.damager = damager; -+ // Paper start - add critical damage API -+ this.critical = critical; -+ } -+ -+ /** -+ * Shows this damage instance was critical. -+ * The damage instance can be critical if the attacking player met the respective conditions. -+ * Furthermore arrows may also cause a critical damage event if the arrow {@link org.bukkit.entity.AbstractArrow#isCritical()}. -+ * -+ * @return if the hit was critical. -+ * @see https://minecraft.fandom.com/wiki/Damage#Critical_hit -+ */ -+ public boolean isCritical() { -+ return this.critical; - } -+ // Paper end - - /** - * Returns the entity that damaged the defender. diff --git a/patches/api/0335-Add-missing-block-data-API.patch b/patches/api/0335-Add-missing-block-data-API.patch new file mode 100644 index 000000000000..1675944429f0 --- /dev/null +++ b/patches/api/0335-Add-missing-block-data-API.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 16 Oct 2021 22:57:10 -0700 +Subject: [PATCH] Add missing block data API + +General purpose patch adding missing getters/setters to BlockData and +its child types. + +Co-authored-by: SoSeDiK +Co-authored-by: Fabrizio La Rosa + +diff --git a/src/main/java/org/bukkit/block/data/Levelled.java b/src/main/java/org/bukkit/block/data/Levelled.java +index 5255538fecae6da413546be3adacd2a99f6c74e9..860f072dee391b300cb1629058a3f9c23dfd95e2 100644 +--- a/src/main/java/org/bukkit/block/data/Levelled.java ++++ b/src/main/java/org/bukkit/block/data/Levelled.java +@@ -36,4 +36,13 @@ public interface Levelled extends BlockData { + * @return the maximum 'level' value + */ + int getMaximumLevel(); ++ ++ // Paper start ++ /** ++ * Gets the minimum allowed value of the 'level' property. ++ * ++ * @return the minimum 'level' value ++ */ ++ int getMinimumLevel(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/block/data/type/Bed.java b/src/main/java/org/bukkit/block/data/type/Bed.java +index ed519bfebe5b921f60867a3900edfce9859058b6..6e7a456dc5e9bfc28a19029a3381e53fa6453d30 100644 +--- a/src/main/java/org/bukkit/block/data/type/Bed.java ++++ b/src/main/java/org/bukkit/block/data/type/Bed.java +@@ -35,6 +35,15 @@ public interface Bed extends Directional { + */ + boolean isOccupied(); + ++ // Paper start ++ /** ++ * Sets the value of the 'occupied' property. ++ * ++ * @param occupied the new 'occupied' value ++ */ ++ void setOccupied(boolean occupied); ++ // Paper end ++ + /** + * Horizontal half of a bed. + */ +diff --git a/src/main/java/org/bukkit/block/data/type/Candle.java b/src/main/java/org/bukkit/block/data/type/Candle.java +index d4d08bd424f84523200d1a2012f4d37c07cc3497..7baccce27f2db2242f628ea92a9d040267caef75 100644 +--- a/src/main/java/org/bukkit/block/data/type/Candle.java ++++ b/src/main/java/org/bukkit/block/data/type/Candle.java +@@ -28,4 +28,13 @@ public interface Candle extends Lightable, Waterlogged { + * @return the maximum 'candles' value + */ + int getMaximumCandles(); ++ ++ // Paper start ++ /** ++ * Gets the minimum allowed value of the 'candles' property. ++ * ++ * @return the minimum 'candles' value ++ */ ++ int getMinimumCandles(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/block/data/type/DecoratedPot.java b/src/main/java/org/bukkit/block/data/type/DecoratedPot.java +index eb0ffa977450ef0c79caa78302cfe75ee35b34b7..b3d290dbfdcbadcbadcb54e6b414e423eba80cc6 100644 +--- a/src/main/java/org/bukkit/block/data/type/DecoratedPot.java ++++ b/src/main/java/org/bukkit/block/data/type/DecoratedPot.java +@@ -4,4 +4,17 @@ import org.bukkit.block.data.Directional; + import org.bukkit.block.data.Waterlogged; + + public interface DecoratedPot extends Directional, Waterlogged { ++ // Paper start - add missing block data api ++ /** ++ * @return whether the pot is cracked ++ */ ++ public boolean isCracked(); ++ ++ /** ++ * Set whether the pot is cracked. ++ * ++ * @param cracked whether the pot is cracked ++ */ ++ public void setCracked(boolean cracked); ++ // Paper end - add missing block data api + } +diff --git a/src/main/java/org/bukkit/block/data/type/Leaves.java b/src/main/java/org/bukkit/block/data/type/Leaves.java +index 3ea21dfad26222ee70fbc627595f54de1a28aa96..cd013a7c42648d819d1e91c7cf9f97a8190c1fad 100644 +--- a/src/main/java/org/bukkit/block/data/type/Leaves.java ++++ b/src/main/java/org/bukkit/block/data/type/Leaves.java +@@ -39,4 +39,20 @@ public interface Leaves extends Waterlogged { + * @param distance the new 'distance' value + */ + void setDistance(int distance); ++ ++ // Paper start ++ /** ++ * Gets the maximum allowed value of the 'distance' property. ++ * ++ * @return the maximum 'distance' value ++ */ ++ int getMaximumDistance(); ++ ++ /** ++ * Gets the minimum allowed value of the 'distance' property. ++ * ++ * @return the minimum 'distance' value ++ */ ++ int getMinimumDistance(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/block/data/type/PinkPetals.java b/src/main/java/org/bukkit/block/data/type/PinkPetals.java +index a84b36f7587eb2ed9e9177973b3166dc94cdf3df..eae9c9cdd0f47a7480ee23ac7b655692f5ee9c1e 100644 +--- a/src/main/java/org/bukkit/block/data/type/PinkPetals.java ++++ b/src/main/java/org/bukkit/block/data/type/PinkPetals.java +@@ -21,6 +21,15 @@ public interface PinkPetals extends Directional { + */ + void setFlowerAmount(int flower_amount); + ++ // Paper start ++ /** ++ * Gets the minimum allowed value of the 'flower_amount' property. ++ * ++ * @return the minimum 'flower_amount' value ++ */ ++ int getMinimumFlowerAmount(); ++ // Paper end ++ + /** + * Gets the maximum allowed value of the 'flower_amount' property. + * diff --git a/patches/api/0336-Custom-Potion-Mixes.patch b/patches/api/0336-Custom-Potion-Mixes.patch new file mode 100644 index 000000000000..5e26417fe9a4 --- /dev/null +++ b/patches/api/0336-Custom-Potion-Mixes.patch @@ -0,0 +1,268 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 7 Oct 2021 14:34:59 -0700 +Subject: [PATCH] Custom Potion Mixes + + +diff --git a/src/main/java/io/papermc/paper/potion/PotionMix.java b/src/main/java/io/papermc/paper/potion/PotionMix.java +new file mode 100644 +index 0000000000000000000000000000000000000000..01b2a7c7a6bf328b3f7c30db3be0bfb8156ebc89 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/potion/PotionMix.java +@@ -0,0 +1,103 @@ ++package io.papermc.paper.potion; ++ ++import java.util.Objects; ++import java.util.function.Predicate; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.inventory.RecipeChoice; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents a potion mix made in a Brewing Stand. ++ */ ++@NullMarked ++public final class PotionMix implements Keyed { ++ ++ private final NamespacedKey key; ++ private final ItemStack result; ++ private final RecipeChoice input; ++ private final RecipeChoice ingredient; ++ ++ /** ++ * Creates a new potion mix. Add it to the server with {@link org.bukkit.potion.PotionBrewer#addPotionMix(PotionMix)}. ++ * ++ * @param key a unique key for the mix ++ * @param result the resulting itemstack that will appear in the 3 bottom slots ++ * @param input the input placed into the bottom 3 slots ++ * @param ingredient the ingredient placed into the top slot ++ */ ++ public PotionMix(final NamespacedKey key, final ItemStack result, final RecipeChoice input, final RecipeChoice ingredient) { ++ this.key = key; ++ this.result = result; ++ this.input = input; ++ this.ingredient = ingredient; ++ } ++ ++ /** ++ * Create a {@link RecipeChoice} based on a Predicate. These RecipeChoices are only ++ * valid for {@link PotionMix}, not anywhere else RecipeChoices may be used. ++ * ++ * @param stackPredicate a predicate for an itemstack. ++ * @return a new RecipeChoice ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ public static RecipeChoice createPredicateChoice(final Predicate stackPredicate) { ++ return new PredicateRecipeChoice(stackPredicate); ++ } ++ ++ @Override ++ public NamespacedKey getKey() { ++ return this.key; ++ } ++ ++ /** ++ * Gets the resulting itemstack after the brew has finished. ++ * ++ * @return the result itemstack ++ */ ++ public ItemStack getResult() { ++ return this.result; ++ } ++ ++ /** ++ * Gets the input for the bottom 3 slots in the brewing stand. ++ * ++ * @return the bottom 3 slot ingredients ++ */ ++ public RecipeChoice getInput() { ++ return this.input; ++ } ++ ++ /** ++ * Gets the ingredient in the top slot of the brewing stand. ++ * ++ * @return the top slot input ++ */ ++ public RecipeChoice getIngredient() { ++ return this.ingredient; ++ } ++ ++ @Override ++ public String toString() { ++ return "PotionMix{" + ++ "result=" + this.result + ++ ", base=" + this.input + ++ ", addition=" + this.ingredient + ++ '}'; ++ } ++ ++ @Override ++ public boolean equals(final Object o) { ++ if (this == o) return true; ++ if (o == null || this.getClass() != o.getClass()) return false; ++ final PotionMix potionMix = (PotionMix) o; ++ return this.key.equals(potionMix.key) && this.result.equals(potionMix.result) && this.input.equals(potionMix.input) && this.ingredient.equals(potionMix.ingredient); ++ } ++ ++ @Override ++ public int hashCode() { ++ return Objects.hash(this.key, this.result, this.input, this.ingredient); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/potion/PredicateRecipeChoice.java b/src/main/java/io/papermc/paper/potion/PredicateRecipeChoice.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c252b432a9df5fd7da71a5eecba37a8844820700 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/potion/PredicateRecipeChoice.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.potion; ++ ++import java.util.function.Predicate; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.inventory.RecipeChoice; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@ApiStatus.Internal ++@NullMarked ++record PredicateRecipeChoice(Predicate itemStackPredicate) implements RecipeChoice, Cloneable { ++ ++ @Override ++ @Deprecated ++ public ItemStack getItemStack() { ++ throw new UnsupportedOperationException("PredicateRecipeChoice does not support this"); ++ } ++ ++ @Override ++ public RecipeChoice clone() { ++ try { ++ return (PredicateRecipeChoice) super.clone(); ++ } catch (final CloneNotSupportedException ex) { ++ throw new AssertionError(ex); ++ } ++ } ++ ++ @Override ++ public boolean test(final ItemStack itemStack) { ++ return this.itemStackPredicate.test(itemStack); ++ } ++} +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index a9d1a9a5223148ea134ed146d059ec9edb922f03..9be54f481a14bc917b465fdef3c2695d8ee64880 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2665,6 +2665,15 @@ public final class Bukkit { + public static io.papermc.paper.datapack.DatapackManager getDatapackManager() { + return server.getDatapackManager(); + } ++ ++ /** ++ * Gets the potion brewer. ++ * ++ * @return the potion brewer ++ */ ++ public static @NotNull org.bukkit.potion.PotionBrewer getPotionBrewer() { ++ return server.getPotionBrewer(); ++ } + // Paper end + + @NotNull +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 06cc09298abcefaacd7a6987c32e5bd86653e719..0da9cee02e2a77e16e3bfaec2197bfc567f5580a 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2322,5 +2322,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + @NotNull + io.papermc.paper.datapack.DatapackManager getDatapackManager(); ++ ++ /** ++ * Gets the potion brewer. ++ * ++ * @return the potion brewer ++ */ ++ @NotNull org.bukkit.potion.PotionBrewer getPotionBrewer(); + // Paper end + } +diff --git a/src/main/java/org/bukkit/potion/PotionBrewer.java b/src/main/java/org/bukkit/potion/PotionBrewer.java +index a90a97901475060e6a4c3ab4e864d30b03974c44..72e159698762f816c06378090a9847d211bfc451 100644 +--- a/src/main/java/org/bukkit/potion/PotionBrewer.java ++++ b/src/main/java/org/bukkit/potion/PotionBrewer.java +@@ -4,10 +4,31 @@ import java.util.Collection; + import org.jetbrains.annotations.NotNull; + + /** +- * Represents a brewer that can create {@link PotionEffect}s. ++ * Used to manage custom {@link io.papermc.paper.potion.PotionMix}s. + */ + public interface PotionBrewer { + ++ // Paper start ++ /** ++ * Adds a new potion mix recipe. ++ * ++ * @param potionMix the potion mix to add ++ */ ++ void addPotionMix(@NotNull io.papermc.paper.potion.PotionMix potionMix); ++ ++ /** ++ * Removes a potion mix recipe. ++ * ++ * @param key the key of the mix to remove ++ */ ++ void removePotionMix(@NotNull org.bukkit.NamespacedKey key); ++ ++ /** ++ * Resets potion mixes to their default, removing all custom ones. ++ */ ++ void resetPotionMixes(); ++ // Paper end ++ + /** + * Creates a {@link PotionEffect} from the given {@link PotionEffectType}, + * applying duration modifiers and checks. +@@ -16,9 +37,15 @@ public interface PotionBrewer { + * @param duration The duration in ticks + * @param amplifier The amplifier of the effect + * @return The resulting potion effect ++ * @deprecated use {@link PotionEffectType#createEffect(int, int)} instead. + */ ++ @Deprecated(forRemoval = true, since = "1.20.5") // Paper + @NotNull +- public PotionEffect createEffect(@NotNull PotionEffectType potion, int duration, int amplifier); ++ // Paper start - make default ++ default PotionEffect createEffect(@NotNull PotionEffectType potion, int duration, int amplifier) { ++ return potion.createEffect(duration, amplifier); ++ } ++ // Paper end + + /** + * Returns a collection of {@link PotionEffect} that would be applied from +@@ -28,9 +55,13 @@ public interface PotionBrewer { + * @return The list of effects + * @deprecated Non-Functional + */ +- @Deprecated(since = "1.6.2") ++ @Deprecated(since = "1.6.2", forRemoval = true) // Paper + @NotNull +- public Collection getEffectsFromDamage(int damage); ++ // Paper start - make default ++ default Collection getEffectsFromDamage(final int damage) { ++ return new java.util.ArrayList<>(); ++ } ++ // Paper end + + /** + * Returns a collection of {@link PotionEffect} that would be applied from +@@ -43,6 +74,6 @@ public interface PotionBrewer { + * @deprecated Upgraded / extended potions are now their own {@link PotionType} use {@link PotionType#getPotionEffects()} instead + */ + @NotNull +- @Deprecated(since = "1.20.2") ++ @Deprecated(since = "1.20.2", forRemoval = true) // Paper + public Collection getEffects(@NotNull PotionType type, boolean upgraded, boolean extended); + } diff --git a/patches/api/0336-Fix-issues-with-mob-conversion.patch b/patches/api/0336-Fix-issues-with-mob-conversion.patch deleted file mode 100644 index 8ee1c4916283..000000000000 --- a/patches/api/0336-Fix-issues-with-mob-conversion.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 24 Oct 2021 20:29:27 -0700 -Subject: [PATCH] Fix issues with mob conversion - - -diff --git a/src/main/java/org/bukkit/entity/PiglinAbstract.java b/src/main/java/org/bukkit/entity/PiglinAbstract.java -index 87f4b7ad7c0a95a7123d142fa023c5da5c760341..70a45e657c6cab6058d1a56fc51c5df79fdce60f 100644 ---- a/src/main/java/org/bukkit/entity/PiglinAbstract.java -+++ b/src/main/java/org/bukkit/entity/PiglinAbstract.java -@@ -31,14 +31,17 @@ public interface PiglinAbstract extends Monster, Ageable { - public int getConversionTime(); - - /** -- * Sets the amount of ticks until this entity will be converted to a -- * Zombified Piglin. -+ * Sets the conversion counter value. The counter is incremented -+ * every tick the {@link #isConverting()} returns true. Setting this -+ * value will not start the conversion if the {@link PiglinAbstract} is -+ * not in a valid environment ({@link org.bukkit.World#isPiglinSafe}) -+ * to convert or {@link #isImmuneToZombification()} is true or -+ * has no AI. - * -- * When this reaches 0, the entity will be converted. A value of less than 0 -- * will stop the current conversion process without converting the current -- * entity. -+ * When this reaches 300, the entity will be converted. To stop the -+ * conversion use {@link #setImmuneToZombification(boolean)}. - * -- * @param time new conversion time -+ * @param time new conversion counter - */ - public void setConversionTime(int time); - diff --git a/patches/api/0337-Add-isCollidable-methods-to-various-places.patch b/patches/api/0337-Add-isCollidable-methods-to-various-places.patch deleted file mode 100644 index 78338a4c0ba7..000000000000 --- a/patches/api/0337-Add-isCollidable-methods-to-various-places.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 4 Nov 2021 11:50:35 -0700 -Subject: [PATCH] Add isCollidable methods to various places - - -diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index 12ed298cb585107370d4400902a651f43bd05d78..2d39ecea67cd033858eaa713e405260a87c718a3 100644 ---- a/src/main/java/org/bukkit/Material.java -+++ b/src/main/java/org/bukkit/Material.java -@@ -4169,6 +4169,16 @@ public enum Material implements Keyed, net.kyori.adventure.translation.Translata - public Multimap getItemAttributes(@NotNull EquipmentSlot equipmentSlot) { - return Bukkit.getUnsafe().getItemAttributes(this, equipmentSlot); - } -+ -+ /** -+ * Checks if this material is collidable. -+ * -+ * @return true if collidable -+ * @throws IllegalArgumentException if {@link #isBlock()} is false -+ */ -+ public boolean isCollidable() { -+ return Bukkit.getUnsafe().isCollidable(this); -+ } - // Paper end - - /** -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index 0a9a50251093e1ea605a748eb8d899f34b26ef7b..be8d5c172b0a300648f21e2163ccf0a9cd7915ee 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -225,5 +225,14 @@ public interface UnsafeValues { - * @throws IllegalArgumentException if the entity does not exist of have default attributes (use {@link #hasDefaultEntityAttributes(NamespacedKey)} first) - */ - @org.jetbrains.annotations.NotNull org.bukkit.attribute.Attributable getDefaultEntityAttributes(@org.jetbrains.annotations.NotNull NamespacedKey entityKey); -+ -+ /** -+ * Checks if this material is collidable. -+ * -+ * @param material the material to check -+ * @return true if collidable -+ * @throws IllegalArgumentException if {@link Material#isBlock()} is false -+ */ -+ boolean isCollidable(@org.jetbrains.annotations.NotNull Material material); - // Paper end - } -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index c847bc83c0911007d226f1a8c6f1d0cefa9a1689..cff39708e66208921da15d12d94407d6b6950298 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -481,6 +481,13 @@ public interface Block extends Metadatable, net.kyori.adventure.translation.Tran - * @return true if block is solid - */ - boolean isSolid(); -+ -+ /** -+ * Checks if this block is collidable. -+ * -+ * @return true if collidable -+ */ -+ boolean isCollidable(); - // Paper end - - /** -diff --git a/src/main/java/org/bukkit/block/BlockState.java b/src/main/java/org/bukkit/block/BlockState.java -index 3147e278eac674ed21d714bbe318b135c0a6b408..10cbe71917bc32cca61748bcb0aa3395c554dbf8 100644 ---- a/src/main/java/org/bukkit/block/BlockState.java -+++ b/src/main/java/org/bukkit/block/BlockState.java -@@ -225,4 +225,13 @@ public interface BlockState extends Metadatable { - * or 'virtual' (e.g. on an itemstack) - */ - boolean isPlaced(); -+ -+ // Paper start -+ /** -+ * Checks if this block state is collidable. -+ * -+ * @return true if collidable -+ */ -+ boolean isCollidable(); -+ // Paper end - } diff --git a/patches/api/0371-Expose-furnace-minecart-push-values.patch b/patches/api/0337-Expose-furnace-minecart-push-values.patch similarity index 100% rename from patches/api/0371-Expose-furnace-minecart-push-values.patch rename to patches/api/0337-Expose-furnace-minecart-push-values.patch diff --git a/patches/api/0338-More-Projectile-API.patch b/patches/api/0338-More-Projectile-API.patch new file mode 100644 index 000000000000..9c3f7dd61631 --- /dev/null +++ b/patches/api/0338-More-Projectile-API.patch @@ -0,0 +1,520 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 26 May 2021 19:34:43 -0400 +Subject: [PATCH] More Projectile API + +Co-authored-by: Nassim Jahnke +Co-authored-by: SoSeDiK +Co-authored-by: MelnCat + +diff --git a/src/main/java/org/bukkit/entity/AbstractArrow.java b/src/main/java/org/bukkit/entity/AbstractArrow.java +index ebb6976aba314f592459cdfa49f6c15079207fd2..88b8f2e81cdd22e5e879832c9223a770df7e9f42 100644 +--- a/src/main/java/org/bukkit/entity/AbstractArrow.java ++++ b/src/main/java/org/bukkit/entity/AbstractArrow.java +@@ -139,17 +139,21 @@ public interface AbstractArrow extends Projectile { + * Gets the ItemStack which will be picked up from this arrow. + * + * @return The picked up ItemStack ++ * @deprecated use {@link #getItemStack()} + */ + @NotNull + @ApiStatus.Experimental ++ @Deprecated(forRemoval = true, since = "1.20.4") // Paper + public ItemStack getItem(); + + /** + * Sets the ItemStack which will be picked up from this arrow. + * + * @param item ItemStack set to be picked up ++ * @deprecated use {@link #getItemStack()} + */ + @ApiStatus.Experimental ++ @Deprecated(forRemoval = true, since = "1.20.4") // Paper + public void setItem(@NotNull ItemStack item); + + /** +@@ -220,4 +224,52 @@ public interface AbstractArrow extends Projectile { + CREATIVE_ONLY; + } + // Paper end ++ ++ // Paper start - more projectile API ++ /** ++ * Gets the {@link ItemStack} for this arrow. This stack is used ++ * for both visuals on the arrow and the stack that could be picked up. ++ * ++ * @return The ItemStack, as if a player picked up the arrow ++ */ ++ @NotNull ItemStack getItemStack(); ++ ++ /** ++ * Sets the {@link ItemStack} for this arrow. This stack is used for both ++ * visuals on the arrow and the stack that could be picked up. ++ * ++ * @param stack the arrow stack ++ */ ++ void setItemStack(@NotNull ItemStack stack); ++ ++ /** ++ * Sets the amount of ticks this arrow has been alive in the world ++ * This is used to determine when the arrow should be automatically despawned. ++ * ++ * @param ticks lifetime ticks ++ */ ++ void setLifetimeTicks(int ticks); ++ ++ /** ++ * Gets how many ticks this arrow has been in the world for. ++ * ++ * @return ticks this arrow has been in the world ++ */ ++ int getLifetimeTicks(); ++ ++ /** ++ * Gets the sound that is played when this arrow hits an entity. ++ * ++ * @return sound that plays ++ */ ++ @NotNull ++ org.bukkit.Sound getHitSound(); ++ ++ /** ++ * Sets the sound that is played when this arrow hits an entity. ++ * ++ * @param sound sound that is played ++ */ ++ void setHitSound(@NotNull org.bukkit.Sound sound); ++ // Paper end - more projectile API + } +diff --git a/src/main/java/org/bukkit/entity/Firework.java b/src/main/java/org/bukkit/entity/Firework.java +index 0d31aa0b22cf1e849572294e2cfe38b48c9210af..217d348ad0bbef720b25d3b507a55ca8105b7731 100644 +--- a/src/main/java/org/bukkit/entity/Firework.java ++++ b/src/main/java/org/bukkit/entity/Firework.java +@@ -16,6 +16,8 @@ public interface Firework extends Projectile { + + /** + * Apply the provided meta to the fireworks ++ *

      ++ * Adjusts detonation ticks automatically. + * + * @param meta The FireworkMeta to apply + */ +@@ -54,31 +56,39 @@ public interface Firework extends Projectile { + * {@link #getMaxLife()}, the firework will detonate. + * + * @param ticks the ticks to set. Must be greater than or equal to 0 ++ * @deprecated use {@link #setTicksFlown(int)} + * @return true if the life was set, false if this firework has already detonated + */ ++ @Deprecated(forRemoval = true) // Paper + boolean setLife(int ticks); + + /** + * Get the ticks that this firework has been alive. When this value reaches + * {@link #getMaxLife()}, the firework will detonate. + * ++ * @deprecated use {@link #getTicksFlown()} + * @return the life ticks + */ ++ @Deprecated(forRemoval = true) // Paper + int getLife(); + + /** + * Set the time in ticks this firework will exist until it is detonated. + * + * @param ticks the ticks to set. Must be greater than 0 ++ * @deprecated use {@link #setTicksToDetonate(int)} + * @return true if the time was set, false if this firework has already detonated + */ ++ @Deprecated(forRemoval = true) // Paper + boolean setMaxLife(int ticks); + + /** + * Get the time in ticks this firework will exist until it is detonated. + * ++ * @deprecated use {@link #getTicksToDetonate()} + * @return the maximum life in ticks + */ ++ @Deprecated(forRemoval = true) // Paper + int getMaxLife(); + + /** +@@ -127,4 +137,52 @@ public interface Firework extends Projectile { + return getAttachedTo(); + } + // Paper end ++ ++ // Paper start - Firework API ++ /** ++ * Gets the item used in the firework. ++ * ++ * @return firework item ++ */ ++ @NotNull ++ public org.bukkit.inventory.ItemStack getItem(); ++ ++ /** ++ * Sets the item used in the firework. ++ *

      ++ * Firework explosion effects are used from this item. ++ * ++ * @param itemStack item to set ++ */ ++ void setItem(@org.jetbrains.annotations.Nullable org.bukkit.inventory.ItemStack itemStack); ++ ++ /** ++ * Gets the number of ticks the firework has flown. ++ * ++ * @return ticks flown ++ */ ++ int getTicksFlown(); ++ ++ /** ++ * Sets the number of ticks the firework has flown. ++ * Setting this greater than detonation ticks will cause the firework to explode. ++ * ++ * @param ticks ticks flown ++ */ ++ void setTicksFlown(int ticks); ++ ++ /** ++ * Gets the number of ticks the firework will detonate on. ++ * ++ * @return the tick to detonate on ++ */ ++ int getTicksToDetonate(); ++ ++ /** ++ * Set the amount of ticks the firework will detonate on. ++ * ++ * @param ticks ticks to detonate on ++ */ ++ void setTicksToDetonate(int ticks); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/FishHook.java b/src/main/java/org/bukkit/entity/FishHook.java +index e17851255506f23b33e3e010d2eeb74e83c6e682..c28e78aa259bbd80343cd6d788436833098f0aea 100644 +--- a/src/main/java/org/bukkit/entity/FishHook.java ++++ b/src/main/java/org/bukkit/entity/FishHook.java +@@ -322,4 +322,50 @@ public interface FishHook extends Projectile { + */ + BOBBING; + } ++ ++ // Paper start - More FishHook API ++ /** ++ * Get the number of ticks the hook needs to wait for a fish to bite. ++ * ++ * @return Number of ticks ++ */ ++ int getWaitTime(); ++ ++ /** ++ * Sets the number of ticks the hook needs to wait for a fish to bite. ++ * ++ * @param ticks Number of ticks ++ */ ++ void setWaitTime(int ticks); ++ ++ /** ++ * Get the number of ticks the fish has to swim until biting the hook. ++ * The {@link #getWaitTime()} has to be zero or below for the fish to start the time until bite timer. ++ * ++ * @return number of ticks. ++ * A value of one indicates that the fish bites the very next time the fish hook is ticked ++ * while a value of zero represents a fish that has already bitten the hook. ++ * @see #getWaitTime() ++ */ ++ @org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE) ++ int getTimeUntilBite(); ++ ++ /** ++ * Sets the number of ticks the fish has to swim until biting the hook. ++ * ++ * @param ticks number of ticks. ++ * One is the minimum that can be passed to this method and instructs the fish to bite the very next tick. ++ * @throws IllegalArgumentException if the passed tick value is less than one. ++ */ ++ void setTimeUntilBite(@org.jetbrains.annotations.Range(from = 1, to = Integer.MAX_VALUE) int ticks) throws IllegalArgumentException; ++ ++ /** ++ * Completely resets this fishing hook's fishing state, re-randomizing the time needed until a fish is lured and ++ * bites the hook. ++ *

      ++ * This method takes all properties of the fishing hook into account when resetting said values, such as a lure ++ * enchantment. ++ */ ++ void resetFishingState(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Projectile.java b/src/main/java/org/bukkit/entity/Projectile.java +index fe64f4e87a0f600b5f1522f788f78ccfc5d7c7ea..f4c7317fd2da03181d836a3d1d24ae910710f0bc 100644 +--- a/src/main/java/org/bukkit/entity/Projectile.java ++++ b/src/main/java/org/bukkit/entity/Projectile.java +@@ -12,6 +12,7 @@ public interface Projectile extends Entity { + * Retrieve the shooter of this projectile. + * + * @return the {@link ProjectileSource} that shot this projectile ++ * @see #getOwnerUniqueId() + */ + @Nullable + public ProjectileSource getShooter(); +@@ -41,4 +42,89 @@ public interface Projectile extends Entity { + */ + @Deprecated(since = "1.20.2", forRemoval = true) + public void setBounce(boolean doesBounce); ++ // Paper start ++ ++ /** ++ * Gets whether the projectile has left the ++ * hitbox of their shooter and can now hit entities. ++ * ++ * @return has left shooter's hitbox ++ */ ++ boolean hasLeftShooter(); ++ ++ /** ++ * Sets whether the projectile has left the ++ * hitbox of their shooter and can now hit entities. ++ * ++ * This is recalculated each tick if the projectile has a shooter. ++ * ++ * @param leftShooter has left shooter's hitbox ++ */ ++ void setHasLeftShooter(boolean leftShooter); ++ ++ /** ++ * Gets whether the projectile has been ++ * shot into the world and has sent a projectile ++ * shot game event. ++ * ++ * @return has been shot into the world ++ */ ++ boolean hasBeenShot(); ++ ++ /** ++ * Sets whether the projectile has been ++ * shot into the world and has sent a projectile ++ * shot game event in the next tick. ++ * ++ * Setting this to false will cause a game event ++ * to fire and the value to be set back to true. ++ * ++ * @param beenShot has been in shot into the world ++ */ ++ void setHasBeenShot(boolean beenShot); ++ ++ /** ++ * Gets whether this projectile can hit an entity. ++ *

      ++ * This method returns true under the following conditions: ++ *

      ++ * - The shooter can see the entity ({@link Player#canSee(Entity)})

      ++ * - The entity is alive and not a spectator

      ++ * - The projectile has left the hitbox of the shooter ({@link #hasLeftShooter()})

      ++ * - If this is an arrow with piercing, it has not pierced the entity already ++ * ++ * @param entity the entity to check if this projectile can hit ++ * @return true if this projectile can damage the entity, false otherwise ++ */ ++ boolean canHitEntity(@org.jetbrains.annotations.NotNull Entity entity); ++ ++ /** ++ * Makes this projectile hit a specific entity. ++ * This uses the current position of the projectile for the hit point. ++ * Using this method will result in {@link org.bukkit.event.entity.ProjectileHitEvent} being called. ++ * @param entity the entity to hit ++ * @see #hitEntity(Entity, org.bukkit.util.Vector) ++ * @see #canHitEntity(Entity) ++ */ ++ void hitEntity(@org.jetbrains.annotations.NotNull Entity entity); ++ ++ /** ++ * Makes this projectile hit a specific entity from a specific point. ++ * Using this method will result in {@link org.bukkit.event.entity.ProjectileHitEvent} being called. ++ * @param entity the entity to hit ++ * @param vector the direction to hit from ++ * @see #hitEntity(Entity) ++ * @see #canHitEntity(Entity) ++ */ ++ void hitEntity(@org.jetbrains.annotations.NotNull Entity entity, @org.jetbrains.annotations.NotNull org.bukkit.util.Vector vector); ++ ++ /** ++ * Gets the owner's UUID ++ * ++ * @return the owner's UUID, or null if not owned ++ * @see #getShooter() ++ */ ++ @Nullable ++ java.util.UUID getOwnerUniqueId(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/ShulkerBullet.java b/src/main/java/org/bukkit/entity/ShulkerBullet.java +index 4623e0d767b343cbdc6fcf20b3b2ff7ff14863cf..dd69a68d1f005c25329bb0366d161ae9b061e108 100644 +--- a/src/main/java/org/bukkit/entity/ShulkerBullet.java ++++ b/src/main/java/org/bukkit/entity/ShulkerBullet.java +@@ -18,4 +18,61 @@ public interface ShulkerBullet extends Projectile { + * @param target the entity to target + */ + void setTarget(@Nullable Entity target); ++ // Paper start ++ /** ++ * Gets the relative offset that this shulker bullet should move towards, ++ * note that this will change each tick as the skulker bullet approaches the target. ++ * ++ * @return target delta offset ++ */ ++ @org.jetbrains.annotations.NotNull ++ org.bukkit.util.Vector getTargetDelta(); ++ ++ ++ /** ++ * Sets the relative offset that this shulker bullet should move towards, ++ * note that this will change each tick as the skulker bullet approaches the target. ++ * This is usually relative towards their target. ++ * ++ * @param vector target ++ */ ++ void setTargetDelta(@org.jetbrains.annotations.NotNull org.bukkit.util.Vector vector); ++ ++ /** ++ * Gets the current movement direction. ++ * This is used to determine the next movement direction to ensure ++ * that the bullet does not move in the same direction. ++ * ++ * @return null or their current direction ++ */ ++ @Nullable ++ org.bukkit.block.BlockFace getCurrentMovementDirection(); ++ ++ /** ++ * Set the current movement direction. ++ * This is used to determine the next movement direction to ensure ++ * that the bullet does not move in the same direction. ++ * ++ * Set to null to simply pick a random direction. ++ * ++ * @param movementDirection null or a direction ++ */ ++ void setCurrentMovementDirection(@Nullable org.bukkit.block.BlockFace movementDirection); ++ ++ /** ++ * Gets how many ticks this shulker bullet ++ * will attempt to move in its current direction. ++ * ++ * @return number of steps ++ */ ++ int getFlightSteps(); ++ ++ /** ++ * Sets how many ticks this shulker bullet ++ * will attempt to move in its current direction. ++ * ++ * @param steps number of steps ++ */ ++ void setFlightSteps(int steps); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/ThrownPotion.java b/src/main/java/org/bukkit/entity/ThrownPotion.java +index 7051e07b4e456aae0ec9e37808b59e5fa62a4027..225ac312613b9e8f3cf680819f2ebe350d1bf48a 100644 +--- a/src/main/java/org/bukkit/entity/ThrownPotion.java ++++ b/src/main/java/org/bukkit/entity/ThrownPotion.java +@@ -32,12 +32,34 @@ public interface ThrownPotion extends ThrowableProjectile { + + /** + * Set the ItemStack for this thrown potion. +- *

      +- * The ItemStack must be of type {@link org.bukkit.Material#SPLASH_POTION} +- * or {@link org.bukkit.Material#LINGERING_POTION}, otherwise an exception +- * is thrown. + * + * @param item New ItemStack + */ + public void setItem(@NotNull ItemStack item); ++ ++ // Paper start - Projectile API ++ /** ++ * Gets a copy of the PotionMeta for this thrown potion. ++ * This includes what effects will be applied by this potion. ++ * ++ * @return potion meta ++ */ ++ @NotNull ++ org.bukkit.inventory.meta.PotionMeta getPotionMeta(); ++ ++ /** ++ * Sets the PotionMeta of this thrown potion. ++ * This will modify the effects applied by this potion. ++ *

      ++ * Note that the type of {@link #getItem()} is irrelevant ++ * ++ * @param meta potion meta ++ */ ++ void setPotionMeta(@NotNull org.bukkit.inventory.meta.PotionMeta meta); ++ ++ /** ++ * Splashes the potion at its current location. ++ */ ++ void splash(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Trident.java b/src/main/java/org/bukkit/entity/Trident.java +index c8015ff610e3c1222cb368ea1d8a0c2f3785d9c7..02584eced96944a551140f8150c65a7c0f4bb55e 100644 +--- a/src/main/java/org/bukkit/entity/Trident.java ++++ b/src/main/java/org/bukkit/entity/Trident.java +@@ -38,5 +38,24 @@ public interface Trident extends AbstractArrow, ThrowableProjectile { + * @throws IllegalArgumentException if the loyalty level is lower than 0 or greater than 127 + */ + void setLoyaltyLevel(int loyaltyLevel); ++ ++ /** ++ * Gets if this trident has dealt damage to an ++ * entity yet or has hit the floor. ++ * ++ * If neither of these events have occurred yet, this will ++ * return false. ++ * ++ * @return has dealt damage ++ */ ++ boolean hasDealtDamage(); ++ ++ /** ++ * Sets if this trident has dealt damage to an entity ++ * yet or has hit the floor. ++ * ++ * @param hasDealtDamage has dealt damage or hit the floor ++ */ ++ void setHasDealtDamage(boolean hasDealtDamage); + } + // Paper end +diff --git a/src/main/java/org/bukkit/projectiles/ProjectileSource.java b/src/main/java/org/bukkit/projectiles/ProjectileSource.java +index 8557bfefaf02538dec95adb29734ae2cf50f3f8c..03faf9a142f494e255258099a6b8831a0d4a879b 100644 +--- a/src/main/java/org/bukkit/projectiles/ProjectileSource.java ++++ b/src/main/java/org/bukkit/projectiles/ProjectileSource.java +@@ -39,4 +39,26 @@ public interface ProjectileSource { + */ + @NotNull + public T launchProjectile(@NotNull Class projectile, @Nullable Vector velocity); ++ ++ // Paper start - add consumer to launchProjectile ++ /** ++ * Launches a {@link Projectile} from the ProjectileSource with an ++ * initial velocity, with the supplied function run before the ++ * entity is added to the world. ++ *
      ++ * Note that when the function is run, the entity will not be actually in ++ * the world. Any operation involving such as teleporting the entity is undefined ++ * until after this function returns. ++ *

      ++ * The family of launchProjectile methods only promise the ability to launch projectile types ++ * that the {@link ProjectileSource} is capable of firing in vanilla. ++ * Any other types of projectiles *may* be implemented but are not part of the method contract. ++ * @param a projectile subclass ++ * @param projectile class of the projectile to launch ++ * @param velocity the velocity with which to launch ++ * @param function the function to be run before the entity is spawned ++ * @return the launched projectile ++ */ ++ @NotNull T launchProjectile(@NotNull Class projectile, @Nullable Vector velocity, java.util.function.@Nullable Consumer function); ++ // Paper end - add consumer to launchProjectile + } diff --git a/patches/api/0339-Add-API-for-resetting-a-single-score.patch b/patches/api/0339-Add-API-for-resetting-a-single-score.patch deleted file mode 100644 index 997ebf42f6fe..000000000000 --- a/patches/api/0339-Add-API-for-resetting-a-single-score.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: booky10 -Date: Fri, 5 Nov 2021 21:01:36 +0100 -Subject: [PATCH] Add API for resetting a single score - -It was only possible to reset all scores for a specific entry, instead of resetting only specific scores. - -diff --git a/src/main/java/org/bukkit/scoreboard/Score.java b/src/main/java/org/bukkit/scoreboard/Score.java -index d25b4d04932da7e7562cd1acf67ebec33af5b6ef..07bfad4a908de26e9aa6291e4ad20006e88ffe87 100644 ---- a/src/main/java/org/bukkit/scoreboard/Score.java -+++ b/src/main/java/org/bukkit/scoreboard/Score.java -@@ -73,4 +73,14 @@ public interface Score { - */ - @Nullable - Scoreboard getScoreboard(); -+ -+ // Paper start -+ /** -+ * Resets this score, if a value has been set. -+ * -+ * @throws IllegalStateException if the associated objective has been -+ * unregistered -+ */ -+ void resetScore() throws IllegalStateException; -+ // Paper end - } diff --git a/patches/api/0339-Add-getComputedBiome-API.patch b/patches/api/0339-Add-getComputedBiome-API.patch new file mode 100644 index 000000000000..fefb8c693eef --- /dev/null +++ b/patches/api/0339-Add-getComputedBiome-API.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Mon, 14 Mar 2022 22:45:32 -0700 +Subject: [PATCH] Add getComputedBiome API + + +diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java +index b68367f123f029c3ff47eab6bfabd7a894a99da4..44ee56a5956cc17194c767a0c1071a2abffe818a 100644 +--- a/src/main/java/org/bukkit/RegionAccessor.java ++++ b/src/main/java/org/bukkit/RegionAccessor.java +@@ -25,6 +25,7 @@ public interface RegionAccessor extends Keyed { // Paper + * + * @param location the location of the biome + * @return Biome at the given location ++ * @see #getComputedBiome(int, int, int) + */ + @NotNull + Biome getBiome(@NotNull Location location); +@@ -36,10 +37,33 @@ public interface RegionAccessor extends Keyed { // Paper + * @param y Y-coordinate of the block + * @param z Z-coordinate of the block + * @return Biome at the given coordinates ++ * @see #getComputedBiome(int, int, int) + */ + @NotNull + Biome getBiome(int x, int y, int z); + ++ // Paper start ++ /** ++ * Gets the computed {@link Biome} at the given coordinates. ++ * ++ *

      The computed Biome is the Biome as seen by clients for rendering ++ * purposes and in the "F3" debug menu. This is computed by looking at the noise biome ++ * at this and surrounding quarts and applying complex math operations.

      ++ * ++ *

      Most other Biome-related methods named getBiome, setBiome, and similar ++ * operate on the "noise biome", which is stored per-quart, or in other words, ++ * 1 Biome per 4x4x4 block region. This is how Biomes are currently generated and ++ * stored on disk.

      ++ * ++ * @param x X-coordinate of the block ++ * @param y Y-coordinate of the block ++ * @param z Z-coordinate of the block ++ * @return Biome at the given coordinates ++ */ ++ @NotNull ++ Biome getComputedBiome(int x, int y, int z); ++ // Paper end ++ + /** + * Sets the {@link Biome} at the given {@link Location}. + * +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index 7f9acd155c1b275145ba53a41b7513dc8cc00531..b47804da74e143b8d3665c3ec7dd9d858eee6a6b 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -375,10 +375,22 @@ public interface Block extends Metadatable, Translatable, net.kyori.adventure.tr + * Returns the biome that this block resides in + * + * @return Biome type containing this block ++ * @see #getComputedBiome() + */ + @NotNull + Biome getBiome(); + ++ // Paper start ++ /** ++ * Gets the computed biome at the location of this Block. ++ * ++ * @return computed biome at the location of this Block. ++ * @see org.bukkit.RegionAccessor#getComputedBiome(int, int, int) ++ */ ++ @NotNull ++ Biome getComputedBiome(); ++ // Paper end ++ + /** + * Sets the biome that this block resides in + * diff --git a/patches/api/0340-Add-Raw-Byte-Entity-Serialization.patch b/patches/api/0340-Add-Raw-Byte-Entity-Serialization.patch deleted file mode 100644 index 422f59252e49..000000000000 --- a/patches/api/0340-Add-Raw-Byte-Entity-Serialization.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sun, 24 Oct 2021 16:19:26 -0400 -Subject: [PATCH] Add Raw Byte Entity Serialization - - -diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java -index be8d5c172b0a300648f21e2163ccf0a9cd7915ee..4fcafddf3792b66c618f91e04d102f374de565a8 100644 ---- a/src/main/java/org/bukkit/UnsafeValues.java -+++ b/src/main/java/org/bukkit/UnsafeValues.java -@@ -112,6 +112,14 @@ public interface UnsafeValues { - - ItemStack deserializeItem(byte[] data); - -+ byte[] serializeEntity(org.bukkit.entity.Entity entity); -+ -+ default org.bukkit.entity.Entity deserializeEntity(byte[] data, World world) { -+ return deserializeEntity(data, world, false); -+ } -+ -+ org.bukkit.entity.Entity deserializeEntity(byte[] data, World world, boolean preserveUUID); -+ - /** - * Return the translation key for the Material, so the client can translate it into the active - * locale when using a {@link net.kyori.adventure.text.TranslatableComponent}. -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 898c005cb715235df8d7ed6a98faa8191af2fd91..9b46e42fcd803c2f0fb46b220ed79d69b1d16fc4 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -775,5 +775,32 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - * @return players in tracking range - */ - @NotNull Set getTrackedPlayers(); -+ -+ /** -+ * Spawns the entity in the world at the given {@link Location} with the default spawn reason. -+ *

      -+ * This will not spawn the entity if the entity is already spawned or has previously been despawned. -+ *

      -+ * Also, this method will fire the same events as a normal entity spawn. -+ * -+ * @param location The location to spawn the entity at. -+ * @return Whether the entity was successfully spawned. -+ */ -+ public default boolean spawnAt(@NotNull Location location) { -+ return spawnAt(location, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); -+ } -+ -+ /** -+ * Spawns the entity in the world at the given {@link Location} with the reason given. -+ *

      -+ * This will not spawn the entity if the entity is already spawned or has previously been despawned. -+ *

      -+ * Also, this method will fire the same events as a normal entity spawn. -+ * -+ * @param location The location to spawn the entity at. -+ * @param reason The reason for the entity being spawned. -+ * @return Whether the entity was successfully spawned. -+ */ -+ public boolean spawnAt(@NotNull Location location, @NotNull org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason); - // Paper end - } diff --git a/patches/api/0340-Add-enchantWithLevels-API.patch b/patches/api/0340-Add-enchantWithLevels-API.patch new file mode 100644 index 000000000000..5b88a184cd3e --- /dev/null +++ b/patches/api/0340-Add-enchantWithLevels-API.patch @@ -0,0 +1,100 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Wed, 16 Mar 2022 20:35:13 -0700 +Subject: [PATCH] Add enchantWithLevels API + +Deprecate upstream's newer and poorly implemented similar +API. + +diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java +index 579a9037b656bef9fb65c6da03611e981492074a..e1986aea72bb1f1ba2ea76f3ba53f274b6aac899 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFactory.java ++++ b/src/main/java/org/bukkit/inventory/ItemFactory.java +@@ -170,8 +170,11 @@ public interface ItemFactory { + * @param level the level to use, which is the level in the enchantment table + * @param allowTreasures allows treasure enchants, e.g. mending, if true. + * @return a new ItemStack containing the result of the Enchantment ++ * @deprecated use {@link #enchantWithLevels(ItemStack, int, boolean, java.util.Random)}. This method's implementation is poorly ++ * designed and was originally broken. + */ + @NotNull ++ @Deprecated(since = "1.19.3") // Paper + ItemStack enchantItem(@NotNull final Entity entity, @NotNull final ItemStack item, final int level, final boolean allowTreasures); + + /** +@@ -184,8 +187,11 @@ public interface ItemFactory { + * @param level the level to use, which is the level in the enchantment table + * @param allowTreasures allow the treasure enchants, e.g. mending, if true. + * @return a new ItemStack containing the result of the Enchantment ++ * @deprecated use {@link #enchantWithLevels(ItemStack, int, boolean, java.util.Random)}. This method's implementation is poorly ++ * designed and was originally broken. + */ + @NotNull ++ @Deprecated(since = "1.19.3") // Paper + ItemStack enchantItem(@NotNull final World world, @NotNull final ItemStack item, final int level, final boolean allowTreasures); + + /** +@@ -197,8 +203,11 @@ public interface ItemFactory { + * @param level the level to use, which is the level in the enchantment table + * @param allowTreasures allow treasure enchantments, e.g. mending, if true. + * @return a new ItemStack containing the result of the Enchantment ++ * @deprecated use {@link #enchantWithLevels(ItemStack, int, boolean, java.util.Random)}. This method's implementation is poorly ++ * designed and was originally broken. + */ + @NotNull ++ @Deprecated(since = "1.19.3") // Paper + ItemStack enchantItem(@NotNull final ItemStack item, final int level, final boolean allowTreasures); + + // Paper start - Adventure +@@ -311,4 +320,22 @@ public interface ItemFactory { + @Deprecated + net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity, @NotNull net.md_5.bungee.api.chat.BaseComponent[] customName); + // Paper end - bungee hover events ++ ++ // Paper start - enchantWithLevels API ++ /** ++ * Randomly enchants a copy of the provided {@link ItemStack} using the given experience levels. ++ * ++ *

      If the provided ItemStack is already enchanted, the existing enchants will be removed before enchanting.

      ++ * ++ *

      Levels must be in range {@code [1, 30]}.

      ++ * ++ * @param itemStack ItemStack to enchant ++ * @param levels levels to use for enchanting ++ * @param allowTreasure whether to allow enchantments where {@link org.bukkit.enchantments.Enchantment#isTreasure()} returns true ++ * @param random {@link java.util.Random} instance to use for enchanting ++ * @return enchanted copy of the provided ItemStack ++ * @throws IllegalArgumentException on bad arguments ++ */ ++ @NotNull ItemStack enchantWithLevels(@NotNull ItemStack itemStack, @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, boolean allowTreasure, @NotNull java.util.Random random); ++ // Paper end - enchantWithLevels API + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index 86404d3b8b4862cd1f140617cae93aa69df122ca..e9b88bb759af1a5c926d3d4c30a333e7720519cd 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -678,6 +678,24 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + } + + // Paper start ++ /** ++ * Randomly enchants a copy of this {@link ItemStack} using the given experience levels. ++ * ++ *

      If this ItemStack is already enchanted, the existing enchants will be removed before enchanting.

      ++ * ++ *

      Levels must be in range {@code [1, 30]}.

      ++ * ++ * @param levels levels to use for enchanting ++ * @param allowTreasure whether to allow enchantments where {@link org.bukkit.enchantments.Enchantment#isTreasure()} returns true ++ * @param random {@link java.util.Random} instance to use for enchanting ++ * @return enchanted copy of the provided ItemStack ++ * @throws IllegalArgumentException on bad arguments ++ */ ++ @NotNull ++ public ItemStack enchantWithLevels(final @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, final boolean allowTreasure, final @NotNull java.util.Random random) { ++ return Bukkit.getServer().getItemFactory().enchantWithLevels(this, levels, allowTreasure, random); ++ } ++ + @NotNull + @Override + public net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { diff --git a/patches/api/0341-Add-PlayerItemFrameChangeEvent.patch b/patches/api/0341-Add-PlayerItemFrameChangeEvent.patch deleted file mode 100644 index a62e452bb411..000000000000 --- a/patches/api/0341-Add-PlayerItemFrameChangeEvent.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SamB440 -Date: Mon, 15 Nov 2021 18:09:46 +0000 -Subject: [PATCH] Add PlayerItemFrameChangeEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerItemFrameChangeEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerItemFrameChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..451fb94a5802755c255e04aebb40f178bbfbf996 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerItemFrameChangeEvent.java -@@ -0,0 +1,97 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.Material; -+import org.bukkit.entity.ItemFrame; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when an {@link ItemFrame} is having an item rotated, added, or removed from it. -+ */ -+public class PlayerItemFrameChangeEvent extends PlayerEvent implements Cancellable { -+ -+ private static final HandlerList HANDLERS = new HandlerList(); -+ private boolean cancelled; -+ private final ItemFrame itemFrame; -+ private ItemStack itemStack; -+ private final ItemFrameChangeAction action; -+ -+ public PlayerItemFrameChangeEvent(@NotNull Player player, @NotNull ItemFrame itemFrame, -+ @NotNull ItemStack itemStack, @NotNull ItemFrameChangeAction action) { -+ super(player); -+ this.itemFrame = itemFrame; -+ this.itemStack = itemStack; -+ this.action = action; -+ } -+ -+ /** -+ * Gets the {@link ItemFrame} involved in this event. -+ * @return the {@link ItemFrame} -+ */ -+ @NotNull -+ public ItemFrame getItemFrame() { -+ return itemFrame; -+ } -+ -+ /** -+ * Gets the {@link ItemStack} involved in this event. -+ * This is the item being added, rotated, or removed from the {@link ItemFrame}. -+ *

      If this method returns air, then the resulting item in the ItemFrame will be empty.

      -+ * @return the {@link ItemStack} being added, rotated, or removed -+ */ -+ @NotNull -+ public ItemStack getItemStack() { -+ return itemStack; -+ } -+ -+ /** -+ * Sets the {@link ItemStack} that this {@link ItemFrame} holds. -+ * If null is provided, the ItemStack will become air and the result in the ItemFrame will be empty. -+ * @param itemStack {@link ItemFrame} item -+ */ -+ public void setItemStack(@Nullable ItemStack itemStack) { -+ this.itemStack = itemStack == null ? new ItemStack(Material.AIR) : itemStack; -+ } -+ -+ /** -+ * Gets the action that was performed on this {@link ItemFrame}. -+ * @see ItemFrameChangeAction -+ * @return action performed on the item frame in this event -+ */ -+ @NotNull -+ public ItemFrameChangeAction getAction() { -+ return action; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return HANDLERS; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return HANDLERS; -+ } -+ -+ public enum ItemFrameChangeAction { -+ PLACE, -+ REMOVE, -+ ROTATE -+ } -+} diff --git a/patches/api/0341-Add-TameableDeathMessageEvent.patch b/patches/api/0341-Add-TameableDeathMessageEvent.patch new file mode 100644 index 000000000000..bfab2aa214c2 --- /dev/null +++ b/patches/api/0341-Add-TameableDeathMessageEvent.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Fri, 19 Mar 2021 23:25:38 -0400 +Subject: [PATCH] Add TameableDeathMessageEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/TameableDeathMessageEvent.java b/src/main/java/io/papermc/paper/event/entity/TameableDeathMessageEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b956ef8f95156c225741f53811b4a36963da6616 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/TameableDeathMessageEvent.java +@@ -0,0 +1,69 @@ ++package io.papermc.paper.event.entity; ++ ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Tameable; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a {@link Tameable} dies and sends a death message. ++ */ ++@NullMarked ++public class TameableDeathMessageEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private Component deathMessage; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public TameableDeathMessageEvent(final Tameable tameable, final Component deathMessage) { ++ super(tameable); ++ this.deathMessage = deathMessage; ++ } ++ ++ /** ++ * Set the death message that appears to the owner of the tameable. ++ * ++ * @param deathMessage Death message to appear ++ */ ++ public void deathMessage(final Component deathMessage) { ++ this.deathMessage = deathMessage; ++ } ++ ++ /** ++ * Get the death message that appears to the owner of the tameable. ++ * ++ * @return Death message to appear ++ */ ++ public Component deathMessage() { ++ return this.deathMessage; ++ } ++ ++ @Override ++ public Tameable getEntity() { ++ return (Tameable) super.getEntity(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0342-Add-player-health-update-API.patch b/patches/api/0342-Add-player-health-update-API.patch deleted file mode 100644 index a8f2c3ba79e0..000000000000 --- a/patches/api/0342-Add-player-health-update-API.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SamB440 -Date: Wed, 17 Nov 2021 12:30:36 +0000 -Subject: [PATCH] Add player health update API - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 792441dd8465edd1e6c2ffcbb8b2823a5884554f..b2b28b48e6e7d9f32460b8a65cbe294be4812bd9 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -1886,6 +1886,31 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - */ - public double getHealthScale(); - -+ // Paper start -+ /** -+ * Forcefully sends a health update to the player. -+ *

      This method can cause the client to display health values -+ * different to their true server values. If the player takes damage or -+ * causes an action to otherwise cause a health update, these values -+ * will no longer be shown.

      -+ * Setting the visible health to 0 will result in the client seeing -+ * the death screen, unable to press the respawn button. -+ * @see #sendHealthUpdate() -+ * @param health the health of the player -+ * @param foodLevel the food level of the player -+ * @param saturationLevel the saturation level of the player -+ */ -+ public void sendHealthUpdate(final double health, final int foodLevel, final float saturationLevel); -+ -+ /** -+ * Forcefully sends a health update to the player. -+ * This uses the player's current health, saturation, and food level. -+ *

      Use after {@link #setHealth(double)} to show the heart animation -+ * of gaining or losing health.

      -+ */ -+ public void sendHealthUpdate(); -+ // Paper end -+ - /** - * Gets the entity which is followed by the camera when in - * {@link GameMode#SPECTATOR}. diff --git a/patches/api/0342-Allow-to-change-the-podium-of-the-EnderDragon.patch b/patches/api/0342-Allow-to-change-the-podium-of-the-EnderDragon.patch new file mode 100644 index 000000000000..08ffa1fdde63 --- /dev/null +++ b/patches/api/0342-Allow-to-change-the-podium-of-the-EnderDragon.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Doc +Date: Sat, 2 Apr 2022 23:03:32 -0300 +Subject: [PATCH] Allow to change the podium of the EnderDragon + + +diff --git a/src/main/java/org/bukkit/entity/EnderDragon.java b/src/main/java/org/bukkit/entity/EnderDragon.java +index 92cd35c87bad578c2b714761c93a5b72ebf4bc9e..68f58c40a56791df177967de5661cca976a7e98c 100644 +--- a/src/main/java/org/bukkit/entity/EnderDragon.java ++++ b/src/main/java/org/bukkit/entity/EnderDragon.java +@@ -108,4 +108,22 @@ public interface EnderDragon extends ComplexLivingEntity, Boss, Mob, Enemy { + * @return this dragon's death animation ticks + */ + int getDeathAnimationTicks(); ++ ++ // Paper start ++ ++ /** ++ * Get the podium location used by the ender dragon. ++ * ++ * @return the podium location of the dragon ++ */ ++ @NotNull ++ org.bukkit.Location getPodium(); ++ ++ /** ++ * Sets the location of the podium for the ender dragon. ++ * ++ * @param location the location of the podium or null to use the default podium location (exit portal of the end) ++ */ ++ void setPodium(@Nullable org.bukkit.Location location); ++ // Paper end + } diff --git a/patches/api/0343-Allow-delegation-to-vanilla-chunk-gen.patch b/patches/api/0343-Allow-delegation-to-vanilla-chunk-gen.patch deleted file mode 100644 index 0e9d7777a6a1..000000000000 --- a/patches/api/0343-Allow-delegation-to-vanilla-chunk-gen.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MiniDigger -Date: Wed, 29 Apr 2020 02:09:17 +0200 -Subject: [PATCH] Allow delegation to vanilla chunk gen - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 23b57b99169881aa6963694d34f55d9c5c133888..a748f268a992ac8ec9b732f530e3dd4847a3d47b 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -1892,6 +1892,24 @@ public final class Bukkit { - return server.createChunkData(world); - } - -+ // Paper start -+ /** -+ * Create a ChunkData for use in a generator, that is populated by the vanilla generator for that world -+ * -+ * @param world the world to create the ChunkData for -+ * @param x the x coordinate of the chunk -+ * @param z the z coordinate of the chunk -+ * @return a new ChunkData for the world -+ * @deprecated The new multi-stage worldgen API allows a similar effect by overriding all of the "shouldGenerate..." methods to -+ * return true, and then modifying the chunkdata in a later stage such as surface or bedrock generation. -+ */ -+ @NotNull -+ @Deprecated(forRemoval = true) -+ public static ChunkGenerator.ChunkData createVanillaChunkData(@NotNull World world, int x, int z) { -+ return server.createVanillaChunkData(world, x, z); -+ } -+ // Paper stop -+ - /** - * Creates a boss bar instance to display to players. The progress - * defaults to 1.0 -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 5c5d124a179e8c0dc0cf24a51d406c9034f48505..e7d1ece4f1e615e2b0f4da1d85ddd60e23433d4d 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1589,6 +1589,22 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - @NotNull - public ChunkGenerator.ChunkData createChunkData(@NotNull World world); - -+ // Paper start -+ /** -+ * Create a ChunkData for use in a generator, that is populated by the vanilla generator for that world. -+ * -+ * @param world the world to create the ChunkData for -+ * @param x the x coordinate of the chunk -+ * @param z the z coordinate of the chunk -+ * @return a new ChunkData for the world -+ * @deprecated The new multi-stage worldgen API allows a similar effect by overriding all of the "shouldGenerate..." methods to -+ * return true, and then modifying the chunkdata in a later stage such as surface or bedrock generation. -+ */ -+ @NotNull -+ @Deprecated(forRemoval = true) -+ ChunkGenerator.ChunkData createVanillaChunkData(@NotNull World world, int x, int z); -+ // Paper end -+ - /** - * Creates a boss bar instance to display to players. The progress - * defaults to 1.0 -diff --git a/src/main/java/org/bukkit/generator/ChunkGenerator.java b/src/main/java/org/bukkit/generator/ChunkGenerator.java -index e70e6949a9d5a5a37f0c92e139071d4060548e96..ef756dcd55146af71649658eadc45b70d3ba057f 100644 ---- a/src/main/java/org/bukkit/generator/ChunkGenerator.java -+++ b/src/main/java/org/bukkit/generator/ChunkGenerator.java -@@ -454,6 +454,22 @@ public abstract class ChunkGenerator { - return false; - } - -+ // Paper start -+ /** -+ * Create a ChunkData for use in a generator, that is populated by the vanilla generator for that world -+ * -+ * @param world the world to create the ChunkData for -+ * @param x the x coordinate of the chunk -+ * @param z the z coordinate of the chunk -+ * @return a new ChunkData for the world -+ * -+ */ -+ @NotNull -+ public ChunkData createVanillaChunkData(@NotNull World world, int x, int z) { -+ return Bukkit.getServer().createVanillaChunkData(world, x, z); -+ } -+ // Paper end -+ - /** - * Data for a Chunk. - */ diff --git a/patches/api/0343-Fix-incorrect-new-blockstate-in-EntityBreakDoorEvent.patch b/patches/api/0343-Fix-incorrect-new-blockstate-in-EntityBreakDoorEvent.patch new file mode 100644 index 000000000000..21b3f85c0bfc --- /dev/null +++ b/patches/api/0343-Fix-incorrect-new-blockstate-in-EntityBreakDoorEvent.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 2 Jul 2023 22:14:09 -0700 +Subject: [PATCH] Fix incorrect new blockstate in EntityBreakDoorEvent + + +diff --git a/src/main/java/org/bukkit/event/entity/EntityBreakDoorEvent.java b/src/main/java/org/bukkit/event/entity/EntityBreakDoorEvent.java +index 30b9bdca89a8d4b226824b3de8b9ac5bc8243c7d..b7889e3b6cc5d3ed4d7fc2380d0acb060cb0905a 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityBreakDoorEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityBreakDoorEvent.java +@@ -12,8 +12,8 @@ import org.jetbrains.annotations.NotNull; + * Cancelling the event will cause the event to be delayed + */ + public class EntityBreakDoorEvent extends EntityChangeBlockEvent { +- public EntityBreakDoorEvent(@NotNull final LivingEntity entity, @NotNull final Block targetBlock) { +- super(entity, targetBlock, Material.AIR.createBlockData()); ++ public EntityBreakDoorEvent(@NotNull final LivingEntity entity, @NotNull final Block targetBlock, @NotNull final org.bukkit.block.data.BlockData to) { // Paper ++ super(entity, targetBlock, to); // Paper + } + + @NotNull diff --git a/patches/api/0377-Add-pre-unbreaking-amount-to-PlayerItemDamageEvent.patch b/patches/api/0344-Add-pre-unbreaking-amount-to-PlayerItemDamageEvent.patch similarity index 100% rename from patches/api/0377-Add-pre-unbreaking-amount-to-PlayerItemDamageEvent.patch rename to patches/api/0344-Add-pre-unbreaking-amount-to-PlayerItemDamageEvent.patch diff --git a/patches/api/0345-Move-VehicleCollisionEvent-HandlerList-up.patch b/patches/api/0345-Move-VehicleCollisionEvent-HandlerList-up.patch deleted file mode 100644 index 8fa566d54ab2..000000000000 --- a/patches/api/0345-Move-VehicleCollisionEvent-HandlerList-up.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 13 Dec 2021 14:35:27 -0800 -Subject: [PATCH] Move VehicleCollisionEvent HandlerList up - - -diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java -index 316f625aa595d2ada16529b16d09f013fc4daeac..7ff9aec7ed341c01feddb8d71170b177e1fde47b 100644 ---- a/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java -+++ b/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java -@@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; - * Raised when a vehicle collides with a block. - */ - public class VehicleBlockCollisionEvent extends VehicleCollisionEvent { -- private static final HandlerList handlers = new HandlerList(); -+ // private static final HandlerList handlers = new HandlerList(); // Paper - move HandlerList to VehicleCollisionEvent - private final Block block; - - public VehicleBlockCollisionEvent(@NotNull final Vehicle vehicle, @NotNull final Block block) { -@@ -26,15 +26,4 @@ public class VehicleBlockCollisionEvent extends VehicleCollisionEvent { - public Block getBlock() { - return block; - } -- -- @NotNull -- @Override -- public HandlerList getHandlers() { -- return handlers; -- } -- -- @NotNull -- public static HandlerList getHandlerList() { -- return handlers; -- } - } -diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java -index 9d493c155ad5c26430c1e404fcf0db5f734679e4..aa1d74eade479195bde8095aafcc91a83635102d 100644 ---- a/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java -+++ b/src/main/java/org/bukkit/event/vehicle/VehicleCollisionEvent.java -@@ -7,7 +7,18 @@ import org.jetbrains.annotations.NotNull; - * Raised when a vehicle collides. - */ - public abstract class VehicleCollisionEvent extends VehicleEvent { -+ private static final org.bukkit.event.HandlerList HANDLER_LIST = new org.bukkit.event.HandlerList(); // Paper - public VehicleCollisionEvent(@NotNull final Vehicle vehicle) { - super(vehicle); - } -+ // Paper start -+ @Override -+ public org.bukkit.event.@org.jetbrains.annotations.NotNull HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ public static org.bukkit.event.@NotNull HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java -index 6bafc62e2235a6b783cbf96f4dabeeaf02bd5178..089c644caf10a4d55a5db4f7aa7d9b5c9764c17a 100644 ---- a/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java -+++ b/src/main/java/org/bukkit/event/vehicle/VehicleEntityCollisionEvent.java -@@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull; - * Raised when a vehicle collides with an entity. - */ - public class VehicleEntityCollisionEvent extends VehicleCollisionEvent implements Cancellable { -- private static final HandlerList handlers = new HandlerList(); -+ // private static final HandlerList handlers = new HandlerList(); // Paper - move HandlerList to VehicleCollisionEvent - private final Entity entity; - private boolean cancelled = false; - private boolean cancelledPickup = false; -@@ -51,15 +51,4 @@ public class VehicleEntityCollisionEvent extends VehicleCollisionEvent implement - public void setCollisionCancelled(boolean cancel) { - cancelledCollision = cancel; - } -- -- @NotNull -- @Override -- public HandlerList getHandlers() { -- return handlers; -- } -- -- @NotNull -- public static HandlerList getHandlerList() { -- return handlers; -- } - } diff --git a/patches/api/0345-WorldCreator-keepSpawnLoaded.patch b/patches/api/0345-WorldCreator-keepSpawnLoaded.patch new file mode 100644 index 000000000000..287c313c5887 --- /dev/null +++ b/patches/api/0345-WorldCreator-keepSpawnLoaded.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sat, 3 Jul 2021 21:18:41 +0100 +Subject: [PATCH] WorldCreator#keepSpawnLoaded + + +diff --git a/src/main/java/org/bukkit/WorldCreator.java b/src/main/java/org/bukkit/WorldCreator.java +index afc0ce2eaa7cf48d1255fec7377103b1f7a99734..58e3e3e0e772640b3944b4acb5a92d96431728a7 100644 +--- a/src/main/java/org/bukkit/WorldCreator.java ++++ b/src/main/java/org/bukkit/WorldCreator.java +@@ -23,7 +23,7 @@ public class WorldCreator { + private boolean generateStructures = true; + private String generatorSettings = ""; + private boolean hardcore = false; +- private boolean keepSpawnInMemory = true; ++ private net.kyori.adventure.util.TriState keepSpawnLoaded = net.kyori.adventure.util.TriState.NOT_SET; // Paper + + /** + * Creates an empty WorldCreationOptions for the given world name +@@ -123,7 +123,7 @@ public class WorldCreator { + type = world.getWorldType(); + generateStructures = world.canGenerateStructures(); + hardcore = world.isHardcore(); +- keepSpawnInMemory = world.getKeepSpawnInMemory(); ++ this.keepSpawnLoaded = net.kyori.adventure.util.TriState.byBoolean(world.getKeepSpawnInMemory()); // Paper + + return this; + } +@@ -146,7 +146,7 @@ public class WorldCreator { + generateStructures = creator.generateStructures(); + generatorSettings = creator.generatorSettings(); + hardcore = creator.hardcore(); +- keepSpawnInMemory = creator.keepSpawnInMemory(); ++ keepSpawnLoaded = creator.keepSpawnLoaded(); // Paper + + return this; + } +@@ -470,21 +470,23 @@ public class WorldCreator { + * + * @param keepSpawnInMemory Whether the spawn chunks will be kept loaded + * @return This object, for chaining ++ * @deprecated use {@link #keepSpawnLoaded(net.kyori.adventure.util.TriState)} + */ + @NotNull ++ @Deprecated(forRemoval = true) // Paper + public WorldCreator keepSpawnInMemory(boolean keepSpawnInMemory) { +- this.keepSpawnInMemory = keepSpawnInMemory; +- +- return this; ++ return this.keepSpawnLoaded(net.kyori.adventure.util.TriState.byBoolean(keepSpawnInMemory)); // Paper + } + + /** + * Gets whether or not the spawn chunks will be kept loaded. + * + * @return True if the spawn chunks will be kept loaded ++ * @deprecated use {@link #keepSpawnLoaded()} + */ ++ @Deprecated(forRemoval = true) // Paper + public boolean keepSpawnInMemory() { +- return keepSpawnInMemory; ++ return this.keepSpawnLoaded() == net.kyori.adventure.util.TriState.TRUE; // Paper + } + + /** +@@ -594,4 +596,31 @@ public class WorldCreator { + + return result; + } ++ ++ // Paper start - keep spawn loaded tristate ++ /** ++ * Returns the current intent to keep the world loaded, @see {@link WorldCreator#keepSpawnLoaded(net.kyori.adventure.util.TriState)} ++ * ++ * @return the current tristate value ++ */ ++ @NotNull ++ public net.kyori.adventure.util.TriState keepSpawnLoaded() { ++ return keepSpawnLoaded; ++ } ++ ++ /** ++ * Controls if a world should be kept loaded or not, default (NOT_SET) will use the servers standard ++ * configuration, otherwise, will act as an override towards this setting ++ * ++ * @param keepSpawnLoaded the new value ++ * @return This object, for chaining ++ */ ++ @NotNull ++ public WorldCreator keepSpawnLoaded(@NotNull net.kyori.adventure.util.TriState keepSpawnLoaded) { ++ Preconditions.checkArgument(keepSpawnLoaded != null, "keepSpawnLoaded"); ++ this.keepSpawnLoaded = keepSpawnLoaded; ++ return this; ++ } ++ ++ // Paper end - keep spawn loaded tristate + } diff --git a/patches/api/0346-Add-EntityDyeEvent-and-CollarColorable-interface.patch b/patches/api/0346-Add-EntityDyeEvent-and-CollarColorable-interface.patch new file mode 100644 index 000000000000..4d61563d3b8a --- /dev/null +++ b/patches/api/0346-Add-EntityDyeEvent-and-CollarColorable-interface.patch @@ -0,0 +1,270 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 18 Mar 2022 21:16:38 -0700 +Subject: [PATCH] Add EntityDyeEvent and CollarColorable interface + + +diff --git a/src/main/java/io/papermc/paper/entity/CollarColorable.java b/src/main/java/io/papermc/paper/entity/CollarColorable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..205b561c76386c02c827694b17ea50175a3c84ff +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/CollarColorable.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.entity; ++ ++import org.bukkit.DyeColor; ++import org.bukkit.entity.LivingEntity; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Entities that can have their collars colored. ++ */ ++@NullMarked ++public interface CollarColorable extends LivingEntity { ++ ++ /** ++ * Get the collar color of this entity ++ * ++ * @return the color of the collar ++ */ ++ DyeColor getCollarColor(); ++ ++ /** ++ * Set the collar color of this entity ++ * ++ * @param color the color to apply ++ */ ++ void setCollarColor(DyeColor color); ++} +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityDyeEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityDyeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..049471bac6c9b830fe7717c129173a723091963f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityDyeEvent.java +@@ -0,0 +1,82 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.DyeColor; ++import org.bukkit.entity.Cat; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.entity.Sheep; ++import org.bukkit.entity.Wolf; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when an entity is dyed. Currently, this is called for {@link Sheep} ++ * being dyed, and {@link Wolf}/{@link Cat} collars being dyed. ++ */ ++@NullMarked ++public class EntityDyeEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final @Nullable Player player; ++ private DyeColor dyeColor; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityDyeEvent(final Entity entity, final DyeColor dyeColor, final @Nullable Player player) { ++ super(entity); ++ this.dyeColor = dyeColor; ++ this.player = player; ++ } ++ ++ /** ++ * Gets the DyeColor the entity is being dyed ++ * ++ * @return the DyeColor the entity is being dyed ++ */ ++ public DyeColor getColor() { ++ return this.dyeColor; ++ } ++ ++ /** ++ * Sets the DyeColor the entity is being dyed ++ * ++ * @param dyeColor the DyeColor the entity will be dyed ++ */ ++ public void setColor(final DyeColor dyeColor) { ++ this.dyeColor = dyeColor; ++ } ++ ++ /** ++ * Returns the player dyeing the entity, if available. ++ * ++ * @return player or {@code null} ++ */ ++ public @Nullable Player getPlayer() { ++ return this.player; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Cat.java b/src/main/java/org/bukkit/entity/Cat.java +index 5101553bb71d60fee7ac234f7ef2863781dd7742..de422f00f8fd1975669ee5431c466c9c16d699af 100644 +--- a/src/main/java/org/bukkit/entity/Cat.java ++++ b/src/main/java/org/bukkit/entity/Cat.java +@@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Meow. + */ +-public interface Cat extends Tameable, Sittable { ++public interface Cat extends Tameable, Sittable, io.papermc.paper.entity.CollarColorable { // Paper - CollarColorable + + /** + * Gets the current type of this cat. +@@ -36,6 +36,7 @@ public interface Cat extends Tameable, Sittable { + * @return the color of the collar + */ + @NotNull ++ @Override // Paper + public DyeColor getCollarColor(); + + /** +@@ -43,6 +44,7 @@ public interface Cat extends Tameable, Sittable { + * + * @param color the color to apply + */ ++ @Override // Paper + public void setCollarColor(@NotNull DyeColor color); + + /** +diff --git a/src/main/java/org/bukkit/entity/Wolf.java b/src/main/java/org/bukkit/entity/Wolf.java +index 91e96ee5362fd71d28deef1687ebeb0d8dfa05b9..c73489f4b745bc84501ce94f0227b034d9768eae 100644 +--- a/src/main/java/org/bukkit/entity/Wolf.java ++++ b/src/main/java/org/bukkit/entity/Wolf.java +@@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents a Wolf + */ +-public interface Wolf extends Tameable, Sittable { ++public interface Wolf extends Tameable, Sittable, io.papermc.paper.entity.CollarColorable { // Paper - CollarColorable + + /** + * Checks if this wolf is angry +@@ -34,6 +34,7 @@ public interface Wolf extends Tameable, Sittable { + * @return the color of the collar + */ + @NotNull ++ @Override // Paper + public DyeColor getCollarColor(); + + /** +@@ -41,6 +42,7 @@ public interface Wolf extends Tameable, Sittable { + * + * @param color the color to apply + */ ++ @Override // Paper + public void setCollarColor(@NotNull DyeColor color); + + /** +diff --git a/src/main/java/org/bukkit/event/entity/SheepDyeWoolEvent.java b/src/main/java/org/bukkit/event/entity/SheepDyeWoolEvent.java +index d93a7efd0f6231dbb02fedc4a9108b7cb1d86838..5d056d6bcb0fec0a4ec0aedc3ce9cb52a33934d3 100644 +--- a/src/main/java/org/bukkit/event/entity/SheepDyeWoolEvent.java ++++ b/src/main/java/org/bukkit/event/entity/SheepDyeWoolEvent.java +@@ -11,11 +11,8 @@ import org.jetbrains.annotations.Nullable; + /** + * Called when a sheep's wool is dyed + */ +-public class SheepDyeWoolEvent extends EntityEvent implements Cancellable { +- private static final HandlerList handlers = new HandlerList(); +- private boolean cancel; +- private DyeColor color; +- private final Player player; ++public class SheepDyeWoolEvent extends io.papermc.paper.event.entity.EntityDyeEvent implements Cancellable { ++ // Paper - move everything to superclass + + @Deprecated(since = "1.17.1") + public SheepDyeWoolEvent(@NotNull final Sheep sheep, @NotNull final DyeColor color) { +@@ -23,20 +20,7 @@ public class SheepDyeWoolEvent extends EntityEvent implements Cancellable { + } + + public SheepDyeWoolEvent(@NotNull final Sheep sheep, @NotNull final DyeColor color, @Nullable Player player) { +- super(sheep); +- this.cancel = false; +- this.color = color; +- this.player = player; +- } +- +- @Override +- public boolean isCancelled() { +- return cancel; +- } +- +- @Override +- public void setCancelled(boolean cancel) { +- this.cancel = cancel; ++ super(sheep, color, player); // Paper + } + + @NotNull +@@ -44,45 +28,4 @@ public class SheepDyeWoolEvent extends EntityEvent implements Cancellable { + public Sheep getEntity() { + return (Sheep) entity; + } +- +- /** +- * Returns the player dyeing the sheep, if available. +- * +- * @return player or null +- */ +- @Nullable +- public Player getPlayer() { +- return player; +- } +- +- /** +- * Gets the DyeColor the sheep is being dyed +- * +- * @return the DyeColor the sheep is being dyed +- */ +- @NotNull +- public DyeColor getColor() { +- return color; +- } +- +- /** +- * Sets the DyeColor the sheep is being dyed +- * +- * @param color the DyeColor the sheep will be dyed +- */ +- public void setColor(@NotNull DyeColor color) { +- this.color = color; +- } +- +- @NotNull +- @Override +- public HandlerList getHandlers() { +- return handlers; +- } +- +- @NotNull +- public static HandlerList getHandlerList() { +- return handlers; +- } +- + } diff --git a/patches/api/0346-Improve-scoreboard-entries.patch b/patches/api/0346-Improve-scoreboard-entries.patch deleted file mode 100644 index fb74c25fd320..000000000000 --- a/patches/api/0346-Improve-scoreboard-entries.patch +++ /dev/null @@ -1,191 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 4 Nov 2021 12:31:45 -0700 -Subject: [PATCH] Improve scoreboard entries - - -diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java -index 75acd6f8f3d774bb79e8e513125e801c5569a244..b93b1b0428d11589605c8edf5c053369e1031076 100644 ---- a/src/main/java/org/bukkit/scoreboard/Objective.java -+++ b/src/main/java/org/bukkit/scoreboard/Objective.java -@@ -140,9 +140,8 @@ public interface Objective { - * @throws IllegalArgumentException if player is null - * @throws IllegalStateException if this objective has been unregistered - * @see #getScore(String) -- * @deprecated Scoreboards can contain entries that aren't players - */ -- @Deprecated -+ // @Deprecated // Paper - @NotNull - Score getScore(@NotNull OfflinePlayer player) throws IllegalArgumentException, IllegalStateException; - -@@ -157,4 +156,16 @@ public interface Objective { - */ - @NotNull - Score getScore(@NotNull String entry) throws IllegalArgumentException, IllegalStateException; -+ -+ // Paper start -+ /** -+ * Gets an entity's Score for an Objective on this Scoreboard. -+ * -+ * @param entity Entity for the Score -+ * @return Score tracking the Objective and entity specified -+ * @throws IllegalArgumentException if entity is null -+ * @throws IllegalStateException if this objective has been unregistered -+ */ -+ @NotNull Score getScoreFor(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException; -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/scoreboard/Scoreboard.java b/src/main/java/org/bukkit/scoreboard/Scoreboard.java -index 1ada91d790abedbc9b3aeb6e96467a0d78560f15..fc3456bb79f2fe1504359455b937c162780110c2 100644 ---- a/src/main/java/org/bukkit/scoreboard/Scoreboard.java -+++ b/src/main/java/org/bukkit/scoreboard/Scoreboard.java -@@ -163,9 +163,8 @@ public interface Scoreboard { - * @return immutable set of all scores tracked for the player - * @throws IllegalArgumentException if player is null - * @see #getScores(String) -- * @deprecated Scoreboards can contain entries that aren't players - */ -- @Deprecated -+ // @Deprecated // Paper - @NotNull - Set getScores(@NotNull OfflinePlayer player) throws IllegalArgumentException; - -@@ -185,9 +184,8 @@ public interface Scoreboard { - * @param player the player to drop all current scores for - * @throws IllegalArgumentException if player is null - * @see #resetScores(String) -- * @deprecated Scoreboards can contain entries that aren't players - */ -- @Deprecated -+ // @Deprecated // Paper - void resetScores(@NotNull OfflinePlayer player) throws IllegalArgumentException; - - /** -@@ -205,9 +203,8 @@ public interface Scoreboard { - * @return the player's Team or null if the player is not on a team - * @throws IllegalArgumentException if player is null - * @see #getEntryTeam(String) -- * @deprecated Scoreboards can contain entries that aren't players - */ -- @Deprecated -+ // @Deprecated // Paper - @Nullable - Team getPlayerTeam(@NotNull OfflinePlayer player) throws IllegalArgumentException; - -@@ -276,4 +273,35 @@ public interface Scoreboard { - * @throws IllegalArgumentException if slot is null - */ - void clearSlot(@NotNull DisplaySlot slot) throws IllegalArgumentException; -+ -+ // Paper start -+ /** -+ * Gets all scores for a entity on this Scoreboard -+ * -+ * @param entity the entity whose scores are being retrieved -+ * @return immutable set of all scores tracked for the entity -+ * @throws IllegalArgumentException if entity is null -+ * @see #getScores(String) -+ */ -+ @NotNull Set getScoresFor(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException; -+ -+ /** -+ * Removes all scores for a entity on this Scoreboard -+ * -+ * @param entity the entity to drop all current scores for -+ * @throws IllegalArgumentException if entity is null -+ * @see #resetScores(String) -+ */ -+ void resetScoresFor(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException; -+ -+ /** -+ * Gets a entity's Team on this Scoreboard -+ * -+ * @param entity the entity to search for -+ * @return the entity's Team or null if the entity is not on a team -+ * @throws IllegalArgumentException if entity is null -+ * @see #getEntryTeam(String) -+ */ -+ @Nullable Team getEntityTeam(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException; -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java -index 47b10df619ad2520b9bb673e2220f36391680f1b..cbc82a03c24f746b913b30f14ecb0c08cdb42c24 100644 ---- a/src/main/java/org/bukkit/scoreboard/Team.java -+++ b/src/main/java/org/bukkit/scoreboard/Team.java -@@ -308,9 +308,8 @@ public interface Team { - * @throws IllegalArgumentException if player is null - * @throws IllegalStateException if this team has been unregistered - * @see #addEntry(String) -- * @deprecated Teams can contain entries that aren't players - */ -- @Deprecated -+ // @Deprecated // Paper - void addPlayer(@NotNull OfflinePlayer player) throws IllegalStateException, IllegalArgumentException; - - /** -@@ -332,9 +331,8 @@ public interface Team { - * @throws IllegalArgumentException if player is null - * @throws IllegalStateException if this team has been unregistered - * @see #removeEntry(String) -- * @deprecated Teams can contain entries that aren't players - */ -- @Deprecated -+ // @Deprecated // Paper - boolean removePlayer(@NotNull OfflinePlayer player) throws IllegalStateException, IllegalArgumentException; - - /** -@@ -362,9 +360,8 @@ public interface Team { - * @throws IllegalArgumentException if player is null - * @throws IllegalStateException if this team has been unregistered - * @see #hasEntry(String) -- * @deprecated Teams can contain entries that aren't players - */ -- @Deprecated -+ // @Deprecated // Paper - boolean hasPlayer(@NotNull OfflinePlayer player) throws IllegalArgumentException, IllegalStateException; - /** - * Checks to see if the specified entry is a member of this team. -@@ -395,6 +392,42 @@ public interface Team { - */ - void setOption(@NotNull Option option, @NotNull OptionStatus status) throws IllegalStateException; - -+ // Paper start -+ /** -+ * This puts the specified entity onto this team for the scoreboard. -+ *

      -+ * This will remove the entity from any other team on the scoreboard. -+ * -+ * @param entity the entity to add -+ * @throws IllegalArgumentException if entity is null -+ * @throws IllegalStateException if this team has been unregistered -+ * @see #addEntry(String) -+ */ -+ void addEntity(@NotNull org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException; -+ -+ /** -+ * Removes the entity from this team. -+ * -+ * @param entity the entity to remove -+ * @return if the entity was on this team -+ * @throws IllegalArgumentException if entity is null -+ * @throws IllegalStateException if this team has been unregistered -+ * @see #removeEntry(String) -+ */ -+ boolean removeEntity(@NotNull org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException; -+ -+ /** -+ * Checks to see if the specified entity is a member of this team. -+ * -+ * @param entity the entity to search for -+ * @return true if the entity is a member of this team -+ * @throws IllegalArgumentException if entity is null -+ * @throws IllegalStateException if this team has been unregistered -+ * @see #hasEntry(String) -+ */ -+ boolean hasEntity(@NotNull org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException; -+ // Paper end -+ - /** - * Represents an option which may be applied to this team. - */ diff --git a/patches/api/0347-Add-PlayerStopUsingItemEvent.patch b/patches/api/0347-Add-PlayerStopUsingItemEvent.patch new file mode 100644 index 000000000000..c4f27c29257d --- /dev/null +++ b/patches/api/0347-Add-PlayerStopUsingItemEvent.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: u9g +Date: Tue, 3 May 2022 20:41:30 -0400 +Subject: [PATCH] Add PlayerStopUsingItemEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerStopUsingItemEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerStopUsingItemEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d79b995292799853a0874d4e113e68b494167242 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerStopUsingItemEvent.java +@@ -0,0 +1,53 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when the server detects a player stopping using an item. ++ * Examples of this are letting go of the interact button when holding a bow, an edible item, or a spyglass. ++ */ ++@NullMarked ++public class PlayerStopUsingItemEvent extends PlayerEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ItemStack item; ++ private final int ticksHeldFor; ++ ++ public PlayerStopUsingItemEvent(final Player player, final ItemStack item, final int ticksHeldFor) { ++ super(player); ++ this.item = item; ++ this.ticksHeldFor = ticksHeldFor; ++ } ++ ++ /** ++ * Gets the exact item the player is releasing ++ * ++ * @return ItemStack the exact item the player released ++ */ ++ public ItemStack getItem() { ++ return this.item; ++ } ++ ++ /** ++ * Gets the number of ticks the item was held for ++ * ++ * @return int the number of ticks the item was held for ++ */ ++ public int getTicksHeldFor() { ++ return this.ticksHeldFor; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0347-Entity-powdered-snow-API.patch b/patches/api/0347-Entity-powdered-snow-API.patch deleted file mode 100644 index 88414bd4ef1f..000000000000 --- a/patches/api/0347-Entity-powdered-snow-API.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 24 Oct 2021 20:58:52 -0700 -Subject: [PATCH] Entity powdered snow API - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 9b46e42fcd803c2f0fb46b220ed79d69b1d16fc4..9c31424a297b9b727ac4ad13040eb9e5674b716b 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -802,5 +802,12 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - * @return Whether the entity was successfully spawned. - */ - public boolean spawnAt(@NotNull Location location, @NotNull org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason); -+ -+ /** -+ * Check if entity is inside powdered snow. -+ * -+ * @return true if in powdered snow. -+ */ -+ boolean isInPowderedSnow(); - // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/Skeleton.java b/src/main/java/org/bukkit/entity/Skeleton.java -index 01d838a60d056bf4b4a8ef9d0ac18c6f91f412e6..c61eba5f400d146a8643542048904e353df94f4b 100644 ---- a/src/main/java/org/bukkit/entity/Skeleton.java -+++ b/src/main/java/org/bukkit/entity/Skeleton.java -@@ -41,6 +41,16 @@ public interface Skeleton extends AbstractSkeleton { - */ - void setConversionTime(int time); - -+ // Paper start -+ /** -+ * Gets the time the skeleton -+ * has been inside powdered snow. -+ * -+ * @return time in ticks -+ */ -+ int inPowderedSnowTime(); -+ // Paper end -+ - /** - * A legacy enum that defines the different variances of skeleton-like - * entities on the server. diff --git a/patches/api/0348-Add-API-for-item-entity-health.patch b/patches/api/0348-Add-API-for-item-entity-health.patch deleted file mode 100644 index 94373dbdf270..000000000000 --- a/patches/api/0348-Add-API-for-item-entity-health.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 28 Aug 2021 09:00:35 -0700 -Subject: [PATCH] Add API for item entity health - - -diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java -index 48858e1c58c13d786bbc935abedb0f059837833c..d0bef15785493b512ff0f7414c1d58d38fead581 100644 ---- a/src/main/java/org/bukkit/entity/Item.java -+++ b/src/main/java/org/bukkit/entity/Item.java -@@ -133,5 +133,24 @@ public interface Item extends Entity { - * @param willAge True if the item should age - */ - public void setWillAge(boolean willAge); -+ -+ /** -+ * Gets the health of item stack. -+ *

      -+ * Currently the default max health is 5. -+ * -+ * @return the health -+ */ -+ public int getHealth(); -+ -+ /** -+ * Sets the health of the item stack. If the value is non-positive -+ * the itemstack's normal "on destroy" functionality will be run. -+ *

      -+ * Currently, the default max health is 5. -+ * -+ * @param health the health, a non-positive value will destroy the entity -+ */ -+ public void setHealth(int health); - // Paper end - } diff --git a/patches/api/0348-Expand-FallingBlock-API.patch b/patches/api/0348-Expand-FallingBlock-API.patch new file mode 100644 index 000000000000..14bfc4015624 --- /dev/null +++ b/patches/api/0348-Expand-FallingBlock-API.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 5 Dec 2021 14:58:55 -0500 +Subject: [PATCH] Expand FallingBlock API + +- add auto expire setting +- add setter for block data +- add accessors for block state + +Co-authored-by: Lukas Planz + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 0f01e87c1f09f2291d12eaac7f12b32ca543c82f..8bfa8db3d0fdbe0c26e3b327d134c6c0af6be206 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -2281,8 +2281,10 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + * @return The spawned {@link FallingBlock} instance + * @throws IllegalArgumentException if {@link Location} or {@link + * MaterialData} are null or {@link Material} of the {@link MaterialData} is not a block ++ * @deprecated Use {@link #spawn(Location, Class, Consumer)} (or a variation thereof) in combination with {@link FallingBlock#setBlockData(BlockData)} + */ + @NotNull ++ @Deprecated(since = "1.20.2") // Paper + public FallingBlock spawnFallingBlock(@NotNull Location location, @NotNull MaterialData data) throws IllegalArgumentException; + + /** +@@ -2295,8 +2297,10 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + * @return The spawned {@link FallingBlock} instance + * @throws IllegalArgumentException if {@link Location} or {@link + * BlockData} are null ++ * @deprecated Use {@link #spawn(Location, Class, Consumer)} (or a variation thereof) in combination with {@link FallingBlock#setBlockData(BlockData)} + */ + @NotNull ++ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.20.2") // Paper + public FallingBlock spawnFallingBlock(@NotNull Location location, @NotNull BlockData data) throws IllegalArgumentException; + + /** +@@ -2313,7 +2317,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + * @return The spawned {@link FallingBlock} instance + * @throws IllegalArgumentException if {@link Location} or {@link + * Material} are null or {@link Material} is not a block +- * @deprecated Magic value ++ * @deprecated Magic value. Use {@link #spawn(Location, Class, Consumer)} (or a variation thereof) in combination with {@link FallingBlock#setBlockData(BlockData)} + */ + @Deprecated(since = "1.7.5") + @NotNull +diff --git a/src/main/java/org/bukkit/entity/FallingBlock.java b/src/main/java/org/bukkit/entity/FallingBlock.java +index 315dcf9da29e077a819f602ebf1c76286164b264..f4ec235b9ccc81e8482f721783561313d160629b 100644 +--- a/src/main/java/org/bukkit/entity/FallingBlock.java ++++ b/src/main/java/org/bukkit/entity/FallingBlock.java +@@ -26,6 +26,33 @@ public interface FallingBlock extends Entity { + */ + @NotNull + BlockData getBlockData(); ++ // Paper start ++ /** ++ * Sets the data for the falling block. ++ *
      ++ * Any potential additional data currently stored in the falling blocks {@link #getBlockState()} will be ++ * purged by calling this setter. ++ * ++ * @param blockData the data to use as the block ++ */ ++ void setBlockData(@NotNull BlockData blockData); ++ ++ /** ++ * Get the data of the falling block represented as a {@link org.bukkit.block.BlockState BlockState} ++ * which includes potential NBT data that gets applied when the block gets placed on landing. ++ * ++ * @return the BlockState representing this block ++ */ ++ @NotNull ++ org.bukkit.block.BlockState getBlockState(); ++ ++ /** ++ * Sets the {@link BlockData} and possibly present tile entity data for the falling block. ++ * ++ * @param blockState the BlockState to use ++ */ ++ void setBlockState(@NotNull org.bukkit.block.BlockState blockState); ++ // Paper end + + /** + * Get if the falling block will break into an item if it cannot be placed. +@@ -137,4 +164,23 @@ public interface FallingBlock extends Entity { + default org.bukkit.Location getSourceLoc() { + return this.getOrigin(); + } ++ // Paper start - Auto expire setting ++ /** ++ * Sets if this falling block should expire after: ++ * - 30 seconds ++ * - 5 seconds and is outside of the world ++ * ++ * @return if this behavior occurs ++ */ ++ boolean doesAutoExpire(); ++ ++ /** ++ * Sets if this falling block should expire after: ++ * - 30 seconds ++ * - 5 seconds and is outside of the world ++ * ++ * @param autoExpires if this behavior should occur ++ */ ++ void shouldAutoExpire(boolean autoExpires); ++ // Paper end - Auto expire setting + } diff --git a/patches/api/0349-Add-method-isTickingWorlds-to-Bukkit.patch b/patches/api/0349-Add-method-isTickingWorlds-to-Bukkit.patch new file mode 100644 index 000000000000..e328c2a07628 --- /dev/null +++ b/patches/api/0349-Add-method-isTickingWorlds-to-Bukkit.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BuildTools <46540330+willkroboth@users.noreply.github.com> +Date: Fri, 19 Aug 2022 16:11:51 -0400 +Subject: [PATCH] Add method isTickingWorlds() to Bukkit. + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 9be54f481a14bc917b465fdef3c2695d8ee64880..629d062b76ff4186cc5c824b1bdcafe3667b50fe 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -809,12 +809,26 @@ public final class Bukkit { + return server.getWorlds(); + } + ++ // Paper start ++ /** ++ * Gets whether the worlds are being ticked right now. ++ * ++ * @return true if the worlds are being ticked, false otherwise. ++ */ ++ public static boolean isTickingWorlds(){ ++ return server.isTickingWorlds(); ++ } ++ // Paper end ++ + /** + * Creates or loads a world with the given name using the specified + * options. + *

      + * If the world is already loaded, it will just return the equivalent of + * getWorld(creator.name()). ++ *

      ++ * Do note that un/loading worlds mid-tick may have potential side effects, we strongly recommend ++ * ensuring that you're not un/loading worlds midtick by checking {@link Bukkit#isTickingWorlds()} + * + * @param creator the options to use when creating the world + * @return newly created or loaded world +@@ -826,6 +840,9 @@ public final class Bukkit { + + /** + * Unloads a world with the given name. ++ *

      ++ * Do note that un/loading worlds mid-tick may have potential side effects, we strongly recommend ++ * ensuring that you're not un/loading worlds midtick by checking {@link Bukkit#isTickingWorlds()} + * + * @param name Name of the world to unload + * @param save whether to save the chunks before unloading +@@ -837,6 +854,9 @@ public final class Bukkit { + + /** + * Unloads the given world. ++ *

      ++ * Do note that un/loading worlds mid-tick may have potential side effects, we strongly recommend ++ * ensuring that you're not un/loading worlds midtick by checking {@link Bukkit#isTickingWorlds()} + * + * @param world the world to unload + * @param save whether to save the chunks before unloading +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 0da9cee02e2a77e16e3bfaec2197bfc567f5580a..3f21dfaaa8a6575c9f9b0d33b60fb9913fec8987 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -679,34 +679,55 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @NotNull + public List getWorlds(); + ++ // Paper start ++ /** ++ * Gets whether the worlds are being ticked right now. ++ * ++ * @return true if the worlds are being ticked, false otherwise. ++ */ ++ public boolean isTickingWorlds(); ++ // Paper end ++ + /** + * Creates or loads a world with the given name using the specified + * options. + *

      + * If the world is already loaded, it will just return the equivalent of + * getWorld(creator.name()). ++ *

      ++ * Do note that un/loading worlds mid-tick may have potential side effects, we strongly recommend ++ * ensuring that you're not un/loading worlds midtick by checking {@link Bukkit#isTickingWorlds()} + * + * @param creator the options to use when creating the world + * @return newly created or loaded world ++ * @throws IllegalStateException when {@link #isTickingWorlds() isTickingWorlds} is true + */ + @Nullable + public World createWorld(@NotNull WorldCreator creator); + + /** + * Unloads a world with the given name. ++ *

      ++ * Do note that un/loading worlds mid-tick may have potential side effects, we strongly recommend ++ * ensuring that you're not un/loading worlds midtick by checking {@link Bukkit#isTickingWorlds()} + * + * @param name Name of the world to unload + * @param save whether to save the chunks before unloading + * @return true if successful, false otherwise ++ * @throws IllegalStateException when {@link #isTickingWorlds() isTickingWorlds} is true + */ + public boolean unloadWorld(@NotNull String name, boolean save); + + /** + * Unloads the given world. ++ *

      ++ * Do note that un/loading worlds mid-tick may have potential side effects, we strongly recommend ++ * ensuring that you're not un/loading worlds midtick by checking {@link Bukkit#isTickingWorlds()} + * + * @param world the world to unload + * @param save whether to save the chunks before unloading + * @return true if successful, false otherwise ++ * @throws IllegalStateException when {@link #isTickingWorlds() isTickingWorlds} is true + */ + public boolean unloadWorld(@NotNull World world, boolean save); + diff --git a/patches/api/0350-Add-WardenAngerChangeEvent.patch b/patches/api/0350-Add-WardenAngerChangeEvent.patch new file mode 100644 index 000000000000..d37a8bcb838f --- /dev/null +++ b/patches/api/0350-Add-WardenAngerChangeEvent.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: nopjar +Date: Sun, 12 Jun 2022 00:56:45 +0200 +Subject: [PATCH] Add WardenAngerChangeEvent + +Adding a event which gets called when a warden is angered by +another entity. + +diff --git a/src/main/java/io/papermc/paper/event/entity/WardenAngerChangeEvent.java b/src/main/java/io/papermc/paper/event/entity/WardenAngerChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7c06de67121f92f6e1e8890f250157721c78e627 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/WardenAngerChangeEvent.java +@@ -0,0 +1,103 @@ ++package io.papermc.paper.event.entity; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Warden; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Range; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a Warden's anger level has changed due to another entity. ++ *

      ++ * If the event is cancelled, the warden's anger level will not change. ++ */ ++@NullMarked ++public class WardenAngerChangeEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Entity target; ++ private final int oldAnger; ++ private int newAnger; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public WardenAngerChangeEvent(final Warden warden, final Entity target, final int oldAnger, final int newAnger) { ++ super(warden); ++ this.target = target; ++ this.oldAnger = oldAnger; ++ this.newAnger = newAnger; ++ } ++ ++ /** ++ * Gets the entity which triggered this anger update. ++ * ++ * @return triggering entity ++ */ ++ public Entity getTarget() { ++ return this.target; ++ } ++ ++ /** ++ * Gets the old anger level. ++ * ++ * @return old anger level ++ * @see Warden#getAnger(Entity) ++ */ ++ public @Range(from = 0, to = 150) int getOldAnger() { ++ return this.oldAnger; ++ } ++ ++ /** ++ * Gets the new anger level resulting from this event. ++ * ++ * @return new anger level ++ * @see Warden#getAnger(Entity) ++ */ ++ public @Range(from = 0, to = 150) int getNewAnger() { ++ return this.newAnger; ++ } ++ ++ /** ++ * Sets the new anger level resulting from this event. ++ *

      ++ * The anger of a warden is capped at 150. ++ * ++ * @param newAnger the new anger level, max 150 ++ * @throws IllegalArgumentException if newAnger is greater than 150 ++ * @see Warden#setAnger(Entity, int) ++ */ ++ public void setNewAnger(final @Range(from = 0, to = 150) int newAnger) { ++ Preconditions.checkArgument(newAnger <= 150, "newAnger must not be greater than 150"); ++ this.newAnger = newAnger; ++ } ++ ++ @Override ++ public Warden getEntity() { ++ return (Warden) super.getEntity(); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0350-Bucketable-API.patch b/patches/api/0350-Bucketable-API.patch deleted file mode 100644 index 26dbdc9f5dc2..000000000000 --- a/patches/api/0350-Bucketable-API.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 26 Dec 2021 14:03:11 -0500 -Subject: [PATCH] Bucketable API - - -diff --git a/src/main/java/io/papermc/paper/entity/Bucketable.java b/src/main/java/io/papermc/paper/entity/Bucketable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..84e360a16de956834a91142d45e4b5a0fe3d3a92 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/entity/Bucketable.java -@@ -0,0 +1,42 @@ -+package io.papermc.paper.entity; -+ -+import org.bukkit.Sound; -+import org.bukkit.entity.Entity; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Represents an entity that can be bucketed. -+ */ -+public interface Bucketable extends Entity { -+ -+ /** -+ * Gets if this entity originated from a bucket. -+ * -+ * @return originated from bucket -+ */ -+ boolean isFromBucket(); -+ -+ /** -+ * Sets if this entity originated from a bucket. -+ * -+ * @param fromBucket is from a bucket -+ */ -+ void setFromBucket(boolean fromBucket); -+ -+ /** -+ * Gets the base itemstack of this entity in a bucket form. -+ * -+ * @return bucket form -+ */ -+ @NotNull -+ ItemStack getBaseBucketItem(); -+ -+ /** -+ * Gets the sound that is played when this entity -+ * is picked up in a bucket. -+ * @return bucket pickup sound -+ */ -+ @NotNull -+ Sound getPickupSound(); -+} -diff --git a/src/main/java/org/bukkit/entity/Axolotl.java b/src/main/java/org/bukkit/entity/Axolotl.java -index 9763f3b9ac8f32c082a476f4b50a32622b2720a0..c8c738b1b72e9ad89d97b7a1f5450d58045a72ca 100644 ---- a/src/main/java/org/bukkit/entity/Axolotl.java -+++ b/src/main/java/org/bukkit/entity/Axolotl.java -@@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; - /** - * An Axolotl. - */ --public interface Axolotl extends Animals { -+public interface Axolotl extends Animals, io.papermc.paper.entity.Bucketable { // Paper - Bucketable API - - /** - * Gets if this axolotl is playing dead. -diff --git a/src/main/java/org/bukkit/entity/Fish.java b/src/main/java/org/bukkit/entity/Fish.java -index 82e390b2152e7c881006ca30f2527d160c01f8a1..86da8dc401ed7db19a39bc682721055cd341ccde 100644 ---- a/src/main/java/org/bukkit/entity/Fish.java -+++ b/src/main/java/org/bukkit/entity/Fish.java -@@ -3,4 +3,4 @@ package org.bukkit.entity; - /** - * Represents a fish entity. - */ --public interface Fish extends WaterMob { } -+public interface Fish extends WaterMob, io.papermc.paper.entity.Bucketable { } // Paper - Bucketable API diff --git a/patches/api/0385-Nameable-Banner-API.patch b/patches/api/0351-Nameable-Banner-API.patch similarity index 100% rename from patches/api/0385-Nameable-Banner-API.patch rename to patches/api/0351-Nameable-Banner-API.patch diff --git a/patches/api/0351-System-prop-for-default-config-comment-parsing.patch b/patches/api/0351-System-prop-for-default-config-comment-parsing.patch deleted file mode 100644 index 632f71e519a8..000000000000 --- a/patches/api/0351-System-prop-for-default-config-comment-parsing.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 30 Dec 2021 16:35:56 -0800 -Subject: [PATCH] System prop for default config comment parsing - -Allows for certain legacy plugins to continue to work without changing -by setting `Paper.parseYamlCommentsByDefault` to false - -diff --git a/src/main/java/org/bukkit/configuration/file/FileConfigurationOptions.java b/src/main/java/org/bukkit/configuration/file/FileConfigurationOptions.java -index c71f8a7b96fc5abc499802a79fcb3b0771de021c..121dbbf163588690d0678ae73a6ab8edf82f8367 100644 ---- a/src/main/java/org/bukkit/configuration/file/FileConfigurationOptions.java -+++ b/src/main/java/org/bukkit/configuration/file/FileConfigurationOptions.java -@@ -15,7 +15,10 @@ import org.jetbrains.annotations.Nullable; - public class FileConfigurationOptions extends MemoryConfigurationOptions { - private List header = Collections.emptyList(); - private List footer = Collections.emptyList(); -- private boolean parseComments = true; -+ // Paper start - add system prop for comment parsing -+ private static final boolean PAPER_PARSE_COMMENTS_BY_DEFAULT = Boolean.parseBoolean(System.getProperty("Paper.parseYamlCommentsByDefault", "true")); -+ private boolean parseComments = PAPER_PARSE_COMMENTS_BY_DEFAULT; -+ // Paper end - - protected FileConfigurationOptions(@NotNull MemoryConfiguration configuration) { - super(configuration); diff --git a/patches/api/0352-Add-Player-getFishHook.patch b/patches/api/0352-Add-Player-getFishHook.patch new file mode 100644 index 000000000000..fc0e0e4157a3 --- /dev/null +++ b/patches/api/0352-Add-Player-getFishHook.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: u9g +Date: Tue, 14 Jun 2022 19:35:21 -0400 +Subject: [PATCH] Add Player#getFishHook + + +diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java +index 10576d39e019c0ca6bbd07b889a4580b2883d875..188c8e27d724a1593dc586b58c7dcb74a1b3d926 100644 +--- a/src/main/java/org/bukkit/entity/HumanEntity.java ++++ b/src/main/java/org/bukkit/entity/HumanEntity.java +@@ -425,6 +425,13 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder + @Nullable + public Location getPotentialBedLocation(); + // Paper end ++ // Paper start ++ /** ++ * @return the player's fishing hook if they are fishing ++ */ ++ @Nullable ++ FishHook getFishHook(); ++ // Paper end + + /** + * Attempts to make the entity sleep at the given location. diff --git a/patches/api/0353-More-Teleport-API.patch b/patches/api/0353-More-Teleport-API.patch new file mode 100644 index 000000000000..7a4a14cfda81 --- /dev/null +++ b/patches/api/0353-More-Teleport-API.patch @@ -0,0 +1,309 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 5 Sep 2021 00:36:05 -0400 +Subject: [PATCH] More Teleport API + + +diff --git a/src/main/java/io/papermc/paper/entity/LookAnchor.java b/src/main/java/io/papermc/paper/entity/LookAnchor.java +new file mode 100644 +index 0000000000000000000000000000000000000000..544eec787ea837f7d29df6519255840d6fe087d7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/LookAnchor.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.entity; ++ ++import io.papermc.paper.math.Position; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.LivingEntity; ++ ++/** ++ * Represents what part of the entity should be used when determining where to face a position/entity. ++ * ++ * @see org.bukkit.entity.Player#lookAt(Position, LookAnchor) ++ * @see org.bukkit.entity.Player#lookAt(Entity, LookAnchor, LookAnchor) ++ */ ++public enum LookAnchor { ++ /** ++ * Represents the entity's feet. ++ * @see LivingEntity#getLocation() ++ */ ++ FEET, ++ /** ++ * Represents the entity's eyes. ++ * @see LivingEntity#getEyeLocation() ++ */ ++ EYES; ++} +diff --git a/src/main/java/io/papermc/paper/entity/TeleportFlag.java b/src/main/java/io/papermc/paper/entity/TeleportFlag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9dbbe1f3cfda3b1862fd9cf1ef9853329eda750c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/TeleportFlag.java +@@ -0,0 +1,113 @@ ++package io.papermc.paper.entity; ++ ++import org.bukkit.Location; ++import org.bukkit.event.player.PlayerTeleportEvent; ++ ++/** ++ * Represents a flag that can be set on teleportation that may ++ * slightly modify the behavior. ++ * ++ * @see EntityState ++ * @see Relative ++ */ ++public sealed interface TeleportFlag permits TeleportFlag.EntityState, TeleportFlag.Relative { ++ ++ /** ++ * Note: These flags only work on {@link org.bukkit.entity.Player} entities. ++ *

      ++ * Relative flags enable a player to not lose their velocity in the flag-specific axis/context when teleporting. ++ * ++ * @apiNote The relative flags exposed in the API do *not* mirror all flags known to vanilla, as relative flags concerning ++ * the position are non-applicable given teleports always expect an absolute location. ++ * @see org.bukkit.entity.Player#teleport(Location, PlayerTeleportEvent.TeleportCause, TeleportFlag...) ++ */ ++ enum Relative implements TeleportFlag { ++ /** ++ * Configures the player to not lose velocity in their x axis during the teleport. ++ */ ++ VELOCITY_X, ++ /** ++ * Configures the player to not lose velocity in their y axis during the teleport. ++ */ ++ VELOCITY_Y, ++ /** ++ * Configures the player to not lose velocity in their z axis during the teleport. ++ */ ++ VELOCITY_Z, ++ /** ++ * Configures the player to not lose velocity in their current rotation during the teleport. ++ */ ++ VELOCITY_ROTATION; ++ /** ++ * Configures the player to not loose velocity in their x axis during the teleport. ++ * @deprecated Since 1.21.3, vanilla split up the relative teleport flags into velocity and position related ++ * ones. As the API does not deal with position relative flags, this name is no longer applicable. ++ * Use {@link #VELOCITY_X} instead. ++ */ ++ @Deprecated(since = "1.21.3", forRemoval = true) ++ public static final Relative X = VELOCITY_X; ++ /** ++ * Configures the player to not loose velocity in their y axis during the teleport. ++ * @deprecated Since 1.21.3, vanilla split up the relative teleport flags into velocity and position related ++ * ones. As the API does not deal with position relative flags, this name is no longer applicable. ++ * Use {@link #VELOCITY_Y} instead. ++ */ ++ @Deprecated(since = "1.21.3", forRemoval = true) ++ public static final Relative Y = VELOCITY_Y; ++ /** ++ * Configures the player to not loose velocity in their z axis during the teleport. ++ * @deprecated Since 1.21.3, vanilla split up the relative teleport flags into velocity and position related ++ * ones. As the API does not deal with position relative flags, this name is no longer applicable. ++ * Use {@link #VELOCITY_Z} instead. ++ */ ++ @Deprecated(since = "1.21.3", forRemoval = true) ++ public static final Relative Z = VELOCITY_Z; ++ /** ++ * Represents the player's yaw ++ * ++ * @deprecated relative velocity flags now allow for the whole rotation to be relative, instead of the yaw and ++ * pitch having individual options. Use {@link #VELOCITY_ROTATION} instead. ++ */ ++ @Deprecated(since = "1.21.3", forRemoval = true) ++ public static final Relative YAW = VELOCITY_ROTATION; ++ /** ++ * Represents the player's pitch ++ * ++ * @deprecated relative velocity flags now allow for the whole rotation to be relative, instead of the yaw and ++ * pitch having individual options. Use {@link #VELOCITY_ROTATION} instead. ++ */ ++ @Deprecated(since = "1.21.3", forRemoval = true) ++ public static final Relative PITCH = VELOCITY_ROTATION; ++ } ++ ++ /** ++ * Represents flags that effect the entity's state on ++ * teleportation. ++ */ ++ enum EntityState implements TeleportFlag { ++ /** ++ * If all passengers should not be required to be removed prior to teleportation. ++ *

      ++ * Note: ++ * Teleporting to a different world with this flag present while the entity has entities riding it ++ * will cause this teleportation to return false and not occur. ++ */ ++ RETAIN_PASSENGERS, ++ /** ++ * If the entity should not be dismounted if they are riding another entity. ++ *

      ++ * Note: ++ * Teleporting to a different world with this flag present while this entity is riding another entity will ++ * cause this teleportation to return false and not occur. ++ */ ++ RETAIN_VEHICLE, ++ /** ++ * Indicates that a player should not have their current open inventory closed when teleporting. ++ *

      ++ * Note: ++ * This option will be ignored when teleported to a different world. ++ */ ++ RETAIN_OPEN_INVENTORY; ++ } ++ ++} +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index fe3f59390ee45a289ae6dbb398ce7954fab717d5..b39ade088062c5e636915f09b7094bc27bac1fcf 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -126,10 +126,32 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + * + * @param yaw the yaw + * @param pitch the pitch +- * @throws UnsupportedOperationException if used for players + */ + public void setRotation(float yaw, float pitch); + ++ // Paper start - Teleport API ++ /** ++ * Teleports this entity to the given location. ++ * ++ * @param location New location to teleport this entity to ++ * @param teleportFlags Flags to be used in this teleportation ++ * @return true if the teleport was successful ++ */ ++ default boolean teleport(@NotNull Location location, @NotNull io.papermc.paper.entity.TeleportFlag @NotNull... teleportFlags) { ++ return this.teleport(location, TeleportCause.PLUGIN, teleportFlags); ++ } ++ ++ /** ++ * Teleports this entity to the given location. ++ * ++ * @param location New location to teleport this entity to ++ * @param cause The cause of this teleportation ++ * @param teleportFlags Flags to be used in this teleportation ++ * @return true if the teleport was successful ++ */ ++ boolean teleport(@NotNull Location location, @NotNull TeleportCause cause, @NotNull io.papermc.paper.entity.TeleportFlag @NotNull... teleportFlags); ++ // Paper end - Teleport API ++ + /** + * Teleports this entity to the given location. If this entity is riding a + * vehicle, it will be dismounted prior to teleportation. +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index db3a1e9170aeada5fe738975124861d79e82e2d1..7d39bf96ac7dd7530d236fc7bff5126b08a7d38a 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3561,6 +3561,45 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + String getClientBrandName(); + // Paper end + ++ // Paper start - Teleport API ++ /** ++ * Sets the player's rotation. ++ * ++ * @param yaw the yaw ++ * @param pitch the pitch ++ */ ++ void setRotation(float yaw, float pitch); ++ ++ /** ++ * Causes the player to look towards the given position. ++ * ++ * @param x x coordinate ++ * @param y y coordinate ++ * @param z z coordinate ++ * @param playerAnchor What part of the player should face the given position ++ */ ++ void lookAt(double x, double y, double z, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor); ++ ++ /** ++ * Causes the player to look towards the given position. ++ * ++ * @param position Position to look at in the player's current world ++ * @param playerAnchor What part of the player should face the given position ++ */ ++ default void lookAt(@NotNull io.papermc.paper.math.Position position, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor) { ++ this.lookAt(position.x(), position.y(), position.z(), playerAnchor); ++ } ++ ++ /** ++ * Causes the player to look towards the given entity. ++ * ++ * @param entity Entity to look at ++ * @param playerAnchor What part of the player should face the entity ++ * @param entityAnchor What part of the entity the player should face ++ */ ++ void lookAt(@NotNull org.bukkit.entity.Entity entity, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor, @NotNull io.papermc.paper.entity.LookAnchor entityAnchor); ++ // Paper end - Teleport API ++ + @NotNull + @Override + Spigot spigot(); +diff --git a/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java b/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java +index 2deae344c88920ab95eefd2f65df5c858e04750b..ccfb08af8c57ddac3062c2cec28d7ff428082709 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java +@@ -13,8 +13,14 @@ public class PlayerTeleportEvent extends PlayerMoveEvent { + private static final HandlerList handlers = new HandlerList(); + private TeleportCause cause = TeleportCause.UNKNOWN; + ++ // Paper start - Teleport API ++ private boolean dismounted = true; ++ private final java.util.Set teleportFlagSet; ++ // Paper end ++ + public PlayerTeleportEvent(@NotNull final Player player, @NotNull final Location from, @Nullable final Location to) { + super(player, from, to); ++ teleportFlagSet = java.util.Collections.emptySet(); // Paper - Teleport API + } + + public PlayerTeleportEvent(@NotNull final Player player, @NotNull final Location from, @Nullable final Location to, @NotNull final TeleportCause cause) { +@@ -23,6 +29,15 @@ public class PlayerTeleportEvent extends PlayerMoveEvent { + this.cause = cause; + } + ++ // Paper start - Teleport API ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public PlayerTeleportEvent(@NotNull final Player player, @NotNull final Location from, @Nullable final Location to, @NotNull final TeleportCause cause, @NotNull java.util.Set teleportFlagSet) { ++ super(player, from, to); ++ this.teleportFlagSet = teleportFlagSet; ++ this.cause = cause; ++ } ++ // Paper end ++ + /** + * Gets the cause of this teleportation event + * +@@ -88,6 +103,30 @@ public class PlayerTeleportEvent extends PlayerMoveEvent { + UNKNOWN; + } + ++ // Paper start - Teleport API ++ /** ++ * Gets if the player will be dismounted in this teleportation. ++ * ++ * @return dismounted or not ++ * @deprecated dismounting on tp is no longer controlled by the server ++ */ ++ @Deprecated(forRemoval = true) ++ public boolean willDismountPlayer() { ++ return this.dismounted; ++ } ++ ++ /** ++ * Returns the relative teleportation flags used in this teleportation. ++ * This determines which axis the player will not lose their velocity in. ++ * ++ * @return an immutable set of relative teleportation flags ++ */ ++ @NotNull ++ public java.util.Set getRelativeTeleportationFlags() { ++ return this.teleportFlagSet; ++ } ++ // Paper end ++ + @NotNull + @Override + public HandlerList getHandlers() { diff --git a/patches/api/0353-Remove-upstream-snakeyaml-fix.patch b/patches/api/0353-Remove-upstream-snakeyaml-fix.patch deleted file mode 100644 index d64efcbe9d2b..000000000000 --- a/patches/api/0353-Remove-upstream-snakeyaml-fix.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 5 Jan 2022 12:12:58 -0800 -Subject: [PATCH] Remove upstream snakeyaml fix - -See Server Patch: Fix saving configs with more long comments - -diff --git a/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java b/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java -index 21d73587e535c43e13473e441dea6fe86c3bf266..0a03cefda788b1dc57ddd61914492a15788aa3d5 100644 ---- a/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java -+++ b/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java -@@ -65,7 +65,7 @@ public class YamlConfiguration extends FileConfiguration { - yamlLoaderOptions = new LoaderOptions(); - yamlLoaderOptions.setMaxAliasesForCollections(Integer.MAX_VALUE); // SPIGOT-5881: Not ideal, but was default pre SnakeYAML 1.26 - -- yaml = new BukkitYaml(constructor, representer, yamlDumperOptions, yamlLoaderOptions); -+ yaml = new /*BukkitYaml*/Yaml(constructor, representer, yamlDumperOptions, yamlLoaderOptions); // Paper - don't use upstream BukkitYaml fix, add the whole snakeyaml Emitter class itself with the fix - } - - @NotNull -diff --git a/src/test/java/org/bukkit/configuration/file/YamlConfigurationTest.java b/src/test/java/org/bukkit/configuration/file/YamlConfigurationTest.java -index 194949d74a3f1c69f7869a826ee3a011a6c26786..9f83d16341b4efd5c7150d2ab9abd579f373fa95 100644 ---- a/src/test/java/org/bukkit/configuration/file/YamlConfigurationTest.java -+++ b/src/test/java/org/bukkit/configuration/file/YamlConfigurationTest.java -@@ -152,6 +152,7 @@ public class YamlConfigurationTest extends FileConfigurationTest { - } - - @Test -+ @org.junit.Ignore // Paper - ignore test because our fix doesn't work in testing environment - public void test100Comments() throws InvalidConfigurationException { - StringBuilder commentBuilder = new StringBuilder(); - for (int i = 0; i < 100; i++) { diff --git a/patches/api/0354-Add-EntityPortalReadyEvent.patch b/patches/api/0354-Add-EntityPortalReadyEvent.patch new file mode 100644 index 000000000000..042c707eb3f6 --- /dev/null +++ b/patches/api/0354-Add-EntityPortalReadyEvent.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 12 May 2021 04:30:53 -0700 +Subject: [PATCH] Add EntityPortalReadyEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityPortalReadyEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityPortalReadyEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bc5f0ed43f5d341ec551e48eecf2614cdfd52d79 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityPortalReadyEvent.java +@@ -0,0 +1,95 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.PortalType; ++import org.bukkit.World; ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.event.entity.EntityPortalEvent; ++import org.bukkit.event.player.PlayerPortalEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when an entity is ready to be teleported by a plugin. ++ * Currently, this is only called after the required ++ * ticks have passed for a Nether Portal. ++ *

      ++ * Cancelling this event resets the entity's readiness ++ * regarding the current portal. ++ */ ++@NullMarked ++public class EntityPortalReadyEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final PortalType portalType; ++ private @Nullable World targetWorld; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityPortalReadyEvent(final Entity entity, final @Nullable World targetWorld, final PortalType portalType) { ++ super(entity); ++ this.targetWorld = targetWorld; ++ this.portalType = portalType; ++ } ++ ++ /** ++ * Gets the world this portal will teleport to. ++ * Can be {@code null} if "allow-nether" is false in server.properties ++ * or if there is another situation where there is no world to teleport to. ++ *

      ++ * This world may be modified by later events such as {@link PlayerPortalEvent} ++ * or {@link EntityPortalEvent}. ++ * ++ * @return the world the portal will teleport the entity to. ++ */ ++ public @Nullable World getTargetWorld() { ++ return this.targetWorld; ++ } ++ ++ /** ++ * Sets the world this portal will teleport to. A {@code null} value ++ * will essentially cancel the teleport and prevent further events ++ * such as {@link PlayerPortalEvent} from firing. ++ *

      ++ * This world may be modified by later events such as {@link PlayerPortalEvent} ++ * or {@link EntityPortalEvent}. ++ * ++ * @param targetWorld the world ++ */ ++ public void setTargetWorld(final @Nullable World targetWorld) { ++ this.targetWorld = targetWorld; ++ } ++ ++ /** ++ * Gets the portal type for this event. ++ * ++ * @return the portal type ++ */ ++ public PortalType getPortalType() { ++ return this.portalType; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0354-Add-new-overload-to-PersistentDataContainer-has.patch b/patches/api/0354-Add-new-overload-to-PersistentDataContainer-has.patch deleted file mode 100644 index 73c49a2fc823..000000000000 --- a/patches/api/0354-Add-new-overload-to-PersistentDataContainer-has.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: u9g -Date: Mon, 3 Jan 2022 23:27:21 -0500 -Subject: [PATCH] Add new overload to PersistentDataContainer#has - -Adds the new overload: PersistentDataContainer#has(NamespacedKey key) - -diff --git a/src/main/java/org/bukkit/persistence/PersistentDataContainer.java b/src/main/java/org/bukkit/persistence/PersistentDataContainer.java -index bf2a957be52d86d07d7d303c86bd3da5fe0a16c0..eebb3da156e2d95efbe22d4afa470b977ce19f10 100644 ---- a/src/main/java/org/bukkit/persistence/PersistentDataContainer.java -+++ b/src/main/java/org/bukkit/persistence/PersistentDataContainer.java -@@ -151,4 +151,18 @@ public interface PersistentDataContainer { - */ - @NotNull - PersistentDataAdapterContext getAdapterContext(); -+ -+ // Paper start -+ /** -+ * Returns if the persistent metadata provider has metadata registered -+ * matching the provided key. -+ * -+ * @param key the key for which existence should be checked. -+ * -+ * @return whether the key exists -+ * -+ * @throws NullPointerException if the key to look up is null -+ */ -+ boolean has(@NotNull NamespacedKey key); -+ // Paper end - } diff --git a/patches/api/0355-Custom-Chat-Completion-Suggestions-API.patch b/patches/api/0355-Custom-Chat-Completion-Suggestions-API.patch new file mode 100644 index 000000000000..5be45fe69224 --- /dev/null +++ b/patches/api/0355-Custom-Chat-Completion-Suggestions-API.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sat, 30 Jul 2022 11:23:11 -0400 +Subject: [PATCH] Custom Chat Completion Suggestions API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 7d39bf96ac7dd7530d236fc7bff5126b08a7d38a..460ac4d102f3e2f0162fd1e489b0866b74f776f1 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3445,6 +3445,31 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + void sendOpLevel(byte level); + // Paper end - sendOpLevel API + ++ // Paper start - custom chat completions API ++ /** ++ * Adds custom chat completion suggestions that the client will ++ * suggest when typing in chat. ++ * ++ * @param completions custom completions ++ * @deprecated use {@link #addCustomChatCompletions(Collection)} ++ */ ++ @Deprecated(since = "1.20.1") ++ void addAdditionalChatCompletions(@NotNull java.util.Collection completions); ++ ++ /** ++ * Removes custom chat completion suggestions that the client ++ * suggests when typing in chat. ++ * ++ * Note: this only applies to previously added custom completions, ++ * online player names are always suggested and cannot be removed. ++ * ++ * @param completions custom completions ++ * @deprecated use {@link #addCustomChatCompletions(Collection)} ++ */ ++ @Deprecated(since = "1.20.1") ++ void removeAdditionalChatCompletions(@NotNull java.util.Collection completions); ++ // Paper end - custom chat completions API ++ + // Spigot start + public class Spigot extends Entity.Spigot { + diff --git a/patches/api/0355-Multiple-Entries-with-Scoreboards.patch b/patches/api/0355-Multiple-Entries-with-Scoreboards.patch deleted file mode 100644 index 2601f1c5a77d..000000000000 --- a/patches/api/0355-Multiple-Entries-with-Scoreboards.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cryptite -Date: Tue, 21 Sep 2021 18:17:34 -0500 -Subject: [PATCH] Multiple Entries with Scoreboards - - -diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java -index cbc82a03c24f746b913b30f14ecb0c08cdb42c24..06a5d3177ca7ab90c3fd9d2053b2ec5e887c7c62 100644 ---- a/src/main/java/org/bukkit/scoreboard/Team.java -+++ b/src/main/java/org/bukkit/scoreboard/Team.java -@@ -323,6 +323,60 @@ public interface Team { - */ - void addEntry(@NotNull String entry) throws IllegalStateException, IllegalArgumentException; - -+ // Paper start -+ /** -+ * This puts a collection of entities onto this team for the scoreboard which results in one -+ * packet for the updates rather than a packet-per-entity. -+ *

      -+ * Entities on other teams will be removed from their respective teams. -+ * -+ * @param entities the entities to add -+ * @throws IllegalArgumentException if entities are null -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ default void addEntities(@NotNull org.bukkit.entity.Entity @NotNull ...entities) { -+ this.addEntities(java.util.List.of(entities)); -+ } -+ -+ /** -+ * This puts a collection of entities onto this team for the scoreboard which results in one -+ * packet for the updates rather than a packet-per-entity. -+ *

      -+ * Entities on other teams will be removed from their respective teams. -+ * -+ * @param entities the entities to add -+ * @throws IllegalArgumentException if entities are null -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ void addEntities(@NotNull java.util.Collection entities) throws IllegalStateException, IllegalArgumentException; -+ -+ /** -+ * This puts a collection of entries onto this team for the scoreboard which results in one -+ * packet for the updates rather than a packet-per-entry. -+ *

      -+ * Entries on other teams will be removed from their respective teams. -+ * -+ * @param entries the entries to add -+ * @throws IllegalArgumentException if entries are null -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ default void addEntries(@NotNull String... entries) throws IllegalStateException, IllegalArgumentException { -+ this.addEntries(java.util.List.of(entries)); -+ } -+ -+ /** -+ * This puts a collection of entries onto this team for the scoreboard which results in one -+ * packet for the updates rather than a packet-per-entry. -+ *

      -+ * Entries on other teams will be removed from their respective teams. -+ * -+ * @param entries the entries to add -+ * @throws IllegalArgumentException if entries are null -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ void addEntries(@NotNull java.util.Collection entries) throws IllegalStateException, IllegalArgumentException; -+ // Paper end -+ - /** - * Removes the player from this team. - * -@@ -345,6 +399,56 @@ public interface Team { - */ - boolean removeEntry(@NotNull String entry) throws IllegalStateException, IllegalArgumentException; - -+ // Paper start -+ /** -+ * Removes a collection of entities from this team which results in one -+ * packet for the updates rather than a packet-per-entity. -+ * -+ * @param entities the entries to remove -+ * @return if any of the entities were a part of this team -+ * @throws IllegalArgumentException if entities is null -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ default boolean removeEntities(@NotNull org.bukkit.entity.Entity @NotNull ... entities) throws IllegalStateException, IllegalArgumentException { -+ return this.removeEntities(java.util.List.of(entities)); -+ } -+ -+ /** -+ * Removes a collection of entities from this team which results in one -+ * packet for the updates rather than a packet-per-entity. -+ * -+ * @param entities the entries to remove -+ * @return if any of the entities were a part of this team -+ * @throws IllegalArgumentException if entities is null -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ boolean removeEntities(@NotNull java.util.Collection entities) throws IllegalStateException, IllegalArgumentException; -+ -+ /** -+ * Removes a collection of entries from this team which results in one -+ * packet for the updates rather than a packet-per-entry. -+ * -+ * @param entries the entries to remove -+ * @return if any of the entries were a part of this team -+ * @throws IllegalArgumentException if entries is null -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ default boolean removeEntries(@NotNull String... entries) throws IllegalStateException, IllegalArgumentException { -+ return this.removeEntries(java.util.List.of(entries)); -+ } -+ -+ /** -+ * Removes a collection of entries from this team which results in one -+ * packet for the updates rather than a packet-per-entry. -+ * -+ * @param entries the entries to remove -+ * @return if any of the entries were a part of this team -+ * @throws IllegalArgumentException if entries is null -+ * @throws IllegalStateException if this team has been unregistered -+ */ -+ boolean removeEntries(@NotNull java.util.Collection entries) throws IllegalStateException, IllegalArgumentException; -+ // Paper end -+ - /** - * Unregisters this team from the Scoreboard - * diff --git a/patches/api/0356-Added-getHostname-to-AsyncPlayerPreLoginEvent.patch b/patches/api/0356-Added-getHostname-to-AsyncPlayerPreLoginEvent.patch deleted file mode 100644 index 3f005c4a38be..000000000000 --- a/patches/api/0356-Added-getHostname-to-AsyncPlayerPreLoginEvent.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MCMDEV -Date: Fri, 24 Sep 2021 17:59:23 +0200 -Subject: [PATCH] Added getHostname to AsyncPlayerPreLoginEvent - - -diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -index baee5038ec7c3e190a328016d9ab290ae48badf6..635b8787fc235b61c0d5677def034656e4ec4cef 100644 ---- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -+++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java -@@ -22,6 +22,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - private final InetAddress ipAddress; - private final InetAddress rawAddress; // Paper - //private UUID uniqueId; // Paper - Not used anymore -+ private final String hostname; // Paper - - @Deprecated - public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress) { -@@ -66,7 +67,14 @@ public class AsyncPlayerPreLoginEvent extends Event { - this(name, ipAddress, ipAddress, uniqueId, profile); - } - -+ @Deprecated // Paper - Add hostname - public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, @NotNull PlayerProfile profile) { -+ // Paper start - Add hostname -+ this(name, ipAddress, rawAddress, uniqueId, profile, ""); -+ } -+ -+ public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, @NotNull PlayerProfile profile, @NotNull String hostname) { -+ // Paper end - Add hostname - super(true); - this.profile = profile; - // Paper end -@@ -76,6 +84,7 @@ public class AsyncPlayerPreLoginEvent extends Event { - this.ipAddress = ipAddress; - this.rawAddress = rawAddress; // Paper - //this.uniqueId = uniqueId; // Paper - Not used anymore -+ this.hostname = hostname; // Paper - Add hostname - } - - /** -@@ -261,6 +270,19 @@ public class AsyncPlayerPreLoginEvent extends Event { - return profile.getId(); // Paper - } - -+ // Paper start -+ /** -+ * Gets the hostname that the player used to connect to the server, or -+ * blank if unknown -+ * -+ * @return The hostname -+ */ -+ @NotNull -+ public String getHostname() { -+ return hostname; -+ } -+ // Paper end -+ - @NotNull - @Override - public HandlerList getHandlers() { diff --git a/patches/api/0356-Collision-API.patch b/patches/api/0356-Collision-API.patch new file mode 100644 index 000000000000..0248530e5015 --- /dev/null +++ b/patches/api/0356-Collision-API.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 6 Oct 2021 20:10:36 -0400 +Subject: [PATCH] Collision API + + +diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java +index 44ee56a5956cc17194c767a0c1071a2abffe818a..43dd6c59cceba12f27e6b265acc3ad97eea37abd 100644 +--- a/src/main/java/org/bukkit/RegionAccessor.java ++++ b/src/main/java/org/bukkit/RegionAccessor.java +@@ -493,5 +493,15 @@ public interface RegionAccessor extends Keyed { // Paper + * @return whether a line of sight exists between {@code from} and {@code to} + */ + public boolean lineOfSightExists(@NotNull Location from, @NotNull Location to); ++ ++ /** ++ * Checks if the world collides with the given boundingbox. ++ * This will check for any colliding hard entities (boats, shulkers) / worldborder / blocks. ++ * Does not load chunks that are within the bounding box. ++ * ++ * @param boundingBox the box to check collisions in ++ * @return collides or not ++ */ ++ boolean hasCollisionsIn(@NotNull org.bukkit.util.BoundingBox boundingBox); + // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index b39ade088062c5e636915f09b7094bc27bac1fcf..2b4058dace5d071f60a9629f81c2323ee8c6d109 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -1023,4 +1023,26 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + boolean isInPowderedSnow(); + // Paper end ++ ++ // Paper start - Collision API ++ /** ++ * Checks for any collisions with the entity's bounding box at the provided location. ++ * This will check for any colliding entities (boats, shulkers) / worldborder / blocks. ++ * Does not load chunks that are within the bounding box at the specified location. ++ * ++ * @param location the location to check collisions in ++ * @return collides or not ++ */ ++ boolean collidesAt(@NotNull Location location); ++ ++ /** ++ * This checks using the given boundingbox as the entity's boundingbox if the entity would collide with anything. ++ * This will check for any colliding entities (boats, shulkers) / worldborder / blocks. ++ * Does not load chunks that are within the bounding box. ++ * ++ * @param boundingBox the box to check collisions in ++ * @return collides or not ++ */ ++ boolean wouldCollideUsing(@NotNull BoundingBox boundingBox); ++ // Paper end - Collision API + } diff --git a/patches/api/0357-Block-Ticking-API.patch b/patches/api/0357-Block-Ticking-API.patch new file mode 100644 index 000000000000..fa6fe2a810e2 --- /dev/null +++ b/patches/api/0357-Block-Ticking-API.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 26 Dec 2021 13:23:52 -0500 +Subject: [PATCH] Block Ticking API + + +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index b47804da74e143b8d3665c3ec7dd9d858eee6a6b..b7530e7f389fdc6d815bdff0949fca4b14298c07 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -593,6 +593,41 @@ public interface Block extends Metadatable, Translatable, net.kyori.adventure.tr + * @return true if the block was destroyed + */ + boolean breakNaturally(@NotNull ItemStack tool, boolean triggerEffect, boolean dropExperience); ++ ++ /** ++ * Causes the block to be ticked, this is different from {@link Block#randomTick()}, ++ * in that it is usually scheduled to occur, for example ++ * redstone components being activated, sand falling, etc. ++ *

      ++ * This method may directly fire events relating to block ticking. ++ * ++ * @see #fluidTick() ++ */ ++ void tick(); ++ ++ /** ++ * Causes the fluid to be ticked, this is different from {@link Block#randomTick()}, ++ * in that it is usually scheduled to occur, for example ++ * causing waterlogged blocks to spread. ++ *

      ++ * This method may directly fire events relating to fluid ticking. ++ * ++ * @see #tick() ++ */ ++ void fluidTick(); ++ ++ /** ++ * Causes the block to be ticked randomly. ++ * This has a chance to execute naturally if {@link BlockData#isRandomlyTicked()} is true. ++ *

      ++ * For certain blocks, this behavior may be the same as {@link Block#tick()}. ++ *

      ++ * This method may directly fire events relating to block random ticking. ++ * ++ * @see #tick() ++ * @see #fluidTick() ++ */ ++ void randomTick(); + // Paper end + + /** +diff --git a/src/main/java/org/bukkit/block/data/BlockData.java b/src/main/java/org/bukkit/block/data/BlockData.java +index 890a511355dd3f2aa9330fdc72c0fb4b3e44e5cb..54664651f34311e95f6c2dcfd93e58477beda8c2 100644 +--- a/src/main/java/org/bukkit/block/data/BlockData.java ++++ b/src/main/java/org/bukkit/block/data/BlockData.java +@@ -295,4 +295,14 @@ public interface BlockData extends Cloneable { + */ + float getDestroySpeed(@NotNull ItemStack itemStack, boolean considerEnchants); + // Paper end - destroy speed API ++ ++ // Paper start - Tick API ++ /** ++ * Gets if this block is ticked randomly in the world. ++ * The blocks current state may change this value. ++ * ++ * @return is ticked randomly ++ */ ++ boolean isRandomlyTicked(); ++ // Paper end - Tick API + } diff --git a/patches/api/0357-Warn-on-strange-EventHandler-return-types.patch b/patches/api/0357-Warn-on-strange-EventHandler-return-types.patch deleted file mode 100644 index 29026c1725f6..000000000000 --- a/patches/api/0357-Warn-on-strange-EventHandler-return-types.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Tue, 18 Jan 2022 11:07:54 -0700 -Subject: [PATCH] Warn on strange @EventHandler return types - - -diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java -index 9026e108ccd3a88aee1267ee275137befa646455..e1860322ae0f3c35097d16767628744034941749 100644 ---- a/src/main/java/org/bukkit/plugin/EventExecutor.java -+++ b/src/main/java/org/bukkit/plugin/EventExecutor.java -@@ -51,6 +51,12 @@ public interface EventExecutor { - Preconditions.checkArgument(m.getParameterCount() != 0, "Incorrect number of arguments %s", m.getParameterCount()); - Preconditions.checkArgument(m.getParameterTypes()[0] == eventClass, "First parameter %s doesn't match event class %s", m.getParameterTypes()[0], eventClass); - ClassDefiner definer = ClassDefiner.getInstance(); -+ if (m.getReturnType() != Void.TYPE) { -+ final org.bukkit.plugin.java.JavaPlugin plugin = org.bukkit.plugin.java.JavaPlugin.getProvidingPlugin(m.getDeclaringClass()); -+ org.bukkit.Bukkit.getLogger().warning("@EventHandler method " + m.getDeclaringClass().getName() + (Modifier.isStatic(m.getModifiers()) ? '.' : '#') + m.getName() -+ + " returns non-void type " + m.getReturnType().getName() + ". This is unsupported behavior and will no longer work in a future version of Paper." -+ + " This should be reported to the developers of " + plugin.getDescription().getFullName() + " (" + String.join(",", plugin.getDescription().getAuthors()) + ')'); -+ } - if (Modifier.isStatic(m.getModifiers())) { - return new StaticMethodHandleEventExecutor(eventClass, m); - } else if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) { diff --git a/patches/api/0358-Add-NamespacedKey-biome-methods.patch b/patches/api/0358-Add-NamespacedKey-biome-methods.patch new file mode 100644 index 000000000000..4eab10357b7e --- /dev/null +++ b/patches/api/0358-Add-NamespacedKey-biome-methods.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Josh Roy <10731363+JRoy@users.noreply.github.com> +Date: Sun, 14 Aug 2022 12:22:54 -0400 +Subject: [PATCH] Add NamespacedKey biome methods + +Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 5be89089da4e8230dc7aa078712428189f38d9f9..3328ae3bab6b4929506a518d6426b81594b1b300 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -223,4 +223,37 @@ public interface UnsafeValues { + */ + @org.jetbrains.annotations.NotNull org.bukkit.attribute.Attributable getDefaultEntityAttributes(@org.jetbrains.annotations.NotNull NamespacedKey entityKey); + // Paper end ++ ++ // Paper start - namespaced key biome methods ++ /** ++ * Gets the {@link NamespacedKey} for the biome at the given location. ++ * ++ * @param accessor The {@link RegionAccessor} of the provided coordinates ++ * @param x X-coordinate of the block ++ * @param y Y-coordinate of the block ++ * @param z Z-coordinate of the block ++ * @deprecated custom biomes are properly supported in API now ++ * @return the biome's {@link NamespacedKey} ++ */ ++ @org.jetbrains.annotations.NotNull ++ @Deprecated(since = "1.21.3", forRemoval = true) ++ NamespacedKey getBiomeKey(RegionAccessor accessor, int x, int y, int z); ++ ++ /** ++ * Sets the biome at the given location to a biome registered ++ * to the given {@link NamespacedKey}. If no biome by the given ++ * {@link NamespacedKey} exists, an {@link IllegalStateException} ++ * will be thrown. ++ * ++ * @param accessor The {@link RegionAccessor} of the provided coordinates ++ * @param x X-coordinate of the block ++ * @param y Y-coordinate of the block ++ * @param z Z-coordinate of the block ++ * @param biomeKey Biome key ++ * @deprecated custom biomes are properly supported in API now ++ * @throws IllegalStateException if no biome by the given key is registered. ++ */ ++ @Deprecated(since = "1.21.3", forRemoval = true) ++ void setBiomeKey(RegionAccessor accessor, int x, int y, int z, NamespacedKey biomeKey); ++ // Paper end - namespaced key biome methods + } diff --git a/patches/api/0358-Multi-Block-Change-API.patch b/patches/api/0358-Multi-Block-Change-API.patch deleted file mode 100644 index 45520149bbb8..000000000000 --- a/patches/api/0358-Multi-Block-Change-API.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brody Beckwith -Date: Fri, 14 Jan 2022 00:40:42 -0500 -Subject: [PATCH] Multi Block Change API - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index b2b28b48e6e7d9f32460b8a65cbe294be4812bd9..c0fc38cacf441273e8430dda31958c15a48fc9b6 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -593,6 +593,27 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - */ - public void sendBlockDamage(@NotNull Location loc, float progress); - -+ // Paper start -+ /** -+ * Send multiple block changes. This fakes a multi block change packet for each -+ * chunk section that a block change occurs. This will not actually change the world in any way. -+ * -+ * @param blockChanges A map of the locations you want to change to their new block data -+ */ -+ public default void sendMultiBlockChange(@NotNull java.util.Map blockChanges) { -+ sendMultiBlockChange(blockChanges, false); -+ } -+ -+ /** -+ * Send multiple block changes. This fakes a multi block change packet for each -+ * chunk section that a block change occurs. This will not actually change the world in any way. -+ * -+ * @param blockChanges A map of the locations you want to change to their new block data -+ * @param suppressLightUpdates Whether to suppress light updates or not -+ */ -+ public void sendMultiBlockChange(@NotNull java.util.Map blockChanges, boolean suppressLightUpdates); -+ // Paper end -+ - /** - * Send the equipment change of an entity. This fakes the equipment change - * of an entity for a user. This will not actually change the inventory of diff --git a/patches/api/0359-Also-load-resources-from-LibraryLoader.patch b/patches/api/0359-Also-load-resources-from-LibraryLoader.patch new file mode 100644 index 000000000000..c2a41c2e53dc --- /dev/null +++ b/patches/api/0359-Also-load-resources-from-LibraryLoader.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nick Hensel +Date: Sun, 28 Aug 2022 23:44:18 +0200 +Subject: [PATCH] Also load resources from LibraryLoader + + +diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +index de017d10db19ca7ca7f73ff0ac08fe6e1773d7dc..7e4f7cb2afbc145e532285c793573ad107bc3033 100644 +--- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +@@ -109,14 +109,35 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm + + @Override + public URL getResource(String name) { +- return findResource(name); ++ // Paper start ++ URL resource = findResource(name); ++ if (resource == null && libraryLoader != null) { ++ return libraryLoader.getResource(name); ++ } ++ return resource; ++ // Paper end + } + + @Override + public Enumeration getResources(String name) throws IOException { +- return findResources(name); ++ // Paper start ++ java.util.ArrayList resources = new java.util.ArrayList<>(); ++ addEnumeration(resources, findResources(name)); ++ if (libraryLoader != null) { ++ addEnumeration(resources, libraryLoader.getResources(name)); ++ } ++ return Collections.enumeration(resources); ++ // Paper end + } + ++ // Paper start ++ private void addEnumeration(java.util.ArrayList list, Enumeration enumeration) { ++ while (enumeration.hasMoreElements()) { ++ list.add(enumeration.nextElement()); ++ } ++ } ++ // Paper end ++ + // Paper start + @Override + public Class loadClass(@NotNull String name, boolean resolve, boolean checkGlobal, boolean checkLibraries) throws ClassNotFoundException { diff --git a/patches/api/0359-Fix-NotePlayEvent.patch b/patches/api/0359-Fix-NotePlayEvent.patch deleted file mode 100644 index a474627df0ec..000000000000 --- a/patches/api/0359-Fix-NotePlayEvent.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Kieran Wallbanks -Date: Mon, 21 Jun 2021 12:33:45 +0100 -Subject: [PATCH] Fix NotePlayEvent - - -diff --git a/src/main/java/org/bukkit/event/block/NotePlayEvent.java b/src/main/java/org/bukkit/event/block/NotePlayEvent.java -index a3887067d1b65fb100ac1407a43c455f5d215510..676b31f6f38d4e85cd4bd16ccf42cbc39a5d8423 100644 ---- a/src/main/java/org/bukkit/event/block/NotePlayEvent.java -+++ b/src/main/java/org/bukkit/event/block/NotePlayEvent.java -@@ -58,9 +58,7 @@ public class NotePlayEvent extends BlockEvent implements Cancellable { - * Overrides the {@link Instrument} to be used. - * - * @param instrument the Instrument. Has no effect if null. -- * @deprecated no effect on newer Minecraft versions - */ -- @Deprecated - public void setInstrument(@NotNull Instrument instrument) { - if (instrument != null) { - this.instrument = instrument; -@@ -71,9 +69,7 @@ public class NotePlayEvent extends BlockEvent implements Cancellable { - * Overrides the {@link Note} to be played. - * - * @param note the Note. Has no effect if null. -- * @deprecated no effect on newer Minecraft versions - */ -- @Deprecated - public void setNote(@NotNull Note note) { - if (note != null) { - this.note = note; diff --git a/patches/api/0360-Added-byte-array-serialization-deserialization-for-P.patch b/patches/api/0360-Added-byte-array-serialization-deserialization-for-P.patch new file mode 100644 index 000000000000..9b71f12681f6 --- /dev/null +++ b/patches/api/0360-Added-byte-array-serialization-deserialization-for-P.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nex +Date: Thu, 24 Feb 2022 16:28:08 +0100 +Subject: [PATCH] Added byte array serialization/deserialization for + PersistentDataContainers + + +diff --git a/src/main/java/org/bukkit/persistence/PersistentDataContainer.java b/src/main/java/org/bukkit/persistence/PersistentDataContainer.java +index 18fc4f1c7151bfdeed32a52cf5050a76ebc391d6..decf3b1949d4653a9fb01684b93ff91048137076 100644 +--- a/src/main/java/org/bukkit/persistence/PersistentDataContainer.java ++++ b/src/main/java/org/bukkit/persistence/PersistentDataContainer.java +@@ -184,4 +184,39 @@ public interface PersistentDataContainer { + */ + @NotNull + PersistentDataAdapterContext getAdapterContext(); ++ ++ // Paper start - byte array serialization ++ /** ++ * Serialize this {@link PersistentDataContainer} instance to a ++ * byte array. ++ * ++ * @return a binary representation of this container ++ * @throws java.io.IOException if we fail to write this container to a byte array ++ */ ++ byte @NotNull [] serializeToBytes() throws java.io.IOException; ++ ++ /** ++ * Read values from a serialised byte array into this ++ * {@link PersistentDataContainer} instance. ++ * ++ * @param bytes the byte array to read from ++ * @param clear if true, this {@link PersistentDataContainer} instance ++ * will be cleared before reading ++ * @throws java.io.IOException if the byte array has an invalid format ++ */ ++ void readFromBytes(byte @NotNull [] bytes, boolean clear) throws java.io.IOException; ++ ++ /** ++ * Read values from a serialised byte array into this ++ * {@link PersistentDataContainer} instance. ++ * This method has the same effect as ++ * PersistentDataContainer#readFromBytes(bytes, true) ++ * ++ * @param bytes the byte array to read from ++ * @throws java.io.IOException if the byte array has an invalid format ++ */ ++ default void readFromBytes(final byte @NotNull [] bytes) throws java.io.IOException { ++ this.readFromBytes(bytes, true); ++ } ++ // Paper end - byte array serialization + } diff --git a/patches/api/0360-Freeze-Tick-Lock-API.patch b/patches/api/0360-Freeze-Tick-Lock-API.patch deleted file mode 100644 index 9f42a812f8df..000000000000 --- a/patches/api/0360-Freeze-Tick-Lock-API.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 26 Dec 2021 20:27:49 -0500 -Subject: [PATCH] Freeze Tick Lock API - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 9c31424a297b9b727ac4ad13040eb9e5674b716b..8bc6876c82935988436597161fa0ec94c032174b 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -278,6 +278,26 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - */ - boolean isFrozen(); - -+ // Paper Start - Freeze Tick Lock API -+ /** -+ * Gets if the entity currently has its freeze ticks locked -+ * to a set amount. -+ *

      -+ * This is only set by plugins -+ * -+ * @return locked or not -+ */ -+ boolean isFreezeTickingLocked(); -+ -+ /** -+ * Sets if the entity currently has its freeze ticks locked, -+ * preventing default vanilla freeze tick modification. -+ * -+ * @param locked prevent vanilla modification or not -+ */ -+ void lockFreezeTicks(boolean locked); -+ // Paper End - Freeze Tick Lock API -+ - /** - * Mark the entity's removal. - */ diff --git a/patches/api/0361-Dolphin-API.patch b/patches/api/0361-Dolphin-API.patch deleted file mode 100644 index 73beed437bbb..000000000000 --- a/patches/api/0361-Dolphin-API.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Tue, 7 Dec 2021 19:34:11 -0500 -Subject: [PATCH] Dolphin API - - -diff --git a/src/main/java/org/bukkit/entity/Dolphin.java b/src/main/java/org/bukkit/entity/Dolphin.java -index f00eaadcdde7ceef95def2d8ec6eb63a76c177bd..8ab329946daaff25646f3dd4582feb9e4c0685ca 100644 ---- a/src/main/java/org/bukkit/entity/Dolphin.java -+++ b/src/main/java/org/bukkit/entity/Dolphin.java -@@ -1,3 +1,52 @@ - package org.bukkit.entity; - --public interface Dolphin extends WaterMob { } -+import org.bukkit.Location; -+ -+public interface Dolphin extends WaterMob { // Paper start - Dolphin API -+ -+ /** -+ * Gets the moistness level of this dolphin -+ */ -+ int getMoistness(); -+ -+ /** -+ * Sets the moistness of this dolphin, once this is less than 0 the dolphin will start to take damage. -+ * -+ * @param moistness moistness level -+ */ -+ void setMoistness(int moistness); -+ -+ /** -+ * Sets if this dolphin was fed a fish. -+ * -+ * @param hasFish has a fish -+ */ -+ void setHasFish(boolean hasFish); -+ -+ /** -+ * Gets if this dolphin has a fish. -+ * -+ * @return has a fish -+ */ -+ boolean hasFish(); -+ -+ /** -+ * Gets the treasure location this dolphin tries to guide players to. -+ *

      -+ * This value is calculated if the player has fed the dolphin a fish, and it tries to start the {@link com.destroystokyo.paper.entity.ai.VanillaGoal#DOLPHIN_SWIM_TO_TREASURE} goal. -+ * -+ * @return calculated closest treasure location -+ */ -+ @org.jetbrains.annotations.NotNull -+ Location getTreasureLocation(); -+ -+ /** -+ * Sets the treasure location that this dolphin will try to lead the player to. -+ * This only has an effect if the dolphin is currently leading a player, as this value is recalculated next time it leads a player. -+ *

      -+ * The world of the location does not matter, as the dolphin will always use the world it is currently in. -+ * -+ * @param location location to guide to -+ */ -+ void setTreasureLocation(@org.jetbrains.annotations.NotNull Location location); -+} // Paper end - Dolphin API diff --git a/patches/api/0361-Expose-codepoint-limit-in-YamlConfigOptions-and-incr.patch b/patches/api/0361-Expose-codepoint-limit-in-YamlConfigOptions-and-incr.patch new file mode 100644 index 000000000000..08a6f15997d4 --- /dev/null +++ b/patches/api/0361-Expose-codepoint-limit-in-YamlConfigOptions-and-incr.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Thu, 22 Sep 2022 07:04:30 +0100 +Subject: [PATCH] Expose codepoint limit in YamlConfigOptions, and increase + default + + +diff --git a/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java b/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java +index b76cf252f44ca858d96b1af52cb38bc801d5f3c1..ed81e850b22b83ac872707daf3c7d5d0cac6176b 100644 +--- a/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java ++++ b/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java +@@ -98,6 +98,7 @@ public class YamlConfiguration extends FileConfiguration { + public void loadFromString(@NotNull String contents) throws InvalidConfigurationException { + Preconditions.checkArgument(contents != null, "Contents cannot be null"); + yamlLoaderOptions.setProcessComments(options().parseComments()); ++ yamlLoaderOptions.setCodePointLimit(options().codePointLimit()); // Paper + + MappingNode node; + try (Reader reader = new UnicodeReader(new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8)))) { +diff --git a/src/main/java/org/bukkit/configuration/file/YamlConfigurationOptions.java b/src/main/java/org/bukkit/configuration/file/YamlConfigurationOptions.java +index 3f69667e6bb89eb1cfdf43598be73640063b2006..6e43fbbe7b43ab5700bb0066b40337b2e47f6c6a 100644 +--- a/src/main/java/org/bukkit/configuration/file/YamlConfigurationOptions.java ++++ b/src/main/java/org/bukkit/configuration/file/YamlConfigurationOptions.java +@@ -12,6 +12,7 @@ import org.jetbrains.annotations.Nullable; + public class YamlConfigurationOptions extends FileConfigurationOptions { + private int indent = 2; + private int width = 80; ++ private int codePointLimit = Integer.MAX_VALUE; // Paper - use upstream's default from YamlConfiguration + + protected YamlConfigurationOptions(@NotNull YamlConfiguration configuration) { + super(configuration); +@@ -122,4 +123,29 @@ public class YamlConfigurationOptions extends FileConfigurationOptions { + this.width = value; + return this; + } ++ ++ // Paper start ++ /** ++ * Gets the maximum code point limit, that being, the maximum length of the document ++ * in which the loader will read ++ * ++ * @return The current value ++ */ ++ public int codePointLimit() { ++ return codePointLimit; ++ } ++ ++ /** ++ * Sets the maximum code point limit, that being, the maximum length of the document ++ * in which the loader will read ++ * ++ * @param codePointLimit new codepoint limit ++ * @return This object, for chaining ++ */ ++ @NotNull ++ public YamlConfigurationOptions codePointLimit(int codePointLimit) { ++ this.codePointLimit = codePointLimit; ++ return this; ++ } ++ // Paper end + } diff --git a/patches/api/0362-Add-getDrops-to-BlockState.patch b/patches/api/0362-Add-getDrops-to-BlockState.patch new file mode 100644 index 000000000000..bb0a24c65e63 --- /dev/null +++ b/patches/api/0362-Add-getDrops-to-BlockState.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MelnCat +Date: Fri, 12 Aug 2022 23:24:53 -0700 +Subject: [PATCH] Add getDrops to BlockState + +Originally added isPreferredTool to BlockData but +upstream added that. + +diff --git a/src/main/java/org/bukkit/block/BlockState.java b/src/main/java/org/bukkit/block/BlockState.java +index ee4cbbc584ec1a10c62464a7abb3ea5da656ffc0..3bcdb02f8f6081dcd7f15dc86587d4b790aa4496 100644 +--- a/src/main/java/org/bukkit/block/BlockState.java ++++ b/src/main/java/org/bukkit/block/BlockState.java +@@ -253,5 +253,41 @@ public interface BlockState extends Metadatable { + * @return true if collidable + */ + boolean isCollidable(); ++ ++ /** ++ * Returns an immutable list of items which would drop by destroying this block state. ++ * ++ * @return an immutable list of dropped items for the block state ++ * @throws IllegalStateException if this block state is not placed ++ */ ++ @NotNull ++ default java.util.@org.jetbrains.annotations.Unmodifiable Collection getDrops() { ++ return this.getDrops(null); ++ } ++ ++ /** ++ * Returns an immutable list of items which would drop by destroying this block state ++ * with a specific tool ++ * ++ * @param tool The tool or item in hand used for digging ++ * @return an immutable list of dropped items for the block state ++ * @throws IllegalStateException if this block state is not placed ++ */ ++ @NotNull ++ default java.util.@org.jetbrains.annotations.Unmodifiable Collection getDrops(@Nullable org.bukkit.inventory.ItemStack tool) { ++ return this.getDrops(tool, null); ++ } ++ ++ /** ++ * Returns an immutable list of items which would drop by the entity destroying this ++ * block state with a specific tool ++ * ++ * @param tool The tool or item in hand used for digging ++ * @param entity the entity destroying the block ++ * @return an immutable list of dropped items for the block state ++ * @throws IllegalStateException if this block state is not placed ++ */ ++ @NotNull ++ java.util.@org.jetbrains.annotations.Unmodifiable Collection getDrops(@Nullable org.bukkit.inventory.ItemStack tool, @Nullable org.bukkit.entity.Entity entity); + // Paper end + } diff --git a/patches/api/0362-More-PotionEffectType-API.patch b/patches/api/0362-More-PotionEffectType-API.patch deleted file mode 100644 index aa6840470dcd..000000000000 --- a/patches/api/0362-More-PotionEffectType-API.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 27 May 2021 21:58:33 -0700 -Subject: [PATCH] More PotionEffectType API - - -diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java -index ec59aa76488a1500ab3df46c98ba7b1d4179df4e..56a90dbf1a61dce615ee0f712851bf01de06b28c 100644 ---- a/src/main/java/org/bukkit/Registry.java -+++ b/src/main/java/org/bukkit/Registry.java -@@ -216,6 +216,25 @@ public interface Registry extends Iterable { - * @see io.papermc.paper.world.structure.ConfiguredStructure - */ - Registry CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); -+ /** -+ * Potion effect types. -+ * -+ * @see org.bukkit.potion.PotionEffectType -+ */ -+ Registry POTION_EFFECT_TYPE = new Registry() { -+ -+ @Nullable -+ @Override -+ public org.bukkit.potion.PotionEffectType get(@NotNull NamespacedKey key) { -+ return org.bukkit.potion.PotionEffectType.getByKey(key); -+ } -+ -+ @NotNull -+ @Override -+ public Iterator iterator() { -+ return Arrays.stream(org.bukkit.potion.PotionEffectType.values()).iterator(); -+ } -+ }; - // Paper end - - /** -diff --git a/src/main/java/org/bukkit/potion/PotionEffectType.java b/src/main/java/org/bukkit/potion/PotionEffectType.java -index 5f3aa6fd18d57055a6d8494938dff149d51b2803..84fd181ad897f620e450750246d9ea416dcbd48a 100644 ---- a/src/main/java/org/bukkit/potion/PotionEffectType.java -+++ b/src/main/java/org/bukkit/potion/PotionEffectType.java -@@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable; - /** - * Represents a type of potion and its effect on an entity. - */ --public abstract class PotionEffectType implements Keyed { -+public abstract class PotionEffectType implements Keyed, net.kyori.adventure.translation.Translatable { // Paper - implement Translatable - /** - * Increases movement speed. - */ -@@ -363,4 +363,56 @@ public abstract class PotionEffectType implements Keyed { - public static PotionEffectType[] values() { - return Arrays.copyOfRange(byId, 1, byId.length); - } -+ // Paper start -+ /** -+ * Gets the effect attributes in an immutable map. -+ * -+ * @return the attribute map -+ */ -+ public abstract @NotNull Map getEffectAttributes(); -+ -+ /** -+ * Gets the true modifier amount based on the effect amplifier. -+ * -+ * @param attribute the attribute -+ * @param effectAmplifier the effect amplifier (0 indexed) -+ * @return the modifier amount -+ * @throws IllegalArgumentException if the supplied attribute is not present in the map from {@link #getEffectAttributes()} -+ */ -+ public abstract double getAttributeModifierAmount(@NotNull org.bukkit.attribute.Attribute attribute, int effectAmplifier); -+ -+ /** -+ * Gets the category of this effect -+ * -+ * @return the category -+ */ -+ public abstract @NotNull PotionEffectType.Category getEffectCategory(); -+ -+ /** -+ * Category of {@link PotionEffectType}s -+ */ -+ public enum Category { -+ -+ BENEFICIAL(net.kyori.adventure.text.format.NamedTextColor.BLUE), -+ HARMFUL(net.kyori.adventure.text.format.NamedTextColor.RED), -+ NEUTRAL(net.kyori.adventure.text.format.NamedTextColor.BLUE); -+ -+ private final net.kyori.adventure.text.format.TextColor color; -+ -+ Category(net.kyori.adventure.text.format.TextColor color) { -+ this.color = color; -+ } -+ -+ /** -+ * Gets the text color used when displaying potions -+ * of this category. -+ * -+ * @return the text color -+ */ -+ @NotNull -+ public net.kyori.adventure.text.format.TextColor getColor() { -+ return color; -+ } -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java b/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java -index c3a86bb1910158a8d13a675dfa7236dd6a3f397c..a7653806c0fa76f4b3342ea199fe892c514a4c27 100644 ---- a/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java -+++ b/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java -@@ -40,4 +40,30 @@ public class PotionEffectTypeWrapper extends PotionEffectType { - public Color getColor() { - return getType().getColor(); - } -+ // Paper start -+ @Override -+ public @NotNull org.bukkit.NamespacedKey getKey() { -+ return this.getType().getKey(); -+ } -+ -+ @Override -+ public @NotNull java.util.Map getEffectAttributes() { -+ return this.getType().getEffectAttributes(); -+ } -+ -+ @Override -+ public double getAttributeModifierAmount(@NotNull org.bukkit.attribute.Attribute attribute, int effectAmplifier) { -+ return this.getType().getAttributeModifierAmount(attribute, effectAmplifier); -+ } -+ -+ @Override -+ public @NotNull PotionEffectType.Category getEffectCategory() { -+ return this.getType().getEffectCategory(); -+ } -+ -+ @Override -+ public @NotNull String translationKey() { -+ return this.getType().translationKey(); -+ } -+ // Paper end - } diff --git a/patches/api/0363-API-for-creating-command-sender-which-forwards-feedb.patch b/patches/api/0363-API-for-creating-command-sender-which-forwards-feedb.patch deleted file mode 100644 index 06e522a4045c..000000000000 --- a/patches/api/0363-API-for-creating-command-sender-which-forwards-feedb.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Tue, 1 Feb 2022 15:51:44 -0700 -Subject: [PATCH] API for creating command sender which forwards feedback - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 23834c3bd3a5e008b1b05c99a7b2f491731d8459..ac7674fb1c9d7bd9572c678f57cab44233328bdc 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -1412,6 +1412,20 @@ public final class Bukkit { - return server.getConsoleSender(); - } - -+ // Paper start -+ /** -+ * Creates a special {@link CommandSender} which redirects command feedback (in the form of chat messages) to the -+ * specified listener. The returned sender will have the same effective permissions as {@link #getConsoleSender()}. -+ * -+ * @param feedback feedback listener -+ * @return a command sender -+ */ -+ @NotNull -+ public static CommandSender createCommandSender(final @NotNull java.util.function.Consumer feedback) { -+ return server.createCommandSender(feedback); -+ } -+ // Paper end -+ - /** - * Gets the folder that contains all of the various {@link World}s. - * -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 515e1bc18e04cd94b5aa7b00434a72381277e678..871d80d0e0ce7cd80e34bfeebee8c543ea023d8e 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -1178,6 +1178,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - @NotNull - public ConsoleCommandSender getConsoleSender(); - -+ // Paper start -+ /** -+ * Creates a special {@link CommandSender} which redirects command feedback (in the form of chat messages) to the -+ * specified listener. The returned sender will have the same effective permissions as {@link #getConsoleSender()}. -+ * -+ * @param feedback feedback listener -+ * @return a command sender -+ */ -+ @NotNull -+ public CommandSender createCommandSender(final @NotNull java.util.function.Consumer feedback); -+ // Paper end -+ - /** - * Gets the folder that contains all of the various {@link World}s. - * diff --git a/patches/api/0363-Add-PlayerInventorySlotChangeEvent.patch b/patches/api/0363-Add-PlayerInventorySlotChangeEvent.patch new file mode 100644 index 000000000000..d0cadabced5e --- /dev/null +++ b/patches/api/0363-Add-PlayerInventorySlotChangeEvent.patch @@ -0,0 +1,110 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jakub Zacek +Date: Sun, 24 Apr 2022 22:56:31 +0200 +Subject: [PATCH] Add PlayerInventorySlotChangeEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerInventorySlotChangeEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerInventorySlotChangeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f3a54ed7efabaa0f6413e1598f14e2770a46440d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerInventorySlotChangeEvent.java +@@ -0,0 +1,98 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.Inventory; ++import org.bukkit.inventory.ItemStack; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a slot contents change in a player's inventory. ++ */ ++@NullMarked ++public class PlayerInventorySlotChangeEvent extends PlayerEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final int rawSlot; ++ private final int slot; ++ private final ItemStack oldItemStack; ++ private final ItemStack newItemStack; ++ private boolean triggerAdvancements = true; ++ ++ public PlayerInventorySlotChangeEvent(final Player player, final int rawSlot, final ItemStack oldItemStack, final ItemStack newItemStack) { ++ super(player); ++ this.rawSlot = rawSlot; ++ this.slot = player.getOpenInventory().convertSlot(rawSlot); ++ this.oldItemStack = oldItemStack; ++ this.newItemStack = newItemStack; ++ } ++ ++ /** ++ * The raw slot number that was changed. ++ * ++ * @return The raw slot number. ++ */ ++ public int getRawSlot() { ++ return this.rawSlot; ++ } ++ ++ /** ++ * The slot number that was changed, ready for passing to ++ * {@link Inventory#getItem(int)}. Note that there may be two slots with ++ * the same slot number, since a view links two different inventories. ++ *

      ++ * If no inventory is opened, internal crafting view is used for conversion. ++ * ++ * @return The slot number. ++ */ ++ public int getSlot() { ++ return this.slot; ++ } ++ ++ /** ++ * Clone of ItemStack that was in the slot before the change. ++ * ++ * @return The old ItemStack in the slot. ++ */ ++ public ItemStack getOldItemStack() { ++ return this.oldItemStack; ++ } ++ ++ /** ++ * Clone of ItemStack that is in the slot after the change. ++ * ++ * @return The new ItemStack in the slot. ++ */ ++ public ItemStack getNewItemStack() { ++ return this.newItemStack; ++ } ++ ++ /** ++ * Gets whether the slot change advancements will be triggered. ++ * ++ * @return Whether the slot change advancements will be triggered. ++ */ ++ public boolean shouldTriggerAdvancements() { ++ return this.triggerAdvancements; ++ } ++ ++ /** ++ * Sets whether the slot change advancements will be triggered. ++ * ++ * @param triggerAdvancements Whether the slot change advancements will be triggered. ++ */ ++ public void setShouldTriggerAdvancements(final boolean triggerAdvancements) { ++ this.triggerAdvancements = triggerAdvancements; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0364-Elder-Guardian-appearance-API.patch b/patches/api/0364-Elder-Guardian-appearance-API.patch new file mode 100644 index 000000000000..a0e9bd6ffd62 --- /dev/null +++ b/patches/api/0364-Elder-Guardian-appearance-API.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Tue, 11 Oct 2022 20:38:47 +0300 +Subject: [PATCH] Elder Guardian appearance API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 460ac4d102f3e2f0162fd1e489b0866b74f776f1..c676524280cc091998859fe1945d06bb7f26560d 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3625,6 +3625,24 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + void lookAt(@NotNull org.bukkit.entity.Entity entity, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor, @NotNull io.papermc.paper.entity.LookAnchor entityAnchor); + // Paper end - Teleport API + ++ // Paper start ++ /** ++ * Displays elder guardian effect with a sound ++ * ++ * @see #showElderGuardian(boolean) ++ */ ++ default void showElderGuardian() { ++ showElderGuardian(false); ++ } ++ ++ /** ++ * Displays elder guardian effect and optionally plays a sound ++ * ++ * @param silent whether sound should be silenced ++ */ ++ void showElderGuardian(boolean silent); ++ // Paper end ++ + @NotNull + @Override + Spigot spigot(); diff --git a/patches/api/0364-Implement-regenerateChunk.patch b/patches/api/0364-Implement-regenerateChunk.patch deleted file mode 100644 index e779ef9bc191..000000000000 --- a/patches/api/0364-Implement-regenerateChunk.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Sat, 5 Feb 2022 20:25:28 +0100 -Subject: [PATCH] Implement regenerateChunk - - -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index e47d0663d42fa38e5c6cd2611f99e23f8187c28f..e8c0c853eb52d1473c20231660355f77b1f7e016 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -498,8 +498,8 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - * @return Whether the chunk was actually regenerated - * - * @deprecated regenerating a single chunk is not likely to produce the same -- * chunk as before as terrain decoration may be spread across chunks. Use of -- * this method should be avoided as it is known to produce buggy results. -+ * chunk as before as terrain decoration may be spread across chunks. It may -+ * or may not change blocks in the adjacent chunks as well. - */ - @Deprecated - public boolean regenerateChunk(int x, int z); diff --git a/patches/api/0365-Add-EquipmentSlot-convenience-methods.patch b/patches/api/0365-Add-EquipmentSlot-convenience-methods.patch new file mode 100644 index 000000000000..f7e2301f315e --- /dev/null +++ b/patches/api/0365-Add-EquipmentSlot-convenience-methods.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Sun, 16 Oct 2022 15:28:49 +0300 +Subject: [PATCH] Add EquipmentSlot convenience methods + + +diff --git a/src/main/java/org/bukkit/inventory/EquipmentSlot.java b/src/main/java/org/bukkit/inventory/EquipmentSlot.java +index 5642d8af60b6649497aba9b0f6ab7bba7702b9ee..c1c69ba4c361740f0ad422a7840a7f0f055c186a 100644 +--- a/src/main/java/org/bukkit/inventory/EquipmentSlot.java ++++ b/src/main/java/org/bukkit/inventory/EquipmentSlot.java +@@ -33,4 +33,42 @@ public enum EquipmentSlot { + public EquipmentSlotGroup getGroup() { + return group.get(); + } ++ // Paper start ++ /** ++ * Checks whether this equipment slot is a hand: ++ * either {@link #HAND} or {@link #OFF_HAND} ++ * ++ * @return whether this is a hand slot ++ */ ++ public boolean isHand() { ++ return this == HAND || this == OFF_HAND; ++ } ++ ++ /** ++ * Gets the opposite hand ++ * ++ * @return the opposite hand ++ * @throws IllegalArgumentException if this equipment slot is not a hand ++ * @see #isHand() ++ */ ++ public @NotNull EquipmentSlot getOppositeHand() { ++ return switch (this) { ++ case HAND -> OFF_HAND; ++ case OFF_HAND -> HAND; ++ default -> throw new IllegalArgumentException("Unable to determine an opposite hand for equipment slot: " + name()); ++ }; ++ } ++ ++ /** ++ * Checks whether this equipment slot ++ * is one of the armor slots: ++ * {@link #HEAD}, {@link #CHEST}, ++ * {@link #LEGS}, {@link #FEET}, or {@link #BODY} ++ * ++ * @return whether this is an armor slot ++ */ ++ public boolean isArmor() { ++ return this == HEAD || this == CHEST || this == LEGS || this == FEET || this == BODY; ++ } ++ // Paper end + } diff --git a/patches/api/0365-Don-t-load-plugins-prefixed-with-a-dot.patch b/patches/api/0365-Don-t-load-plugins-prefixed-with-a-dot.patch deleted file mode 100644 index 79e35efc0ccb..000000000000 --- a/patches/api/0365-Don-t-load-plugins-prefixed-with-a-dot.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Sat, 22 Jan 2022 16:35:44 +0100 -Subject: [PATCH] Don't load plugins prefixed with a dot - - -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index 34c3df7570479d4f045897fe4e26dfa3f27479c4..45114d587a8f201778adcba16c8a019f9959f472 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -137,6 +137,7 @@ public final class SimplePluginManager implements PluginManager { - final List pluginJars = new ArrayList<>(java.util.Arrays.asList(directory.listFiles())); - pluginJars.addAll(extraPluginJars); - for (File file : pluginJars) { -+ if (file.getName().startsWith(".") && !extraPluginJars.contains(file)) continue; // Don't load plugin if the file name starts with a dot, except if it's a extra plugin jar. - // Paper end - PluginLoader loader = null; - for (Pattern filter : filters) { diff --git a/patches/api/0366-Add-GameEvent-tags.patch b/patches/api/0366-Add-GameEvent-tags.patch deleted file mode 100644 index ffef095e76d8..000000000000 --- a/patches/api/0366-Add-GameEvent-tags.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 18 Dec 2021 10:34:21 -0800 -Subject: [PATCH] Add GameEvent tags - - -diff --git a/src/main/java/org/bukkit/Tag.java b/src/main/java/org/bukkit/Tag.java -index 9694b862d62afbaa831735a6f6d095315bcdf37c..4749d4c01069f0e0cbe948ede1dd043baceaa97b 100644 ---- a/src/main/java/org/bukkit/Tag.java -+++ b/src/main/java/org/bukkit/Tag.java -@@ -848,6 +848,18 @@ public interface Tag extends Keyed { - */ - @Deprecated(forRemoval = true) - Tag SKELETONS = ENTITY_TYPES_SKELETONS; -+ -+ String REGISTRY_GAME_EVENTS = "game_events"; -+ -+ /** -+ * Tag for game events that trigger sculk sensors -+ */ -+ Tag GAME_EVENT_VIBRATIONS = Bukkit.getTag(REGISTRY_GAME_EVENTS, NamespacedKey.minecraft("vibrations"), GameEvent.class); -+ -+ /** -+ * Tag for game events that are ignored if the entity is sneaking -+ */ -+ Tag GAME_EVENT_IGNORE_VIBRATIONS_SNEAKING = Bukkit.getTag(REGISTRY_GAME_EVENTS, NamespacedKey.minecraft("ignore_vibrations_sneaking"), GameEvent.class); - // Paper end - - /** diff --git a/patches/api/0366-Add-LivingEntity-swingHand-EquipmentSlot-convenience.patch b/patches/api/0366-Add-LivingEntity-swingHand-EquipmentSlot-convenience.patch new file mode 100644 index 000000000000..b66bb330f3c9 --- /dev/null +++ b/patches/api/0366-Add-LivingEntity-swingHand-EquipmentSlot-convenience.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Tue, 11 Oct 2022 22:35:56 +0300 +Subject: [PATCH] Add LivingEntity#swingHand(EquipmentSlot) convenience method + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 292b8d0370723f019fb90a8b86300fa631bee683..be91821c47ff582576eb845610c3bde7e65ed8b3 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1341,4 +1341,24 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + @Deprecated + void setHurtDirection(float hurtDirection); + // Paper end - hurt direction API ++ ++ // Paper start - swing hand API ++ /** ++ * Makes this entity swing their hand. ++ * ++ *

      This method does nothing if this entity does not ++ * have an animation for swinging their hand. ++ * ++ * @param hand hand to be swung, either {@link org.bukkit.inventory.EquipmentSlot#HAND} or {@link org.bukkit.inventory.EquipmentSlot#OFF_HAND} ++ * @throws IllegalArgumentException if invalid hand is passed ++ */ ++ default void swingHand(@NotNull org.bukkit.inventory.EquipmentSlot hand) { ++ com.google.common.base.Preconditions.checkArgument(hand != null && hand.isHand(), String.format("Expected a valid hand, got \"%s\" instead!", hand)); ++ if (hand == org.bukkit.inventory.EquipmentSlot.HAND) { ++ this.swingMainHand(); ++ } else { ++ this.swingOffHand(); ++ } ++ } ++ // Paper end - swing hand API + } diff --git a/patches/api/0367-Add-entity-knockback-API.patch b/patches/api/0367-Add-entity-knockback-API.patch new file mode 100644 index 000000000000..73dd5f365870 --- /dev/null +++ b/patches/api/0367-Add-entity-knockback-API.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MelnCat +Date: Sun, 16 Oct 2022 12:10:00 -0700 +Subject: [PATCH] Add entity knockback API + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index be91821c47ff582576eb845610c3bde7e65ed8b3..8ee3f82049541041623c10940bdda1746200b1e6 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1361,4 +1361,18 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + } + } + // Paper end - swing hand API ++ ++ // Paper start - knockback API ++ /** ++ * Knocks back this entity from a specific direction with a specified strength. Mechanics such ++ * as knockback resistance will be factored in. ++ * ++ * The direction specified in this method will be the direction of the source of the knockback, ++ * so the entity will be pushed in the opposite direction. ++ * @param strength The strength of the knockback. Must be greater than 0. ++ * @param directionX The relative x position of the knockback source direction ++ * @param directionZ The relative z position of the knockback source direction ++ */ ++ void knockback(double strength, double directionX, double directionZ); ++ // Paper end - knockback API + } diff --git a/patches/api/0368-Added-EntityToggleSitEvent.patch b/patches/api/0368-Added-EntityToggleSitEvent.patch new file mode 100644 index 000000000000..435450daf4d6 --- /dev/null +++ b/patches/api/0368-Added-EntityToggleSitEvent.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: KyGuy2002 +Date: Fri, 11 Mar 2022 15:33:10 +0000 +Subject: [PATCH] Added EntityToggleSitEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityToggleSitEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityToggleSitEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ab1955bc61114798fe71cffa6fae3ee0beb3bd2a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityToggleSitEvent.java +@@ -0,0 +1,54 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Is called when an entity sits down or stands up. ++ */ ++@NullMarked ++public class EntityToggleSitEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final boolean isSitting; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityToggleSitEvent(final Entity entity, final boolean isSitting) { ++ super(entity); ++ this.isSitting = isSitting; ++ } ++ ++ /** ++ * Gets the new sitting state that the entity will change to. ++ * ++ * @return If it's going to sit or not. ++ */ ++ public boolean getSittingState() { ++ return this.isSitting; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0369-Add-Moving-Piston-API.patch b/patches/api/0369-Add-Moving-Piston-API.patch new file mode 100644 index 000000000000..e93ac68dd268 --- /dev/null +++ b/patches/api/0369-Add-Moving-Piston-API.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sat, 4 Dec 2021 13:29:45 -0500 +Subject: [PATCH] Add Moving Piston API + + +diff --git a/src/main/java/io/papermc/paper/block/MovingPiston.java b/src/main/java/io/papermc/paper/block/MovingPiston.java +new file mode 100644 +index 0000000000000000000000000000000000000000..962b92d487b3c442d2fe8b665ec3b2d375aaa9aa +--- /dev/null ++++ b/src/main/java/io/papermc/paper/block/MovingPiston.java +@@ -0,0 +1,42 @@ ++package io.papermc.paper.block; ++ ++import org.bukkit.block.BlockFace; ++import org.bukkit.block.TileState; ++import org.bukkit.block.data.BlockData; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public interface MovingPiston extends TileState { ++ ++ /** ++ * Gets the block that is being pushed ++ * ++ * @return the pushed block ++ */ ++ BlockData getMovingBlock(); ++ ++ /** ++ * The direction that the current moving piston ++ * is pushing/pulling a block in. ++ * ++ * @return the direction ++ */ ++ BlockFace getDirection(); ++ ++ /** ++ * Gets if the piston is extending or not. ++ * Returns false if the piston is retracting. ++ * ++ * @return is extending or not ++ */ ++ boolean isExtending(); ++ ++ /** ++ * Returns if this moving piston represents the main piston head ++ * from the original piston. ++ * ++ * @return is the piston head or not ++ */ ++ boolean isPistonHead(); ++ ++} diff --git a/patches/api/0369-Add-missing-block-data-mins-and-maxes.patch b/patches/api/0369-Add-missing-block-data-mins-and-maxes.patch deleted file mode 100644 index 600497b952ab..000000000000 --- a/patches/api/0369-Add-missing-block-data-mins-and-maxes.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 16 Oct 2021 22:57:10 -0700 -Subject: [PATCH] Add missing block data mins and maxes - - -diff --git a/src/main/java/org/bukkit/block/data/Levelled.java b/src/main/java/org/bukkit/block/data/Levelled.java -index 5255538fecae6da413546be3adacd2a99f6c74e9..860f072dee391b300cb1629058a3f9c23dfd95e2 100644 ---- a/src/main/java/org/bukkit/block/data/Levelled.java -+++ b/src/main/java/org/bukkit/block/data/Levelled.java -@@ -36,4 +36,13 @@ public interface Levelled extends BlockData { - * @return the maximum 'level' value - */ - int getMaximumLevel(); -+ -+ // Paper start -+ /** -+ * Gets the minimum allowed value of the 'level' property. -+ * -+ * @return the minimum 'level' value -+ */ -+ int getMinimumLevel(); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/block/data/type/Candle.java b/src/main/java/org/bukkit/block/data/type/Candle.java -index d4d08bd424f84523200d1a2012f4d37c07cc3497..7baccce27f2db2242f628ea92a9d040267caef75 100644 ---- a/src/main/java/org/bukkit/block/data/type/Candle.java -+++ b/src/main/java/org/bukkit/block/data/type/Candle.java -@@ -28,4 +28,13 @@ public interface Candle extends Lightable, Waterlogged { - * @return the maximum 'candles' value - */ - int getMaximumCandles(); -+ -+ // Paper start -+ /** -+ * Gets the minimum allowed value of the 'candles' property. -+ * -+ * @return the minimum 'candles' value -+ */ -+ int getMinimumCandles(); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/block/data/type/Leaves.java b/src/main/java/org/bukkit/block/data/type/Leaves.java -index 3ea21dfad26222ee70fbc627595f54de1a28aa96..cd013a7c42648d819d1e91c7cf9f97a8190c1fad 100644 ---- a/src/main/java/org/bukkit/block/data/type/Leaves.java -+++ b/src/main/java/org/bukkit/block/data/type/Leaves.java -@@ -39,4 +39,20 @@ public interface Leaves extends Waterlogged { - * @param distance the new 'distance' value - */ - void setDistance(int distance); -+ -+ // Paper start -+ /** -+ * Gets the maximum allowed value of the 'distance' property. -+ * -+ * @return the maximum 'distance' value -+ */ -+ int getMaximumDistance(); -+ -+ /** -+ * Gets the minimum allowed value of the 'distance' property. -+ * -+ * @return the minimum 'distance' value -+ */ -+ int getMinimumDistance(); -+ // Paper end - } diff --git a/patches/api/0370-Add-PrePlayerAttackEntityEvent.patch b/patches/api/0370-Add-PrePlayerAttackEntityEvent.patch new file mode 100644 index 000000000000..1caf6f769686 --- /dev/null +++ b/patches/api/0370-Add-PrePlayerAttackEntityEvent.patch @@ -0,0 +1,102 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 18 Sep 2022 13:10:28 -0400 +Subject: [PATCH] Add PrePlayerAttackEntityEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PrePlayerAttackEntityEvent.java b/src/main/java/io/papermc/paper/event/player/PrePlayerAttackEntityEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a6c5818bcdd8de5f2d0e9bf72d1e3816652e0199 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PrePlayerAttackEntityEvent.java +@@ -0,0 +1,90 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when the player tries to attack an entity. ++ *

      ++ * This occurs before any of the damage logic, so cancelling this event ++ * will prevent any sort of sounds from being played when attacking. ++ *

      ++ * This event will fire as cancelled for certain entities, with {@link PrePlayerAttackEntityEvent#willAttack()} being false ++ * to indicate that this entity will not actually be attacked. ++ *

      ++ * Note: there may be other factors (invulnerability, etc.) that will prevent this entity from being attacked that this event will not cover ++ */ ++@NullMarked ++public class PrePlayerAttackEntityEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Entity attacked; ++ private final boolean willAttack; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PrePlayerAttackEntityEvent(final Player player, final Entity attacked, final boolean willAttack) { ++ super(player); ++ this.attacked = attacked; ++ this.willAttack = willAttack; ++ this.cancelled = !willAttack; ++ } ++ ++ /** ++ * Gets the entity that was attacked in this event. ++ * ++ * @return entity that was attacked ++ */ ++ public Entity getAttacked() { ++ return this.attacked; ++ } ++ ++ /** ++ * Gets if this entity will be attacked normally. ++ * Entities like falling sand will return {@code false} because ++ * their entity type does not allow them to be attacked. ++ *

      ++ * Note: there may be other factors (invulnerability, etc.) that will prevent this entity from being attacked that this event will not cover ++ * ++ * @return if the entity will actually be attacked ++ */ ++ public boolean willAttack() { ++ return this.willAttack; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * Sets if this attack should be cancelled, note if {@link PrePlayerAttackEntityEvent#willAttack()} returns false ++ * this event will always be cancelled. ++ * ++ * @param cancel {@code true} if you wish to cancel this event ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ if (!this.willAttack) { ++ return; ++ } ++ ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0370-Custom-Potion-Mixes.patch b/patches/api/0370-Custom-Potion-Mixes.patch deleted file mode 100644 index 5d6edd5a1dc3..000000000000 --- a/patches/api/0370-Custom-Potion-Mixes.patch +++ /dev/null @@ -1,170 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 7 Oct 2021 14:34:59 -0700 -Subject: [PATCH] Custom Potion Mixes - - -diff --git a/src/main/java/io/papermc/paper/potion/PotionMix.java b/src/main/java/io/papermc/paper/potion/PotionMix.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cb6d93526b637946aec311bef103ad3096781113 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/potion/PotionMix.java -@@ -0,0 +1,91 @@ -+package io.papermc.paper.potion; -+ -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.inventory.ItemStack; -+import org.bukkit.inventory.RecipeChoice; -+import org.jetbrains.annotations.ApiStatus; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.Objects; -+ -+/** -+ * Represents a potion mix made in a Brewing Stand. -+ */ -+@ApiStatus.NonExtendable -+public class PotionMix implements Keyed { -+ -+ private final NamespacedKey key; -+ private final ItemStack result; -+ private final RecipeChoice input; -+ private final RecipeChoice ingredient; -+ -+ /** -+ * Creates a new potion mix. Add it to the server with {@link org.bukkit.potion.PotionBrewer#addPotionMix(PotionMix)}. -+ * -+ * @param key a unique key for the mix -+ * @param result the resulting itemstack that will appear in the 3 bottom slots -+ * @param input the input placed into the bottom 3 slots -+ * @param ingredient the ingredient placed into the top slot -+ */ -+ public PotionMix(@NotNull NamespacedKey key, @NotNull ItemStack result, @NotNull RecipeChoice input, @NotNull RecipeChoice ingredient) { -+ this.key = key; -+ this.result = result; -+ this.input = input; -+ this.ingredient = ingredient; -+ } -+ -+ @Override -+ public @NotNull NamespacedKey getKey() { -+ return this.key; -+ } -+ -+ /** -+ * Gets the resulting itemstack after the brew has finished. -+ * -+ * @return the result itemstack -+ */ -+ public @NotNull ItemStack getResult() { -+ return this.result; -+ } -+ -+ /** -+ * Gets the input for the bottom 3 slots in the brewing stand. -+ * -+ * @return the bottom 3 slot ingredients -+ */ -+ public @NotNull RecipeChoice getInput() { -+ return this.input; -+ } -+ -+ /** -+ * Gets the ingredient in the top slot of the brewing stand. -+ * -+ * @return the top slot input -+ */ -+ public @NotNull RecipeChoice getIngredient() { -+ return this.ingredient; -+ } -+ -+ @Override -+ public String toString() { -+ return "PotionMix{" + -+ "result=" + this.result + -+ ", base=" + this.input + -+ ", addition=" + this.ingredient + -+ '}'; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (this == o) return true; -+ if (o == null || getClass() != o.getClass()) return false; -+ PotionMix potionMix = (PotionMix) o; -+ return this.key.equals(potionMix.key) && this.result.equals(potionMix.result) && this.input.equals(potionMix.input) && this.ingredient.equals(potionMix.ingredient); -+ } -+ -+ @Override -+ public int hashCode() { -+ return Objects.hash(this.key, this.result, this.input, this.ingredient); -+ } -+} -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index ac7674fb1c9d7bd9572c678f57cab44233328bdc..92a1462261029e804da73da2743bbd68e57841e9 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2414,6 +2414,15 @@ public final class Bukkit { - public static io.papermc.paper.datapack.DatapackManager getDatapackManager() { - return server.getDatapackManager(); - } -+ -+ /** -+ * Gets the potion brewer. -+ * -+ * @return the potion brewer -+ */ -+ public static @NotNull org.bukkit.potion.PotionBrewer getPotionBrewer() { -+ return server.getPotionBrewer(); -+ } - // Paper end - - @NotNull -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 871d80d0e0ce7cd80e34bfeebee8c543ea023d8e..56e261efa654e4a6872ccea28f0461df13845d13 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -2097,5 +2097,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - */ - @NotNull - io.papermc.paper.datapack.DatapackManager getDatapackManager(); -+ -+ /** -+ * Gets the potion brewer. -+ * -+ * @return the potion brewer -+ */ -+ @NotNull org.bukkit.potion.PotionBrewer getPotionBrewer(); - // Paper end - } -diff --git a/src/main/java/org/bukkit/potion/PotionBrewer.java b/src/main/java/org/bukkit/potion/PotionBrewer.java -index d21f407cc16cfd709c1cabf408e8d8d16aba7e1a..1598f34d306fb34ff7ffe7886b0d6e4abe734b6b 100644 ---- a/src/main/java/org/bukkit/potion/PotionBrewer.java -+++ b/src/main/java/org/bukkit/potion/PotionBrewer.java -@@ -43,4 +43,25 @@ public interface PotionBrewer { - */ - @NotNull - public Collection getEffects(@NotNull PotionType type, boolean upgraded, boolean extended); -+ -+ // Paper start -+ /** -+ * Adds a new potion mix recipe. -+ * -+ * @param potionMix the potion mix to add -+ */ -+ void addPotionMix(@NotNull io.papermc.paper.potion.PotionMix potionMix); -+ -+ /** -+ * Removes a potion mix recipe. -+ * -+ * @param key the key of the mix to remove -+ */ -+ void removePotionMix(@NotNull org.bukkit.NamespacedKey key); -+ -+ /** -+ * Resets potion mixes to their default, removing all custom ones. -+ */ -+ void resetPotionMixes(); -+ // Paper end - } diff --git a/patches/api/0371-Add-Player-Warden-Warning-API.patch b/patches/api/0371-Add-Player-Warden-Warning-API.patch new file mode 100644 index 000000000000..3b23da22254f --- /dev/null +++ b/patches/api/0371-Add-Player-Warden-Warning-API.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dawon +Date: Sat, 15 Oct 2022 00:46:32 +0200 +Subject: [PATCH] Add Player Warden Warning API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index c676524280cc091998859fe1945d06bb7f26560d..8873f0eb1451cd4e8801b75e8bd477eae588e73b 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3641,6 +3641,59 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param silent whether sound should be silenced + */ + void showElderGuardian(boolean silent); ++ ++ /** ++ * Returns the player's cooldown in ticks until the next Warden warning can occur. ++ * ++ * @return ticks until next Warden warning can occur. 0 means there is no cooldown left. ++ */ ++ int getWardenWarningCooldown(); ++ ++ /** ++ * Sets the player's cooldown in ticks until next Warden warning can occur. ++ * ++ * @param cooldown ticks until next Warden warning can occur. 0 means there is no cooldown left. Values less than 0 are set to 0. ++ */ ++ void setWardenWarningCooldown(int cooldown); ++ ++ /** ++ * Returns time since last Warden warning in ticks. ++ * ++ * @return ticks since last Warden warning ++ */ ++ int getWardenTimeSinceLastWarning(); ++ ++ /** ++ * Sets time since last Warden warning in ticks. ++ * ++ * @param time ticks since last Warden warning ++ */ ++ void setWardenTimeSinceLastWarning(int time); ++ ++ /** ++ * Returns the player's current Warden warning level. ++ * ++ * @return current Warden warning level ++ */ ++ int getWardenWarningLevel(); ++ ++ /** ++ * Sets the player's Warden warning level. ++ *

      ++ * Note: This will not actually spawn the Warden. ++ * Even if the warning level is over threshold, the player still needs to activate a Shrieker in order to summon the Warden. ++ * ++ * @param warningLevel player's Warden warning level. The warning level is internally limited to valid values. ++ */ ++ void setWardenWarningLevel(int warningLevel); ++ ++ /** ++ * Increases the player's Warden warning level if possible and not on cooldown. ++ *

      ++ * Note: This will not actually spawn the Warden. ++ * Even if the warning level is over threshold, the player still needs to activate a Shrieker in order to summon the Warden. ++ */ ++ void increaseWardenWarningLevel(); + // Paper end + + @NotNull diff --git a/patches/api/0372-More-Projectile-API.patch b/patches/api/0372-More-Projectile-API.patch deleted file mode 100644 index c9374b52dc0d..000000000000 --- a/patches/api/0372-More-Projectile-API.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Wed, 26 May 2021 19:34:43 -0400 -Subject: [PATCH] More Projectile API - - -diff --git a/src/main/java/org/bukkit/entity/Firework.java b/src/main/java/org/bukkit/entity/Firework.java -index d616d5941b3c7b85e350e845901da798601b9a3c..b7a6e3b1ac327c4e03f9d73952c1ce4d54967cf4 100644 ---- a/src/main/java/org/bukkit/entity/Firework.java -+++ b/src/main/java/org/bukkit/entity/Firework.java -@@ -15,6 +15,8 @@ public interface Firework extends Projectile { - - /** - * Apply the provided meta to the fireworks -+ *

      -+ * Adjusts detonation ticks automatically. - * - * @param meta The FireworkMeta to apply - */ -@@ -54,4 +56,52 @@ public interface Firework extends Projectile { - @org.jetbrains.annotations.Nullable - public LivingEntity getBoostedEntity(); - // Paper end -+ -+ // Paper start - Firework API -+ /** -+ * Gets the item used in the firework. -+ * -+ * @return firework item -+ */ -+ @NotNull -+ public org.bukkit.inventory.ItemStack getItem(); -+ -+ /** -+ * Sets the item used in the firework. -+ *

      -+ * Firework explosion effects are used from this item. -+ * -+ * @param itemStack item to set -+ */ -+ void setItem(@org.jetbrains.annotations.Nullable org.bukkit.inventory.ItemStack itemStack); -+ -+ /** -+ * Gets the number of ticks the firework has flown. -+ * -+ * @return ticks flown -+ */ -+ int getTicksFlown(); -+ -+ /** -+ * Sets the number of ticks the firework has flown. -+ * Setting this greater than detonation ticks will cause the firework to explode. -+ * -+ * @param ticks ticks flown -+ */ -+ void setTicksFlown(int ticks); -+ -+ /** -+ * Gets the number of ticks the firework will detonate on. -+ * -+ * @return the tick to detonate on -+ */ -+ int getTicksToDetonate(); -+ -+ /** -+ * Set the amount of ticks the firework will detonate on. -+ * -+ * @param ticks ticks to detonate on -+ */ -+ void setTicksToDetonate(int ticks); -+ // Paper stop - } -diff --git a/src/main/java/org/bukkit/entity/FishHook.java b/src/main/java/org/bukkit/entity/FishHook.java -index d1b37530319f6d37ee37f62080289c1e45848bc8..e94c7e279356c510f60508b26277d4891a4258fa 100644 ---- a/src/main/java/org/bukkit/entity/FishHook.java -+++ b/src/main/java/org/bukkit/entity/FishHook.java -@@ -162,4 +162,20 @@ public interface FishHook extends Projectile { - */ - BOBBING; - } -+ -+ // Paper start - More FishHook API -+ /** -+ * Get the number of ticks the hook needs to wait for a fish to bite. -+ * -+ * @return Number of ticks -+ */ -+ int getWaitTime(); -+ -+ /** -+ * Sets the number of ticks the hook needs to wait for a fish to bite. -+ * -+ * @param ticks Number of ticks -+ */ -+ void setWaitTime(int ticks); -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/entity/ThrownPotion.java b/src/main/java/org/bukkit/entity/ThrownPotion.java -index 10a3c297bd87ad3ab4555054858f47a479e76e1a..1afda5d6d948b7e8589e69d3cd2c045763b5e784 100644 ---- a/src/main/java/org/bukkit/entity/ThrownPotion.java -+++ b/src/main/java/org/bukkit/entity/ThrownPotion.java -@@ -32,12 +32,29 @@ public interface ThrownPotion extends Projectile { - - /** - * Set the ItemStack for this thrown potion. -- *

      -- * The ItemStack must be of type {@link org.bukkit.Material#SPLASH_POTION} -- * or {@link org.bukkit.Material#LINGERING_POTION}, otherwise an exception -- * is thrown. - * - * @param item New ItemStack - */ - public void setItem(@NotNull ItemStack item); -+ -+ // Paper start - Projectile API -+ /** -+ * Gets a copy of the PotionMeta for this thrown potion. -+ * This includes what effects will be applied by this potion. -+ * -+ * @return potion meta -+ */ -+ @NotNull -+ org.bukkit.inventory.meta.PotionMeta getPotionMeta(); -+ -+ /** -+ * Sets the PotionMeta of this thrown potion. -+ * This will modify the effects applied by this potion. -+ *

      -+ * Note that the type of {@link #getItem()} is irrelevant -+ * -+ * @param meta potion meta -+ */ -+ void setPotionMeta(@NotNull org.bukkit.inventory.meta.PotionMeta meta); -+ // Paper end - } diff --git a/patches/api/0372-More-vanilla-friendly-methods-to-update-trades.patch b/patches/api/0372-More-vanilla-friendly-methods-to-update-trades.patch new file mode 100644 index 000000000000..b56f34f9d14d --- /dev/null +++ b/patches/api/0372-More-vanilla-friendly-methods-to-update-trades.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Sun, 16 Oct 2022 15:58:38 +0200 +Subject: [PATCH] More vanilla friendly methods to update trades + + +diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java +index 163f1afde2e04fdf4dddb894da62b301b52ed539..bc7137eb802d4613d042fba5fd97eca54a6eea29 100644 +--- a/src/main/java/org/bukkit/entity/Villager.java ++++ b/src/main/java/org/bukkit/entity/Villager.java +@@ -64,8 +64,11 @@ public interface Villager extends AbstractVillager { + * A villager with a level of 1 and no experience is liable to lose its + * profession. + * ++ * This doesn't update the trades of this villager. ++ * + * @param level the new level + * @throws IllegalArgumentException if level not between [1, 5] ++ * @see #increaseLevel(int) + */ + public void setVillagerLevel(int level); + +@@ -85,6 +88,34 @@ public interface Villager extends AbstractVillager { + public void setVillagerExperience(int experience); + + // Paper start ++ /** ++ * Increases the level of this villager. ++ * The villager will also unlock new recipes unlike the raw ++ * method {@link #setVillagerLevel(int)}. ++ *

      ++ * A villager with a level of 1 and no experience is liable to lose its ++ * profession. ++ *

      ++ * A master villager has a level of 5 in its profession and ++ * will unlock 10 trades (2 per level). ++ * ++ * @param amount The amount of level ++ * @return Whether trades are unlocked ++ * @throws IllegalArgumentException if current level plus the amount ++ * isn't between [1, 5] or the amount isn't positive ++ * @see #setVillagerLevel(int) ++ */ ++ boolean increaseLevel(int amount); ++ ++ /** ++ * Gives to this villager some potential new trades ++ * based to its profession and level. ++ * @param amount The amount of trades to give ++ * @return Whether trades are added ++ * @throws IllegalArgumentException if the amount isn't positive ++ */ ++ boolean addTrades(int amount); ++ + /** + * Gets the amount of times a villager has restocked their trades today + * @return The amount of trade restocks. diff --git a/patches/api/0373-Add-getComputedBiome-API.patch b/patches/api/0373-Add-getComputedBiome-API.patch deleted file mode 100644 index b192af710193..000000000000 --- a/patches/api/0373-Add-getComputedBiome-API.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Mon, 14 Mar 2022 22:45:32 -0700 -Subject: [PATCH] Add getComputedBiome API - - -diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java -index 43b53c21af01e0f496c8aaacff82dfdfadaf40f6..3f7e860de4e28745fcdf8d2f41f4a8c210f48909 100644 ---- a/src/main/java/org/bukkit/RegionAccessor.java -+++ b/src/main/java/org/bukkit/RegionAccessor.java -@@ -26,6 +26,7 @@ public interface RegionAccessor extends Keyed { // Paper - * - * @param location the location of the biome - * @return Biome at the given location -+ * @see #getComputedBiome(int, int, int) - */ - @NotNull - Biome getBiome(@NotNull Location location); -@@ -37,10 +38,33 @@ public interface RegionAccessor extends Keyed { // Paper - * @param y Y-coordinate of the block - * @param z Z-coordinate of the block - * @return Biome at the given coordinates -+ * @see #getComputedBiome(int, int, int) - */ - @NotNull - Biome getBiome(int x, int y, int z); - -+ // Paper start -+ /** -+ * Gets the computed {@link Biome} at the given coordinates. -+ * -+ *

      The computed Biome is the Biome as seen by clients for rendering -+ * purposes and in the "F3" debug menu. This is computed by looking at the noise biome -+ * at this and surrounding quarts and applying complex math operations.

      -+ * -+ *

      Most other Biome-related methods named getBiome, setBiome, and similar -+ * operate on the "noise biome", which is stored per-quart, or in other words, -+ * 1 Biome per 4x4x4 block region. This is how Biomes are currently generated and -+ * stored on disk.

      -+ * -+ * @param x X-coordinate of the block -+ * @param y Y-coordinate of the block -+ * @param z Z-coordinate of the block -+ * @return Biome at the given coordinates -+ */ -+ @NotNull -+ Biome getComputedBiome(int x, int y, int z); -+ // Paper end -+ - /** - * Sets the {@link Biome} at the given {@link Location}. - * -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index cff39708e66208921da15d12d94407d6b6950298..e405c279f6135c94c775a856ab88fd3cace6bd5c 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -370,10 +370,22 @@ public interface Block extends Metadatable, net.kyori.adventure.translation.Tran - * Returns the biome that this block resides in - * - * @return Biome type containing this block -+ * @see #getComputedBiome() - */ - @NotNull - Biome getBiome(); - -+ // Paper start -+ /** -+ * Gets the computed biome at the location of this Block. -+ * -+ * @return computed biome at the location of this Block. -+ * @see org.bukkit.RegionAccessor#getComputedBiome(int, int, int) -+ */ -+ @NotNull -+ Biome getComputedBiome(); -+ // Paper end -+ - /** - * Sets the biome that this block resides in - * diff --git a/patches/api/0373-Add-paper-dumplisteners-command.patch b/patches/api/0373-Add-paper-dumplisteners-command.patch new file mode 100644 index 000000000000..8ad550e4eede --- /dev/null +++ b/patches/api/0373-Add-paper-dumplisteners-command.patch @@ -0,0 +1,175 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Sat, 19 Nov 2022 19:46:44 +0100 +Subject: [PATCH] Add /paper dumplisteners command + + +diff --git a/src/main/java/co/aikar/timings/TimedEventExecutor.java b/src/main/java/co/aikar/timings/TimedEventExecutor.java +index a3ad690691eb5537a565d7ba684354acfec5ee2d..157617933a772451f6c073d97afaf305769b4d40 100644 +--- a/src/main/java/co/aikar/timings/TimedEventExecutor.java ++++ b/src/main/java/co/aikar/timings/TimedEventExecutor.java +@@ -84,4 +84,10 @@ public class TimedEventExecutor implements EventExecutor { + executor.execute(listener, event); + } + } ++ ++ @Override ++ @NotNull ++ public String toString() { ++ return "TimedEventExecutor['" + this.executor.toString() + "']"; ++ } + } +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java +index 5a702481d28d90cb503faad0d9b9c3231bbff940..2a169d2f6fdada6c361ee4291abb38446d45d654 100644 +--- a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java ++++ b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java +@@ -18,10 +18,12 @@ public class MethodHandleEventExecutor implements EventExecutor { + + private final Class eventClass; + private final MethodHandle handle; ++ private final @Nullable Method method; + + public MethodHandleEventExecutor(final Class eventClass, final MethodHandle handle) { + this.eventClass = eventClass; + this.handle = handle; ++ this.method = null; + } + + public MethodHandleEventExecutor(final Class eventClass, final Method m) { +@@ -32,6 +34,7 @@ public class MethodHandleEventExecutor implements EventExecutor { + } catch (final IllegalAccessException e) { + throw new AssertionError("Unable to set accessible", e); + } ++ this.method = m; + } + + @Override +@@ -43,4 +46,9 @@ public class MethodHandleEventExecutor implements EventExecutor { + SneakyThrow.sneaky(t); + } + } ++ ++ @Override ++ public String toString() { ++ return "MethodHandleEventExecutor['" + this.method + "']"; ++ } + } +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java +index bbdb5b472df116b71c459bdc6cc4b74267ea0f5e..e98962b6c6651c580684d8580484de87b5ad65a5 100644 +--- a/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java ++++ b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java +@@ -19,6 +19,7 @@ public class StaticMethodHandleEventExecutor implements EventExecutor { + + private final Class eventClass; + private final MethodHandle handle; ++ private final Method method; + + public StaticMethodHandleEventExecutor(final Class eventClass, final Method m) { + Preconditions.checkArgument(Modifier.isStatic(m.getModifiers()), "Not a static method: %s", m); +@@ -30,6 +31,7 @@ public class StaticMethodHandleEventExecutor implements EventExecutor { + } catch (final IllegalAccessException e) { + throw new AssertionError("Unable to set accessible", e); + } ++ this.method = m; + } + + @Override +@@ -41,4 +43,9 @@ public class StaticMethodHandleEventExecutor implements EventExecutor { + SneakyThrow.sneaky(throwable); + } + } ++ ++ @Override ++ public String toString() { ++ return "StaticMethodHandleEventExecutor['" + this.method + "']"; ++ } + } +diff --git a/src/main/java/org/bukkit/event/HandlerList.java b/src/main/java/org/bukkit/event/HandlerList.java +index ed78cca71f83b296d082d0af147ca8d622c7606a..2292bd460ce2be113beb4ba6b4eb19350060f01c 100644 +--- a/src/main/java/org/bukkit/event/HandlerList.java ++++ b/src/main/java/org/bukkit/event/HandlerList.java +@@ -33,6 +33,13 @@ public class HandlerList { + */ + private static ArrayList allLists = new ArrayList(); + ++ // Paper start ++ /** ++ * Event types which have instantiated a {@link HandlerList}. ++ */ ++ private static final java.util.Set EVENT_TYPES = java.util.concurrent.ConcurrentHashMap.newKeySet(); ++ // Paper end ++ + /** + * Bake all handler lists. Best used just after all normal event + * registration is complete, ie just after all plugins are loaded if +@@ -94,6 +101,12 @@ public class HandlerList { + * The HandlerList is then added to meta-list for use in bakeAll() + */ + public HandlerList() { ++ // Paper start ++ java.lang.StackWalker.getInstance(java.util.EnumSet.of(java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE), 4) ++ .walk(s -> s.filter(f -> Event.class.isAssignableFrom(f.getDeclaringClass())).findFirst()) ++ .map(f -> f.getDeclaringClass().getName()) ++ .ifPresent(EVENT_TYPES::add); ++ // Paper end + handlerslots = new EnumMap>(EventPriority.class); + for (EventPriority o : EventPriority.values()) { + handlerslots.put(o, new ArrayList()); +diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java +index 5fa52419f21d8e8b3d8f9aafd248b05774a28348..60e086be70529e0804280b24a2a3e7ae72d8d363 100644 +--- a/src/main/java/org/bukkit/plugin/EventExecutor.java ++++ b/src/main/java/org/bukkit/plugin/EventExecutor.java +@@ -70,9 +70,18 @@ public interface EventExecutor { + try { + EventExecutor asmExecutor = executorClass.newInstance(); + // Define a wrapper to conform to bukkit stupidity (passing in events that don't match and wrapper exception) +- return (listener, event) -> { +- if (!eventClass.isInstance(event)) return; +- asmExecutor.execute(listener, event); ++ return new EventExecutor() { ++ @Override ++ public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { ++ if (!eventClass.isInstance(event)) return; ++ asmExecutor.execute(listener, event); ++ } ++ ++ @Override ++ @NotNull ++ public String toString() { ++ return "ASMEventExecutor['" + m + "']"; ++ } + }; + } catch (InstantiationException | IllegalAccessException e) { + throw new AssertionError("Unable to initialize generated event executor", e); +diff --git a/src/main/java/org/bukkit/plugin/RegisteredListener.java b/src/main/java/org/bukkit/plugin/RegisteredListener.java +index 419aec56b0e3fa8bcec2ea7f340caa3456b57d00..3b3d9642a8d63798dc28f2f8df77f0466451cbff 100644 +--- a/src/main/java/org/bukkit/plugin/RegisteredListener.java ++++ b/src/main/java/org/bukkit/plugin/RegisteredListener.java +@@ -78,4 +78,27 @@ public class RegisteredListener { + public boolean isIgnoringCancelled() { + return ignoreCancelled; + } ++ ++ // Paper start ++ /** ++ * Get the executor for this registration. ++ * ++ * @return executor ++ */ ++ @NotNull ++ public EventExecutor getExecutor() { ++ return this.executor; ++ } ++ ++ @Override ++ public String toString() { ++ return "RegisteredListener{" ++ + "plugin=\"" + this.plugin.getName() ++ + "\", listener=\"" + this.listener ++ + "\", executor=\"" + this.executor ++ + "\", priority=\"" + this.priority.name() + " (" + this.priority.getSlot() + ")" ++ + "\", ignoringCancelled=" + this.ignoreCancelled ++ + "}"; ++ } ++ // Paper end + } diff --git a/patches/api/0374-Add-enchantWithLevels-API.patch b/patches/api/0374-Add-enchantWithLevels-API.patch deleted file mode 100644 index 394fcb62bf2c..000000000000 --- a/patches/api/0374-Add-enchantWithLevels-API.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Wed, 16 Mar 2022 20:35:13 -0700 -Subject: [PATCH] Add enchantWithLevels API - - -diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java -index 2acafae468fcbb7213d6b6c30803a3924a3bbc30..40edff7c93b6bf75de81102326667135b9344666 100644 ---- a/src/main/java/org/bukkit/inventory/ItemFactory.java -+++ b/src/main/java/org/bukkit/inventory/ItemFactory.java -@@ -161,6 +161,22 @@ public interface ItemFactory { - Material updateMaterial(@NotNull final ItemMeta meta, @NotNull final Material material) throws IllegalArgumentException; - - // Paper start -+ /** -+ * Randomly enchants a copy of the provided {@link ItemStack} using the given experience levels. -+ * -+ *

      If the provided ItemStack is already enchanted, the existing enchants will be removed before enchanting.

      -+ * -+ *

      Levels must be in range {@code [1, 30]}.

      -+ * -+ * @param itemStack ItemStack to enchant -+ * @param levels levels to use for enchanting -+ * @param allowTreasure whether to allow enchantments where {@link org.bukkit.enchantments.Enchantment#isTreasure()} returns true -+ * @param random {@link java.util.Random} instance to use for enchanting -+ * @return enchanted copy of the provided ItemStack -+ * @throws IllegalArgumentException on bad arguments -+ */ -+ @NotNull ItemStack enchantWithLevels(@NotNull ItemStack itemStack, @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, boolean allowTreasure, @NotNull java.util.Random random); -+ - /** - * Creates a hover event for the given item. - * -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 77ef41527a05e2d7899633ef7fa813774dd15bd9..b8a344fd900dcbd4b28085a54b85b16c742e9c6f 100644 ---- a/src/main/java/org/bukkit/inventory/ItemStack.java -+++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -648,6 +648,24 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - } - - // Paper start -+ /** -+ * Randomly enchants a copy of this {@link ItemStack} using the given experience levels. -+ * -+ *

      If this ItemStack is already enchanted, the existing enchants will be removed before enchanting.

      -+ * -+ *

      Levels must be in range {@code [1, 30]}.

      -+ * -+ * @param levels levels to use for enchanting -+ * @param allowTreasure whether to allow enchantments where {@link org.bukkit.enchantments.Enchantment#isTreasure()} returns true -+ * @param random {@link java.util.Random} instance to use for enchanting -+ * @return enchanted copy of the provided ItemStack -+ * @throws IllegalArgumentException on bad arguments -+ */ -+ @NotNull -+ public ItemStack enchantWithLevels(final @org.jetbrains.annotations.Range(from = 1, to = 30) int levels, final boolean allowTreasure, final @NotNull java.util.Random random) { -+ return Bukkit.getServer().getItemFactory().enchantWithLevels(this, levels, allowTreasure, random); -+ } -+ - @NotNull - @Override - public net.kyori.adventure.text.event.HoverEvent asHoverEvent(final @NotNull java.util.function.UnaryOperator op) { diff --git a/patches/api/0374-ItemStack-damage-API.patch b/patches/api/0374-ItemStack-damage-API.patch new file mode 100644 index 000000000000..56fe1421a75b --- /dev/null +++ b/patches/api/0374-ItemStack-damage-API.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 8 May 2022 13:35:58 -0700 +Subject: [PATCH] ItemStack damage API + +Adds methods notify clients about item breaks and +to simulate damage done to an itemstack and all +the logic associated with damaging them + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 8ee3f82049541041623c10940bdda1746200b1e6..fd4d74a637a93c85a057e867b8c07e574916175a 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1375,4 +1375,53 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + void knockback(double strength, double directionX, double directionZ); + // Paper end - knockback API ++ ++ // Paper start - ItemStack damage API ++ /** ++ * Notifies all clients tracking this entity that the item in ++ * the slot of this entity broke. ++ *

      ++ * NOTE: this does not mutate any entity state ++ * ++ * @param slot the slot ++ */ ++ void broadcastSlotBreak(org.bukkit.inventory.@NotNull EquipmentSlot slot); ++ ++ /** ++ * Notifies specified players that the item in the slot ++ * of this entity broke. ++ *

      ++ * NOTE: this does not mutate any entity state ++ * ++ * @param slot the slot ++ * @param players the players to notify ++ */ ++ void broadcastSlotBreak(org.bukkit.inventory.@NotNull EquipmentSlot slot, @NotNull Collection players); ++ ++ /** ++ * Damages the itemstack in this slot by the specified amount. ++ *

      ++ * This runs all logic associated with damaging an itemstack like ++ * gamemode and enchantment checks, events, stat changes, and advancement ++ * triggers. ++ * ++ * @param stack the itemstack to damage ++ * @param amount the amount of damage to do ++ * @return the damaged itemstack, or an empty stack if it broke. There are no ++ * guarantees the returned itemstack is the same instance ++ */ ++ @NotNull ItemStack damageItemStack(@NotNull ItemStack stack, int amount); ++ ++ /** ++ * Damages the itemstack in this slot by the specified amount. ++ *

      ++ * This runs all logic associated with damaging an itemstack like ++ * gamemode and enchantment checks, events, stat changes, advancement ++ * triggers, and notifying clients to play break animations. ++ * ++ * @param slot the slot of the stack to damage ++ * @param amount the amount of damage to do ++ */ ++ void damageItemStack(org.bukkit.inventory.@NotNull EquipmentSlot slot, int amount); ++ // Paper end - ItemStack damage API + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index e9b88bb759af1a5c926d3d4c30a333e7720519cd..6393e5249b4469b1c8ebfb05a0f09572d116c40f 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -1090,5 +1090,19 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + public boolean canRepair(@NotNull ItemStack toBeRepaired) { + return Bukkit.getUnsafe().isValidRepairItemStack(toBeRepaired, this); + } ++ ++ /** ++ * Damages this itemstack by the specified amount. This ++ * runs all logic associated with damaging an itemstack like ++ * events and stat changes. ++ * ++ * @param amount the amount of damage to do ++ * @param livingEntity the entity related to the damage ++ * @return the damaged itemstack or an empty one if it broke. May return the same instance of ItemStack ++ * @see org.bukkit.entity.LivingEntity#damageItemStack(EquipmentSlot, int) to damage itemstacks in equipment slots ++ */ ++ public @NotNull ItemStack damage(int amount, @NotNull org.bukkit.entity.LivingEntity livingEntity) { ++ return livingEntity.damageItemStack(this, amount); ++ } + // Paper end + } diff --git a/patches/api/0375-Add-TameableDeathMessageEvent.patch b/patches/api/0375-Add-TameableDeathMessageEvent.patch deleted file mode 100644 index 6152eacbe6e6..000000000000 --- a/patches/api/0375-Add-TameableDeathMessageEvent.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Fri, 19 Mar 2021 23:25:38 -0400 -Subject: [PATCH] Add TameableDeathMessageEvent - - -diff --git a/src/main/java/io/papermc/paper/event/entity/TameableDeathMessageEvent.java b/src/main/java/io/papermc/paper/event/entity/TameableDeathMessageEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..70cd37aefbd5d64c798ab2fc3b6d502134690348 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/TameableDeathMessageEvent.java -@@ -0,0 +1,69 @@ -+package io.papermc.paper.event.entity; -+ -+import net.kyori.adventure.text.Component; -+import org.bukkit.entity.Tameable; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a {@link Tameable} dies and sends a death message. -+ */ -+public class TameableDeathMessageEvent extends EntityEvent implements Cancellable { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private Component deathMessage; -+ -+ public TameableDeathMessageEvent(@NotNull Tameable what, @NotNull Component deathMessage) { -+ super(what); -+ this.deathMessage = deathMessage; -+ } -+ -+ /** -+ * Set the death message that appears to the owner of the tameable. -+ * -+ * @param deathMessage Death message to appear -+ */ -+ public void deathMessage(@NotNull Component deathMessage) { -+ this.deathMessage = deathMessage; -+ } -+ -+ /** -+ * Get the death message that appears to the owner of the tameable. -+ * -+ * @return Death message to appear -+ */ -+ @NotNull -+ public Component deathMessage() { -+ return deathMessage; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public Tameable getEntity() { -+ return (Tameable) super.getEntity(); -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0375-Add-Tick-TemporalUnit.patch b/patches/api/0375-Add-Tick-TemporalUnit.patch new file mode 100644 index 000000000000..2f5ad025dd49 --- /dev/null +++ b/patches/api/0375-Add-Tick-TemporalUnit.patch @@ -0,0 +1,162 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kieran Wallbanks +Date: Fri, 2 Apr 2021 17:28:58 +0100 +Subject: [PATCH] Add Tick TemporalUnit + + +diff --git a/src/main/java/io/papermc/paper/util/Tick.java b/src/main/java/io/papermc/paper/util/Tick.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1b264819c6faf2a4390d76350deb8e93804c6772 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/Tick.java +@@ -0,0 +1,101 @@ ++package io.papermc.paper.util; ++ ++import java.time.Duration; ++import java.time.temporal.ChronoUnit; ++import java.time.temporal.Temporal; ++import java.time.temporal.TemporalUnit; ++import java.util.Objects; ++import net.kyori.adventure.util.Ticks; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A TemporalUnit that represents the target length of one server tick. This is defined ++ * as 50 milliseconds. Note that this class is not for measuring the length that a tick ++ * took, rather it is used for simple conversion between times and ticks. ++ * ++ * @see #tick() ++ */ ++@NullMarked ++public final class Tick implements TemporalUnit { ++ ++ private static final Tick INSTANCE = new Tick(Ticks.SINGLE_TICK_DURATION_MS); ++ ++ private final long milliseconds; ++ ++ /** ++ * Gets the instance of the tick temporal unit. ++ * ++ * @return the tick instance ++ */ ++ public static Tick tick() { ++ return INSTANCE; ++ } ++ ++ /** ++ * Creates a new tick. ++ * ++ * @param length the length of the tick in milliseconds ++ * @see #tick() ++ */ ++ private Tick(final long length) { ++ this.milliseconds = length; ++ } ++ ++ /** ++ * Creates a duration from an amount of ticks. This is shorthand for ++ * {@link Duration#of(long, TemporalUnit)} called with the amount of ticks and ++ * {@link #tick()}. ++ * ++ * @param ticks the amount of ticks ++ * @return the duration ++ */ ++ public static Duration of(final long ticks) { ++ return Duration.of(ticks, INSTANCE); ++ } ++ ++ /** ++ * Gets the number of whole ticks that occur in the provided duration. Note that this ++ * method returns an {@code int} as this is the unit that Minecraft stores ticks in. ++ * ++ * @param duration the duration ++ * @return the number of whole ticks in this duration ++ * @throws ArithmeticException if the duration is zero or an overflow occurs ++ */ ++ public int fromDuration(final Duration duration) { ++ Objects.requireNonNull(duration, "duration cannot be null"); ++ return Math.toIntExact(Math.floorDiv(duration.toMillis(), this.milliseconds)); ++ } ++ ++ @Override ++ public Duration getDuration() { ++ return Duration.ofMillis(this.milliseconds); ++ } ++ ++ // Note: This is a workaround in order to allow calculations with this duration. ++ // See: Duration#add ++ @Override ++ public boolean isDurationEstimated() { ++ return false; ++ } ++ ++ @Override ++ public boolean isDateBased() { ++ return false; ++ } ++ ++ @Override ++ public boolean isTimeBased() { ++ return true; ++ } ++ ++ @SuppressWarnings("unchecked") // following ChronoUnit#addTo ++ @Override ++ public R addTo(final R temporal, final long amount) { ++ return (R) temporal.plus(this.getDuration().multipliedBy(amount)); ++ } ++ ++ @Override ++ public long between(final Temporal start, final Temporal end) { ++ return start.until(end, ChronoUnit.MILLIS) / this.milliseconds; ++ } ++} +diff --git a/src/test/java/io/papermc/paper/util/TickTest.java b/src/test/java/io/papermc/paper/util/TickTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f147d909f2fc710c1d12bac3c7b66c2883139026 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/util/TickTest.java +@@ -0,0 +1,43 @@ ++package io.papermc.paper.util; ++ ++import java.time.Duration; ++import java.time.Instant; ++import java.time.temporal.ChronoUnit; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++ ++public class TickTest { ++ ++ @Test ++ public void testTickLength() { ++ assertEquals(50, Duration.of(1, Tick.tick()).toMillis()); ++ assertEquals(100, Duration.of(2, Tick.tick()).toMillis()); ++ } ++ ++ @Test ++ public void testTickFromDuration() { ++ assertEquals(0, Tick.tick().fromDuration(Duration.ofMillis(0))); ++ assertEquals(0, Tick.tick().fromDuration(Duration.ofMillis(10))); ++ assertEquals(1, Tick.tick().fromDuration(Duration.ofMillis(60))); ++ assertEquals(2, Tick.tick().fromDuration(Duration.ofMillis(100))); ++ } ++ ++ @Test ++ public void testAddTickToInstant() { ++ Instant now = Instant.now(); ++ assertEquals(now, now.plus(0, Tick.tick())); ++ assertEquals(now.plus(50, ChronoUnit.MILLIS), now.plus(1, Tick.tick())); ++ assertEquals(now.plus(100, ChronoUnit.MILLIS), now.plus(2, Tick.tick())); ++ assertEquals(now.plus(150, ChronoUnit.MILLIS), now.plus(3, Tick.tick())); ++ } ++ ++ @Test ++ public void testTicksBetweenInstants() { ++ Instant now = Instant.now(); ++ assertEquals(0, now.until(now.plus(20, ChronoUnit.MILLIS), Tick.tick())); ++ assertEquals(1, now.until(now.plus(50, ChronoUnit.MILLIS), Tick.tick())); ++ assertEquals(1, now.until(now.plus(60, ChronoUnit.MILLIS), Tick.tick())); ++ assertEquals(2, now.until(now.plus(100, ChronoUnit.MILLIS), Tick.tick())); ++ } ++} diff --git a/patches/api/0376-Allow-to-change-the-podium-of-the-EnderDragon.patch b/patches/api/0376-Allow-to-change-the-podium-of-the-EnderDragon.patch deleted file mode 100644 index b86913ddbe3c..000000000000 --- a/patches/api/0376-Allow-to-change-the-podium-of-the-EnderDragon.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Doc -Date: Sat, 2 Apr 2022 23:03:32 -0300 -Subject: [PATCH] Allow to change the podium of the EnderDragon - - -diff --git a/src/main/java/org/bukkit/entity/EnderDragon.java b/src/main/java/org/bukkit/entity/EnderDragon.java -index 856015b08bfa3f18b3df11e25efd079d4a4f7eca..23cbaf886e230d38b3023923f74d1a6c34cd9b9d 100644 ---- a/src/main/java/org/bukkit/entity/EnderDragon.java -+++ b/src/main/java/org/bukkit/entity/EnderDragon.java -@@ -104,4 +104,22 @@ public interface EnderDragon extends ComplexLivingEntity, Boss, Mob { - * @return this dragon's death animation ticks - */ - int getDeathAnimationTicks(); -+ -+ // Paper start -+ -+ /** -+ * Get the podium location used by the ender dragon. -+ * -+ * @return the podium location of the dragon -+ */ -+ @NotNull -+ org.bukkit.Location getPodium(); -+ -+ /** -+ * Sets the location of the podium for the ender dragon. -+ * -+ * @param location the location of the podium or null to use the default podium location (exit portal of the end) -+ */ -+ void setPodium(@Nullable org.bukkit.Location location); -+ // Paper end - } diff --git a/patches/api/0376-Friction-API.patch b/patches/api/0376-Friction-API.patch new file mode 100644 index 000000000000..8c1155dd714a --- /dev/null +++ b/patches/api/0376-Friction-API.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Wed, 15 Sep 2021 20:40:51 +0200 +Subject: [PATCH] Friction API + + +diff --git a/src/main/java/io/papermc/paper/entity/Frictional.java b/src/main/java/io/papermc/paper/entity/Frictional.java +new file mode 100644 +index 0000000000000000000000000000000000000000..315558d8a592f7238f45fd1e68b70476e721be92 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/Frictional.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper.entity; ++ ++import net.kyori.adventure.util.TriState; ++import org.bukkit.entity.Entity; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents an {@link Entity} that can experience friction with the air and ground. ++ */ ++@NullMarked ++public interface Frictional { ++ ++ /** ++ * Gets the friction state of this entity. ++ * When set to {@link TriState#TRUE}, the entity will always experience friction. ++ * When set to {@link TriState#FALSE}, the entity will never experience friction. ++ * When set to {@link TriState#NOT_SET}, the entity will fall back to Minecraft's default behaviour. ++ * ++ * @return the entity's friction state ++ */ ++ TriState getFrictionState(); ++ ++ /** ++ * Sets the friction state of this entity. ++ * When set to {@link TriState#TRUE}, the entity will always experience friction. ++ * When set to {@link TriState#FALSE}, the entity will never experience friction. ++ * When set to {@link TriState#NOT_SET}, the entity will fall back to Minecraft's default behaviour. ++ *

      ++ * Please note that changing this value will do nothing for a player. ++ * ++ * @param state the new friction state to set for the entity ++ */ ++ void setFrictionState(TriState state); ++ ++} +diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java +index ced419f8655bff72f0257b639d5f7d73afe3c2e2..bcc6ba95bd21c7972865838c636a03f50b6c1f1a 100644 +--- a/src/main/java/org/bukkit/entity/Item.java ++++ b/src/main/java/org/bukkit/entity/Item.java +@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a dropped item. + */ +-public interface Item extends Entity { ++public interface Item extends Entity, io.papermc.paper.entity.Frictional { // Paper + + /** + * Gets the item stack associated with this item drop. +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index fd4d74a637a93c85a057e867b8c07e574916175a..8cc4ab8f560f5db9cf7f58233578838945a52deb 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -27,7 +27,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a living entity, such as a monster or player + */ +-public interface LivingEntity extends Attributable, Damageable, ProjectileSource { ++public interface LivingEntity extends Attributable, Damageable, ProjectileSource, io.papermc.paper.entity.Frictional { // Paper + + /** + * Gets the height of the living entity's eyes above its Location. +diff --git a/src/main/java/org/bukkit/entity/Minecart.java b/src/main/java/org/bukkit/entity/Minecart.java +index c3c94a5694f1e8d79e5acc45af1cd2e0fa6a621f..0e4163c9358dc2dc6b8b0aca1da0f59c805e47f4 100644 +--- a/src/main/java/org/bukkit/entity/Minecart.java ++++ b/src/main/java/org/bukkit/entity/Minecart.java +@@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a minecart entity. + */ +-public interface Minecart extends Vehicle { ++public interface Minecart extends Vehicle, io.papermc.paper.entity.Frictional { // Paper + + /** + * Sets a minecart's damage. diff --git a/patches/api/0377-Player-Entity-Tracking-Events.patch b/patches/api/0377-Player-Entity-Tracking-Events.patch new file mode 100644 index 000000000000..ff550d451b2d --- /dev/null +++ b/patches/api/0377-Player-Entity-Tracking-Events.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yannick Lamprecht +Date: Wed, 30 Mar 2022 18:16:37 +0200 +Subject: [PATCH] Player Entity Tracking Events + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerTrackEntityEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerTrackEntityEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0e37c8c94a77f6f1c2c4f5290722ca02d76ab924 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerTrackEntityEvent.java +@@ -0,0 +1,60 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Is called when a {@link Player} tracks an {@link Entity}. ++ *

      ++ * If cancelled entity is not shown to the player and interaction in both directions is not possible. ++ *

      ++ * Adding or removing entities from the world at the point in time this event is called is completely ++ * unsupported and should be avoided. ++ */ ++@NullMarked ++public class PlayerTrackEntityEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Entity entity; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerTrackEntityEvent(final Player player, final Entity entity) { ++ super(player); ++ this.entity = entity; ++ } ++ ++ /** ++ * Gets the entity that will be tracked ++ * ++ * @return the entity tracked ++ */ ++ public Entity getEntity() { ++ return this.entity; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerUntrackEntityEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerUntrackEntityEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..30e01ffc8b0d4a8e43a046d85f1903cc20e0e84d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerUntrackEntityEvent.java +@@ -0,0 +1,46 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Is called when a {@link Player} untracks an {@link Entity}. ++ *

      ++ * Adding or removing entities from the world at the point in time this event is called is completely ++ * unsupported and should be avoided. ++ */ ++@NullMarked ++public class PlayerUntrackEntityEvent extends PlayerEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Entity entity; ++ ++ @ApiStatus.Internal ++ public PlayerUntrackEntityEvent(final Player player, final Entity entity) { ++ super(player); ++ this.entity = entity; ++ } ++ ++ /** ++ * Gets the entity that will be untracked ++ * ++ * @return the entity untracked ++ */ ++ public Entity getEntity() { ++ return this.entity; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0378-Update-Folder-Uses-Plugin-Name.patch b/patches/api/0378-Update-Folder-Uses-Plugin-Name.patch deleted file mode 100644 index a8338f699b3e..000000000000 --- a/patches/api/0378-Update-Folder-Uses-Plugin-Name.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Xemorr <31805746+Xemorr@users.noreply.github.com> -Date: Fri, 1 Apr 2022 19:57:40 +0100 -Subject: [PATCH] Update Folder Uses Plugin Name - - -diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index 45114d587a8f201778adcba16c8a019f9959f472..ed07f5820281b139739f673fa4e25171de81b894 100644 ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -395,7 +395,7 @@ public final class SimplePluginManager implements PluginManager { - public synchronized Plugin loadPlugin(@NotNull File file) throws InvalidPluginException, UnknownDependencyException { - Preconditions.checkArgument(file != null, "File cannot be null"); - -- checkUpdate(file); -+ file = checkUpdate(file); // Paper - update the reference in case checkUpdate renamed it - - Set filters = fileAssociations.keySet(); - Plugin result = null; -@@ -422,16 +422,56 @@ public final class SimplePluginManager implements PluginManager { - return result; - } - -- private void checkUpdate(@NotNull File file) { -+ // Paper start - Update Folder Uses Plugin Name to replace -+ /** -+ * Replaces a plugin with a plugin of the same plugin name in the update folder. -+ * @param file -+ * @throws InvalidPluginException -+ */ -+ private File checkUpdate(@NotNull File file) throws InvalidPluginException { - if (updateDirectory == null || !updateDirectory.isDirectory()) { -- return; -+ return file; -+ } -+ PluginLoader pluginLoader = getPluginLoader(file); -+ try { -+ String pluginName = pluginLoader.getPluginDescription(file).getName(); -+ for (File updateFile : updateDirectory.listFiles()) { -+ if (!updateFile.isFile()) continue; -+ PluginLoader updatePluginLoader = getPluginLoader(updateFile); -+ if (updatePluginLoader == null) continue; -+ String updatePluginName; -+ try { -+ updatePluginName = updatePluginLoader.getPluginDescription(updateFile).getName(); -+ // We failed to load this data for some reason, so, we'll skip over this -+ } catch (InvalidDescriptionException ex) { -+ continue; -+ } -+ if (!pluginName.equals(updatePluginName)) continue; -+ if (!FileUtil.copy(updateFile, file)) continue; -+ File newName = new File(file.getParentFile(), updateFile.getName()); -+ file.renameTo(newName); -+ updateFile.delete(); -+ return newName; -+ } -+ } -+ catch (InvalidDescriptionException e) { -+ throw new InvalidPluginException(e); - } -+ return file; -+ } - -- File updateFile = new File(updateDirectory, file.getName()); -- if (updateFile.isFile() && FileUtil.copy(updateFile, file)) { -- updateFile.delete(); -+ @Nullable -+ private PluginLoader getPluginLoader(File file) { -+ Set filters = fileAssociations.keySet(); -+ for (Pattern filter : filters) { -+ Matcher match = filter.matcher(file.getName()); -+ if (match.find()) { -+ return fileAssociations.get(filter); -+ } - } -+ return null; - } -+ // Paper end - - /** - * Checks if the given plugin is loaded and returns it when applicable diff --git a/patches/api/0378-fix-Instruments.patch b/patches/api/0378-fix-Instruments.patch new file mode 100644 index 000000000000..3ce4ac68fafa --- /dev/null +++ b/patches/api/0378-fix-Instruments.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 9 Dec 2022 01:34:03 -0800 +Subject: [PATCH] fix Instruments + +Add missing instrument enums +fix some wrong javadocs + +diff --git a/src/main/java/org/bukkit/Instrument.java b/src/main/java/org/bukkit/Instrument.java +index 90bf1521e5b8b6c6d47489145e116f2a43fd3250..8df26e0d7bea77bb257cddbc2ab9e969fa160681 100644 +--- a/src/main/java/org/bukkit/Instrument.java ++++ b/src/main/java/org/bukkit/Instrument.java +@@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable; + public enum Instrument { + + /** +- * Piano is the standard instrument for a note block. ++ * Piano (Harp) is the standard instrument for a note block. + */ + PIANO(0x0, Sound.BLOCK_NOTE_BLOCK_HARP), + /** +@@ -21,7 +21,7 @@ public enum Instrument { + */ + SNARE_DRUM(0x2, Sound.BLOCK_NOTE_BLOCK_SNARE), + /** +- * Sticks are normally played when a note block is on top of a glass ++ * Sticks (Hat) are normally played when a note block is on top of a glass + * block. + */ + STICKS(0x3, Sound.BLOCK_NOTE_BLOCK_HAT), +@@ -78,39 +78,37 @@ public enum Instrument { + /** + * Zombie is normally played when a Zombie Head is on top of the note block. + */ +- ZOMBIE(Sound.BLOCK_NOTE_BLOCK_IMITATE_ZOMBIE), ++ ZOMBIE(0x10, Sound.BLOCK_NOTE_BLOCK_IMITATE_ZOMBIE), // Paper + /** + * Skeleton is normally played when a Skeleton Head is on top of the note block. + */ +- SKELETON(Sound.BLOCK_NOTE_BLOCK_IMITATE_SKELETON), ++ SKELETON(0x11, Sound.BLOCK_NOTE_BLOCK_IMITATE_SKELETON), // Paper + /** + * Creeper is normally played when a Creeper Head is on top of the note block. + */ +- CREEPER(Sound.BLOCK_NOTE_BLOCK_IMITATE_CREEPER), ++ CREEPER(0x12, Sound.BLOCK_NOTE_BLOCK_IMITATE_CREEPER), // Paper + /** + * Dragon is normally played when a Dragon Head is on top of the note block. + */ +- DRAGON(Sound.BLOCK_NOTE_BLOCK_IMITATE_ENDER_DRAGON), ++ DRAGON(0x13, Sound.BLOCK_NOTE_BLOCK_IMITATE_ENDER_DRAGON), // Paper + /** + * Wither Skeleton is normally played when a Wither Skeleton Head is on top of the note block. + */ +- WITHER_SKELETON(Sound.BLOCK_NOTE_BLOCK_IMITATE_WITHER_SKELETON), ++ WITHER_SKELETON(0x14, Sound.BLOCK_NOTE_BLOCK_IMITATE_WITHER_SKELETON), // Paper + /** + * Piglin is normally played when a Piglin Head is on top of the note block. + */ +- PIGLIN(Sound.BLOCK_NOTE_BLOCK_IMITATE_PIGLIN), ++ PIGLIN(0x15, Sound.BLOCK_NOTE_BLOCK_IMITATE_PIGLIN), // Paper + /** + * Custom Sound is normally played when a Player Head with the required data is on top of the note block. + */ +- CUSTOM_HEAD(null); ++ CUSTOM_HEAD(0x16, null); // Paper + + private final byte type; + private final Sound sound; + private static final Map BY_DATA = Maps.newHashMap(); + +- private Instrument(final Sound sound) { +- this(-1, sound); +- } ++ // Paper - remove ctor (the server still uses the byte magic value) + + private Instrument(final int type, final Sound sound) { + this.type = (byte) type; +@@ -130,9 +128,8 @@ public enum Instrument { + + /** + * @return The type ID of this instrument. +- * @deprecated Magic value + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + public byte getType() { + return this.type; + } +@@ -142,9 +139,8 @@ public enum Instrument { + * + * @param type The type ID + * @return The instrument +- * @deprecated Magic value + */ +- @Deprecated(since = "1.6.2") ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Nullable + public static Instrument getByType(final byte type) { + return BY_DATA.get(type); +diff --git a/src/test/java/org/bukkit/InstrumentTest.java b/src/test/java/org/bukkit/InstrumentTest.java +deleted file mode 100644 +index 6f27b260d9dbe76da733459c8341282e23440b8a..0000000000000000000000000000000000000000 +--- a/src/test/java/org/bukkit/InstrumentTest.java ++++ /dev/null +@@ -1,19 +0,0 @@ +-package org.bukkit; +- +-import static org.bukkit.support.MatcherAssert.*; +-import static org.hamcrest.CoreMatchers.*; +-import org.bukkit.support.AbstractTestingBase; +-import org.junit.jupiter.api.Test; +- +-public class InstrumentTest extends AbstractTestingBase { +- @Test +- public void getByType() { +- for (Instrument instrument : Instrument.values()) { +- if (instrument.getType() < 0) { +- continue; +- } +- +- assertThat(Instrument.getByType(instrument.getType()), is(instrument)); +- } +- } +-} diff --git a/patches/api/0379-Add-BlockLockCheckEvent.patch b/patches/api/0379-Add-BlockLockCheckEvent.patch new file mode 100644 index 000000000000..b9a9adb70ce8 --- /dev/null +++ b/patches/api/0379-Add-BlockLockCheckEvent.patch @@ -0,0 +1,242 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 21 May 2022 20:59:56 -0700 +Subject: [PATCH] Add BlockLockCheckEvent + + +diff --git a/src/main/java/io/papermc/paper/block/LockableTileState.java b/src/main/java/io/papermc/paper/block/LockableTileState.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f309961e0e96b6baacc4fe6d80dabd6c7c5d2e1d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/block/LockableTileState.java +@@ -0,0 +1,11 @@ ++package io.papermc.paper.block; ++ ++import org.bukkit.Nameable; ++import org.bukkit.block.Lockable; ++import org.bukkit.block.TileState; ++ ++/** ++ * Interface for tile entities that are lockable. ++ */ ++public interface LockableTileState extends TileState, Lockable, Nameable { ++} +diff --git a/src/main/java/io/papermc/paper/event/block/BlockLockCheckEvent.java b/src/main/java/io/papermc/paper/event/block/BlockLockCheckEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f08d390f0ee9357dcc229d7a2520da602677d9ef +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BlockLockCheckEvent.java +@@ -0,0 +1,187 @@ ++package io.papermc.paper.event.block; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.block.LockableTileState; ++import java.util.Objects; ++import net.kyori.adventure.sound.Sound; ++import net.kyori.adventure.text.Component; ++import org.bukkit.block.Block; ++import org.bukkit.block.BlockState; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when the server tries to check the lock on a lockable block entity. ++ *
      ++ * See {@link #setResult(Result)} to change behavior ++ */ ++@NullMarked ++public class BlockLockCheckEvent extends BlockEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Player player; ++ private @Nullable Component lockedMessage; ++ private @Nullable Sound lockedSound; ++ private @Nullable ItemStack itemStack; ++ private Result result = Result.DEFAULT; ++ ++ @ApiStatus.Internal ++ public BlockLockCheckEvent(final Block block, final Player player, final Component lockedMessage, final Sound lockedSound) { ++ super(block); ++ this.player = player; ++ this.lockedMessage = lockedMessage; ++ this.lockedSound = lockedSound; ++ } ++ ++ /** ++ * Gets the snapshot {@link LockableTileState} of the block entity ++ * whose lock is being checked. ++ * ++ * @return the snapshot block state. ++ */ ++ public LockableTileState getBlockState() { ++ final BlockState blockState = this.getBlock().getState(); ++ Preconditions.checkState(blockState instanceof LockableTileState, "Block state of lock-checked block is no longer a lockable tile state!"); ++ return (LockableTileState) blockState; ++ } ++ ++ /** ++ * Get the player involved this lock check. ++ * ++ * @return the player ++ */ ++ public Player getPlayer() { ++ return this.player; ++ } ++ ++ /** ++ * Gets the itemstack that will be used as the key itemstack. Initially ++ * this will be the item in the player's main hand but an override can be set ++ * with {@link #setKeyItem(ItemStack)}. Use {@link #isUsingCustomKeyItemStack()} ++ * to check if a custom key stack has been set. ++ * ++ * @return the item being used as the key item ++ * @see #isUsingCustomKeyItemStack() ++ */ ++ public ItemStack getKeyItem() { ++ return Objects.requireNonNullElseGet(this.itemStack, this.player.getInventory()::getItemInMainHand); ++ } ++ ++ /** ++ * Sets the itemstack that will be used as the key item. ++ * ++ * @param stack the stack to use as a key ++ * @see #resetKeyItem() to clear a custom key item ++ */ ++ public void setKeyItem(final ItemStack stack) { ++ Preconditions.checkArgument(stack != null, "stack cannot be null"); ++ this.itemStack = stack; ++ } ++ ++ /** ++ * Reset the key stack to the default (the player's main hand). ++ */ ++ public void resetKeyItem() { ++ this.itemStack = null; ++ } ++ ++ /** ++ * Checks if a custom key stack has been set. ++ * ++ * @return {@code true} if a custom key itemstack has been set ++ */ ++ public boolean isUsingCustomKeyItemStack() { ++ return this.itemStack != null; ++ } ++ ++ /** ++ * Gets the result of this event. ++ * ++ * @return the result ++ * @see #setResult(Result) ++ */ ++ public Result getResult() { ++ return this.result; ++ } ++ ++ /** ++ * Gets the result of this event. {@link Result#DEFAULT} is the default ++ * allowing the vanilla logic to check the lock of this block. Set to {@link Result#ALLOW} ++ * or {@link Result#DENY} to override that behavior. ++ *

      ++ * Setting this to {@link Result#ALLOW} bypasses the spectator check. ++ * ++ * @param result the result of this event ++ */ ++ public void setResult(final Result result) { ++ this.result = result; ++ } ++ ++ /** ++ * Shorthand method to set the {@link #getResult()} to {@link Result#DENY}, ++ * the locked message and locked sound. ++ * ++ * @param lockedMessage the message to show if locked (or {@code null} for none) ++ * @param lockedSound the sound to play if locked (or {@code null} for none) ++ */ ++ public void denyWithMessageAndSound(final @Nullable Component lockedMessage, final @Nullable Sound lockedSound) { ++ this.result = Result.DENY; ++ this.lockedMessage = lockedMessage; ++ this.lockedSound = lockedSound; ++ } ++ ++ /** ++ * Gets the locked message that will be sent if the ++ * player cannot open the block. ++ * ++ * @return the locked message (or {@code null} if none) ++ */ ++ public @Nullable Component getLockedMessage() { ++ return this.lockedMessage; ++ } ++ ++ /** ++ * Sets the locked message that will be sent if the ++ * player cannot open the block. ++ * ++ * @param lockedMessage the locked message (or {@code null} for none) ++ */ ++ public void setLockedMessage(final @Nullable Component lockedMessage) { ++ this.lockedMessage = lockedMessage; ++ } ++ ++ /** ++ * Gets the locked sound that will play if the ++ * player cannot open the block. ++ * ++ * @return the locked sound (or {@code null} if none) ++ */ ++ public @Nullable Sound getLockedSound() { ++ return this.lockedSound; ++ } ++ ++ /** ++ * Sets the locked sound that will play if the ++ * player cannot open the block. ++ * ++ * @param lockedSound the locked sound (or {@code null} for none) ++ */ ++ public void setLockedSound(final @Nullable Sound lockedSound) { ++ this.lockedSound = lockedSound; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/org/bukkit/block/Beacon.java b/src/main/java/org/bukkit/block/Beacon.java +index 7d212c409035ccb8b22d4ffc322b4a1aea367627..79c04b840adb768f7a38e95a82f79287f42681f5 100644 +--- a/src/main/java/org/bukkit/block/Beacon.java ++++ b/src/main/java/org/bukkit/block/Beacon.java +@@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a captured state of a beacon. + */ +-public interface Beacon extends TileState, Lockable, Nameable { ++public interface Beacon extends io.papermc.paper.block.LockableTileState { // Paper + + /** + * Returns the list of players within the beacon's range of effect. +diff --git a/src/main/java/org/bukkit/block/Container.java b/src/main/java/org/bukkit/block/Container.java +index bc06199f0a1cc43e0bdfd5b11fa170badd46e180..a67ee0cb0cd2cbab8dab375e2fe44168c250bcb7 100644 +--- a/src/main/java/org/bukkit/block/Container.java ++++ b/src/main/java/org/bukkit/block/Container.java +@@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents a captured state of a container block. + */ +-public interface Container extends TileState, BlockInventoryHolder, Lockable, Nameable { ++public interface Container extends io.papermc.paper.block.LockableTileState, BlockInventoryHolder { // Paper + + /** + * Gets the inventory of the block represented by this block state. diff --git a/patches/api/0379-WorldCreator-keepSpawnLoaded.patch b/patches/api/0379-WorldCreator-keepSpawnLoaded.patch deleted file mode 100644 index 239a61f5a015..000000000000 --- a/patches/api/0379-WorldCreator-keepSpawnLoaded.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sat, 3 Jul 2021 21:18:41 +0100 -Subject: [PATCH] WorldCreator#keepSpawnLoaded - - -diff --git a/src/main/java/org/bukkit/WorldCreator.java b/src/main/java/org/bukkit/WorldCreator.java -index cbdcac688afb7c13dd7058fa522bbd2c5adc445e..355f9f27d29c65efebf099a72c37892a309edef1 100644 ---- a/src/main/java/org/bukkit/WorldCreator.java -+++ b/src/main/java/org/bukkit/WorldCreator.java -@@ -22,6 +22,7 @@ public class WorldCreator { - private boolean generateStructures = true; - private String generatorSettings = ""; - private boolean hardcore = false; -+ private net.kyori.adventure.util.TriState keepSpawnLoaded = net.kyori.adventure.util.TriState.NOT_SET; // Paper - - /** - * Creates an empty WorldCreationOptions for the given world name -@@ -573,4 +574,29 @@ public class WorldCreator { - - return result; - } -+ -+ // Paper start -+ -+ /** -+ * Returns the current intent to keep the world loaded, @see {@link WorldCreator#keepSpawnLoaded(net.kyori.adventure.util.TriState)} -+ * -+ * @return the current tristate value -+ */ -+ @NotNull -+ public net.kyori.adventure.util.TriState keepSpawnLoaded() { -+ return keepSpawnLoaded; -+ } -+ -+ /** -+ * Controls if a world should be kept loaded or not, default (NOT_SET) will use the servers standard -+ * configuration, otherwise, will act as an override towards this setting -+ * -+ * @param keepSpawnLoaded the new value -+ */ -+ public void keepSpawnLoaded(@NotNull net.kyori.adventure.util.TriState keepSpawnLoaded) { -+ java.util.Objects.requireNonNull(keepSpawnLoaded, "keepSpawnLoaded"); -+ this.keepSpawnLoaded = keepSpawnLoaded; -+ } -+ -+ // Paper end - } diff --git a/patches/api/0380-Add-EntityDyeEvent-and-CollarColorable-interface.patch b/patches/api/0380-Add-EntityDyeEvent-and-CollarColorable-interface.patch deleted file mode 100644 index 1f8509de8a40..000000000000 --- a/patches/api/0380-Add-EntityDyeEvent-and-CollarColorable-interface.patch +++ /dev/null @@ -1,262 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 18 Mar 2022 21:16:38 -0700 -Subject: [PATCH] Add EntityDyeEvent and CollarColorable interface - - -diff --git a/src/main/java/io/papermc/paper/entity/CollarColorable.java b/src/main/java/io/papermc/paper/entity/CollarColorable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bb68e6a2528eee81eb3f26f22b9c35508f1e69c1 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/entity/CollarColorable.java -@@ -0,0 +1,25 @@ -+package io.papermc.paper.entity; -+ -+import org.bukkit.DyeColor; -+import org.bukkit.entity.LivingEntity; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Entities that can have their collars colored. -+ */ -+public interface CollarColorable extends LivingEntity { -+ -+ /** -+ * Get the collar color of this entity -+ * -+ * @return the color of the collar -+ */ -+ @NotNull DyeColor getCollarColor(); -+ -+ /** -+ * Set the collar color of this entity -+ * -+ * @param color the color to apply -+ */ -+ void setCollarColor(@NotNull DyeColor color); -+} -diff --git a/src/main/java/io/papermc/paper/event/entity/EntityDyeEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityDyeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..aefbaccd32f1ab25a4da63bdc878922e0c220478 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/EntityDyeEvent.java -@@ -0,0 +1,75 @@ -+package io.papermc.paper.event.entity; -+ -+import org.bukkit.DyeColor; -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when an entity is dyed. Currently, this is called for {@link org.bukkit.entity.Sheep} -+ * being dyed, and {@link org.bukkit.entity.Wolf}/{@link org.bukkit.entity.Cat} collars being dyed. -+ */ -+public class EntityDyeEvent extends EntityEvent implements Cancellable { -+ -+ private static final HandlerList HANDLER_LIST = new HandlerList(); -+ -+ private DyeColor dyeColor; -+ private final Player player; -+ private boolean cancel; -+ -+ public EntityDyeEvent(@NotNull Entity entity, @NotNull DyeColor dyeColor, @Nullable Player player) { -+ super(entity); -+ this.dyeColor = dyeColor; -+ this.player = player; -+ } -+ -+ /** -+ * Gets the DyeColor the entity is being dyed -+ * -+ * @return the DyeColor the entity is being dyed -+ */ -+ public @NotNull DyeColor getColor() { -+ return this.dyeColor; -+ } -+ -+ /** -+ * Sets the DyeColor the entity is being dyed -+ * -+ * @param dyeColor the DyeColor the entity will be dyed -+ */ -+ public void setColor(@NotNull DyeColor dyeColor) { -+ this.dyeColor = dyeColor; -+ } -+ -+ /** -+ * Returns the player dyeing the entity, if available. -+ * -+ * @return player or null -+ */ -+ public @Nullable Player getPlayer() { -+ return player; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return this.cancel; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return HANDLER_LIST; -+ } -+ -+ public static @NotNull HandlerList getHandlerList() { -+ return HANDLER_LIST; -+ } -+} -diff --git a/src/main/java/org/bukkit/entity/Cat.java b/src/main/java/org/bukkit/entity/Cat.java -index c340fecb61bac66baf0f44189d21bc85289b1269..97b0d8ccd3fd3a711ec5fa4ce3d8703515895081 100644 ---- a/src/main/java/org/bukkit/entity/Cat.java -+++ b/src/main/java/org/bukkit/entity/Cat.java -@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; - /** - * Meow. - */ --public interface Cat extends Tameable, Sittable { -+public interface Cat extends Tameable, Sittable, io.papermc.paper.entity.CollarColorable { // Paper - CollarColorable - - /** - * Gets the current type of this cat. -@@ -29,6 +29,7 @@ public interface Cat extends Tameable, Sittable { - * @return the color of the collar - */ - @NotNull -+ @Override // Paper - public DyeColor getCollarColor(); - - /** -@@ -36,6 +37,7 @@ public interface Cat extends Tameable, Sittable { - * - * @param color the color to apply - */ -+ @Override // Paper - public void setCollarColor(@NotNull DyeColor color); - - /** -diff --git a/src/main/java/org/bukkit/entity/Wolf.java b/src/main/java/org/bukkit/entity/Wolf.java -index 490395f38c4d9977d30a6f48585a4ea0e7faff0f..297b65a6cf7d25f02bbd824ea507c5c083e0abec 100644 ---- a/src/main/java/org/bukkit/entity/Wolf.java -+++ b/src/main/java/org/bukkit/entity/Wolf.java -@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; - /** - * Represents a Wolf - */ --public interface Wolf extends Tameable, Sittable { -+public interface Wolf extends Tameable, Sittable, io.papermc.paper.entity.CollarColorable { // Paper - CollarColorable - - /** - * Checks if this wolf is angry -@@ -31,6 +31,7 @@ public interface Wolf extends Tameable, Sittable { - * @return the color of the collar - */ - @NotNull -+ @Override // Paper - public DyeColor getCollarColor(); - - /** -@@ -38,6 +39,7 @@ public interface Wolf extends Tameable, Sittable { - * - * @param color the color to apply - */ -+ @Override // Paper - public void setCollarColor(@NotNull DyeColor color); - - // Paper start -diff --git a/src/main/java/org/bukkit/event/entity/SheepDyeWoolEvent.java b/src/main/java/org/bukkit/event/entity/SheepDyeWoolEvent.java -index 10d2466fb69919cead26af2fcdf6bd2e678f2927..ddf4aec01e4873aa799721ce615f5d7c929dc915 100644 ---- a/src/main/java/org/bukkit/event/entity/SheepDyeWoolEvent.java -+++ b/src/main/java/org/bukkit/event/entity/SheepDyeWoolEvent.java -@@ -11,11 +11,8 @@ import org.jetbrains.annotations.Nullable; - /** - * Called when a sheep's wool is dyed - */ --public class SheepDyeWoolEvent extends EntityEvent implements Cancellable { -- private static final HandlerList handlers = new HandlerList(); -- private boolean cancel; -- private DyeColor color; -- private final Player player; -+public class SheepDyeWoolEvent extends io.papermc.paper.event.entity.EntityDyeEvent implements Cancellable { -+ // Paper - move everything to superclass - - @Deprecated - public SheepDyeWoolEvent(@NotNull final Sheep sheep, @NotNull final DyeColor color) { -@@ -23,20 +20,7 @@ public class SheepDyeWoolEvent extends EntityEvent implements Cancellable { - } - - public SheepDyeWoolEvent(@NotNull final Sheep sheep, @NotNull final DyeColor color, @Nullable Player player) { -- super(sheep); -- this.cancel = false; -- this.color = color; -- this.player = player; -- } -- -- @Override -- public boolean isCancelled() { -- return cancel; -- } -- -- @Override -- public void setCancelled(boolean cancel) { -- this.cancel = cancel; -+ super(sheep, color, player); // Paper - } - - @NotNull -@@ -44,45 +28,4 @@ public class SheepDyeWoolEvent extends EntityEvent implements Cancellable { - public Sheep getEntity() { - return (Sheep) entity; - } -- -- /** -- * Returns the player dyeing the sheep, if available. -- * -- * @return player or null -- */ -- @Nullable -- public Player getPlayer() { -- return player; -- } -- -- /** -- * Gets the DyeColor the sheep is being dyed -- * -- * @return the DyeColor the sheep is being dyed -- */ -- @NotNull -- public DyeColor getColor() { -- return color; -- } -- -- /** -- * Sets the DyeColor the sheep is being dyed -- * -- * @param color the DyeColor the sheep will be dyed -- */ -- public void setColor(@NotNull DyeColor color) { -- this.color = color; -- } -- -- @NotNull -- @Override -- public HandlerList getHandlers() { -- return handlers; -- } -- -- @NotNull -- public static HandlerList getHandlerList() { -- return handlers; -- } -- - } diff --git a/patches/api/0380-Add-Sneaking-API-for-Entities.patch b/patches/api/0380-Add-Sneaking-API-for-Entities.patch new file mode 100644 index 000000000000..638560281fe1 --- /dev/null +++ b/patches/api/0380-Add-Sneaking-API-for-Entities.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dawon +Date: Wed, 19 Oct 2022 23:36:42 +0200 +Subject: [PATCH] Add Sneaking API for Entities + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 2b4058dace5d071f60a9629f81c2323ee8c6d109..9cfffc02da491450c080cdd80e96f60921518fb9 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -823,6 +823,25 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + @NotNull + Pose getPose(); + ++ // Paper start ++ /** ++ * Returns if the entity is in sneak mode ++ * ++ * @return true if the entity is in sneak mode ++ */ ++ boolean isSneaking(); ++ ++ /** ++ * Sets the sneak mode the entity. ++ *

      ++ * Note: For most Entities this does not update Entity's pose ++ * and just makes its name tag less visible. ++ * ++ * @param sneak true if the entity should be sneaking ++ */ ++ void setSneaking(boolean sneak); ++ // Paper end ++ + /** + * Get the category of spawn to which this entity belongs. + * +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 8873f0eb1451cd4e8801b75e8bd477eae588e73b..acb65c90ad87b35c00fafc4e60803adc13af1225 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -475,6 +475,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * + * @return true if player is in sneak mode + */ ++ @Override // Paper + public boolean isSneaking(); + + /** +@@ -482,6 +483,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * + * @param sneak true if player should appear sneaking + */ ++ @Override // Paper + public void setSneaking(boolean sneak); + + /** diff --git a/patches/api/0381-Add-PlayerStopUsingItemEvent.patch b/patches/api/0381-Add-PlayerStopUsingItemEvent.patch deleted file mode 100644 index 0743d44ae11b..000000000000 --- a/patches/api/0381-Add-PlayerStopUsingItemEvent.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: u9g -Date: Tue, 3 May 2022 20:41:30 -0400 -Subject: [PATCH] Add PlayerStopUsingItemEvent - - -diff --git a/src/main/java/io/papermc/paper/event/player/PlayerStopUsingItemEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerStopUsingItemEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3689551baf2c9880f3e2a70435f8b4ad05cba49a ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/player/PlayerStopUsingItemEvent.java -@@ -0,0 +1,53 @@ -+package io.papermc.paper.event.player; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when the server detects a player stopping using an item. -+ * Examples of this are letting go of the interact button when holding a bow, an edible item, or a spyglass. -+ */ -+public class PlayerStopUsingItemEvent extends PlayerEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ @NotNull private final ItemStack item; -+ private final int ticksHeldFor; -+ -+ public PlayerStopUsingItemEvent(@NotNull final Player player, @NotNull final ItemStack item, final int ticksHeldFor) { -+ super(player); -+ this.item = item; -+ this.ticksHeldFor = ticksHeldFor; -+ } -+ -+ /** -+ * Gets the exact item the player is releasing -+ * -+ * @return ItemStack the exact item the player released -+ */ -+ @NotNull -+ public ItemStack getItem() { -+ return item; -+ } -+ -+ /** -+ * Gets the number of ticks the item was held for -+ * -+ * @return int the number of ticks the item was held for -+ */ -+ public int getTicksHeldFor() { -+ return ticksHeldFor; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0381-Improve-PortalEvents.patch b/patches/api/0381-Improve-PortalEvents.patch new file mode 100644 index 000000000000..88c76230fdee --- /dev/null +++ b/patches/api/0381-Improve-PortalEvents.patch @@ -0,0 +1,225 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 15 Dec 2022 10:33:34 -0800 +Subject: [PATCH] Improve PortalEvents + + +diff --git a/src/main/java/org/bukkit/PortalType.java b/src/main/java/org/bukkit/PortalType.java +index 427cfbb8b542215c5d9993056e0cadf18ab9bd4b..e6120b83259c15189bbbf6b6dd13fbe7ccdf073d 100644 +--- a/src/main/java/org/bukkit/PortalType.java ++++ b/src/main/java/org/bukkit/PortalType.java +@@ -14,6 +14,12 @@ public enum PortalType { + * This is an Ender portal. + */ + ENDER, ++ // Paper start ++ /** ++ * This is an end gateway ++ */ ++ END_GATEWAY, ++ // Paper end + + /** + * This is a custom Plugin portal. +diff --git a/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java b/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java +index 6818e9f0ba32ca1a1e612703f7526b29f5a6438f..d3724db0a5a67cde15b05fecd32b2ca370cca998 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java +@@ -7,14 +7,25 @@ import org.jetbrains.annotations.NotNull; + + /** + * Called when an entity comes into contact with a portal ++ *

      ++ * Cancelling this event prevents any further processing of the portal for that tick. ++ * @see io.papermc.paper.event.entity.EntityInsideBlockEvent + */ +-public class EntityPortalEnterEvent extends EntityEvent { ++public class EntityPortalEnterEvent extends EntityEvent implements org.bukkit.event.Cancellable { // Paper + private static final HandlerList handlers = new HandlerList(); + private final Location location; + ++ @Deprecated(since = "1.21") @io.papermc.paper.annotation.DoNotUse // Paper + public EntityPortalEnterEvent(@NotNull final Entity entity, @NotNull final Location location) { ++ // Paper start ++ this(entity, location, org.bukkit.PortalType.CUSTOM); ++ } ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public EntityPortalEnterEvent(@NotNull final Entity entity, @NotNull final Location location, @NotNull final org.bukkit.PortalType portalType) { ++ // Paper end + super(entity); + this.location = location; ++ this.portalType = portalType; // Paper + } + + /** +@@ -27,6 +38,30 @@ public class EntityPortalEnterEvent extends EntityEvent { + return location; + } + ++ // Paper start ++ private boolean cancelled = false; ++ private final org.bukkit.PortalType portalType; ++ ++ /** ++ * Get the portal type. ++ * ++ * @return the portal type ++ */ ++ public org.bukkit.@NotNull PortalType getPortalType() { ++ return this.portalType; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ // Paper end ++ + @NotNull + @Override + public HandlerList getHandlers() { +diff --git a/src/main/java/org/bukkit/event/entity/EntityPortalEvent.java b/src/main/java/org/bukkit/event/entity/EntityPortalEvent.java +index d70400236b08217ba675e560877f951ea4f143ca..4544e7e155619a6ae31cbb2999ae3dedfd3b5f4b 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityPortalEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPortalEvent.java +@@ -3,6 +3,7 @@ package org.bukkit.event.entity; + import org.bukkit.Location; + import org.bukkit.entity.Entity; + import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +@@ -17,23 +18,68 @@ public class EntityPortalEvent extends EntityTeleportEvent { + private int searchRadius = 128; + private boolean canCreatePortal = true; + private int creationRadius = 16; ++ private final org.bukkit.PortalType type; // Paper + + public EntityPortalEvent(@NotNull final Entity entity, @NotNull final Location from, @Nullable final Location to) { +- super(entity, from, to); ++ this(entity, from, to, 128); // Paper + } + + public EntityPortalEvent(@NotNull Entity entity, @NotNull Location from, @Nullable Location to, int searchRadius) { + super(entity, from, to); + this.searchRadius = searchRadius; ++ this.type = org.bukkit.PortalType.CUSTOM; // Paper + } + + public EntityPortalEvent(@NotNull Entity entity, @NotNull Location from, @Nullable Location to, int searchRadius, boolean canCreatePortal, int creationRadius) { ++ // Paper start ++ this(entity, from, to, searchRadius, canCreatePortal, creationRadius, org.bukkit.PortalType.CUSTOM); ++ } ++ ++ @ApiStatus.Internal ++ public EntityPortalEvent(@NotNull Entity entity, @NotNull Location from, @Nullable Location to, int searchRadius, boolean canCreatePortal, int creationRadius, final @NotNull org.bukkit.PortalType portalType) { + super(entity, from, to); ++ this.type = portalType; ++ // Paper end + this.searchRadius = searchRadius; + this.canCreatePortal = canCreatePortal; + this.creationRadius = creationRadius; + } + ++ // Paper start ++ /** ++ * Get the portal type relating to this event. ++ * ++ * @return the portal type ++ */ ++ public @NotNull org.bukkit.PortalType getPortalType() { ++ return this.type; ++ } ++ /** ++ * For {@link org.bukkit.PortalType#NETHER}, this is initially just the starting point ++ * for the search for a portal to teleport to. It will initially just be the {@link #getFrom()} ++ * scaled for dimension scaling and clamped to be inside the world border. ++ *

      ++ * For {@link org.bukkit.PortalType#ENDER}, this will initially be the exact destination ++ * either, the world spawn for end->any world or end spawn for any world->end. ++ * ++ * @return starting point for search or exact destination ++ */ ++ @Override ++ public @Nullable Location getTo() { ++ return super.getTo(); ++ } ++ ++ /** ++ * See the description of {@link #getTo()}. ++ * @param to starting point for search or exact destination ++ * or null to cancel ++ */ ++ @Override ++ public void setTo(@Nullable final Location to) { ++ super.setTo(to); ++ } ++ // Paper end ++ + /** + * Set the Block radius to search in for available portals. + * +diff --git a/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java b/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java +index 57eeeafae84f83a939925820e827769749ff27ec..929a997671de8202efb9da97fbf9b4a0bf7c37e8 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java +@@ -32,6 +32,53 @@ public class PlayerPortalEvent extends PlayerTeleportEvent { + this.canCreatePortal = canCreatePortal; + this.creationRadius = creationRadius; + } ++ // Paper start ++ /** ++ * For {@link TeleportCause#NETHER_PORTAL}, this is initially just the starting point ++ * for the search for a portal to teleport to. It will initially just be the {@link #getFrom()} ++ * scaled for dimension scaling and clamped to be inside the world border. ++ *

      ++ * For {@link TeleportCause#END_PORTAL}, this will initially be the exact destination ++ * either, the world spawn for end->any world or end spawn for any world->end. ++ * ++ * @return starting point for search or exact destination ++ */ ++ @Override ++ public @NotNull Location getTo() { ++ return super.getTo(); ++ } ++ ++ /** ++ * See the description of {@link #getTo()}. ++ * @param to starting point for search or exact destination ++ */ ++ @Override ++ public void setTo(@NotNull final Location to) { ++ super.setTo(to); ++ } ++ ++ /** ++ * No effect ++ * @return no effect ++ * @deprecated No effect ++ */ ++ @Deprecated ++ @Override ++ public boolean willDismountPlayer() { ++ return super.willDismountPlayer(); ++ } ++ ++ /** ++ * No effect ++ * @return no effect ++ * @deprecated No effect ++ */ ++ @Deprecated ++ @Override ++ public @NotNull java.util.Set getRelativeTeleportationFlags() { ++ return super.getRelativeTeleportationFlags(); ++ } ++ // Paper end + + /** + * Set the Block radius to search in for available portals. diff --git a/patches/api/0382-FallingBlock-auto-expire-setting.patch b/patches/api/0382-FallingBlock-auto-expire-setting.patch deleted file mode 100644 index 90c104c7ce46..000000000000 --- a/patches/api/0382-FallingBlock-auto-expire-setting.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Sun, 5 Dec 2021 14:58:55 -0500 -Subject: [PATCH] FallingBlock auto expire setting - - -diff --git a/src/main/java/org/bukkit/entity/FallingBlock.java b/src/main/java/org/bukkit/entity/FallingBlock.java -index 14cb0d770561151570ab4399ca5facff43076819..ae8fab2395e56d25227b5877b8648510c73bf948 100644 ---- a/src/main/java/org/bukkit/entity/FallingBlock.java -+++ b/src/main/java/org/bukkit/entity/FallingBlock.java -@@ -65,4 +65,23 @@ public interface FallingBlock extends Entity { - default org.bukkit.Location getSourceLoc() { - return this.getOrigin(); - } -+ // Paper Start - Auto expire setting -+ /** -+ * Sets if this falling block should expire after: -+ * - 30 seconds -+ * - 5 seconds and is outside of the world -+ * -+ * @return if this behavior occurs -+ */ -+ boolean doesAutoExpire(); -+ -+ /** -+ * Sets if this falling block should expire after: -+ * - 30 seconds -+ * - 5 seconds and is outside of the world -+ * -+ * @param autoExpires if this behavior should occur -+ */ -+ void shouldAutoExpire(boolean autoExpires); -+ // Paper End - Auto expire setting - } diff --git a/patches/api/0382-Flying-Fall-Damage-API.patch b/patches/api/0382-Flying-Fall-Damage-API.patch new file mode 100644 index 000000000000..8144d7e6d5b9 --- /dev/null +++ b/patches/api/0382-Flying-Fall-Damage-API.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TreyRuffy +Date: Fri, 27 May 2022 02:25:38 -0600 +Subject: [PATCH] Flying Fall Damage API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index acb65c90ad87b35c00fafc4e60803adc13af1225..4e15db5b6dacc784d6893874295dbd9b84595011 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -1948,6 +1948,23 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public void setAllowFlight(boolean flight); + ++ // Paper start - flying fall damage ++ /** ++ * Allows you to enable fall damage while {@link #getAllowFlight()} is {@code true} ++ * ++ * @param flyingFallDamage Enables fall damage when {@link #getAllowFlight()} is {@code true} ++ */ ++ public void setFlyingFallDamage(@NotNull net.kyori.adventure.util.TriState flyingFallDamage); ++ ++ /** ++ * Allows you to get if fall damage is enabled while {@link #getAllowFlight()} is {@code true} ++ * ++ * @return A tristate of whether fall damage is enabled, not set, or disabled when {@link #getAllowFlight()} is {@code true} ++ */ ++ @NotNull ++ public net.kyori.adventure.util.TriState hasFlyingFallDamage(); ++ // Paper end ++ + /** + * Hides a player from this player + * diff --git a/patches/api/0383-Keyed-Cat-Type.patch b/patches/api/0383-Keyed-Cat-Type.patch deleted file mode 100644 index b0797d78b771..000000000000 --- a/patches/api/0383-Keyed-Cat-Type.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Wed, 8 Jun 2022 18:23:17 -0400 -Subject: [PATCH] Keyed Cat Type - - -diff --git a/src/main/java/org/bukkit/entity/Cat.java b/src/main/java/org/bukkit/entity/Cat.java -index 97b0d8ccd3fd3a711ec5fa4ce3d8703515895081..bd74b47879b69b7a2e078a5aca460e5c97b0a919 100644 ---- a/src/main/java/org/bukkit/entity/Cat.java -+++ b/src/main/java/org/bukkit/entity/Cat.java -@@ -43,7 +43,7 @@ public interface Cat extends Tameable, Sittable, io.papermc.paper.entity.CollarC - /** - * Represents the various different cat types there are. - */ -- public enum Type { -+ public enum Type implements org.bukkit.Keyed { // Paper - TABBY, - BLACK, - RED, -@@ -55,6 +55,20 @@ public interface Cat extends Tameable, Sittable, io.papermc.paper.entity.CollarC - WHITE, - JELLIE, - ALL_BLACK; -+ -+ // Paper start -+ private final org.bukkit.NamespacedKey key; -+ -+ Type() { -+ this.key = org.bukkit.NamespacedKey.minecraft(name().toLowerCase(java.util.Locale.ROOT)); -+ } -+ -+ @NotNull -+ @Override -+ public org.bukkit.NamespacedKey getKey() { -+ return key; -+ } -+ // Paper end - } - - // Paper Start - More cat api diff --git a/patches/api/0383-Replace-ItemFlag.HIDE_POTION_EFFECTS.patch b/patches/api/0383-Replace-ItemFlag.HIDE_POTION_EFFECTS.patch new file mode 100644 index 000000000000..475ca65bbf54 --- /dev/null +++ b/patches/api/0383-Replace-ItemFlag.HIDE_POTION_EFFECTS.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Thu, 5 Jan 2023 10:45:20 +0100 +Subject: [PATCH] Replace ItemFlag.HIDE_POTION_EFFECTS + + +diff --git a/src/main/java/org/bukkit/inventory/ItemFlag.java b/src/main/java/org/bukkit/inventory/ItemFlag.java +index 1b3580d1861af402396121805715e4087b3bc587..5b8dac777bb1640dc00bbe98feb6460c36eebb98 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFlag.java ++++ b/src/main/java/org/bukkit/inventory/ItemFlag.java +@@ -38,4 +38,27 @@ public enum ItemFlag { + * Setting to show/hide armor trim from armor. + */ + HIDE_ARMOR_TRIM; ++ // Paper start ++ /** ++ * Setting to show/hide item-specific information, including, but not limited to: ++ *

        ++ *
      • Potion effects on potions, tipped arrows, and suspicious stew
      • ++ *
      • Enchanted book enchantments
      • ++ *
      • Book author and generation
      • ++ *
      • Record names
      • ++ *
      • Patterns of banners and shields
      • ++ *
      • Fish bucket variants
      • ++ *
      • Instrument item descriptions (i.e. goat horn sounds)
      • ++ *
      • Map data
      • ++ *
      • Firework data
      • ++ *
      • Crossbow projectile info
      • ++ *
      • Bundle fullness
      • ++ *
      • Shulker box contents
      • ++ *
      • Spawner descriptions
      • ++ *
      ++ * @deprecated use {@link #HIDE_ADDITIONAL_TOOLTIP} ++ */ ++ @Deprecated(since = "1.20.5") ++ public static final ItemFlag HIDE_ITEM_SPECIFICS = HIDE_ADDITIONAL_TOOLTIP; ++ // Paper end + } diff --git a/patches/api/0384-Add-WardenAngerChangeEvent.patch b/patches/api/0384-Add-WardenAngerChangeEvent.patch deleted file mode 100644 index acf45b53149a..000000000000 --- a/patches/api/0384-Add-WardenAngerChangeEvent.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: nopjar -Date: Sun, 12 Jun 2022 00:56:45 +0200 -Subject: [PATCH] Add WardenAngerChangeEvent - -Adding a event which gets called when a warden is angered by -another entity. - -diff --git a/src/main/java/io/papermc/paper/event/entity/WardenAngerChangeEvent.java b/src/main/java/io/papermc/paper/event/entity/WardenAngerChangeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4fd31d4d8b35f27789f3cd9581e7c17a6bde5373 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/event/entity/WardenAngerChangeEvent.java -@@ -0,0 +1,103 @@ -+package io.papermc.paper.event.entity; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.Warden; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when a Warden's anger level has changed due to another entity. -+ *

      -+ * If the event is cancelled, the warden's anger level will not change. -+ */ -+public class WardenAngerChangeEvent extends EntityEvent implements Cancellable { -+ -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private final Entity target; -+ private final int oldAnger; -+ private int newAnger; -+ -+ public WardenAngerChangeEvent(@NotNull final Warden warden, @Nullable final Entity target, final int oldAnger, final int newAnger) { -+ super(warden); -+ this.target = target; -+ this.oldAnger = oldAnger; -+ this.newAnger = newAnger; -+ } -+ -+ /** -+ * Gets the entity (if any) which triggered this anger update. -+ * -+ * @return triggering entity, or null -+ */ -+ @Nullable -+ public Entity getTarget() { -+ return target; -+ } -+ -+ /** -+ * Gets the old anger level. -+ * -+ * @return old anger level -+ * @see Warden#getAnger(Entity) -+ */ -+ public int getOldAnger() { -+ return oldAnger; -+ } -+ -+ /** -+ * Gets the new anger level resulting from this event. -+ * -+ * @return new anger level -+ * @see Warden#getAnger(Entity) -+ */ -+ public int getNewAnger() { -+ return newAnger; -+ } -+ -+ /** -+ * Sets the new anger level resulting from this event. -+ *

      -+ * The anger of a warden is capped at 150. -+ * -+ * @param newAnger the new anger level, max 150 -+ * @see Warden#setAnger(Entity, int) -+ * @throws IllegalArgumentException if newAnger is greater than 150 -+ */ -+ public void setNewAnger(int newAnger) { -+ if (newAnger > 150) -+ throw new IllegalArgumentException("newAnger must not be greater than 150"); -+ -+ this.newAnger = newAnger; -+ } -+ -+ @NotNull -+ @Override -+ public Warden getEntity() { -+ return (Warden) entity; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancelled) { -+ this.cancelled = cancelled; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0384-Win-Screen-API.patch b/patches/api/0384-Win-Screen-API.patch new file mode 100644 index 000000000000..03a11e325b63 --- /dev/null +++ b/patches/api/0384-Win-Screen-API.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lama06 +Date: Sat, 21 Jan 2023 13:45:22 +0100 +Subject: [PATCH] Win Screen API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 4e15db5b6dacc784d6893874295dbd9b84595011..c2d49ff3aee971598451734f95144ac5dbbf131a 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -1287,6 +1287,47 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public void sendMap(@NotNull MapView map); + ++ // Paper start ++ /** ++ * Shows the player the win screen that normally is only displayed after one kills the ender dragon ++ * and exits the end for the first time. ++ * In vanilla, the win screen starts with a poem and then continues with the credits but its content can be ++ * changed by using a resource pack. ++ *
      ++ * Calling this method does not change the value of {@link #hasSeenWinScreen()}. ++ * That means that the win screen is still displayed to a player if they leave the end for the first time, even though ++ * they have seen it before because this method was called. ++ * Note this method does not make the player invulnerable, which is normally expected when viewing credits. ++ * ++ * @see #hasSeenWinScreen() ++ * @see #setHasSeenWinScreen(boolean) ++ * @see https://minecraft.wiki/wiki/End_Poem#Technical_details ++ */ ++ public void showWinScreen(); ++ ++ /** ++ * Returns whether this player has seen the win screen before. ++ * When a player leaves the end the win screen is shown to them if they have not seen it before. ++ * ++ * @return Whether this player has seen the win screen before ++ * @see #setHasSeenWinScreen(boolean) ++ * @see #showWinScreen() ++ * @see https://minecraft.wiki/wiki/End_Poem ++ */ ++ public boolean hasSeenWinScreen(); ++ ++ /** ++ * Changes whether this player has seen the win screen before. ++ * When a player leaves the end the win screen is shown to them if they have not seen it before. ++ * ++ * @param hasSeenWinScreen Whether this player has seen the win screen before ++ * @see #hasSeenWinScreen() ++ * @see #showWinScreen() ++ * @see https://minecraft.wiki/wiki/End_Poem ++ */ ++ public void setHasSeenWinScreen(boolean hasSeenWinScreen); ++ // Paper end ++ + // Paper start + /** + * Permanently Bans the Profile and IP address currently used by the player. diff --git a/patches/api/0385-Add-Entity-Body-Yaw-API.patch b/patches/api/0385-Add-Entity-Body-Yaw-API.patch new file mode 100644 index 000000000000..aba64c12663b --- /dev/null +++ b/patches/api/0385-Add-Entity-Body-Yaw-API.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TheTuso +Date: Thu, 2 Feb 2023 16:40:11 +0100 +Subject: [PATCH] Add Entity Body Yaw API + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 9cfffc02da491450c080cdd80e96f60921518fb9..0ca7cb73c4007647841ed6a78c8949fcc3ed97ff 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -1041,6 +1041,43 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + * @return true if in powdered snow. + */ + boolean isInPowderedSnow(); ++ ++ /** ++ * Gets the x-coordinate of this entity ++ * ++ * @return x-coordinate ++ */ ++ double getX(); ++ ++ /** ++ * Gets the y-coordinate of this entity ++ * ++ * @return y-coordinate ++ */ ++ double getY(); ++ ++ /** ++ * Gets the z-coordinate of this entity ++ * ++ * @return z-coordinate ++ */ ++ double getZ(); ++ ++ /** ++ * Gets this entity's pitch ++ * ++ * @see Location#getPitch() ++ * @return the entity's pitch ++ */ ++ float getPitch(); ++ ++ /** ++ * Gets this entity's yaw ++ * ++ * @see Location#getYaw() ++ * @return the entity's yaw ++ */ ++ float getYaw(); + // Paper end + + // Paper start - Collision API +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 8cc4ab8f560f5db9cf7f58233578838945a52deb..8375ec85b78378f6ebc0a970fb0df205feb984e7 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1424,4 +1424,22 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + void damageItemStack(org.bukkit.inventory.@NotNull EquipmentSlot slot, int amount); + // Paper end - ItemStack damage API ++ ++ // Paper start - body yaw API ++ /** ++ * Gets entity body yaw ++ * ++ * @return entity body yaw ++ * @see Location#getYaw() ++ */ ++ float getBodyYaw(); ++ ++ /** ++ * Sets entity body yaw ++ * ++ * @param bodyYaw new entity body yaw ++ * @see Location#setYaw(float) ++ */ ++ void setBodyYaw(float bodyYaw); ++ // Paper end - body yaw API + } diff --git a/patches/api/0386-Add-Player-getFishHook.patch b/patches/api/0386-Add-Player-getFishHook.patch deleted file mode 100644 index c58145c58b31..000000000000 --- a/patches/api/0386-Add-Player-getFishHook.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: u9g -Date: Tue, 14 Jun 2022 19:35:21 -0400 -Subject: [PATCH] Add Player#getFishHook - - -diff --git a/src/main/java/org/bukkit/entity/HumanEntity.java b/src/main/java/org/bukkit/entity/HumanEntity.java -index f9531c0f909c7caeddfb8f06ef9a11469ba7d434..f854c1252f42ac02ad4eb84f7b5734b4cec88e53 100644 ---- a/src/main/java/org/bukkit/entity/HumanEntity.java -+++ b/src/main/java/org/bukkit/entity/HumanEntity.java -@@ -355,6 +355,13 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder - @Nullable - public Location getPotentialBedLocation(); - // Paper end -+ // Paper start -+ /** -+ * @return the player's fishing hook if they are fishing -+ */ -+ @Nullable -+ FishHook getFishHook(); -+ // Paper end - - /** - * Attempts to make the entity sleep at the given location. diff --git a/patches/api/0386-Fix-HandlerList-for-InventoryBlockStartEvent-subclas.patch b/patches/api/0386-Fix-HandlerList-for-InventoryBlockStartEvent-subclas.patch new file mode 100644 index 000000000000..c375206bf7e8 --- /dev/null +++ b/patches/api/0386-Fix-HandlerList-for-InventoryBlockStartEvent-subclas.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 7 Feb 2023 08:20:27 -0800 +Subject: [PATCH] Fix HandlerList for InventoryBlockStartEvent subclasses + + +diff --git a/src/main/java/org/bukkit/event/block/BrewingStartEvent.java b/src/main/java/org/bukkit/event/block/BrewingStartEvent.java +index 37be83184cae203d5e99518b0ff5c708fafb0331..43eac972f45d1cbb6278b048f8e6d7882c0aabeb 100644 +--- a/src/main/java/org/bukkit/event/block/BrewingStartEvent.java ++++ b/src/main/java/org/bukkit/event/block/BrewingStartEvent.java +@@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; + @org.jetbrains.annotations.ApiStatus.Experimental // Paper + public class BrewingStartEvent extends InventoryBlockStartEvent { + +- private static final HandlerList handlers = new HandlerList(); ++ // Paper - remove HandlerList + private int brewingTime; + + public BrewingStartEvent(@NotNull final Block furnace, @NotNull ItemStack source, int brewingTime) { +@@ -37,14 +37,5 @@ public class BrewingStartEvent extends InventoryBlockStartEvent { + this.brewingTime = brewTime; + } + +- @NotNull +- @Override +- public HandlerList getHandlers() { +- return handlers; +- } +- +- @NotNull +- public static HandlerList getHandlerList() { +- return handlers; +- } ++ // Paper - remove HandlerList + } +diff --git a/src/main/java/org/bukkit/event/block/CampfireStartEvent.java b/src/main/java/org/bukkit/event/block/CampfireStartEvent.java +index 2d084214e991fecc51f8e18e3d733e43b1dca248..4b12575107b3f1fa6d0ed7f667bf0d0ae40acae0 100644 +--- a/src/main/java/org/bukkit/event/block/CampfireStartEvent.java ++++ b/src/main/java/org/bukkit/event/block/CampfireStartEvent.java +@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull; + @org.jetbrains.annotations.ApiStatus.Experimental // Paper + public class CampfireStartEvent extends InventoryBlockStartEvent { + +- private static final HandlerList handlers = new HandlerList(); ++ // Paper - remove HandlerList + private int cookingTime; + private CampfireRecipe campfireRecipe; + +@@ -50,14 +50,5 @@ public class CampfireStartEvent extends InventoryBlockStartEvent { + this.cookingTime = cookTime; + } + +- @NotNull +- @Override +- public HandlerList getHandlers() { +- return handlers; +- } +- +- @NotNull +- public static HandlerList getHandlerList() { +- return handlers; +- } ++ // Paper - remove HandlerList + } +diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java +index d386ab5dd46cc6706ace61fe6b646713ffd50cb7..abfd0441f1dd485e59ce5a9f7fca88ffa32e87f7 100644 +--- a/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceStartSmeltEvent.java +@@ -14,7 +14,7 @@ import org.jetbrains.annotations.NotNull; + * {@link org.bukkit.block.Smoker}, and {@link org.bukkit.block.BlastFurnace}. + */ + public class FurnaceStartSmeltEvent extends InventoryBlockStartEvent { +- private static final HandlerList handlers = new HandlerList(); ++ // Paper - remove HandlerList + private final CookingRecipe recipe; + private int totalCookTime; + +@@ -59,14 +59,5 @@ public class FurnaceStartSmeltEvent extends InventoryBlockStartEvent { + this.totalCookTime = cookTime; + } + +- @NotNull +- @Override +- public HandlerList getHandlers() { +- return handlers; +- } +- +- @NotNull +- public static HandlerList getHandlerList() { +- return handlers; +- } ++ // Paper - remove HandlerList + } diff --git a/patches/api/0387-Add-EntityFertilizeEggEvent.patch b/patches/api/0387-Add-EntityFertilizeEggEvent.patch new file mode 100644 index 000000000000..8c15e656f8b1 --- /dev/null +++ b/patches/api/0387-Add-EntityFertilizeEggEvent.patch @@ -0,0 +1,145 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Fri, 24 Jun 2022 11:56:32 +0200 +Subject: [PATCH] Add EntityFertilizeEggEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityFertilizeEggEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityFertilizeEggEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a96c28678c5f6a52710ae287d3bbc25e180d058e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityFertilizeEggEvent.java +@@ -0,0 +1,133 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.Material; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityBreedEvent; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Called when two entities mate and the mating process results in a fertilization. ++ * Fertilization differs from normal breeding, as represented by the {@link EntityBreedEvent}, as ++ * it does not result in the immediate creation of the child entity in the world. ++ *

      ++ * An example of this would be: ++ *

        ++ *
      • A frog being marked as "is_pregnant" and laying {@link Material#FROGSPAWN} later.
      • ++ *
      • Sniffers producing the {@link Material#SNIFFER_EGG} item, which needs to be placed before it can begin to hatch.
      • ++ *
      • A turtle being marked with "HasEgg" and laying a {@link Material#TURTLE_EGG} later.
      • ++ *
      ++ *

      ++ * The event hence only exposes the two parent entities in the fertilization process and cannot provide the child entity, as it will only exist at a later point in time. ++ */ ++@NullMarked ++public class EntityFertilizeEggEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final LivingEntity mother; ++ private final LivingEntity father; ++ private final @Nullable Player breeder; ++ private final @Nullable ItemStack bredWith; ++ private int experience; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityFertilizeEggEvent(final LivingEntity mother, final LivingEntity father, final @Nullable Player breeder, final @Nullable ItemStack bredWith, final int experience) { ++ super(mother); ++ this.mother = mother; ++ this.father = father; ++ this.breeder = breeder; ++ this.bredWith = bredWith; ++ this.experience = experience; ++ } ++ ++ @Override ++ public LivingEntity getEntity() { ++ return (LivingEntity) super.getEntity(); ++ } ++ ++ /** ++ * Provides the entity in the fertilization process that will eventually be responsible for "creating" offspring, ++ * may that be by setting a block that later hatches or dropping an egg that has to be placed. ++ * ++ * @return The "mother" entity. ++ */ ++ public LivingEntity getMother() { ++ return this.mother; ++ } ++ ++ /** ++ * Provides the "father" entity in the fertilization process that is not responsible for initiating the offspring ++ * creation. ++ * ++ * @return the other parent ++ */ ++ public LivingEntity getFather() { ++ return this.father; ++ } ++ ++ /** ++ * Gets the Entity responsible for fertilization. Breeder is {@code null} for spontaneous ++ * conception. ++ * ++ * @return The Entity who initiated fertilization. ++ */ ++ public @Nullable Player getBreeder() { ++ return this.breeder; ++ } ++ ++ /** ++ * The ItemStack that was used to initiate fertilization, if present. ++ * ++ * @return ItemStack used to initiate fertilization. ++ */ ++ public @Nullable ItemStack getBredWith() { ++ return this.bredWith; ++ } ++ ++ /** ++ * Get the amount of experience granted by fertilization. ++ * ++ * @return experience amount ++ */ ++ public int getExperience() { ++ return this.experience; ++ } ++ ++ /** ++ * Set the amount of experience granted by fertilization. ++ * If the amount is negative or zero, no experience will be dropped. ++ * ++ * @param experience experience amount ++ */ ++ public void setExperience(final int experience) { ++ this.experience = experience; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0388-Add-CompostItemEvent-and-EntityCompostItemEvent.patch b/patches/api/0388-Add-CompostItemEvent-and-EntityCompostItemEvent.patch new file mode 100644 index 000000000000..e639e46b4dec --- /dev/null +++ b/patches/api/0388-Add-CompostItemEvent-and-EntityCompostItemEvent.patch @@ -0,0 +1,129 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Sat, 7 Aug 2021 15:11:27 +0200 +Subject: [PATCH] Add CompostItemEvent and EntityCompostItemEvent + + +diff --git a/src/main/java/io/papermc/paper/event/block/CompostItemEvent.java b/src/main/java/io/papermc/paper/event/block/CompostItemEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..03497ac2489b159716811f03ab68e345ff864fa6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/CompostItemEvent.java +@@ -0,0 +1,66 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.block.Block; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.bukkit.event.inventory.InventoryMoveItemEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when an item is about to be composted by a hopper. ++ * To prevent hoppers from moving items into composters, cancel the {@link InventoryMoveItemEvent}. ++ */ ++@NullMarked ++public class CompostItemEvent extends BlockEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final ItemStack item; ++ private boolean willRaiseLevel; ++ ++ @ApiStatus.Internal ++ public CompostItemEvent(final Block composter, final ItemStack item, final boolean willRaiseLevel) { ++ super(composter); ++ this.item = item; ++ this.willRaiseLevel = willRaiseLevel; ++ } ++ ++ /** ++ * Gets the item that was used on the composter. ++ * ++ * @return the item ++ */ ++ public ItemStack getItem() { ++ return this.item; ++ } ++ ++ /** ++ * Gets whether the composter will rise a level. ++ * ++ * @return {@code true} if successful ++ */ ++ public boolean willRaiseLevel() { ++ return this.willRaiseLevel; ++ } ++ ++ /** ++ * Sets whether the composter will rise a level. ++ * ++ * @param willRaiseLevel {@code true} if the composter should rise a level ++ */ ++ public void setWillRaiseLevel(final boolean willRaiseLevel) { ++ this.willRaiseLevel = willRaiseLevel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/event/entity/EntityCompostItemEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityCompostItemEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..213d957fdc68aa32d77424c84c5cf3b244cd4314 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/EntityCompostItemEvent.java +@@ -0,0 +1,45 @@ ++package io.papermc.paper.event.entity; ++ ++import io.papermc.paper.event.block.CompostItemEvent; ++import org.bukkit.block.Block; ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when an item is about to be composted by an entity. ++ */ ++@NullMarked ++public class EntityCompostItemEvent extends CompostItemEvent implements Cancellable { ++ ++ private final Entity entity; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public EntityCompostItemEvent(final Entity entity, final Block composter, final ItemStack item, final boolean willRaiseLevel) { ++ super(composter, item, willRaiseLevel); ++ this.entity = entity; ++ } ++ ++ /** ++ * Gets the entity that interacted with the composter. ++ * ++ * @return the entity that composted an item. ++ */ ++ public Entity getEntity() { ++ return this.entity; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++} diff --git a/patches/api/0389-Add-Shearable-API.patch b/patches/api/0389-Add-Shearable-API.patch new file mode 100644 index 000000000000..29875e12d92d --- /dev/null +++ b/patches/api/0389-Add-Shearable-API.patch @@ -0,0 +1,143 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 17 Oct 2021 15:39:41 -0400 +Subject: [PATCH] Add Shearable API + + +diff --git a/src/main/java/io/papermc/paper/entity/Shearable.java b/src/main/java/io/papermc/paper/entity/Shearable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3991f2aa530c588f52e1f596d3b03743e8a8ecc4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/Shearable.java +@@ -0,0 +1,44 @@ ++package io.papermc.paper.entity; ++ ++import net.kyori.adventure.sound.Sound; ++import org.bukkit.entity.Entity; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents an entity that can be sheared. ++ */ ++@NullMarked ++public interface Shearable extends Entity { ++ ++ /** ++ * Forces the entity to be sheared and then play the effect as if it were sheared by a player. ++ * This will cause the entity to be sheared, even if {@link Shearable#readyToBeSheared()} is false. ++ *

      ++ * Some shearing behavior may cause the entity to no longer be valid ++ * due to it being replaced by a different entity. ++ */ ++ default void shear() { ++ this.shear(Sound.Source.PLAYER); ++ } ++ ++ /** ++ * Forces the entity to be sheared and then play the effect as if it were sheared by the provided source. ++ * This will cause the entity to be sheared, even if {@link Shearable#readyToBeSheared()} is false. ++ *

      ++ * Some shearing behavior may cause the entity to no longer be valid ++ * due to it being replaced by a different entity. ++ *

      ++ * This simulates the behavior of an actual shearing, which may cause events like EntityTransformEvent to be called ++ * for mooshrooms, and EntityDropItemEvent to be called for sheep. ++ * ++ * @param source Sound source to play any sound effects on ++ */ ++ void shear(Sound.Source source); ++ ++ /** ++ * Gets if the entity would be able to be sheared or not naturally using shears. ++ * ++ * @return if the entity can be sheared ++ */ ++ boolean readyToBeSheared(); ++} +diff --git a/src/main/java/org/bukkit/entity/Bogged.java b/src/main/java/org/bukkit/entity/Bogged.java +index 0e5aaf54df0a5d0995147a905daef52442b070c5..6093b1dad8ad48708267a83bf4c1ad20467b3cf9 100644 +--- a/src/main/java/org/bukkit/entity/Bogged.java ++++ b/src/main/java/org/bukkit/entity/Bogged.java +@@ -6,7 +6,7 @@ import org.jetbrains.annotations.ApiStatus; + * Represents a Bogged Skeleton. + */ + @ApiStatus.Experimental +-public interface Bogged extends AbstractSkeleton, Shearable { ++public interface Bogged extends AbstractSkeleton, Shearable, io.papermc.paper.entity.Shearable { // Paper - Shear API + + /** + * Gets whether the bogged is in its sheared state. +diff --git a/src/main/java/org/bukkit/entity/MushroomCow.java b/src/main/java/org/bukkit/entity/MushroomCow.java +index cef1700834643fe28ed5737578d91ecefbe99e2f..86c0043ef4e1288b6fe2f68a9b6d01c3de2c3454 100644 +--- a/src/main/java/org/bukkit/entity/MushroomCow.java ++++ b/src/main/java/org/bukkit/entity/MushroomCow.java +@@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents a mushroom {@link Cow} + */ +-public interface MushroomCow extends Cow { ++public interface MushroomCow extends Cow, io.papermc.paper.entity.Shearable { // Paper + + /** + * Checks for the presence of custom potion effects to be applied to the +diff --git a/src/main/java/org/bukkit/entity/Shearable.java b/src/main/java/org/bukkit/entity/Shearable.java +index 0215d20f81bfbef080f86ce46147a38f71310f65..9967c8a52ddd2c7e10db49a3f166731373f1ba45 100644 +--- a/src/main/java/org/bukkit/entity/Shearable.java ++++ b/src/main/java/org/bukkit/entity/Shearable.java +@@ -2,20 +2,30 @@ package org.bukkit.entity; + + /** + * Represents an entity which can be shorn with shears. ++ * @deprecated Spigots shearable API miserably fails at capturing all entities that may be sheared by a player, like ++ * mushroom cows which, once sheared, convert into normal cows. For such entities, methods like ++ * {@link #setSheared(boolean)} or {@link #isSheared()} make no sense, making this API and interface dead API from ++ * the get-go. + */ ++@Deprecated(forRemoval = true, since = "1.21") + public interface Shearable { + + /** + * Gets whether the entity is in its sheared state. + * + * @return Whether the entity is sheared. ++ * @deprecated Use {@link io.papermc.paper.entity.Shearable#readyToBeSheared()} instead. + */ ++ @Deprecated(forRemoval = true, since = "1.21") + boolean isSheared(); + + /** + * Sets whether the entity is in its sheared state. + * + * @param flag Whether to shear the entity ++ * @deprecated Use {@link io.papermc.paper.entity.Shearable#shear()} instead if applicable. ++ * Some entities cannot be "unsheared". + */ ++ @Deprecated(forRemoval = true, since = "1.21") + void setSheared(boolean flag); + } +diff --git a/src/main/java/org/bukkit/entity/Sheep.java b/src/main/java/org/bukkit/entity/Sheep.java +index 9ed473e5e993ef2d9558fe18bbcea7dad9b42994..f67f478945a7ba99bf72601678a153553526799a 100644 +--- a/src/main/java/org/bukkit/entity/Sheep.java ++++ b/src/main/java/org/bukkit/entity/Sheep.java +@@ -5,7 +5,7 @@ import org.bukkit.material.Colorable; + /** + * Represents a Sheep. + */ +-public interface Sheep extends Animals, Colorable, Shearable { ++public interface Sheep extends Animals, Colorable, Shearable, io.papermc.paper.entity.Shearable { // Paper - Shear API + + /** + * Gets whether the sheep is in its sheared state. +diff --git a/src/main/java/org/bukkit/entity/Snowman.java b/src/main/java/org/bukkit/entity/Snowman.java +index 10f8f6d45ae9280651c3ebddd1f90acbd7d6ff29..7fbfdb07585c7b28acea1f0c1f58ada0cc744441 100644 +--- a/src/main/java/org/bukkit/entity/Snowman.java ++++ b/src/main/java/org/bukkit/entity/Snowman.java +@@ -5,7 +5,7 @@ import com.destroystokyo.paper.entity.RangedEntity; + /** + * Represents a snowman entity + */ +-public interface Snowman extends Golem, RangedEntity { // Paper ++public interface Snowman extends Golem, RangedEntity, io.papermc.paper.entity.Shearable { // Paper + + /** + * Gets whether this snowman is in "derp mode", meaning it is not wearing a diff --git a/patches/api/0390-Fix-SpawnEggMeta-get-setSpawnedType.patch b/patches/api/0390-Fix-SpawnEggMeta-get-setSpawnedType.patch new file mode 100644 index 000000000000..6eeaa9736fe2 --- /dev/null +++ b/patches/api/0390-Fix-SpawnEggMeta-get-setSpawnedType.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 26 Feb 2023 07:14:19 -0800 +Subject: [PATCH] Fix SpawnEggMeta#get/setSpawnedType + + +diff --git a/src/main/java/org/bukkit/inventory/meta/SpawnEggMeta.java b/src/main/java/org/bukkit/inventory/meta/SpawnEggMeta.java +index 2151946cf791c4c37b2ad527fe20bd784a037190..159055dfc6bd1eb77e07c5eb199c3ae892a749e0 100644 +--- a/src/main/java/org/bukkit/inventory/meta/SpawnEggMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/SpawnEggMeta.java +@@ -17,7 +17,7 @@ public interface SpawnEggMeta extends ItemMeta { + * @return The entity type. May be null for implementation specific default. + * @deprecated different types are different items + */ +- @Deprecated(since = "1.13") ++ @Deprecated(since = "1.13", forRemoval = true) // Paper + @Contract("-> fail") + EntityType getSpawnedType(); + +@@ -28,7 +28,7 @@ public interface SpawnEggMeta extends ItemMeta { + * default. + * @deprecated different types are different items + */ +- @Deprecated(since = "1.13") ++ @Deprecated(since = "1.13", forRemoval = true) // Paper + @Contract("_ -> fail") + void setSpawnedType(EntityType type); + +@@ -54,6 +54,22 @@ public interface SpawnEggMeta extends ItemMeta { + */ + void setSpawnedEntity(@NotNull EntitySnapshot snapshot); + ++ // Paper start ++ /** ++ * Get the custom type of entity this egg will spawn. ++ * ++ * @return the entity type or null if no custom type is set ++ */ ++ @org.jetbrains.annotations.Nullable EntityType getCustomSpawnedType(); ++ ++ /** ++ * Set the custom type of entity this egg will spawn. ++ * ++ * @param type the entity type or null to clear the custom type ++ */ ++ void setCustomSpawnedType(@org.jetbrains.annotations.Nullable EntityType type); ++ // Paper end ++ + @NotNull + @Override + SpawnEggMeta clone(); diff --git a/patches/api/0391-Add-Mob-Experience-reward-API.patch b/patches/api/0391-Add-Mob-Experience-reward-API.patch new file mode 100644 index 000000000000..354d6d1eb467 --- /dev/null +++ b/patches/api/0391-Add-Mob-Experience-reward-API.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: GodOfPro <1387ilia@gmail.com> +Date: Tue, 11 Apr 2023 16:30:58 +0430 +Subject: [PATCH] Add Mob Experience reward API + + +diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java +index d55250d820b02f3a23b99a59e68d3361698baddf..256e5645bcfa76e7ede58ae365e69b4a4bed6204 100644 +--- a/src/main/java/org/bukkit/entity/Mob.java ++++ b/src/main/java/org/bukkit/entity/Mob.java +@@ -220,4 +220,13 @@ public interface Mob extends LivingEntity, Lootable { + */ + public void setLeftHanded(boolean leftHanded); + // Paper end - left-handed API ++ ++ // Paper start - mob xp reward API ++ /** ++ * Gets the amount of experience the mob will possibly drop. This value is randomized and it can give different results ++ * ++ * @return the amount of experience the mob will possibly drop ++ */ ++ public int getPossibleExperienceReward(); ++ // Paper end - mob xp reward API + } diff --git a/patches/api/0392-Expand-PlayerItemMendEvent.patch b/patches/api/0392-Expand-PlayerItemMendEvent.patch new file mode 100644 index 000000000000..d13509496bc0 --- /dev/null +++ b/patches/api/0392-Expand-PlayerItemMendEvent.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 20 Jan 2022 18:11:44 -0800 +Subject: [PATCH] Expand PlayerItemMendEvent + + +diff --git a/src/main/java/org/bukkit/event/player/PlayerItemMendEvent.java b/src/main/java/org/bukkit/event/player/PlayerItemMendEvent.java +index cfbd0b42ae0d7c083467e9c3139fd1ed99d9e94b..f0533271dd38276e210061f8767a8acc0fef2a64 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerItemMendEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerItemMendEvent.java +@@ -6,6 +6,7 @@ import org.bukkit.event.Cancellable; + import org.bukkit.event.HandlerList; + import org.bukkit.inventory.EquipmentSlot; + import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.Contract; + import org.jetbrains.annotations.NotNull; + + /** +@@ -23,14 +24,67 @@ public class PlayerItemMendEvent extends PlayerEvent implements Cancellable { + private final ExperienceOrb experienceOrb; + private int repairAmount; + private boolean cancelled; ++ private final int consumedExperience; // Paper + ++ @Deprecated // Paper + public PlayerItemMendEvent(@NotNull Player who, @NotNull ItemStack item, @NotNull EquipmentSlot slot, @NotNull ExperienceOrb experienceOrb, int repairAmount) { ++ // Paper start ++ this(who, item, slot, experienceOrb, repairAmount, repairAmount / 2); ++ } ++ ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public PlayerItemMendEvent(@NotNull Player who, @NotNull ItemStack item, @NotNull EquipmentSlot slot, @NotNull ExperienceOrb experienceOrb, int repairAmount, int consumedExperience) { ++ // Paper end + super(who); + this.item = item; + this.slot = slot; + this.experienceOrb = experienceOrb; + this.repairAmount = repairAmount; ++ // Paper start ++ this.consumedExperience = consumedExperience; ++ } ++ ++ /** ++ * Get the operation used to calculate xp used based on ++ * the set repair amount. Used to calculate how much of ++ * an XP orb will be consumed by this mend operation. ++ * ++ * @return the durability-to-xp operation ++ * @deprecated the mending enchantment uses enchantment effects to compute how much durability is granted per xp. ++ * The enchantment effects operation are too complex to reliably offer the inverse function. ++ */ ++ @Contract("-> fail") ++ @Deprecated(forRemoval = true, since = "1.21") ++ public @NotNull java.util.function.IntUnaryOperator getDurabilityToXpOperation() { ++ throw new UnsupportedOperationException("Enchantments use effects to compute xp to durability since 1.21."); ++ } ++ ++ /** ++ * Sets the operation used to calculate xp used based on ++ * the set repair amount. Used to calculate how much of ++ * an XP orb will be consumed by this mend operation. ++ * ++ * @param durabilityToXpOp the durability-to-xp operation ++ * @deprecated the mending enchantment uses enchantment effects to compute how much durability is granted per xp. ++ * The enchantment effects operation are too complex to reliably offer the inverse function. ++ */ ++ @Contract("_ -> fail") ++ @Deprecated(forRemoval = true, since = "1.21") ++ public void setDurabilityToXpOperation(@NotNull java.util.function.IntUnaryOperator durabilityToXpOp) { ++ throw new UnsupportedOperationException("Enchantments use effects to compute xp to durability since 1.21."); ++ } ++ ++ /** ++ * Helper method to get the amount of experience that will be consumed. ++ * This method just returns the result of inputting {@link #getRepairAmount()} ++ * into the function {@link #getDurabilityToXpOperation()}. ++ * ++ * @return the amount of xp that will be consumed ++ */ ++ public int getConsumedExperience() { ++ return this.consumedExperience; + } ++ // Paper end + + @Deprecated(since = "1.19.2") + public PlayerItemMendEvent(@NotNull Player who, @NotNull ItemStack item, @NotNull ExperienceOrb experienceOrb, int repairAmount) { diff --git a/patches/api/0393-Add-method-to-remove-all-active-potion-effects.patch b/patches/api/0393-Add-method-to-remove-all-active-potion-effects.patch new file mode 100644 index 000000000000..cbbc90e94a21 --- /dev/null +++ b/patches/api/0393-Add-method-to-remove-all-active-potion-effects.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 17 Jun 2023 13:17:20 -0700 +Subject: [PATCH] Add method to remove all active potion effects + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 8375ec85b78378f6ebc0a970fb0df205feb984e7..7cc29c7a9e2c30feaedaab188024387e12f51c75 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -657,6 +657,15 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + @NotNull + public Collection getActivePotionEffects(); + ++ // Paper start - LivingEntity#clearActivePotionEffects(); ++ /** ++ * Removes all active potion effects for this entity. ++ * ++ * @return true if any were removed ++ */ ++ boolean clearActivePotionEffects(); ++ // Paper end ++ + /** + * Checks whether the living entity has block line of sight to another. + *

      diff --git a/patches/api/0394-Folia-scheduler-and-owned-region-API.patch b/patches/api/0394-Folia-scheduler-and-owned-region-API.patch new file mode 100644 index 000000000000..6017268d79c0 --- /dev/null +++ b/patches/api/0394-Folia-scheduler-and-owned-region-API.patch @@ -0,0 +1,832 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sat, 17 Jun 2023 11:52:41 +0200 +Subject: [PATCH] Folia scheduler and owned region API + +Pulling Folia API to Paper is primarily intended for plugins +that want to target both Paper and Folia without unnecessary +compatibility layers. + +Add both a location based scheduler, an entity based scheduler, +and a global region scheduler. + +Owned region API may be useful for plugins which want to perform +operations over large areas outside of the buffer zone provided +by the regionaliser, as it is not guaranteed that anything +outside of the buffer zone is owned. Then, the plugins may use +the schedulers depending on the result of the ownership check. + +diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/AsyncScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/AsyncScheduler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9852e14e68d12ca56b0d57cd6e83e252f47bde72 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/AsyncScheduler.java +@@ -0,0 +1,51 @@ ++package io.papermc.paper.threadedregions.scheduler; ++ ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.concurrent.TimeUnit; ++import java.util.function.Consumer; ++ ++/** ++ * Scheduler that may be used by plugins to schedule tasks to execute asynchronously from the server tick process. ++ */ ++public interface AsyncScheduler { ++ ++ /** ++ * Schedules the specified task to be executed asynchronously immediately. ++ * @param plugin Plugin which owns the specified task. ++ * @param task Specified task. ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ @NotNull ScheduledTask runNow(@NotNull Plugin plugin, @NotNull Consumer task); ++ ++ /** ++ * Schedules the specified task to be executed asynchronously after the time delay has passed. ++ * @param plugin Plugin which owns the specified task. ++ * @param task Specified task. ++ * @param delay The time delay to pass before the task should be executed. ++ * @param unit The time unit for the time delay. ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ @NotNull ScheduledTask runDelayed(@NotNull Plugin plugin, @NotNull Consumer task, long delay, ++ @NotNull TimeUnit unit); ++ ++ /** ++ * Schedules the specified task to be executed asynchronously after the initial delay has passed, ++ * and then periodically executed with the specified period. ++ * @param plugin Plugin which owns the specified task. ++ * @param task Specified task. ++ * @param initialDelay The time delay to pass before the first execution of the task. ++ * @param period The time between task executions after the first execution of the task. ++ * @param unit The time unit for the initial delay and period. ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ @NotNull ScheduledTask runAtFixedRate(@NotNull Plugin plugin, @NotNull Consumer task, ++ long initialDelay, long period, @NotNull TimeUnit unit); ++ ++ /** ++ * Attempts to cancel all tasks scheduled by the specified plugin. ++ * @param plugin Specified plugin. ++ */ ++ void cancelTasks(@NotNull Plugin plugin); ++} +diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/EntityScheduler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..99e9e20ae01f9b4b8cde585d29c57e27c53c996e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/EntityScheduler.java +@@ -0,0 +1,104 @@ ++package io.papermc.paper.threadedregions.scheduler; ++ ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.function.Consumer; ++ ++/** ++ * An entity can move between worlds with an arbitrary tick delay, be temporarily removed ++ * for players (i.e end credits), be partially removed from world state (i.e inactive but not removed), ++ * teleport between ticking regions, teleport between worlds, and even be removed entirely from the server. ++ * The uncertainty of an entity's state can make it difficult to schedule tasks without worrying about undefined ++ * behaviors resulting from any of the states listed previously. ++ * ++ *

      ++ * This class is designed to eliminate those states by providing an interface to run tasks only when an entity ++ * is contained in a world, on the owning thread for the region, and by providing the current Entity object. ++ * The scheduler also allows a task to provide a callback, the "retired" callback, that will be invoked ++ * if the entity is removed before a task that was scheduled could be executed. The scheduler is also ++ * completely thread-safe, allowing tasks to be scheduled from any thread context. The scheduler also indicates ++ * properly whether a task was scheduled successfully (i.e scheduler not retired), thus the code scheduling any task ++ * knows whether the given callbacks will be invoked eventually or not - which may be critical for off-thread ++ * contexts. ++ *

      ++ */ ++public interface EntityScheduler { ++ ++ /** ++ * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity ++ * removed), then returns {@code false}. Otherwise, either the run callback will be invoked after the specified delay, ++ * or the retired callback will be invoked if the scheduler is retired. ++ * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove ++ * other entities, load chunks, load worlds, modify ticket levels, etc. ++ * ++ *

      ++ * It is guaranteed that the run and retired callback are invoked on the region which owns the entity. ++ *

      ++ * @param run The callback to run after the specified delay, may not be null. ++ * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. ++ * @param delay The delay in ticks before the run callback is invoked. Any value less-than 1 is treated as 1. ++ * @return {@code true} if the task was scheduled, which means that either the run function or the retired function ++ * will be invoked (but never both), or {@code false} indicating neither the run nor retired function will be invoked ++ * since the scheduler has been retired. ++ */ ++ boolean execute(@NotNull Plugin plugin, @NotNull Runnable run, @Nullable Runnable retired, long delay); ++ ++ /** ++ * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity ++ * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, ++ * or the retired callback will be invoked if the scheduler is retired. ++ * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove ++ * other entities, load chunks, load worlds, modify ticket levels, etc. ++ * ++ *

      ++ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. ++ *

      ++ * @param plugin The plugin that owns the task ++ * @param task The task to execute ++ * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. ++ * @return The {@link ScheduledTask} that represents the scheduled task, or {@code null} if the entity has been removed. ++ */ ++ @Nullable ScheduledTask run(@NotNull Plugin plugin, @NotNull Consumer task, ++ @Nullable Runnable retired); ++ ++ /** ++ * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity ++ * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, ++ * or the retired callback will be invoked if the scheduler is retired. ++ * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove ++ * other entities, load chunks, load worlds, modify ticket levels, etc. ++ * ++ *

      ++ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. ++ *

      ++ * @param plugin The plugin that owns the task ++ * @param task The task to execute ++ * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. ++ * @param delayTicks The delay, in ticks. ++ * @return The {@link ScheduledTask} that represents the scheduled task, or {@code null} if the entity has been removed. ++ */ ++ @Nullable ScheduledTask runDelayed(@NotNull Plugin plugin, @NotNull Consumer task, ++ @Nullable Runnable retired, long delayTicks); ++ ++ /** ++ * Schedules a repeating task with the given delay and period. If the task failed to schedule because the scheduler ++ * is retired (entity removed), then returns {@code null}. Otherwise, either the task callback will be invoked after ++ * the specified delay, or the retired callback will be invoked if the scheduler is retired. ++ * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove ++ * other entities, load chunks, load worlds, modify ticket levels, etc. ++ * ++ *

      ++ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. ++ *

      ++ * @param plugin The plugin that owns the task ++ * @param task The task to execute ++ * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. ++ * @param initialDelayTicks The initial delay, in ticks. ++ * @param periodTicks The period, in ticks. ++ * @return The {@link ScheduledTask} that represents the scheduled task, or {@code null} if the entity has been removed. ++ */ ++ @Nullable ScheduledTask runAtFixedRate(@NotNull Plugin plugin, @NotNull Consumer task, ++ @Nullable Runnable retired, long initialDelayTicks, long periodTicks); ++} +diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..57455aca80ecc458b96b44c086cea94ddcecae47 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java +@@ -0,0 +1,58 @@ ++package io.papermc.paper.threadedregions.scheduler; ++ ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.function.Consumer; ++ ++/** ++ * The global region task scheduler may be used to schedule tasks that will execute on the global region. ++ *

      ++ * The global region is responsible for maintaining world day time, world game time, weather cycle, ++ * sleep night skipping, executing commands for console, and other misc. tasks that do not belong to any specific region. ++ *

      ++ */ ++public interface GlobalRegionScheduler { ++ ++ /** ++ * Schedules a task to be executed on the global region. ++ * @param plugin The plugin that owns the task ++ * @param run The task to execute ++ */ ++ void execute(@NotNull Plugin plugin, @NotNull Runnable run); ++ ++ /** ++ * Schedules a task to be executed on the global region on the next tick. ++ * @param plugin The plugin that owns the task ++ * @param task The task to execute ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ @NotNull ScheduledTask run(@NotNull Plugin plugin, @NotNull Consumer task); ++ ++ /** ++ * Schedules a task to be executed on the global region after the specified delay in ticks. ++ * @param plugin The plugin that owns the task ++ * @param task The task to execute ++ * @param delayTicks The delay, in ticks. ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ @NotNull ScheduledTask runDelayed(@NotNull Plugin plugin, @NotNull Consumer task, long delayTicks); ++ ++ /** ++ * Schedules a repeating task to be executed on the global region after the initial delay with the ++ * specified period. ++ * @param plugin The plugin that owns the task ++ * @param task The task to execute ++ * @param initialDelayTicks The initial delay, in ticks. ++ * @param periodTicks The period, in ticks. ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ @NotNull ScheduledTask runAtFixedRate(@NotNull Plugin plugin, @NotNull Consumer task, ++ long initialDelayTicks, long periodTicks); ++ ++ /** ++ * Attempts to cancel all tasks scheduled by the specified plugin. ++ * @param plugin Specified plugin. ++ */ ++ void cancelTasks(@NotNull Plugin plugin); ++} +diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/RegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/RegionScheduler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7557e170f84cde7292869fbd92b44b0e6eb43b4f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/RegionScheduler.java +@@ -0,0 +1,127 @@ ++package io.papermc.paper.threadedregions.scheduler; ++ ++import org.bukkit.Location; ++import org.bukkit.World; ++import org.bukkit.entity.Entity; ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.function.Consumer; ++ ++/** ++ * The region task scheduler can be used to schedule tasks by location to be executed on the region which owns the location. ++ *

      ++ * Note: It is entirely inappropriate to use the region scheduler to schedule tasks for entities. ++ * If you wish to schedule tasks to perform actions on entities, you should be using {@link Entity#getScheduler()} ++ * as the entity scheduler will "follow" an entity if it is teleported, whereas the region task scheduler ++ * will not. ++ *

      ++ */ ++public interface RegionScheduler { ++ ++ /** ++ * Schedules a task to be executed on the region which owns the location. ++ * ++ * @param plugin The plugin that owns the task ++ * @param world The world of the region that owns the task ++ * @param chunkX The chunk X coordinate of the region that owns the task ++ * @param chunkZ The chunk Z coordinate of the region that owns the task ++ * @param run The task to execute ++ */ ++ void execute(@NotNull Plugin plugin, @NotNull World world, int chunkX, int chunkZ, @NotNull Runnable run); ++ ++ /** ++ * Schedules a task to be executed on the region which owns the location. ++ * ++ * @param plugin The plugin that owns the task ++ * @param location The location at which the region executing should own ++ * @param run The task to execute ++ */ ++ default void execute(@NotNull Plugin plugin, @NotNull Location location, @NotNull Runnable run) { ++ this.execute(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, run); ++ } ++ ++ /** ++ * Schedules a task to be executed on the region which owns the location on the next tick. ++ * ++ * @param plugin The plugin that owns the task ++ * @param world The world of the region that owns the task ++ * @param chunkX The chunk X coordinate of the region that owns the task ++ * @param chunkZ The chunk Z coordinate of the region that owns the task ++ * @param task The task to execute ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ @NotNull ScheduledTask run(@NotNull Plugin plugin, @NotNull World world, int chunkX, int chunkZ, @NotNull Consumer task); ++ ++ /** ++ * Schedules a task to be executed on the region which owns the location on the next tick. ++ * ++ * @param plugin The plugin that owns the task ++ * @param location The location at which the region executing should own ++ * @param task The task to execute ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ default @NotNull ScheduledTask run(@NotNull Plugin plugin, @NotNull Location location, @NotNull Consumer task) { ++ return this.run(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task); ++ } ++ ++ /** ++ * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. ++ * ++ * @param plugin The plugin that owns the task ++ * @param world The world of the region that owns the task ++ * @param chunkX The chunk X coordinate of the region that owns the task ++ * @param chunkZ The chunk Z coordinate of the region that owns the task ++ * @param task The task to execute ++ * @param delayTicks The delay, in ticks. ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ @NotNull ScheduledTask runDelayed(@NotNull Plugin plugin, @NotNull World world, int chunkX, int chunkZ, @NotNull Consumer task, ++ long delayTicks); ++ ++ /** ++ * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. ++ * ++ * @param plugin The plugin that owns the task ++ * @param location The location at which the region executing should own ++ * @param task The task to execute ++ * @param delayTicks The delay, in ticks. ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ default @NotNull ScheduledTask runDelayed(@NotNull Plugin plugin, @NotNull Location location, @NotNull Consumer task, ++ long delayTicks) { ++ return this.runDelayed(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks); ++ } ++ ++ /** ++ * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the ++ * specified period. ++ * ++ * @param plugin The plugin that owns the task ++ * @param world The world of the region that owns the task ++ * @param chunkX The chunk X coordinate of the region that owns the task ++ * @param chunkZ The chunk Z coordinate of the region that owns the task ++ * @param task The task to execute ++ * @param initialDelayTicks The initial delay, in ticks. ++ * @param periodTicks The period, in ticks. ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ @NotNull ScheduledTask runAtFixedRate(@NotNull Plugin plugin, @NotNull World world, int chunkX, int chunkZ, @NotNull Consumer task, ++ long initialDelayTicks, long periodTicks); ++ ++ /** ++ * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the ++ * specified period. ++ * ++ * @param plugin The plugin that owns the task ++ * @param location The location at which the region executing should own ++ * @param task The task to execute ++ * @param initialDelayTicks The initial delay, in ticks. ++ * @param periodTicks The period, in ticks. ++ * @return The {@link ScheduledTask} that represents the scheduled task. ++ */ ++ default @NotNull ScheduledTask runAtFixedRate(@NotNull Plugin plugin, @NotNull Location location, @NotNull Consumer task, ++ long initialDelayTicks, long periodTicks) { ++ return this.runAtFixedRate(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, initialDelayTicks, periodTicks); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/ScheduledTask.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/ScheduledTask.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a6b50c9d8af589cc4747e14d343d2045216c249c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/ScheduledTask.java +@@ -0,0 +1,112 @@ ++package io.papermc.paper.threadedregions.scheduler; ++ ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents a task scheduled to a scheduler. ++ */ ++public interface ScheduledTask { ++ ++ /** ++ * Returns the plugin that scheduled this task. ++ * @return the plugin that scheduled this task. ++ */ ++ @NotNull Plugin getOwningPlugin(); ++ ++ /** ++ * Returns whether this task executes on a fixed period, as opposed to executing only once. ++ * @return whether this task executes on a fixed period, as opposed to executing only once. ++ */ ++ boolean isRepeatingTask(); ++ ++ /** ++ * Attempts to cancel this task, returning the result of the attempt. In all cases, if the task is currently ++ * being executed no attempt is made to halt the task, however any executions in the future are halted. ++ * @return the result of the cancellation attempt. ++ */ ++ @NotNull CancelledState cancel(); ++ ++ /** ++ * Returns the current execution state of this task. ++ * @return the current execution state of this task. ++ */ ++ @NotNull ExecutionState getExecutionState(); ++ ++ /** ++ * Returns whether the current execution state is {@link ExecutionState#CANCELLED} or {@link ExecutionState#CANCELLED_RUNNING}. ++ * @return whether the current execution state is {@link ExecutionState#CANCELLED} or {@link ExecutionState#CANCELLED_RUNNING}. ++ */ ++ default boolean isCancelled() { ++ final ExecutionState state = this.getExecutionState(); ++ return state == ExecutionState.CANCELLED || state == ExecutionState.CANCELLED_RUNNING; ++ } ++ ++ /** ++ * Represents the result of attempting to cancel a task. ++ */ ++ enum CancelledState { ++ /** ++ * The task (repeating or not) has been successfully cancelled by the caller thread. The task is not executing ++ * currently, and it will not begin execution in the future. ++ */ ++ CANCELLED_BY_CALLER, ++ /** ++ * The task (repeating or not) is already cancelled. The task is not executing currently, and it will not ++ * begin execution in the future. ++ */ ++ CANCELLED_ALREADY, ++ ++ /** ++ * The task is not a repeating task, and could not be cancelled because the task is being executed. ++ */ ++ RUNNING, ++ /** ++ * The task is not a repeating task, and could not be cancelled because the task has already finished execution. ++ */ ++ ALREADY_EXECUTED, ++ ++ /** ++ * The caller thread successfully stopped future executions of a repeating task, but the task is currently ++ * being executed. ++ */ ++ NEXT_RUNS_CANCELLED, ++ ++ /** ++ * The repeating task's future executions are cancelled already, but the task is currently ++ * being executed. ++ */ ++ NEXT_RUNS_CANCELLED_ALREADY, ++ } ++ ++ /** ++ * Represents the current execution state of the task. ++ */ ++ enum ExecutionState { ++ /** ++ * The task is currently not executing, but may begin execution in the future. ++ */ ++ IDLE, ++ ++ /** ++ * The task is currently executing. ++ */ ++ RUNNING, ++ ++ /** ++ * The task is not repeating, and the task finished executing. ++ */ ++ FINISHED, ++ ++ /** ++ * The task is not executing and will not begin execution in the future. If this task is not repeating, then ++ * this task was never executed. ++ */ ++ CANCELLED, ++ ++ /** ++ * The task is repeating and currently executing, but future executions are cancelled and will not occur. ++ */ ++ CANCELLED_RUNNING; ++ } ++} +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 629d062b76ff4186cc5c824b1bdcafe3667b50fe..5170f7ba71d8a09f2b4ae0d945c758fd4ae4130f 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2696,6 +2696,164 @@ public final class Bukkit { + } + // Paper end + ++ // Paper start - Folia region threading API ++ /** ++ * Returns the region task scheduler. The region task scheduler can be used to schedule ++ * tasks by location to be executed on the region which owns the location. ++ *

      ++ * Note: It is entirely inappropriate to use the region scheduler to schedule tasks for entities. ++ * If you wish to schedule tasks to perform actions on entities, you should be using {@link Entity#getScheduler()} ++ * as the entity scheduler will "follow" an entity if it is teleported, whereas the region task scheduler ++ * will not. ++ *

      ++ *

      If you do not need/want to make your plugin run on Folia, use {@link #getScheduler()} instead.

      ++ * @return the region task scheduler ++ */ ++ public static @NotNull io.papermc.paper.threadedregions.scheduler.RegionScheduler getRegionScheduler() { ++ return server.getRegionScheduler(); ++ } ++ ++ /** ++ * Returns the async task scheduler. The async task scheduler can be used to schedule tasks ++ * that execute asynchronously from the server tick process. ++ * @return the async task scheduler ++ */ ++ public static @NotNull io.papermc.paper.threadedregions.scheduler.AsyncScheduler getAsyncScheduler() { ++ return server.getAsyncScheduler(); ++ } ++ ++ /** ++ * Returns the global region task scheduler. The global task scheduler can be used to schedule ++ * tasks to execute on the global region. ++ *

      ++ * The global region is responsible for maintaining world day time, world game time, weather cycle, ++ * sleep night skipping, executing commands for console, and other misc. tasks that do not belong to any specific region. ++ *

      ++ *

      If you do not need/want to make your plugin run on Folia, use {@link #getScheduler()} instead.

      ++ * @return the global region scheduler ++ */ ++ public static @NotNull io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler getGlobalRegionScheduler() { ++ return server.getGlobalRegionScheduler(); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunk at the specified world and block position. ++ * @param world Specified world. ++ * @param position Specified block position. ++ */ ++ public static boolean isOwnedByCurrentRegion(@NotNull World world, @NotNull io.papermc.paper.math.Position position) { ++ return server.isOwnedByCurrentRegion(world, position); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunks centered at the specified block position within the specified square radius. ++ * Specifically, this function checks that every chunk with position x in [centerX - radius, centerX + radius] and ++ * position z in [centerZ - radius, centerZ + radius] is owned by the current ticking region. ++ * @param world Specified world. ++ * @param position Specified block position. ++ * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared ++ * radius, but rather a Chebyshev Distance. ++ */ ++ public static boolean isOwnedByCurrentRegion(@NotNull World world, @NotNull io.papermc.paper.math.Position position, int squareRadiusChunks) { ++ return server.isOwnedByCurrentRegion(world, position, squareRadiusChunks); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunk at the specified world and block position as included in the specified location. ++ * @param location Specified location, must have a non-null world. ++ */ ++ public static boolean isOwnedByCurrentRegion(@NotNull Location location) { ++ return server.isOwnedByCurrentRegion(location); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunks centered at the specified world and block position as included in the specified location ++ * within the specified square radius. ++ * Specifically, this function checks that every chunk with position x in [centerX - radius, centerX + radius] and ++ * position z in [centerZ - radius, centerZ + radius] is owned by the current ticking region. ++ * @param location Specified location, must have a non-null world. ++ * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared ++ * radius, but rather a Chebyshev Distance. ++ */ ++ public static boolean isOwnedByCurrentRegion(@NotNull Location location, int squareRadiusChunks) { ++ return server.isOwnedByCurrentRegion(location, squareRadiusChunks); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunk at the specified block position. ++ * @param block Specified block position. ++ */ ++ public static boolean isOwnedByCurrentRegion(@NotNull org.bukkit.block.Block block) { ++ return server.isOwnedByCurrentRegion(block.getLocation()); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunk at the specified world and chunk position. ++ * @param world Specified world. ++ * @param chunkX Specified x-coordinate of the chunk position. ++ * @param chunkZ Specified z-coordinate of the chunk position. ++ */ ++ public static boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ) { ++ return server.isOwnedByCurrentRegion(world, chunkX, chunkZ); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunks centered at the specified world and chunk position within the specified ++ * square radius. ++ * Specifically, this function checks that every chunk with position x in [centerX - radius, centerX + radius] and ++ * position z in [centerZ - radius, centerZ + radius] is owned by the current ticking region. ++ * @param world Specified world. ++ * @param chunkX Specified x-coordinate of the chunk position. ++ * @param chunkZ Specified z-coordinate of the chunk position. ++ * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared ++ * radius, but rather a Chebyshev Distance. ++ */ ++ public static boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ, int squareRadiusChunks) { ++ return server.isOwnedByCurrentRegion(world, chunkX, chunkZ, squareRadiusChunks); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunks in the rectangle specified by the min and max parameters. ++ * Specifically, this function checks that every chunk with position x in [minChunkX, maxChunkX] and ++ * position z in [minChunkZ, maxChunkZ] is owned by the current ticking region. ++ * @param world Specified world. ++ * @param minChunkX Specified x-coordinate of the minimum chunk position. ++ * @param minChunkZ Specified z-coordinate of the minimum chunk position. ++ * @param maxChunkX Specified x-coordinate of the maximum chunk position. ++ * @param maxChunkZ Specified z-coordinate of the maximum chunk position. ++ */ ++ public static boolean isOwnedByCurrentRegion(@NotNull World world, int minChunkX, int minChunkZ, int maxChunkX, int maxChunkZ) { ++ return server.isOwnedByCurrentRegion(world, minChunkX, minChunkZ, maxChunkX, maxChunkZ); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the specified entity. Note that this function is the only appropriate method of checking ++ * for ownership of an entity, as retrieving the entity's location is undefined unless the entity is owned ++ * by the current region. ++ * @param entity Specified entity. ++ */ ++ public static boolean isOwnedByCurrentRegion(@NotNull Entity entity) { ++ return server.isOwnedByCurrentRegion(entity); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking the global region. ++ * @see io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler ++ */ ++ public static boolean isGlobalTickThread() { ++ return server.isGlobalTickThread(); ++ } ++ // Paper end - Folia region threading API ++ + @NotNull + public static Server.Spigot spigot() { + return server.spigot(); +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 3f21dfaaa8a6575c9f9b0d33b60fb9913fec8987..d05ea34d8f58b475628157a7bd2ba0143e9a6c36 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2351,4 +2351,138 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + @NotNull org.bukkit.potion.PotionBrewer getPotionBrewer(); + // Paper end ++ ++ // Paper start - Folia region threading API ++ /** ++ * Returns the Folia region task scheduler. The region task scheduler can be used to schedule ++ * tasks by location to be executed on the region which owns the location. ++ *

      ++ * Note: It is entirely inappropriate to use the region scheduler to schedule tasks for entities. ++ * If you wish to schedule tasks to perform actions on entities, you should be using {@link Entity#getScheduler()} ++ * as the entity scheduler will "follow" an entity if it is teleported, whereas the region task scheduler ++ * will not. ++ *

      ++ *

      If you do not need/want to make your plugin run on Folia, use {@link #getScheduler()} instead.

      ++ * @return the region task scheduler ++ */ ++ @NotNull io.papermc.paper.threadedregions.scheduler.RegionScheduler getRegionScheduler(); ++ ++ /** ++ * Returns the Folia async task scheduler. The async task scheduler can be used to schedule tasks ++ * that execute asynchronously from the server tick process. ++ * @return the async task scheduler ++ */ ++ @NotNull io.papermc.paper.threadedregions.scheduler.AsyncScheduler getAsyncScheduler(); ++ ++ /** ++ * Returns the Folia global region task scheduler. The global task scheduler can be used to schedule ++ * tasks to execute on the global region. ++ *

      ++ * The global region is responsible for maintaining world day time, world game time, weather cycle, ++ * sleep night skipping, executing commands for console, and other misc. tasks that do not belong to any specific region. ++ *

      ++ *

      If you do not need/want to make your plugin run on Folia, use {@link #getScheduler()} instead.

      ++ * @return the global region scheduler ++ */ ++ @NotNull io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler getGlobalRegionScheduler(); ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunk at the specified world and block position. ++ * @param world Specified world. ++ * @param position Specified block position. ++ */ ++ boolean isOwnedByCurrentRegion(@NotNull World world, @NotNull io.papermc.paper.math.Position position); ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunks centered at the specified block position within the specified square radius. ++ * Specifically, this function checks that every chunk with position x in [centerX - radius, centerX + radius] and ++ * position z in [centerZ - radius, centerZ + radius] is owned by the current ticking region. ++ * @param world Specified world. ++ * @param position Specified block position. ++ * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared ++ * radius, but rather a Chebyshev Distance. ++ */ ++ boolean isOwnedByCurrentRegion(@NotNull World world, @NotNull io.papermc.paper.math.Position position, int squareRadiusChunks); ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunk at the specified world and block position as included in the specified location. ++ * @param location Specified location, must have a non-null world. ++ */ ++ boolean isOwnedByCurrentRegion(@NotNull Location location); ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunks centered at the specified world and block position as included in the specified location ++ * within the specified square radius. ++ * Specifically, this function checks that every chunk with position x in [centerX - radius, centerX + radius] and ++ * position z in [centerZ - radius, centerZ + radius] is owned by the current ticking region. ++ * @param location Specified location, must have a non-null world. ++ * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared ++ * radius, but rather a Chebyshev Distance. ++ */ ++ boolean isOwnedByCurrentRegion(@NotNull Location location, int squareRadiusChunks); ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunk at the specified block position. ++ * @param block Specified block position. ++ */ ++ default boolean isOwnedByCurrentRegion(@NotNull org.bukkit.block.Block block) { ++ return isOwnedByCurrentRegion(block.getLocation()); ++ } ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunk at the specified world and chunk position. ++ * @param world Specified world. ++ * @param chunkX Specified x-coordinate of the chunk position. ++ * @param chunkZ Specified z-coordinate of the chunk position. ++ */ ++ boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ); ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunks centered at the specified world and chunk position within the specified ++ * square radius. ++ * Specifically, this function checks that every chunk with position x in [centerX - radius, centerX + radius] and ++ * position z in [centerZ - radius, centerZ + radius] is owned by the current ticking region. ++ * @param world Specified world. ++ * @param chunkX Specified x-coordinate of the chunk position. ++ * @param chunkZ Specified z-coordinate of the chunk position. ++ * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared ++ * radius, but rather a Chebyshev Distance. ++ */ ++ boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ, int squareRadiusChunks); ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the chunks in the rectangle specified by the min and max parameters. ++ * Specifically, this function checks that every chunk with position x in [minChunkX, maxChunkX] and ++ * position z in [minChunkZ, maxChunkZ] is owned by the current ticking region. ++ * @param world Specified world. ++ * @param minChunkX Specified x-coordinate of the minimum chunk position. ++ * @param minChunkZ Specified z-coordinate of the minimum chunk position. ++ * @param maxChunkX Specified x-coordinate of the maximum chunk position. ++ * @param maxChunkZ Specified z-coordinate of the maximum chunk position. ++ */ ++ boolean isOwnedByCurrentRegion(@NotNull World world, int minChunkX, int minChunkZ, int maxChunkX, int maxChunkZ); ++ ++ /** ++ * Returns whether the current thread is ticking a region and that the region being ticked ++ * owns the specified entity. Note that this function is the only appropriate method of checking ++ * for ownership of an entity, as retrieving the entity's location is undefined unless the entity is owned ++ * by the current region. ++ * @param entity Specified entity. ++ */ ++ boolean isOwnedByCurrentRegion(@NotNull Entity entity); ++ ++ /** ++ * Returns whether the current thread is ticking the global region. ++ * @see io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler ++ */ ++ public boolean isGlobalTickThread(); ++ // Paper end - Folia region threading API + } +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 0ca7cb73c4007647841ed6a78c8949fcc3ed97ff..e196b66c02b5ba9ca35df804182f9b7ab4f7b45c 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -1101,4 +1101,15 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + boolean wouldCollideUsing(@NotNull BoundingBox boundingBox); + // Paper end - Collision API ++ ++ // Paper start - Folia schedulers ++ /** ++ * Returns the task scheduler for this entity. The entity scheduler can be used to schedule tasks ++ * that are guaranteed to always execute on the tick thread that owns the entity. ++ *

      If you do not need/want to make your plugin run on Folia, use {@link org.bukkit.Server#getScheduler()} instead.

      ++ * @return the task scheduler for this entity. ++ * @see io.papermc.paper.threadedregions.scheduler.EntityScheduler ++ */ ++ @NotNull io.papermc.paper.threadedregions.scheduler.EntityScheduler getScheduler(); ++ // Paper end - Folia schedulers + } diff --git a/patches/api/0395-Add-event-for-player-editing-sign.patch b/patches/api/0395-Add-event-for-player-editing-sign.patch new file mode 100644 index 000000000000..c0b95f9d58e6 --- /dev/null +++ b/patches/api/0395-Add-event-for-player-editing-sign.patch @@ -0,0 +1,132 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: by77er +Date: Sat, 10 Jun 2023 19:06:24 -0400 +Subject: [PATCH] Add event for player editing sign + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerOpenSignEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerOpenSignEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0b905aafe5b228993944af1850c93c797f6eaf47 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerOpenSignEvent.java +@@ -0,0 +1,105 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.block.Sign; ++import org.bukkit.block.sign.Side; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when a player begins editing a sign's text. ++ *

      ++ * Cancelling this event stops the sign editing menu from opening. ++ */ ++@NullMarked ++public class PlayerOpenSignEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Sign sign; ++ private final Side side; ++ private final Cause cause; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerOpenSignEvent(final Player editor, final Sign sign, final Side side, final Cause cause) { ++ super(editor); ++ this.sign = sign; ++ this.side = side; ++ this.cause = cause; ++ } ++ ++ /** ++ * Gets the sign that was clicked. ++ * ++ * @return {@link Sign} that was clicked ++ */ ++ public Sign getSign() { ++ return this.sign; ++ } ++ ++ /** ++ * Gets which side of the sign was clicked. ++ * ++ * @return {@link Side} that was clicked ++ * @see Sign#getSide(Side) ++ */ ++ public Side getSide() { ++ return this.side; ++ } ++ ++ /** ++ * The cause of this sign open. ++ * ++ * @return the cause ++ */ ++ public Cause getCause() { ++ return this.cause; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ /** ++ * The cause of the {@link PlayerOpenSignEvent}. ++ */ ++ public enum Cause { ++ /** ++ * The event was triggered by the placement of a sign. ++ */ ++ PLACE, ++ /** ++ * The event was triggered by an interaction with a sign. ++ */ ++ INTERACT, ++ /** ++ * The event was triggered via a plugin with {@link HumanEntity#openSign(Sign, Side)} ++ */ ++ PLUGIN, ++ /** ++ * Fallback cause for any unknown cause. ++ */ ++ UNKNOWN, ++ } ++} +diff --git a/src/main/java/org/bukkit/event/player/PlayerSignOpenEvent.java b/src/main/java/org/bukkit/event/player/PlayerSignOpenEvent.java +index cf935d9c8d8f9a9684024507846a9754f0207986..72fe69c3830f07dd264cfd89e92410dc107034a4 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerSignOpenEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerSignOpenEvent.java +@@ -9,7 +9,10 @@ import org.jetbrains.annotations.NotNull; + + /** + * This event is fired when a sign is opened by the player. ++ * @deprecated use {@link io.papermc.paper.event.player.PlayerOpenSignEvent} + */ ++@Deprecated(forRemoval = true) // Paper ++@org.bukkit.Warning(false) // Paper + public class PlayerSignOpenEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); diff --git a/patches/api/0396-More-Sign-Block-API.patch b/patches/api/0396-More-Sign-Block-API.patch new file mode 100644 index 000000000000..d01d6037166f --- /dev/null +++ b/patches/api/0396-More-Sign-Block-API.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 23 Jun 2023 12:16:35 -0700 +Subject: [PATCH] More Sign Block API + +Co-authored-by: SoSeDiK + +diff --git a/src/main/java/org/bukkit/block/Sign.java b/src/main/java/org/bukkit/block/Sign.java +index be36f722c7e465fae09ae7c99d92bfa032b66cc3..859217e0109beb555e2357d806be96b53471955d 100644 +--- a/src/main/java/org/bukkit/block/Sign.java ++++ b/src/main/java/org/bukkit/block/Sign.java +@@ -182,9 +182,58 @@ public interface Sign extends TileState, Colorable { + /** + * Gets the player that is currently allowed to edit this sign.
      + * Edits from other players will be rejected if this value is not null. ++ *

      You should prefer {@link #getAllowedEditorUniqueId()} if you don't ++ * need the player instance as this method will fetch the player from UUID. + * + * @return the player allowed to edit this sign, or null + */ + @Nullable + public Player getAllowedEditor(); ++ // Paper start - More Sign Block API ++ /** ++ * Gets the allowed editor's UUID. ++ *
      Edits from other players will be rejected if this value is not null. ++ * ++ * @return the allowed editor's UUID, or null ++ */ ++ @Nullable java.util.UUID getAllowedEditorUniqueId(); ++ ++ /** ++ * Sets the allowed editor's UUID. ++ *

      Note: the server sets the UUID back to null if the player can't ++ * interact with the sign (is either offline or outside the allowed interaction range). ++ * ++ * @param uuid the allowed editor's UUID ++ */ ++ void setAllowedEditorUniqueId(@Nullable java.util.UUID uuid); ++ ++ /** ++ * Compute the side facing the specified entity. ++ * ++ * @param entity the entity ++ * @return the side it is facing ++ */ ++ default @NotNull Side getInteractableSideFor(org.bukkit.entity.@NotNull Entity entity) { ++ return this.getInteractableSideFor(entity.getLocation()); ++ } ++ ++ /** ++ * Compute the side facing the specific position. ++ * ++ * @param position the position ++ * @return the side the position is facing ++ */ ++ default @NotNull Side getInteractableSideFor(io.papermc.paper.math.@NotNull Position position) { ++ return this.getInteractableSideFor(position.x(), position.z()); ++ } ++ ++ /** ++ * Compute the side facing the specific x and z coordinates. ++ * ++ * @param x the x coord ++ * @param z the z coord ++ * @return the side the coordinates are facing ++ */ ++ @NotNull Side getInteractableSideFor(double x, double z); ++ // Paper end - More Sign Block API + } diff --git a/patches/api/0397-Fix-BanList-API.patch b/patches/api/0397-Fix-BanList-API.patch new file mode 100644 index 000000000000..c09a61d37417 --- /dev/null +++ b/patches/api/0397-Fix-BanList-API.patch @@ -0,0 +1,162 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 4 Jul 2023 11:27:18 -0700 +Subject: [PATCH] Fix BanList API + + +diff --git a/src/main/java/org/bukkit/BanList.java b/src/main/java/org/bukkit/BanList.java +index 5829aca9e5aa700bd95f19db3ae032100f74d5a3..60aea29d51a8ad499401f94a7c326d9b415b6a3a 100644 +--- a/src/main/java/org/bukkit/BanList.java ++++ b/src/main/java/org/bukkit/BanList.java +@@ -48,7 +48,7 @@ public interface BanList { + */ + @Deprecated(since = "1.20.1") + @Nullable +- public BanEntry getBanEntry(@NotNull String target); ++ public > E getBanEntry(@NotNull String target); // Paper + + /** + * Gets a {@link BanEntry} by target. +@@ -77,7 +77,7 @@ public interface BanList { + */ + @Deprecated(since = "1.20.1") + @Nullable +- public BanEntry addBan(@NotNull String target, @Nullable String reason, @Nullable Date expires, @Nullable String source); ++ public > E addBan(@NotNull String target, @Nullable String reason, @Nullable Date expires, @Nullable String source); // Paper + + /** + * Adds a ban to this list. If a previous ban exists, this will +@@ -140,7 +140,7 @@ public interface BanList { + * @return an immutable set containing every entry tracked by this list + */ + @NotNull +- public Set> getEntries(); ++ public > Set getEntries(); // Paper + + /** + * Gets if a {@link BanEntry} exists for the target, indicating an active +diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java +index 9facde856fa9b1b8f2a6198a1b541b819ea12518..a8003b4796b3f80986043a9dbc2e6ad08a1bb4d7 100644 +--- a/src/main/java/org/bukkit/OfflinePlayer.java ++++ b/src/main/java/org/bukkit/OfflinePlayer.java +@@ -147,7 +147,7 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio + * (updated) previous ban + */ + @Nullable +- public BanEntry ban(@Nullable String reason, @Nullable Date expires, @Nullable String source); ++ public > E ban(@Nullable String reason, @Nullable Date expires, @Nullable String source); // Paper - fix ban list API + + /** + * Adds this user to the {@link ProfileBanList}. If a previous ban exists, this will +@@ -161,7 +161,7 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio + * (updated) previous ban + */ + @Nullable +- public BanEntry ban(@Nullable String reason, @Nullable Instant expires, @Nullable String source); ++ public > E ban(@Nullable String reason, @Nullable Instant expires, @Nullable String source); // Paper - fix ban list API + + /** + * Adds this user to the {@link ProfileBanList}. If a previous ban exists, this will +@@ -175,7 +175,7 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio + * (updated) previous ban + */ + @Nullable +- public BanEntry ban(@Nullable String reason, @Nullable Duration duration, @Nullable String source); ++ public > E ban(@Nullable String reason, @Nullable Duration duration, @Nullable String source); // Paper - fix ban list API + + /** + * Checks if this player is whitelisted or not +diff --git a/src/main/java/org/bukkit/ban/ProfileBanList.java b/src/main/java/org/bukkit/ban/ProfileBanList.java +index e805e629cede1c4c0674282c930cb67852718c3e..5248cf08ef83c7304dd76c42a2f646bb81e0efae 100644 +--- a/src/main/java/org/bukkit/ban/ProfileBanList.java ++++ b/src/main/java/org/bukkit/ban/ProfileBanList.java +@@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable; + /** + * A {@link BanList} targeting player profile bans. + */ +-public interface ProfileBanList extends BanList { ++public interface ProfileBanList extends BanList { // Paper + + /** + * {@inheritDoc} +@@ -23,8 +23,48 @@ public interface ProfileBanList extends BanList { + * @return the entry for the newly created ban, or the entry for the + * (updated) previous ban + * @throws IllegalArgumentException if ProfilePlayer has an invalid UUID ++ * @deprecated use {@link #addBan(com.destroystokyo.paper.profile.PlayerProfile, String, Date, String)} + */ + @Nullable +- public BanEntry addBan(@NotNull PlayerProfile target, @Nullable String reason, @Nullable Date expires, @Nullable String source); ++ // Paper start ++ @Deprecated ++ public > E addBan(@NotNull PlayerProfile target, @Nullable String reason, @Nullable Date expires, @Nullable String source); + ++ /** ++ * @throws IllegalArgumentException if ProfilePlayer has an invalid UUID ++ */ ++ @Nullable BanEntry addBan(com.destroystokyo.paper.profile.@NotNull PlayerProfile target, @Nullable String reason, @Nullable Date expires, @Nullable String source); ++ ++ // the 5 methods below are added to maintain compat for the bukkit.PlayerProfile parameter type ++ /** ++ * @deprecated use {@link #getBanEntry(Object)} ++ */ ++ @Deprecated ++ @Nullable > E getBanEntry(@NotNull PlayerProfile target); ++ ++ /** ++ * @deprecated use {@link #isBanned(Object)} ++ */ ++ @Deprecated ++ boolean isBanned(@NotNull PlayerProfile target); ++ ++ /** ++ * @deprecated use {@link #pardon(Object)} ++ */ ++ @Deprecated ++ void pardon(@NotNull PlayerProfile target); ++ ++ /** ++ * @deprecated use {@link #addBan(Object, String, java.time.Instant, String)} ++ */ ++ @Deprecated ++ @Nullable > E addBan(@NotNull PlayerProfile target, @Nullable String reason, @Nullable java.time.Instant expires, @Nullable String source); ++ ++ /** ++ * @deprecated use {@link #addBan(Object, String, java.time.Duration, String)} ++ */ ++ @Deprecated ++ @Nullable > E addBan(@NotNull PlayerProfile target, @Nullable String reason, @Nullable java.time.Duration duration, @Nullable String source); ++ ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index c2d49ff3aee971598451734f95144ac5dbbf131a..ad8e53bc528f6a078c85962fb85956bd97d67703 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -359,7 +359,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * (updated) previous ban + */ + @Nullable +- public BanEntry ban(@Nullable String reason, @Nullable Date expires, @Nullable String source, boolean kickPlayer); ++ public > E ban(@Nullable String reason, @Nullable Date expires, @Nullable String source, boolean kickPlayer); // Paper - fix ban list API + + /** + * Adds this user to the {@link ProfileBanList}. If a previous ban exists, this will +@@ -375,7 +375,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * (updated) previous ban + */ + @Nullable +- public BanEntry ban(@Nullable String reason, @Nullable Instant expires, @Nullable String source, boolean kickPlayer); ++ public > E ban(@Nullable String reason, @Nullable Instant expires, @Nullable String source, boolean kickPlayer); // Paper - fix ban list API + + /** + * Adds this user to the {@link ProfileBanList}. If a previous ban exists, this will +@@ -391,7 +391,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * (updated) previous ban + */ + @Nullable +- public BanEntry ban(@Nullable String reason, @Nullable Duration duration, @Nullable String source, boolean kickPlayer); ++ public > E ban(@Nullable String reason, @Nullable Duration duration, @Nullable String source, boolean kickPlayer); // Paper - fix ban list API + + /** + * Adds this user's current IP address to the {@link IpBanList}. If a previous ban exists, this will diff --git a/patches/api/0398-Add-whitelist-events.patch b/patches/api/0398-Add-whitelist-events.patch new file mode 100644 index 000000000000..3f768a812431 --- /dev/null +++ b/patches/api/0398-Add-whitelist-events.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SageSphinx63920 +Date: Sun, 14 May 2023 12:56:15 +0200 +Subject: [PATCH] Add whitelist events + + +diff --git a/src/main/java/io/papermc/paper/event/server/WhitelistStateUpdateEvent.java b/src/main/java/io/papermc/paper/event/server/WhitelistStateUpdateEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ff8c2c74fc68b1dd564e07c938b28b5950871533 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/server/WhitelistStateUpdateEvent.java +@@ -0,0 +1,83 @@ ++package io.papermc.paper.event.server; ++ ++import com.destroystokyo.paper.profile.PlayerProfile; ++import org.bukkit.Bukkit; ++import org.bukkit.OfflinePlayer; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * This event gets called when the whitelist status of a player is changed ++ */ ++@NullMarked ++public class WhitelistStateUpdateEvent extends Event implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final PlayerProfile playerProfile; ++ private final WhitelistStatus status; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public WhitelistStateUpdateEvent(final PlayerProfile playerProfile, final WhitelistStatus status) { ++ this.playerProfile = playerProfile; ++ this.status = status; ++ } ++ ++ /** ++ * Gets the player whose whitelist status is being changed ++ * ++ * @return the player whose status is being changed ++ */ ++ public OfflinePlayer getPlayer() { ++ return Bukkit.getOfflinePlayer(this.playerProfile.getId()); ++ } ++ ++ /** ++ * Gets the player profile whose whitelist status is being changed ++ * ++ * @return the player profile whose status is being changed ++ */ ++ public PlayerProfile getPlayerProfile() { ++ return this.playerProfile; ++ } ++ ++ /** ++ * Gets the status change of the player profile ++ * ++ * @return the whitelist status ++ */ ++ public WhitelistStatus getStatus() { ++ return this.status; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ /** ++ * Enum for the whitelist status changes ++ */ ++ public enum WhitelistStatus { ++ ADDED, REMOVED ++ } ++} diff --git a/patches/api/0399-API-for-updating-recipes-on-clients.patch b/patches/api/0399-API-for-updating-recipes-on-clients.patch new file mode 100644 index 000000000000..68ba48ebf46d --- /dev/null +++ b/patches/api/0399-API-for-updating-recipes-on-clients.patch @@ -0,0 +1,169 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 21 Aug 2021 17:25:54 -0700 +Subject: [PATCH] API for updating recipes on clients + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 5170f7ba71d8a09f2b4ae0d945c758fd4ae4130f..886c1aab96bd34739665c22793217f3f41ba92d0 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -1004,6 +1004,26 @@ public final class Bukkit { + server.reloadData(); + } + ++ // Paper start - update reloadable data ++ /** ++ * Updates all advancement, tag, and recipe data for all connected clients. ++ * Useful for updating clients to new advancements/recipes/tags. ++ * @see #updateRecipes() ++ */ ++ public static void updateResources() { ++ server.updateResources(); ++ } ++ ++ /** ++ * Updates recipe data and the recipe book for all connected clients. Useful for ++ * updating clients to new recipes. ++ * @see #updateResources() ++ */ ++ public static void updateRecipes() { ++ server.updateRecipes(); ++ } ++ // Paper end - update reloadable data ++ + /** + * Returns the primary logger associated with this server instance. + * +@@ -1064,6 +1084,20 @@ public final class Bukkit { + return server.addRecipe(recipe); + } + ++ // Paper start - method to send recipes immediately ++ /** ++ * Adds a recipe to the crafting manager. ++ * ++ * @param recipe the recipe to add ++ * @param resendRecipes true to update the client with the full set of recipes ++ * @return true if the recipe was added, false if it wasn't for some reason ++ */ ++ @Contract("null, _ -> false") ++ public static boolean addRecipe(@Nullable Recipe recipe, boolean resendRecipes) { ++ return server.addRecipe(recipe, resendRecipes); ++ } ++ // Paper end - method to send recipes immediately ++ + /** + * Get a list of all recipes for a given item. The stack size is ignored + * in comparisons. If the durability is -1, it will match any data value. +@@ -1255,6 +1289,24 @@ public final class Bukkit { + return server.removeRecipe(key); + } + ++ // Paper start - method to resend recipes ++ /** ++ * Remove a recipe from the server. ++ *

      ++ * Note that removing a recipe may cause permanent loss of data ++ * associated with that recipe (eg whether it has been discovered by ++ * players). ++ * ++ * @param key NamespacedKey of recipe to remove. ++ * @param resendRecipes true to update all clients on the new recipe list. ++ * Will only update if a recipe was actually removed ++ * @return True if recipe was removed ++ */ ++ public static boolean removeRecipe(@NotNull NamespacedKey key, boolean resendRecipes) { ++ return server.removeRecipe(key, resendRecipes); ++ } ++ // Paper end - method to resend recipes ++ + /** + * Gets a list of command aliases defined in the server properties. + * +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index d05ea34d8f58b475628157a7bd2ba0143e9a6c36..897d659e45d1a32c1bdaf8e0941f00597261a0b9 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -853,6 +853,22 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + public void reloadData(); + ++ // Paper start - update reloadable data ++ /** ++ * Updates all advancement, tag, and recipe data to all connected clients. ++ * Useful for updating clients to new advancements/recipes/tags. ++ * @see #updateRecipes() ++ */ ++ void updateResources(); ++ ++ /** ++ * Updates recipe data and the recipe book to each player. Useful for ++ * updating clients to new recipes. ++ * @see #updateResources() ++ */ ++ void updateRecipes(); ++ // Paper end - update reloadable data ++ + /** + * Returns the primary logger associated with this server instance. + * +@@ -894,15 +910,34 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + public boolean dispatchCommand(@NotNull CommandSender sender, @NotNull String commandLine) throws CommandException; + + /** +- * Adds a recipe to the crafting manager. ++ * Adds a recipe to the crafting manager. Recipes added with ++ * this method won't be sent to the client automatically. Use ++ * {@link #updateRecipes()} or {@link #updateResources()} to ++ * update clients to new recipes added. ++ *

      ++ * Player's still have to discover recipes via {@link Player#discoverRecipe(NamespacedKey)} ++ * before seeing them in their recipe book. + * + * @param recipe the recipe to add + * @return true if the recipe was added, false if it wasn't for some + * reason ++ * @see #addRecipe(Recipe, boolean) + */ + @Contract("null -> false") + public boolean addRecipe(@Nullable Recipe recipe); + ++ // Paper start - method to send recipes immediately ++ /** ++ * Adds a recipe to the crafting manager. ++ * ++ * @param recipe the recipe to add ++ * @param resendRecipes true to update the client with the full set of recipes ++ * @return true if the recipe was added, false if it wasn't for some reason ++ */ ++ @Contract("null, _ -> false") ++ boolean addRecipe(@Nullable Recipe recipe, boolean resendRecipes); ++ // Paper end - method to send recipes immediately ++ + /** + * Get a list of all recipes for a given item. The stack size is ignored + * in comparisons. If the durability is -1, it will match any data value. +@@ -1071,6 +1106,22 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + public boolean removeRecipe(@NotNull NamespacedKey key); + ++ // Paper start - method to resend recipes ++ /** ++ * Remove a recipe from the server. ++ *

      ++ * Note that removing a recipe may cause permanent loss of data ++ * associated with that recipe (eg whether it has been discovered by ++ * players). ++ * ++ * @param key NamespacedKey of recipe to remove. ++ * @param resendRecipes true to update all clients on the new recipe list. ++ * Will only update if a recipe was actually removed ++ * @return True if recipe was removed ++ */ ++ boolean removeRecipe(@NotNull NamespacedKey key, boolean resendRecipes); ++ // Paper end - method to resend recipes ++ + /** + * Gets a list of command aliases defined in the server properties. + * diff --git a/patches/api/0400-Add-PlayerFailMoveEvent.patch b/patches/api/0400-Add-PlayerFailMoveEvent.patch new file mode 100644 index 000000000000..e6903a2b56b6 --- /dev/null +++ b/patches/api/0400-Add-PlayerFailMoveEvent.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Moulberry +Date: Wed, 26 Jul 2023 20:57:11 +0800 +Subject: [PATCH] Add PlayerFailMoveEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerFailMoveEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerFailMoveEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c7380874f99cd2aa28a24bbb0dd3375e8842dd0d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerFailMoveEvent.java +@@ -0,0 +1,113 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.Location; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Runs when a player attempts to move, but is prevented from doing so by the server ++ */ ++@NullMarked ++public class PlayerFailMoveEvent extends PlayerEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final FailReason failReason; ++ private final Location from; ++ private final Location to; ++ private boolean allowed; ++ private boolean logWarning; ++ ++ @ApiStatus.Internal ++ public PlayerFailMoveEvent(final Player player, final FailReason failReason, final boolean allowed, final boolean logWarning, final Location from, final Location to) { ++ super(player); ++ this.failReason = failReason; ++ this.allowed = allowed; ++ this.logWarning = logWarning; ++ this.from = from; ++ this.to = to; ++ } ++ ++ /** ++ * Gets the reason this movement was prevented by the server ++ * ++ * @return The reason the movement was prevented ++ */ ++ public FailReason getFailReason() { ++ return this.failReason; ++ } ++ ++ /** ++ * Gets the location this player moved from ++ * ++ * @return Location the player moved from ++ */ ++ public Location getFrom() { ++ return this.from.clone(); ++ } ++ ++ /** ++ * Gets the location this player tried to move to ++ * ++ * @return Location the player tried to move to ++ */ ++ public Location getTo() { ++ return this.to.clone(); ++ } ++ ++ /** ++ * Gets if the check should be bypassed, allowing the movement ++ * ++ * @return whether to bypass the check ++ */ ++ public boolean isAllowed() { ++ return this.allowed; ++ } ++ ++ /** ++ * Set if the check should be bypassed and the movement should be allowed ++ * ++ * @param allowed whether to bypass the check ++ */ ++ public void setAllowed(final boolean allowed) { ++ this.allowed = allowed; ++ } ++ ++ /** ++ * Gets if warnings will be printed to console. e.g. "Player123 moved too quickly!" ++ * ++ * @return whether to log warnings ++ */ ++ public boolean getLogWarning() { ++ return this.logWarning; ++ } ++ ++ /** ++ * Set if a warning is printed to console. e.g. "Player123 moved too quickly!" ++ * ++ * @param logWarning whether to log warnings ++ */ ++ public void setLogWarning(final boolean logWarning) { ++ this.logWarning = logWarning; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++ ++ public enum FailReason { ++ MOVED_INTO_UNLOADED_CHUNK, // Only fired if the world setting prevent-moving-into-unloaded-chunks is true ++ MOVED_TOO_QUICKLY, ++ MOVED_WRONGLY, ++ CLIPPED_INTO_BLOCK ++ } ++ ++} diff --git a/patches/api/0401-Fix-custom-statistic-criteria-creation.patch b/patches/api/0401-Fix-custom-statistic-criteria-creation.patch new file mode 100644 index 000000000000..06e1015bba8a --- /dev/null +++ b/patches/api/0401-Fix-custom-statistic-criteria-creation.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Sat, 12 Aug 2023 15:33:55 +0200 +Subject: [PATCH] Fix custom statistic criteria creation + + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 3328ae3bab6b4929506a518d6426b81594b1b300..8e0877321edb26e1dbdb3570a62814d06c0616af 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -256,4 +256,6 @@ public interface UnsafeValues { + @Deprecated(since = "1.21.3", forRemoval = true) + void setBiomeKey(RegionAccessor accessor, int x, int y, int z, NamespacedKey biomeKey); + // Paper end - namespaced key biome methods ++ ++ String getStatisticCriteriaKey(@NotNull org.bukkit.Statistic statistic); // Paper - fix custom stats criteria creation + } +diff --git a/src/main/java/org/bukkit/scoreboard/Criteria.java b/src/main/java/org/bukkit/scoreboard/Criteria.java +index 7d79d7fadab19bfbefc4797d7e5bbd3e9d733b53..3bc3abaf093d13e22b6ac2ee59ab584c92b4666a 100644 +--- a/src/main/java/org/bukkit/scoreboard/Criteria.java ++++ b/src/main/java/org/bukkit/scoreboard/Criteria.java +@@ -335,7 +335,7 @@ public interface Criteria { + @NotNull + public static Criteria statistic(@NotNull Statistic statistic) { + Preconditions.checkArgument(statistic != null, "statistic must not be null"); +- return Bukkit.getScoreboardCriteria("minecraft.custom:minecraft." + statistic.getKey().getKey()); ++ return Bukkit.getScoreboardCriteria(org.bukkit.Bukkit.getUnsafe().getStatisticCriteriaKey(statistic)); // Paper + } + + /** diff --git a/patches/api/0402-SculkCatalyst-bloom-API.patch b/patches/api/0402-SculkCatalyst-bloom-API.patch new file mode 100644 index 000000000000..49d8c8c2bdb0 --- /dev/null +++ b/patches/api/0402-SculkCatalyst-bloom-API.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Oliwier Miodun +Date: Mon, 10 Jul 2023 17:59:42 +0200 +Subject: [PATCH] SculkCatalyst bloom API + + +diff --git a/src/main/java/org/bukkit/block/SculkCatalyst.java b/src/main/java/org/bukkit/block/SculkCatalyst.java +index 46260df8938bb616dd0e26829a123a24736b0a70..7d53b24003d49c5d7623598e92a6b0603c5d3069 100644 +--- a/src/main/java/org/bukkit/block/SculkCatalyst.java ++++ b/src/main/java/org/bukkit/block/SculkCatalyst.java +@@ -24,4 +24,14 @@ public interface SculkCatalyst extends TileState { + * @param charges how much charge to spawn. + */ + void bloom(@NotNull Block block, int charges); ++ ++ // Paper start - SculkCatalyst bloom API ++ /** ++ * Bloom at the specified location as if an entity that drops experience just died there. ++ * ++ * @param position position to bloom at ++ * @param charge charge to bloom with, normally the amount of experience dropped from the dead entity ++ */ ++ void bloom(@org.jetbrains.annotations.NotNull io.papermc.paper.math.Position position, int charge); ++ // Paper end - SculkCatalyst bloom API + } diff --git a/patches/api/0403-API-for-an-entity-s-scoreboard-name.patch b/patches/api/0403-API-for-an-entity-s-scoreboard-name.patch new file mode 100644 index 000000000000..c7f79f623584 --- /dev/null +++ b/patches/api/0403-API-for-an-entity-s-scoreboard-name.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 9 Jul 2023 11:54:54 -0700 +Subject: [PATCH] API for an entity's scoreboard name + +Was obtainable through different methods, but you had to use different +methods depending on the implementation of Entity you were working with. + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index e196b66c02b5ba9ca35df804182f9b7ab4f7b45c..ee5a27ba09ec4100dbedab4f190cf74549ce858e 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -1112,4 +1112,15 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + @NotNull io.papermc.paper.threadedregions.scheduler.EntityScheduler getScheduler(); + // Paper end - Folia schedulers ++ ++ // Paper start - entity scoreboard name ++ /** ++ * Gets the string name of the entity used to track it in {@link org.bukkit.scoreboard.Scoreboard Scoreboards}. ++ * ++ * @return the scoreboard entry name ++ * @see org.bukkit.scoreboard.Scoreboard#getScores(String) ++ * @see org.bukkit.scoreboard.Scoreboard#getEntries() ++ */ ++ @NotNull String getScoreboardEntryName(); ++ // Paper end - entity scoreboard name + } diff --git a/patches/api/0404-Deprecate-and-replace-methods-with-old-StructureType.patch b/patches/api/0404-Deprecate-and-replace-methods-with-old-StructureType.patch new file mode 100644 index 000000000000..5edb856e1995 --- /dev/null +++ b/patches/api/0404-Deprecate-and-replace-methods-with-old-StructureType.patch @@ -0,0 +1,159 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 10 Dec 2022 17:52:45 -0800 +Subject: [PATCH] Deprecate and replace methods with old StructureType + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 886c1aab96bd34739665c22793217f3f41ba92d0..c3c76dd82b209f6720afc51622aeb3fd92f1c0c2 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -949,9 +949,6 @@ public final class Bukkit { + /** + * Create a new explorer map targeting the closest nearby structure of a + * given {@link StructureType}. +- *
      +- * This method uses implementation default values for radius and +- * findUnexplored (usually 100, true). + * + * @param world the world the map will belong to + * @param location the origin location to find the nearest structure +@@ -960,7 +957,9 @@ public final class Bukkit { + * + * @see World#locateNearestStructure(org.bukkit.Location, + * org.bukkit.StructureType, int, boolean) ++ * @deprecated use {@link #createExplorerMap(World, Location, org.bukkit.generator.structure.StructureType, org.bukkit.map.MapCursor.Type)} + */ ++ @Deprecated // Paper + @NotNull + public static ItemStack createExplorerMap(@NotNull World world, @NotNull Location location, @NotNull StructureType structureType) { + return server.createExplorerMap(world, location, structureType); +@@ -983,11 +982,54 @@ public final class Bukkit { + * + * @see World#locateNearestStructure(org.bukkit.Location, + * org.bukkit.StructureType, int, boolean) ++ * @deprecated use {@link #createExplorerMap(World, Location, org.bukkit.generator.structure.StructureType, org.bukkit.map.MapCursor.Type, int, boolean)} + */ ++ @Deprecated // Paper + @NotNull + public static ItemStack createExplorerMap(@NotNull World world, @NotNull Location location, @NotNull StructureType structureType, int radius, boolean findUnexplored) { + return server.createExplorerMap(world, location, structureType, radius, findUnexplored); + } ++ // Paper start ++ /** ++ * Create a new explorer map targeting the closest nearby structure of a ++ * given {@link org.bukkit.generator.structure.StructureType}. ++ *
      ++ * This method uses implementation default values for radius and ++ * findUnexplored (usually 100, true). ++ * ++ * @param world the world the map will belong to ++ * @param location the origin location to find the nearest structure ++ * @param structureType the type of structure to find ++ * @param mapIcon the map icon to use on the map ++ * @return a newly created item stack or null if it can't find a location ++ * ++ * @see World#locateNearestStructure(org.bukkit.Location, ++ * org.bukkit.generator.structure.StructureType, int, boolean) ++ */ ++ public static @Nullable ItemStack createExplorerMap(@NotNull World world, @NotNull Location location, @NotNull org.bukkit.generator.structure.StructureType structureType, @NotNull org.bukkit.map.MapCursor.Type mapIcon) { ++ return server.createExplorerMap(world, location, structureType, mapIcon); ++ } ++ ++ /** ++ * Create a new explorer map targeting the closest nearby structure of a ++ * given {@link org.bukkit.generator.structure.StructureType}. ++ * ++ * @param world the world the map will belong to ++ * @param location the origin location to find the nearest structure ++ * @param structureType the type of structure to find ++ * @param mapIcon the map icon to use on the map ++ * @param radius radius to search, see World#locateNearestStructure for more ++ * information ++ * @param findUnexplored whether to find unexplored structures ++ * @return the newly created item stack or null if it can't find a location ++ * ++ * @see World#locateNearestStructure(org.bukkit.Location, ++ * org.bukkit.generator.structure.StructureType, int, boolean) ++ */ ++ public static @Nullable ItemStack createExplorerMap(@NotNull World world, @NotNull Location location, @NotNull org.bukkit.generator.structure.StructureType structureType, @NotNull org.bukkit.map.MapCursor.Type mapIcon, int radius, boolean findUnexplored) { ++ return server.createExplorerMap(world, location, structureType, mapIcon, radius, findUnexplored); ++ } ++ // Paper end + + /** + * Reloads the server, refreshing settings and plugin information. +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 897d659e45d1a32c1bdaf8e0941f00597261a0b9..1b968953fdf470bff32122bd06c4f83f27b97383 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -817,16 +817,15 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * + * @see World#locateNearestStructure(org.bukkit.Location, + * org.bukkit.StructureType, int, boolean) ++ * @deprecated use {@link #createExplorerMap(World, Location, org.bukkit.generator.structure.StructureType, org.bukkit.map.MapCursor.Type)} + */ ++ @Deprecated // Paper + @NotNull + public ItemStack createExplorerMap(@NotNull World world, @NotNull Location location, @NotNull StructureType structureType); + + /** + * Create a new explorer map targeting the closest nearby structure of a + * given {@link StructureType}. +- *
      +- * This method uses implementation default values for radius and +- * findUnexplored (usually 100, true). + * + * @param world the world the map will belong to + * @param location the origin location to find the nearest structure +@@ -838,9 +837,50 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * + * @see World#locateNearestStructure(org.bukkit.Location, + * org.bukkit.StructureType, int, boolean) ++ * @deprecated use {@link #createExplorerMap(World, Location, org.bukkit.generator.structure.StructureType, org.bukkit.map.MapCursor.Type, int, boolean)} + */ ++ @Deprecated // Paper + @NotNull + public ItemStack createExplorerMap(@NotNull World world, @NotNull Location location, @NotNull StructureType structureType, int radius, boolean findUnexplored); ++ // Paper start ++ /** ++ * Create a new explorer map targeting the closest nearby structure of a ++ * given {@link org.bukkit.generator.structure.StructureType}. ++ *
      ++ * This method uses implementation default values for radius and ++ * findUnexplored (usually 100, true). ++ * ++ * @param world the world the map will belong to ++ * @param location the origin location to find the nearest structure ++ * @param structureType the type of structure to find ++ * @param mapIcon the map icon to use on the map ++ * @return a newly created item stack or null if it can't find a location ++ * ++ * @see World#locateNearestStructure(org.bukkit.Location, ++ * org.bukkit.generator.structure.StructureType, int, boolean) ++ */ ++ default @Nullable ItemStack createExplorerMap(@NotNull World world, @NotNull Location location, @NotNull org.bukkit.generator.structure.StructureType structureType, @NotNull org.bukkit.map.MapCursor.Type mapIcon) { ++ return this.createExplorerMap(world, location, structureType, mapIcon, 100, true); ++ } ++ ++ /** ++ * Create a new explorer map targeting the closest nearby structure of a ++ * given {@link org.bukkit.generator.structure.StructureType}. ++ * ++ * @param world the world the map will belong to ++ * @param location the origin location to find the nearest structure ++ * @param structureType the type of structure to find ++ * @param mapIcon the map icon to use on the map ++ * @param radius radius to search, see World#locateNearestStructure for more ++ * information ++ * @param findUnexplored whether to find unexplored structures ++ * @return the newly created item stack or null if it can't find a location ++ * ++ * @see World#locateNearestStructure(org.bukkit.Location, ++ * org.bukkit.generator.structure.StructureType, int, boolean) ++ */ ++ @Nullable ItemStack createExplorerMap(@NotNull World world, @NotNull Location location, @NotNull org.bukkit.generator.structure.StructureType structureType, @NotNull org.bukkit.map.MapCursor.Type mapIcon, int radius, boolean findUnexplored); ++ // Paper end + + /** + * Reloads the server, refreshing settings and plugin information. diff --git a/patches/api/0405-Add-Listing-API-for-Player.patch b/patches/api/0405-Add-Listing-API-for-Player.patch new file mode 100644 index 000000000000..bd09b03dc0c4 --- /dev/null +++ b/patches/api/0405-Add-Listing-API-for-Player.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Corey Shupe +Date: Wed, 11 Jan 2023 16:40:31 -0500 +Subject: [PATCH] Add Listing API for Player + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index ad8e53bc528f6a078c85962fb85956bd97d67703..094c2056f4124dbb1caa0a5e962933b653d950a9 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -2078,6 +2078,32 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + */ + public boolean canSee(@NotNull Entity entity); + ++ // Paper start ++ /** ++ * Returns whether the {@code other} player is listed for {@code this}. ++ * ++ * @param other The other {@link Player} to check for listing. ++ * @return True if the {@code other} player is listed for {@code this}. ++ */ ++ boolean isListed(@NotNull Player other); ++ ++ /** ++ * Unlists the {@code other} player from the tablist. ++ * ++ * @param other The other {@link Player} to de-list. ++ * @return True if the {@code other} player was listed. ++ */ ++ boolean unlistPlayer(@NotNull Player other); ++ ++ /** ++ * Lists the {@code other} player. ++ * ++ * @param other The other {@link Player} to list. ++ * @return True if the {@code other} player was not listed. ++ */ ++ boolean listPlayer(@NotNull Player other); ++ // Paper end ++ + /** + * Checks to see if this player is currently flying or not. + * diff --git a/patches/api/0406-Expose-clicked-BlockFace-during-BlockDamageEvent.patch b/patches/api/0406-Expose-clicked-BlockFace-during-BlockDamageEvent.patch new file mode 100644 index 000000000000..34d194086683 --- /dev/null +++ b/patches/api/0406-Expose-clicked-BlockFace-during-BlockDamageEvent.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: aerulion +Date: Mon, 21 Aug 2023 04:36:07 +0200 +Subject: [PATCH] Expose clicked BlockFace during BlockDamageEvent + + +diff --git a/src/main/java/org/bukkit/event/block/BlockDamageEvent.java b/src/main/java/org/bukkit/event/block/BlockDamageEvent.java +index cd04a0bd9d232857408b38605787016a217cb8d2..392cde07d578d684423e1bf369af28696eb7e484 100644 +--- a/src/main/java/org/bukkit/event/block/BlockDamageEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockDamageEvent.java +@@ -19,9 +19,20 @@ public class BlockDamageEvent extends BlockEvent implements Cancellable { + private boolean instaBreak; + private boolean cancel; + private final ItemStack itemstack; ++ private final org.bukkit.block.BlockFace blockFace; // Paper - Expose BlockFace + ++ // Paper start - expose blockface ++ @Deprecated(forRemoval = true) ++ @io.papermc.paper.annotation.DoNotUse + public BlockDamageEvent(@NotNull final Player player, @NotNull final Block block, @NotNull final ItemStack itemInHand, final boolean instaBreak) { ++ this(player, block, null, itemInHand, instaBreak); // Some plugin do bad things... ++ } ++ ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper ++ public BlockDamageEvent(@NotNull final Player player, @NotNull final Block block, @NotNull final org.bukkit.block.BlockFace blockFace, @NotNull final ItemStack itemInHand, final boolean instaBreak) { // Paper - Expose BlockFace + super(block); ++ this.blockFace = blockFace; ++ // Paper end - expose blockface + this.instaBreak = instaBreak; + this.player = player; + this.itemstack = itemInHand; +@@ -67,6 +78,20 @@ public class BlockDamageEvent extends BlockEvent implements Cancellable { + public ItemStack getItemInHand() { + return itemstack; + } ++ // Paper start - Expose BlockFace ++ /** ++ * Gets the BlockFace the player is interacting with. ++ * ++ * @return The BlockFace clicked to damage the block ++ */ ++ @NotNull ++ public org.bukkit.block.BlockFace getBlockFace() { ++ if (this.blockFace == null) { ++ throw new IllegalStateException("BlockFace is not available for this event, most likely due to a bad constructor call by a plugin"); ++ } ++ return this.blockFace; ++ } ++ //Paper end + + @Override + public boolean isCancelled() { diff --git a/patches/api/0407-Fix-NPE-on-Boat-getStatus.patch b/patches/api/0407-Fix-NPE-on-Boat-getStatus.patch new file mode 100644 index 000000000000..03398ef0e74d --- /dev/null +++ b/patches/api/0407-Fix-NPE-on-Boat-getStatus.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: LemonCaramel +Date: Tue, 11 Apr 2023 04:04:41 +0900 +Subject: [PATCH] Fix NPE on Boat getStatus + + +diff --git a/src/main/java/org/bukkit/entity/Boat.java b/src/main/java/org/bukkit/entity/Boat.java +index 9e8224d7e0a83a6252a32d352b9db55a9079325e..219a2f06c57c8a64052c372a62892389a98f9ae1 100644 +--- a/src/main/java/org/bukkit/entity/Boat.java ++++ b/src/main/java/org/bukkit/entity/Boat.java +@@ -175,6 +175,7 @@ public interface Boat extends Vehicle { + */ + public enum Status { + ++ NOT_IN_WORLD, // Paper + IN_WATER, + UNDER_WATER, + UNDER_FLOWING_WATER, diff --git a/patches/api/0408-Expand-Pose-API.patch b/patches/api/0408-Expand-Pose-API.patch new file mode 100644 index 000000000000..cdc5e59a2aab --- /dev/null +++ b/patches/api/0408-Expand-Pose-API.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Wed, 11 Jan 2023 20:59:02 +0200 +Subject: [PATCH] Expand Pose API + + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index ee5a27ba09ec4100dbedab4f190cf74549ce858e..e56808a884a4fda9a891468a787b3dff9303debc 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -840,6 +840,42 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + * @param sneak true if the entity should be sneaking + */ + void setSneaking(boolean sneak); ++ ++ /** ++ * Sets the entity's current {@link Pose}. ++ * ++ *

      Note: While poses affect some things like hitboxes, they do not change the entity's state ++ * (e.g. having {@link Pose#SNEAKING} does not guarantee {@link #isSneaking()} being {@code true}). ++ * ++ *

      If applied to the {@link Player}, they might see a different pose client-side. ++ * ++ * @param pose a new {@link Pose} ++ * @see #setPose(Pose, boolean) ++ */ ++ default void setPose(@NotNull Pose pose) { ++ setPose(pose, false); ++ } ++ ++ /** ++ * Sets the entity's current {@link Pose}. ++ * ++ *

      Note: While poses affect some things like hitboxes, they do not change the entity's state ++ * (e.g. having {@link Pose#SNEAKING} does not guarantee {@link #isSneaking()} being {@code true}). ++ * ++ *

      If applied to the {@link Player}, they might see a different pose client-side. ++ * ++ * @param pose a new {@link Pose} ++ * @param fixed whether the new {@link Pose} should stay until manually changed ++ */ ++ void setPose(@NotNull Pose pose, boolean fixed); ++ ++ /** ++ * Checks whether the entity has a fixed {@link Pose} ++ * ++ * @see #setPose(Pose, boolean) ++ * @return whether the entity has a fixed {@link Pose} ++ */ ++ boolean hasFixedPose(); + // Paper end + + /** diff --git a/patches/api/0409-MerchantRecipe-add-copy-constructor.patch b/patches/api/0409-MerchantRecipe-add-copy-constructor.patch new file mode 100644 index 000000000000..1c5ba2803c26 --- /dev/null +++ b/patches/api/0409-MerchantRecipe-add-copy-constructor.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Joo200 +Date: Tue, 20 Dec 2022 15:26:36 +0100 +Subject: [PATCH] MerchantRecipe: add copy constructor + + +diff --git a/src/main/java/org/bukkit/inventory/MerchantRecipe.java b/src/main/java/org/bukkit/inventory/MerchantRecipe.java +index afaa21b9347683fa373a938d9b1aa01c2058192a..39f9766a03d420340d79841197f75c8b1dd49f4a 100644 +--- a/src/main/java/org/bukkit/inventory/MerchantRecipe.java ++++ b/src/main/java/org/bukkit/inventory/MerchantRecipe.java +@@ -91,6 +91,13 @@ public class MerchantRecipe implements Recipe { + this.specialPrice = specialPrice; + } + ++ // Paper start - add copy ctor ++ public MerchantRecipe(@NotNull MerchantRecipe recipe) { ++ this(recipe.result.clone(), recipe.uses, recipe.maxUses, recipe.experienceReward, recipe.villagerExperience, recipe.priceMultiplier, recipe.demand, recipe.specialPrice, recipe.ignoreDiscounts); ++ this.setIngredients(recipe.ingredients); ++ } ++ // Paper end ++ + @NotNull + @Override + public ItemStack getResult() { diff --git a/patches/api/0410-More-DragonBattle-API.patch b/patches/api/0410-More-DragonBattle-API.patch new file mode 100644 index 000000000000..e25208ec1931 --- /dev/null +++ b/patches/api/0410-More-DragonBattle-API.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 18 Dec 2022 13:40:17 -0800 +Subject: [PATCH] More DragonBattle API + + +diff --git a/src/main/java/org/bukkit/boss/DragonBattle.java b/src/main/java/org/bukkit/boss/DragonBattle.java +index 6e5fc92243ee63c2a965f8a4905e29a7993588fd..5dbd12a786a66640ce80acafe2a42e35adef41eb 100644 +--- a/src/main/java/org/bukkit/boss/DragonBattle.java ++++ b/src/main/java/org/bukkit/boss/DragonBattle.java +@@ -145,4 +145,44 @@ public interface DragonBattle { + */ + NONE; + } ++ // Paper start ++ /** ++ * Gets the number of gateways tracked by this DragonBattle. ++ * This starts out at 0 and will increase to 20, once for each ++ * kill of the {@link EnderDragon}. ++ * ++ * @return the number of gateways around the end island tracked by this ++ */ ++ int getGatewayCount(); ++ ++ /** ++ * Tries to spawn a new end gateway using default game mechanics. ++ * ++ * @return true if successful, false if there is already the maximum. ++ */ ++ boolean spawnNewGateway(); ++ ++ /** ++ * Spawns a new end gateway at the specified position. This will ++ * spawn regardless of the number of gateways already present. ++ * ++ * @param position position for the new gateway ++ */ ++ void spawnNewGateway(@NotNull io.papermc.paper.math.Position position); ++ ++ /** ++ * Gets the {@link org.bukkit.entity.EnderCrystal}s being used to respawn the dragon. If no respawn ++ * is ongoing, the list will be empty. ++ * ++ * @return the respawn crystals ++ */ ++ java.util.@NotNull @org.jetbrains.annotations.Unmodifiable List getRespawnCrystals(); ++ ++ /** ++ * Gets the {@link org.bukkit.entity.EnderCrystal}s on top of the pillars that heal the dragon. ++ * ++ * @return the healing crystals ++ */ ++ java.util.@NotNull @org.jetbrains.annotations.Unmodifiable List getHealingCrystals(); ++ // Paper end + } diff --git a/patches/api/0411-Add-PlayerPickItemEvent.patch b/patches/api/0411-Add-PlayerPickItemEvent.patch new file mode 100644 index 000000000000..f1ceb87ff2d8 --- /dev/null +++ b/patches/api/0411-Add-PlayerPickItemEvent.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: RodneyMKay <36546810+RodneyMKay@users.noreply.github.com> +Date: Wed, 8 Sep 2021 22:15:43 +0200 +Subject: [PATCH] Add PlayerPickItemEvent + + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7de240399f3ae069c496add9f0d437a41ed8f58d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java +@@ -0,0 +1,95 @@ ++package io.papermc.paper.event.player; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Range; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Event that is fired when a player uses the pick item functionality (middle-clicking a block or entity to get the ++ * appropriate item). After the handling of this event, the contents of the source and the target slot will be swapped ++ * and the currently selected hotbar slot of the player will be set to the target slot. ++ */ ++@NullMarked ++public class PlayerPickItemEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private int targetSlot; ++ private int sourceSlot; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerPickItemEvent(final Player player, final int targetSlot, final int sourceSlot) { ++ super(player); ++ this.targetSlot = targetSlot; ++ this.sourceSlot = sourceSlot; ++ } ++ ++ /** ++ * Returns the slot the item that is being picked goes into. ++ * ++ * @return hotbar slot (0-8 inclusive) ++ */ ++ public @Range(from = 0, to = 8) int getTargetSlot() { ++ return this.targetSlot; ++ } ++ ++ /** ++ * Changes the slot the item that is being picked goes into. ++ * ++ * @param targetSlot hotbar slot (0-8 inclusive) ++ */ ++ public void setTargetSlot(final @Range(from = 0, to = 8) int targetSlot) { ++ Preconditions.checkArgument(targetSlot >= 0 && targetSlot <= 8, "Target slot must be in range 0 - 8 (inclusive)"); ++ this.targetSlot = targetSlot; ++ } ++ ++ /** ++ * Returns the slot in which the item that will be put into the players hotbar is located. ++ *

      ++ * Returns {@code -1} if the item is not in the player's inventory. ++ * If this is the case and the player is in creative mode, the item will be spawned in. ++ * ++ * @return player inventory slot (0-35 inclusive, or {@code -1} if not in the player inventory) ++ */ ++ public @Range(from = -1, to = 35) int getSourceSlot() { ++ return this.sourceSlot; ++ } ++ ++ /** ++ * Change the source slot from which the item that will be put in the players hotbar will be taken. ++ *

      ++ * If set to {@code -1} and the player is in creative mode, the item will be spawned in. ++ * ++ * @param sourceSlot player inventory slot (0-35 inclusive, or {@code -1} if not in the player inventory) ++ */ ++ public void setSourceSlot(final @Range(from = -1, to = 35) int sourceSlot) { ++ Preconditions.checkArgument(sourceSlot >= -1 && sourceSlot <= 35, "Source slot must be in range of the player's inventory slot, or -1"); ++ this.sourceSlot = sourceSlot; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0412-Allow-trident-custom-damage.patch b/patches/api/0412-Allow-trident-custom-damage.patch new file mode 100644 index 000000000000..870b7355485c --- /dev/null +++ b/patches/api/0412-Allow-trident-custom-damage.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Wed, 13 Jul 2022 15:29:53 +0200 +Subject: [PATCH] Allow trident custom damage + + +diff --git a/src/main/java/org/bukkit/entity/Trident.java b/src/main/java/org/bukkit/entity/Trident.java +index 02584eced96944a551140f8150c65a7c0f4bb55e..d21df39ceef657575f3c2e9070bf6d2671978c7a 100644 +--- a/src/main/java/org/bukkit/entity/Trident.java ++++ b/src/main/java/org/bukkit/entity/Trident.java +@@ -57,5 +57,23 @@ public interface Trident extends AbstractArrow, ThrowableProjectile { + * @param hasDealtDamage has dealt damage or hit the floor + */ + void setHasDealtDamage(boolean hasDealtDamage); ++ ++ /** ++ * Sets the base amount of damage this trident will do. ++ * ++ * @param damage new damage amount ++ */ ++ void setDamage(double damage); ++ ++ /** ++ * Gets the base amount of damage this trident will do. ++ * ++ * Defaults to 8.0 for a normal trident with ++ * 0.5 * (1 + power level) added for trident fired from ++ * damage enchanted bows. ++ * ++ * @return base damage amount ++ */ ++ double getDamage(); + } + // Paper end diff --git a/patches/api/0413-Expose-hand-during-BlockCanBuildEvent.patch b/patches/api/0413-Expose-hand-during-BlockCanBuildEvent.patch new file mode 100644 index 000000000000..0d0054f292f8 --- /dev/null +++ b/patches/api/0413-Expose-hand-during-BlockCanBuildEvent.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: The456gamer +Date: Mon, 21 Aug 2023 14:13:43 +0100 +Subject: [PATCH] Expose hand during BlockCanBuildEvent + + +diff --git a/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java b/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java +index 7d2501278812c7f06d1416fa73389e84c258d71c..31fd64187fc5bd50a5ba36b3b68001ce6ff2211c 100644 +--- a/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java +@@ -25,10 +25,11 @@ public class BlockCanBuildEvent extends BlockEvent { + + protected BlockData blockData; + private final Player player; ++ private final org.bukkit.inventory.EquipmentSlot hand; // Paper - expose hand + + @Deprecated(since = "1.13.2") + public BlockCanBuildEvent(@NotNull final Block block, @NotNull final BlockData type, final boolean canBuild) { +- this(block, null, type, canBuild); ++ this(block, null, type, canBuild, org.bukkit.inventory.EquipmentSlot.HAND); // Paper - expose hand + } + + /** +@@ -37,12 +38,30 @@ public class BlockCanBuildEvent extends BlockEvent { + * @param type the id of the block to place + * @param canBuild whether we can build + */ ++ @java.lang.Deprecated // Paper ++ @io.papermc.paper.annotation.DoNotUse // Paper + public BlockCanBuildEvent(@NotNull final Block block, @Nullable final Player player, @NotNull final BlockData type, final boolean canBuild) { ++ this(block, player, type, canBuild, org.bukkit.inventory.EquipmentSlot.HAND); // Paper start - expose hand ++ } ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public BlockCanBuildEvent(@NotNull final Block block, @Nullable final Player player, @NotNull final BlockData type, final boolean canBuild, @NotNull final org.bukkit.inventory.EquipmentSlot hand) { // Paper end - expose hand + super(block); + this.player = player; + this.buildable = canBuild; + this.blockData = type; ++ this.hand = hand; // Paper ++ } ++ // Paper start ++ /** ++ * Gets the hand the player will use to place the block ++ * ++ * @return the EquipmentSlot representing the players hand. ++ */ ++ @NotNull ++ public org.bukkit.inventory.EquipmentSlot getHand() { ++ return hand; + } ++ // Paper end + + /** + * Gets whether or not the block can be built here. diff --git a/patches/api/0414-Limit-setBurnTime-to-valid-short-values.patch b/patches/api/0414-Limit-setBurnTime-to-valid-short-values.patch new file mode 100644 index 000000000000..2faac56fd883 --- /dev/null +++ b/patches/api/0414-Limit-setBurnTime-to-valid-short-values.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Fri, 18 Aug 2023 08:07:38 +0200 +Subject: [PATCH] Limit setBurnTime to valid short values + + +diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java +index ba4dc8aed85169e55cac276bdd51116919305019..2f80910dd23dacb30c41189a07a4e54117110bb8 100644 +--- a/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/FurnaceBurnEvent.java +@@ -52,8 +52,8 @@ public class FurnaceBurnEvent extends BlockEvent implements Cancellable { + * + * @param burnTime the burn time for this fuel + */ +- public void setBurnTime(int burnTime) { +- this.burnTime = burnTime; ++ public void setBurnTime(@org.jetbrains.annotations.Range(from = Short.MIN_VALUE, to = Short.MAX_VALUE) int burnTime) { // Paper ++ this.burnTime = Math.max(Short.MIN_VALUE, Math.min(Short.MAX_VALUE, burnTime)); // Paper + } + + /** diff --git a/patches/api/0415-Add-OfflinePlayer-isConnected.patch b/patches/api/0415-Add-OfflinePlayer-isConnected.patch new file mode 100644 index 000000000000..126881d0fd3c --- /dev/null +++ b/patches/api/0415-Add-OfflinePlayer-isConnected.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aeltumn +Date: Thu, 24 Aug 2023 13:05:07 +0200 +Subject: [PATCH] Add OfflinePlayer#isConnected + +This adds an alternative to OfflinePlayer#isOnline that returns true only if the same instance of the player is still online. This is generally more useful than isOnline as it allows you to determine if you have an instance of a Player that still exists. If a player relogs an old Player instance becomes unlinked leading to e.g. messages sent to the old player no longer arriving despite isOnline returning true. Checking against isConnected is more useful there to discard invalid instances. + +diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java +index a8003b4796b3f80986043a9dbc2e6ad08a1bb4d7..18720a965b814d02e783d5039da90af0e966025d 100644 +--- a/src/main/java/org/bukkit/OfflinePlayer.java ++++ b/src/main/java/org/bukkit/OfflinePlayer.java +@@ -24,10 +24,26 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio + /** + * Checks if this player is currently online + * ++ * It should be noted that this will return true if any instance of this player is ++ * online! This instance may have disconnected. If you wish to check if this specific ++ * instance of the player is still online, see {@link OfflinePlayer#isConnected()}. ++ * + * @return true if they are online + */ + public boolean isOnline(); + ++ // Paper start ++ /** ++ * Checks whether the connection to this player is still valid. This will return ++ * true as long as this specific instance of the player is still connected. This ++ * will return false after this instance has disconnected, even if the same player ++ * has reconnected since. ++ * ++ * @return true if this player instance is connected ++ */ ++ public boolean isConnected(); ++ // Paper end ++ + /** + * Returns the name of this player + *

      diff --git a/patches/api/0416-Add-titleOverride-to-InventoryOpenEvent.patch b/patches/api/0416-Add-titleOverride-to-InventoryOpenEvent.patch new file mode 100644 index 000000000000..68e755f0102b --- /dev/null +++ b/patches/api/0416-Add-titleOverride-to-InventoryOpenEvent.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 4 Mar 2022 12:45:21 -0800 +Subject: [PATCH] Add titleOverride to InventoryOpenEvent + + +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java +index ceae092eb782698803c6c3df41267dde20ba62b2..8e2afeab4c62724148e8bb0c83fb7eec569c7a0c 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java +@@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull; + public class InventoryOpenEvent extends InventoryEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; ++ private net.kyori.adventure.text.Component titleOverride; // Paper + + public InventoryOpenEvent(@NotNull InventoryView transaction) { + super(transaction); +@@ -56,6 +57,33 @@ public class InventoryOpenEvent extends InventoryEvent implements Cancellable { + cancelled = cancel; + } + ++ // Paper start ++ /** ++ * Gets the title override set by another event or null ++ * if not set. ++ * ++ * @return the title override or null ++ */ ++ public net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component titleOverride() { ++ return this.titleOverride; ++ } ++ ++ /** ++ * Sets the title override or clears the override. ++ *

      ++ * This is only the title sent to the client in the open packet, this doesn't change ++ * the title returned by {@link InventoryView#title()}, hence "override". ++ *

      ++ * NOTE: Horse inventories are a special case where setting this will ++ * have no effect. Horse inventory titles are set by the horse display name. ++ * ++ * @param titleOverride the title override or null ++ */ ++ public void titleOverride(net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component titleOverride) { ++ this.titleOverride = titleOverride; ++ } ++ // Paper end ++ + @NotNull + @Override + public HandlerList getHandlers() { diff --git a/patches/api/0417-Allow-proper-checking-of-empty-item-stacks.patch b/patches/api/0417-Allow-proper-checking-of-empty-item-stacks.patch new file mode 100644 index 000000000000..b413b7e7e7e3 --- /dev/null +++ b/patches/api/0417-Allow-proper-checking-of-empty-item-stacks.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aeltumn +Date: Mon, 28 Aug 2023 13:41:09 +0200 +Subject: [PATCH] Allow proper checking of empty item stacks + +This adds a method to check if an item stack is empty or not. This mirrors vanilla's implementation of the same method. + +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index 6393e5249b4469b1c8ebfb05a0f09572d116c40f..bcead776776665fc7558ee11f928d842bd2e3da5 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -1104,5 +1104,24 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + public @NotNull ItemStack damage(int amount, @NotNull org.bukkit.entity.LivingEntity livingEntity) { + return livingEntity.damageItemStack(this, amount); + } ++ ++ /** ++ * Returns an empty item stack, consists of an air material and a stack size of 0. ++ * ++ * Any item stack with a material of air or a stack size of 0 is seen ++ * as being empty by {@link ItemStack#isEmpty}. ++ */ ++ @NotNull ++ public static ItemStack empty() { ++ return new ItemStack(); ++ } ++ ++ /** ++ * Returns whether this item stack is empty and contains no item. This means ++ * it is either air or the stack has a size of 0. ++ */ ++ public boolean isEmpty() { ++ return type.isAir() || amount <= 0; ++ } + // Paper end + } diff --git a/patches/api/0418-Fix-PlayerSwapHandItemsEvent-throwing-exception-when.patch b/patches/api/0418-Fix-PlayerSwapHandItemsEvent-throwing-exception-when.patch new file mode 100644 index 000000000000..e72f86be5d20 --- /dev/null +++ b/patches/api/0418-Fix-PlayerSwapHandItemsEvent-throwing-exception-when.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tamion <70228790+notTamion@users.noreply.github.com> +Date: Mon, 25 Sep 2023 19:55:51 +0200 +Subject: [PATCH] Fix PlayerSwapHandItemsEvent throwing exception when mainhand + or offhand set to null + + +diff --git a/src/main/java/org/bukkit/event/player/PlayerSwapHandItemsEvent.java b/src/main/java/org/bukkit/event/player/PlayerSwapHandItemsEvent.java +index 9f592317c920589c22a5fb8e916c6ca58ebe5c59..39dd08de71b8b52fe3462c105ecdbfc1cd2cd9a3 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerSwapHandItemsEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerSwapHandItemsEvent.java +@@ -31,7 +31,7 @@ public class PlayerSwapHandItemsEvent extends PlayerEvent implements Cancellable + * + * @return item in the main hand + */ +- @Nullable ++ @NotNull // Paper + public ItemStack getMainHandItem() { + return mainHandItem; + } +@@ -42,7 +42,7 @@ public class PlayerSwapHandItemsEvent extends PlayerEvent implements Cancellable + * @param mainHandItem new item in the main hand + */ + public void setMainHandItem(@Nullable ItemStack mainHandItem) { +- this.mainHandItem = mainHandItem; ++ this.mainHandItem = mainHandItem == null ? ItemStack.empty() : mainHandItem; // Paper + } + + /** +@@ -50,7 +50,7 @@ public class PlayerSwapHandItemsEvent extends PlayerEvent implements Cancellable + * + * @return item in the off hand + */ +- @Nullable ++ @NotNull // Paper + public ItemStack getOffHandItem() { + return offHandItem; + } +@@ -61,7 +61,7 @@ public class PlayerSwapHandItemsEvent extends PlayerEvent implements Cancellable + * @param offHandItem new item in the off hand + */ + public void setOffHandItem(@Nullable ItemStack offHandItem) { +- this.offHandItem = offHandItem; ++ this.offHandItem = offHandItem == null ? ItemStack.empty() : offHandItem; // Paper + } + + @Override diff --git a/patches/api/0419-Add-player-idle-duration-API.patch b/patches/api/0419-Add-player-idle-duration-API.patch new file mode 100644 index 000000000000..b64d0bcece99 --- /dev/null +++ b/patches/api/0419-Add-player-idle-duration-API.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: booky10 +Date: Sat, 14 Oct 2023 03:11:11 +0200 +Subject: [PATCH] Add player idle duration API + +Implements API for getting and resetting a player's idle duration. + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 094c2056f4124dbb1caa0a5e962933b653d950a9..d84fe3e439f3b190b7bbec15f406cc3a393dccfc 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3782,6 +3782,29 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + void increaseWardenWarningLevel(); + // Paper end + ++ // Paper start ++ /** ++ * The idle duration is reset when the player ++ * sends specific action packets. ++ *

      ++ * After the idle duration exceeds {@link org.bukkit.Bukkit#getIdleTimeout()}, the ++ * player will be kicked for {@link org.bukkit.event.player.PlayerKickEvent.Cause#IDLING}. ++ * ++ * @return the current idle duration of this player ++ */ ++ @NotNull Duration getIdleDuration(); ++ ++ /** ++ * Resets this player's idle duration. ++ *

      ++ * After the idle duration exceeds {@link org.bukkit.Bukkit#getIdleTimeout()}, the ++ * player will be kicked for {@link org.bukkit.event.player.PlayerKickEvent.Cause#IDLING}. ++ * ++ * @see #getIdleDuration() ++ */ ++ void resetIdleDuration(); ++ // Paper end ++ + @NotNull + @Override + Spigot spigot(); diff --git a/patches/api/0420-Add-API-to-get-the-collision-shape-of-a-block-before.patch b/patches/api/0420-Add-API-to-get-the-collision-shape-of-a-block-before.patch new file mode 100644 index 000000000000..3bb30787dc38 --- /dev/null +++ b/patches/api/0420-Add-API-to-get-the-collision-shape-of-a-block-before.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TrollyLoki +Date: Wed, 11 Oct 2023 00:45:54 -0400 +Subject: [PATCH] Add API to get the collision shape of a block before it's + placed + + +diff --git a/src/main/java/org/bukkit/block/data/BlockData.java b/src/main/java/org/bukkit/block/data/BlockData.java +index 54664651f34311e95f6c2dcfd93e58477beda8c2..0ecc54bd810a2805b7209d9433b76743500e45a8 100644 +--- a/src/main/java/org/bukkit/block/data/BlockData.java ++++ b/src/main/java/org/bukkit/block/data/BlockData.java +@@ -205,6 +205,19 @@ public interface BlockData extends Cloneable { + */ + boolean isFaceSturdy(@NotNull BlockFace face, @NotNull BlockSupport support); + ++ // Paper start ++ /** ++ * Calculates the collision shape this block data would have at a particular location. ++ *

      ++ * This does not take into account any block updates that may occur if the block was to be actually placed in the world. ++ * ++ * @param location the location to calculate the collision shape at ++ * ++ * @return a {@link org.bukkit.util.VoxelShape} representing the collision shape of this block data. ++ */ ++ @NotNull org.bukkit.util.VoxelShape getCollisionShape(@NotNull Location location); ++ // Paper end ++ + /** + * Gets the color this block should appear as when rendered on a map. + * diff --git a/patches/api/0421-Add-predicate-for-blocks-when-raytracing.patch b/patches/api/0421-Add-predicate-for-blocks-when-raytracing.patch new file mode 100644 index 000000000000..507244270d25 --- /dev/null +++ b/patches/api/0421-Add-predicate-for-blocks-when-raytracing.patch @@ -0,0 +1,116 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TonytheMacaroni +Date: Wed, 6 Sep 2023 19:24:53 -0400 +Subject: [PATCH] Add predicate for blocks when raytracing + + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 8bfa8db3d0fdbe0c26e3b327d134c6c0af6be206..3cb0aecf582b3d1c5195fca9160780ad5e98155a 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -1686,6 +1686,27 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @Nullable + public RayTraceResult rayTraceEntities(@NotNull Location start, @NotNull Vector direction, double maxDistance, double raySize, @Nullable Predicate filter); + ++ // Paper start ++ /** ++ * Performs a ray trace that checks for entity collisions. ++ *

      ++ * This may not consider entities in currently unloaded chunks. Some ++ * implementations may impose artificial restrictions on the maximum ++ * distance. ++ * ++ * @param start the start position ++ * @param direction the ray direction ++ * @param maxDistance the maximum distance ++ * @param raySize entity bounding boxes will be uniformly expanded (or ++ * shrinked) by this value before doing collision checks ++ * @param filter only entities that fulfill this predicate are considered, ++ * or null to consider all entities ++ * @return the closest ray trace hit result, or null if there ++ * is no hit ++ */ ++ @Nullable RayTraceResult rayTraceEntities(io.papermc.paper.math.@NotNull Position start, @NotNull Vector direction, double maxDistance, double raySize, @Nullable Predicate filter); ++ // Paper end ++ + /** + * Performs a ray trace that checks for block collisions using the blocks' + * precise collision shapes. +@@ -1749,6 +1770,34 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @Nullable + public RayTraceResult rayTraceBlocks(@NotNull Location start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks); + ++ // Paper start ++ /** ++ * Performs a ray trace that checks for block collisions using the blocks' ++ * precise collision shapes. ++ *

      ++ * If collisions with passable blocks are ignored, fluid collisions are ++ * ignored as well regardless of the fluid collision mode. ++ *

      ++ * Portal blocks are only considered passable if the ray starts within ++ * them. Apart from that collisions with portal blocks will be considered ++ * even if collisions with passable blocks are otherwise ignored. ++ *

      ++ * This may cause loading of chunks! Some implementations may impose ++ * artificial restrictions on the maximum distance. ++ * ++ * @param start the start position ++ * @param direction the ray direction ++ * @param maxDistance the maximum distance ++ * @param fluidCollisionMode the fluid collision mode ++ * @param ignorePassableBlocks whether to ignore passable but collidable ++ * blocks (ex. tall grass, signs, fluids, ..) ++ * @param canCollide predicate for blocks the ray can potentially collide ++ * with, or null to consider all blocks ++ * @return the ray trace hit result, or null if there is no hit ++ */ ++ @Nullable RayTraceResult rayTraceBlocks(io.papermc.paper.math.@NotNull Position start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, @Nullable Predicate canCollide); ++ // Paper end ++ + /** + * Performs a ray trace that checks for both block and entity collisions. + *

      +@@ -1782,6 +1831,42 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @Nullable + public RayTraceResult rayTrace(@NotNull Location start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, @Nullable Predicate filter); + ++ // Paper start ++ /** ++ * Performs a ray trace that checks for both block and entity collisions. ++ *

      ++ * Block collisions use the blocks' precise collision shapes. The ++ * raySize parameter is only taken into account for entity ++ * collision checks. ++ *

      ++ * If collisions with passable blocks are ignored, fluid collisions are ++ * ignored as well regardless of the fluid collision mode. ++ *

      ++ * Portal blocks are only considered passable if the ray starts within them. ++ * Apart from that collisions with portal blocks will be considered even if ++ * collisions with passable blocks are otherwise ignored. ++ *

      ++ * This may cause loading of chunks! Some implementations may impose ++ * artificial restrictions on the maximum distance. ++ * ++ * @param start the start position ++ * @param direction the ray direction ++ * @param maxDistance the maximum distance ++ * @param fluidCollisionMode the fluid collision mode ++ * @param ignorePassableBlocks whether to ignore passable but collidable ++ * blocks (ex. tall grass, signs, fluids, ..) ++ * @param raySize entity bounding boxes will be uniformly expanded (or ++ * shrinked) by this value before doing collision checks ++ * @param filter only entities that fulfill this predicate are considered, ++ * or null to consider all entities ++ * @param canCollide predicate for blocks the ray can potentially collide ++ * with, or null to consider all blocks ++ * @return the closest ray trace hit result with either a block or an ++ * entity, or null if there is no hit ++ */ ++ @Nullable RayTraceResult rayTrace(io.papermc.paper.math.@NotNull Position start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, @Nullable Predicate filter, @Nullable Predicate canCollide); ++ // Paper end ++ + /** + * Gets the default spawn {@link Location} of this world + * diff --git a/patches/api/0422-Add-hand-to-fish-event-for-all-player-interactions.patch b/patches/api/0422-Add-hand-to-fish-event-for-all-player-interactions.patch new file mode 100644 index 000000000000..b431332b9a0a --- /dev/null +++ b/patches/api/0422-Add-hand-to-fish-event-for-all-player-interactions.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: booky10 +Date: Mon, 3 Jul 2023 01:55:32 +0200 +Subject: [PATCH] Add hand to fish event for all player interactions + + +diff --git a/src/main/java/org/bukkit/event/player/PlayerFishEvent.java b/src/main/java/org/bukkit/event/player/PlayerFishEvent.java +index 45342030ad0f46632d3ee9a6d0348251f8ee375f..d4001f64a7ee9d5173e9bafd9c45860cbda1fc85 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerFishEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerFishEvent.java +@@ -94,8 +94,9 @@ public class PlayerFishEvent extends PlayerEvent implements Cancellable { + /** + * Get the hand that was used in this event. + *

      +- * The hand used is only present when the event state is {@link State#FISHING}. +- * In all other states, the hand is null. ++ * The hand used is only present for player interactions. ++ * This means it will be null if state is set ++ * to {@link State#BITE} or {@link State#FAILED_ATTEMPT}. + * + * @return the hand + */ diff --git a/patches/api/0423-Attribute-Modifier-API-improvements.patch b/patches/api/0423-Attribute-Modifier-API-improvements.patch new file mode 100644 index 000000000000..7384a7ae3bbb --- /dev/null +++ b/patches/api/0423-Attribute-Modifier-API-improvements.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TonytheMacaroni +Date: Thu, 9 Nov 2023 20:35:35 -0500 +Subject: [PATCH] Attribute Modifier API improvements + +Co-authored-by: Malfrador + +diff --git a/src/main/java/org/bukkit/attribute/AttributeInstance.java b/src/main/java/org/bukkit/attribute/AttributeInstance.java +index f08ee26cc4d479e1bfc5264b8cbe721315de91f2..f1fa86ddf1f50a357c9e94cc61261d8c96a2da6f 100644 +--- a/src/main/java/org/bukkit/attribute/AttributeInstance.java ++++ b/src/main/java/org/bukkit/attribute/AttributeInstance.java +@@ -39,6 +39,42 @@ public interface AttributeInstance { + @NotNull + Collection getModifiers(); + ++ // Paper start ++ /** ++ * Gets the modifier with the corresponding key. ++ * ++ * @param key the jey of the modifier ++ * @return the modifier, if it exists ++ */ ++ @org.jetbrains.annotations.Nullable AttributeModifier getModifier(@NotNull net.kyori.adventure.key.Key key); ++ ++ /** ++ * Remove a modifier with the corresponding key from this instance. ++ * ++ * @param key the key of the modifier ++ */ ++ void removeModifier(@NotNull net.kyori.adventure.key.Key key); ++ ++ /** ++ * Gets the modifier with the corresponding UUID. ++ * ++ * @param uuid the UUID of the modifier ++ * @return the modifier, if it exists ++ * @deprecated use {@link #getModifier(net.kyori.adventure.key.Key)}, modifiers are no longer stored by UUID ++ */ ++ @Deprecated(forRemoval = true, since = "1.21") ++ @org.jetbrains.annotations.Nullable AttributeModifier getModifier(@NotNull java.util.UUID uuid); ++ ++ /** ++ * Remove a modifier with the corresponding UUID from this instance. ++ * ++ * @param uuid the UUID of the modifier ++ * @deprecated use {@link #removeModifier(net.kyori.adventure.key.Key)}, modifiers are no longer stored by UUID ++ */ ++ @Deprecated(forRemoval = true, since = "1.21") ++ void removeModifier(@NotNull java.util.UUID uuid); ++ // Paper end ++ + /** + * Add a modifier to this instance. + * +@@ -46,6 +82,16 @@ public interface AttributeInstance { + */ + void addModifier(@NotNull AttributeModifier modifier); + ++ // Paper start - Transient modifier API ++ /** ++ * Add a transient modifier to this instance. ++ * Transient modifiers are not persisted (saved with the NBT data) ++ * ++ * @param modifier to add ++ */ ++ void addTransientModifier(@NotNull AttributeModifier modifier); ++ // Paper end ++ + /** + * Remove a modifier from this instance. + * +diff --git a/src/main/java/org/bukkit/attribute/AttributeModifier.java b/src/main/java/org/bukkit/attribute/AttributeModifier.java +index b90af00a8eb83d4c1b183fbc4f1e9eae84c9074b..4ad09a2673ce573b63d133635a772197a2062901 100644 +--- a/src/main/java/org/bukkit/attribute/AttributeModifier.java ++++ b/src/main/java/org/bukkit/attribute/AttributeModifier.java +@@ -48,6 +48,12 @@ public class AttributeModifier implements ConfigurationSerializable, Keyed { + this(NamespacedKey.fromString(uuid.toString()), amount, operation, slot); + } + ++ // Paper start - Add constructor without EquipmentSlotGroup ++ public AttributeModifier(@NotNull NamespacedKey key, double amount, @NotNull Operation operation) { ++ this(key, amount, operation, EquipmentSlotGroup.ANY); ++ } ++ // Paper end ++ + public AttributeModifier(@NotNull NamespacedKey key, double amount, @NotNull Operation operation, @NotNull EquipmentSlotGroup slot) { + Preconditions.checkArgument(key != null, "Key cannot be null"); + Preconditions.checkArgument(operation != null, "Operation cannot be null"); diff --git a/patches/api/0424-Expand-LingeringPotion-API.patch b/patches/api/0424-Expand-LingeringPotion-API.patch new file mode 100644 index 000000000000..4fc454cfb4fb --- /dev/null +++ b/patches/api/0424-Expand-LingeringPotion-API.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tamion <70228790+notTamion@users.noreply.github.com> +Date: Sat, 4 Nov 2023 23:56:23 +0100 +Subject: [PATCH] Expand LingeringPotion API + + +diff --git a/src/main/java/org/bukkit/event/entity/LingeringPotionSplashEvent.java b/src/main/java/org/bukkit/event/entity/LingeringPotionSplashEvent.java +index 581241d066310ba6f59811fee8cb32811b8e0b65..2392885ca6294079b939d25b8cbf23c12d86220d 100644 +--- a/src/main/java/org/bukkit/event/entity/LingeringPotionSplashEvent.java ++++ b/src/main/java/org/bukkit/event/entity/LingeringPotionSplashEvent.java +@@ -17,6 +17,7 @@ public class LingeringPotionSplashEvent extends ProjectileHitEvent implements Ca + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final AreaEffectCloud entity; ++ private boolean allowEmptyAreaEffectCreation; // Paper + + @Deprecated(since = "1.20.2") + public LingeringPotionSplashEvent(@NotNull final ThrownPotion potion, @NotNull final AreaEffectCloud entity) { +@@ -44,6 +45,26 @@ public class LingeringPotionSplashEvent extends ProjectileHitEvent implements Ca + return entity; + } + ++ // Paper start ++ /** ++ * Sets if an Empty AreaEffectCloud may be created ++ * ++ * @param allowEmptyAreaEffectCreation If an Empty AreaEffectCloud may be created ++ */ ++ public void allowsEmptyCreation(boolean allowEmptyAreaEffectCreation) { ++ this.allowEmptyAreaEffectCreation = allowEmptyAreaEffectCreation; ++ } ++ ++ /** ++ * Gets if an empty AreaEffectCloud may be created ++ * ++ * @return if an empty AreaEffectCloud may be created ++ */ ++ public boolean allowsEmptyCreation() { ++ return allowEmptyAreaEffectCreation; ++ } ++ // Paper end ++ + @Override + public boolean isCancelled() { + return cancelled; diff --git a/patches/api/0425-Remove-unnecessary-durability-check-in-ItemStack-isS.patch b/patches/api/0425-Remove-unnecessary-durability-check-in-ItemStack-isS.patch new file mode 100644 index 000000000000..64f385ece019 --- /dev/null +++ b/patches/api/0425-Remove-unnecessary-durability-check-in-ItemStack-isS.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrPowerGamerBR +Date: Sun, 26 Nov 2023 20:00:50 -0300 +Subject: [PATCH] Remove unnecessary durability check in + "ItemStack#isSimilar(...)" + +By removing this check we avoid unnecessarily allocating useless `ItemMeta` objects if we are comparing two items, or one of the two items, that don't have any durability. Don't worry, the durability of the item is checked when it checks if both item metas are equal. + +This is a leftover from when checking for the item's durability was "free" because the durability was stored in the `ItemStack` itself, this [was changed in Minecraft 1.13](https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/commits/f8b2086d60942eb2cd7ac25a2a1408cb790c222c#src/main/java/org/bukkit/inventory/ItemStack.java). + +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index bcead776776665fc7558ee11f928d842bd2e3da5..c3ae09dc66119cb2873201fb2975ad5e0f8237d2 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -307,7 +307,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + return true; + } + Material comparisonType = (this.type.isLegacy()) ? Bukkit.getUnsafe().fromLegacy(this.getData(), true) : this.type; // This may be called from legacy item stacks, try to get the right material +- return comparisonType == stack.getType() && getDurability() == stack.getDurability() && hasItemMeta() == stack.hasItemMeta() && (hasItemMeta() ? Bukkit.getItemFactory().equals(getItemMeta(), stack.getItemMeta()) : true); ++ return comparisonType == stack.getType() && /* getDurability() == stack.getDurability() && */hasItemMeta() == stack.hasItemMeta() && (hasItemMeta() ? Bukkit.getItemFactory().equals(getItemMeta(), stack.getItemMeta()) : true); // Paper - remove redundant item durability check + } + + @NotNull diff --git a/patches/api/0426-Add-Structure-check-API.patch b/patches/api/0426-Add-Structure-check-API.patch new file mode 100644 index 000000000000..3923a385a323 --- /dev/null +++ b/patches/api/0426-Add-Structure-check-API.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 27 Mar 2023 10:20:06 -0700 +Subject: [PATCH] Add Structure check API + + +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 3cb0aecf582b3d1c5195fca9160780ad5e98155a..1796615065c8a6d06450d1b9c389804e804c4327 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -78,6 +78,30 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + */ + int getPlayerCount(); + // Paper end ++ // Paper start - structure check API ++ /** ++ * Check if the naturally-generated structure exists at the position. ++ *

      ++ * Note that if the position is not loaded, this may cause chunk loads/generation ++ * to check if a structure is at that position. Use {@link #isPositionLoaded(io.papermc.paper.math.Position)} ++ * to check if a position is loaded ++ * ++ * @param position the position to check at ++ * @param structure the structure to check for ++ * @return true if that structure exists at the position ++ */ ++ boolean hasStructureAt(io.papermc.paper.math.@NotNull Position position, @NotNull Structure structure); ++ ++ /** ++ * Checks if this position is loaded. ++ * ++ * @param position position to check ++ * @return true if loaded ++ */ ++ default boolean isPositionLoaded(io.papermc.paper.math.@NotNull Position position) { ++ return this.isChunkLoaded(position.blockX() >> 4, position.blockZ() >> 4); ++ } ++ // Paper end + + /** + * Gets the {@link Block} at the given coordinates diff --git a/patches/api/0427-Experimental-annotations-change.patch b/patches/api/0427-Experimental-annotations-change.patch new file mode 100644 index 000000000000..52cbc8f45a1f --- /dev/null +++ b/patches/api/0427-Experimental-annotations-change.patch @@ -0,0 +1,201 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 9 Dec 2023 11:47:53 -0800 +Subject: [PATCH] Experimental annotations change + + +diff --git a/src/main/java/org/bukkit/FeatureFlag.java b/src/main/java/org/bukkit/FeatureFlag.java +index 54859fc5d8a14d26f22b57373045408d84766595..dd157b650aa7ac759d156ced30fa7514d34c43ed 100644 +--- a/src/main/java/org/bukkit/FeatureFlag.java ++++ b/src/main/java/org/bukkit/FeatureFlag.java +@@ -29,6 +29,7 @@ public interface FeatureFlag extends Keyed { + @Deprecated(since = "1.20.2") + public static final FeatureFlag UPDATE_1_20 = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("update_1_20")); + ++ @ApiStatus.Experimental // Paper - add missing annotation + public static final FeatureFlag TRADE_REBALANCE = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("trade_rebalance")); + + /** +@@ -47,8 +48,10 @@ public interface FeatureFlag extends Keyed { + @Deprecated(since = "1.21.4") + public static final FeatureFlag WINTER_DROP = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("winter_drop")); + ++ @ApiStatus.Experimental // Paper - add missing annotation + public static final FeatureFlag REDSTONE_EXPERIMENTS = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("redstone_experiments")); + ++ @ApiStatus.Experimental // Paper - add missing annotation + public static final FeatureFlag MINECART_IMPROVEMENTS = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("minecart_improvements")); + + } +diff --git a/src/main/java/org/bukkit/GameRule.java b/src/main/java/org/bukkit/GameRule.java +index 8b6584fae0a9d5cccbe350d889fa8b4a14c78ca3..89f1820ae94c48f51a44df750904bb285013720c 100644 +--- a/src/main/java/org/bukkit/GameRule.java ++++ b/src/main/java/org/bukkit/GameRule.java +@@ -287,6 +287,8 @@ public final class GameRule implements net.kyori.adventure.translation.Transl + * The maximum speed of minecarts (when the new movement algorithm is + * enabled). + */ ++ @MinecraftExperimental(MinecraftExperimental.Requires.MINECART_IMPROVEMENTS) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + public static final GameRule MINECART_MAX_SPEED = new GameRule<>("minecartMaxSpeed", Integer.class); + + /** +diff --git a/src/main/java/org/bukkit/block/Crafter.java b/src/main/java/org/bukkit/block/Crafter.java +index 8d2dd78fc588a6817dfede8040b9909a7d5bde67..f737a2aae3f57a1bfe4cf68ea66f603da4eebd47 100644 +--- a/src/main/java/org/bukkit/block/Crafter.java ++++ b/src/main/java/org/bukkit/block/Crafter.java +@@ -6,7 +6,6 @@ import org.jetbrains.annotations.ApiStatus; + /** + * Represents a captured state of a crafter. + */ +-@ApiStatus.Experimental + public interface Crafter extends Container, com.destroystokyo.paper.loottable.LootableBlockInventory { // Paper - LootTable API + + /** +diff --git a/src/main/java/org/bukkit/block/TrialSpawner.java b/src/main/java/org/bukkit/block/TrialSpawner.java +index 2d46d85aff243e9b3c6764f0de041fff6b766853..6fc7b5fe1152f739663a4715a1c93246c3ee6df2 100644 +--- a/src/main/java/org/bukkit/block/TrialSpawner.java ++++ b/src/main/java/org/bukkit/block/TrialSpawner.java +@@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents a captured state of a trial spawner. + */ +-@ApiStatus.Experimental + public interface TrialSpawner extends TileState { + + /** +diff --git a/src/main/java/org/bukkit/block/Vault.java b/src/main/java/org/bukkit/block/Vault.java +index f0c5d27f6f1ff56ffe4b88dfdce8d0b7f06d19e1..375f41fe4aebdbf140497b5ba1e54e1c72f0cdfc 100644 +--- a/src/main/java/org/bukkit/block/Vault.java ++++ b/src/main/java/org/bukkit/block/Vault.java +@@ -5,6 +5,5 @@ import org.jetbrains.annotations.ApiStatus; + /** + * Represents a captured state of a trial spawner. + */ +-@ApiStatus.Experimental + public interface Vault extends TileState { + } +diff --git a/src/main/java/org/bukkit/entity/AbstractWindCharge.java b/src/main/java/org/bukkit/entity/AbstractWindCharge.java +index 60fbacee263e55f91ac977f020e390d46024723a..ecff691c3a0878659fb051926ef769ce1e339c48 100644 +--- a/src/main/java/org/bukkit/entity/AbstractWindCharge.java ++++ b/src/main/java/org/bukkit/entity/AbstractWindCharge.java +@@ -5,7 +5,6 @@ import org.jetbrains.annotations.ApiStatus; + /** + * Represents a Wind Charge. + */ +-@ApiStatus.Experimental + public interface AbstractWindCharge extends Fireball { + + /** +diff --git a/src/main/java/org/bukkit/entity/Bogged.java b/src/main/java/org/bukkit/entity/Bogged.java +index 6093b1dad8ad48708267a83bf4c1ad20467b3cf9..c84ddf808e2062dae7f68d574f05fbbc05273144 100644 +--- a/src/main/java/org/bukkit/entity/Bogged.java ++++ b/src/main/java/org/bukkit/entity/Bogged.java +@@ -5,7 +5,6 @@ import org.jetbrains.annotations.ApiStatus; + /** + * Represents a Bogged Skeleton. + */ +-@ApiStatus.Experimental + public interface Bogged extends AbstractSkeleton, Shearable, io.papermc.paper.entity.Shearable { // Paper - Shear API + + /** +diff --git a/src/main/java/org/bukkit/entity/Breeze.java b/src/main/java/org/bukkit/entity/Breeze.java +index a75e725805c193a408683885cba83ca168347165..254bc6e18961a72f471334cc0535e3c7a9d70012 100644 +--- a/src/main/java/org/bukkit/entity/Breeze.java ++++ b/src/main/java/org/bukkit/entity/Breeze.java +@@ -5,6 +5,5 @@ import org.jetbrains.annotations.ApiStatus; + /** + * Represents a Breeze. Whoosh! + */ +-@ApiStatus.Experimental + public interface Breeze extends Monster { + } +diff --git a/src/main/java/org/bukkit/entity/BreezeWindCharge.java b/src/main/java/org/bukkit/entity/BreezeWindCharge.java +index 06ca3dc4b0b69cbaefa96464dce484cea93e0717..748e58eb93c7882e15d9cbdd56d11bb14808698b 100644 +--- a/src/main/java/org/bukkit/entity/BreezeWindCharge.java ++++ b/src/main/java/org/bukkit/entity/BreezeWindCharge.java +@@ -5,7 +5,6 @@ import org.jetbrains.annotations.ApiStatus; + /** + * Represents a Wind Charge. + */ +-@ApiStatus.Experimental + public interface BreezeWindCharge extends AbstractWindCharge { + + } +diff --git a/src/main/java/org/bukkit/entity/OminousItemSpawner.java b/src/main/java/org/bukkit/entity/OminousItemSpawner.java +index 4aa07d4edb2c81d0ae7999b30ad53ff8bb884ec7..dbd4da4c63b6b1b21c3e638ac4d2c9fdd6716a8e 100644 +--- a/src/main/java/org/bukkit/entity/OminousItemSpawner.java ++++ b/src/main/java/org/bukkit/entity/OminousItemSpawner.java +@@ -7,7 +7,6 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents an ominous item spawner. + */ +-@ApiStatus.Experimental + public interface OminousItemSpawner extends Entity { + + /** +diff --git a/src/main/java/org/bukkit/entity/WindCharge.java b/src/main/java/org/bukkit/entity/WindCharge.java +index 4adc91ba3dff00ab44303778e9d4499f7808ad00..beb62426490a361af793fb530106d8547a83ae03 100644 +--- a/src/main/java/org/bukkit/entity/WindCharge.java ++++ b/src/main/java/org/bukkit/entity/WindCharge.java +@@ -5,7 +5,6 @@ import org.jetbrains.annotations.ApiStatus; + /** + * Represents a Wind Charge. + */ +-@ApiStatus.Experimental + public interface WindCharge extends AbstractWindCharge { + + } +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java +index 06e037ce94b368b3685ab04ba46c1ab5e5479dbb..e0d73d432cd31da35a72b479c854f2124c63ebe5 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java +@@ -148,7 +148,6 @@ public enum InventoryType { + /** + * A crafter inventory, with 9 CRAFTING slots. + */ +- @ApiStatus.Experimental + CRAFTER(9, "Crafter", MenuType.CRAFTER_3X3), + /** + * The new smithing inventory, with 3 CRAFTING slots and 1 RESULT slot. +diff --git a/src/main/java/org/bukkit/inventory/CrafterInventory.java b/src/main/java/org/bukkit/inventory/CrafterInventory.java +index bb1fb5e0518c6a62ef8b206733ee51d831f1f85b..49d0a37bbeb0b8fa9207164c74245ef05485467c 100644 +--- a/src/main/java/org/bukkit/inventory/CrafterInventory.java ++++ b/src/main/java/org/bukkit/inventory/CrafterInventory.java +@@ -5,5 +5,4 @@ import org.jetbrains.annotations.ApiStatus; + /** + * Interface to the inventory of a Crafter. + */ +-@ApiStatus.Experimental + public interface CrafterInventory extends Inventory { } +diff --git a/src/main/java/org/bukkit/map/MapCursor.java b/src/main/java/org/bukkit/map/MapCursor.java +index bd1c0417fbf72731e6301bf79966c6ea4102fc70..8d00f58883222fac4c3bef62eafa7bcbdedc896d 100644 +--- a/src/main/java/org/bukkit/map/MapCursor.java ++++ b/src/main/java/org/bukkit/map/MapCursor.java +@@ -314,12 +314,26 @@ public final class MapCursor { + Type BANNER_RED = getType("banner_red"); + Type BANNER_BLACK = getType("banner_black"); + Type RED_X = getType("red_x"); ++ @org.bukkit.MinecraftExperimental(org.bukkit.MinecraftExperimental.Requires.TRADE_REBALANCE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + Type VILLAGE_DESERT = getType("village_desert"); ++ @org.bukkit.MinecraftExperimental(org.bukkit.MinecraftExperimental.Requires.TRADE_REBALANCE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + Type VILLAGE_PLAINS = getType("village_plains"); ++ @org.bukkit.MinecraftExperimental(org.bukkit.MinecraftExperimental.Requires.TRADE_REBALANCE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + Type VILLAGE_SAVANNA = getType("village_savanna"); ++ @org.bukkit.MinecraftExperimental(org.bukkit.MinecraftExperimental.Requires.TRADE_REBALANCE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + Type VILLAGE_SNOWY = getType("village_snowy"); ++ @org.bukkit.MinecraftExperimental(org.bukkit.MinecraftExperimental.Requires.TRADE_REBALANCE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + Type VILLAGE_TAIGA = getType("village_taiga"); ++ @org.bukkit.MinecraftExperimental(org.bukkit.MinecraftExperimental.Requires.TRADE_REBALANCE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + Type JUNGLE_TEMPLE = getType("jungle_temple"); ++ @org.bukkit.MinecraftExperimental(org.bukkit.MinecraftExperimental.Requires.TRADE_REBALANCE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + Type SWAMP_HUT = getType("swamp_hut"); + Type TRIAL_CHAMBERS = getType("trial_chambers"); + diff --git a/patches/api/0428-Add-more-scoreboard-API.patch b/patches/api/0428-Add-more-scoreboard-API.patch new file mode 100644 index 000000000000..34e12e5b96d6 --- /dev/null +++ b/patches/api/0428-Add-more-scoreboard-API.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 16 Dec 2023 14:45:46 -0800 +Subject: [PATCH] Add more scoreboard API + + +diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java +index d6d52bc9185e8a1581ccfa57df3550bc12d9872a..d8a249bb2dd8ab96962897c2a52f40ea288f7bd6 100644 +--- a/src/main/java/org/bukkit/scoreboard/Objective.java ++++ b/src/main/java/org/bukkit/scoreboard/Objective.java +@@ -175,4 +175,24 @@ public interface Objective { + */ + @NotNull Score getScoreFor(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException; + // Paper end - improve scoreboard entries ++ ++ // Paper start - add more score API ++ /** ++ * Gets if this objective will auto update score ++ * displays on changes. ++ * ++ * @return true if auto updating ++ * @throws IllegalStateException if this objective has been unregistered ++ */ ++ boolean willAutoUpdateDisplay(); ++ ++ /** ++ * Sets if this objective will auto update ++ * score displays on changes. ++ * ++ * @param autoUpdateDisplay true to auto update ++ * @throws IllegalStateException if this objective has been unregistered ++ */ ++ void setAutoUpdateDisplay(boolean autoUpdateDisplay); ++ // Paper end - add more score API + } +diff --git a/src/main/java/org/bukkit/scoreboard/Score.java b/src/main/java/org/bukkit/scoreboard/Score.java +index 48a1654a2dd8da82cb91bcfa4b3a523f88323568..a3b482e07bb3dceb9b81d66c7208556a0bedd948 100644 +--- a/src/main/java/org/bukkit/scoreboard/Score.java ++++ b/src/main/java/org/bukkit/scoreboard/Score.java +@@ -83,4 +83,50 @@ public interface Score { + */ + void resetScore() throws IllegalStateException; + // Paper end ++ ++ // Paper start - add more score API ++ /** ++ * Gets if this score is triggerable and cannot ++ * be used by the {@code /trigger} command executed ++ * by the owner of this score. ++ * ++ * @return true if triggerable, false if not triggerable, score isn't set, or the objective isn't {@link Criteria#TRIGGER} ++ * @throws IllegalStateException if the associated objective has been unregistered ++ */ ++ boolean isTriggerable(); ++ ++ /** ++ * Sets if this score is triggerable and can ++ * be used by the {@code /trigger} command ++ * executed by the owner of this score. Can ++ * only be set on {@link Criteria#TRIGGER} objectives. ++ *

      ++ * If the score doesn't exist (aka {@link #isScoreSet()} returns false), ++ * this will create the score with a 0 value. ++ * ++ * @param triggerable true to enable trigger, false to disable ++ * @throws IllegalArgumentException if this objective isn't {@link Criteria#TRIGGER} ++ * @throws IllegalStateException if the associated objective has been unregistered ++ */ ++ void setTriggerable(boolean triggerable); ++ ++ /** ++ * Get the custom name for this entry. ++ * ++ * @return the custom name or null if not set (or score isn't set) ++ * @throws IllegalStateException if the associated objective has been unregistered ++ */ ++ @Nullable net.kyori.adventure.text.Component customName(); ++ ++ /** ++ * Sets the custom name for this entry. ++ *

      ++ * If the score doesn't exist (aka {@link #isScoreSet()} returns false), ++ * this will create the score with a 0 value. ++ * ++ * @param customName the custom name or null to reset ++ * @throws IllegalStateException if the associated objective has been unregistered ++ */ ++ void customName(net.kyori.adventure.text.@Nullable Component customName); ++ // Paper end - add more score API + } diff --git a/patches/api/0429-Improve-Registry.patch b/patches/api/0429-Improve-Registry.patch new file mode 100644 index 000000000000..96e3965ecda7 --- /dev/null +++ b/patches/api/0429-Improve-Registry.patch @@ -0,0 +1,320 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 20 Dec 2023 02:03:10 -0800 +Subject: [PATCH] Improve Registry + +Adds Registry#getKey(Object) which should be the +primary way people get the key for an object. Registry +items need to exist without having a key and so +getKey() methods on Keyed objects that have a registry +are marked as Deprecated or Obsolete. + +diff --git a/src/main/java/org/bukkit/Art.java b/src/main/java/org/bukkit/Art.java +index d24bf449f58fd7c1b8ffab8dbc42f9f1fef8c4ef..a53e59e030aea65a99806d5b0375cbb4b7457319 100644 +--- a/src/main/java/org/bukkit/Art.java ++++ b/src/main/java/org/bukkit/Art.java +@@ -97,6 +97,26 @@ public interface Art extends OldEnum, Keyed { + @Deprecated(since = "1.6.2") + int getId(); + ++ // Paper start - deprecate getKey ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#PAINTING_VARIANT}. Painting variants can exist without a key. ++ */ ++ @Deprecated(since = "1.21", forRemoval = true) ++ @Override ++ @NotNull NamespacedKey getKey(); ++ ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#PAINTING_VARIANT}. Painting variants can exist without a key. ++ */ ++ @Deprecated(since = "1.21", forRemoval = true) ++ @Override ++ default net.kyori.adventure.key.@org.jetbrains.annotations.NotNull Key key() { ++ return Keyed.super.key(); ++ } ++ // Paper end - deprecate getKey ++ + /** + * Get a painting by its numeric ID + * +diff --git a/src/main/java/org/bukkit/MusicInstrument.java b/src/main/java/org/bukkit/MusicInstrument.java +index 3b107e35f006cb1a0745778d99dab0783c67d4d8..d41892af5253623112fb3f8c53958c7914609e30 100644 +--- a/src/main/java/org/bukkit/MusicInstrument.java ++++ b/src/main/java/org/bukkit/MusicInstrument.java +@@ -47,6 +47,27 @@ public abstract class MusicInstrument implements Keyed, net.kyori.adventure.tran + return Registry.INSTRUMENT.getOrThrow(NamespacedKey.minecraft(key)); + } + ++ // Paper start - deprecate getKey ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#INSTRUMENT}. MusicInstruments can exist without a key. ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.5") ++ @Override ++ public abstract @NotNull NamespacedKey getKey(); ++ ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#INSTRUMENT}. MusicInstruments can exist without a key. ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.5") ++ @Override ++ public net.kyori.adventure.key.@org.jetbrains.annotations.NotNull Key key() { ++ return Keyed.super.key(); ++ } ++ ++ // Paper end - deprecate getKey ++ + // Paper start - mark translation key as deprecated + /** + * @deprecated this method assumes that the instrument description +diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java +index b2bd12736d08fe72128142af4ca2022da8309f6d..c3d49f9c640eb390f507f9521a389cb7c172983a 100644 +--- a/src/main/java/org/bukkit/Registry.java ++++ b/src/main/java/org/bukkit/Registry.java +@@ -385,6 +385,79 @@ public interface Registry extends Iterable { + @Nullable + T get(@NotNull NamespacedKey key); + ++ // Paper start - improve Registry ++ /** ++ * Gets the object by its key or throws if it doesn't exist. ++ * ++ * @param key the key to get the object of in this registry ++ * @return the object for the key ++ * @throws java.util.NoSuchElementException if the key doesn't point to an object in the registry ++ */ ++ default @NotNull T getOrThrow(final net.kyori.adventure.key.@NotNull Key key) { ++ final T value = this.get(key); ++ if (value == null) { ++ throw new java.util.NoSuchElementException("No value for " + key + " in " + this); ++ } ++ return value; ++ } ++ ++ /** ++ * Gets the object by its key or throws if it doesn't exist. ++ * ++ * @param key the key to get the object of in this registry ++ * @return the object for the key ++ * @throws java.util.NoSuchElementException if the key doesn't point to an object in the registry ++ */ ++ default @NotNull T getOrThrow(final io.papermc.paper.registry.@NotNull TypedKey key) { ++ final T value = this.get(key); ++ if (value == null) { ++ throw new java.util.NoSuchElementException("No value for " + key + " in " + this); ++ } ++ return value; ++ } ++ ++ /** ++ * Gets the key for this object or throws if it doesn't exist. ++ *

      ++ * Some types can exist without being in a registry ++ * and such will have no key associated with them. This ++ * method throw an exception if it isn't in this registry. ++ * ++ * @param value the value to get the key of in this registry ++ * @return the key for the value ++ * @throws java.util.NoSuchElementException if the value doesn't exist in this registry ++ * @see #getKey(Keyed) ++ */ ++ default @NotNull NamespacedKey getKeyOrThrow(final @NotNull T value) { ++ Preconditions.checkArgument(value != null, "value cannot be null"); ++ final NamespacedKey key = this.getKey(value); ++ if (key == null) { ++ throw new java.util.NoSuchElementException(value + " has no key in " + this); ++ } ++ return key; ++ } ++ ++ /** ++ * Get the key for this object. ++ *

      ++ * Some types can exist without being in a registry ++ * and such will have no key associated with them. This ++ * method will return null. ++ * ++ * @param value the value to get the key of in this registry ++ * @return the key for the value or null if not in the registry ++ * @see #getKeyOrThrow(Keyed) ++ */ ++ default @Nullable NamespacedKey getKey(final @NotNull T value) { ++ Preconditions.checkArgument(value != null, "value cannot be null"); ++ //noinspection ConstantValue (it might not be in the future...) ++ if (value instanceof Keyed) { ++ return value.getKey(); ++ } ++ return null; ++ } ++ // Paper end - improve Registry ++ + /** + * Get the object by its key. + * +@@ -481,5 +554,12 @@ public interface Registry extends Iterable { + public Class getType() { + return this.type; + } ++ ++ // Paper start - improve Registry ++ @Override ++ public @NotNull NamespacedKey getKey(final @NotNull T value) { ++ return value.getKey(); ++ } ++ // Paper end - improve Registry + } + } +diff --git a/src/main/java/org/bukkit/Sound.java b/src/main/java/org/bukkit/Sound.java +index 779fd6dd572dea41e7e22464c9c6068a0fb71b9d..70d6dedcad934be38ec5dc3807ec946b0fe3b649 100644 +--- a/src/main/java/org/bukkit/Sound.java ++++ b/src/main/java/org/bukkit/Sound.java +@@ -1704,6 +1704,16 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. + return sound; + } + ++ // Paper start - deprecate getKey ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)} and {@link Registry#SOUNDS}. Sounds ++ * can exist without a key. ++ */ ++ @Deprecated(since = "1.20.5", forRemoval = true) ++ @Override ++ @NotNull NamespacedKey getKey(); ++ // Paper end - deprecate getKey ++ + /** + * @return an array of all known sounds. + * @deprecated use {@link Registry#iterator()}. +@@ -1715,6 +1725,11 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. + } + + // Paper start ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)} and {@link Registry#SOUNDS}. Sounds ++ * can exist without a key. ++ */ ++ @Deprecated(since = "1.20.5", forRemoval = true) + @Override + default net.kyori.adventure.key.@NotNull Key key() { + return this.getKey(); +diff --git a/src/main/java/org/bukkit/block/banner/PatternType.java b/src/main/java/org/bukkit/block/banner/PatternType.java +index b6aa112ffcf43c8854e4060a83117cdc311c937d..4620b39b3257a29f964f94a2ddef9c46a365baa1 100644 +--- a/src/main/java/org/bukkit/block/banner/PatternType.java ++++ b/src/main/java/org/bukkit/block/banner/PatternType.java +@@ -56,6 +56,23 @@ public interface PatternType extends OldEnum, Keyed { + PatternType FLOW = getType("flow"); + PatternType GUSTER = getType("guster"); + ++ // Paper start - deprecate getKey ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#BANNER_PATTERN}. PatternTypes can exist without a key. ++ */ ++ @Deprecated(since = "1.20.5", forRemoval = true) ++ @Override ++ default net.kyori.adventure.key.@org.jetbrains.annotations.NotNull Key key() { ++ return org.bukkit.Keyed.super.key(); ++ } ++ ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#BANNER_PATTERN}. PatternTypes can exist without a key. ++ */ ++ @Deprecated(since = "1.20.5", forRemoval = true) ++ // Paper end - deprecate getKey + @Override + @NotNull + public NamespacedKey getKey(); +diff --git a/src/main/java/org/bukkit/generator/structure/Structure.java b/src/main/java/org/bukkit/generator/structure/Structure.java +index 20a7fd27ba3a029d58dd18ad9b470ffaed8c9578..b6920f834f8f5992214734abd093af54fc01991c 100644 +--- a/src/main/java/org/bukkit/generator/structure/Structure.java ++++ b/src/main/java/org/bukkit/generator/structure/Structure.java +@@ -61,4 +61,24 @@ public abstract class Structure implements Keyed { + */ + @NotNull + public abstract StructureType getStructureType(); ++ // Paper start - deprecate getKey ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#STRUCTURE}. Structures can exist without a key. ++ */ ++ @Override ++ @Deprecated(since = "1.20.4", forRemoval = true) ++ public abstract @NotNull NamespacedKey getKey(); ++ ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#STRUCTURE}. Structures can exist without a key. ++ */ ++ @Override ++ @Deprecated(since = "1.20.4", forRemoval = true) ++ public net.kyori.adventure.key.@org.jetbrains.annotations.NotNull Key key() { ++ return org.bukkit.Keyed.super.key(); ++ } ++ ++ // Paper end - deprecate getKey + } +diff --git a/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java b/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java +index cc38bee3c412bef4767f08407c0f5559a113fce5..7e8a4b4ec625072cb4aff1f9e113d9d0c162dc8c 100644 +--- a/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java ++++ b/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java +@@ -78,4 +78,25 @@ public interface TrimMaterial extends Keyed, Translatable { + @Deprecated(forRemoval = true) + @org.jetbrains.annotations.NotNull String getTranslationKey(); + // Paper end - adventure ++ ++ // Paper start - Registry#getKey ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#TRIM_MATERIAL}. TrimMaterials can exist without a key. ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.4") ++ @Override ++ org.bukkit.@org.jetbrains.annotations.NotNull NamespacedKey getKey(); ++ ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#TRIM_MATERIAL}. TrimMaterials can exist without a key. ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.4") ++ @Override ++ default net.kyori.adventure.key.@org.jetbrains.annotations.NotNull Key key() { ++ return org.bukkit.Keyed.super.key(); ++ } ++ ++ // Paper end - Registry#getKey + } +diff --git a/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java b/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java +index 56cfe665daba1754e41f633d7c18172bebf87028..b2fa0d565b2492aa812b0ac036ecd74889f67f76 100644 +--- a/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java ++++ b/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java +@@ -106,4 +106,24 @@ public interface TrimPattern extends Keyed, Translatable { + @Deprecated(forRemoval = true) + @org.jetbrains.annotations.NotNull String getTranslationKey(); + // Paper end - adventure ++ ++ // Paper start - Registry#getKey ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#TRIM_PATTERN}. TrimPatterns can exist without a key. ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.4") ++ @Override ++ org.bukkit.@org.jetbrains.annotations.NotNull NamespacedKey getKey(); ++ ++ /** ++ * @deprecated use {@link Registry#getKey(Keyed)}, {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)}, ++ * and {@link io.papermc.paper.registry.RegistryKey#TRIM_PATTERN}. TrimPatterns can exist without a key. ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.4") ++ @Override ++ default net.kyori.adventure.key.@org.jetbrains.annotations.NotNull Key key() { ++ return org.bukkit.Keyed.super.key(); ++ } ++ // Paper end - Registry#getKey + } diff --git a/patches/api/0430-Add-experience-points-API.patch b/patches/api/0430-Add-experience-points-API.patch new file mode 100644 index 000000000000..8951bfce950f --- /dev/null +++ b/patches/api/0430-Add-experience-points-API.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lukas Planz +Date: Tue, 5 Sep 2023 20:33:52 +0200 +Subject: [PATCH] Add experience points API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index d84fe3e439f3b190b7bbec15f406cc3a393dccfc..a7a4e5423cedb67bcdf02738be62bdf83e748b82 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -1947,6 +1947,45 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param exp New total experience points + */ + public void setTotalExperience(int exp); ++ // Paper start ++ /** ++ * Gets the players total amount of experience points he collected to reach the current level and level progress. ++ * ++ *

      This method differs from {@link #getTotalExperience()} in that this method always returns an ++ * up-to-date value that reflects the players{@link #getLevel() level} and {@link #getExp() level progress}

      ++ * ++ * @return Current total experience points ++ * @see #getLevel() ++ * @see #getExp() ++ * @see #setExperienceLevelAndProgress(int) ++ */ ++ @org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE) int calculateTotalExperiencePoints(); ++ ++ /** ++ * Updates the players level and level progress to that what would be reached when the total amount of experience ++ * had been collected. ++ * ++ *

      This method differs from {@link #setTotalExperience(int)} in that this method actually updates the ++ * {@link #getLevel() level} and {@link #getExp() level progress} so that a subsequent call of ++ * {@link #calculateTotalExperiencePoints()} yields the same amount of points that have been set

      ++ * ++ * @param totalExperience New total experience points ++ * @see #setLevel(int) ++ * @see #setExp(float) ++ * @see #calculateTotalExperiencePoints() ++ */ ++ void setExperienceLevelAndProgress(@org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE) int totalExperience); ++ ++ /** ++ * Gets the total amount of experience points that are needed to reach the next level from zero progress towards it. ++ * ++ *

      Can be used with {@link #getExp()} to calculate the current points for the current level and alike

      ++ * ++ * @return The required experience points ++ * @see #getExp() ++ */ ++ int getExperiencePointsNeededForNextLevel(); ++ // Paper end + + /** + * Send an experience change. diff --git a/patches/api/0431-Add-missing-InventoryType.patch b/patches/api/0431-Add-missing-InventoryType.patch new file mode 100644 index 000000000000..d3d0cd545825 --- /dev/null +++ b/patches/api/0431-Add-missing-InventoryType.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 27 Dec 2023 16:46:13 -0800 +Subject: [PATCH] Add missing InventoryType + +Upstream did not add a DECORATED_POT inventory type + +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java +index e0d73d432cd31da35a72b479c854f2124c63ebe5..81118a91c2e22e02a1f774d1cc4d3e97064087ce 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java +@@ -145,6 +145,12 @@ public enum InventoryType { + * Pseudo jukebox inventory with 1 slot of undefined type. + */ + JUKEBOX(1, "Jukebox", null, false), ++ // Paper start - add missing type ++ /** ++ * Pseudo decorated pot with 1 slot of undefined type. ++ */ ++ DECORATED_POT(1, "Decorated Pot", null, false), ++ // Paper end - add missing type + /** + * A crafter inventory, with 9 CRAFTING slots. + */ diff --git a/patches/api/0432-Add-drops-to-shear-events.patch b/patches/api/0432-Add-drops-to-shear-events.patch new file mode 100644 index 000000000000..abbab7dac401 --- /dev/null +++ b/patches/api/0432-Add-drops-to-shear-events.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 18 May 2021 12:31:54 -0700 +Subject: [PATCH] Add drops to shear events + + +diff --git a/src/main/java/org/bukkit/event/block/BlockShearEntityEvent.java b/src/main/java/org/bukkit/event/block/BlockShearEntityEvent.java +index 71c0af9373069cfaa074e1fbad592eab81025b1c..610768bd329b8612627d361fd9a773a7b91ff108 100644 +--- a/src/main/java/org/bukkit/event/block/BlockShearEntityEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockShearEntityEvent.java +@@ -17,11 +17,14 @@ public class BlockShearEntityEvent extends BlockEvent implements Cancellable { + private final Entity sheared; + private final ItemStack tool; + private boolean cancelled; ++ private java.util.List drops; // Paper + +- public BlockShearEntityEvent(@NotNull Block dispenser, @NotNull Entity sheared, @NotNull ItemStack tool) { ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper ++ public BlockShearEntityEvent(@NotNull Block dispenser, @NotNull Entity sheared, @NotNull ItemStack tool, final @NotNull java.util.List drops) { // Paper - custom shear drops + super(dispenser); + this.sheared = sheared; + this.tool = tool; ++ this.drops = drops; // Paper + } + + /** +@@ -64,4 +67,24 @@ public class BlockShearEntityEvent extends BlockEvent implements Cancellable { + public static HandlerList getHandlerList() { + return handlers; + } ++ // Paper start - custom shear drops ++ /** ++ * Get an immutable list of drops for this shearing. ++ * ++ * @return the shearing drops ++ * @see #setDrops(java.util.List) ++ */ ++ public java.util.@NotNull @org.jetbrains.annotations.Unmodifiable List getDrops() { ++ return java.util.Collections.unmodifiableList(this.drops); ++ } ++ ++ /** ++ * Sets the drops for the shearing. ++ * ++ * @param drops the shear drops ++ */ ++ public void setDrops(final java.util.@NotNull List drops) { ++ this.drops = java.util.List.copyOf(drops); ++ } ++ // Paper end - custom shear drops + } +diff --git a/src/main/java/org/bukkit/event/player/PlayerShearEntityEvent.java b/src/main/java/org/bukkit/event/player/PlayerShearEntityEvent.java +index 2616943d298c523e9fe71926f42b1362c9379853..3a12674e47f3e20a32ac1ea5647105196cf3a1c9 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerShearEntityEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerShearEntityEvent.java +@@ -18,17 +18,20 @@ public class PlayerShearEntityEvent extends PlayerEvent implements Cancellable { + private final Entity what; + private final ItemStack item; + private final EquipmentSlot hand; ++ private java.util.List drops; // Paper - custom shear drops + +- public PlayerShearEntityEvent(@NotNull Player who, @NotNull Entity what, @NotNull ItemStack item, @NotNull EquipmentSlot hand) { ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper ++ public PlayerShearEntityEvent(@NotNull Player who, @NotNull Entity what, @NotNull ItemStack item, @NotNull EquipmentSlot hand, final java.util.@NotNull List drops) { // Paper - custom shear drops + super(who); + this.what = what; + this.item = item; + this.hand = hand; ++ this.drops = drops; // Paper - custom shear drops + } + + @Deprecated(since = "1.15.2") + public PlayerShearEntityEvent(@NotNull final Player who, @NotNull final Entity what) { +- this(who, what, new ItemStack(Material.SHEARS), EquipmentSlot.HAND); ++ this(who, what, new ItemStack(Material.SHEARS), EquipmentSlot.HAND, java.util.Collections.emptyList()); // Paper - custom shear drops + } + + @Override +@@ -82,4 +85,24 @@ public class PlayerShearEntityEvent extends PlayerEvent implements Cancellable { + return handlers; + } + ++ // Paper start - custom shear drops ++ /** ++ * Get an immutable list of drops for this shearing. ++ * ++ * @return the shearing drops ++ * @see #setDrops(java.util.List) ++ */ ++ public java.util.@NotNull @org.jetbrains.annotations.Unmodifiable List getDrops() { ++ return this.drops; ++ } ++ ++ /** ++ * Sets the drops for the shearing. ++ * ++ * @param drops the shear drops ++ */ ++ public void setDrops(final java.util.@NotNull List drops) { ++ this.drops = java.util.List.copyOf(drops); ++ } ++ // Paper end - custom shear drops + } diff --git a/patches/api/0433-Add-HiddenPotionEffect-API.patch b/patches/api/0433-Add-HiddenPotionEffect-API.patch new file mode 100644 index 000000000000..1e0c0ad3671c --- /dev/null +++ b/patches/api/0433-Add-HiddenPotionEffect-API.patch @@ -0,0 +1,170 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tamion <70228790+notTamion@users.noreply.github.com> +Date: Sun, 5 Nov 2023 09:50:48 +0100 +Subject: [PATCH] Add HiddenPotionEffect API + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index 7cc29c7a9e2c30feaedaab188024387e12f51c75..ac86962fa3c0fb0c3138e98bd89d73b467a5fb60 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -591,6 +591,9 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + + /** + * Adds the given {@link PotionEffect} to the living entity. ++ *

      ++ * Note: {@link PotionEffect#getHiddenPotionEffect()} is ignored when ++ * adding the effect to the entity. + * + * @param effect PotionEffect to be added + * @return whether the effect could be added +@@ -615,6 +618,9 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + /** + * Attempts to add all of the given {@link PotionEffect} to the living + * entity. ++ *

      ++ * Note: {@link PotionEffect#getHiddenPotionEffect()} is ignored when ++ * adding the effect to the entity. + * + * @param effects the effects to add + * @return whether all of the effects could be added +diff --git a/src/main/java/org/bukkit/potion/PotionEffect.java b/src/main/java/org/bukkit/potion/PotionEffect.java +index 0d60a1b740199783d3fcb775f190ee85bd84696b..ab8f3c089ff50f4414d4c35810e65b2e73e2f678 100644 +--- a/src/main/java/org/bukkit/potion/PotionEffect.java ++++ b/src/main/java/org/bukkit/potion/PotionEffect.java +@@ -28,6 +28,7 @@ public class PotionEffect implements ConfigurationSerializable { + */ + public static final int INFINITE_DURATION = -1; + ++ private static final String HIDDEN_EFFECT = "hidden_effect"; // Paper + private static final String AMPLIFIER = "amplifier"; + private static final String DURATION = "duration"; + private static final String TYPE = "effect"; +@@ -40,6 +41,7 @@ public class PotionEffect implements ConfigurationSerializable { + private final boolean ambient; + private final boolean particles; + private final boolean icon; ++ private final PotionEffect hiddenEffect; // Paper + + /** + * Creates a potion effect. +@@ -50,8 +52,11 @@ public class PotionEffect implements ConfigurationSerializable { + * @param ambient the ambient status, see {@link PotionEffect#isAmbient()} + * @param particles the particle status, see {@link PotionEffect#hasParticles()} + * @param icon the icon status, see {@link PotionEffect#hasIcon()} ++ * @param hiddenEffect the hidden PotionEffect ++ * @hidden Internal-- hidden effects are only shown internally + */ +- public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon) { ++ @org.jetbrains.annotations.ApiStatus.Internal // Paper ++ public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon, @Nullable PotionEffect hiddenEffect) { // Paper + Preconditions.checkArgument(type != null, "effect type cannot be null"); + this.type = type; + this.duration = duration; +@@ -59,6 +64,23 @@ public class PotionEffect implements ConfigurationSerializable { + this.ambient = ambient; + this.particles = particles; + this.icon = icon; ++ // Paper start ++ this.hiddenEffect = hiddenEffect; ++ } ++ ++ /** ++ * Creates a potion effect. ++ * @param type effect type ++ * @param duration measured in ticks, see {@link ++ * PotionEffect#getDuration()} ++ * @param amplifier the amplifier, see {@link PotionEffect#getAmplifier()} ++ * @param ambient the ambient status, see {@link PotionEffect#isAmbient()} ++ * @param particles the particle status, see {@link PotionEffect#hasParticles()} ++ * @param icon the icon status, see {@link PotionEffect#hasIcon()} ++ */ ++ public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon) { ++ this(type, duration, amplifier, ambient, particles, icon, null); ++ // Paper end + } + + /** +@@ -106,7 +128,7 @@ public class PotionEffect implements ConfigurationSerializable { + * @param map the map to deserialize from + */ + public PotionEffect(@NotNull Map map) { +- this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true))); ++ this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true)), (PotionEffect) map.get(HIDDEN_EFFECT)); // Paper + } + + // Paper start +@@ -134,6 +156,19 @@ public class PotionEffect implements ConfigurationSerializable { + public PotionEffect withIcon(boolean icon) { + return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); + } ++ ++ /** ++ * Returns the PotionEffect that will become active ++ * after the current PotionEffect has run out. ++ *

      ++ * Note: This value is only applicable to type applied to living entities. ++ * ++ * @return The hidden PotionEffect. ++ */ ++ @Nullable ++ public PotionEffect getHiddenPotionEffect() { ++ return hiddenEffect; ++ } + // Paper end + + @NotNull +@@ -170,19 +205,27 @@ public class PotionEffect implements ConfigurationSerializable { + @Override + @NotNull + public Map serialize() { +- return ImmutableMap.builder() ++ ImmutableMap.Builder builder = ImmutableMap.builder() // Paper + .put(TYPE, type.getKey().toString()) + .put(DURATION, duration) + .put(AMPLIFIER, amplifier) + .put(AMBIENT, ambient) + .put(PARTICLES, particles) +- .put(ICON, icon) +- .build(); ++ .put(ICON, icon); ++ // Paper start ++ if (this.hiddenEffect != null) { ++ builder.put(HIDDEN_EFFECT, this.hiddenEffect); ++ } ++ return builder.build(); ++ // Paper end + } + + /** + * Attempts to add the effect represented by this object to the given + * {@link LivingEntity}. ++ *

      ++ * Note: {@link PotionEffect#getHiddenPotionEffect()} is ignored when ++ * adding the effect to the entity. + * + * @param entity The entity to add this effect to + * @return Whether the effect could be added +@@ -201,7 +244,7 @@ public class PotionEffect implements ConfigurationSerializable { + return false; + } + PotionEffect that = (PotionEffect) obj; +- return this.type.equals(that.type) && this.ambient == that.ambient && this.amplifier == that.amplifier && this.duration == that.duration && this.particles == that.particles && this.icon == that.icon; ++ return this.type.equals(that.type) && this.ambient == that.ambient && this.amplifier == that.amplifier && this.duration == that.duration && this.particles == that.particles && this.icon == that.icon && java.util.Objects.equals(this.hiddenEffect, that.hiddenEffect); // Paper + } + + /** +@@ -306,11 +349,12 @@ public class PotionEffect implements ConfigurationSerializable { + hash ^= 0x22222222 >> (ambient ? 1 : -1); + hash ^= 0x22222222 >> (particles ? 1 : -1); + hash ^= 0x22222222 >> (icon ? 1 : -1); ++ if (hiddenEffect != null) hash = hash * 31 + hiddenEffect.hashCode(); // Paper + return hash; + } + + @Override + public String toString() { +- return type.getName() + (ambient ? ":(" : ":") + duration + "t-x" + amplifier + (ambient ? ")" : ""); ++ return "PotionEffect{" + "amplifier=" + amplifier + ", duration=" + duration + ", type=" + type + ", ambient=" + ambient + ", particles=" + particles + ", icon=" + icon + ", hiddenEffect=" + hiddenEffect + '}'; // Paper + } + } diff --git a/patches/api/0434-Add-PlayerShieldDisableEvent.patch b/patches/api/0434-Add-PlayerShieldDisableEvent.patch new file mode 100644 index 000000000000..ddc6deadf570 --- /dev/null +++ b/patches/api/0434-Add-PlayerShieldDisableEvent.patch @@ -0,0 +1,113 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Mon, 1 May 2023 16:22:43 -0500 +Subject: [PATCH] Add PlayerShieldDisableEvent + +Called whenever a players shield is disabled. This is mainly caused by +attacking players or monsters that carry axes. + +The event, while similar to the PlayerItemCooldownEvent, offers other +behaviour and can hence not be implemented as a childtype of said event. +Specifically, cancelling the event prevents the game events from being +sent to the player. + +Plugins listening to just the PlayerItemCooldownEvent may not want said +sideeffects, meaning the disable event cannot share a handlerlist with +the cooldown event. + +diff --git a/src/main/java/io/papermc/paper/event/player/PlayerShieldDisableEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerShieldDisableEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..aa2fb7923b121cda547291d14cff60895361a4dd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/PlayerShieldDisableEvent.java +@@ -0,0 +1,90 @@ ++package io.papermc.paper.event.player; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called whenever a players shield is disabled due to an attack from another entity that was capable of disabling the ++ * shield. This, most commonly, may be another player attacking with an axe. ++ *

      ++ * Notably, this even is distinct from a {@link PlayerItemCooldownEvent} and will fire prior to the item going on ++ * cooldown. ++ * It follows that, if this event is cancelled, no {@link PlayerItemCooldownEvent} is called as the shield is never ++ * disabled in the first place. ++ */ ++@NullMarked ++public class PlayerShieldDisableEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Entity damager; ++ private int cooldown; ++ ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public PlayerShieldDisableEvent(final Player player, final Entity damager, final int cooldown) { ++ super(player); ++ this.damager = damager; ++ this.cooldown = cooldown; ++ } ++ ++ /** ++ * Provides the damager that disabled the shield. ++ * ++ * @return the entity instance that damaged the player in a way that caused the shield to be disabled. ++ */ ++ public Entity getDamager() { ++ return this.damager; ++ } ++ ++ /** ++ * Gets the cooldown the disabled shield will be disabled for in ticks. ++ *

      ++ * Notably, this value is not final as it might be changed by a {@link PlayerItemCooldownEvent} down the line, ++ * as said event is called if this event is not cancelled. ++ * ++ * @return cooldown in ticks ++ */ ++ public int getCooldown() { ++ return this.cooldown; ++ } ++ ++ /** ++ * Sets the cooldown of the shield in ticks. ++ *

      ++ * Notably, this value is not final as it might be changed by a {@link PlayerItemCooldownEvent} down the line, ++ * as said event is called if this event is not cancelled. ++ * ++ * @param cooldown cooldown in ticks, has to be a positive number ++ */ ++ public void setCooldown(final int cooldown) { ++ Preconditions.checkArgument(cooldown >= 0, "The cooldown has to be equal to or greater than 0!"); ++ this.cooldown = cooldown; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0435-Return-null-for-empty-String-in-NamespacedKey.fromSt.patch b/patches/api/0435-Return-null-for-empty-String-in-NamespacedKey.fromSt.patch new file mode 100644 index 000000000000..0701be14b5aa --- /dev/null +++ b/patches/api/0435-Return-null-for-empty-String-in-NamespacedKey.fromSt.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Sat, 6 Jan 2024 14:18:58 +0100 +Subject: [PATCH] Return null for empty String in NamespacedKey.fromString + + +diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java +index ceb1009252e25e244baab9208b7494666aebc508..6d266c111bfa2bd51338e03ed740f6ac81ed07c7 100644 +--- a/src/main/java/org/bukkit/NamespacedKey.java ++++ b/src/main/java/org/bukkit/NamespacedKey.java +@@ -90,7 +90,7 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key { // Pap + this.key = key; + + String string = toString(); +- Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters", string); ++ Preconditions.checkArgument(string.length() <= Short.MAX_VALUE, "NamespacedKey must be less than 32768 characters", string); // Paper - Fix improper length validation + } + + /** +@@ -117,7 +117,7 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key { // Pap + Preconditions.checkArgument(isValidKey(this.key), "Invalid key. Must be [a-z0-9/._-]: %s", this.key); + + String string = toString(); +- Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters (%s)", string); ++ Preconditions.checkArgument(string.length() <= Short.MAX_VALUE, "NamespacedKey must be less than 32768 characters", string); // Paper - Fix improper length validation + } + + @NotNull +@@ -205,7 +205,10 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key { // Pap + */ + @Nullable + public static NamespacedKey fromString(@NotNull String string, @Nullable Plugin defaultNamespace) { +- Preconditions.checkArgument(string != null && !string.isEmpty(), "Input string must not be empty or null"); ++ // Paper - Return null for empty string, check length ++ Preconditions.checkArgument(string != null, "Input string must not be null"); ++ if (string.isEmpty() || string.length() > Short.MAX_VALUE) return null; ++ // Paper end - Return null for empty string, check length + + String[] components = string.split(":", 3); + if (components.length > 2) { +diff --git a/src/test/java/org/bukkit/NamespacedKeyTest.java b/src/test/java/org/bukkit/NamespacedKeyTest.java +index 6317798e43332f34f79970ded0f023beee868fed..d4e9e24b705a7ac3e9f4fc27eefa44ecb16aa35c 100644 +--- a/src/test/java/org/bukkit/NamespacedKeyTest.java ++++ b/src/test/java/org/bukkit/NamespacedKeyTest.java +@@ -29,6 +29,7 @@ public class NamespacedKeyTest { + assertNull(NamespacedKey.fromString("foo:bar:bazz")); + } + ++ @org.junit.jupiter.api.Disabled // Paper - Fixup NamespacedKey handling + @Test + public void testFromStringEmptyInput() { + assertThrows(IllegalArgumentException.class, () -> NamespacedKey.fromString("")); +@@ -75,6 +76,7 @@ public class NamespacedKeyTest { + "loremipsumdolorsitametconsecteturadipiscingelitduisvolutpatvelitsitametmaximusscelerisquemorbiullamcorperexacconsequategestas").toString(); + } + ++ @org.junit.jupiter.api.Disabled // Paper - Fixup NamespacedKey handling + @Test + public void testAboveLength() { + assertThrows(IllegalArgumentException.class, () -> new NamespacedKey("loremipsumdolorsitametconsecteturadipiscingelitduisvolutpatvelitsitametmaximusscelerisquemorbiullamcorperexacconsequategestas", diff --git a/patches/api/0436-Add-BlockStateMeta-clearBlockState.patch b/patches/api/0436-Add-BlockStateMeta-clearBlockState.patch new file mode 100644 index 000000000000..7e8c47a8e2be --- /dev/null +++ b/patches/api/0436-Add-BlockStateMeta-clearBlockState.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 11 Jan 2024 12:41:54 -0800 +Subject: [PATCH] Add BlockStateMeta#clearBlockState + + +diff --git a/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java b/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java +index c7d3041221742f6655155f19ef2addcaf2401015..dedb33e3d7f99e12fddba438af0874e6973d9372 100644 +--- a/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java +@@ -14,6 +14,13 @@ public interface BlockStateMeta extends ItemMeta { + */ + boolean hasBlockState(); + ++ // Paper start - add method to clear block state ++ /** ++ * Clears the block state currently attached to this item. ++ */ ++ void clearBlockState(); ++ // Paper end - add method to clear block state ++ + /** + * Returns the currently attached block state for this + * item or creates a new one if one doesn't exist. diff --git a/patches/api/0437-Expose-LootTable-of-DecoratedPot.patch b/patches/api/0437-Expose-LootTable-of-DecoratedPot.patch new file mode 100644 index 000000000000..1004281c9ae3 --- /dev/null +++ b/patches/api/0437-Expose-LootTable-of-DecoratedPot.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: FireInstall +Date: Sat, 20 Jan 2024 16:20:07 +0100 +Subject: [PATCH] Expose LootTable of DecoratedPot + + +diff --git a/src/main/java/org/bukkit/block/DecoratedPot.java b/src/main/java/org/bukkit/block/DecoratedPot.java +index a04df8105a462eac3a4a8eb04eac70fdd979d0e3..8c0e946ead8b7d9e2e6e94b0533564eb26653092 100644 +--- a/src/main/java/org/bukkit/block/DecoratedPot.java ++++ b/src/main/java/org/bukkit/block/DecoratedPot.java +@@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a captured state of a decorated pot. + */ +-public interface DecoratedPot extends TileState, BlockInventoryHolder { ++public interface DecoratedPot extends TileState, BlockInventoryHolder , org.bukkit.loot.Lootable { // Paper - expose loot table + + /** + * Set the sherd on the provided side. diff --git a/patches/api/0438-Add-ShulkerDuplicateEvent.patch b/patches/api/0438-Add-ShulkerDuplicateEvent.patch new file mode 100644 index 000000000000..bed71db2554d --- /dev/null +++ b/patches/api/0438-Add-ShulkerDuplicateEvent.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chase Henderson +Date: Fri, 5 Jan 2024 03:50:10 -0500 +Subject: [PATCH] Add ShulkerDuplicateEvent + + +diff --git a/src/main/java/io/papermc/paper/event/entity/ShulkerDuplicateEvent.java b/src/main/java/io/papermc/paper/event/entity/ShulkerDuplicateEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d427a67a5c7e44aee78d21a7b344b8bb19235dc7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/entity/ShulkerDuplicateEvent.java +@@ -0,0 +1,68 @@ ++package io.papermc.paper.event.entity; ++ ++import org.bukkit.entity.Shulker; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired when a shulker duplicates itself by spawning a new shulker. ++ *

      ++ * The event is fired prior to the newly created shulker, accessible via {@link #getEntity()}, being added to the world. ++ */ ++@NullMarked ++public class ShulkerDuplicateEvent extends EntityEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final Shulker parent; ++ private boolean cancelled; ++ ++ @ApiStatus.Internal ++ public ShulkerDuplicateEvent(final Shulker child, final Shulker parent) { ++ super(child); ++ this.parent = parent; ++ } ++ ++ /** ++ * Provides the newly created shulker, which did not exist prior to the duplication. ++ * At the point of this event, said shulker is not part of the world yet. ++ * ++ * @return the newly duplicated shulker. ++ */ ++ @Override ++ public Shulker getEntity() { ++ return (Shulker) super.getEntity(); ++ } ++ ++ /** ++ * Provides the "parent" of the freshly created shulker. ++ * The parent shulker is the one that initiated the duplication. ++ * ++ * @return the previously existing shulker which duplicated. ++ */ ++ public Shulker getParent() { ++ return this.parent; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0439-Add-api-for-spawn-egg-texture-colors.patch b/patches/api/0439-Add-api-for-spawn-egg-texture-colors.patch new file mode 100644 index 000000000000..cce28b1bfae7 --- /dev/null +++ b/patches/api/0439-Add-api-for-spawn-egg-texture-colors.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Luis +Date: Thu, 11 Jan 2024 19:58:17 +0100 +Subject: [PATCH] Add api for spawn egg texture colors + + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 8e0877321edb26e1dbdb3570a62814d06c0616af..ffe382002c66d7d3fc539c3269261ca1fab4aa2a 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -258,4 +258,17 @@ public interface UnsafeValues { + // Paper end - namespaced key biome methods + + String getStatisticCriteriaKey(@NotNull org.bukkit.Statistic statistic); // Paper - fix custom stats criteria creation ++ ++ // Paper start - spawn egg color visibility ++ /** ++ * Obtains the underlying color informating for a spawn egg of a given ++ * entity type, or null if the entity passed does not have a spawn egg. ++ * Spawn eggs have two colors - the background layer (0), and the ++ * foreground layer (1) ++ * @param entityType The entity type to get the color for ++ * @param layer The texture layer to get a color for ++ * @return The color of the layer for the entity's spawn egg ++ */ ++ @Nullable org.bukkit.Color getSpawnEggLayerColor(org.bukkit.entity.EntityType entityType, int layer); ++ // Paper end - spawn egg color visibility + } diff --git a/patches/api/0440-Add-Lifecycle-Event-system.patch b/patches/api/0440-Add-Lifecycle-Event-system.patch new file mode 100644 index 000000000000..60bb62f8ce7a --- /dev/null +++ b/patches/api/0440-Add-Lifecycle-Event-system.patch @@ -0,0 +1,646 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 18 Jul 2023 14:47:02 -0700 +Subject: [PATCH] Add Lifecycle Event system + +This event system is separate from Bukkit's event system and is +meant for managing resources across reloads and from points in the +PluginBootstrap. + +diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java +index 4c47414fc08e1183b1e59369bacc4d7f7042f262..577a9d5aeae55a3b8452b6d873b51b30384c1fea 100644 +--- a/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java ++++ b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java +@@ -1,5 +1,7 @@ + package io.papermc.paper.plugin.bootstrap; + ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; + import org.jetbrains.annotations.ApiStatus; + import org.jspecify.annotations.NullMarked; + +@@ -12,5 +14,13 @@ import org.jspecify.annotations.NullMarked; + @ApiStatus.Experimental + @NullMarked + @ApiStatus.NonExtendable +-public interface BootstrapContext extends PluginProviderContext { ++public interface BootstrapContext extends PluginProviderContext, LifecycleEventOwner { ++ ++ /** ++ * Get the lifecycle event manager for registering handlers ++ * for lifecycle events allowed on the {@link BootstrapContext}. ++ * ++ * @return the lifecycle event manager ++ */ ++ LifecycleEventManager getLifecycleManager(); + } +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0b8eafd3e79494d4a750cd9182387fbaead24011 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEvent.java +@@ -0,0 +1,17 @@ ++package io.papermc.paper.plugin.lifecycle.event; ++ ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Base type for all Lifecycle Events. ++ *

      ++ * Lifecycle events are generally fired when the older ++ * event system is not available, like during early ++ * server initialization. ++ * @see LifecycleEvents ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface LifecycleEvent { ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventManager.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e05cdb7ab166f92e270ea1b85e75f465878d05f2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventManager.java +@@ -0,0 +1,53 @@ ++package io.papermc.paper.plugin.lifecycle.event; ++ ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Manages a plugin's lifecycle events. Can be obtained ++ * from {@link org.bukkit.plugin.Plugin} or {@link io.papermc.paper.plugin.bootstrap.BootstrapContext}. ++ * ++ * @param the owning type, {@link org.bukkit.plugin.Plugin} or {@link io.papermc.paper.plugin.bootstrap.BootstrapContext} ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface LifecycleEventManager { ++ ++ /** ++ * Registers an event handler for a specific event type. ++ *

      ++ * This is shorthand for creating a new {@link LifecycleEventHandlerConfiguration} and ++ * just passing in the {@link LifecycleEventHandler}. ++ *

      {@code
      ++     * LifecycleEventHandler> handler = new Handler();
      ++     * manager.registerEventHandler(LifecycleEvents.COMMANDS, handler);
      ++     * }
      ++ * is equivalent to ++ *
      {@code
      ++     * LifecycleEventHandler> handler = new Handler();
      ++     * manager.registerEventHandler(LifecycleEvents.COMMANDS.newHandler(handler));
      ++     * }
      ++ * ++ * @param eventType the event type to listen to ++ * @param eventHandler the handler for that event ++ * @param the type of the event object ++ */ ++ default void registerEventHandler(final LifecycleEventType eventType, final LifecycleEventHandler eventHandler) { ++ this.registerEventHandler(eventType.newHandler(eventHandler)); ++ } ++ ++ /** ++ * Registers an event handler configuration. ++ *

      ++ * Configurations are created via {@link LifecycleEventType#newHandler(LifecycleEventHandler)}. ++ * Event types may have different configurations options available on the builder-like object ++ * returned by {@link LifecycleEventType#newHandler(LifecycleEventHandler)}. ++ * ++ * @param handlerConfiguration the handler configuration to register ++ */ ++ void registerEventHandler(LifecycleEventHandlerConfiguration handlerConfiguration); ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventOwner.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventOwner.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ce5891eb110464a1c0cd7416712110851d010a1b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventOwner.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.plugin.lifecycle.event; ++ ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Implemented by types that are considered owners ++ * of registered handlers for lifecycle events. Generally ++ * the types that implement this interface also provide ++ * a {@link LifecycleEventManager} where you can register ++ * event handlers. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface LifecycleEventOwner { ++ ++ /** ++ * Get the plugin meta for this plugin. ++ * ++ * @return the plugin meta ++ */ ++ PluginMeta getPluginMeta(); ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/LifecycleEventHandler.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/LifecycleEventHandler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3093ef23dd92f86240854065f7a7bb6c11ecf4fe +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/LifecycleEventHandler.java +@@ -0,0 +1,19 @@ ++package io.papermc.paper.plugin.lifecycle.event.handler; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A handler for a specific event. Can be implemented ++ * in a concrete class or as a lambda. ++ * ++ * @param the event ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@FunctionalInterface ++public interface LifecycleEventHandler { ++ ++ void run(E event); ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/LifecycleEventHandlerConfiguration.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/LifecycleEventHandlerConfiguration.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9b9f4655f222597b4e00519cfe128147bc438367 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/LifecycleEventHandlerConfiguration.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.plugin.lifecycle.event.handler.configuration; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Base type for constructing configured event handlers for ++ * lifecycle events. Usually created via {@link io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType#newHandler(LifecycleEventHandler)} ++ * from event types in {@link io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents} ++ * ++ * @param ++ */ ++@SuppressWarnings("unused") ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface LifecycleEventHandlerConfiguration { ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfiguration.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfiguration.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a2acc6e3867d6805c68e4c630aca3d14aa958a1d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfiguration.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.plugin.lifecycle.event.handler.configuration; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Handler configuration for event types that allow "monitor" handlers. ++ * ++ * @param the required owner type ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface MonitorLifecycleEventHandlerConfiguration extends LifecycleEventHandlerConfiguration { ++ ++ /** ++ * Sets this handler configuration to be considered a "monitor". ++ * These handlers will run last and should only be used by plugins ++ * to observe changes from previously run handlers. ++ * ++ * @return this configuration for chaining ++ */ ++ @Contract("-> this") ++ MonitorLifecycleEventHandlerConfiguration monitor(); ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfiguration.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfiguration.java +new file mode 100644 +index 0000000000000000000000000000000000000000..100e5d169f1f644e54a042c697649f08fff1e6de +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfiguration.java +@@ -0,0 +1,41 @@ ++package io.papermc.paper.plugin.lifecycle.event.handler.configuration; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Handler configuration that allows both "monitor" and prioritized handlers. ++ * The default priority is 0. ++ * ++ * @param the required owner type ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface PrioritizedLifecycleEventHandlerConfiguration extends LifecycleEventHandlerConfiguration { ++ ++ /** ++ * Sets the priority for this handler. Resets ++ * all previous calls to {@link #monitor()}. A ++ * lower numeric value correlates to the handler ++ * being run earlier. ++ * ++ * @param priority the numerical priority ++ * @return this configuration for chaining ++ */ ++ @Contract("_ -> this") ++ PrioritizedLifecycleEventHandlerConfiguration priority(int priority); ++ ++ /** ++ * Sets this handler configuration to be considered a "monitor". ++ * These handlers will run last and should only be used by plugins ++ * to observe any changes from previously ran handlers. ++ * ++ * @return this configuration for chaining ++ */ ++ @Contract("-> this") ++ PrioritizedLifecycleEventHandlerConfiguration monitor(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/Registrar.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/Registrar.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fd9c3605a8f5e6bdd31e42f18a45154d4074eb67 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/Registrar.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.plugin.lifecycle.event.registrar; ++ ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * To be implemented by types that provide ways to register types ++ * either on server start or during a reload ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface Registrar { ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7dca6be092a8b5deca9c45b152a96ffe72fe2533 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEvent.java +@@ -0,0 +1,28 @@ ++package io.papermc.paper.plugin.lifecycle.event.registrar; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A lifecycle event that exposes a {@link Registrar} of some kind ++ * to allow management of various things. Look at implementations of ++ * {@link Registrar} for an idea of what uses this event. ++ * ++ * @param registrar type ++ * @see ReloadableRegistrarEvent ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface RegistrarEvent extends LifecycleEvent { ++ ++ /** ++ * Get the registrar related to this event. ++ * ++ * @return the registrar ++ */ ++ @Contract(pure = true) ++ R registrar(); ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/ReloadableRegistrarEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/ReloadableRegistrarEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9bce1c13c8092238939fbbec6b499d1ca85e5b89 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/ReloadableRegistrarEvent.java +@@ -0,0 +1,39 @@ ++package io.papermc.paper.plugin.lifecycle.event.registrar; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A lifecycle event that exposes a {@link Registrar} that is ++ * reloadable. ++ * ++ * @param the registrar type ++ * @see RegistrarEvent ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface ReloadableRegistrarEvent extends RegistrarEvent { ++ ++ /** ++ * Get the cause of this reload. ++ * ++ * @return the cause ++ */ ++ @Contract(pure = true) ++ Cause cause(); ++ ++ @ApiStatus.Experimental ++ enum Cause { ++ /** ++ * The initial load of the server. ++ */ ++ INITIAL, ++ /** ++ * A reload, triggered via one of the various mechanisms like ++ * the bukkit or minecraft reload commands. ++ */ ++ RELOAD ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..75d9e20f53735ead4fa4aec478b4b72b85ca5e1e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventType.java +@@ -0,0 +1,74 @@ ++package io.papermc.paper.plugin.lifecycle.event.types; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.MonitorLifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Base type for all types of lifecycle events. Differs from ++ * {@link LifecycleEvent} which is the actual event object, whereas ++ * this is an object representing the type of the event. Used ++ * to construct subtypes of {@link LifecycleEventHandlerConfiguration} for ++ * use in {@link LifecycleEventManager} ++ * ++ * @param the required owner type ++ * @param the event object type ++ * @param the configuration type ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface LifecycleEventType> { ++ ++ /** ++ * Gets the name of the lifecycle event. ++ * ++ * @return the name ++ */ ++ @Contract(pure = true) ++ String name(); ++ ++ /** ++ * Create a configuration for this event with the specified ++ * handler. ++ * ++ * @param handler the event handler ++ * @return a new configuration ++ * @see LifecycleEventManager#registerEventHandler(LifecycleEventHandlerConfiguration) ++ */ ++ @Contract("_ -> new") ++ C newHandler(LifecycleEventHandler handler); ++ ++ /** ++ * Lifecycle event type that supports separate registration ++ * of handlers as "monitors" that are run last. Useful ++ * if a plugin wants to only observe the changes other handlers ++ * made. ++ * ++ * @param the required owner type ++ * @param the event object type ++ */ ++ @ApiStatus.Experimental ++ @ApiStatus.NonExtendable ++ interface Monitorable extends LifecycleEventType> { ++ } ++ ++ /** ++ * Lifecycle event type that supports both {@link Monitorable "monitors"} and ++ * specific numeric-based priorities. ++ * ++ * @param the required owner type ++ * @param the event object type ++ */ ++ @ApiStatus.Experimental ++ @ApiStatus.NonExtendable ++ interface Prioritizable extends LifecycleEventType> { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProvider.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProvider.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e15e09c2a4d3f43db6a0159fa8af6179362ea8d6 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProvider.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.plugin.lifecycle.event.types; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import java.util.Optional; ++import java.util.ServiceLoader; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@ApiStatus.Internal ++@NullMarked ++interface LifecycleEventTypeProvider { ++ ++ Optional INSTANCE = ServiceLoader.load(LifecycleEventTypeProvider.class) ++ .findFirst(); ++ ++ static LifecycleEventTypeProvider provider() { ++ return INSTANCE.orElseThrow(); ++ } ++ ++ LifecycleEventType.Monitorable monitor(String name, Class ownerType); ++ ++ LifecycleEventType.Prioritizable prioritized(String name, Class ownerType); ++} +diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f70814de0d6c40b2c1c9921b8abdd1162e1d3995 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java +@@ -0,0 +1,54 @@ ++package io.papermc.paper.plugin.lifecycle.event.types; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Holds various types of lifecycle events for ++ * use when creating event handler configurations ++ * in {@link LifecycleEventManager}. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++public final class LifecycleEvents { ++ ++ // ++ @ApiStatus.Internal ++ static LifecycleEventType.Monitorable plugin(final String name) { ++ return monitor(name, Plugin.class); ++ } ++ ++ @ApiStatus.Internal ++ static LifecycleEventType.Prioritizable pluginPrioritized(final String name) { ++ return prioritized(name, Plugin.class); ++ } ++ ++ @ApiStatus.Internal ++ static LifecycleEventType.Monitorable bootstrap(final String name) { ++ return monitor(name, BootstrapContext.class); ++ } ++ ++ @ApiStatus.Internal ++ static LifecycleEventType.Prioritizable bootstrapPrioritized(final String name) { ++ return prioritized(name, BootstrapContext.class); ++ } ++ ++ @ApiStatus.Internal ++ static LifecycleEventType.Monitorable monitor(final String name, final Class ownerType) { ++ return LifecycleEventTypeProvider.provider().monitor(name, ownerType); ++ } ++ ++ @ApiStatus.Internal ++ static LifecycleEventType.Prioritizable prioritized(final String name, final Class ownerType) { ++ return LifecycleEventTypeProvider.provider().prioritized(name, ownerType); ++ } ++ // ++ ++ private LifecycleEvents() { ++ } ++} +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index ffe382002c66d7d3fc539c3269261ca1fab4aa2a..159e96b1eedb0c97b624c338fefa1783336483e3 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -271,4 +271,12 @@ public interface UnsafeValues { + */ + @Nullable org.bukkit.Color getSpawnEggLayerColor(org.bukkit.entity.EntityType entityType, int layer); + // Paper end - spawn egg color visibility ++ ++ // Paper start - lifecycle event API ++ /** ++ * @hidden ++ */ ++ @org.jetbrains.annotations.ApiStatus.Internal ++ io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager createPluginLifecycleEventManager(final org.bukkit.plugin.java.JavaPlugin plugin, final java.util.function.BooleanSupplier registrationCheck); ++ // Paper end - lifecycle event API + } +diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java +index 46fc37a36403c8fbc4c0c9f863d4d57eb3896bd4..0ff8b53f900092dc419d61a8ede0a7cd72a2e1e1 100644 +--- a/src/main/java/org/bukkit/plugin/Plugin.java ++++ b/src/main/java/org/bukkit/plugin/Plugin.java +@@ -16,7 +16,7 @@ import org.jetbrains.annotations.Nullable; + *

      + * The use of {@link PluginBase} is recommended for actual Implementation + */ +-public interface Plugin extends TabExecutor { ++public interface Plugin extends TabExecutor, io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner { // Paper + /** + * Returns the folder that the plugin data files are located in. The + * folder may not yet exist. +@@ -224,4 +224,14 @@ public interface Plugin extends TabExecutor { + */ + @NotNull + public String getName(); ++ ++ // Paper start - lifecycle events ++ /** ++ * Get the lifecycle event manager for registering handlers ++ * for lifecycle events allowed on the {@link Plugin}. ++ * ++ * @return the lifecycle event manager ++ */ ++ io.papermc.paper.plugin.lifecycle.event.@NotNull LifecycleEventManager getLifecycleManager(); ++ // Paper end - lifecycle events + } +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +index 2d64fc065d53dcd8c01d05215c3e63aaf4428177..e0203f199700c397961a0667a79792497da7f796 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +@@ -48,6 +48,11 @@ public abstract class JavaPlugin extends PluginBase { + private FileConfiguration newConfig = null; + private File configFile = null; + private Logger logger = null; // Paper - PluginLogger -> Logger ++ // Paper start - lifecycle events ++ @SuppressWarnings("deprecation") ++ private final io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager lifecycleEventManager = org.bukkit.Bukkit.getUnsafe().createPluginLifecycleEventManager(this, () -> this.allowsLifecycleRegistration); ++ private boolean allowsLifecycleRegistration = true; ++ // Paper end + + public JavaPlugin() { + // Paper start +@@ -279,7 +284,9 @@ public abstract class JavaPlugin extends PluginBase { + isEnabled = enabled; + + if (isEnabled) { ++ try { // Paper - lifecycle events + onEnable(); ++ } finally { this.allowsLifecycleRegistration = false; } // Paper - lifecycle events + } else { + onDisable(); + } +@@ -457,4 +464,11 @@ public abstract class JavaPlugin extends PluginBase { + } + return plugin; + } ++ ++ // Paper start - lifecycle events ++ @Override ++ public final io.papermc.paper.plugin.lifecycle.event.@NotNull LifecycleEventManager getLifecycleManager() { ++ return this.lifecycleEventManager; ++ } ++ // Paper end - lifecycle events + } +diff --git a/src/test/java/org/bukkit/plugin/TestPlugin.java b/src/test/java/org/bukkit/plugin/TestPlugin.java +index 43b58e920e739bb949ac0673e9ef73ba7b500dc9..affe88cf8e98a787e197936f5fc443464a2343c6 100644 +--- a/src/test/java/org/bukkit/plugin/TestPlugin.java ++++ b/src/test/java/org/bukkit/plugin/TestPlugin.java +@@ -133,4 +133,11 @@ public class TestPlugin extends PluginBase { + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + throw new UnsupportedOperationException("Not supported."); + } ++ ++ // Paper start - lifecycle events ++ @Override ++ public io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager getLifecycleManager() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ // Paper end - lifecycle events + } diff --git a/patches/api/0441-ItemStack-Tooltip-API.patch b/patches/api/0441-ItemStack-Tooltip-API.patch new file mode 100644 index 000000000000..d7749819046b --- /dev/null +++ b/patches/api/0441-ItemStack-Tooltip-API.patch @@ -0,0 +1,148 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yannick Lamprecht +Date: Mon, 22 Jan 2024 13:27:18 +0100 +Subject: [PATCH] ItemStack Tooltip API + + +diff --git a/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContext.java b/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContext.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7e16f2645e956cbac8d0fc75ba8209f67fd1835c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContext.java +@@ -0,0 +1,76 @@ ++package io.papermc.paper.inventory.tooltip; ++ ++import org.bukkit.entity.Player; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Context for computing itemstack tooltips via ++ * {@link org.bukkit.inventory.ItemStack#computeTooltipLines(TooltipContext, Player)} ++ */ ++@NullMarked ++public interface TooltipContext { ++ ++ /** ++ * Creates a new context with the given advanced and creative ++ * mode settings. ++ * ++ * @param advanced whether the context is for advanced tooltips ++ * @param creative whether the context is for the creative inventory ++ * @return a new context ++ */ ++ @Contract("_, _ -> new") ++ static TooltipContext create(final boolean advanced, final boolean creative) { ++ return new TooltipContextImpl(advanced, creative); ++ } ++ ++ /** ++ * Creates a new context that is neither advanced nor creative. ++ * ++ * @return a new context ++ */ ++ @Contract("-> new") ++ static TooltipContext create() { ++ return new TooltipContextImpl(false, false); ++ } ++ ++ /** ++ * Returns whether the context is for advanced ++ * tooltips. ++ *

      ++ * Advanced tooltips are shown by default ++ * when a player has {@code F3+H} enabled. ++ * ++ * @return true if for advanced tooltips ++ */ ++ boolean isAdvanced(); ++ ++ /** ++ * Returns whether the context is for the creative ++ * mode inventory. ++ *

      ++ * Creative tooltips are shown by default when a player is ++ * in the creative inventory. ++ * ++ * @return true if for creative mode inventory ++ */ ++ boolean isCreative(); ++ ++ /** ++ * Returns a new context with {@link #isAdvanced()} ++ * set to true. ++ * ++ * @return a new context ++ */ ++ @Contract("-> new") ++ TooltipContext asAdvanced(); ++ ++ /** ++ * Returns a new context with {@link #isCreative()} ++ * set to true. ++ * ++ * @return a new context ++ */ ++ @Contract("-> new") ++ TooltipContext asCreative(); ++} +diff --git a/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContextImpl.java b/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContextImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a649b90dfac6000c01579a48234a11383c731439 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContextImpl.java +@@ -0,0 +1,17 @@ ++package io.papermc.paper.inventory.tooltip; ++ ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++record TooltipContextImpl(boolean isAdvanced, boolean isCreative) implements TooltipContext { ++ ++ @Override ++ public TooltipContext asCreative() { ++ return new TooltipContextImpl(this.isAdvanced, true); ++ } ++ ++ @Override ++ public TooltipContext asAdvanced() { ++ return new TooltipContextImpl(true, this.isCreative); ++ } ++} +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 159e96b1eedb0c97b624c338fefa1783336483e3..ff155bd22a6ea7f59dbf91c9280a653917b5010f 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -279,4 +279,6 @@ public interface UnsafeValues { + @org.jetbrains.annotations.ApiStatus.Internal + io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager createPluginLifecycleEventManager(final org.bukkit.plugin.java.JavaPlugin plugin, final java.util.function.BooleanSupplier registrationCheck); + // Paper end - lifecycle event API ++ ++ @NotNull java.util.List computeTooltipLines(@NotNull ItemStack itemStack, @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, @Nullable org.bukkit.entity.Player player); // Paper - expose itemstack tooltip lines + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index c3ae09dc66119cb2873201fb2975ad5e0f8237d2..0e6103628673130139363b53d23d3432deff5c50 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -1124,4 +1124,21 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + return type.isAir() || amount <= 0; + } + // Paper end ++ // Paper start - expose itemstack tooltip lines ++ /** ++ * Computes the tooltip lines for this stack. ++ *

      ++ * Disclaimer: ++ * Tooltip contents are not guaranteed to be consistent across different ++ * Minecraft versions. ++ * ++ * @param tooltipContext the tooltip context ++ * @param player a player for player-specific tooltip lines ++ * @return an immutable list of components (can be empty) ++ */ ++ @SuppressWarnings("deprecation") // abusing unsafe as a bridge ++ public java.util.@NotNull @org.jetbrains.annotations.Unmodifiable List computeTooltipLines(final @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, final @Nullable org.bukkit.entity.Player player) { ++ return Bukkit.getUnsafe().computeTooltipLines(this, tooltipContext, player); ++ } ++ // Paper end - expose itemstack tooltip lines + } diff --git a/patches/api/0442-Add-getChunkSnapshot-includeLightData-parameter.patch b/patches/api/0442-Add-getChunkSnapshot-includeLightData-parameter.patch new file mode 100644 index 000000000000..9b950f949339 --- /dev/null +++ b/patches/api/0442-Add-getChunkSnapshot-includeLightData-parameter.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Sat, 10 Feb 2024 10:05:59 +0100 +Subject: [PATCH] Add getChunkSnapshot includeLightData parameter + + +diff --git a/src/main/java/org/bukkit/Chunk.java b/src/main/java/org/bukkit/Chunk.java +index c2eb2edd87b4087bfcdffd98f0f8904fbfd4e657..bc8b5bc17706250b8535b1b309134843d2ce2bb1 100644 +--- a/src/main/java/org/bukkit/Chunk.java ++++ b/src/main/java/org/bukkit/Chunk.java +@@ -103,6 +103,23 @@ public interface Chunk extends PersistentDataHolder { + @NotNull + ChunkSnapshot getChunkSnapshot(boolean includeMaxblocky, boolean includeBiome, boolean includeBiomeTempRain); + ++ // Paper start - Add getChunkSnapshot includeLightData parameter ++ /** ++ * Capture thread-safe read-only snapshot of chunk data ++ * ++ * @param includeMaxblocky if true, snapshot includes per-coordinate ++ * maximum Y values ++ * @param includeBiome if true, snapshot includes per-coordinate biome ++ * type ++ * @param includeBiomeTempRain if true, snapshot includes per-coordinate ++ * raw biome temperature and rainfall ++ * @param includeLightData Whether to include per-coordinate light emitted by blocks and sky light data ++ * @return ChunkSnapshot ++ */ ++ @NotNull ++ ChunkSnapshot getChunkSnapshot(boolean includeMaxblocky, boolean includeBiome, boolean includeBiomeTempRain, boolean includeLightData); ++ // Paper end - Add getChunkSnapshot includeLightData parameter ++ + /** + * Checks if entities in this chunk are loaded. + * diff --git a/patches/api/0443-Add-FluidState-API.patch b/patches/api/0443-Add-FluidState-API.patch new file mode 100644 index 000000000000..8f786918cbb7 --- /dev/null +++ b/patches/api/0443-Add-FluidState-API.patch @@ -0,0 +1,165 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: vicisacat +Date: Fri, 17 Nov 2023 20:21:47 +0100 +Subject: [PATCH] Add FluidState API + + +diff --git a/src/main/java/io/papermc/paper/block/fluid/FluidData.java b/src/main/java/io/papermc/paper/block/fluid/FluidData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0750219fc68261e5c396636967e0b633ae17b72e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/block/fluid/FluidData.java +@@ -0,0 +1,69 @@ ++package io.papermc.paper.block.fluid; ++ ++import org.bukkit.Fluid; ++import org.bukkit.Location; ++import org.bukkit.util.Vector; ++import org.jetbrains.annotations.Range; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A representation of a fluid in a specific state of data. ++ * This type is not linked to a specific location and hence mostly resembles a {@link org.bukkit.block.data.BlockData}. ++ */ ++@NullMarked ++public interface FluidData extends Cloneable { ++ ++ /** ++ * Gets the fluid type of this fluid data. ++ * ++ * @return the fluid type ++ */ ++ Fluid getFluidType(); ++ ++ /** ++ * Returns a copy of this FluidData. ++ * ++ * @return a copy of the fluid data ++ */ ++ FluidData clone(); ++ ++ /** ++ * Computes the direction of the flow of the liquid at the given location as a vector. ++ *

      ++ * This method requires the passed location's chunk to be loaded. ++ * If said chunk is not loaded when this method is called, the chunk will first be loaded prior to the computation ++ * which leads to a potentially slow sync chunk load. ++ * ++ * @param location - the location to check the liquid flow ++ * @return the flow direction vector at the given location ++ */ ++ Vector computeFlowDirection(Location location); ++ ++ /** ++ * Returns the level of liquid this fluid data holds. ++ * ++ * @return the amount as an integer, between 0 and 8 ++ */ ++ @Range(from = 0, to = 8) ++ int getLevel(); ++ ++ /** ++ * Computes the height of the fluid in the world. ++ *

      ++ * This method requires the passed location's chunk to be loaded. ++ * If said chunk is not loaded when this method is called, the chunk will first be loaded prior to the computation ++ * which leads to a potentially slow sync chunk load. ++ * ++ * @param location the location at which to check the high of this fluid data. ++ * @return the height as a float value ++ */ ++ @Range(from = 0, to = 1) ++ float computeHeight(Location location); ++ ++ /** ++ * Returns whether this fluid is a source block ++ * ++ * @return true if the fluid is a source block, false otherwise ++ */ ++ boolean isSource(); ++} +diff --git a/src/main/java/io/papermc/paper/block/fluid/type/FallingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/FallingFluidData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7bd9f28ba646f09080b5c29b9d3be5af676c912e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/block/fluid/type/FallingFluidData.java +@@ -0,0 +1,16 @@ ++package io.papermc.paper.block.fluid.type; ++ ++import io.papermc.paper.block.fluid.FluidData; ++ ++/** ++ * A specific subtype of {@link FluidData} that is returned by the API for fluid data of potentially falling fluids. ++ */ ++public interface FallingFluidData extends FluidData { ++ ++ /** ++ * Get if this liquid is falling. ++ * ++ * @return true if falling ++ */ ++ boolean isFalling(); ++} +diff --git a/src/main/java/io/papermc/paper/block/fluid/type/FlowingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/FlowingFluidData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fbccdffe8d73e517204081c73bca9154f8c7d69f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/block/fluid/type/FlowingFluidData.java +@@ -0,0 +1,10 @@ ++package io.papermc.paper.block.fluid.type; ++ ++import io.papermc.paper.block.fluid.FluidData; ++ ++/** ++ * A specific subtype of {@link FluidData} that is returned by the API for fluid data of potentially falling fluids. ++ */ ++public interface FlowingFluidData extends FallingFluidData { ++ ++} +diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java +index 43dd6c59cceba12f27e6b265acc3ad97eea37abd..eb33e8e671972aa308ad75a7ce9aa9ac526f470f 100644 +--- a/src/main/java/org/bukkit/RegionAccessor.java ++++ b/src/main/java/org/bukkit/RegionAccessor.java +@@ -102,6 +102,41 @@ public interface RegionAccessor extends Keyed { // Paper + @NotNull + BlockState getBlockState(int x, int y, int z); + ++ // Paper start - FluidState API ++ /** ++ * Gets the {@link io.papermc.paper.block.fluid.FluidData} at the specified position. ++ * ++ * @param x The x-coordinate of the position ++ * @param y The y-coordinate of the position ++ * @param z The z-coordinate of the position ++ * @return The {@link io.papermc.paper.block.fluid.FluidData} at the specified position ++ */ ++ @NotNull ++ io.papermc.paper.block.fluid.FluidData getFluidData(int x, int y, int z); ++ ++ /** ++ * Gets the {@link io.papermc.paper.block.fluid.FluidData} at the given position ++ * ++ * @param position The position of the fluid ++ * @return The fluid data at the given position ++ */ ++ @NotNull ++ default io.papermc.paper.block.fluid.FluidData getFluidData(@NotNull io.papermc.paper.math.Position position) { ++ return getFluidData(position.blockX(), position.blockY(), position.blockZ()); ++ } ++ ++ /** ++ * Gets the {@link io.papermc.paper.block.fluid.FluidData} at the given position ++ * ++ * @param location The location of the fluid ++ * @return The fluid data at the given position ++ */ ++ @NotNull ++ default io.papermc.paper.block.fluid.FluidData getFluidData(@NotNull Location location) { ++ return getFluidData(location.blockX(), location.blockY(), location.blockZ()); ++ } ++ // Paper end ++ + /** + * Gets the {@link BlockData} at the given {@link Location}. + * diff --git a/patches/api/0444-add-number-format-api.patch b/patches/api/0444-add-number-format-api.patch new file mode 100644 index 000000000000..ac3ce0b6babe --- /dev/null +++ b/patches/api/0444-add-number-format-api.patch @@ -0,0 +1,234 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Mayr +Date: Sat, 16 Dec 2023 10:40:29 +0100 +Subject: [PATCH] add number format api + +Signed-off-by: David Mayr + +diff --git a/src/main/java/io/papermc/paper/scoreboard/numbers/BlankFormatImpl.java b/src/main/java/io/papermc/paper/scoreboard/numbers/BlankFormatImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..486da6ebe0137bb3280e8b33c8e35e309507f118 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/scoreboard/numbers/BlankFormatImpl.java +@@ -0,0 +1,5 @@ ++package io.papermc.paper.scoreboard.numbers; ++ ++record BlankFormatImpl() implements NumberFormat { ++ public static final BlankFormatImpl INSTANCE = new BlankFormatImpl(); ++} +diff --git a/src/main/java/io/papermc/paper/scoreboard/numbers/FixedFormat.java b/src/main/java/io/papermc/paper/scoreboard/numbers/FixedFormat.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3ef4595b692a13566c5c738050b83b0462094e9b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/scoreboard/numbers/FixedFormat.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.scoreboard.numbers; ++ ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.ComponentLike; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A scoreboard number format that replaces the score number with a chat component. ++ */ ++@NullMarked ++public interface FixedFormat extends NumberFormat, ComponentLike { ++ ++ /** ++ * The component shown instead of the number for a score ++ * ++ * @return the chat component ++ */ ++ Component component(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/scoreboard/numbers/FixedFormatImpl.java b/src/main/java/io/papermc/paper/scoreboard/numbers/FixedFormatImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..be47bf438805f9ab84b241e564281ea9c287aa6e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/scoreboard/numbers/FixedFormatImpl.java +@@ -0,0 +1,13 @@ ++package io.papermc.paper.scoreboard.numbers; ++ ++import net.kyori.adventure.text.Component; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++record FixedFormatImpl(Component component) implements FixedFormat { ++ ++ @Override ++ public Component asComponent() { ++ return this.component(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/scoreboard/numbers/NumberFormat.java b/src/main/java/io/papermc/paper/scoreboard/numbers/NumberFormat.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7c093e4e9a2a67021da9025631a3c6fa7ac3ef35 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/scoreboard/numbers/NumberFormat.java +@@ -0,0 +1,61 @@ ++package io.papermc.paper.scoreboard.numbers; ++ ++import net.kyori.adventure.text.ComponentLike; ++import net.kyori.adventure.text.format.Style; ++import net.kyori.adventure.text.format.StyleBuilderApplicable; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Describes a scoreboard number format that applies custom formatting to scoreboard scores. ++ */ ++@NullMarked ++public interface NumberFormat { ++ ++ /** ++ * Creates a blank scoreboard number format that removes the score number entirely. ++ * ++ * @return a blank number format ++ */ ++ static NumberFormat blank() { ++ return BlankFormatImpl.INSTANCE; ++ } ++ ++ /** ++ * Gets an un-styled number format. ++ * ++ * @return an un-styled number format ++ */ ++ static StyledFormat noStyle() { ++ return StyledFormatImpl.NO_STYLE; ++ } ++ ++ /** ++ * Creates a scoreboard number format that applies a custom formatting to the score number. ++ * ++ * @param style the style to apply on the number ++ * @return a styled number format ++ */ ++ static StyledFormat styled(final Style style) { ++ return new StyledFormatImpl(style); ++ } ++ ++ /** ++ * Creates a scoreboard number format that applies a custom formatting to the score number. ++ * ++ * @param styleBuilderApplicables the style to apply on the number ++ * @return a styled number format ++ */ ++ static StyledFormat styled(final StyleBuilderApplicable... styleBuilderApplicables) { ++ return styled(Style.style(styleBuilderApplicables)); ++ } ++ ++ /** ++ * Creates a scoreboard number format that replaces the score number with a chat component. ++ * ++ * @param component the component to replace the number with ++ * @return a fixed number format ++ */ ++ static FixedFormat fixed(final ComponentLike component) { ++ return new FixedFormatImpl(component.asComponent()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/scoreboard/numbers/StyledFormat.java b/src/main/java/io/papermc/paper/scoreboard/numbers/StyledFormat.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cfb14bb1b338727a5d9eeaa7a73c40540b04dbed +--- /dev/null ++++ b/src/main/java/io/papermc/paper/scoreboard/numbers/StyledFormat.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.scoreboard.numbers; ++ ++import net.kyori.adventure.text.format.Style; ++import net.kyori.adventure.text.format.StyleBuilderApplicable; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A scoreboard number format that applies a custom formatting to the score number. ++ */ ++@NullMarked ++public interface StyledFormat extends NumberFormat, StyleBuilderApplicable { ++ ++ /** ++ * The style that is being applied to the number in the score ++ * ++ * @return the style to apply ++ */ ++ Style style(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/scoreboard/numbers/StyledFormatImpl.java b/src/main/java/io/papermc/paper/scoreboard/numbers/StyledFormatImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e288beb1596f2d4e7e602364955da4e8bc0de21c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/scoreboard/numbers/StyledFormatImpl.java +@@ -0,0 +1,14 @@ ++package io.papermc.paper.scoreboard.numbers; ++ ++import net.kyori.adventure.text.format.Style; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++record StyledFormatImpl(Style style) implements StyledFormat { ++ static final StyledFormat NO_STYLE = new StyledFormatImpl(Style.empty()); ++ ++ @Override ++ public void styleApply(final Style.Builder style) { ++ style.merge(this.style); ++ } ++} +diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java +index d8a249bb2dd8ab96962897c2a52f40ea288f7bd6..d1016ee4282321d99734a251edfd93facb9b903f 100644 +--- a/src/main/java/org/bukkit/scoreboard/Objective.java ++++ b/src/main/java/org/bukkit/scoreboard/Objective.java +@@ -195,4 +195,22 @@ public interface Objective { + */ + void setAutoUpdateDisplay(boolean autoUpdateDisplay); + // Paper end - add more score API ++ ++ // Paper start - number format api ++ /** ++ * Gets the number format for this objective's scores or null if the client default is used. ++ * ++ * @return this objective's number format, or null if the client default is used ++ * @throws IllegalStateException if this objective has been unregistered ++ */ ++ @Nullable io.papermc.paper.scoreboard.numbers.NumberFormat numberFormat(); ++ ++ /** ++ * Sets the number format for this objective's scores. ++ * ++ * @param format the number format to set, pass null to reset format to default ++ * @throws IllegalStateException if this objective has been unregistered ++ */ ++ void numberFormat(@Nullable io.papermc.paper.scoreboard.numbers.NumberFormat format); ++ // Paper end - number format api + } +diff --git a/src/main/java/org/bukkit/scoreboard/Score.java b/src/main/java/org/bukkit/scoreboard/Score.java +index a3b482e07bb3dceb9b81d66c7208556a0bedd948..3600804874843975eb12b84b71b6848c68b2a244 100644 +--- a/src/main/java/org/bukkit/scoreboard/Score.java ++++ b/src/main/java/org/bukkit/scoreboard/Score.java +@@ -129,4 +129,26 @@ public interface Score { + */ + void customName(net.kyori.adventure.text.@Nullable Component customName); + // Paper end - add more score API ++ ++ // Paper start - number format api ++ /** ++ * Gets the number format for this score or null if the score has not been set yet ++ * or the objective's default is being used. ++ * ++ * @return this score's number format, or null if the objective's default is used or the score doesn't exist ++ * @throws IllegalStateException if the associated objective has been ++ * unregistered ++ */ ++ @Nullable io.papermc.paper.scoreboard.numbers.NumberFormat numberFormat(); ++ ++ /** ++ * Sets the number format for this score. If this score has not been set yet {@link #isScoreSet()}, it will be created ++ * ++ * @param format the number format to set, pass null to reset format to default ++ * @throws IllegalStateException if the associated objective has been ++ * unregistered ++ */ ++ void numberFormat(@Nullable io.papermc.paper.scoreboard.numbers.NumberFormat format); ++ // Paper end - number format api ++ + } diff --git a/patches/api/0445-improve-BanList-types.patch b/patches/api/0445-improve-BanList-types.patch new file mode 100644 index 000000000000..70d8b83c87ff --- /dev/null +++ b/patches/api/0445-improve-BanList-types.patch @@ -0,0 +1,133 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yannick Lamprecht +Date: Sat, 10 Feb 2024 20:49:47 +0100 +Subject: [PATCH] improve BanList types + + +diff --git a/src/main/java/io/papermc/paper/ban/BanListType.java b/src/main/java/io/papermc/paper/ban/BanListType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fdd5cfdc8c2c2ba97a3ac3db57be5a0e13dc327d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/ban/BanListType.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.ban; ++ ++import org.bukkit.BanList; ++import org.bukkit.ban.IpBanList; ++import org.bukkit.ban.ProfileBanList; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents a ban-type that a {@link BanList} may track. ++ * It enforces the correct return value at compile time. ++ */ ++@NullMarked ++public interface BanListType { ++ ++ /** ++ * Banned IP addresses ++ */ ++ BanListType IP = new BanListTypeImpl<>(IpBanList.class); ++ /** ++ * Banned player profiles ++ */ ++ BanListType PROFILE = new BanListTypeImpl<>(ProfileBanList.class); ++ ++ /** ++ * Returns the type class of the ban list used generically ++ * ++ * @return the type class ++ */ ++ Class typeClass(); ++} +diff --git a/src/main/java/io/papermc/paper/ban/BanListTypeImpl.java b/src/main/java/io/papermc/paper/ban/BanListTypeImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..26d4df3cbf8d31790218095bb7fb1a1762e2b322 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/ban/BanListTypeImpl.java +@@ -0,0 +1,9 @@ ++package io.papermc.paper.ban; ++ ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@ApiStatus.Internal ++@NullMarked ++record BanListTypeImpl(Class typeClass) implements BanListType { ++} +diff --git a/src/main/java/org/bukkit/BanList.java b/src/main/java/org/bukkit/BanList.java +index 60aea29d51a8ad499401f94a7c326d9b415b6a3a..bd06fe7cb5bf3268feae52d37357dca82206b991 100644 +--- a/src/main/java/org/bukkit/BanList.java ++++ b/src/main/java/org/bukkit/BanList.java +@@ -16,7 +16,9 @@ public interface BanList { + + /** + * Represents a ban-type that a {@link BanList} may track. ++ * @deprecated use {@link io.papermc.paper.ban.BanListType} to enforce the correct return value at compile time. + */ ++ @Deprecated(since = "1.20.4") // Paper - BanList Type Improvements + public enum Type { + /** + * Banned player names +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index c3c76dd82b209f6720afc51622aeb3fd92f1c0c2..8ab94f8189ebd9d4158231871abdebec399deb2c 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -1663,11 +1663,27 @@ public final class Bukkit { + * @param The ban target + * + * @return a ban list of the specified type ++ * @deprecated use {@link #getBanList(io.papermc.paper.ban.BanListType)} to enforce the correct return value at compile time. + */ + @NotNull ++ @Deprecated(since = "1.20.4") // Paper - add BanListType (which has a generic) + public static > T getBanList(@NotNull BanList.Type type) { + return server.getBanList(type); + } ++ // Paper start - add BanListType (which has a generic) ++ /** ++ * Gets a ban list for the supplied type. ++ * ++ * @param type the type of list to fetch, cannot be null ++ * @param The ban target ++ * ++ * @return a ban list of the specified type ++ */ ++ @NotNull ++ public static , E> B getBanList(final io.papermc.paper.ban.@NotNull BanListType type) { ++ return server.getBanList(type); ++ } ++ // Paper end - add BanListType (which has a generic) + + /** + * Gets a set containing all player operators. +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 1b968953fdf470bff32122bd06c4f83f27b97383..e187bb03006e84f08ca09c33ea182a76ae2d9d39 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1425,10 +1425,25 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @param The ban target + * + * @return a ban list of the specified type ++ * @deprecated use {@link #getBanList(io.papermc.paper.ban.BanListType)} to enforce the correct return value at compile time. + */ ++ @Deprecated // Paper - add BanListType (which has a generic) + @NotNull + public > T getBanList(@NotNull BanList.Type type); + ++ // Paper start - add BanListType (which has a generic) ++ /** ++ * Gets a ban list for the supplied type. ++ * ++ * @param type the type of list to fetch, cannot be null ++ * @param The ban target ++ * ++ * @return a ban list of the specified type ++ */ ++ @NotNull ++ , E> B getBanList(@NotNull io.papermc.paper.ban.BanListType type); ++ // Paper end - add BanListType (which has a generic) ++ + /** + * Gets a set containing all player operators. + * diff --git a/patches/api/0446-Suspicious-Effect-Entry-API.patch b/patches/api/0446-Suspicious-Effect-Entry-API.patch new file mode 100644 index 000000000000..d591d57ce9d1 --- /dev/null +++ b/patches/api/0446-Suspicious-Effect-Entry-API.patch @@ -0,0 +1,220 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Sun, 3 Mar 2024 19:45:52 +0100 +Subject: [PATCH] Suspicious Effect Entry API + +Exposes a new suspicious effect entry type that properly represents +storable effects in the context of suspicious effects as they only +define the potion effect type and duration. + +This differentiates them from the existing PotionEffect API found in +bukkit and hence clarifies that storable values in the parts of the API +in which it replaces PotionEffect. + +Co-authored-by: Yannick Lamprecht + +diff --git a/src/main/java/io/papermc/paper/potion/SuspiciousEffectEntry.java b/src/main/java/io/papermc/paper/potion/SuspiciousEffectEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6311ede3e3812da2ccdbcb19522facd7b2e3bd5c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/potion/SuspiciousEffectEntry.java +@@ -0,0 +1,39 @@ ++package io.papermc.paper.potion; ++ ++import org.bukkit.potion.PotionEffect; ++import org.bukkit.potion.PotionEffectType; ++import org.jetbrains.annotations.Contract; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Represents a {@link PotionEffectType} paired with a duration. ++ */ ++@NullMarked ++public sealed interface SuspiciousEffectEntry permits SuspiciousEffectEntryImpl { ++ ++ /** ++ * Gets the effect type. ++ * ++ * @return effect type ++ */ ++ PotionEffectType effect(); ++ ++ /** ++ * Gets the duration for this effect instance. ++ * ++ * @return duration (in ticks) or {@link PotionEffect#INFINITE_DURATION} ++ */ ++ int duration(); ++ ++ /** ++ * Creates a new instance of SuspiciousEffectEntry. ++ * ++ * @param effectType effect type ++ * @param duration duration (in ticks) or {@link PotionEffect#INFINITE_DURATION} ++ * @return new instance of an entry ++ */ ++ @Contract(value = "_, _ -> new", pure = true) ++ static SuspiciousEffectEntry create(final PotionEffectType effectType, final int duration) { ++ return new SuspiciousEffectEntryImpl(effectType, duration); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/potion/SuspiciousEffectEntryImpl.java b/src/main/java/io/papermc/paper/potion/SuspiciousEffectEntryImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a91d37ee450944ea779bd6b61d416467948bb55f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/potion/SuspiciousEffectEntryImpl.java +@@ -0,0 +1,10 @@ ++package io.papermc.paper.potion; ++ ++import org.bukkit.potion.PotionEffectType; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++@ApiStatus.Internal ++@NullMarked ++record SuspiciousEffectEntryImpl(PotionEffectType effect, int duration) implements SuspiciousEffectEntry { ++} +diff --git a/src/main/java/org/bukkit/entity/MushroomCow.java b/src/main/java/org/bukkit/entity/MushroomCow.java +index 86c0043ef4e1288b6fe2f68a9b6d01c3de2c3454..3677f19ef1c05b76d946b1b2b491a6c3cec76140 100644 +--- a/src/main/java/org/bukkit/entity/MushroomCow.java ++++ b/src/main/java/org/bukkit/entity/MushroomCow.java +@@ -34,14 +34,30 @@ public interface MushroomCow extends Cow, io.papermc.paper.entity.Shearable { // + * Adds a custom potion effect to be applied to the next suspicious stew + * received from milking this {@link MushroomCow}. + * ++ * @deprecated use {@link #addEffectToNextStew(io.papermc.paper.potion.SuspiciousEffectEntry, boolean)} as PotionEffect suggests that all attributes are used. In fact, only the PotionEffectType and the duration are used. + * @param effect the potion effect to add + * @param overwrite true if any existing effect of the same type should be + * overwritten + * @return true if the effects to be applied to the suspicious stew changed + * as a result of this call + */ ++ @Deprecated(forRemoval = true, since = "1.20.2") // Paper - add overloads to use suspicious effect entry to mushroom cow and suspicious stew meta + boolean addEffectToNextStew(@NotNull PotionEffect effect, boolean overwrite); + ++ // Paper start - add overloads to use suspicious effect entry to mushroom cow and suspicious stew meta ++ /** ++ * Adds a suspicious effect entry to be applied to the next suspicious stew ++ * received from milking this {@link MushroomCow}. ++ * ++ * @param suspiciousEffectEntry the suspicious effect entry to add ++ * @param overwrite true if any existing effect of the same type should be ++ * overwritten ++ * @return true if the effects to be applied to the suspicious stew changed ++ * as a result of this call ++ */ ++ boolean addEffectToNextStew(@NotNull io.papermc.paper.potion.SuspiciousEffectEntry suspiciousEffectEntry, boolean overwrite); ++ // Paper end - add overloads to use suspicious effect entry to mushroom cow and suspicious stew meta ++ + /** + * Removes a custom potion effect from being applied to the next suspicious + * stew received from milking this {@link MushroomCow}. +@@ -95,4 +111,75 @@ public interface MushroomCow extends Cow, io.papermc.paper.entity.Shearable { // + */ + BROWN; + } ++ // Paper start ++ /** ++ * Gets how long the effect applied to stew ++ * from this mushroom cow is. ++ * ++ * @return duration of the effect (in ticks) ++ * @deprecated Mushroom cows can now hold multiple effects, use {@link #getStewEffects()} ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.2") ++ @org.jetbrains.annotations.Contract("-> fail") ++ default int getStewEffectDuration() { ++ throw new UnsupportedOperationException("Mushroom cows can now hold multiple effects. Use #getStewEffects"); ++ } ++ ++ /** ++ * Sets how long the effect applied to stew ++ * from this mushroom cow is. ++ * ++ * @param duration duration of the effect (in ticks) ++ * @deprecated Mushroom cows can now hold multiple effects, use {@link #setStewEffects(java.util.List)} ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.2") ++ @org.jetbrains.annotations.Contract("_ -> fail") ++ default void setStewEffectDuration(int duration) { ++ throw new UnsupportedOperationException("Mushroom cows can now hold multiple effects. Use #setStewEffects"); ++ } ++ ++ /** ++ * Gets the type of effect applied to stew ++ * from this mushroom cow is. ++ * ++ * @return effect type, or null if an effect is currently not set ++ * @deprecated Mushroom cows can now hold multiple effects, use {@link #getStewEffects()} ++ * @throws UnsupportedOperationException ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.2") ++ @org.jetbrains.annotations.Contract("-> fail") ++ default org.bukkit.potion.PotionEffectType getStewEffectType() { ++ throw new UnsupportedOperationException("Mushroom cows can now hold multiple effects. Use #getStewEffects"); ++ } ++ ++ /** ++ * Sets the type of effect applied to stew ++ * from this mushroom cow is. ++ * ++ * @param type new effect type ++ * or null if this cow does not give effects ++ * @deprecated Mushroom cows can now hold multiple effects, use {@link #setStewEffects(java.util.List)} ++ * @throws UnsupportedOperationException ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.2") ++ @org.jetbrains.annotations.Contract("_ -> fail") ++ default void setStewEffect(@org.jetbrains.annotations.Nullable org.bukkit.potion.PotionEffectType type) { ++ throw new UnsupportedOperationException("Mushroom cows can now hold multiple effects. Use #setStewEffects"); ++ } ++ ++ /** ++ * Returns an immutable collection of the effects applied to stew ++ * items for this mushroom cow. ++ * ++ * @return immutable effect entry collection ++ */ ++ java.util.@NotNull @org.jetbrains.annotations.Unmodifiable List getStewEffects(); ++ ++ /** ++ * Sets effects applied to stew items for this mushroom cow. ++ * ++ * @param effects effect entry list ++ */ ++ void setStewEffects(java.util.@NotNull List effects); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/inventory/meta/SuspiciousStewMeta.java b/src/main/java/org/bukkit/inventory/meta/SuspiciousStewMeta.java +index c2f4282c188e7d8041459cb3acaad674443ba147..c5bfc062fcca56495f44039d83356fc1fd7568d0 100644 +--- a/src/main/java/org/bukkit/inventory/meta/SuspiciousStewMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/SuspiciousStewMeta.java +@@ -32,13 +32,28 @@ public interface SuspiciousStewMeta extends ItemMeta { + /** + * Adds a custom potion effect to this suspicious stew. + * ++ * @deprecated use {@link #addCustomEffect(io.papermc.paper.potion.SuspiciousEffectEntry, boolean)} as PotionEffect suggests that all attributes are used. In fact, only the PotionEffectType and the duration are used. + * @param effect the potion effect to add + * @param overwrite true if any existing effect of the same type should be + * overwritten + * @return true if the suspicious stew meta changed as a result of this call + */ ++ @Deprecated // Paper - add overloads to use suspicious effect entry to mushroom cow and suspicious stew meta + boolean addCustomEffect(@NotNull PotionEffect effect, boolean overwrite); + ++ // Paper start - add overloads to use suspicious effect entry to mushroom cow and suspicious stew meta ++ /** ++ * Adds a custom potion effect to this suspicious stew. ++ * ++ * @param suspiciousEffectEntry the suspicious effect entry to add ++ * @param overwrite true if any existing effect of the same type should be ++ * overwritten ++ * @return true if the suspicious stew meta changed as a result of this call ++ * as a result of this call ++ */ ++ boolean addCustomEffect(@NotNull io.papermc.paper.potion.SuspiciousEffectEntry suspiciousEffectEntry, boolean overwrite); ++ // Paper end - add overloads to use suspicious effect entry to mushroom cow and suspicious stew meta ++ + /** + * Removes a custom potion effect from this suspicious stew. + * diff --git a/patches/api/0447-Fix-DamageSource-API.patch b/patches/api/0447-Fix-DamageSource-API.patch new file mode 100644 index 000000000000..eec753daa546 --- /dev/null +++ b/patches/api/0447-Fix-DamageSource-API.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 16 Mar 2024 11:21:14 -0700 +Subject: [PATCH] Fix DamageSource API + + +diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java +index 341f99550d077c60306e8a246a254b768ebbeb48..31a36ed3baf44c961173c6dd10d69055e3597897 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java +@@ -60,6 +60,20 @@ public class EntityDamageByEntityEvent extends EntityDamageEvent { + } + // Paper end + ++ // Paper start ++ /** ++ * {@inheritDoc} ++ *

      ++ * The {@link DamageSource#getDirectEntity()} may be different from the {@link #getDamager()} ++ * if the Minecraft damage source did not originally include an damager entity, but one was included ++ * for this event {@link #getDamager()}. ++ */ ++ @Override ++ public @NotNull DamageSource getDamageSource() { ++ return super.getDamageSource(); ++ } ++ // Paper end ++ + /** + * Returns the entity that damaged the defender. + * diff --git a/patches/api/0448-Expanded-Hopper-API.patch b/patches/api/0448-Expanded-Hopper-API.patch new file mode 100644 index 000000000000..51cb6dfee2a9 --- /dev/null +++ b/patches/api/0448-Expanded-Hopper-API.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: vicisacat +Date: Fri, 15 Mar 2024 17:35:18 +0100 +Subject: [PATCH] Expanded Hopper API + + +diff --git a/src/main/java/org/bukkit/block/Hopper.java b/src/main/java/org/bukkit/block/Hopper.java +index 7ade312f180b7e30871d3a3240c76325cc369c26..61ea33c1f2dbb546a66f945a01feae437b1381e0 100644 +--- a/src/main/java/org/bukkit/block/Hopper.java ++++ b/src/main/java/org/bukkit/block/Hopper.java +@@ -6,4 +6,20 @@ import org.bukkit.loot.Lootable; + /** + * Represents a captured state of a hopper. + */ +-public interface Hopper extends Container, LootableBlockInventory { } // Paper ++public interface Hopper extends Container, LootableBlockInventory { // Paper ++ // Paper start - Expanded Hopper API ++ /** ++ * Sets the cooldown before the hopper transfers or sucks in another item ++ * @param cooldown the cooldown in ticks ++ * @throws IllegalArgumentException if the passed cooldown value is negative. ++ */ ++ void setTransferCooldown(@org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE) int cooldown); ++ ++ /** ++ * Returns the cooldown before the hopper transfers or sucks in another item ++ * @return the cooldown in ticks ++ */ ++ int getTransferCooldown(); ++ // Paper end - Expanded Hopper API ++} ++ diff --git a/patches/api/0449-Clone-mutables-to-prevent-unexpected-issues.patch b/patches/api/0449-Clone-mutables-to-prevent-unexpected-issues.patch new file mode 100644 index 000000000000..50f9f8e25dcd --- /dev/null +++ b/patches/api/0449-Clone-mutables-to-prevent-unexpected-issues.patch @@ -0,0 +1,151 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 16 Mar 2024 11:10:48 -0700 +Subject: [PATCH] Clone mutables to prevent unexpected issues + +There are lots of locations in the API where mutable +types are not cloned, either on return or when passed +as a parameter and assigned to a field, which can cause +unexpected behaviors. Let this be a lesson to use +immutable types for simple things Location, Vector, and +others. + +diff --git a/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java b/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java +index 31fd64187fc5bd50a5ba36b3b68001ce6ff2211c..f5923049bfd0478938dafa76287db76f8a4c29f9 100644 +--- a/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockCanBuildEvent.java +@@ -102,7 +102,7 @@ public class BlockCanBuildEvent extends BlockEvent { + */ + @NotNull + public BlockData getBlockData() { +- return blockData; ++ return blockData.clone(); // Paper - clone because mutation isn't used + } + + /** +diff --git a/src/main/java/org/bukkit/event/entity/EntityChangeBlockEvent.java b/src/main/java/org/bukkit/event/entity/EntityChangeBlockEvent.java +index 1a9575ad4c81aefa5ef0b927f6ac8f7064b55c49..24e1a49e48dd8f9eb2515b2ffe472a0c4d2bc09b 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityChangeBlockEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityChangeBlockEvent.java +@@ -61,7 +61,7 @@ public class EntityChangeBlockEvent extends EntityEvent implements Cancellable { + */ + @NotNull + public BlockData getBlockData() { +- return to; ++ return to.clone(); // Paper - clone because mutation isn't used + } + + @NotNull +diff --git a/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java b/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java +index 50161d313cfcc9e61441589685c3d0e1f057dd86..e468e55d426b8f81f87c0a08451d02b3866c226f 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityExplodeEvent.java +@@ -72,7 +72,7 @@ public class EntityExplodeEvent extends EntityEvent implements Cancellable { + */ + @NotNull + public Location getLocation() { +- return location; ++ return location.clone(); // Paper - clone to avoid changes + } + + /** +diff --git a/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java b/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java +index d3724db0a5a67cde15b05fecd32b2ca370cca998..8b2caf665b9e829ceefc89bf41b192f53f3d5773 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPortalEnterEvent.java +@@ -35,7 +35,7 @@ public class EntityPortalEnterEvent extends EntityEvent implements org.bukkit.ev + */ + @NotNull + public Location getLocation() { +- return location; ++ return location.clone(); // Paper - clone to avoid changes + } + + // Paper start +diff --git a/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java b/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java +index 6fc66197eb2c5d59c70d8d028b7963748371edbe..2bb29fa449cd6c90b52d2786ed15b6154d591607 100644 +--- a/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java ++++ b/src/main/java/org/bukkit/event/entity/ItemDespawnEvent.java +@@ -46,7 +46,7 @@ public class ItemDespawnEvent extends EntityEvent implements Cancellable { + */ + @NotNull + public Location getLocation() { +- return location; ++ return location.clone(); // Paper - clone to avoid changes + } + + @NotNull +diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java +index d0a437bd8aeec18f800893f51ece06deb0c8972c..50fad23cf4d9f591b12a9eaebeb4e26f18e8528d 100644 +--- a/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java ++++ b/src/main/java/org/bukkit/event/vehicle/VehicleBlockCollisionEvent.java +@@ -31,7 +31,7 @@ public class VehicleBlockCollisionEvent extends VehicleCollisionEvent { + */ + @NotNull + public org.bukkit.util.Vector getVelocity() { +- return velocity; ++ return velocity.clone(); + } + // Paper end + +diff --git a/src/main/java/org/bukkit/event/vehicle/VehicleMoveEvent.java b/src/main/java/org/bukkit/event/vehicle/VehicleMoveEvent.java +index 7bfb84d3948c773e943374316ea25a19288ec7d0..fc4cf7b21b24fe38617fa150f697bc29da76754e 100644 +--- a/src/main/java/org/bukkit/event/vehicle/VehicleMoveEvent.java ++++ b/src/main/java/org/bukkit/event/vehicle/VehicleMoveEvent.java +@@ -27,7 +27,7 @@ public class VehicleMoveEvent extends VehicleEvent { + */ + @NotNull + public Location getFrom() { +- return from; ++ return from.clone(); // Paper - clone to avoid changes + } + + /** +@@ -37,7 +37,7 @@ public class VehicleMoveEvent extends VehicleEvent { + */ + @NotNull + public Location getTo() { +- return to; ++ return to.clone(); // Paper - clone to avoid changes + } + + +diff --git a/src/main/java/org/bukkit/event/world/GenericGameEvent.java b/src/main/java/org/bukkit/event/world/GenericGameEvent.java +index 2a2a329877d8da45c2d6afecf78ce88d52635cad..fb975fefc74d8c9746cab4c02860f55654cf92f7 100644 +--- a/src/main/java/org/bukkit/event/world/GenericGameEvent.java ++++ b/src/main/java/org/bukkit/event/world/GenericGameEvent.java +@@ -49,7 +49,7 @@ public class GenericGameEvent extends WorldEvent implements Cancellable { + */ + @NotNull + public Location getLocation() { +- return location; ++ return location.clone(); // Paper - clone to avoid changes + } + + /** +diff --git a/src/main/java/org/bukkit/event/world/SpawnChangeEvent.java b/src/main/java/org/bukkit/event/world/SpawnChangeEvent.java +index 9ce93d00935446589cb2bb970cb540d109616e85..73997ae04ff39ac3984c59de32aaced9eb72ce16 100644 +--- a/src/main/java/org/bukkit/event/world/SpawnChangeEvent.java ++++ b/src/main/java/org/bukkit/event/world/SpawnChangeEvent.java +@@ -25,7 +25,7 @@ public class SpawnChangeEvent extends WorldEvent { + */ + @NotNull + public Location getPreviousLocation() { +- return previousLocation; ++ return previousLocation.clone(); // Paper - clone to avoid changes + } + + @NotNull +diff --git a/src/main/java/org/bukkit/event/world/StructureGrowEvent.java b/src/main/java/org/bukkit/event/world/StructureGrowEvent.java +index 7af8d6e51c824cf0592b722b834f1d4986e3cc08..783e74bc382f0f6d24203fde7b811f588a674731 100644 +--- a/src/main/java/org/bukkit/event/world/StructureGrowEvent.java ++++ b/src/main/java/org/bukkit/event/world/StructureGrowEvent.java +@@ -39,7 +39,7 @@ public class StructureGrowEvent extends WorldEvent implements Cancellable { + */ + @NotNull + public Location getLocation() { +- return location; ++ return location.clone(); // Paper - clone to avoid changes + } + + /** diff --git a/patches/api/0450-Add-BlockBreakProgressUpdateEvent.patch b/patches/api/0450-Add-BlockBreakProgressUpdateEvent.patch new file mode 100644 index 000000000000..9a1913895ba4 --- /dev/null +++ b/patches/api/0450-Add-BlockBreakProgressUpdateEvent.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Badbird5907 <50347938+Badbird5907@users.noreply.github.com> +Date: Mon, 4 Mar 2024 22:18:33 -0500 +Subject: [PATCH] Add BlockBreakProgressUpdateEvent + + +diff --git a/src/main/java/io/papermc/paper/event/block/BlockBreakProgressUpdateEvent.java b/src/main/java/io/papermc/paper/event/block/BlockBreakProgressUpdateEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1820e9b12141f3798dac499e19f8337c6f89d671 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BlockBreakProgressUpdateEvent.java +@@ -0,0 +1,57 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.block.Block; ++import org.bukkit.entity.Entity; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when the progress of a block break is updated. ++ */ ++@NullMarked ++public class BlockBreakProgressUpdateEvent extends BlockEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ ++ private final float progress; ++ private final Entity entity; ++ ++ @ApiStatus.Internal ++ public BlockBreakProgressUpdateEvent(final Block block, final float progress, final Entity entity) { ++ super(block); ++ this.progress = progress; ++ this.entity = entity; ++ } ++ ++ /** ++ * The progress of the block break ++ *

      ++ * The progress ranges from 0.0 - 1.0, where 0 is no damage and ++ * 1.0 is the most damaged ++ * ++ * @return The progress of the block break ++ */ ++ public float getProgress() { ++ return this.progress; ++ } ++ ++ /** ++ * The entity breaking the block. ++ * ++ * @return The entity breaking the block ++ */ ++ public Entity getEntity() { ++ return this.entity; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} diff --git a/patches/api/0451-Deprecate-ItemStack-setType.patch b/patches/api/0451-Deprecate-ItemStack-setType.patch new file mode 100644 index 000000000000..edfbdb9d0a52 --- /dev/null +++ b/patches/api/0451-Deprecate-ItemStack-setType.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Thu, 29 Feb 2024 17:54:26 -0500 +Subject: [PATCH] Deprecate ItemStack#setType + + +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index 0e6103628673130139363b53d23d3432deff5c50..4bb051af04d7e76853309386eb4ee43a00813c58 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -143,8 +143,18 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + * {@link Material#isItem()} returns false. + * + * @param type New type to set the items in this stack to ++ * @deprecated Setting the material type of ItemStacks is no longer supported. ++ *

      ++ * This method is deprecated due to potential illegal behavior that may occur ++ * during the context of which this ItemStack is being used, allowing for certain item validation to be bypassed. ++ * It is recommended to instead create a new ItemStack object with the desired ++ * Material type, and if possible, set it in the appropriate context. ++ * ++ * Using this method in ItemStacks passed in events will result in undefined behavior. ++ * @see ItemStack#withType(Material) + */ + @Utility ++ @Deprecated // Paper + public void setType(@NotNull Material type) { + Preconditions.checkArgument(type != null, "Material cannot be null"); + this.type = type; +@@ -157,6 +167,24 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + this.data = null; + } + } ++ // Paper start ++ /** ++ * Creates a new ItemStack with the specified Material type, where the item count and item meta is preserved. ++ * ++ * @param type The Material type of the new ItemStack. ++ * @return A new ItemStack instance with the specified Material type. ++ */ ++ @NotNull ++ @org.jetbrains.annotations.Contract(value = "_ -> new", pure = true) ++ public ItemStack withType(@NotNull Material type) { ++ ItemStack itemStack = new ItemStack(type, this.amount); ++ if (this.hasItemMeta()) { ++ itemStack.setItemMeta(this.getItemMeta()); ++ } ++ ++ return itemStack; ++ } ++ // Paper end + + /** + * Gets the amount of items in this stack diff --git a/patches/api/0452-Item-Mutation-Fixes.patch b/patches/api/0452-Item-Mutation-Fixes.patch new file mode 100644 index 000000000000..ccd77b7fbc62 --- /dev/null +++ b/patches/api/0452-Item-Mutation-Fixes.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 20 Mar 2024 20:42:31 -0400 +Subject: [PATCH] Item Mutation Fixes + + +diff --git a/src/main/java/org/bukkit/event/block/InventoryBlockStartEvent.java b/src/main/java/org/bukkit/event/block/InventoryBlockStartEvent.java +index 1ebd45295a29fbc990a1311a7f0fe7f42ac79275..b70450919e78e869c9f158c4e3e25944bcaa73f2 100644 +--- a/src/main/java/org/bukkit/event/block/InventoryBlockStartEvent.java ++++ b/src/main/java/org/bukkit/event/block/InventoryBlockStartEvent.java +@@ -17,7 +17,7 @@ import org.jetbrains.annotations.NotNull; + public class InventoryBlockStartEvent extends BlockEvent { + + private static final HandlerList handlers = new HandlerList(); +- private final ItemStack source; ++ protected ItemStack source; // Paper + + public InventoryBlockStartEvent(@NotNull final Block block, @NotNull ItemStack source) { + super(block); +diff --git a/src/main/java/org/bukkit/event/enchantment/EnchantItemEvent.java b/src/main/java/org/bukkit/event/enchantment/EnchantItemEvent.java +index 1829529c9915937dcdd0e6d1ceba9e64819fb93f..e7c243038b70ca13b7eabdf88ce518b6198c6db9 100644 +--- a/src/main/java/org/bukkit/event/enchantment/EnchantItemEvent.java ++++ b/src/main/java/org/bukkit/event/enchantment/EnchantItemEvent.java +@@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull; + public class EnchantItemEvent extends InventoryEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private final Block table; +- private final ItemStack item; ++ private ItemStack item; // Paper + private int level; + private boolean cancelled; + private final Map enchants; +@@ -72,6 +72,17 @@ public class EnchantItemEvent extends InventoryEvent implements Cancellable { + return item; + } + ++ // Paper start ++ /** ++ * Sets the item to be enchanted ++ * ++ * @param item item ++ */ ++ public void setItem(@NotNull final ItemStack item) { ++ this.item = item; ++ } ++ // Paper end ++ + /** + * Gets the cost (minimum level) which is displayed as a number on the right + * hand side of the enchantment offer. diff --git a/patches/api/0453-API-for-checking-sent-chunks.patch b/patches/api/0453-API-for-checking-sent-chunks.patch new file mode 100644 index 000000000000..ce630de11f4e --- /dev/null +++ b/patches/api/0453-API-for-checking-sent-chunks.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Flo0 +Date: Mon, 8 Apr 2024 16:22:07 +0200 +Subject: [PATCH] API for checking sent chunks + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index a7a4e5423cedb67bcdf02738be62bdf83e748b82..f007c82bb8cab84856930e654d77610242501589 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3844,6 +3844,47 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + void resetIdleDuration(); + // Paper end + ++ // Paper start - Add chunk view API ++ /** ++ * Gets the a set of chunk keys for all chunks that have been sent to the player. ++ * ++ * @return an immutable set of chunk keys ++ * @apiNote currently marked as experimental to gather feedback regarding the returned set being an immutable copy ++ * vs it potentially being an unmodifiable view of the set chunks. ++ */ ++ @ApiStatus.Experimental ++ java.util.@NotNull @org.jetbrains.annotations.Unmodifiable Set getSentChunkKeys(); ++ ++ /** ++ * Gets the set of chunks that have been sent to the player. ++ * ++ * @return an immutable set of chunks ++ * @apiNote currently marked as experimental to gather feedback regarding the returned set being an immutable copy ++ * vs it potentially being an unmodifiable view of the set chunks. ++ */ ++ @ApiStatus.Experimental ++ java.util.@NotNull @org.jetbrains.annotations.Unmodifiable Set getSentChunks(); ++ ++ /** ++ * Checks if the player has been sent a specific chunk. ++ * ++ * @param chunk the chunk to check ++ * @return true if the player has been sent the chunk, false otherwise ++ */ ++ default boolean isChunkSent(@NotNull org.bukkit.Chunk chunk) { ++ return this.isChunkSent(chunk.getChunkKey()); ++ } ++ ++ /** ++ * Checks if the player has been sent a specific chunk. ++ * ++ * @param chunkKey the chunk key to check ++ * @return true if the player has been sent the chunk, false otherwise ++ * @see org.bukkit.Chunk#getChunkKey() ++ */ ++ boolean isChunkSent(long chunkKey); ++ // Paper end ++ + @NotNull + @Override + Spigot spigot(); diff --git a/patches/api/0454-Add-CartographyItemEvent.patch b/patches/api/0454-Add-CartographyItemEvent.patch new file mode 100644 index 000000000000..8bfd237e0ccf --- /dev/null +++ b/patches/api/0454-Add-CartographyItemEvent.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Janet Blackquill +Date: Sun, 7 Apr 2024 16:51:04 -0400 +Subject: [PATCH] Add CartographyItemEvent + +Similar to SmithItemEvent, but for cartography tables. + +diff --git a/src/main/java/io/papermc/paper/event/player/CartographyItemEvent.java b/src/main/java/io/papermc/paper/event/player/CartographyItemEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d5c67f5462b9011683ce742a197959f9c4380d40 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/CartographyItemEvent.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.event.player; ++ ++import org.bukkit.event.inventory.ClickType; ++import org.bukkit.event.inventory.InventoryAction; ++import org.bukkit.event.inventory.InventoryClickEvent; ++import org.bukkit.event.inventory.InventoryType; ++import org.bukkit.inventory.CartographyInventory; ++import org.bukkit.inventory.InventoryView; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when the recipe of an Item is completed inside a cartography table. ++ */ ++@NullMarked ++public class CartographyItemEvent extends InventoryClickEvent { ++ ++ @ApiStatus.Internal ++ public CartographyItemEvent(final InventoryView view, final InventoryType.SlotType type, final int slot, final ClickType click, final InventoryAction action) { ++ super(view, type, slot, click, action); ++ } ++ ++ @ApiStatus.Internal ++ public CartographyItemEvent(final InventoryView view, final InventoryType.SlotType type, final int slot, final ClickType click, final InventoryAction action, final int key) { ++ super(view, type, slot, click, action, key); ++ } ++ ++ @Override ++ public CartographyInventory getInventory() { ++ return (CartographyInventory) super.getInventory(); ++ } ++} diff --git a/patches/api/0455-More-Raid-API.patch b/patches/api/0455-More-Raid-API.patch new file mode 100644 index 000000000000..ac5714cfba75 --- /dev/null +++ b/patches/api/0455-More-Raid-API.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 4 Mar 2022 09:46:40 -0800 +Subject: [PATCH] More Raid API + + +diff --git a/src/main/java/org/bukkit/Raid.java b/src/main/java/org/bukkit/Raid.java +index 983a8c20a06d2b509602b27f49c090598b8ecc42..fa98599e3eee37bf68f0e9813497c718f457485c 100644 +--- a/src/main/java/org/bukkit/Raid.java ++++ b/src/main/java/org/bukkit/Raid.java +@@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents a raid event. + */ +-public interface Raid { ++public interface Raid extends org.bukkit.persistence.PersistentDataHolder { // Paper + + /** + * Get whether this raid started. +@@ -131,4 +131,20 @@ public interface Raid { + */ + STOPPED; + } ++ ++ // Paper start ++ /** ++ * Gets the id of this raid. ++ * ++ * @return the raid id ++ */ ++ int getId(); ++ ++ /** ++ * Get the boss bar to be displayed for this raid. ++ * ++ * @return the boss bar ++ */ ++ org.bukkit.boss.@NotNull BossBar getBossBar(); ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java +index 1796615065c8a6d06450d1b9c389804e804c4327..e2573ede859a536dfbb487b3f237caff742b0b30 100644 +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -4164,6 +4164,17 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient + @Nullable + public Raid locateNearestRaid(@NotNull Location location, int radius); + ++ // Paper start - more Raid API ++ /** ++ * Get a raid with the specific id from {@link Raid#getId} ++ * from this world. ++ * ++ * @param id the id of the raid ++ * @return the raid or null if none with that id ++ */ ++ @Nullable Raid getRaid(int id); ++ // Paper end - more Raid API ++ + /** + * Gets all raids that are going on over this world. + * diff --git a/patches/api/0456-Fix-SpawnerEntry-Equipment-API.patch b/patches/api/0456-Fix-SpawnerEntry-Equipment-API.patch new file mode 100644 index 000000000000..e170eabd170e --- /dev/null +++ b/patches/api/0456-Fix-SpawnerEntry-Equipment-API.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 26 Apr 2024 17:00:00 -0700 +Subject: [PATCH] Fix SpawnerEntry$Equipment API + + +diff --git a/src/main/java/org/bukkit/block/spawner/SpawnerEntry.java b/src/main/java/org/bukkit/block/spawner/SpawnerEntry.java +index fc1c0435dfea121923eb1fe0182880752f321143..bc8ccd139df6072f9744cfb85ad0070369600aa1 100644 +--- a/src/main/java/org/bukkit/block/spawner/SpawnerEntry.java ++++ b/src/main/java/org/bukkit/block/spawner/SpawnerEntry.java +@@ -120,27 +120,29 @@ public class SpawnerEntry { + private final Map dropChances; + + public Equipment(@NotNull LootTable equipmentLootTable, @NotNull Map dropChances) { ++ Preconditions.checkArgument(equipmentLootTable != null, "table cannot be null"); // Paper + this.equipmentLootTable = equipmentLootTable; + this.dropChances = dropChances; + } + + /** +- * Set the loot table for the entity. ++ * Set the loot table for the spawned entity's equipment slots. + *
      +- * To remove a loot table use null. ++ * To remove a loot table use the empty loot table. + * + * @param table this {@link org.bukkit.entity.Mob} will have. + */ + public void setEquipmentLootTable(@NotNull LootTable table) { ++ Preconditions.checkArgument(table != null, "table cannot be null"); // Paper + this.equipmentLootTable = table; + } + + /** +- * Gets the loot table for the entity. ++ * Gets the loot table for the spawned entity's equipment. + *
      + * +- * If an entity does not have a loot table, this will return null, NOT +- * an empty loot table. ++ * If an entity does not have a loot table, this will return an ++ * empty loot table. + * + * @return the loot table for this entity. + */ diff --git a/patches/api/0457-Fix-ItemFlags.patch b/patches/api/0457-Fix-ItemFlags.patch new file mode 100644 index 000000000000..75f8c497f26d --- /dev/null +++ b/patches/api/0457-Fix-ItemFlags.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 27 Apr 2024 13:28:17 -0700 +Subject: [PATCH] Fix ItemFlags + +Adds new flag in HIDE_STORED_ENCHANTS which was split +from HIDE_ADDITIONAL_INFO. Adds a migration to account for +this, adding the new flag if the itemstack is old and had the +old flag. + +diff --git a/src/main/java/org/bukkit/inventory/ItemFlag.java b/src/main/java/org/bukkit/inventory/ItemFlag.java +index 5b8dac777bb1640dc00bbe98feb6460c36eebb98..1af15fd327e0613cd1a179bd7fef1e83cbe31761 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFlag.java ++++ b/src/main/java/org/bukkit/inventory/ItemFlag.java +@@ -2,6 +2,8 @@ package org.bukkit.inventory; + + /** + * A ItemFlag can hide some Attributes from ItemStacks ++ * @apiNote Setting these without also setting the data they are hiding ++ * may not result in the item flag being persisted in the ItemMeta/ItemStack. + */ + public enum ItemFlag { + +@@ -27,7 +29,8 @@ public enum ItemFlag { + HIDE_PLACED_ON, + /** + * Setting to show/hide potion effects, book and firework information, map +- * tooltips, patterns of banners, and enchantments of enchanted books. ++ * tooltips, patterns of banners. ++ * @see #HIDE_STORED_ENCHANTS HIDE_STORED_ENCHANTS for hiding stored enchants (like on enchanted books) + */ + HIDE_ADDITIONAL_TOOLTIP, + /** +@@ -37,7 +40,13 @@ public enum ItemFlag { + /** + * Setting to show/hide armor trim from armor. + */ +- HIDE_ARMOR_TRIM; ++ HIDE_ARMOR_TRIM, ++ /** ++ * Setting to show/hide stored enchants on an item, such as enchantments ++ * on an enchanted book. ++ */ ++ HIDE_STORED_ENCHANTS, ++ ; + // Paper start + /** + * Setting to show/hide item-specific information, including, but not limited to: +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index 4bb051af04d7e76853309386eb4ee43a00813c58..10b913490eaba71849f896754dfcb62b4b114e2c 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -588,6 +588,13 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat + Object raw = args.get("meta"); + if (raw instanceof ItemMeta) { + ((ItemMeta) raw).setVersion(version); ++ // Paper start - for pre 1.20.5 itemstacks, add HIDE_STORED_ENCHANTS flag if HIDE_ADDITIONAL_TOOLTIP is set ++ if (version < 3837) { // 1.20.5 ++ if (((ItemMeta) raw).hasItemFlag(ItemFlag.HIDE_ADDITIONAL_TOOLTIP)) { ++ ((ItemMeta) raw).addItemFlags(ItemFlag.HIDE_STORED_ENCHANTS); ++ } ++ } ++ // Paper end + result.setItemMeta((ItemMeta) raw); + } + } diff --git a/patches/api/0458-Allow-modifying-library-loader-jars-bytecode.patch b/patches/api/0458-Allow-modifying-library-loader-jars-bytecode.patch new file mode 100644 index 000000000000..0c0311e790ef --- /dev/null +++ b/patches/api/0458-Allow-modifying-library-loader-jars-bytecode.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Sun, 28 Apr 2024 11:11:26 -0700 +Subject: [PATCH] Allow modifying library loader jars bytecode + + +diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +index f4d655a158410039305ac68cebe0d79000f73df8..5b0203e908f84c531886b8ea8faeb591eb045636 100644 +--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +@@ -46,6 +46,7 @@ public class LibraryLoader + private final RepositorySystem repository; + private final DefaultRepositorySystemSession session; + private final List repositories; ++ public static java.util.function.BiFunction LIBRARY_LOADER_FACTORY; // Paper - rewrite reflection in libraries + + public LibraryLoader(@NotNull Logger logger) + { +@@ -130,7 +131,14 @@ public class LibraryLoader + } ); + } + +- URLClassLoader loader = new URLClassLoader( jarFiles.toArray( new URL[ jarFiles.size() ] ), getClass().getClassLoader() ); ++ // Paper start - rewrite reflection in libraries ++ URLClassLoader loader; ++ if (LIBRARY_LOADER_FACTORY == null) { ++ loader = new URLClassLoader( jarFiles.toArray( new URL[ jarFiles.size() ] ), getClass().getClassLoader() ); ++ } else { ++ loader = LIBRARY_LOADER_FACTORY.apply(jarFiles.toArray( new URL[ jarFiles.size() ] ), getClass().getClassLoader()); ++ } ++ // Paper end - rewrite reflection in libraries + + return loader; + } diff --git a/patches/api/0459-Add-hook-to-remap-library-jars.patch b/patches/api/0459-Add-hook-to-remap-library-jars.patch new file mode 100644 index 000000000000..fe1609629e8e --- /dev/null +++ b/patches/api/0459-Add-hook-to-remap-library-jars.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Sun, 28 Apr 2024 13:51:08 -0700 +Subject: [PATCH] Add hook to remap library jars + + +diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +index 5b0203e908f84c531886b8ea8faeb591eb045636..8e1b6be2462aaa692efa1f72986921a6dc357196 100644 +--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +@@ -47,6 +47,7 @@ public class LibraryLoader + private final DefaultRepositorySystemSession session; + private final List repositories; + public static java.util.function.BiFunction LIBRARY_LOADER_FACTORY; // Paper - rewrite reflection in libraries ++ public static java.util.function.Function, List> REMAPPER; // Paper - remap libraries + + public LibraryLoader(@NotNull Logger logger) + { +@@ -111,9 +112,18 @@ public class LibraryLoader + } + + List jarFiles = new ArrayList<>(); ++ List jarPaths = new ArrayList<>(); // Paper - remap libraries + for ( ArtifactResult artifact : result.getArtifactResults() ) + { +- File file = artifact.getArtifact().getFile(); ++ // Paper start - remap libraries ++ jarPaths.add(artifact.getArtifact().getFile().toPath()); ++ } ++ if (REMAPPER != null) { ++ jarPaths = REMAPPER.apply(jarPaths); ++ } ++ for (java.nio.file.Path path : jarPaths) { ++ File file = path.toFile(); ++ // Paper end - remap libraries + + URL url; + try diff --git a/patches/api/0460-Add-GameMode-isInvulnerable.patch b/patches/api/0460-Add-GameMode-isInvulnerable.patch new file mode 100644 index 000000000000..b4b81c5f523f --- /dev/null +++ b/patches/api/0460-Add-GameMode-isInvulnerable.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Wed, 1 May 2024 06:56:21 +0300 +Subject: [PATCH] Add GameMode#isInvulnerable + + +diff --git a/src/main/java/org/bukkit/GameMode.java b/src/main/java/org/bukkit/GameMode.java +index fdc42a79c5af30fdade41ee99245e6641f353571..ddc56524b3bd2bdebba81c61a5600e6f46a4aaa4 100644 +--- a/src/main/java/org/bukkit/GameMode.java ++++ b/src/main/java/org/bukkit/GameMode.java +@@ -79,4 +79,16 @@ public enum GameMode implements net.kyori.adventure.translation.Translatable { / + BY_ID.put(mode.getValue(), mode); + } + } ++ ++ // Paper start - Add GameMode#isInvulnerable ++ /** ++ * Checks whether this game mode is invulnerable ++ * (i.e. is either {@link #CREATIVE} or {@link #SPECTATOR}) ++ * ++ * @return whether this game mode is invulnerable ++ */ ++ public boolean isInvulnerable() { ++ return this == CREATIVE || this == SPECTATOR; ++ } ++ // Paper end - Add GameMode#isInvulnerable + } diff --git a/patches/api/0461-Expose-hasColor-to-leather-armor.patch b/patches/api/0461-Expose-hasColor-to-leather-armor.patch new file mode 100644 index 000000000000..e2c609b4f0fc --- /dev/null +++ b/patches/api/0461-Expose-hasColor-to-leather-armor.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Wed, 1 May 2024 10:58:50 +0300 +Subject: [PATCH] Expose #hasColor to leather armor + + +diff --git a/src/main/java/org/bukkit/inventory/meta/LeatherArmorMeta.java b/src/main/java/org/bukkit/inventory/meta/LeatherArmorMeta.java +index c701d5fbc5fef503f18a3a46fa54c983bf96e895..2d68f93c371e4a40638f56e5cd4d39472d4e462b 100644 +--- a/src/main/java/org/bukkit/inventory/meta/LeatherArmorMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/LeatherArmorMeta.java +@@ -36,4 +36,13 @@ public interface LeatherArmorMeta extends ItemMeta { + @Override + @NotNull + LeatherArmorMeta clone(); ++ ++ // Paper start - Expose #hasColor to leather armor ++ /** ++ * Checks whether this leather armor is dyed. ++ * ++ * @return whether this leather armor is dyed ++ */ ++ boolean isDyed(); ++ // Paper end - Expose #hasColor to leather armor + } diff --git a/patches/api/0462-Added-API-to-get-player-ha-proxy-address.patch b/patches/api/0462-Added-API-to-get-player-ha-proxy-address.patch new file mode 100644 index 000000000000..d1e0188a7bb1 --- /dev/null +++ b/patches/api/0462-Added-API-to-get-player-ha-proxy-address.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: nostalfinals +Date: Mon, 8 Apr 2024 23:24:38 +0800 +Subject: [PATCH] Added API to get player ha proxy address + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index f007c82bb8cab84856930e654d77610242501589..0387eb02575cd2f20061f92c2ba5432f16b014b2 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -267,6 +267,16 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + @Nullable + public InetSocketAddress getAddress(); + ++ // Paper start - Add API to get player's proxy address ++ /** ++ * Gets the socket address of this player's proxy ++ * ++ * @return the player's proxy address, null if the server doesn't have Proxy Protocol enabled, or the player didn't connect to an HAProxy instance ++ */ ++ @Nullable ++ public InetSocketAddress getHAProxyAddress(); ++ // Paper end - Add API to get player's proxy address ++ + /** + * Gets if this connection has been transferred from another server. + * diff --git a/patches/api/0463-More-Chest-Block-API.patch b/patches/api/0463-More-Chest-Block-API.patch new file mode 100644 index 000000000000..1fc3614c74c8 --- /dev/null +++ b/patches/api/0463-More-Chest-Block-API.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Wed, 1 May 2024 08:22:13 +0300 +Subject: [PATCH] More Chest Block API + + +diff --git a/src/main/java/org/bukkit/block/Chest.java b/src/main/java/org/bukkit/block/Chest.java +index db6affbc78106b2d93b41953b624a0bca0ca1d72..5d02f9c938d0d7d0f4e491ccfaf6beb0a7a61aa4 100644 +--- a/src/main/java/org/bukkit/block/Chest.java ++++ b/src/main/java/org/bukkit/block/Chest.java +@@ -27,4 +27,14 @@ public interface Chest extends Container, LootableBlockInventory, Lidded { // Pa + */ + @NotNull + Inventory getBlockInventory(); ++ ++ // Paper start - More Chest Block API ++ /** ++ * Checks whether this chest is blocked ++ * by either a block above or a sitting cat ++ * ++ * @return whether this chest is blocked ++ */ ++ boolean isBlocked(); ++ // Paper end - More Chest Block API + } +diff --git a/src/main/java/org/bukkit/block/EnderChest.java b/src/main/java/org/bukkit/block/EnderChest.java +index 1150b449a3f5c40fe10136779c2ccc65ab4d884c..6b66f38e5509f90aad5ee1fffca01003dcbe9896 100644 +--- a/src/main/java/org/bukkit/block/EnderChest.java ++++ b/src/main/java/org/bukkit/block/EnderChest.java +@@ -3,4 +3,13 @@ package org.bukkit.block; + /** + * Represents a captured state of an ender chest. + */ +-public interface EnderChest extends Lidded, TileState { } ++public interface EnderChest extends Lidded, TileState { ++ // Paper start - More Chest Block API ++ /** ++ * Checks whether this ender chest is blocked by a block above ++ * ++ * @return whether this ender chest is blocked ++ */ ++ boolean isBlocked(); ++ // Paper end - More Chest Block API ++} diff --git a/patches/api/0464-Brigadier-based-command-API.patch b/patches/api/0464-Brigadier-based-command-API.patch new file mode 100644 index 000000000000..894baf9ad80b --- /dev/null +++ b/patches/api/0464-Brigadier-based-command-API.patch @@ -0,0 +1,2073 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Mon, 1 Aug 2022 22:50:29 -0400 +Subject: [PATCH] Brigadier based command API + +Co-authored-by: Jake Potrebic + +diff --git a/build.gradle.kts b/build.gradle.kts +index 2b489adc50d45facd347f79c34224d347dc20a75..571534b42cd9c33d6a7bb6fe3bf3a28e33f8e5de 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -39,6 +39,7 @@ abstract class MockitoAgentProvider : CommandLineArgumentProvider { + // Paper end - configure mockito agent that is needed in newer java versions + + dependencies { ++ api("com.mojang:brigadier:1.2.9") // Paper - Brigadier command api + // api dependencies are listed transitively to API consumers + api("com.google.guava:guava:33.3.1-jre") + api("com.google.code.gson:gson:2.11.0") +@@ -108,9 +109,33 @@ sourceSets { + } + } + // Paper end ++// Paper start - brigadier API ++val outgoingVariants = arrayOf("runtimeElements", "apiElements", "sourcesElements", "javadocElements") ++val mainCapability = "${project.group}:${project.name}:${project.version}" ++configurations { ++ val outgoing = outgoingVariants.map { named(it) } ++ for (config in outgoing) { ++ config { ++ attributes { ++ attribute(io.papermc.paperweight.util.mainCapabilityAttribute, mainCapability) ++ } ++ outgoing { ++ capability(mainCapability) ++ capability("io.papermc.paper:paper-mojangapi:${project.version}") ++ capability("com.destroystokyo.paper:paper-mojangapi:${project.version}") ++ } ++ } ++ } ++} ++// Paper end + + configure { + publications.create("maven") { ++ // Paper start - brigadier API ++ outgoingVariants.forEach { ++ suppressPomMetadataWarningsFor(it) ++ } ++ // Paper end + from(components["java"]) + } + } +diff --git a/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommand.java b/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..03a1078446f84b998cd7fe8d64abecb2e36bab0a +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommand.java +@@ -0,0 +1,16 @@ ++package com.destroystokyo.paper.brigadier; ++ ++import com.mojang.brigadier.Command; ++import com.mojang.brigadier.suggestion.SuggestionProvider; ++ ++import java.util.function.Predicate; ++ ++/** ++ * Brigadier {@link Command}, {@link SuggestionProvider}, and permission checker for Bukkit {@link Command}s. ++ * ++ * @param command source type ++ * @deprecated For removal, see {@link io.papermc.paper.command.brigadier.Commands} on how to use the new Brigadier API. ++ */ ++@Deprecated(forRemoval = true, since = "1.20.6") ++public interface BukkitBrigadierCommand extends Command, Predicate, SuggestionProvider { ++} +diff --git a/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommandSource.java b/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommandSource.java +new file mode 100644 +index 0000000000000000000000000000000000000000..28b44789e3be586c4b680fff56e5d2ff095f9ac2 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommandSource.java +@@ -0,0 +1,25 @@ ++package com.destroystokyo.paper.brigadier; ++ ++import org.bukkit.Location; ++import org.bukkit.World; ++import org.bukkit.command.CommandSender; ++import org.bukkit.entity.Entity; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * @deprecated For removal, see {@link io.papermc.paper.command.brigadier.Commands} on how to use the new Brigadier API. ++ */ ++@Deprecated(forRemoval = true) ++public interface BukkitBrigadierCommandSource { ++ ++ @Nullable ++ Entity getBukkitEntity(); ++ ++ @Nullable ++ World getBukkitWorld(); ++ ++ @Nullable ++ Location getBukkitLocation(); ++ ++ CommandSender getBukkitSender(); ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/brigadier/AsyncPlayerSendCommandsEvent.java b/src/main/java/com/destroystokyo/paper/event/brigadier/AsyncPlayerSendCommandsEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9e1b70d438c4341ec944503b5bbe6b1f08bc0478 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/brigadier/AsyncPlayerSendCommandsEvent.java +@@ -0,0 +1,73 @@ ++package com.destroystokyo.paper.event.brigadier; ++ ++import com.mojang.brigadier.tree.RootCommandNode; ++import io.papermc.paper.command.brigadier.CommandSourceStack; ++import org.bukkit.Bukkit; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Fired any time a Brigadier RootCommandNode is generated for a player to inform the client of commands. ++ * You may manipulate this CommandNode to change what the client sees. ++ * ++ *

      This event may fire on login, world change, and permission rebuilds, by plugin request, and potentially future means.

      ++ * ++ *

      This event will fire before {@link org.bukkit.event.player.PlayerCommandSendEvent}, so no filtering has been done by ++ * other plugins yet.

      ++ * ++ *

      WARNING: This event will potentially (and most likely) fire twice! Once for Async, and once again for Sync. ++ * It is important that you check event.isAsynchronous() and event.hasFiredAsync() to ensure you only act once. ++ * If for some reason we are unable to send this asynchronously in the future, only the sync method will fire.

      ++ * ++ *

      Your logic should look like this: ++ * {@code if (event.isAsynchronous() || !event.hasFiredAsync()) { // do stuff }}

      ++ * ++ *

      If your logic is not safe to run asynchronously, only react to the synchronous version.

      ++ * ++ *

      This is a draft/experimental API and is subject to change.

      ++ */ ++@ApiStatus.Experimental ++@NullMarked ++public class AsyncPlayerSendCommandsEvent extends PlayerEvent { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ private final RootCommandNode node; ++ private final boolean hasFiredAsync; ++ ++ @ApiStatus.Internal ++ public AsyncPlayerSendCommandsEvent(final Player player, final RootCommandNode node, final boolean hasFiredAsync) { ++ super(player, !Bukkit.isPrimaryThread()); ++ this.node = node; ++ this.hasFiredAsync = hasFiredAsync; ++ } ++ ++ /** ++ * Gets the full Root Command Node being sent to the client, which is mutable. ++ * ++ * @return the root command node ++ */ ++ public RootCommandNode getCommandNode() { ++ return this.node; ++ } ++ ++ /** ++ * Gets if this event has already fired asynchronously. ++ * ++ * @return whether this event has already fired asynchronously ++ */ ++ public boolean hasFiredAsync() { ++ return this.hasFiredAsync; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/brigadier/AsyncPlayerSendSuggestionsEvent.java b/src/main/java/com/destroystokyo/paper/event/brigadier/AsyncPlayerSendSuggestionsEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..faade9d35514687f21a0e8b62fa2e392d4ad238a +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/brigadier/AsyncPlayerSendSuggestionsEvent.java +@@ -0,0 +1,85 @@ ++package com.destroystokyo.paper.event.brigadier; ++ ++import com.mojang.brigadier.suggestion.Suggestions; ++import org.bukkit.Bukkit; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * Called when sending {@link Suggestions} to the client. Will be called asynchronously if a plugin ++ * marks the {@link com.destroystokyo.paper.event.server.AsyncTabCompleteEvent} event handled asynchronously, ++ * otherwise called synchronously. ++ */ ++@NullMarked ++public class AsyncPlayerSendSuggestionsEvent extends PlayerEvent implements Cancellable { ++ ++ private static final HandlerList HANDLER_LIST = new HandlerList(); ++ private boolean cancelled = false; ++ ++ private Suggestions suggestions; ++ private final String buffer; ++ ++ @ApiStatus.Internal ++ public AsyncPlayerSendSuggestionsEvent(final Player player, final Suggestions suggestions, final String buffer) { ++ super(player, !Bukkit.isPrimaryThread()); ++ this.suggestions = suggestions; ++ this.buffer = buffer; ++ } ++ ++ /** ++ * Gets the input buffer sent to request these suggestions. ++ * ++ * @return the input buffer ++ */ ++ public String getBuffer() { ++ return this.buffer; ++ } ++ ++ /** ++ * Gets the suggestions to be sent to client. ++ * ++ * @return the suggestions ++ */ ++ public Suggestions getSuggestions() { ++ return this.suggestions; ++ } ++ ++ /** ++ * Sets the suggestions to be sent to client. ++ * ++ * @param suggestions suggestions ++ */ ++ public void setSuggestions(final Suggestions suggestions) { ++ this.suggestions = suggestions; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * Cancels sending suggestions to the client. ++ * {@inheritDoc} ++ */ ++ @Override ++ public void setCancelled(final boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLER_LIST; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return HANDLER_LIST; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/event/brigadier/CommandRegisteredEvent.java b/src/main/java/com/destroystokyo/paper/event/brigadier/CommandRegisteredEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..acc2bd2ec56e64b9d4bd8677d99448a97ecb5201 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/brigadier/CommandRegisteredEvent.java +@@ -0,0 +1,171 @@ ++package com.destroystokyo.paper.event.brigadier; ++ ++import com.destroystokyo.paper.brigadier.BukkitBrigadierCommand; ++import com.mojang.brigadier.tree.ArgumentCommandNode; ++import com.mojang.brigadier.tree.LiteralCommandNode; ++import com.mojang.brigadier.tree.RootCommandNode; ++import org.bukkit.Warning; ++import org.bukkit.command.Command; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.server.ServerEvent; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Fired anytime the server synchronizes Bukkit commands to Brigadier. ++ * ++ *

      Allows a plugin to control the command node structure for its commands. ++ * This is done at Plugin Enable time after commands have been registered, but may also ++ * run at a later point in the server lifetime due to plugins, a server reload, etc.

      ++ * ++ *

      This is a draft/experimental API and is subject to change.

      ++ * @deprecated For removal, use the new brigadier api. ++ */ ++@ApiStatus.Experimental ++@Deprecated(since = "1.20.6") ++@Warning(reason = "This event has been superseded by the Commands API and will be removed in a future release. Listen to LifecycleEvents.COMMANDS instead.", value = true) ++public class CommandRegisteredEvent extends ServerEvent implements Cancellable { ++ ++ private static final HandlerList handlers = new HandlerList(); ++ private final String commandLabel; ++ private final Command command; ++ private final com.destroystokyo.paper.brigadier.BukkitBrigadierCommand brigadierCommand; ++ private final RootCommandNode root; ++ private final ArgumentCommandNode defaultArgs; ++ private LiteralCommandNode literal; ++ private boolean rawCommand = false; ++ private boolean cancelled = false; ++ ++ public CommandRegisteredEvent(String commandLabel, com.destroystokyo.paper.brigadier.BukkitBrigadierCommand brigadierCommand, Command command, RootCommandNode root, LiteralCommandNode literal, ArgumentCommandNode defaultArgs) { ++ this.commandLabel = commandLabel; ++ this.brigadierCommand = brigadierCommand; ++ this.command = command; ++ this.root = root; ++ this.literal = literal; ++ this.defaultArgs = defaultArgs; ++ } ++ ++ /** ++ * Gets the command label of the {@link Command} being registered. ++ * ++ * @return the command label ++ */ ++ public String getCommandLabel() { ++ return this.commandLabel; ++ } ++ ++ /** ++ * Gets the {@link BukkitBrigadierCommand} for the {@link Command} being registered. This can be used ++ * as the {@link com.mojang.brigadier.Command command executor} or ++ * {@link com.mojang.brigadier.suggestion.SuggestionProvider} of a {@link com.mojang.brigadier.tree.CommandNode} ++ * to delegate to the {@link Command} being registered. ++ * ++ * @return the {@link BukkitBrigadierCommand} ++ */ ++ public BukkitBrigadierCommand getBrigadierCommand() { ++ return this.brigadierCommand; ++ } ++ ++ /** ++ * Gets the {@link Command} being registered. ++ * ++ * @return the {@link Command} ++ */ ++ public Command getCommand() { ++ return this.command; ++ } ++ ++ /** ++ * Gets the {@link RootCommandNode} which is being registered to. ++ * ++ * @return the {@link RootCommandNode} ++ */ ++ public RootCommandNode getRoot() { ++ return this.root; ++ } ++ ++ /** ++ * Gets the Bukkit APIs default arguments node (greedy string), for if ++ * you wish to reuse it. ++ * ++ * @return default arguments node ++ */ ++ public ArgumentCommandNode getDefaultArgs() { ++ return this.defaultArgs; ++ } ++ ++ /** ++ * Gets the {@link LiteralCommandNode} to be registered for the {@link Command}. ++ * ++ * @return the {@link LiteralCommandNode} ++ */ ++ public LiteralCommandNode getLiteral() { ++ return this.literal; ++ } ++ ++ /** ++ * Sets the {@link LiteralCommandNode} used to register this command. The default literal is mutable, so ++ * this is primarily if you want to completely replace the object. ++ * ++ * @param literal new node ++ */ ++ public void setLiteral(LiteralCommandNode literal) { ++ this.literal = literal; ++ } ++ ++ /** ++ * Gets whether this command should is treated as "raw". ++ * ++ * @see #setRawCommand(boolean) ++ * @return whether this command is treated as "raw" ++ */ ++ public boolean isRawCommand() { ++ return this.rawCommand; ++ } ++ ++ /** ++ * Sets whether this command should be treated as "raw". ++ * ++ *

      A "raw" command will only use the node provided by this event for ++ * sending the command tree to the client. For execution purposes, the default ++ * greedy string execution of a standard Bukkit {@link Command} is used.

      ++ * ++ *

      On older versions of Paper, this was the default and only behavior of this ++ * event.

      ++ * ++ * @param rawCommand whether this command should be treated as "raw" ++ */ ++ public void setRawCommand(final boolean rawCommand) { ++ this.rawCommand = rawCommand; ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ @Override ++ public boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ /** ++ * Cancels registering this command to Brigadier, but will remain in Bukkit Command Map. Can be used to hide a ++ * command from all players. ++ * ++ * {@inheritDoc} ++ */ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancelled = cancel; ++ } ++ ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/brigadier/PaperBrigadier.java b/src/main/java/io/papermc/paper/brigadier/PaperBrigadier.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9df87708206e26167a2c4934deff7fc6f1657106 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/brigadier/PaperBrigadier.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.brigadier; ++ ++import com.mojang.brigadier.Message; ++import io.papermc.paper.command.brigadier.MessageComponentSerializer; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.ComponentLike; ++import net.kyori.adventure.text.TextComponent; ++import org.checkerframework.checker.nullness.qual.NonNull; ++ ++/** ++ * Helper methods to bridge the gaps between Brigadier and Paper-MojangAPI. ++ * @deprecated for removal. See {@link MessageComponentSerializer} for a direct replacement of functionality found in ++ * this class. ++ * As a general entrypoint to brigadier on paper, see {@link io.papermc.paper.command.brigadier.Commands}. ++ */ ++@Deprecated(forRemoval = true, since = "1.20.6") ++public final class PaperBrigadier { ++ private PaperBrigadier() { ++ throw new RuntimeException("PaperBrigadier is not to be instantiated!"); ++ } ++ ++ /** ++ * Create a new Brigadier {@link Message} from a {@link ComponentLike}. ++ * ++ *

      Mostly useful for creating rich suggestion tooltips in combination with other Paper-MojangAPI APIs.

      ++ * ++ * @param componentLike The {@link ComponentLike} to use for the {@link Message} contents ++ * @return A new Brigadier {@link Message} ++ */ ++ public static @NonNull Message message(final @NonNull ComponentLike componentLike) { ++ return MessageComponentSerializer.message().serialize(componentLike.asComponent()); ++ } ++ ++ /** ++ * Create a new {@link Component} from a Brigadier {@link Message}. ++ * ++ *

      If the {@link Message} was created from a {@link Component}, it will simply be ++ * converted back, otherwise a new {@link TextComponent} will be created with the ++ * content of {@link Message#getString()}

      ++ * ++ * @param message The {@link Message} to create a {@link Component} from ++ * @return The created {@link Component} ++ */ ++ public static @NonNull Component componentFromMessage(final @NonNull Message message) { ++ return MessageComponentSerializer.message().deserialize(message); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/BasicCommand.java b/src/main/java/io/papermc/paper/command/brigadier/BasicCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c89d6c4c38e2390cb11ffba182f8741d3726cfd1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/BasicCommand.java +@@ -0,0 +1,62 @@ ++package io.papermc.paper.command.brigadier; ++ ++import java.util.Collection; ++import java.util.Collections; ++import org.bukkit.command.CommandSender; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * Implementing this interface allows for easily creating "Bukkit-style" {@code String[] args} commands. ++ * The implementation handles converting the command to a representation compatible with Brigadier on registration, usually in the form of {@literal /commandlabel }. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@FunctionalInterface ++public interface BasicCommand { ++ ++ /** ++ * Executes the command with the given {@link CommandSourceStack} and arguments. ++ * ++ * @param commandSourceStack the commandSourceStack of the command ++ * @param args the arguments of the command ignoring repeated spaces ++ */ ++ @ApiStatus.OverrideOnly ++ void execute(CommandSourceStack commandSourceStack, String[] args); ++ ++ /** ++ * Suggests possible completions for the given command {@link CommandSourceStack} and arguments. ++ * ++ * @param commandSourceStack the commandSourceStack of the command ++ * @param args the arguments of the command including repeated spaces ++ * @return a collection of suggestions ++ */ ++ @ApiStatus.OverrideOnly ++ default Collection suggest(final CommandSourceStack commandSourceStack, final String[] args) { ++ return Collections.emptyList(); ++ } ++ ++ /** ++ * Checks whether a command sender can receive and run the root command. ++ * ++ * @param sender the command sender trying to execute the command ++ * @return whether the command sender fulfills the root command requirement ++ * @see #permission() ++ */ ++ @ApiStatus.OverrideOnly ++ default boolean canUse(final CommandSender sender) { ++ final String permission = this.permission(); ++ return permission == null || sender.hasPermission(permission); ++ } ++ ++ /** ++ * Returns the permission for the root command used in {@link #canUse(CommandSender)} by default. ++ * ++ * @return the permission for the root command used in {@link #canUse(CommandSender)} ++ */ ++ @ApiStatus.OverrideOnly ++ default @Nullable String permission() { ++ return null; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/CommandRegistrationFlag.java b/src/main/java/io/papermc/paper/command/brigadier/CommandRegistrationFlag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7e24babf746de474c8deec4b147e22031e8dadb2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/CommandRegistrationFlag.java +@@ -0,0 +1,14 @@ ++package io.papermc.paper.command.brigadier; ++ ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * A {@link CommandRegistrationFlag} is used in {@link Commands} registration for internal purposes. ++ *

      ++ * A command library may use this to achieve more specific customization on how their commands are registered. ++ * @apiNote Stability of these flags is not promised! This api is not intended for public use. ++ */ ++@ApiStatus.Internal ++public enum CommandRegistrationFlag { ++ FLATTEN_ALIASES ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/CommandSourceStack.java b/src/main/java/io/papermc/paper/command/brigadier/CommandSourceStack.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ac6f5b754a15e85ce09de4ed4cdee2044b45022c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/CommandSourceStack.java +@@ -0,0 +1,51 @@ ++package io.papermc.paper.command.brigadier; ++ ++import org.bukkit.Location; ++import org.bukkit.command.CommandSender; ++import org.bukkit.entity.Entity; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * The command source type for Brigadier commands registered using Paper API. ++ *

      ++ * While the general use case for CommandSourceStack is similar to that of {@link CommandSender}, it provides access to ++ * important additional context for the command execution. ++ * Specifically, commands such as {@literal /execute} may alter the location or executor of the source stack before ++ * passing it to another command. ++ *

      The {@link CommandSender} returned by {@link #getSender()} may be a "no-op" ++ * instance of {@link CommandSender} in cases where the server either doesn't ++ * exist yet, or no specific sender is available. Methods on such a {@link CommandSender} ++ * will either have no effect or throw an {@link UnsupportedOperationException}.

      ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface CommandSourceStack { ++ ++ /** ++ * Gets the location that this command is being executed at. ++ * ++ * @return a cloned location instance. ++ */ ++ Location getLocation(); ++ ++ /** ++ * Gets the command sender that executed this command. ++ * The sender of a command source stack is the one that initiated/triggered the execution of a command. ++ * It differs to {@link #getExecutor()} as the executor can be changed by a command, e.g. {@literal /execute}. ++ * ++ * @return the command sender instance ++ */ ++ CommandSender getSender(); ++ ++ /** ++ * Gets the entity that executes this command. ++ * May not always be {@link #getSender()} as the executor of a command can be changed to a different entity ++ * than the one that triggered the command. ++ * ++ * @return entity that executes this command ++ */ ++ @Nullable Entity getExecutor(); ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/Commands.java b/src/main/java/io/papermc/paper/command/brigadier/Commands.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e32559772a39af781d89de101b3f7483a339e317 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/Commands.java +@@ -0,0 +1,267 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.mojang.brigadier.CommandDispatcher; ++import com.mojang.brigadier.arguments.ArgumentType; ++import com.mojang.brigadier.builder.LiteralArgumentBuilder; ++import com.mojang.brigadier.builder.RequiredArgumentBuilder; ++import com.mojang.brigadier.tree.LiteralCommandNode; ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.bootstrap.PluginBootstrap; ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; ++import io.papermc.paper.plugin.lifecycle.event.registrar.Registrar; ++import java.util.Collection; ++import java.util.Collections; ++import java.util.Set; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Unmodifiable; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * The registrar for custom commands. Supports Brigadier commands and {@link BasicCommand}. ++ *

      ++ * An example of a command being registered is below ++ *

      {@code
      ++ * class YourPluginClass extends JavaPlugin {
      ++ *
      ++ *     @Override
      ++ *     public void onEnable() {
      ++ *         LifecycleEventManager manager = this.getLifecycleManager();
      ++ *         manager.registerEventHandler(LifecycleEvents.COMMANDS, event -> {
      ++ *             final Commands commands = event.registrar();
      ++ *             commands.register(
      ++ *                 Commands.literal("new-command")
      ++ *                     .executes(ctx -> {
      ++ *                         ctx.getSource().getSender().sendPlainMessage("some message");
      ++ *                         return Command.SINGLE_SUCCESS;
      ++ *                     })
      ++ *                     .build(),
      ++ *                 "some bukkit help description string",
      ++ *                 List.of("an-alias")
      ++ *             );
      ++ *         });
      ++ *     }
      ++ * }
      ++ * }
      ++ *

      ++ * You can also register commands in {@link PluginBootstrap} by getting the {@link LifecycleEventManager} from ++ * {@link BootstrapContext}. ++ * Commands registered in the {@link PluginBootstrap} will be available for datapack's ++ * command function parsing. ++ * Note that commands registered via {@link PluginBootstrap} with the same literals as a vanilla command will override ++ * that command within all loaded datapacks. ++ *

      ++ *

      The {@code register} methods that do not have {@link PluginMeta} as a parameter will ++ * implicitly use the {@link PluginMeta} for the plugin that the {@link io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler} ++ * was registered with.

      ++ * ++ * @see io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents#COMMANDS ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface Commands extends Registrar { ++ ++ /** ++ * Utility to create a literal command node builder with the correct generic. ++ * ++ * @param literal literal name ++ * @return a new builder instance ++ */ ++ static LiteralArgumentBuilder literal(final String literal) { ++ return LiteralArgumentBuilder.literal(literal); ++ } ++ ++ /** ++ * Utility to create a required argument builder with the correct generic. ++ * ++ * @param name the name of the argument ++ * @param argumentType the type of the argument ++ * @param the generic type of the argument value ++ * @return a new required argument builder ++ */ ++ static RequiredArgumentBuilder argument(final String name, final ArgumentType argumentType) { ++ return RequiredArgumentBuilder.argument(name, argumentType); ++ } ++ ++ /** ++ * Gets the underlying {@link CommandDispatcher}. ++ * ++ *

      Note: This is a delicate API that must be used with care to ensure a consistent user experience.

      ++ * ++ *

      When registering commands, it should be preferred to use the {@link #register(PluginMeta, LiteralCommandNode, String, Collection) register methods} ++ * over directly registering to the dispatcher wherever possible. ++ * {@link #register(PluginMeta, LiteralCommandNode, String, Collection) Register methods} automatically handle ++ * command namespacing, command help, plugin association with commands, and more.

      ++ * ++ *

      Example use cases for this method may include: ++ *

        ++ *
      • Implementing integration between an external command framework and Paper (although {@link #register(PluginMeta, LiteralCommandNode, String, Collection) register methods} should still be preferred where possible)
      • ++ *
      • Registering new child nodes to an existing plugin command (for example an "addon" plugin to another plugin may want to do this)
      • ++ *
      • Retrieving existing command nodes to build redirects
      • ++ *
      ++ * ++ * @return the dispatcher instance ++ */ ++ @ApiStatus.Experimental ++ CommandDispatcher getDispatcher(); ++ ++ /** ++ * Registers a command for the current plugin context. ++ * ++ *

      Commands have certain overriding behavior: ++ *

        ++ *
      • Aliases will not override already existing commands (excluding namespaced ones)
      • ++ *
      • The main command/namespaced label will override already existing commands
      • ++ *
      ++ * ++ * @param node the built literal command node ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ default @Unmodifiable Set register(final LiteralCommandNode node) { ++ return this.register(node, null, Collections.emptyList()); ++ } ++ ++ /** ++ * Registers a command for the current plugin context. ++ * ++ *

      Commands have certain overriding behavior: ++ *

        ++ *
      • Aliases will not override already existing commands (excluding namespaced ones)
      • ++ *
      • The main command/namespaced label will override already existing commands
      • ++ *
      ++ * ++ * @param node the built literal command node ++ * @param description the help description for the root literal node ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ default @Unmodifiable Set register(final LiteralCommandNode node, final @Nullable String description) { ++ return this.register(node, description, Collections.emptyList()); ++ } ++ ++ /** ++ * Registers a command for the current plugin context. ++ * ++ *

      Commands have certain overriding behavior: ++ *

        ++ *
      • Aliases will not override already existing commands (excluding namespaced ones)
      • ++ *
      • The main command/namespaced label will override already existing commands
      • ++ *
      ++ * ++ * @param node the built literal command node ++ * @param aliases a collection of aliases to register the literal node's command to ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ default @Unmodifiable Set register(final LiteralCommandNode node, final Collection aliases) { ++ return this.register(node, null, aliases); ++ } ++ ++ /** ++ * Registers a command for the current plugin context. ++ * ++ *

      Commands have certain overriding behavior: ++ *

        ++ *
      • Aliases will not override already existing commands (excluding namespaced ones)
      • ++ *
      • The main command/namespaced label will override already existing commands
      • ++ *
      ++ * ++ * @param node the built literal command node ++ * @param description the help description for the root literal node ++ * @param aliases a collection of aliases to register the literal node's command to ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ @Unmodifiable Set register(LiteralCommandNode node, @Nullable String description, Collection aliases); ++ ++ /** ++ * Registers a command for a plugin. ++ * ++ *

      Commands have certain overriding behavior: ++ *

        ++ *
      • Aliases will not override already existing commands (excluding namespaced ones)
      • ++ *
      • The main command/namespaced label will override already existing commands
      • ++ *
      ++ * ++ * @param pluginMeta the owning plugin's meta ++ * @param node the built literal command node ++ * @param description the help description for the root literal node ++ * @param aliases a collection of aliases to register the literal node's command to ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ @Unmodifiable Set register(PluginMeta pluginMeta, LiteralCommandNode node, @Nullable String description, Collection aliases); ++ ++ /** ++ * This allows configuring the registration of your command, which is not intended for public use. ++ * See {@link Commands#register(PluginMeta, LiteralCommandNode, String, Collection)} for more information. ++ * ++ * @param pluginMeta the owning plugin's meta ++ * @param node the built literal command node ++ * @param description the help description for the root literal node ++ * @param aliases a collection of aliases to register the literal node's command to ++ * @param flags a collection of registration flags that control registration behaviour. ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ * ++ * @apiNote This method is not guaranteed to be stable as it is not intended for public use. ++ * See {@link CommandRegistrationFlag} for a more indepth explanation of this method's use-case. ++ */ ++ @ApiStatus.Internal ++ @Unmodifiable Set registerWithFlags(PluginMeta pluginMeta, LiteralCommandNode node, @Nullable String description, Collection aliases, Set flags); ++ ++ /** ++ * Registers a command under the same logic as {@link Commands#register(LiteralCommandNode, String, Collection)}. ++ * ++ * @param label the label of the to-be-registered command ++ * @param basicCommand the basic command instance to register ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ default @Unmodifiable Set register(final String label, final BasicCommand basicCommand) { ++ return this.register(label, null, Collections.emptyList(), basicCommand); ++ } ++ ++ /** ++ * Registers a command under the same logic as {@link Commands#register(LiteralCommandNode, String, Collection)}. ++ * ++ * @param label the label of the to-be-registered command ++ * @param description the help description for the root literal node ++ * @param basicCommand the basic command instance to register ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ default @Unmodifiable Set register(final String label, final @Nullable String description, final BasicCommand basicCommand) { ++ return this.register(label, description, Collections.emptyList(), basicCommand); ++ } ++ ++ /** ++ * Registers a command under the same logic as {@link Commands#register(LiteralCommandNode, String, Collection)}. ++ * ++ * @param label the label of the to-be-registered command ++ * @param aliases a collection of aliases to register the basic command under. ++ * @param basicCommand the basic command instance to register ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ default @Unmodifiable Set register(final String label, final Collection aliases, final BasicCommand basicCommand) { ++ return this.register(label, null, aliases, basicCommand); ++ } ++ ++ /** ++ * Registers a command under the same logic as {@link Commands#register(LiteralCommandNode, String, Collection)}. ++ * ++ * @param label the label of the to-be-registered command ++ * @param description the help description for the root literal node ++ * @param aliases a collection of aliases to register the basic command under. ++ * @param basicCommand the basic command instance to register ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ @Unmodifiable Set register(String label, @Nullable String description, Collection aliases, BasicCommand basicCommand); ++ ++ /** ++ * Registers a command under the same logic as {@link Commands#register(PluginMeta, LiteralCommandNode, String, Collection)}. ++ * ++ * @param pluginMeta the owning plugin's meta ++ * @param label the label of the to-be-registered command ++ * @param description the help description for the root literal node ++ * @param aliases a collection of aliases to register the basic command under. ++ * @param basicCommand the basic command instance to register ++ * @return successfully registered root command labels (including aliases and namespaced variants) ++ */ ++ @Unmodifiable Set register(PluginMeta pluginMeta, String label, @Nullable String description, Collection aliases, BasicCommand basicCommand); ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializer.java b/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..19f3dc12426be09613a13b5889f77627a81305f4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializer.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.command.brigadier; ++ ++import com.mojang.brigadier.Message; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.serializer.ComponentSerializer; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++/** ++ * A component serializer for converting between {@link Message} and {@link Component}. ++ */ ++@ApiStatus.Experimental ++@NullMarked ++@ApiStatus.NonExtendable ++public interface MessageComponentSerializer extends ComponentSerializer { ++ ++ /** ++ * A component serializer for converting between {@link Message} and {@link Component}. ++ * ++ * @return serializer instance ++ */ ++ static MessageComponentSerializer message() { ++ return MessageComponentSerializerHolder.PROVIDER.orElseThrow(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializerHolder.java b/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializerHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2db12952461c92a64505d6646f6f49f824e83050 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializerHolder.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.command.brigadier; ++ ++import java.util.Optional; ++import java.util.ServiceLoader; ++import org.jetbrains.annotations.ApiStatus; ++ ++@ApiStatus.Internal ++final class MessageComponentSerializerHolder { ++ ++ static final Optional PROVIDER = ServiceLoader.load(MessageComponentSerializer.class) ++ .findFirst(); ++} +diff --git a/src/main/java/io/papermc/paper/command/brigadier/argument/ArgumentTypes.java b/src/main/java/io/papermc/paper/command/brigadier/argument/ArgumentTypes.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9abb9ff33672036bb548c688c5661dc8f237aae2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/brigadier/argument/ArgumentTypes.java +@@ -0,0 +1,371 @@ ++package io.papermc.paper.command.brigadier.argument; ++ ++import com.mojang.brigadier.arguments.ArgumentType; ++import io.papermc.paper.command.brigadier.argument.predicate.ItemStackPredicate; ++import io.papermc.paper.command.brigadier.argument.range.DoubleRangeProvider; ++import io.papermc.paper.command.brigadier.argument.range.IntegerRangeProvider; ++import io.papermc.paper.command.brigadier.argument.resolvers.BlockPositionResolver; ++import io.papermc.paper.command.brigadier.argument.resolvers.FinePositionResolver; ++import io.papermc.paper.command.brigadier.argument.resolvers.PlayerProfileListResolver; ++import io.papermc.paper.command.brigadier.argument.resolvers.selector.EntitySelectorArgumentResolver; ++import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver; ++import io.papermc.paper.entity.LookAnchor; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.TypedKey; ++import java.util.UUID; ++import net.kyori.adventure.key.Key; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.format.Style; ++import org.bukkit.GameMode; ++import org.bukkit.HeightMap; ++import org.bukkit.NamespacedKey; ++import org.bukkit.World; ++import org.bukkit.block.BlockState; ++import org.bukkit.block.structure.Mirror; ++import org.bukkit.block.structure.StructureRotation; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.scoreboard.Criteria; ++import org.bukkit.scoreboard.DisplaySlot; ++import org.jetbrains.annotations.ApiStatus; ++import org.jspecify.annotations.NullMarked; ++ ++import static io.papermc.paper.command.brigadier.argument.VanillaArgumentProvider.provider; ++ ++/** ++ * Vanilla Minecraft includes several custom {@link ArgumentType}s that are recognized by the client. ++ * Many of these argument types include client-side completions and validation, and some include command signing context. ++ * ++ *

      This class allows creating instances of these types for use in plugin commands, with friendly API result types.

      ++ * ++ *

      {@link CustomArgumentType} is provided for customizing parsing or result types server-side, while sending the vanilla argument type to the client.

      ++ */ ++@ApiStatus.Experimental ++@NullMarked ++public final class ArgumentTypes { ++ ++ /** ++ * Represents a selector that can capture any ++ * single entity. ++ * ++ * @return argument that takes one entity ++ */ ++ public static ArgumentType entity() { ++ return provider().entity(); ++ } ++ ++ /** ++ * Represents a selector that can capture multiple ++ * entities. ++ * ++ * @return argument that takes multiple entities ++ */ ++ public static ArgumentType entities() { ++ return provider().entities(); ++ } ++ ++ /** ++ * Represents a selector that can capture a ++ * singular player entity. ++ * ++ * @return argument that takes one player ++ */ ++ public static ArgumentType player() { ++ return provider().player(); ++ } ++ ++ /** ++ * Represents a selector that can capture multiple ++ * player entities. ++ * ++ * @return argument that takes multiple players ++ */ ++ public static ArgumentType players() { ++ return provider().players(); ++ } ++ ++ /** ++ * A selector argument that provides a list ++ * of player profiles. ++ * ++ * @return player profile argument ++ */ ++ public static ArgumentType playerProfiles() { ++ return provider().playerProfiles(); ++ } ++ ++ /** ++ * A block position argument. ++ * ++ * @return block position argument ++ */ ++ public static ArgumentType blockPosition() { ++ return provider().blockPosition(); ++ } ++ ++ /** ++ * A fine position argument. ++ * ++ * @return fine position argument ++ * @see #finePosition(boolean) to center whole numbers ++ */ ++ public static ArgumentType finePosition() { ++ return finePosition(false); ++ } ++ ++ /** ++ * A fine position argument. ++ * ++ * @param centerIntegers if whole numbers should be centered (+0.5) ++ * @return fine position argument ++ */ ++ public static ArgumentType finePosition(final boolean centerIntegers) { ++ return provider().finePosition(centerIntegers); ++ } ++ ++ /** ++ * A blockstate argument which will provide rich parsing for specifying ++ * the specific block variant and then the block entity NBT if applicable. ++ * ++ * @return argument ++ */ ++ public static ArgumentType blockState() { ++ return provider().blockState(); ++ } ++ ++ /** ++ * An ItemStack argument which provides rich parsing for ++ * specifying item material and item NBT information. ++ * ++ * @return argument ++ */ ++ public static ArgumentType itemStack() { ++ return provider().itemStack(); ++ } ++ ++ /** ++ * An item predicate argument. ++ * ++ * @return argument ++ */ ++ public static ArgumentType itemPredicate() { ++ return provider().itemStackPredicate(); ++ } ++ ++ /** ++ * An argument for parsing {@link NamedTextColor}s. ++ * ++ * @return argument ++ */ ++ public static ArgumentType namedColor() { ++ return provider().namedColor(); ++ } ++ ++ /** ++ * A component argument. ++ * ++ * @return argument ++ */ ++ public static ArgumentType component() { ++ return provider().component(); ++ } ++ ++ /** ++ * A style argument. ++ * ++ * @return argument ++ */ ++ public static ArgumentType