From 24224e4f9d4dc2d16e1d4b1f1de6b2863d1f3962 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 20 Mar 2021 13:06:33 -0400 Subject: [PATCH 001/139] Add CurseForge release workflow --- .github/workflows/ci.yml | 21 +++------- .github/workflows/release.yml | 34 ++++++++++++++++ pom.xml | 2 +- scripts/generate_changelog.sh | 26 +++++++++--- scripts/get_spigot_versions.sh | 56 ++++++++++++++++++++++++++ scripts/install_spigot_dependencies.sh | 35 ++-------------- scripts/set_curseforge_env.sh | 42 +++++++++++++++++++ scripts/set_release_env.sh | 32 +++++++++++++++ 8 files changed, 195 insertions(+), 53 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 scripts/get_spigot_versions.sh create mode 100644 scripts/set_curseforge_env.sh create mode 100644 scripts/set_release_env.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a73e107..41ddcce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,28 +60,17 @@ jobs: - name: Download Artifacts uses: actions/download-artifact@v2 - - name: Generate changelog - run: . scripts/generate_changelog.sh + - name: Set Release Variables + run: . scripts/set_release_env.sh - name: Create Release id: create-release - uses: actions/create-release@v1 + uses: softprops/action-gh-release@v0.1.5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} + name: ${{ env.VERSIONED_NAME }} body: ${{ env.GENERATED_CHANGELOG }} draft: true prerelease: false - - - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1.0.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: ./OpenInv.jar - asset_name: OpenInv.jar - asset_content_type: application/java-archive \ No newline at end of file + files: ./OpenInv.jar diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..8901e47 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,34 @@ +name: Release to CurseForge + +on: + release: + types: [ released ] + +jobs: + curseforge_release: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v2 + + - name: Set CurseForge Variables + run: . scripts/set_curseforge_env.sh + + - name: Fetch Github Release Asset + uses: dsaltares/fetch-gh-release-asset@0.0.5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: ${{ github.event.release.id }} + file: OpenInv.jar + + - name: Create CurseForge Release + uses: itsmeow/curseforge-upload@v3 + with: + token: ${{ secrets.CURSEFORGE_TOKEN }} + project_id: 31432 + game_endpoint: minecraft + file_path: ./OpenInv.jar + changelog: ${{ github.event.release.body }} + display_name: ${{ github.event.release.name }} + game_versions: ${{ env.CURSEFORGE_MINECRAFT_VERSIONS }} + release-type: release diff --git a/pom.xml b/pom.xml index 6882a32..6362a21 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ com.lishid openinvparent - OpenInvParent + OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ 4.1.6-SNAPSHOT diff --git a/scripts/generate_changelog.sh b/scripts/generate_changelog.sh index 72c823d..8aa0ec7 100644 --- a/scripts/generate_changelog.sh +++ b/scripts/generate_changelog.sh @@ -15,14 +15,15 @@ # along with this program. If not, see . # -# A script for generating a changelog from Git. -# # Note that this script is designed for use in GitHub Actions, and is not # particularly robust nor configurable. Run from project parent directory. # Query GitHub for the username of the given email address. # Falls through to the given author name. -lookup_email_username() { +function lookup_email_username() { + # Ensure fallthrough is set + ${2:?Must provide email and username as parameters, i.e. 'lookup_email_username admin@example.com Admin'} + lookup=$(curl -G --data-urlencode "q=$1 in:email" https://api.github.com/search/users -H 'Accept: application/vnd.github.v3+json' | grep '"login":' | sed -e 's/^.*": "//g' -e 's/",.*$//g') if [[ $lookup ]]; then @@ -32,10 +33,23 @@ lookup_email_username() { fi } +# Get a pretty list of supported Minecraft versions +function get_minecraft_versions() { + versions=$(. ./scripts/get_spigot_versions.sh) + + for version in "${versions[@]}"; do + # Append comma if variable is set, then append version + minecraft_versions="${minecraft_versions:+${minecraft_versions},}${version%%-R*}" + done + + echo "${minecraft_versions}" +} + # Use formatted log to pull authors list authors_raw=$(git log --pretty=format:"%ae|%an" "$(git describe --tags --abbrev=0 @^)"..@) readarray -t authors <<<"$authors_raw" +# Use associative array to map email to author name declare -A author_data for author in "${authors[@]}"; do @@ -55,7 +69,7 @@ for author in "${authors[@]}"; do done # Fetch actual formatted changelog -changelog=$(git log --pretty=format:"%s (%h) - %ae" "$(git describe --tags --abbrev=0 @^)"..@) +changelog=$(git log --pretty=format:"* %s (%h) - %ae" "$(git describe --tags --abbrev=0 @^)"..@) for author_email in "${!author_data[@]}"; do # Ignore case when matching @@ -64,4 +78,6 @@ for author_email in "${!author_data[@]}"; do changelog=${changelog//$author_email/${author_data[$author_email]}} done -echo "GENERATED_CHANGELOG<> "$GITHUB_ENV" +minecraft_versions=$(get_minecraft_versions) + +printf "## Supported Minecraft versions\n%s\n\n##Changelog\n%s" "${minecraft_versions}" "${changelog}" diff --git a/scripts/get_spigot_versions.sh b/scripts/get_spigot_versions.sh new file mode 100644 index 0000000..252291d --- /dev/null +++ b/scripts/get_spigot_versions.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Copyright (C) 2011-2021 lishid. All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Note that this script is designed for use in GitHub Actions, and is not +# particularly robust nor configurable. Run from project parent directory. + +# Use a nameref as a cache - maven evaluation is pretty slow. +# Re-calling the script and relying on it to handle caching is way easier than passing around info. +declare -a spigot_versions + +# We don't care about concatenation - either it's not null and we return or it's null and we instantiate. +# shellcheck disable=SC2199 +if [[ ${spigot_versions[@]} ]]; then + for spigot_version in "${spigot_versions[@]}"; do + echo "$spigot_version" + done + return +fi + +# Pull Spigot dependency information from Maven. +modules=$(mvn help:evaluate -Dexpression=project.modules -q -DforceStdout -P all -pl internal | grep -oP '(?<=)(.*)(?=<\/string>)') + +declare -n versions="spigot_versions" + +for module in "${modules[@]}"; do + # Get number of dependencies declared in pom of specified internal module. + max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl internal/"$module" | grep -c "") + + for ((i=0; i < max_index; i++)); do + # Get artifactId of dependency. + artifact_id=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].artifactId -q -DforceStdout -P all -pl internal/"$module") + + # Ensure dependency is Spigot. + if [[ "$artifact_id" == spigot ]]; then + # Get Spigot version. + spigot_version=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].version -q -DforceStdout -P all -pl internal/"$module") + versions+=("$spigot_version") + echo "$spigot_version" + break + fi + done +done diff --git a/scripts/install_spigot_dependencies.sh b/scripts/install_spigot_dependencies.sh index 09e93e1..0225669 100644 --- a/scripts/install_spigot_dependencies.sh +++ b/scripts/install_spigot_dependencies.sh @@ -15,39 +15,12 @@ # along with this program. If not, see . # -# A script for installing required Spigot versions. -# -# Note that this script is designed for use in GitHub Actions, and is -# not particularly robust nor configurable. -# In its current state, the script must be run from OpenInv's parent -# project directory and will always install BuildTools to ~/buildtools. +# Note that this script is designed for use in GitHub Actions, and is not +# particularly robust nor configurable. Run from project parent directory. buildtools_dir=~/buildtools buildtools=$buildtools_dir/BuildTools.jar -get_spigot_versions () { - # Get all submodules of internal module - modules=$(mvn help:evaluate -Dexpression=project.modules -q -DforceStdout -P all -pl internal | grep -oP '(?<=)(.*)(?=<\/string>)') - for module in "${modules[@]}"; do - - # Get number of dependencies declared in pom of specified internal module - max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl internal/"$module" | grep -c "") - - for ((i=0; i < max_index; i++)); do - # Get artifactId of dependency - artifact_id=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].artifactId -q -DforceStdout -P all -pl internal/"$module") - - # Ensure dependency is spigot - if [[ "$artifact_id" == spigot ]]; then - # Get spigot version - spigot_version=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].version -q -DforceStdout -P all -pl internal/"$module") - echo "$spigot_version" - break - fi - done - done -} - get_buildtools () { if [[ -d $buildtools_dir && -f $buildtools ]]; then return @@ -57,7 +30,7 @@ get_buildtools () { wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O $buildtools } -versions=$(get_spigot_versions) +versions=$(. ./scripts/get_spigot_versions.sh) echo Found Spigot dependencies: "$versions" for version in "${versions[@]}"; do @@ -66,7 +39,7 @@ for version in "${versions[@]}"; do mvn dependency:get -Dartifact=org.spigotmc:spigot:"$version" -q -o || exit_code=$? if [ $exit_code -ne 0 ]; then echo Installing missing Spigot version "$version" - revision=$(echo "$version" | grep -oP '(\d+\.\d+(\.\d+)?)(?=-R[0-9\.]+-SNAPSHOT)') + revision=${version//-R.*/} get_buildtools java -jar $buildtools -rev "$revision" else diff --git a/scripts/set_curseforge_env.sh b/scripts/set_curseforge_env.sh new file mode 100644 index 0000000..08940fa --- /dev/null +++ b/scripts/set_curseforge_env.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Copyright (C) 2011-2021 lishid. All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Note that this script is designed for use in GitHub Actions, and is not +# particularly robust nor configurable. Run from project parent directory. + +# Parse Spigot dependency information into major Minecraft versions +function get_curseforge_minecraft_versions() { + versions=$(. ./scripts/get_spigot_versions.sh) + + for version in "${versions[@]}"; do + # Parse Minecraft major version + version="${version%[.-]"${version#*.*[.-]}"}" + + # Skip already listed versions + if [[ "$minecraft_versions" =~ "$version"($|,) ]]; then + continue + fi + + # Append comma if variable is set, then append version + minecraft_versions="${minecraft_versions:+${minecraft_versions},}Minecraft ${version}" + done + + echo "${minecraft_versions}" +} + +minecraft_versions=$(get_curseforge_minecraft_versions) +echo "CURSEFORGE_MINECRAFT_VERSIONS=$minecraft_versions" diff --git a/scripts/set_release_env.sh b/scripts/set_release_env.sh new file mode 100644 index 0000000..3d850dc --- /dev/null +++ b/scripts/set_release_env.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# +# Copyright (C) 2011-2021 lishid. All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Note that this script is designed for use in GitHub Actions, and is not +# particularly robust nor configurable. Run from project parent directory. + +# Get a pretty string of the project's name and version +# Disable SC warning about variable expansion for this function - those are Maven variables. +# shellcheck disable=SC2016 +function get_versioned_name() { + mvn -q -Dexec.executable=echo -Dexec.args='${project.name} ${project.version}' --non-recursive exec:exec +} + +# Set GitHub environmental variables +echo "VERSIONED_NAME=$(get_versioned_name)" >> "$GITHUB_ENV" + +changelog="$(. ./scripts/generate_changelog.sh)" +printf "GENERATED_CHANGELOG<> "$GITHUB_ENV" -- 2.49.1 From 15ee6ef9a5b6f42c721d893edeb6e161086ab54e Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 20 Mar 2021 13:19:33 -0400 Subject: [PATCH 002/139] Fix revision number --- scripts/install_spigot_dependencies.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install_spigot_dependencies.sh b/scripts/install_spigot_dependencies.sh index 0225669..84fce3f 100644 --- a/scripts/install_spigot_dependencies.sh +++ b/scripts/install_spigot_dependencies.sh @@ -39,7 +39,7 @@ for version in "${versions[@]}"; do mvn dependency:get -Dartifact=org.spigotmc:spigot:"$version" -q -o || exit_code=$? if [ $exit_code -ne 0 ]; then echo Installing missing Spigot version "$version" - revision=${version//-R.*/} + revision=${version%%-R*} get_buildtools java -jar $buildtools -rev "$revision" else -- 2.49.1 From 18c7916d796fd0a3a5ea8de7c5023766e7ab4314 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sun, 21 Mar 2021 07:56:51 -0400 Subject: [PATCH 003/139] Include release script --- scripts/tag_release.sh | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 scripts/tag_release.sh diff --git a/scripts/tag_release.sh b/scripts/tag_release.sh new file mode 100644 index 0000000..2e4d022 --- /dev/null +++ b/scripts/tag_release.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# +# Copyright (C) 2011-2021 lishid. All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +if [[ ! $1 ]]; then + echo "Please provide a version string." + return +fi + +version="$1" +snapshot="${version%.*}.$((${version##*.} + 1))-SNAPSHOT" + +mvn versions:set -DnewVersion="$version" + +git add . +git commit -S -m "Bump version to $version for release" +git tag -s "$version" -m "Release $version" + +mvn clean package -am -P all + +mvn versions:set -DnewVersion="$snapshot" + +git add . +git commit -S -m "Bump version to $snapshot for development" -- 2.49.1 From e09e7c59c7457980b8e2f164aa7bf907190f0bbf Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 22 Mar 2021 09:42:11 -0400 Subject: [PATCH 004/139] Fix release action --- .github/workflows/ci.yml | 14 +++++++------- .github/workflows/release.yml | 2 ++ scripts/generate_changelog.sh | 11 +++++------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41ddcce..72f4c31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,8 +2,6 @@ name: OpenInv CI on: push: - create: - types: [tag] pull_request_target: jobs: @@ -51,18 +49,20 @@ jobs: release: name: Create Github Release needs: [ build ] - if: github.event_name == 'create' && github.event.ref_type == 'tag' + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set Release Variables + run: bash ./scripts/set_release_env.sh - name: Download Artifacts uses: actions/download-artifact@v2 - - name: Set Release Variables - run: . scripts/set_release_env.sh - - name: Create Release id: create-release uses: softprops/action-gh-release@v0.1.5 @@ -73,4 +73,4 @@ jobs: body: ${{ env.GENERATED_CHANGELOG }} draft: true prerelease: false - files: ./OpenInv.jar + files: ./dist/OpenInv.jar diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8901e47..76eb6d9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,8 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: Set CurseForge Variables run: . scripts/set_curseforge_env.sh diff --git a/scripts/generate_changelog.sh b/scripts/generate_changelog.sh index 8aa0ec7..81cddfb 100644 --- a/scripts/generate_changelog.sh +++ b/scripts/generate_changelog.sh @@ -21,9 +21,6 @@ # Query GitHub for the username of the given email address. # Falls through to the given author name. function lookup_email_username() { - # Ensure fallthrough is set - ${2:?Must provide email and username as parameters, i.e. 'lookup_email_username admin@example.com Admin'} - lookup=$(curl -G --data-urlencode "q=$1 in:email" https://api.github.com/search/users -H 'Accept: application/vnd.github.v3+json' | grep '"login":' | sed -e 's/^.*": "//g' -e 's/",.*$//g') if [[ $lookup ]]; then @@ -45,8 +42,10 @@ function get_minecraft_versions() { echo "${minecraft_versions}" } +previous_tag=$(git describe --tags --abbrev=0 @^) + # Use formatted log to pull authors list -authors_raw=$(git log --pretty=format:"%ae|%an" "$(git describe --tags --abbrev=0 @^)"..@) +authors_raw=$(git log --pretty=format:"%ae|%an" "$previous_tag"..@) readarray -t authors <<<"$authors_raw" # Use associative array to map email to author name @@ -69,7 +68,7 @@ for author in "${authors[@]}"; do done # Fetch actual formatted changelog -changelog=$(git log --pretty=format:"* %s (%h) - %ae" "$(git describe --tags --abbrev=0 @^)"..@) +changelog=$(git log --pretty=format:"* %s (%h) - %ae" "$previous_tag"..@) for author_email in "${!author_data[@]}"; do # Ignore case when matching @@ -80,4 +79,4 @@ done minecraft_versions=$(get_minecraft_versions) -printf "## Supported Minecraft versions\n%s\n\n##Changelog\n%s" "${minecraft_versions}" "${changelog}" +printf "## Supported Minecraft versions\n%s\n\n## Changelog\n%s" "${minecraft_versions}" "${changelog}" -- 2.49.1 From 0e3bdb8741caba032ea826f7bbd109d37016fc5b Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 22 Mar 2021 10:21:09 -0400 Subject: [PATCH 005/139] Convert to HTML for CF --- .github/workflows/release.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 76eb6d9..b607b90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,6 +23,12 @@ jobs: version: ${{ github.event.release.id }} file: OpenInv.jar + - name: Convert to HTML + id: convert_to_html + uses: lifepal/markdown-to-html@v1.2 + with: + text: ${{ github.event.release.body }} + - name: Create CurseForge Release uses: itsmeow/curseforge-upload@v3 with: @@ -30,7 +36,7 @@ jobs: project_id: 31432 game_endpoint: minecraft file_path: ./OpenInv.jar - changelog: ${{ github.event.release.body }} + changelog: ${{ steps.convert_to_html.outputs.html }} display_name: ${{ github.event.release.name }} game_versions: ${{ env.CURSEFORGE_MINECRAFT_VERSIONS }} release-type: release -- 2.49.1 From ae6c3bd292acd9946d86518d11d16e677ccf7689 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 22 Mar 2021 10:24:48 -0400 Subject: [PATCH 006/139] Move release location --- .../src/main/java/com/lishid/openinv/util/InternalAccessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java b/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java index fb24552..236d0cf 100644 --- a/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java +++ b/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java @@ -84,7 +84,7 @@ public class InternalAccessor { return "https://github.com/lishid/OpenInv/releases/tag/4.1.5"; case "v1_16_R3": default: - return "https://github.com/lishid/OpenInv/releases"; + return "https://github.com/Jikoo/OpenInv/releases"; } } -- 2.49.1 From ccc6f4b4a6bb531b9e93bf070e30ab34cc59c355 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 22 Mar 2021 11:50:56 -0400 Subject: [PATCH 007/139] Fix CF release --- .github/workflows/release.yml | 2 +- scripts/set_curseforge_env.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b607b90..a850dc3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,4 +39,4 @@ jobs: changelog: ${{ steps.convert_to_html.outputs.html }} display_name: ${{ github.event.release.name }} game_versions: ${{ env.CURSEFORGE_MINECRAFT_VERSIONS }} - release-type: release + release_type: release diff --git a/scripts/set_curseforge_env.sh b/scripts/set_curseforge_env.sh index 08940fa..dcd8b85 100644 --- a/scripts/set_curseforge_env.sh +++ b/scripts/set_curseforge_env.sh @@ -39,4 +39,4 @@ function get_curseforge_minecraft_versions() { } minecraft_versions=$(get_curseforge_minecraft_versions) -echo "CURSEFORGE_MINECRAFT_VERSIONS=$minecraft_versions" +echo "CURSEFORGE_MINECRAFT_VERSIONS=$minecraft_versions" >> "$GITHUB_ENV" -- 2.49.1 From c440f618c90a67f8a90f57fc509a1f67db3702c5 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 22 Mar 2021 11:52:04 -0400 Subject: [PATCH 008/139] Bump version to 4.1.6 for release --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/pom.xml | 2 +- internal/v1_16_R3/pom.xml | 4 ++-- plugin/pom.xml | 4 ++-- pom.xml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index cc34012..e8bf585 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.6-SNAPSHOT + 4.1.6 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 421f77e..41283f9 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.6-SNAPSHOT + 4.1.6 openinvassembly diff --git a/internal/pom.xml b/internal/pom.xml index fd28dce..fbacebb 100644 --- a/internal/pom.xml +++ b/internal/pom.xml @@ -20,7 +20,7 @@ com.lishid openinvparent - 4.1.6-SNAPSHOT + 4.1.6 openinvinternal diff --git a/internal/v1_16_R3/pom.xml b/internal/v1_16_R3/pom.xml index 74905ed..37df536 100644 --- a/internal/v1_16_R3/pom.xml +++ b/internal/v1_16_R3/pom.xml @@ -22,7 +22,7 @@ com.lishid openinvinternal - 4.1.6-SNAPSHOT + 4.1.6 openinvadapter1_16_R3 @@ -38,7 +38,7 @@ com.lishid openinvplugincore - 4.1.6-SNAPSHOT + 4.1.6 diff --git a/plugin/pom.xml b/plugin/pom.xml index 358b396..827bcc5 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.6-SNAPSHOT + 4.1.6 openinvplugincore @@ -31,7 +31,7 @@ com.lishid openinvapi - 4.1.6-SNAPSHOT + 4.1.6 org.spigotmc diff --git a/pom.xml b/pom.xml index 6362a21..0307715 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.6-SNAPSHOT + 4.1.6 pom -- 2.49.1 From 889c2ffdabac3059677350f2736ea631fc42c19f Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 22 Mar 2021 11:52:14 -0400 Subject: [PATCH 009/139] Bump version to 4.1.7-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/pom.xml | 2 +- internal/v1_16_R3/pom.xml | 4 ++-- plugin/pom.xml | 4 ++-- pom.xml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index e8bf585..5957eeb 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.6 + 4.1.7-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 41283f9..d982b92 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.6 + 4.1.7-SNAPSHOT openinvassembly diff --git a/internal/pom.xml b/internal/pom.xml index fbacebb..e5c7354 100644 --- a/internal/pom.xml +++ b/internal/pom.xml @@ -20,7 +20,7 @@ com.lishid openinvparent - 4.1.6 + 4.1.7-SNAPSHOT openinvinternal diff --git a/internal/v1_16_R3/pom.xml b/internal/v1_16_R3/pom.xml index 37df536..3446dcd 100644 --- a/internal/v1_16_R3/pom.xml +++ b/internal/v1_16_R3/pom.xml @@ -22,7 +22,7 @@ com.lishid openinvinternal - 4.1.6 + 4.1.7-SNAPSHOT openinvadapter1_16_R3 @@ -38,7 +38,7 @@ com.lishid openinvplugincore - 4.1.6 + 4.1.7-SNAPSHOT diff --git a/plugin/pom.xml b/plugin/pom.xml index 827bcc5..25ea5ce 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.6 + 4.1.7-SNAPSHOT openinvplugincore @@ -31,7 +31,7 @@ com.lishid openinvapi - 4.1.6 + 4.1.7-SNAPSHOT org.spigotmc diff --git a/pom.xml b/pom.xml index 0307715..b7b97b6 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.6 + 4.1.7-SNAPSHOT pom -- 2.49.1 From 2a0e0d33d85d2f7559000d663346369076eb732b Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 22 Mar 2021 11:56:39 -0400 Subject: [PATCH 010/139] Don't shade annotations --- api/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/api/pom.xml b/api/pom.xml index 5957eeb..9b5d9ba 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -32,6 +32,7 @@ org.jetbrains annotations 17.0.0 + provided org.spigotmc -- 2.49.1 From 2b563e0e1b6c3527419ed5d43bbcc6fbd50c26bd Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 22 Mar 2021 12:07:53 -0400 Subject: [PATCH 011/139] Don't convert release notes to HTML We'll try this in another few months when there're enough changes to be worth it. --- .github/workflows/release.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a850dc3..b08f280 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,12 +23,6 @@ jobs: version: ${{ github.event.release.id }} file: OpenInv.jar - - name: Convert to HTML - id: convert_to_html - uses: lifepal/markdown-to-html@v1.2 - with: - text: ${{ github.event.release.body }} - - name: Create CurseForge Release uses: itsmeow/curseforge-upload@v3 with: @@ -36,7 +30,7 @@ jobs: project_id: 31432 game_endpoint: minecraft file_path: ./OpenInv.jar - changelog: ${{ steps.convert_to_html.outputs.html }} + changelog: ${{ github.event.release.body }} display_name: ${{ github.event.release.name }} game_versions: ${{ env.CURSEFORGE_MINECRAFT_VERSIONS }} release_type: release -- 2.49.1 From 7ab86f2af978e35f75625f9126a774f496c2d094 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 22 Mar 2021 12:20:58 -0400 Subject: [PATCH 012/139] Fix build --- api/pom.xml | 15 --------------- plugin/pom.xml | 6 ------ pom.xml | 15 +++++++++++++++ 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 9b5d9ba..dfba6c4 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -27,21 +27,6 @@ openinvapi OpenInvAPI - - - org.jetbrains - annotations - 17.0.0 - provided - - - org.spigotmc - spigot-api - 1.16.5-R0.1-SNAPSHOT - provided - - - diff --git a/plugin/pom.xml b/plugin/pom.xml index 25ea5ce..e926663 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -33,12 +33,6 @@ openinvapi 4.1.7-SNAPSHOT - - org.spigotmc - spigot-api - 1.15.2-R0.1-SNAPSHOT - provided - diff --git a/pom.xml b/pom.xml index b7b97b6..0101a38 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,21 @@ + + + org.jetbrains + annotations + 17.0.0 + provided + + + org.spigotmc + spigot-api + 1.16.5-R0.1-SNAPSHOT + provided + + + -- 2.49.1 From 5b186564850b248c2ca11e162f35a6d1f0967b8c Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sun, 28 Mar 2021 11:10:39 -0400 Subject: [PATCH 013/139] Fix incorrect player name in title Closes #13 --- .../java/com/lishid/openinv/internal/OpenInventoryView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java index 8fc6f09..dd3fd20 100644 --- a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java +++ b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java @@ -17,6 +17,7 @@ package com.lishid.openinv.internal; import com.lishid.openinv.OpenInv; +import java.util.Objects; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; @@ -62,7 +63,7 @@ public class OpenInventoryView extends InventoryView { @Override public @NotNull String getTitle() { if (title == null) { - HumanEntity owner = getPlayer(); + HumanEntity owner = (HumanEntity) Objects.requireNonNull(inventory.getBukkitInventory().getHolder()); String localTitle = OpenInv.getPlugin(OpenInv.class) .getLocalizedMessage( -- 2.49.1 From 6c4818dfd954e97ee594af0588d65408abc94a32 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sun, 28 Mar 2021 11:12:49 -0400 Subject: [PATCH 014/139] Add method to access owner Makes handling ISpecialInventory ownership much more consistent with a lot less spaghetti. --- .../com/lishid/openinv/internal/ISpecialInventory.java | 8 ++++++++ .../openinv/internal/v1_16_R3/SpecialEnderChest.java | 5 +++++ .../openinv/internal/v1_16_R3/SpecialPlayerInventory.java | 5 +++++ .../com/lishid/openinv/internal/OpenInventoryView.java | 3 +-- .../com/lishid/openinv/listeners/InventoryListener.java | 2 +- 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java b/api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java index e6929c9..d53ae32 100644 --- a/api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java +++ b/api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java @@ -16,6 +16,7 @@ package com.lishid.openinv.internal; +import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.jetbrains.annotations.NotNull; @@ -48,4 +49,11 @@ public interface ISpecialInventory { */ boolean isInUse(); + /** + * Gets the Player associated with this ISpecialInventory. + * + * @return the HumanEntity + */ + @NotNull HumanEntity getPlayer(); + } diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialEnderChest.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialEnderChest.java index 7fe8bee..f5717ef 100644 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialEnderChest.java +++ b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialEnderChest.java @@ -80,6 +80,11 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn } } + @Override + public @NotNull Player getPlayer() { + return owner.getBukkitEntity(); + } + @Override public void update() { this.owner.getEnderChest().update(); diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialPlayerInventory.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialPlayerInventory.java index ada345c..cffc59e 100644 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialPlayerInventory.java +++ b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialPlayerInventory.java @@ -212,6 +212,11 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP this.playerOnline = false; } + @Override + public @NotNull HumanEntity getPlayer() { + return this.player.getBukkitEntity(); + } + @Override public ItemStack splitStack(int i, final int j) { List list = this.items; diff --git a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java index dd3fd20..6a3fe84 100644 --- a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java +++ b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java @@ -17,7 +17,6 @@ package com.lishid.openinv.internal; import com.lishid.openinv.OpenInv; -import java.util.Objects; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; @@ -63,7 +62,7 @@ public class OpenInventoryView extends InventoryView { @Override public @NotNull String getTitle() { if (title == null) { - HumanEntity owner = (HumanEntity) Objects.requireNonNull(inventory.getBukkitInventory().getHolder()); + HumanEntity owner = inventory.getPlayer(); String localTitle = OpenInv.getPlugin(OpenInv.class) .getLocalizedMessage( diff --git a/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java b/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java index eee6686..2b87c50 100644 --- a/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java +++ b/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java @@ -199,7 +199,7 @@ public class InventoryListener implements Listener { } // Only specially handle actions in the player's own inventory. - return !event.getWhoClicked().equals(event.getView().getTopInventory().getHolder()); + return !event.getWhoClicked().equals(playerInventory.getPlayer()); } } -- 2.49.1 From e3acb5384a5871ed986fb38fedd4b7de80f0a7c0 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 5 Apr 2021 19:12:45 -0400 Subject: [PATCH 015/139] Deprecate API for removed notification configuration --- api/src/main/java/com/lishid/openinv/IOpenInv.java | 12 ++++++++++-- plugin/src/main/java/com/lishid/openinv/OpenInv.java | 10 ---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/api/src/main/java/com/lishid/openinv/IOpenInv.java b/api/src/main/java/com/lishid/openinv/IOpenInv.java index b4f4e8f..2d18f65 100644 --- a/api/src/main/java/com/lishid/openinv/IOpenInv.java +++ b/api/src/main/java/com/lishid/openinv/IOpenInv.java @@ -232,16 +232,24 @@ public interface IOpenInv { * when a container is activated with AnyChest. * * @return true unless configured otherwise + * @deprecated OpenInv uses action bar chat for notifications. Whether or not they show is based on language settings. */ - boolean notifyAnyChest(); + @Deprecated + default boolean notifyAnyChest() { + return true; + } /** * Check the configuration value for whether or not OpenInv displays a notification to the user * when a container is activated with SilentChest. * * @return true unless configured otherwise + * @deprecated OpenInv uses action bar chat for notifications. Whether or not they show is based on language settings. */ - boolean notifySilentChest(); + @Deprecated + default boolean notifySilentChest() { + return true; + } /** * Mark a Player as no longer in use by a Plugin to allow OpenInv to remove it from the cache diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index 8137584..a8ac3a1 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -334,16 +334,6 @@ public class OpenInv extends JavaPlugin implements IOpenInv { } } - @Override - public boolean notifyAnyChest() { - return this.getConfig().getBoolean("notify.any-chest", true); - } - - @Override - public boolean notifySilentChest() { - return this.getConfig().getBoolean("notify.silent-chest", true); - } - @Override public void onDisable() { -- 2.49.1 From eae402113869cad95c98096bd2761f49c48cd17c Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 11 Apr 2021 18:29:37 -0400 Subject: [PATCH 016/139] Add relocation notice --- README.MD | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.MD b/README.MD index 66c183f..4fdab3e 100644 --- a/README.MD +++ b/README.MD @@ -1,3 +1,6 @@ +## Notice +I am now maintaining OpenInv over at [Jikoo/OpenInv](https://github.com/Jikoo/OpenInv) because I needed higher levels of access to add secrets to the repository for Github Actions. It feels ruder to send an email saying what amounts to "pls op" than to redirect people to my fork, though neither option is polite. Existing issues will remain open here until resolved (you can't transfer issues across organizations/users), but any new issues in this repo will be closed without resolution. + ## About OpenInv is a [Bukkit plugin](https://dev.bukkit.org/bukkit-plugins/openinv/) which allows users to open and edit anyone's inventory or ender chest - online or not! -- 2.49.1 From 30425d2baa5c141705da21d8d83488fdf5bfa6ee Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 21 Apr 2021 14:35:22 -0400 Subject: [PATCH 017/139] Don't bother validating names Fixes problems with players from Geyser not being obtainable when using FloodGate. --- api/src/main/java/com/lishid/openinv/IOpenInv.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/com/lishid/openinv/IOpenInv.java b/api/src/main/java/com/lishid/openinv/IOpenInv.java index 2d18f65..ae5c41e 100644 --- a/api/src/main/java/com/lishid/openinv/IOpenInv.java +++ b/api/src/main/java/com/lishid/openinv/IOpenInv.java @@ -24,6 +24,7 @@ import com.lishid.openinv.internal.ISpecialPlayerInventory; import com.lishid.openinv.util.InventoryAccess; import com.lishid.openinv.util.StringMetric; import java.util.UUID; +import java.util.logging.Level; import java.util.logging.Logger; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; @@ -153,10 +154,7 @@ public interface IOpenInv { if (Bukkit.getServer().isPrimaryThread()) { this.getLogger().warning("Call to OpenInv#matchPlayer made on the main thread!"); this.getLogger().warning("This can cause the server to hang, potentially severely."); - this.getLogger().warning("Trace:"); - for (StackTraceElement element : new Throwable().fillInStackTrace().getStackTrace()) { - this.getLogger().warning(element.toString()); - } + this.getLogger().log(Level.WARNING, new Throwable("Current stack trace"), () -> "Current stack trace"); } OfflinePlayer player; @@ -172,11 +170,6 @@ public interface IOpenInv { // Not a UUID } - // Ensure name is valid if server is in online mode to avoid unnecessary searching - if (Bukkit.getServer().getOnlineMode() && !name.matches("[a-zA-Z0-9_]{3,16}")) { - return null; - } - player = Bukkit.getServer().getPlayerExact(name); if (player != null) { -- 2.49.1 From bd207e948a353a3435961e4cd93f5ccfc27a870a Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 21 Apr 2021 11:07:15 -0400 Subject: [PATCH 018/139] Simplify dependency management Use dependencyManagement for versioning shared dependencies Use pluginManagement for versioning and configuring plugins --- README.MD | 95 +++++-------- api/pom.xml | 18 ++- assembly/pom.xml | 2 +- assembly/src/assembly/reactor-uberjar.xml | 20 ++- internal/pom.xml | 42 ------ internal/v1_16_R3/pom.xml | 35 ++--- plugin/pom.xml | 25 +--- pom.xml | 162 +++++++++++++--------- scripts/get_spigot_versions.sh | 9 +- 9 files changed, 176 insertions(+), 232 deletions(-) delete mode 100644 internal/pom.xml diff --git a/README.MD b/README.MD index 66c183f..3cf7cd9 100644 --- a/README.MD +++ b/README.MD @@ -15,48 +15,7 @@ OpenInv is a [Bukkit plugin](https://dev.bukkit.org/bukkit-plugins/openinv/) whi - **AnyContainer**: Open containers, even if blocked by ocelots or blocks. ## Commands - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CommandAliasesDescription
/openinv [player]oi, inv, openOpen a player's inventory. If unspecified, will select last player opened or own if none opened previously.
/openender [player]oeOpen a player's ender chest. If unspecified, will select last player opened or own if none opened previously.
/searchinv <item> [minAmount]siLists all online players that have a certain item in their inventory.
/searchender <item> [minAmount]seLists all online players that have a certain item in their ender chest.
/searchenchant <[enchantment] [MinLevel]>searchenchantsLists all online players with a specific enchantment.
/anycontainer [check]ac, anychestCheck or toggle the AnyContainer function, allowing opening blocked containers.
/silentcontainer [check]sc, silentchestCheck or toggle the SilentContainer function, allowing opening containers silently.
+See [the wiki](https://github.com/Jikoo/OpenInv/wiki/Commands). ## Permissions @@ -143,8 +102,39 @@ OpenInv is a [Bukkit plugin](https://dev.bukkit.org/bukkit-plugins/openinv/) whi
## For Developers -To compile, the relevant Craftbukkit/Spigot jars must be installed in your local repository using the install plugin. -Ex: `mvn install:install-file -Dpackaging=jar -Dfile=spigot-1.8-R0.1-SNAPSHOT.jar -DgroupId=org.spigotmc -DartifactId=spigot -Dversion=1.8-R0.1-SNAPSHOT` + +### As a Dependency +The OpenInv API is available via [JitPack](https://jitpack.io/). +```xml + + + jitpack.io + https://jitpack.io + + +``` +```xml + + + com.github.jikoo.OpenInv + openinvapi + ${openinv.version} + + +``` + +### Compilation +To compile, the relevant Spigot jars must be installed in your local repository using the `install` plugin: +```shell +mvn install:install-file -Dpackaging=jar -Dfile=spigot-1.8-R0.1-SNAPSHOT.jar \ + -DgroupId=org.spigotmc -DartifactId=spigot -Dversion=1.8-R0.1-SNAPSHOT +``` +Note that BuildTools automatically installs produced files. If you use BuildTools to compile Spigot locally, you don't need to install it manually. +If you want to use Paper as a dependency, you can install it by executing PaperClip with the property `paperclip.install` set to true: +```shell +wget -O paperclip.jar https://papermc.io/api/v1/paper/1.16.5/latest/download +java -jar -Dpaperclip.install=true paperclip.jar +``` To compile for a single version, specify the NMS revision you are targeting: `mvn -pl -am clean install` @@ -153,20 +143,3 @@ To compile for a set of versions, you'll need to use a profile. The only provide For more information, check out the [official Maven guide](http://maven.apache.org/guides/introduction/introduction-to-profiles.html). The final file is `target/OpenInv.jar` - -## License -``` -Copyright (C) 2011-2020 lishid. All rights reserved. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 3. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -``` diff --git a/api/pom.xml b/api/pom.xml index dfba6c4..a04210b 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -19,23 +19,29 @@ 4.0.0 - com.lishid openinvparent + com.lishid 4.1.7-SNAPSHOT openinvapi OpenInvAPI + + + annotations + org.jetbrains + + + spigot-api + org.spigotmc + + + maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - diff --git a/assembly/pom.xml b/assembly/pom.xml index d982b92..51126a4 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -26,6 +26,7 @@ openinvassembly OpenInvAssembly + pom ../target @@ -34,7 +35,6 @@ maven-assembly-plugin - 3.2.0 reactor-uberjar diff --git a/assembly/src/assembly/reactor-uberjar.xml b/assembly/src/assembly/reactor-uberjar.xml index 36beb33..afe5bfa 100644 --- a/assembly/src/assembly/reactor-uberjar.xml +++ b/assembly/src/assembly/reactor-uberjar.xml @@ -14,9 +14,9 @@ ~ along with this program. If not, see . --> - + reactor-uberjar @@ -34,8 +34,18 @@ / true - - + + + + META-INF/** + + + + false diff --git a/internal/pom.xml b/internal/pom.xml deleted file mode 100644 index e5c7354..0000000 --- a/internal/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - 4.0.0 - - - com.lishid - openinvparent - 4.1.7-SNAPSHOT - - - openinvinternal - OpenInvInternal - - pom - - - - - all - - v1_16_R3 - - - - - - diff --git a/internal/v1_16_R3/pom.xml b/internal/v1_16_R3/pom.xml index 3446dcd..69e9502 100644 --- a/internal/v1_16_R3/pom.xml +++ b/internal/v1_16_R3/pom.xml @@ -20,8 +20,9 @@ 4.0.0 + openinvparent com.lishid - openinvinternal + ../../pom.xml 4.1.7-SNAPSHOT @@ -30,44 +31,32 @@ - org.spigotmc spigot - 1.16.5-R0.1-SNAPSHOT + org.spigotmc provided + 1.16.5-R0.1-SNAPSHOT + openinvapi com.lishid + + openinvplugincore - 4.1.7-SNAPSHOT + com.lishid + + + annotations + org.jetbrains - org.apache.maven.plugins maven-shade-plugin - 3.2.2 - - true - - - - package - - shade - - - - maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - diff --git a/plugin/pom.xml b/plugin/pom.xml index e926663..1ae03f7 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -19,8 +19,8 @@ 4.0.0 - com.lishid openinvparent + com.lishid 4.1.7-SNAPSHOT @@ -29,9 +29,8 @@ - com.lishid openinvapi - 4.1.7-SNAPSHOT + com.lishid @@ -42,31 +41,13 @@ true + - org.apache.maven.plugins maven-shade-plugin - 3.2.2 - - true - - - - package - - shade - - - - maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - diff --git a/pom.xml b/pom.xml index 0101a38..a166257 100644 --- a/pom.xml +++ b/pom.xml @@ -27,33 +27,32 @@ UTF-8 + 1.8 + 1.8 - - api - plugin - internal - assembly - - - - - all - - - all - true - - + + api + plugin + internal/v1_16_R3 + assembly + + + default + + true + + + api + plugin + assembly + + @@ -63,57 +62,84 @@ - - - org.jetbrains - annotations - 17.0.0 - provided - - - org.spigotmc - spigot-api - 1.16.5-R0.1-SNAPSHOT - provided - - + + + + annotations + org.jetbrains + provided + 20.1.0 + + + spigot-api + org.spigotmc + provided + 1.16.5-R0.1-SNAPSHOT + + + openinvapi + com.lishid + compile + 4.1.7-SNAPSHOT + + + openinvplugincore + com.lishid + compile + 4.1.7-SNAPSHOT + + + - - - org.apache.maven.plugins - maven-shade-plugin - 3.2.2 - - - - *:* - - - META-INF/maven/** - - - - - - - package - - shade - - - - + + + + maven-shade-plugin + + + + + com.lishid:openinv* + + ** + + + + *:* + + + META-INF/MANIFEST.MF + + + + true + + + + package + + shade + + + + org.apache.maven.plugins + 3.2.4 + - - maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - - - + + maven-compiler-plugin + org.apache.maven.plugins + 3.8.1 + + + + maven-assembly-plugin + org.apache.maven.plugins + 3.3.0 + + + diff --git a/scripts/get_spigot_versions.sh b/scripts/get_spigot_versions.sh index 252291d..64c2fea 100644 --- a/scripts/get_spigot_versions.sh +++ b/scripts/get_spigot_versions.sh @@ -32,22 +32,23 @@ if [[ ${spigot_versions[@]} ]]; then fi # Pull Spigot dependency information from Maven. -modules=$(mvn help:evaluate -Dexpression=project.modules -q -DforceStdout -P all -pl internal | grep -oP '(?<=)(.*)(?=<\/string>)') +# Since we only care about Spigot versions, only check modules in the folder internal. +readarray -t modules <<< "$(mvn help:evaluate -Dexpression=project.modules -q -DforceStdout -P all | grep -oP '(?<=)(internal/.*)(?=)')" declare -n versions="spigot_versions" for module in "${modules[@]}"; do # Get number of dependencies declared in pom of specified internal module. - max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl internal/"$module" | grep -c "") + max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl "$module" | grep -c "") for ((i=0; i < max_index; i++)); do # Get artifactId of dependency. - artifact_id=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].artifactId -q -DforceStdout -P all -pl internal/"$module") + artifact_id=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].artifactId -q -DforceStdout -P all -pl "$module") # Ensure dependency is Spigot. if [[ "$artifact_id" == spigot ]]; then # Get Spigot version. - spigot_version=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].version -q -DforceStdout -P all -pl internal/"$module") + spigot_version=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].version -q -DforceStdout -P all -pl "$module") versions+=("$spigot_version") echo "$spigot_version" break -- 2.49.1 From 9e0ca479a5d69014b48d5ea714b22195d1fa3f6f Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 26 May 2021 08:16:25 -0400 Subject: [PATCH 019/139] Fix Bukkit data not being loaded while offline Closes #16 --- .../lishid/openinv/internal/v1_16_R3/OpenPlayer.java | 11 ++++++++++- .../openinv/internal/v1_16_R3/PlayerDataManager.java | 6 ++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java index def3f96..ec87e3b 100644 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java +++ b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java @@ -32,15 +32,24 @@ public class OpenPlayer extends CraftPlayer { super(server, entity); } + @Override + public void loadData() { + // See CraftPlayer#loadData + NBTTagCompound loaded = this.server.getHandle().playerFileData.load(this.getHandle()); + if (loaded != null) { + readExtraData(loaded); + } + } + @Override public void saveData() { - super.saveData(); EntityPlayer player = this.getHandle(); // See net.minecraft.server.WorldNBTStorage#save(EntityPlayer) try { WorldNBTStorage worldNBTStorage = player.server.getPlayerList().playerFileData; NBTTagCompound playerData = player.save(new NBTTagCompound()); + setExtraData(playerData); if (!isOnline()) { // Special case: save old vehicle data diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java index 5a29ceb..35cae33 100644 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java +++ b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java @@ -57,8 +57,7 @@ public class PlayerDataManager implements IPlayerDataManager { } } - @NotNull - public static EntityPlayer getHandle(final Player player) { + public static @NotNull EntityPlayer getHandle(final Player player) { if (player instanceof CraftPlayer) { return ((CraftPlayer) player).getHandle(); } @@ -78,9 +77,8 @@ public class PlayerDataManager implements IPlayerDataManager { return nmsPlayer; } - @Nullable @Override - public Player loadPlayer(@NotNull final OfflinePlayer offline) { + public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { // Ensure player has data if (!offline.hasPlayedBefore()) { return null; -- 2.49.1 From 0f417014290c3d686a242a9d04909ca6ccfe8849 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 26 May 2021 08:17:11 -0400 Subject: [PATCH 020/139] Update annotations --- plugin/pom.xml | 8 ++++++++ pom.xml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugin/pom.xml b/plugin/pom.xml index 1ae03f7..6a164c5 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -32,6 +32,14 @@ openinvapi com.lishid + + annotations + org.jetbrains + + + spigot-api + org.spigotmc + diff --git a/pom.xml b/pom.xml index a166257..d563330 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ annotations org.jetbrains provided - 20.1.0 + 21.0.1 spigot-api -- 2.49.1 From 2cfc55813b5b45183028f1dbd18982ed567966d9 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 29 May 2021 09:51:25 -0400 Subject: [PATCH 021/139] Bump version to 4.1.7 for release --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_16_R3/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index a04210b..bd10fb7 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.7-SNAPSHOT + 4.1.7 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 51126a4..5dfc745 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.7-SNAPSHOT + 4.1.7 openinvassembly diff --git a/internal/v1_16_R3/pom.xml b/internal/v1_16_R3/pom.xml index 69e9502..d2e8f39 100644 --- a/internal/v1_16_R3/pom.xml +++ b/internal/v1_16_R3/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.7-SNAPSHOT + 4.1.7 openinvadapter1_16_R3 diff --git a/plugin/pom.xml b/plugin/pom.xml index 6a164c5..e48aa2f 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.7-SNAPSHOT + 4.1.7 openinvplugincore diff --git a/pom.xml b/pom.xml index d563330..7c102a6 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.7-SNAPSHOT + 4.1.7 pom @@ -80,13 +80,13 @@ openinvapi com.lishid compile - 4.1.7-SNAPSHOT + 4.1.7 openinvplugincore com.lishid compile - 4.1.7-SNAPSHOT + 4.1.7 -- 2.49.1 From 4d800361d8a4f4dbd5332ec3680a5c51cbbab685 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 29 May 2021 09:51:39 -0400 Subject: [PATCH 022/139] Bump version to 4.1.8-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_16_R3/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index bd10fb7..8182f60 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.7 + 4.1.8-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 5dfc745..0390710 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.7 + 4.1.8-SNAPSHOT openinvassembly diff --git a/internal/v1_16_R3/pom.xml b/internal/v1_16_R3/pom.xml index d2e8f39..673afbb 100644 --- a/internal/v1_16_R3/pom.xml +++ b/internal/v1_16_R3/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.7 + 4.1.8-SNAPSHOT openinvadapter1_16_R3 diff --git a/plugin/pom.xml b/plugin/pom.xml index e48aa2f..3bf3393 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.7 + 4.1.8-SNAPSHOT openinvplugincore diff --git a/pom.xml b/pom.xml index 7c102a6..8940b5f 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.7 + 4.1.8-SNAPSHOT pom @@ -80,13 +80,13 @@ openinvapi com.lishid compile - 4.1.7 + 4.1.8-SNAPSHOT
openinvplugincore com.lishid compile - 4.1.7 + 4.1.8-SNAPSHOT -- 2.49.1 From 9a2b379a649fd22fe5e84f7d3e138effc167a648 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Tue, 8 Jun 2021 11:38:26 -0400 Subject: [PATCH 023/139] Escape changelog for YAML With 1.17 releasing soon, we'll get to see if this was the issue very shortly. Worst case scenario the yaml is still messed up, but since the changelog is now the last element, unless it's so badly malformed that the entire action can't run the file should still upload even if the changelog does not. --- .github/workflows/release.yml | 13 +++++++------ scripts/set_curseforge_env.sh | 13 +++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b08f280..5b78047 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,9 +13,6 @@ jobs: with: fetch-depth: 0 - - name: Set CurseForge Variables - run: . scripts/set_curseforge_env.sh - - name: Fetch Github Release Asset uses: dsaltares/fetch-gh-release-asset@0.0.5 with: @@ -23,6 +20,9 @@ jobs: version: ${{ github.event.release.id }} file: OpenInv.jar + - name: Set CurseForge Variables + run: . scripts/set_curseforge_env.sh "${{ github.event.release.body }}" + - name: Create CurseForge Release uses: itsmeow/curseforge-upload@v3 with: @@ -30,7 +30,8 @@ jobs: project_id: 31432 game_endpoint: minecraft file_path: ./OpenInv.jar - changelog: ${{ github.event.release.body }} - display_name: ${{ github.event.release.name }} - game_versions: ${{ env.CURSEFORGE_MINECRAFT_VERSIONS }} + display_name: "${{ github.event.release.name }}" + game_versions: "${{ env.CURSEFORGE_MINECRAFT_VERSIONS }}" release_type: release + changelog_type: markdown + changelog: "${{ env.CURSEFORGE_CHANGELOG }}" diff --git a/scripts/set_curseforge_env.sh b/scripts/set_curseforge_env.sh index dcd8b85..f21dd40 100644 --- a/scripts/set_curseforge_env.sh +++ b/scripts/set_curseforge_env.sh @@ -38,5 +38,18 @@ function get_curseforge_minecraft_versions() { echo "${minecraft_versions}" } +# Modify provided changelog to not break when inserted into yaml file. +function get_yaml_safe_changelog() { + changelog=$1 + # Since we're using a flow scalar, newlines need to be doubled. + echo "${changelog// +/ + +}" +} + minecraft_versions=$(get_curseforge_minecraft_versions) echo "CURSEFORGE_MINECRAFT_VERSIONS=$minecraft_versions" >> "$GITHUB_ENV" + +changelog=$(get_yaml_safe_changelog "$1") +printf "CURSEFORGE_CHANGELOG<> "$GITHUB_ENV" \ No newline at end of file -- 2.49.1 From 9fccea60f765cff6c929ac64bcf194483f4ca689 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 11 Jun 2021 10:50:36 -0400 Subject: [PATCH 024/139] Update copyright --- api/pom.xml | 2 +- api/src/main/java/com/lishid/openinv/IOpenInv.java | 2 +- .../java/com/lishid/openinv/internal/IAnySilentContainer.java | 2 +- .../main/java/com/lishid/openinv/internal/IInventoryAccess.java | 2 +- .../java/com/lishid/openinv/internal/ISpecialEnderChest.java | 2 +- .../java/com/lishid/openinv/internal/ISpecialInventory.java | 2 +- .../com/lishid/openinv/internal/ISpecialPlayerInventory.java | 2 +- api/src/main/java/com/lishid/openinv/util/InventoryAccess.java | 2 +- api/src/main/java/com/lishid/openinv/util/StringMetric.java | 2 +- assembly/pom.xml | 2 +- assembly/src/assembly/reactor-uberjar.xml | 2 +- internal/v1_16_R3/pom.xml | 2 +- .../lishid/openinv/internal/v1_16_R3/AnySilentContainer.java | 2 +- .../com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java | 2 +- .../com/lishid/openinv/internal/v1_16_R3/SpecialEnderChest.java | 2 +- .../openinv/internal/v1_16_R3/SpecialPlayerInventory.java | 2 +- plugin/pom.xml | 2 +- plugin/src/main/java/com/lishid/openinv/OpenInv.java | 2 +- .../com/lishid/openinv/commands/ContainerSettingCommand.java | 2 +- .../main/java/com/lishid/openinv/commands/OpenInvCommand.java | 2 +- .../com/lishid/openinv/commands/SearchContainerCommand.java | 2 +- .../java/com/lishid/openinv/commands/SearchEnchantCommand.java | 2 +- .../main/java/com/lishid/openinv/commands/SearchInvCommand.java | 2 +- .../java/com/lishid/openinv/internal/IPlayerDataManager.java | 2 +- .../java/com/lishid/openinv/listeners/InventoryListener.java | 2 +- .../main/java/com/lishid/openinv/listeners/PlayerListener.java | 2 +- .../main/java/com/lishid/openinv/listeners/PluginListener.java | 2 +- plugin/src/main/java/com/lishid/openinv/util/Cache.java | 2 +- plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java | 2 +- .../src/main/java/com/lishid/openinv/util/InternalAccessor.java | 2 +- .../src/main/java/com/lishid/openinv/util/LanguageManager.java | 2 +- plugin/src/main/java/com/lishid/openinv/util/Permissions.java | 2 +- plugin/src/main/java/com/lishid/openinv/util/TabCompleter.java | 2 +- pom.xml | 2 +- 34 files changed, 34 insertions(+), 34 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 8182f60..7adc2da 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -1,5 +1,5 @@ + + + 4.0.0 + + + openinvparent + com.lishid + ../../pom.xml + 4.1.8-SNAPSHOT + + + openinvadapter1_17_R1 + OpenInvAdapter1_17_R1 + + + 16 + 16 + + + + + spigot + org.spigotmc + provided + 1.17-R0.1-SNAPSHOT + + + openinvapi + com.lishid + + + openinvplugincore + com.lishid + + + annotations + org.jetbrains + + + + + + + maven-shade-plugin + + + false + + + + maven-compiler-plugin + + + + + diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java new file mode 100644 index 0000000..3f7085e --- /dev/null +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_17_R1; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IAnySilentContainer; +import java.lang.reflect.Field; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.minecraft.core.BlockPosition; +import net.minecraft.network.chat.ChatMessage; +import net.minecraft.network.chat.IChatBaseComponent; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.server.level.PlayerInteractManager; +import net.minecraft.world.ITileInventory; +import net.minecraft.world.InventoryLargeChest; +import net.minecraft.world.TileInventory; +import net.minecraft.world.entity.player.EntityHuman; +import net.minecraft.world.entity.player.PlayerInventory; +import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.ContainerChest; +import net.minecraft.world.inventory.Containers; +import net.minecraft.world.inventory.InventoryEnderChest; +import net.minecraft.world.level.EnumGamemode; +import net.minecraft.world.level.World; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.BlockBarrel; +import net.minecraft.world.level.block.BlockChest; +import net.minecraft.world.level.block.BlockChestTrapped; +import net.minecraft.world.level.block.BlockShulkerBox; +import net.minecraft.world.level.block.entity.TileEntity; +import net.minecraft.world.level.block.entity.TileEntityChest; +import net.minecraft.world.level.block.entity.TileEntityEnderChest; +import net.minecraft.world.level.block.entity.TileEntityLootable; +import net.minecraft.world.level.block.state.IBlockData; +import net.minecraft.world.level.block.state.properties.BlockPropertyChestType; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.block.Barrel; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.EnderChest; +import org.bukkit.block.ShulkerBox; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; +import org.bukkit.block.data.type.Chest; +import org.bukkit.entity.Cat; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; +import org.bukkit.util.BoundingBox; +import org.jetbrains.annotations.NotNull; + +public class AnySilentContainer implements IAnySilentContainer { + + private Field playerInteractManagerGamemode; + + public AnySilentContainer() { + try { + this.playerInteractManagerGamemode = PlayerInteractManager.class.getDeclaredField("b"); + this.playerInteractManagerGamemode.setAccessible(true); + } catch (NoSuchFieldException | SecurityException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to directly write player gamemode! SilentChest will fail."); + logger.log(Level.WARNING, "Error obtaining gamemode field", e); + } + } + + @Override + public boolean isAnySilentContainer(@NotNull final org.bukkit.block.Block bukkitBlock) { + if (bukkitBlock.getType() == Material.ENDER_CHEST) { + return true; + } + BlockState state = bukkitBlock.getState(); + return state instanceof org.bukkit.block.Chest + || state instanceof org.bukkit.block.ShulkerBox + || state instanceof org.bukkit.block.Barrel; + } + + @Override + public boolean isAnyContainerNeeded(@NotNull final Player p, @NotNull final org.bukkit.block.Block block) { + BlockState blockState = block.getState(); + + // Barrels do not require AnyContainer. + if (blockState instanceof Barrel) { + return false; + } + + // Enderchests require a non-occluding block on top to open. + if (blockState instanceof EnderChest) { + return block.getRelative(0, 1, 0).getType().isOccluding(); + } + + // Shulker boxes require 1/2 a block clear in the direction they open. + if (blockState instanceof ShulkerBox) { + BoundingBox boundingBox = block.getBoundingBox(); + if (boundingBox.getVolume() > 1) { + // Shulker box is already open. + return false; + } + + BlockData blockData = block.getBlockData(); + if (!(blockData instanceof Directional directional)) { + // Shouldn't be possible. Just in case, demand AnyChest. + return true; + } + + BlockFace face = directional.getFacing(); + boundingBox.shift(face.getDirection()); + // Return whether or not bounding boxes overlap. + return block.getRelative(face, 1).getBoundingBox().overlaps(boundingBox); + } + + if (!(blockState instanceof org.bukkit.block.Chest)) { + return false; + } + + if (isBlockedChest(block)) { + return true; + } + + BlockData blockData = block.getBlockData(); + if (!(blockData instanceof Chest chest) || ((Chest) blockData).getType() == Chest.Type.SINGLE) { + return false; + } + + int ordinal = (chest.getFacing().ordinal() + 4 + (chest.getType() == Chest.Type.RIGHT ? -1 : 1)) % 4; + BlockFace relativeFace = BlockFace.values()[ordinal]; + org.bukkit.block.Block relative = block.getRelative(relativeFace); + + if (relative.getType() != block.getType()) { + return false; + } + + BlockData relativeData = relative.getBlockData(); + if (!(relativeData instanceof Chest relativeChest)) { + return false; + } + + if (relativeChest.getFacing() != chest.getFacing() + || relativeChest.getType() != (chest.getType() == Chest.Type.RIGHT ? Chest.Type.LEFT : Chest.Type.RIGHT)) { + return false; + } + + return isBlockedChest(relative); + } + + private boolean isBlockedChest(org.bukkit.block.Block block) { + org.bukkit.block.Block relative = block.getRelative(0, 1, 0); + return relative.getType().isOccluding() + || block.getWorld().getNearbyEntities(BoundingBox.of(relative), entity -> entity instanceof Cat).size() > 0; + } + + @Override + public boolean activateContainer( + @NotNull final Player bukkitPlayer, + final boolean silentchest, + @NotNull final org.bukkit.block.Block bukkitBlock) { + + // Silent ender chest is API-only + if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) { + bukkitPlayer.openInventory(bukkitPlayer.getEnderChest()); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + final World world = player.getWorld(); + final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + final TileEntity tile = world.getTileEntity(blockPosition); + + if (tile == null) { + return false; + } + + if (tile instanceof TileEntityEnderChest) { + // Anychest ender chest. See net.minecraft.world.level.block.BlockEnderChest + InventoryEnderChest enderChest = player.getEnderChest(); + enderChest.a((TileEntityEnderChest) tile); + player.openContainer(new TileInventory((containerCounter, playerInventory, ignored) -> { + Containers containers = PlayerDataManager.getContainers(enderChest.getSize()); + int rows = enderChest.getSize() / 9; + return new ContainerChest(containers, containerCounter, playerInventory, enderChest, rows); + }, new ChatMessage("container.enderchest"))); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + if (!(tile instanceof ITileInventory tileInventory)) { + return false; + } + + IBlockData blockData = world.getType(blockPosition); + Block block = blockData.getBlock(); + + if (block instanceof BlockChest) { + + BlockPropertyChestType chestType = blockData.get(BlockChest.c); + + if (chestType != BlockPropertyChestType.a) { + + BlockPosition adjacentBlockPosition = blockPosition.shift(BlockChest.h(blockData)); + IBlockData adjacentBlockData = world.getType(adjacentBlockPosition); + + if (adjacentBlockData.getBlock() == block) { + + BlockPropertyChestType adjacentChestType = adjacentBlockData.get(BlockChest.c); + + if (adjacentChestType != BlockPropertyChestType.a && chestType != adjacentChestType + && adjacentBlockData.get(BlockChest.b) == blockData.get(BlockChest.b)) { + + TileEntity adjacentTile = world.getTileEntity(adjacentBlockPosition); + + if (adjacentTile instanceof TileEntityChest && tileInventory instanceof TileEntityChest) { + TileEntityChest rightChest = chestType == BlockPropertyChestType.c ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile; + TileEntityChest leftChest = chestType == BlockPropertyChestType.c ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory); + + if (silentchest && (rightChest.g != null || leftChest.g != null)) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + + tileInventory = new ITileInventory() { + public Container createMenu(int containerCounter, PlayerInventory playerInventory, EntityHuman entityHuman) { + leftChest.d(playerInventory.l); + rightChest.d(playerInventory.l); + return ContainerChest.b(containerCounter, playerInventory, new InventoryLargeChest(rightChest, leftChest)); + } + + public IChatBaseComponent getScoreboardDisplayName() { + if (leftChest.hasCustomName()) { + return leftChest.getScoreboardDisplayName(); + } + if (rightChest.hasCustomName()) { + return rightChest.getScoreboardDisplayName(); + } + return new ChatMessage("container.chestDouble"); + } + }; + } + } + } + } + + if (block instanceof BlockChestTrapped) { + bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); + } else { + bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED); + } + } + + if (block instanceof BlockShulkerBox) { + bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED); + } + + if (block instanceof BlockBarrel) { + bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL); + } + + // AnyChest only - SilentChest not active, container unsupported, or unnecessary. + if (!silentchest || player.d.getGameMode() == EnumGamemode.d) { + player.openContainer(tileInventory); + return true; + } + + // SilentChest requires access to setting players' gamemode directly. + if (this.playerInteractManagerGamemode == null) { + return false; + } + + if (tile instanceof TileEntityLootable lootable) { + if (lootable.g != null) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + } + + EnumGamemode gamemode = player.d.getGameMode(); + this.forceGameMode(player, EnumGamemode.d); + player.openContainer(tileInventory); + this.forceGameMode(player, gamemode); + return true; + } + + @Override + public void deactivateContainer(@NotNull final Player bukkitPlayer) { + if (this.playerInteractManagerGamemode == null) { + return; + } + + InventoryView view = bukkitPlayer.getOpenInventory(); + switch (view.getType()) { + case CHEST: + case ENDER_CHEST: + case SHULKER_BOX: + case BARREL: + break; + default: + return; + } + + EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + // Force game mode change without informing plugins or players. + EnumGamemode gamemode = player.d.getGameMode(); + this.forceGameMode(player, EnumGamemode.d); + + // See EntityPlayer#closeInventory - can't call or we'd recursively deactivate. + player.bV.b(player); + player.bU.a(player.bV); + player.bV = player.bU; + + // Revert forced game mode. + this.forceGameMode(player, gamemode); + } + + private void forceGameMode(final EntityPlayer player, final EnumGamemode gameMode) { + if (this.playerInteractManagerGamemode == null) { + // No need to warn repeatedly, error on startup and lack of function should be enough. + return; + } + try { + this.playerInteractManagerGamemode.setAccessible(true); + this.playerInteractManagerGamemode.set(player.d, gameMode); + // TODO: may need additional calls to update abilities to prevent container sound + animation + // gameMode.a(player.getAbilities()); + // player.updateAbilities(); + // should be the fix if it doesn't work as-is + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + +} diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java new file mode 100644 index 0000000..15ca1b7 --- /dev/null +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_17_R1; + +import java.io.File; +import java.io.FileOutputStream; +import net.minecraft.nbt.NBTCompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.level.storage.WorldNBTStorage; +import org.apache.logging.log4j.LogManager; +import org.bukkit.craftbukkit.v1_17_R1.CraftServer; +import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; + +public class OpenPlayer extends CraftPlayer { + + public OpenPlayer(CraftServer server, EntityPlayer entity) { + super(server, entity); + } + + @Override + public void loadData() { + super.loadData(); + // See CraftPlayer#loadData + NBTTagCompound loaded = this.server.getHandle().r.load(this.getHandle()); + if (loaded != null) { + readExtraData(loaded); + } + } + + @Override + public void saveData() { + EntityPlayer player = this.getHandle(); + // See net.minecraft.world.level.storage.WorldNBTStorage#save(EntityHuman) + try { + WorldNBTStorage worldNBTStorage = player.c.getPlayerList().r; + + NBTTagCompound playerData = player.save(new NBTTagCompound()); + setExtraData(playerData); + + if (!isOnline()) { + // Special case: save old vehicle data + NBTTagCompound oldData = worldNBTStorage.load(player); + + if (oldData != null && oldData.hasKeyOfType("RootVehicle", 10)) { + // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound) + playerData.set("RootVehicle", oldData.getCompound("RootVehicle")); + } + } + + File file = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat.tmp"); + File file1 = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat"); + + NBTCompressedStreamTools.a(playerData, new FileOutputStream(file)); + + if (file1.exists() && !file1.delete() || !file.renameTo(file1)) { + LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString()); + } + + } catch (Exception e) { + LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString()); + } + } + +} diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java new file mode 100644 index 0000000..618e5ba --- /dev/null +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_17_R1; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IPlayerDataManager; +import com.lishid.openinv.internal.ISpecialInventory; +import com.lishid.openinv.internal.OpenInventoryView; +import com.mojang.authlib.GameProfile; +import java.lang.reflect.Field; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.minecraft.network.chat.ChatComponentText; +import net.minecraft.network.protocol.game.PacketPlayOutOpenWindow; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.server.level.WorldServer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.Containers; +import net.minecraft.world.level.World; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.craftbukkit.v1_17_R1.CraftServer; +import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_17_R1.event.CraftEventFactory; +import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftContainer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PlayerDataManager implements IPlayerDataManager { + + private @Nullable Field bukkitEntity; + + public PlayerDataManager() { + try { + bukkitEntity = Entity.class.getDeclaredField("bukkitEntity"); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded."); + logger.log(Level.WARNING, e.getMessage(), e); + bukkitEntity = null; + } + } + + public static @NotNull EntityPlayer getHandle(final Player player) { + if (player instanceof CraftPlayer) { + return ((CraftPlayer) player).getHandle(); + } + + Server server = player.getServer(); + EntityPlayer nmsPlayer = null; + + if (server instanceof CraftServer) { + nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getName()); + } + + if (nmsPlayer == null) { + // Could use reflection to examine fields, but it's honestly not worth the bother. + throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation"); + } + + return nmsPlayer; + } + + @Override + public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { + // Ensure player has data + if (!offline.hasPlayedBefore()) { + return null; + } + + // Create a profile and entity to load the player data + // See net.minecraft.server.PlayerList#attemptLogin + GameProfile profile = new GameProfile(offline.getUniqueId(), + offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + WorldServer worldServer = server.getWorldServer(World.f); + + if (worldServer == null) { + return null; + } + + EntityPlayer entity = new EntityPlayer(server, worldServer, profile); + + try { + injectPlayer(entity); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + // Get the bukkit entity + Player target = entity.getBukkitEntity(); + if (target != null) { + // Load data + target.loadData(); + } + // Return the entity + return target; + } + + void injectPlayer(EntityPlayer player) throws IllegalAccessException { + if (bukkitEntity == null) { + return; + } + + bukkitEntity.setAccessible(true); + + bukkitEntity.set(player, new OpenPlayer(player.c.server, player)); + } + + @NotNull + @Override + public Player inject(@NotNull Player player) { + try { + EntityPlayer nmsPlayer = getHandle(player); + injectPlayer(nmsPlayer); + return nmsPlayer.getBukkitEntity(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return player; + } + } + + @Nullable + @Override + public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) { + + EntityPlayer nmsPlayer = getHandle(player); + + if (nmsPlayer.b == null) { + return null; + } + + InventoryView view = getView(player, inventory); + + if (view == null) { + return player.openInventory(inventory.getBukkitInventory()); + } + + Container container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { + @Override + public Containers getType() { + return getContainers(inventory.getBukkitInventory().getSize()); + } + }; + + container.setTitle(new ChatComponentText(view.getTitle())); + container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); + + if (container == null) { + return null; + } + + nmsPlayer.b.sendPacket(new PacketPlayOutOpenWindow(nmsPlayer.bV.j, container.getType(), + new ChatComponentText(container.getBukkitView().getTitle()))); + nmsPlayer.bV = container; + nmsPlayer.initMenu(container); + + return container.getBukkitView(); + + } + + private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) { + if (inventory instanceof SpecialEnderChest) { + return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest"); + } else if (inventory instanceof SpecialPlayerInventory) { + return new OpenInventoryView(player, inventory, "container.player", "'s Inventory"); + } else { + return null; + } + } + + static @NotNull Containers getContainers(int inventorySize) { + + return switch (inventorySize) { + case 9 -> Containers.a; + case 18 -> Containers.b; + case 36 -> Containers.d; // PLAYER + case 41, 45 -> Containers.e; + case 54 -> Containers.f; + default -> Containers.c; // 9x3 + }; + } + + @Override + public int convertToPlayerSlot(InventoryView view, int rawSlot) { + int topSize = view.getTopInventory().getSize(); + if (topSize <= rawSlot) { + // Slot is not inside special inventory, use Bukkit logic. + return view.convertSlot(rawSlot); + } + + // Main inventory, slots 0-26 -> 9-35 + if (rawSlot < 27) { + return rawSlot + 9; + } + // Hotbar, slots 27-35 -> 0-8 + if (rawSlot < 36) { + return rawSlot - 27; + } + // Armor, slots 36-39 -> 39-36 + if (rawSlot < 40) { + return 36 + (39 - rawSlot); + } + // Off hand + if (rawSlot == 40) { + return 40; + } + // Drop slots, "out of inventory" + return -1; + } + +} diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java new file mode 100644 index 0000000..6a6a592 --- /dev/null +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_17_R1; + +import com.lishid.openinv.internal.ISpecialEnderChest; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.ContainerUtil; +import net.minecraft.world.IInventoryListener; +import net.minecraft.world.entity.player.AutoRecipeStackManager; +import net.minecraft.world.entity.player.EntityHuman; +import net.minecraft.world.inventory.InventoryEnderChest; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.TileEntityEnderChest; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_17_R1.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEnderChest { + + private final CraftInventory inventory; + private EntityPlayer owner; + private NonNullList c; + private boolean playerOnline; + + public SpecialEnderChest(final Player player, final Boolean online) { + super(PlayerDataManager.getHandle(player)); + this.inventory = new CraftInventory(this); + this.owner = PlayerDataManager.getHandle(player); + this.playerOnline = online; + this.c = this.owner.getEnderChest().c; + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return inventory; + } + + @Override + public boolean isInUse() { + return !this.getViewers().isEmpty(); + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public void setPlayerOnline(@NotNull final Player player) { + if (!this.playerOnline) { + try { + this.owner = PlayerDataManager.getHandle(player); + InventoryEnderChest enderChest = owner.getEnderChest(); + for (int i = 0; i < enderChest.getSize(); ++i) { + enderChest.setItem(i, this.c.get(i)); + } + this.c = enderChest.c; + enderChest.transaction.addAll(this.transaction); + } catch (Exception ignored) {} + this.playerOnline = true; + } + } + + @Override + public @NotNull Player getPlayer() { + return owner.getBukkitEntity(); + } + + @Override + public void update() { + this.owner.getEnderChest().update(); + } + + @Override + public List getContents() { + return this.c; + } + + @Override + public void onOpen(CraftHumanEntity who) { + super.onOpen(who); + this.owner.getEnderChest().onOpen(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + super.onClose(who); + this.owner.getEnderChest().onClose(who); + } + + @Override + public List getViewers() { + return this.owner.getEnderChest().getViewers(); + } + + @Override + public boolean a(EntityHuman entityhuman) { + return true; + } + + @Override + public void a(TileEntityEnderChest tileentityenderchest) { + this.owner.getEnderChest().a(tileentityenderchest); + } + + @Override + public boolean b(TileEntityEnderChest tileentityenderchest) { + return this.owner.getEnderChest().b(tileentityenderchest); + } + + @Override + public int getMaxStackSize() { + return this.owner.getEnderChest().getMaxStackSize(); + } + + @Override + public void setMaxStackSize(int i) { + this.owner.getEnderChest().setMaxStackSize(i); + } + + @Override + public InventoryHolder getOwner() { + return this.owner.getEnderChest().getOwner(); + } + + @Override + public @Nullable Location getLocation() { + return null; + } + + @Override + public void a(IInventoryListener iinventorylistener) { + this.owner.getEnderChest().a(iinventorylistener); + } + + @Override + public void b(IInventoryListener iinventorylistener) { + this.owner.getEnderChest().b(iinventorylistener); + } + + @Override + public ItemStack getItem(int i) { + return i >= 0 && i < this.c.size() ? this.c.get(i) : ItemStack.b; + } + + @Override + public ItemStack splitStack(int i, int j) { + ItemStack itemstack = ContainerUtil.a(this.c, i, j); + if (!itemstack.isEmpty()) { + this.update(); + } + + return itemstack; + } + + @Override + public ItemStack a(ItemStack itemstack) { + ItemStack itemstack1 = itemstack.cloneItemStack(); + this.d(itemstack1); + if (itemstack1.isEmpty()) { + return ItemStack.b; + } else { + this.c(itemstack1); + return itemstack1.isEmpty() ? ItemStack.b : itemstack1; + } + } + + private void c(ItemStack itemstack) { + for(int i = 0; i < this.getSize(); ++i) { + ItemStack itemstack1 = this.getItem(i); + if (itemstack1.isEmpty()) { + this.setItem(i, itemstack.cloneItemStack()); + itemstack.setCount(0); + return; + } + } + } + + private void d(ItemStack itemstack) { + for(int i = 0; i < this.getSize(); ++i) { + ItemStack itemstack1 = this.getItem(i); + if (ItemStack.e(itemstack1, itemstack)) { + this.a(itemstack, itemstack1); + if (itemstack.isEmpty()) { + return; + } + } + } + } + + private void a(ItemStack itemstack, ItemStack itemstack1) { + int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize()); + int j = Math.min(itemstack.getCount(), i - itemstack1.getCount()); + if (j > 0) { + itemstack1.add(j); + itemstack.subtract(j); + this.update(); + } + } + + @Override + public ItemStack splitWithoutUpdate(int i) { + ItemStack itemstack = this.c.get(i); + if (itemstack.isEmpty()) { + return ItemStack.b; + } else { + this.c.set(i, ItemStack.b); + return itemstack; + } + } + + @Override + public void setItem(int i, ItemStack itemstack) { + this.c.set(i, itemstack); + if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { + itemstack.setCount(this.getMaxStackSize()); + } + + this.update(); + } + + @Override + public int getSize() { + return this.owner.getEnderChest().getSize(); + } + + @Override + public boolean isEmpty() { + return this.c.stream().allMatch(ItemStack::isEmpty); + } + + @Override + public void startOpen(EntityHuman entityhuman) { + } + + @Override + public void closeContainer(EntityHuman entityhuman) { + } + + @Override + public boolean b(int i, ItemStack itemstack) { + return true; + } + + @Override + public void clear() { + this.c.clear(); + this.update(); + } + + @Override + public void a(AutoRecipeStackManager autorecipestackmanager) { + for (ItemStack itemstack : this.c) { + autorecipestackmanager.b(itemstack); + } + + } + + @Override + public List f() { + List list = this.c.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList()); + this.clear(); + return list; + } + + @Override + public ItemStack a(Item item, int i) { + ItemStack itemstack = new ItemStack(item, 0); + + for(int j = this.getSize() - 1; j >= 0; --j) { + ItemStack itemstack1 = this.getItem(j); + if (itemstack1.getItem().equals(item)) { + int k = i - itemstack.getCount(); + ItemStack itemstack2 = itemstack1.cloneAndSubtract(k); + itemstack.add(itemstack2.getCount()); + if (itemstack.getCount() == i) { + break; + } + } + } + + if (!itemstack.isEmpty()) { + this.update(); + } + + return itemstack; + } + + @Override + public boolean b(ItemStack itemStack) { + for (ItemStack itemStack1 : this.c) { + if (itemStack1.isEmpty() || ItemStack.e(itemStack1, itemStack) && itemStack1.getCount() < itemStack1.getMaxStackSize()) { + return true; + } + } + + return false; + } + + @Override + public String toString() { + return this.c.stream().filter((itemStack) -> !itemStack.isEmpty()).collect(Collectors.toList()).toString(); + } + + @Override + public void a(NBTTagList nbttaglist) { + for(int i = 0; i < nbttaglist.size(); ++i) { + ItemStack itemstack = ItemStack.a(nbttaglist.getCompound(i)); + if (!itemstack.isEmpty()) { + this.a(itemstack); + } + } + + } + +} diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java new file mode 100644 index 0000000..0cf6972 --- /dev/null +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java @@ -0,0 +1,777 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_17_R1; + +import com.google.common.collect.ImmutableList; +import com.lishid.openinv.internal.ISpecialPlayerInventory; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.CrashReport; +import net.minecraft.CrashReportSystemDetails; +import net.minecraft.ReportedException; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.network.chat.ChatMessage; +import net.minecraft.network.chat.IChatBaseComponent; +import net.minecraft.network.protocol.game.PacketPlayOutSetSlot; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.tags.Tag; +import net.minecraft.world.ContainerUtil; +import net.minecraft.world.IInventory; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EnumItemSlot; +import net.minecraft.world.entity.player.AutoRecipeStackManager; +import net.minecraft.world.entity.player.EntityHuman; +import net.minecraft.world.entity.player.PlayerInventory; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemArmor; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.IBlockData; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_17_R1.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; + +public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory { + + private final CraftInventory inventory; + private boolean playerOnline; + private EntityHuman l; + private NonNullList h; + private NonNullList i; + private NonNullList j; + private List> n; + + public SpecialPlayerInventory(final Player bukkitPlayer, final Boolean online) { + super(PlayerDataManager.getHandle(bukkitPlayer)); + this.inventory = new CraftInventory(this); + this.playerOnline = online; + this.l = super.l; + this.h = this.l.getInventory().h; + this.i = this.l.getInventory().i; + this.j = this.l.getInventory().j; + this.n = ImmutableList.of(this.h, this.i, this.j); + } + + @Override + public void setPlayerOnline(@NotNull final Player player) { + if (!this.playerOnline) { + EntityPlayer entityPlayer = PlayerDataManager.getHandle(player); + entityPlayer.getInventory().transaction.addAll(this.transaction); + this.l = entityPlayer; + for (int i = 0; i < getSize(); ++i) { + this.l.getInventory().setItem(i, getRawItem(i)); + } + this.l.getInventory().k = this.k; + this.h = this.l.getInventory().h; + this.i = this.l.getInventory().i; + this.j = this.l.getInventory().j; + this.n = ImmutableList.of(this.h, this.i, this.j); + this.playerOnline = true; + } + } + + @Override + public boolean a(final EntityHuman entityhuman) { + return true; + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return this.inventory; + } + + @Override + public ItemStack getItem(int i) { + List list = this.h; + + if (i >= list.size()) { + i -= list.size(); + list = this.i; + } else { + i = this.getReversedItemSlotNum(i); + } + + if (i >= list.size()) { + i -= list.size(); + list = this.j; + } else if (list == this.i) { + i = this.getReversedArmorSlotNum(i); + } + + if (i >= list.size()) { + return ItemStack.b; + } + + return list.get(i); + } + + private ItemStack getRawItem(int i) { + NonNullList list = null; + for (NonNullList next : this.n) { + if (i < next.size()) { + list = next; + break; + } + i -= next.size(); + } + + return list == null ? ItemStack.b : list.get(i); + } + + @Override + public IChatBaseComponent getDisplayName() { + return new ChatMessage(this.l.getName()); + } + + @Override + public boolean hasCustomName() { + return false; + } + + private int getReversedArmorSlotNum(final int i) { + if (i == 0) { + return 3; + } + if (i == 1) { + return 2; + } + if (i == 2) { + return 1; + } + if (i == 3) { + return 0; + } + return i; + } + + private int getReversedItemSlotNum(final int i) { + if (i >= 27) { + return i - 27; + } + return i + 9; + } + + @Override + public int getSize() { + return 45; + } + + @Override + public boolean isInUse() { + return !this.getViewers().isEmpty(); + } + + @Override + public void setItem(int i, final ItemStack itemstack) { + List list = this.h; + + if (i >= list.size()) { + i -= list.size(); + list = this.i; + } else { + i = this.getReversedItemSlotNum(i); + } + + if (i >= list.size()) { + i -= list.size(); + list = this.j; + } else if (list == this.i) { + i = this.getReversedArmorSlotNum(i); + } + + if (i >= list.size()) { + this.l.drop(itemstack, true); + return; + } + + list.set(i, itemstack); + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public @NotNull HumanEntity getPlayer() { + return this.l.getBukkitEntity(); + } + + @Override + public ItemStack splitStack(int i, final int j) { + List list = this.h; + + if (i >= list.size()) { + i -= list.size(); + list = this.i; + } else { + i = this.getReversedItemSlotNum(i); + } + + if (i >= list.size()) { + i -= list.size(); + list = this.j; + } else if (list == this.i) { + i = this.getReversedArmorSlotNum(i); + } + + if (i >= list.size()) { + return ItemStack.b; + } + + return list.get(i).isEmpty() ? ItemStack.b : ContainerUtil.a(list, i, j); + } + + @Override + public ItemStack splitWithoutUpdate(int i) { + List list = this.h; + + if (i >= list.size()) { + i -= list.size(); + list = this.i; + } else { + i = this.getReversedItemSlotNum(i); + } + + if (i >= list.size()) { + i -= list.size(); + list = this.j; + } else if (list == this.i) { + i = this.getReversedArmorSlotNum(i); + } + + if (i >= list.size()) { + return ItemStack.b; + } + + if (!list.get(i).isEmpty()) { + ItemStack itemstack = list.get(i); + + list.set(i, ItemStack.b); + return itemstack; + } + + return ItemStack.b; + } + + @Override + public List getContents() { + return this.n.stream().flatMap(Collection::stream).collect(Collectors.toList()); + } + + @Override + public boolean isEmpty() { + return this.n.stream().flatMap(Collection::stream).allMatch(ItemStack::isEmpty); + } + + @Override + public List getArmorContents() { + return this.i; + } + + @Override + public void onOpen(CraftHumanEntity who) { + this.transaction.add(who); + this.l.getInventory().transaction.add(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + this.transaction.remove(who); + this.l.getInventory().transaction.remove(who); + } + + @Override + public List getViewers() { + return this.transaction; + } + + @Override + public InventoryHolder getOwner() { + return this.l.getBukkitEntity(); + } + + public Location getLocation() { + return this.l.getBukkitEntity().getLocation(); + } + + /* Below this point largely just copied out of NMS to redirect to our overridden variables. */ + + @Override + public ItemStack getItemInHand() { + return d(this.k) ? this.h.get(this.k) : ItemStack.b; + } + + private boolean isSimilarAndNotFull(ItemStack itemstack, ItemStack itemstack1) { + return !itemstack.isEmpty() && ItemStack.e(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); + } + + @Override + public int canHold(ItemStack itemstack) { + int remains = itemstack.getCount(); + + for(int i = 0; i < this.h.size(); ++i) { + ItemStack itemstack1 = this.getItem(i); + if (itemstack1.isEmpty()) { + return itemstack.getCount(); + } + + if (this.isSimilarAndNotFull(itemstack1, itemstack)) { + remains -= (Math.min(itemstack1.getMaxStackSize(), this.getMaxStackSize())) - itemstack1.getCount(); + } + + if (remains <= 0) { + return itemstack.getCount(); + } + } + + ItemStack offhandItemStack = this.getItem(this.h.size() + this.i.size()); + if (this.isSimilarAndNotFull(offhandItemStack, itemstack)) { + remains -= (Math.min(offhandItemStack.getMaxStackSize(), this.getMaxStackSize())) - offhandItemStack.getCount(); + } + + return remains <= 0 ? itemstack.getCount() : itemstack.getCount() - remains; + } + + @Override + public int getFirstEmptySlotIndex() { + for(int i = 0; i < this.h.size(); ++i) { + if (this.h.get(i).isEmpty()) { + return i; + } + } + + return -1; + } + + @Override + public void a(ItemStack itemstack) { + int i = this.b(itemstack); + if (d(i)) { + this.k = i; + } else if (i == -1) { + this.k = this.i(); + if (!this.h.get(this.k).isEmpty()) { + int j = this.getFirstEmptySlotIndex(); + if (j != -1) { + this.h.set(j, this.h.get(this.k)); + } + } + + this.h.set(this.k, itemstack); + } else { + this.c(i); + } + + } + + @Override + public void c(int i) { + this.k = this.i(); + ItemStack itemstack = this.h.get(this.k); + this.h.set(this.k, this.h.get(i)); + this.h.set(i, itemstack); + } + + @Override + public int b(ItemStack itemstack) { + for (int i = 0; i < this.h.size(); ++i) { + if (!this.h.get(i).isEmpty() && ItemStack.e(itemstack, this.h.get(i))) { + return i; + } + } + + return -1; + } + + @Override + public int c(ItemStack itemstack) { + for (int i = 0; i < this.h.size(); ++i) { + ItemStack itemstack1 = this.h.get(i); + if (!this.h.get(i).isEmpty() && ItemStack.e(itemstack, this.h.get(i)) && !this.h.get(i).g() && !itemstack1.hasEnchantments() && !itemstack1.hasName()) { + return i; + } + } + + return -1; + } + + @Override + public int i() { + int i; + int j; + for (j = 0; j < 9; ++j) { + i = (this.k + j) % 9; + if (this.h.get(i).isEmpty()) { + return i; + } + } + + for (j = 0; j < 9; ++j) { + i = (this.k + j) % 9; + if (!this.h.get(i).hasEnchantments()) { + return i; + } + } + + return this.k; + } + + @Override + public void a(double d0) { + if (d0 > 0.0D) { + d0 = 1.0D; + } + + if (d0 < 0.0D) { + d0 = -1.0D; + } + + this.k = (int) (this.k - d0); + + while (this.k < 0) { + this.k += 9; + } + + while (this.k >= 9) { + this.k -= 9; + } + + } + + @Override + public int a(Predicate predicate, int i, IInventory iinventory) { + byte b0 = 0; + boolean flag = i == 0; + int j = b0 + ContainerUtil.a(this, predicate, i - b0, flag); + j += ContainerUtil.a(iinventory, predicate, i - j, flag); + ItemStack itemstack = this.l.bV.getCarried(); + j += ContainerUtil.a(itemstack, predicate, i - j, flag); + if (itemstack.isEmpty()) { + this.l.bV.setCarried(ItemStack.b); + } + + return j; + } + + private int i(ItemStack itemstack) { + int i = this.firstPartial(itemstack); + if (i == -1) { + i = this.getFirstEmptySlotIndex(); + } + + return i == -1 ? itemstack.getCount() : this.d(i, itemstack); + } + + private int d(int i, ItemStack itemstack) { + Item item = itemstack.getItem(); + int j = itemstack.getCount(); + ItemStack itemstack1 = this.getItem(i); + if (itemstack1.isEmpty()) { + itemstack1 = new ItemStack(item, 0); + if (itemstack.hasTag()) { + itemstack1.setTag(Objects.requireNonNull(itemstack.getTag()).clone()); + } + + this.setItem(i, itemstack1); + } + + k = Math.min(j, itemstack1.getMaxStackSize() - itemstack1.getCount()); + + if (k > this.getMaxStackSize() - itemstack1.getCount()) { + k = this.getMaxStackSize() - itemstack1.getCount(); + } + + if (k != 0) { + j -= k; + itemstack1.add(k); + itemstack1.d(5); + } + + return j; + } + + @Override + public int firstPartial(ItemStack itemstack) { + if (this.isSimilarAndNotFull(this.getItem(this.k), itemstack)) { + return this.k; + } else if (this.isSimilarAndNotFull(this.getItem(40), itemstack)) { + return 40; + } else { + for(int i = 0; i < this.h.size(); ++i) { + if (this.isSimilarAndNotFull(this.h.get(i), itemstack)) { + return i; + } + } + + return -1; + } + } + + @Override + public void j() { + for (NonNullList nonNullList : this.n) { + for (int i = 0; i < nonNullList.size(); ++i) { + if (!nonNullList.get(i).isEmpty()) { + nonNullList.get(i).a(this.l.t, this.l, i, this.k == i); + } + } + } + + } + + @Override + public boolean pickup(ItemStack itemStack) { + return this.c(-1, itemStack); + } + + @Override + public boolean c(int i, ItemStack itemStack) { + if (itemStack.isEmpty()) { + return false; + } else { + try { + if (itemStack.g()) { + if (i == -1) { + i = this.getFirstEmptySlotIndex(); + } + + if (i >= 0) { + this.h.set(i, itemStack.cloneItemStack()); + this.h.get(i).d(5); + itemStack.setCount(0); + return true; + } else if (this.l.getAbilities().d) { + itemStack.setCount(0); + return true; + } else { + return false; + } + } else { + int j; + do { + j = itemStack.getCount(); + if (i == -1) { + itemStack.setCount(this.i(itemStack)); + } else { + itemStack.setCount(this.d(i, itemStack)); + } + } while(!itemStack.isEmpty() && itemStack.getCount() < j); + + if (itemStack.getCount() == j && this.l.getAbilities().d) { + itemStack.setCount(0); + return true; + } else { + return itemStack.getCount() < j; + } + } + } catch (Throwable var6) { + CrashReport crashreport = CrashReport.a(var6, "Adding item to inventory"); + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Item being added"); + crashreportsystemdetails.a("Item ID", Item.getId(itemStack.getItem())); + crashreportsystemdetails.a("Item data", itemStack.getDamage()); + crashreportsystemdetails.a("Item name", () -> itemStack.getName().getString()); + throw new ReportedException(crashreport); + } + } + } + + @Override + public void f(ItemStack itemStack) { + this.a(itemStack, true); + } + + @Override + public void a(ItemStack itemStack, boolean flag) { + while(true) { + if (!itemStack.isEmpty()) { + int i = this.firstPartial(itemStack); + if (i == -1) { + i = this.getFirstEmptySlotIndex(); + } + + if (i != -1) { + int j = itemStack.getMaxStackSize() - this.getItem(i).getCount(); + if (this.c(i, itemStack.cloneAndSubtract(j)) && flag && this.l instanceof EntityPlayer) { + ((EntityPlayer)this.l).b.sendPacket(new PacketPlayOutSetSlot(-2, i, this.getItem(i))); + } + continue; + } + + this.l.drop(itemStack, false); + } + + return; + } + } + + @Override + public void g(ItemStack itemStack) { + for (NonNullList nonNullList : this.n) { + for (int i = 0; i < nonNullList.size(); ++i) { + if (nonNullList.get(i) == itemStack) { + nonNullList.set(i, ItemStack.b); + break; + } + } + } + } + + @Override + public float a(IBlockData iBlockData) { + return this.h.get(this.k).a(iBlockData); + } + + @Override + public NBTTagList a(NBTTagList nbtTagList) { + NBTTagCompound nbttagcompound; + int i; + for(i = 0; i < this.h.size(); ++i) { + if (!this.h.get(i).isEmpty()) { + nbttagcompound = new NBTTagCompound(); + nbttagcompound.setByte("Slot", (byte)i); + this.h.get(i).save(nbttagcompound); + nbtTagList.add(nbttagcompound); + } + } + + for(i = 0; i < this.i.size(); ++i) { + if (!this.i.get(i).isEmpty()) { + nbttagcompound = new NBTTagCompound(); + nbttagcompound.setByte("Slot", (byte)(i + 100)); + this.i.get(i).save(nbttagcompound); + nbtTagList.add(nbttagcompound); + } + } + + for(i = 0; i < this.j.size(); ++i) { + if (!this.j.get(i).isEmpty()) { + nbttagcompound = new NBTTagCompound(); + nbttagcompound.setByte("Slot", (byte)(i + 150)); + this.j.get(i).save(nbttagcompound); + nbtTagList.add(nbttagcompound); + } + } + + return nbtTagList; + } + + @Override + public void b(NBTTagList nbtTagList) { + this.h.clear(); + this.i.clear(); + this.j.clear(); + + for(int i = 0; i < nbtTagList.size(); ++i) { + NBTTagCompound nbttagcompound = nbtTagList.getCompound(i); + int j = nbttagcompound.getByte("Slot") & 255; + ItemStack itemstack = ItemStack.a(nbttagcompound); + if (!itemstack.isEmpty()) { + if (j < this.h.size()) { + this.h.set(j, itemstack); + } else if (j >= 100 && j < this.i.size() + 100) { + this.i.set(j - 100, itemstack); + } else if (j >= 150 && j < this.j.size() + 150) { + this.j.set(j - 150, itemstack); + } + } + } + + } + + @Override + public ItemStack e(int i) { + return this.i.get(i); + } + + @Override + public void a(DamageSource damageSource, float f, int[] intArray) { + if (f > 0.0F) { + f /= 4.0F; + if (f < 1.0F) { + f = 1.0F; + } + + for (int index : intArray) { + ItemStack itemstack = this.i.get(index); + if ((!damageSource.isFire() || !itemstack.getItem().w()) && itemstack.getItem() instanceof ItemArmor) { + itemstack.damage((int) f, this.l, (entityHuman) -> entityHuman.broadcastItemBreak(EnumItemSlot.a(EnumItemSlot.Function.b, index))); + } + } + } + + } + + @Override + public void dropContents() { + for (List list : this.n) { + for (int i = 0; i < list.size(); ++i) { + ItemStack itemstack = list.get(i); + if (!itemstack.isEmpty()) { + list.set(i, ItemStack.b); + this.l.a(itemstack, true, false); + } + } + } + } + + @Override + public boolean h(ItemStack itemStack) { + return this.n.stream() + .flatMap(Collection::stream) + .anyMatch(itemStack1 -> !itemStack1.isEmpty() && itemStack1.doMaterialsMatch(itemStack)); + } + + @Override + public boolean a(Tag tag) { + return this.n.stream() + .flatMap(Collection::stream) + .anyMatch(itemStack -> !itemStack.isEmpty() && itemStack.a(tag)); + } + + @Override + public void a(PlayerInventory playerInventory) { + for(int i = 0; i < this.getSize(); ++i) { + this.setItem(i, playerInventory.getItem(i)); + } + + this.k = playerInventory.k; + } + + @Override + public void clear() { + for (List list : this.n) { + list.clear(); + } + } + + @Override + public void a(AutoRecipeStackManager autoRecipeStackManager) { + for (ItemStack itemstack : this.h) { + autoRecipeStackManager.a(itemstack); + } + } + +} diff --git a/pom.xml b/pom.xml index 8014443..fa34fdc 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,7 @@ api plugin internal/v1_16_R3 + internal/v1_17_R1 assembly -- 2.49.1 From ff7243db6a69e9b8fc2097907b813bc76a745517 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 11 Jun 2021 12:05:38 -0400 Subject: [PATCH 026/139] Fix script issues Temporarily explicitly declare Spigot dependencies I don't have the time to deal with whatever the difference between remote and local bash/maven versions is right now. --- scripts/generate_changelog.sh | 2 +- scripts/get_spigot_versions.sh | 23 ++++++++--------------- scripts/install_spigot_dependencies.sh | 4 ++-- scripts/set_curseforge_env.sh | 2 +- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/scripts/generate_changelog.sh b/scripts/generate_changelog.sh index 81cddfb..d2261f1 100644 --- a/scripts/generate_changelog.sh +++ b/scripts/generate_changelog.sh @@ -32,7 +32,7 @@ function lookup_email_username() { # Get a pretty list of supported Minecraft versions function get_minecraft_versions() { - versions=$(. ./scripts/get_spigot_versions.sh) + readarray -t versions <<< "$(. ./scripts/get_spigot_versions.sh)" for version in "${versions[@]}"; do # Append comma if variable is set, then append version diff --git a/scripts/get_spigot_versions.sh b/scripts/get_spigot_versions.sh index 64c2fea..e524912 100644 --- a/scripts/get_spigot_versions.sh +++ b/scripts/get_spigot_versions.sh @@ -15,28 +15,21 @@ # along with this program. If not, see . # +# TODO FIGURE OUT AND REMOVE WHEN LESS STRESS +hacky_versions=("1.16.5-R0.1-SNAPSHOT" "1.17-R0.1-SNAPSHOT") +for hacky_version in "${hacky_versions[@]}"; do + echo "$hacky_version" +done + +exit 0 + # Note that this script is designed for use in GitHub Actions, and is not # particularly robust nor configurable. Run from project parent directory. -# Use a nameref as a cache - maven evaluation is pretty slow. -# Re-calling the script and relying on it to handle caching is way easier than passing around info. -declare -a spigot_versions - -# We don't care about concatenation - either it's not null and we return or it's null and we instantiate. -# shellcheck disable=SC2199 -if [[ ${spigot_versions[@]} ]]; then - for spigot_version in "${spigot_versions[@]}"; do - echo "$spigot_version" - done - return -fi - # Pull Spigot dependency information from Maven. # Since we only care about Spigot versions, only check modules in the folder internal. readarray -t modules <<< "$(mvn help:evaluate -Dexpression=project.modules -q -DforceStdout -P all | grep -oP '(?<=)(internal/.*)(?=)')" -declare -n versions="spigot_versions" - for module in "${modules[@]}"; do # Get number of dependencies declared in pom of specified internal module. max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl "$module" | grep -c "") diff --git a/scripts/install_spigot_dependencies.sh b/scripts/install_spigot_dependencies.sh index 84fce3f..0beac8f 100644 --- a/scripts/install_spigot_dependencies.sh +++ b/scripts/install_spigot_dependencies.sh @@ -30,8 +30,8 @@ get_buildtools () { wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O $buildtools } -versions=$(. ./scripts/get_spigot_versions.sh) -echo Found Spigot dependencies: "$versions" +readarray -t versions <<< "$(. ./scripts/get_spigot_versions.sh)" +echo Found Spigot dependencies: "${versions[@]}" for version in "${versions[@]}"; do set -e diff --git a/scripts/set_curseforge_env.sh b/scripts/set_curseforge_env.sh index f21dd40..09f08b4 100644 --- a/scripts/set_curseforge_env.sh +++ b/scripts/set_curseforge_env.sh @@ -20,7 +20,7 @@ # Parse Spigot dependency information into major Minecraft versions function get_curseforge_minecraft_versions() { - versions=$(. ./scripts/get_spigot_versions.sh) + readarray -t versions <<< "$(. ./scripts/get_spigot_versions.sh)" for version in "${versions[@]}"; do # Parse Minecraft major version -- 2.49.1 From 1cae4c7a8e4337e2115d160a5a4b1f5a81c830d4 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 11 Jun 2021 18:39:07 -0400 Subject: [PATCH 027/139] Correct window id --- .../com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java index 618e5ba..4071eec 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java @@ -169,7 +169,7 @@ public class PlayerDataManager implements IPlayerDataManager { return null; } - nmsPlayer.b.sendPacket(new PacketPlayOutOpenWindow(nmsPlayer.bV.j, container.getType(), + nmsPlayer.b.sendPacket(new PacketPlayOutOpenWindow(container.j, container.getType(), new ChatComponentText(container.getBukkitView().getTitle()))); nmsPlayer.bV = container; nmsPlayer.initMenu(container); -- 2.49.1 From f613c0a522601f6bf2c0b097da5412f210b49981 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 11 Jun 2021 18:39:19 -0400 Subject: [PATCH 028/139] Remove redundant load --- .../java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java index 15ca1b7..cf420ea 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java @@ -34,7 +34,6 @@ public class OpenPlayer extends CraftPlayer { @Override public void loadData() { - super.loadData(); // See CraftPlayer#loadData NBTTagCompound loaded = this.server.getHandle().r.load(this.getHandle()); if (loaded != null) { -- 2.49.1 From 64af4dddb096086a2e86979d6e80c50f3c2def48 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 11 Jun 2021 18:40:39 -0400 Subject: [PATCH 029/139] Bump version to 4.1.8 for release --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_16_R3/pom.xml | 2 +- internal/v1_17_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 7adc2da..98df50d 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.8-SNAPSHOT + 4.1.8 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 76aa28a..ab03109 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.8-SNAPSHOT + 4.1.8 openinvassembly diff --git a/internal/v1_16_R3/pom.xml b/internal/v1_16_R3/pom.xml index 13f5dc5..572b269 100644 --- a/internal/v1_16_R3/pom.xml +++ b/internal/v1_16_R3/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.8-SNAPSHOT + 4.1.8 openinvadapter1_16_R3 diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index e69e24a..5de997b 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.8-SNAPSHOT + 4.1.8 openinvadapter1_17_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index fa7537d..b4c2c24 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.8-SNAPSHOT + 4.1.8 openinvplugincore diff --git a/pom.xml b/pom.xml index fa34fdc..4f00289 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.8-SNAPSHOT + 4.1.8 pom @@ -81,13 +81,13 @@ openinvapi com.lishid compile - 4.1.8-SNAPSHOT + 4.1.8 openinvplugincore com.lishid compile - 4.1.8-SNAPSHOT + 4.1.8 -- 2.49.1 From b198931f3063940403d979bdce0471642ee8f7fb Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 11 Jun 2021 18:40:48 -0400 Subject: [PATCH 030/139] Bump version to 4.1.9-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_16_R3/pom.xml | 2 +- internal/v1_17_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 98df50d..b8f6259 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.8 + 4.1.9-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index ab03109..53bd6f5 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.8 + 4.1.9-SNAPSHOT openinvassembly diff --git a/internal/v1_16_R3/pom.xml b/internal/v1_16_R3/pom.xml index 572b269..90b9458 100644 --- a/internal/v1_16_R3/pom.xml +++ b/internal/v1_16_R3/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.8 + 4.1.9-SNAPSHOT openinvadapter1_16_R3 diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index 5de997b..2cd9043 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.8 + 4.1.9-SNAPSHOT openinvadapter1_17_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index b4c2c24..9a8a538 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.8 + 4.1.9-SNAPSHOT openinvplugincore diff --git a/pom.xml b/pom.xml index 4f00289..c26be77 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.8 + 4.1.9-SNAPSHOT pom @@ -81,13 +81,13 @@ openinvapi com.lishid compile - 4.1.8 + 4.1.9-SNAPSHOT
openinvplugincore com.lishid compile - 4.1.8 + 4.1.9-SNAPSHOT -- 2.49.1 From 4336b454b7a2edca0901fb570eb0e5bd5dade006 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Thu, 24 Jun 2021 08:21:26 -0400 Subject: [PATCH 031/139] Fix potential CME closing viewers without access Closes #33 --- .../internal/v1_17_R1/AnySilentContainer.java | 4 -- .../main/java/com/lishid/openinv/OpenInv.java | 40 +++++++++---------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java index 3f7085e..4e8091d 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java @@ -336,10 +336,6 @@ public class AnySilentContainer implements IAnySilentContainer { try { this.playerInteractManagerGamemode.setAccessible(true); this.playerInteractManagerGamemode.set(player.d, gameMode); - // TODO: may need additional calls to update abilities to prevent container sound + animation - // gameMode.a(player.getAbilities()); - // player.updateAbilities(); - // should be the fix if it doesn't work as-is } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index 3d34472..680683d 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -35,10 +35,12 @@ import com.lishid.openinv.util.ConfigUpdater; import com.lishid.openinv.util.InternalAccessor; import com.lishid.openinv.util.LanguageManager; import com.lishid.openinv.util.Permissions; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.function.Consumer; @@ -88,7 +90,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { // Check if inventory is stored, and if it is, remove it and eject all viewers if (OpenInv.this.inventories.containsKey(key)) { Inventory inv = OpenInv.this.inventories.remove(key).getBukkitInventory(); - List viewers = inv.getViewers(); + List viewers = new ArrayList<>(inv.getViewers()); for (HumanEntity entity : viewers.toArray(new HumanEntity[0])) { entity.closeInventory(); } @@ -97,7 +99,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { // Check if ender chest is stored, and if it is, remove it and eject all viewers if (OpenInv.this.enderChests.containsKey(key)) { Inventory inv = OpenInv.this.enderChests.remove(key).getBukkitInventory(); - List viewers = inv.getViewers(); + List viewers = new ArrayList<>(inv.getViewers()); for (HumanEntity entity : viewers.toArray(new HumanEntity[0])) { entity.closeInventory(); } @@ -126,29 +128,23 @@ public class OpenInv extends JavaPlugin implements IOpenInv { } if (this.inventories.containsKey(key)) { - Iterator iterator = this.inventories.get(key).getBukkitInventory().getViewers().iterator(); - //noinspection WhileLoopReplaceableByForEach - while (iterator.hasNext()) { - HumanEntity human = iterator.next(); - // If player has permission or is in the same world, allow continued access - // Just in case, also allow null worlds. - if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld().equals(player.getWorld())) { - continue; - } - human.closeInventory(); - } + kickCrossWorldViewers(player, this.inventories.get(key)); } if (this.enderChests.containsKey(key)) { - Iterator iterator = this.enderChests.get(key).getBukkitInventory().getViewers().iterator(); - //noinspection WhileLoopReplaceableByForEach - while (iterator.hasNext()) { - HumanEntity human = iterator.next(); - if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld().equals(player.getWorld())) { - continue; - } - human.closeInventory(); + kickCrossWorldViewers(player, this.enderChests.get(key)); + } + } + + private void kickCrossWorldViewers(Player player, ISpecialInventory inventory) { + List viewers = new ArrayList<>(inventory.getBukkitInventory().getViewers()); + for (HumanEntity human : viewers) { + // If player has permission or is in the same world, allow continued access + // Just in case, also allow null worlds. + if (Permissions.CROSSWORLD.hasPermission(human) || Objects.equals(human.getWorld(), player.getWorld())) { + continue; } + human.closeInventory(); } } @@ -326,7 +322,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { return this.languageManager.getValue(key, getLocale(sender), replacements); } - private @Nullable String getLocale(@NotNull CommandSender sender) { + private @NotNull String getLocale(@NotNull CommandSender sender) { if (sender instanceof Player) { return ((Player) sender).getLocale(); } else { -- 2.49.1 From e5ebf11d3298329f380639f42bcb0289f2e96a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=98=AD=E8=98=AD=E9=9C=B2=20Flandre=5Ftw?= <51469621+gregman98@users.noreply.github.com> Date: Tue, 29 Jun 2021 08:05:15 +0800 Subject: [PATCH 032/139] Add Chinese Traditional translation (#34) --- plugin/src/main/resources/zh_tw.yml | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 plugin/src/main/resources/zh_tw.yml diff --git a/plugin/src/main/resources/zh_tw.yml b/plugin/src/main/resources/zh_tw.yml new file mode 100644 index 0000000..c5e7399 --- /dev/null +++ b/plugin/src/main/resources/zh_tw.yml @@ -0,0 +1,31 @@ +# Translated into Chinese Traditional by Flandre_tw +messages: + error: + consoleUnsupported: 該指令無法在控制台執行。 + lootNotGenerated: '&c獎勵箱尚未生成 ! 請關閉 &b/silentcontainer&c。' + invalidMaterial: '&c無效的物品 : "%target%"' + invalidNumber: '&c無效的數字 : "%target%"' + invalidPlayer: '&c玩家不存在 !' + permissionOpenSelf: '&c你無法開啟自己的物品欄。' + permissionEnderAll: '&c你無法開啟其他玩家的終界箱。' + permissionExempt: '&c%target% 的物品欄受到保護。' + permissionCrossWorld: '&c%target% 不在你所在的世界。' + permissionPlayerOnline: '&c你無法開啟線上玩家的物品欄。' + permissionPlayerOffline: '&c你無法開啟離線玩家的物品欄。' + commandException: '&c發生錯誤,請查看控制台。' + info: + containerBlocked: 你正在開啟受阻擋的儲物箱。 + containerBlockedSilent: 你正在悄悄開啟受阻擋的儲物箱。 + containerSilent: 你正在悄悄開啟儲物箱。 + settingState: '%setting% : %state%' + player: + noMatches: 找不到持有 %target% 的玩家。 + matches: '找到持有 %target% 的玩家 : %detail%' + container: + noMatches: 找不到放有 %target% 的儲物箱。 + matches: '找到放有 %target% 的儲物箱 : %detail%' + 'true': '開啟' + 'false': '關閉' +container: + player: '%player% 的物品欄' + enderchest: '%player% 的終界箱' -- 2.49.1 From 2f36a4d4dca7966e1cc704d91647a2c91bace132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=98=AD=E8=98=AD=E9=9C=B2=20Flandre=5Ftw?= <51469621+gregman98@users.noreply.github.com> Date: Tue, 29 Jun 2021 08:05:55 +0800 Subject: [PATCH 033/139] Add Chinese Simplified translation (#35) --- plugin/src/main/resources/zh_cn.yml | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 plugin/src/main/resources/zh_cn.yml diff --git a/plugin/src/main/resources/zh_cn.yml b/plugin/src/main/resources/zh_cn.yml new file mode 100644 index 0000000..bec0185 --- /dev/null +++ b/plugin/src/main/resources/zh_cn.yml @@ -0,0 +1,31 @@ +# Translated into Chinese Simplified by Flandre_tw +messages: + error: + consoleUnsupported: 该命令无法在后台执行。 + lootNotGenerated: '&c奖励箱尚未生成 ! 请关闭 &b/silentcontainer&c。' + invalidMaterial: '&c无效的物品 : "%target%"' + invalidNumber: '&c无效的数字 : "%target%"' + invalidPlayer: '&c玩家不存在 !' + permissionOpenSelf: '&c你无法开启自己的物品栏。' + permissionEnderAll: '&c你无法开启其他玩家的末影箱。' + permissionExempt: '&c%target% 的物品栏受到保护。' + permissionCrossWorld: '&c%target% 不在你所在的世界。' + permissionPlayerOnline: '&c你无法开启线上玩家的物品栏。' + permissionPlayerOffline: '&c你无法开启离线玩家的物品栏。' + commandException: '&c发生错误,请查看后台。' + info: + containerBlocked: 你正在开启受阻挡的储物箱。 + containerBlockedSilent: 你正在悄悄开启受阻挡的储物箱。 + containerSilent: 你正在悄悄开启储物箱。 + settingState: '%setting% : %state%' + player: + noMatches: 找不到持有 %target% 的玩家。 + matches: '找到持有 %target% 的玩家 : %detail%' + container: + noMatches: 找不到放有 %target% 的储物箱。 + matches: '找到放有 %target% 的储物箱 : %detail%' + 'true': '开启' + 'false': '关闭' +container: + player: '%player% 的物品栏' + enderchest: '%player% 的末影箱' -- 2.49.1 From 1c579564bc39da0b6c6bd52d1bc164d7b4d9b2d9 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 12 Jul 2021 21:07:45 -0400 Subject: [PATCH 034/139] Add reading assistant --- .github/workflows/ci.yml | 87 ------------------------------- .github/workflows/close-issue.yml | 13 +++++ .github/workflows/close-pr.yml | 13 +++++ 3 files changed, 26 insertions(+), 87 deletions(-) delete mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/close-issue.yml create mode 100644 .github/workflows/close-pr.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index a73e107..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: OpenInv CI - -on: - push: - create: - types: [tag] - pull_request_target: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v2 - - - name: Set Up Java - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - # Use cache to speed up build - - name: Cache Maven Repo - uses: actions/cache@v2 - id: cache - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - - # Install Spigot dependencies. - # This script uses Maven to check all required installations and ensure that they are present. - - name: Install Spigot Dependencies - run: . scripts/install_spigot_dependencies.sh - - - name: Build With Maven - run: mvn -e clean package -am -P all - - # Upload artifacts - - name: Upload Distributable Jar - id: upload-final - uses: actions/upload-artifact@v2 - with: - name: dist - path: ./target/OpenInv.jar - - name: Upload API Jar - id: upload-api - uses: actions/upload-artifact@v2 - with: - name: api - path: ./api/target/openinvapi*.jar - - release: - name: Create Github Release - needs: [ build ] - if: github.event_name == 'create' && github.event.ref_type == 'tag' - runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v2 - - - name: Download Artifacts - uses: actions/download-artifact@v2 - - - name: Generate changelog - run: . scripts/generate_changelog.sh - - - name: Create Release - id: create-release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} - body: ${{ env.GENERATED_CHANGELOG }} - draft: true - prerelease: false - - - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1.0.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: ./OpenInv.jar - asset_name: OpenInv.jar - asset_content_type: application/java-archive \ No newline at end of file diff --git a/.github/workflows/close-issue.yml b/.github/workflows/close-issue.yml new file mode 100644 index 0000000..af9c023 --- /dev/null +++ b/.github/workflows/close-issue.yml @@ -0,0 +1,13 @@ +name: Close Issue + +on: + issues: + types: [opened] + +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: peter-evans/close-issue@v1.0.3 + with: + comment: "Per the notice in the readme, OpenInv is now being maintained at [Jikoo/OpenInv](https://github.com/Jikoo/OpenInv)." diff --git a/.github/workflows/close-pr.yml b/.github/workflows/close-pr.yml new file mode 100644 index 0000000..69d1173 --- /dev/null +++ b/.github/workflows/close-pr.yml @@ -0,0 +1,13 @@ +name: Close Pull Request + +on: + pull_request_target: + types: [opened] + +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: superbrothers/close-pull-request@v3.1.0 + with: + comment: "Per the notice in the readme, OpenInv is now being maintained at [Jikoo/OpenInv](https://github.com/Jikoo/OpenInv)." -- 2.49.1 From ea99bd5fd454246db201a50afa2ac48cd0fa5ecb Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 28 Jul 2021 11:28:08 -0400 Subject: [PATCH 035/139] Extract duplicate API-only code --- .../openinv/internal/IAnySilentContainer.java | 110 +++++++++++++++++- .../internal/v1_16_R3/AnySilentContainer.java | 98 ---------------- .../internal/v1_17_R1/AnySilentContainer.java | 95 --------------- 3 files changed, 107 insertions(+), 196 deletions(-) diff --git a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java index d5e586b..c042777 100644 --- a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java +++ b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java @@ -16,8 +16,19 @@ package com.lishid.openinv.internal; +import org.bukkit.Material; +import org.bukkit.block.Barrel; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.EnderChest; +import org.bukkit.block.ShulkerBox; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; +import org.bukkit.block.data.type.Chest; +import org.bukkit.entity.Cat; import org.bukkit.entity.Player; +import org.bukkit.util.BoundingBox; import org.jetbrains.annotations.NotNull; public interface IAnySilentContainer { @@ -41,14 +52,99 @@ public interface IAnySilentContainer { */ void deactivateContainer(@NotNull Player player); + /** + * @deprecated use {@link #isAnyContainerNeeded(Block)} + * @param player the player opening the container + * @param block the block + * @return true if the container is blocked + */ + @Deprecated + default boolean isAnyContainerNeeded(@NotNull Player player, @NotNull Block block) { + return isAnyContainerNeeded(block); + } + /** * Checks if the container at the given coordinates is blocked. * - * @param player the Player opening the container * @param block the Block * @return true if the container is blocked */ - boolean isAnyContainerNeeded(@NotNull Player player, @NotNull Block block); + default boolean isAnyContainerNeeded(@NotNull Block block) { + BlockState blockState = block.getState(); + + // Barrels do not require AnyContainer. + if (blockState instanceof Barrel) { + return false; + } + + // Enderchests require a non-occluding block on top to open. + if (blockState instanceof EnderChest) { + return block.getRelative(0, 1, 0).getType().isOccluding(); + } + + // Shulker boxes require 1/2 a block clear in the direction they open. + if (blockState instanceof ShulkerBox) { + BoundingBox boundingBox = block.getBoundingBox(); + if (boundingBox.getVolume() > 1) { + // Shulker box is already open. + return false; + } + + BlockData blockData = block.getBlockData(); + if (!(blockData instanceof Directional)) { + // Shouldn't be possible. Just in case, demand AnyChest. + return true; + } + + Directional directional = (Directional) blockData; + BlockFace face = directional.getFacing(); + boundingBox.shift(face.getDirection()); + // Return whether or not bounding boxes overlap. + return block.getRelative(face, 1).getBoundingBox().overlaps(boundingBox); + } + + + if (!(blockState instanceof org.bukkit.block.Chest)) { + return false; + } + + if (isChestBlocked(block)) { + return true; + } + + BlockData blockData = block.getBlockData(); + if (!(blockData instanceof Chest) || ((Chest) blockData).getType() == Chest.Type.SINGLE) { + return false; + } + + Chest chest = (Chest) blockData; + int ordinal = (chest.getFacing().ordinal() + 4 + (chest.getType() == Chest.Type.RIGHT ? -1 : 1)) % 4; + BlockFace relativeFace = BlockFace.values()[ordinal]; + org.bukkit.block.Block relative = block.getRelative(relativeFace); + + if (relative.getType() != block.getType()) { + return false; + } + + BlockData relativeData = relative.getBlockData(); + if (!(relativeData instanceof Chest)) { + return false; + } + + Chest relativeChest = (Chest) relativeData; + if (relativeChest.getFacing() != chest.getFacing() + || relativeChest.getType() != (chest.getType() == Chest.Type.RIGHT ? Chest.Type.LEFT : Chest.Type.RIGHT)) { + return false; + } + + return isChestBlocked(relative); + } + + default boolean isChestBlocked(Block chest) { + org.bukkit.block.Block relative = chest.getRelative(0, 1, 0); + return relative.getType().isOccluding() + || chest.getWorld().getNearbyEntities(BoundingBox.of(relative), entity -> entity instanceof Cat).size() > 0; + } /** * Checks if the given block is a container which can be unblocked or silenced. @@ -56,6 +152,14 @@ public interface IAnySilentContainer { * @param block the BlockState * @return true if the Block is a supported container */ - boolean isAnySilentContainer(@NotNull Block block); + default boolean isAnySilentContainer(@NotNull Block block) { + if (block.getType() == Material.ENDER_CHEST) { + return true; + } + BlockState state = block.getState(); + return state instanceof org.bukkit.block.Chest + || state instanceof org.bukkit.block.ShulkerBox + || state instanceof org.bukkit.block.Barrel; + } } diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java index 36281c2..3e099c0 100644 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java +++ b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java @@ -48,18 +48,8 @@ import net.minecraft.server.v1_16_R3.TileInventory; import net.minecraft.server.v1_16_R3.World; import org.bukkit.Material; import org.bukkit.Statistic; -import org.bukkit.block.Barrel; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.block.EnderChest; -import org.bukkit.block.ShulkerBox; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Directional; -import org.bukkit.block.data.type.Chest; -import org.bukkit.entity.Cat; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryView; -import org.bukkit.util.BoundingBox; import org.jetbrains.annotations.NotNull; public class AnySilentContainer implements IAnySilentContainer { @@ -76,94 +66,6 @@ public class AnySilentContainer implements IAnySilentContainer { } } - @Override - public boolean isAnySilentContainer(@NotNull final org.bukkit.block.Block bukkitBlock) { - if (bukkitBlock.getType() == Material.ENDER_CHEST) { - return true; - } - BlockState state = bukkitBlock.getState(); - return state instanceof org.bukkit.block.Chest - || state instanceof org.bukkit.block.ShulkerBox - || state instanceof org.bukkit.block.Barrel; - } - - @Override - public boolean isAnyContainerNeeded(@NotNull final Player p, @NotNull final org.bukkit.block.Block block) { - BlockState blockState = block.getState(); - - // Barrels do not require AnyContainer. - if (blockState instanceof Barrel) { - return false; - } - - // Enderchests require a non-occluding block on top to open. - if (blockState instanceof EnderChest) { - return block.getRelative(0, 1, 0).getType().isOccluding(); - } - - // Shulker boxes require 1/2 a block clear in the direction they open. - if (blockState instanceof ShulkerBox) { - BoundingBox boundingBox = block.getBoundingBox(); - if (boundingBox.getVolume() > 1) { - // Shulker box is already open. - return false; - } - - BlockData blockData = block.getBlockData(); - if (!(blockData instanceof Directional)) { - // Shouldn't be possible. Just in case, demand AnyChest. - return true; - } - - Directional directional = (Directional) blockData; - BlockFace face = directional.getFacing(); - boundingBox.shift(face.getDirection()); - // Return whether or not bounding boxes overlap. - return block.getRelative(face, 1).getBoundingBox().overlaps(boundingBox); - } - - if (!(blockState instanceof org.bukkit.block.Chest)) { - return false; - } - - if (isBlockedChest(block)) { - return true; - } - - BlockData blockData = block.getBlockData(); - if (!(blockData instanceof Chest) || ((Chest) blockData).getType() == Chest.Type.SINGLE) { - return false; - } - - Chest chest = (Chest) blockData; - int ordinal = (chest.getFacing().ordinal() + 4 + (chest.getType() == Chest.Type.RIGHT ? -1 : 1)) % 4; - BlockFace relativeFace = BlockFace.values()[ordinal]; - org.bukkit.block.Block relative = block.getRelative(relativeFace); - - if (relative.getType() != block.getType()) { - return false; - } - - BlockData relativeData = relative.getBlockData(); - if (!(relativeData instanceof Chest)) { - return false; - } - - Chest relativeChest = (Chest) relativeData; - if (relativeChest.getFacing() != chest.getFacing() - || relativeChest.getType() != (chest.getType() == Chest.Type.RIGHT ? Chest.Type.LEFT : Chest.Type.RIGHT)) { - return false; - } - - return isBlockedChest(relative); - } - - private boolean isBlockedChest(org.bukkit.block.Block block) { - org.bukkit.block.Block relative = block.getRelative(0, 1, 0); - return relative.getType().isOccluding() - || block.getWorld().getNearbyEntities(BoundingBox.of(relative), entity -> entity instanceof Cat).size() > 0; - } - @Override public boolean activateContainer(@NotNull final Player bukkitPlayer, final boolean silentchest, @NotNull final org.bukkit.block.Block bukkitBlock) { diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java index 4e8091d..26a6266 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java @@ -50,18 +50,8 @@ import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.block.state.properties.BlockPropertyChestType; import org.bukkit.Material; import org.bukkit.Statistic; -import org.bukkit.block.Barrel; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.block.EnderChest; -import org.bukkit.block.ShulkerBox; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Directional; -import org.bukkit.block.data.type.Chest; -import org.bukkit.entity.Cat; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryView; -import org.bukkit.util.BoundingBox; import org.jetbrains.annotations.NotNull; public class AnySilentContainer implements IAnySilentContainer { @@ -79,91 +69,6 @@ public class AnySilentContainer implements IAnySilentContainer { } } - @Override - public boolean isAnySilentContainer(@NotNull final org.bukkit.block.Block bukkitBlock) { - if (bukkitBlock.getType() == Material.ENDER_CHEST) { - return true; - } - BlockState state = bukkitBlock.getState(); - return state instanceof org.bukkit.block.Chest - || state instanceof org.bukkit.block.ShulkerBox - || state instanceof org.bukkit.block.Barrel; - } - - @Override - public boolean isAnyContainerNeeded(@NotNull final Player p, @NotNull final org.bukkit.block.Block block) { - BlockState blockState = block.getState(); - - // Barrels do not require AnyContainer. - if (blockState instanceof Barrel) { - return false; - } - - // Enderchests require a non-occluding block on top to open. - if (blockState instanceof EnderChest) { - return block.getRelative(0, 1, 0).getType().isOccluding(); - } - - // Shulker boxes require 1/2 a block clear in the direction they open. - if (blockState instanceof ShulkerBox) { - BoundingBox boundingBox = block.getBoundingBox(); - if (boundingBox.getVolume() > 1) { - // Shulker box is already open. - return false; - } - - BlockData blockData = block.getBlockData(); - if (!(blockData instanceof Directional directional)) { - // Shouldn't be possible. Just in case, demand AnyChest. - return true; - } - - BlockFace face = directional.getFacing(); - boundingBox.shift(face.getDirection()); - // Return whether or not bounding boxes overlap. - return block.getRelative(face, 1).getBoundingBox().overlaps(boundingBox); - } - - if (!(blockState instanceof org.bukkit.block.Chest)) { - return false; - } - - if (isBlockedChest(block)) { - return true; - } - - BlockData blockData = block.getBlockData(); - if (!(blockData instanceof Chest chest) || ((Chest) blockData).getType() == Chest.Type.SINGLE) { - return false; - } - - int ordinal = (chest.getFacing().ordinal() + 4 + (chest.getType() == Chest.Type.RIGHT ? -1 : 1)) % 4; - BlockFace relativeFace = BlockFace.values()[ordinal]; - org.bukkit.block.Block relative = block.getRelative(relativeFace); - - if (relative.getType() != block.getType()) { - return false; - } - - BlockData relativeData = relative.getBlockData(); - if (!(relativeData instanceof Chest relativeChest)) { - return false; - } - - if (relativeChest.getFacing() != chest.getFacing() - || relativeChest.getType() != (chest.getType() == Chest.Type.RIGHT ? Chest.Type.LEFT : Chest.Type.RIGHT)) { - return false; - } - - return isBlockedChest(relative); - } - - private boolean isBlockedChest(org.bukkit.block.Block block) { - org.bukkit.block.Block relative = block.getRelative(0, 1, 0); - return relative.getType().isOccluding() - || block.getWorld().getNearbyEntities(BoundingBox.of(relative), entity -> entity instanceof Cat).size() > 0; - } - @Override public boolean activateContainer( @NotNull final Player bukkitPlayer, -- 2.49.1 From 8599997e03ebc0665f981bba9b63f3bcafd4a650 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 28 Jul 2021 13:38:21 -0400 Subject: [PATCH 036/139] Work towards fixing shulkers --- .../openinv/internal/IAnySilentContainer.java | 22 +++++++++++++++---- .../internal/v1_16_R3/AnySilentContainer.java | 20 +++++++++++++++++ internal/v1_17_R1/pom.xml | 2 +- .../internal/v1_17_R1/AnySilentContainer.java | 20 +++++++++++++++++ scripts/get_spigot_versions.sh | 2 +- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java index c042777..ef78c76 100644 --- a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java +++ b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java @@ -98,11 +98,17 @@ public interface IAnySilentContainer { Directional directional = (Directional) blockData; BlockFace face = directional.getFacing(); - boundingBox.shift(face.getDirection()); - // Return whether or not bounding boxes overlap. - return block.getRelative(face, 1).getBoundingBox().overlaps(boundingBox); - } + Block relative = block.getRelative(face, 1); + if (isShulkerIgnoreBoundingBox(relative)) { + // Certain special cases are ignored. Signs, simple redstone, etc. + return false; + } + + boundingBox.expand(face.getDirection(), 0.5); + // Return whether or not bounding boxes overlap. + return relative.getBoundingBox().overlaps(boundingBox); + } if (!(blockState instanceof org.bukkit.block.Chest)) { return false; @@ -140,6 +146,14 @@ public interface IAnySilentContainer { return isChestBlocked(relative); } + boolean isShulkerIgnoreBoundingBox(Block block); + + /** + * Determine whether or not a chest is blocked. + * + * @param chest the chest block + * @return true if the chest block cannot be opened under ordinary circumstances + */ default boolean isChestBlocked(Block chest) { org.bukkit.block.Block relative = chest.getRelative(0, 1, 0); return relative.getType().isOccluding() diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java index 3e099c0..03a9173 100644 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java +++ b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java @@ -19,6 +19,7 @@ package com.lishid.openinv.internal.v1_16_R3; import com.lishid.openinv.OpenInv; import com.lishid.openinv.internal.IAnySilentContainer; import java.lang.reflect.Field; +import java.util.logging.Level; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockBarrel; import net.minecraft.server.v1_16_R3.BlockChest; @@ -46,8 +47,10 @@ import net.minecraft.server.v1_16_R3.TileEntityEnderChest; import net.minecraft.server.v1_16_R3.TileEntityLootable; import net.minecraft.server.v1_16_R3.TileInventory; import net.minecraft.server.v1_16_R3.World; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Statistic; +import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.NotNull; @@ -66,6 +69,23 @@ public class AnySilentContainer implements IAnySilentContainer { } } + @Override + public boolean isShulkerIgnoreBoundingBox(org.bukkit.block.Block bukkitBlock) { + org.bukkit.World bukkitWorld = bukkitBlock.getWorld(); + if (!(bukkitWorld instanceof CraftWorld)) { + bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); + } + if (!(bukkitWorld instanceof CraftWorld)) { + Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); + OpenInv.getPlugin(OpenInv.class).getLogger().log(Level.WARNING, exception.getMessage(), exception); + return false; + } + + final World world = ((CraftWorld) bukkitWorld).getHandle(); + final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + return world.getType(blockPosition).d(); + } + @Override public boolean activateContainer(@NotNull final Player bukkitPlayer, final boolean silentchest, @NotNull final org.bukkit.block.Block bukkitBlock) { diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index 2cd9043..2c06c72 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -39,7 +39,7 @@ spigot org.spigotmc provided - 1.17-R0.1-SNAPSHOT + 1.17.1-R0.1-SNAPSHOT
openinvapi diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java index 26a6266..672e890 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java @@ -48,8 +48,10 @@ import net.minecraft.world.level.block.entity.TileEntityEnderChest; import net.minecraft.world.level.block.entity.TileEntityLootable; import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.block.state.properties.BlockPropertyChestType; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Statistic; +import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.NotNull; @@ -69,6 +71,24 @@ public class AnySilentContainer implements IAnySilentContainer { } } + @Override + public boolean isShulkerIgnoreBoundingBox(org.bukkit.block.Block bukkitBlock) { + org.bukkit.World bukkitWorld = bukkitBlock.getWorld(); + if (!(bukkitWorld instanceof CraftWorld)) { + bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); + } + if (!(bukkitWorld instanceof CraftWorld)) { + Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); + OpenInv.getPlugin(OpenInv.class).getLogger().log(Level.WARNING, exception.getMessage(), exception); + return false; + } + + final World world = ((CraftWorld) bukkitWorld).getHandle(); + final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + // isLargeVoxelShape + return world.getType(blockPosition).d(); + } + @Override public boolean activateContainer( @NotNull final Player bukkitPlayer, diff --git a/scripts/get_spigot_versions.sh b/scripts/get_spigot_versions.sh index e524912..29376e0 100644 --- a/scripts/get_spigot_versions.sh +++ b/scripts/get_spigot_versions.sh @@ -16,7 +16,7 @@ # # TODO FIGURE OUT AND REMOVE WHEN LESS STRESS -hacky_versions=("1.16.5-R0.1-SNAPSHOT" "1.17-R0.1-SNAPSHOT") +hacky_versions=("1.16.5-R0.1-SNAPSHOT" "1.17.1-R0.1-SNAPSHOT") for hacky_version in "${hacky_versions[@]}"; do echo "$hacky_version" done -- 2.49.1 From 556a8bcfce58217686ec10dd1afaf94296b048e8 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 16 Oct 2021 16:23:26 -0400 Subject: [PATCH 037/139] Drop 1.16.5 support to use Mojang mappings Because there is no option to create a `remapped-mojang` artifact for 1.16.5 and the whole point of the scripts is to save me time, 1.16.5 support is being removed earlier than usual. Also fixes issues with NMS-based shulker collision check. Closes #36 --- .../openinv/internal/IAnySilentContainer.java | 26 +- .../lishid/openinv/util/InventoryAccess.java | 21 +- .../lishid/openinv/util/ReflectionHelper.java | 75 ++ internal/v1_16_R3/pom.xml | 64 -- .../internal/v1_16_R3/AnySilentContainer.java | 265 ------ .../openinv/internal/v1_16_R3/OpenPlayer.java | 78 -- .../internal/v1_16_R3/PlayerDataManager.java | 235 ------ .../internal/v1_16_R3/SpecialEnderChest.java | 261 ------ .../v1_16_R3/SpecialPlayerInventory.java | 738 ---------------- internal/v1_17_R1/pom.xml | 33 + .../internal/v1_17_R1/AnySilentContainer.java | 260 +++--- .../openinv/internal/v1_17_R1/OpenPlayer.java | 44 +- .../internal/v1_17_R1/PlayerDataManager.java | 63 +- .../internal/v1_17_R1/SpecialEnderChest.java | 369 ++++---- .../v1_17_R1/SpecialPlayerInventory.java | 796 +++++++++--------- .../lishid/openinv/util/InternalAccessor.java | 2 + pom.xml | 7 +- scripts/get_spigot_versions.sh | 4 +- scripts/install_spigot_dependencies.sh | 4 +- 19 files changed, 889 insertions(+), 2456 deletions(-) create mode 100644 api/src/main/java/com/lishid/openinv/util/ReflectionHelper.java delete mode 100644 internal/v1_16_R3/pom.xml delete mode 100644 internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java delete mode 100644 internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java delete mode 100644 internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java delete mode 100644 internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialEnderChest.java delete mode 100644 internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialPlayerInventory.java diff --git a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java index ef78c76..62b95e4 100644 --- a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java +++ b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java @@ -24,7 +24,6 @@ import org.bukkit.block.BlockState; import org.bukkit.block.EnderChest; import org.bukkit.block.ShulkerBox; import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Directional; import org.bukkit.block.data.type.Chest; import org.bukkit.entity.Cat; import org.bukkit.entity.Player; @@ -84,30 +83,9 @@ public interface IAnySilentContainer { // Shulker boxes require 1/2 a block clear in the direction they open. if (blockState instanceof ShulkerBox) { - BoundingBox boundingBox = block.getBoundingBox(); - if (boundingBox.getVolume() > 1) { - // Shulker box is already open. - return false; - } - - BlockData blockData = block.getBlockData(); - if (!(blockData instanceof Directional)) { - // Shouldn't be possible. Just in case, demand AnyChest. + if (isShulkerBlocked((ShulkerBox) blockState)) { return true; } - - Directional directional = (Directional) blockData; - BlockFace face = directional.getFacing(); - Block relative = block.getRelative(face, 1); - - if (isShulkerIgnoreBoundingBox(relative)) { - // Certain special cases are ignored. Signs, simple redstone, etc. - return false; - } - - boundingBox.expand(face.getDirection(), 0.5); - // Return whether or not bounding boxes overlap. - return relative.getBoundingBox().overlaps(boundingBox); } if (!(blockState instanceof org.bukkit.block.Chest)) { @@ -146,7 +124,7 @@ public interface IAnySilentContainer { return isChestBlocked(relative); } - boolean isShulkerIgnoreBoundingBox(Block block); + boolean isShulkerBlocked(ShulkerBox block); /** * Determine whether or not a chest is blocked. diff --git a/api/src/main/java/com/lishid/openinv/util/InventoryAccess.java b/api/src/main/java/com/lishid/openinv/util/InventoryAccess.java index 90885da..1de0d85 100644 --- a/api/src/main/java/com/lishid/openinv/util/InventoryAccess.java +++ b/api/src/main/java/com/lishid/openinv/util/InventoryAccess.java @@ -20,7 +20,6 @@ import com.lishid.openinv.internal.IInventoryAccess; import com.lishid.openinv.internal.ISpecialEnderChest; import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.internal.ISpecialPlayerInventory; -import java.lang.reflect.Field; import java.lang.reflect.Method; import org.bukkit.Bukkit; import org.bukkit.inventory.Inventory; @@ -81,7 +80,8 @@ public class InventoryAccess implements IInventoryAccess { } catch (ReflectiveOperationException ignored) {} } - inv = grabFieldOfTypeFromObject(expected, inventory); + // Use reflection to find the IInventory + inv = ReflectionHelper.grabObjectByType(inventory, expected); if (expected.isInstance(inv)) { return expected.cast(inv); @@ -90,23 +90,6 @@ public class InventoryAccess implements IInventoryAccess { return null; } - private static @Nullable T grabFieldOfTypeFromObject(final Class type, final Object object) { - // Use reflection to find the IInventory - Class clazz = object.getClass(); - T result = null; - for (Field f : clazz.getDeclaredFields()) { - f.setAccessible(true); - if (type.isAssignableFrom(f.getDeclaringClass())) { - try { - result = type.cast(f.get(object)); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - return result; - } - @Deprecated @Override public @Nullable ISpecialEnderChest getSpecialEnderChest(@NotNull Inventory inventory) { diff --git a/api/src/main/java/com/lishid/openinv/util/ReflectionHelper.java b/api/src/main/java/com/lishid/openinv/util/ReflectionHelper.java new file mode 100644 index 0000000..7c28374 --- /dev/null +++ b/api/src/main/java/com/lishid/openinv/util/ReflectionHelper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.util; + +import java.lang.reflect.Field; +import org.jetbrains.annotations.Nullable; + +/** + * A utility for making reflection easier. + */ +public final class ReflectionHelper { + + private ReflectionHelper() {} + + /** + * Grab an {@link Object} stored in a {@link Field} of another {@code Object}. + * + *

This casts the field to the correct class. Any issues will result in a {@code null} return value. + * + * @param fieldType the {@link Class} of {@code Object} stored in the {@code Field} + * @param holder the containing {@code Object} + * @param the type of stored {@code Object} + * @return the first matching {@code Object} or {@code null} if none match + */ + public static @Nullable T grabObjectByType(final Object holder, final Class fieldType) { + Field field = grabFieldByType(holder.getClass(), fieldType); + + if (field != null) { + try { + return fieldType.cast(field.get(holder)); + } catch (IllegalAccessException ignored) { + // Ignore issues obtaining field + } + } + + return null; + } + + /** + * Grab a {@link Field} of an {@link Object} + * + * @param fieldType the {@link Class} of the object + * @param holderType the containing {@code Class} + * @return the first matching object or {@code null} if none match + */ + public static @Nullable Field grabFieldByType(Class holderType, Class fieldType) { + for (Field field : holderType.getDeclaredFields()) { + field.setAccessible(true); + if (fieldType.isAssignableFrom(field.getType())) { + return field; + } + } + + if (holderType.getSuperclass() != null) { + return grabFieldByType(fieldType, holderType.getSuperclass()); + } + + return null; + } + +} diff --git a/internal/v1_16_R3/pom.xml b/internal/v1_16_R3/pom.xml deleted file mode 100644 index 90b9458..0000000 --- a/internal/v1_16_R3/pom.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - 4.0.0 - - - openinvparent - com.lishid - ../../pom.xml - 4.1.9-SNAPSHOT - - - openinvadapter1_16_R3 - OpenInvAdapter1_16_R3 - - - - spigot - org.spigotmc - provided - 1.16.5-R0.1-SNAPSHOT - - - openinvapi - com.lishid - - - openinvplugincore - com.lishid - - - annotations - org.jetbrains - - - - - - - maven-shade-plugin - - - maven-compiler-plugin - - - - - diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java deleted file mode 100644 index 03a9173..0000000 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (C) 2011-2021 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_16_R3; - -import com.lishid.openinv.OpenInv; -import com.lishid.openinv.internal.IAnySilentContainer; -import java.lang.reflect.Field; -import java.util.logging.Level; -import net.minecraft.server.v1_16_R3.Block; -import net.minecraft.server.v1_16_R3.BlockBarrel; -import net.minecraft.server.v1_16_R3.BlockChest; -import net.minecraft.server.v1_16_R3.BlockChestTrapped; -import net.minecraft.server.v1_16_R3.BlockPosition; -import net.minecraft.server.v1_16_R3.BlockPropertyChestType; -import net.minecraft.server.v1_16_R3.BlockShulkerBox; -import net.minecraft.server.v1_16_R3.ChatMessage; -import net.minecraft.server.v1_16_R3.Container; -import net.minecraft.server.v1_16_R3.ContainerChest; -import net.minecraft.server.v1_16_R3.Containers; -import net.minecraft.server.v1_16_R3.EntityHuman; -import net.minecraft.server.v1_16_R3.EntityPlayer; -import net.minecraft.server.v1_16_R3.EnumGamemode; -import net.minecraft.server.v1_16_R3.IBlockData; -import net.minecraft.server.v1_16_R3.IChatBaseComponent; -import net.minecraft.server.v1_16_R3.ITileInventory; -import net.minecraft.server.v1_16_R3.InventoryEnderChest; -import net.minecraft.server.v1_16_R3.InventoryLargeChest; -import net.minecraft.server.v1_16_R3.PlayerInteractManager; -import net.minecraft.server.v1_16_R3.PlayerInventory; -import net.minecraft.server.v1_16_R3.TileEntity; -import net.minecraft.server.v1_16_R3.TileEntityChest; -import net.minecraft.server.v1_16_R3.TileEntityEnderChest; -import net.minecraft.server.v1_16_R3.TileEntityLootable; -import net.minecraft.server.v1_16_R3.TileInventory; -import net.minecraft.server.v1_16_R3.World; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.Statistic; -import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; -import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryView; -import org.jetbrains.annotations.NotNull; - -public class AnySilentContainer implements IAnySilentContainer { - - private Field playerInteractManagerGamemode; - - public AnySilentContainer() { - try { - this.playerInteractManagerGamemode = PlayerInteractManager.class.getDeclaredField("gamemode"); - this.playerInteractManagerGamemode.setAccessible(true); - } catch (NoSuchFieldException | SecurityException e) { - System.err.println("[OpenInv] Unable to directly write player gamemode! SilentChest will fail."); - e.printStackTrace(); - } - } - - @Override - public boolean isShulkerIgnoreBoundingBox(org.bukkit.block.Block bukkitBlock) { - org.bukkit.World bukkitWorld = bukkitBlock.getWorld(); - if (!(bukkitWorld instanceof CraftWorld)) { - bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); - } - if (!(bukkitWorld instanceof CraftWorld)) { - Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); - OpenInv.getPlugin(OpenInv.class).getLogger().log(Level.WARNING, exception.getMessage(), exception); - return false; - } - - final World world = ((CraftWorld) bukkitWorld).getHandle(); - final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); - return world.getType(blockPosition).d(); - } - - @Override - public boolean activateContainer(@NotNull final Player bukkitPlayer, final boolean silentchest, - @NotNull final org.bukkit.block.Block bukkitBlock) { - - // Silent ender chest is API-only - if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) { - bukkitPlayer.openInventory(bukkitPlayer.getEnderChest()); - bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); - return true; - } - - EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer); - - final World world = player.world; - final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); - final TileEntity tile = world.getTileEntity(blockPosition); - - if (tile == null) { - return false; - } - - if (tile instanceof TileEntityEnderChest) { - // Anychest ender chest. See net.minecraft.server.BlockEnderChest - InventoryEnderChest enderChest = player.getEnderChest(); - enderChest.a((TileEntityEnderChest) tile); - player.openContainer(new TileInventory((containerCounter, playerInventory, ignored) -> { - Containers containers = PlayerDataManager.getContainers(enderChest.getSize()); - int rows = enderChest.getSize() / 9; - return new ContainerChest(containers, containerCounter, playerInventory, enderChest, rows); - }, new ChatMessage("container.enderchest"))); - bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); - return true; - } - - if (!(tile instanceof ITileInventory)) { - return false; - } - - ITileInventory tileInventory = (ITileInventory) tile; - IBlockData blockData = world.getType(blockPosition); - Block block = blockData.getBlock(); - - if (block instanceof BlockChest) { - - BlockPropertyChestType chestType = blockData.get(BlockChest.c); - - if (chestType != BlockPropertyChestType.SINGLE) { - - BlockPosition adjacentBlockPosition = blockPosition.shift(BlockChest.h(blockData)); - IBlockData adjacentBlockData = world.getType(adjacentBlockPosition); - - if (adjacentBlockData.getBlock() == block) { - - BlockPropertyChestType adjacentChestType = adjacentBlockData.get(BlockChest.c); - - if (adjacentChestType != BlockPropertyChestType.SINGLE && chestType != adjacentChestType - && adjacentBlockData.get(BlockChest.FACING) == blockData.get(BlockChest.FACING)) { - - TileEntity adjacentTile = world.getTileEntity(adjacentBlockPosition); - - if (adjacentTile instanceof TileEntityChest && tileInventory instanceof TileEntityChest) { - TileEntityChest rightChest = chestType == BlockPropertyChestType.RIGHT ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile; - TileEntityChest leftChest = chestType == BlockPropertyChestType.RIGHT ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory); - - if (silentchest && (rightChest.lootTable != null || leftChest.lootTable != null)) { - OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); - return false; - } - - tileInventory = new ITileInventory() { - public Container createMenu(int containerCounter, PlayerInventory playerInventory, EntityHuman entityHuman) { - leftChest.d(playerInventory.player); - rightChest.d(playerInventory.player); - return ContainerChest.b(containerCounter, playerInventory, new InventoryLargeChest(rightChest, leftChest)); - } - - public IChatBaseComponent getScoreboardDisplayName() { - if (leftChest.hasCustomName()) { - return leftChest.getScoreboardDisplayName(); - } - if (rightChest.hasCustomName()) { - return rightChest.getScoreboardDisplayName(); - } - return new ChatMessage("container.chestDouble"); - } - }; - } - } - } - } - - if (block instanceof BlockChestTrapped) { - bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); - } else { - bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED); - } - } - - if (block instanceof BlockShulkerBox) { - bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED); - } - - if (block instanceof BlockBarrel) { - bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL); - } - - // AnyChest only - SilentChest not active, container unsupported, or unnecessary. - if (!silentchest || player.playerInteractManager.getGameMode() == EnumGamemode.SPECTATOR) { - player.openContainer(tileInventory); - return true; - } - - // SilentChest requires access to setting players' gamemode directly. - if (this.playerInteractManagerGamemode == null) { - return false; - } - - if (tile instanceof TileEntityLootable) { - TileEntityLootable lootable = (TileEntityLootable) tile; - if (lootable.lootTable != null) { - OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); - return false; - } - } - - EnumGamemode gamemode = player.playerInteractManager.getGameMode(); - this.forceGameMode(player, EnumGamemode.SPECTATOR); - player.openContainer(tileInventory); - this.forceGameMode(player, gamemode); - return true; - } - - @Override - public void deactivateContainer(@NotNull final Player bukkitPlayer) { - if (this.playerInteractManagerGamemode == null) { - return; - } - - InventoryView view = bukkitPlayer.getOpenInventory(); - switch (view.getType()) { - case CHEST: - case ENDER_CHEST: - case SHULKER_BOX: - case BARREL: - break; - default: - return; - } - - EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer); - - EnumGamemode gamemode = player.playerInteractManager.getGameMode(); - this.forceGameMode(player, EnumGamemode.SPECTATOR); - player.activeContainer.b(player); - player.activeContainer.a(player, false); - player.activeContainer.transferTo(player.defaultContainer, player.getBukkitEntity()); - player.activeContainer = player.defaultContainer; - this.forceGameMode(player, gamemode); - } - - private void forceGameMode(final EntityPlayer player, final EnumGamemode gameMode) { - if (this.playerInteractManagerGamemode == null) { - // No need to warn repeatedly, error on startup and lack of function should be enough. - return; - } - try { - if (!this.playerInteractManagerGamemode.isAccessible()) { - // Just in case, ensure accessible. - this.playerInteractManagerGamemode.setAccessible(true); - } - this.playerInteractManagerGamemode.set(player.playerInteractManager, gameMode); - } catch (IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - } - } - -} diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java deleted file mode 100644 index ec87e3b..0000000 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2011-2021 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_16_R3; - -import java.io.File; -import java.io.FileOutputStream; -import net.minecraft.server.v1_16_R3.EntityPlayer; -import net.minecraft.server.v1_16_R3.NBTCompressedStreamTools; -import net.minecraft.server.v1_16_R3.NBTTagCompound; -import net.minecraft.server.v1_16_R3.WorldNBTStorage; -import org.apache.logging.log4j.LogManager; -import org.bukkit.craftbukkit.v1_16_R3.CraftServer; -import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; - -public class OpenPlayer extends CraftPlayer { - - public OpenPlayer(CraftServer server, EntityPlayer entity) { - super(server, entity); - } - - @Override - public void loadData() { - // See CraftPlayer#loadData - NBTTagCompound loaded = this.server.getHandle().playerFileData.load(this.getHandle()); - if (loaded != null) { - readExtraData(loaded); - } - } - - @Override - public void saveData() { - EntityPlayer player = this.getHandle(); - // See net.minecraft.server.WorldNBTStorage#save(EntityPlayer) - try { - WorldNBTStorage worldNBTStorage = player.server.getPlayerList().playerFileData; - - NBTTagCompound playerData = player.save(new NBTTagCompound()); - setExtraData(playerData); - - if (!isOnline()) { - // Special case: save old vehicle data - NBTTagCompound oldData = worldNBTStorage.load(player); - - if (oldData != null && oldData.hasKeyOfType("RootVehicle", 10)) { - // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound) - playerData.set("RootVehicle", oldData.getCompound("RootVehicle")); - } - } - - File file = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat.tmp"); - File file1 = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat"); - - NBTCompressedStreamTools.a(playerData, new FileOutputStream(file)); - - if (file1.exists() && !file1.delete() || !file.renameTo(file1)) { - LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString()); - } - - } catch (Exception e) { - LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString()); - } - } - -} diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java deleted file mode 100644 index 56490ec..0000000 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2011-2021 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_16_R3; - -import com.lishid.openinv.internal.IPlayerDataManager; -import com.lishid.openinv.internal.ISpecialInventory; -import com.lishid.openinv.internal.OpenInventoryView; -import com.mojang.authlib.GameProfile; -import java.lang.reflect.Field; -import net.minecraft.server.v1_16_R3.ChatComponentText; -import net.minecraft.server.v1_16_R3.Container; -import net.minecraft.server.v1_16_R3.Containers; -import net.minecraft.server.v1_16_R3.Entity; -import net.minecraft.server.v1_16_R3.EntityPlayer; -import net.minecraft.server.v1_16_R3.MinecraftServer; -import net.minecraft.server.v1_16_R3.PacketPlayOutOpenWindow; -import net.minecraft.server.v1_16_R3.PlayerInteractManager; -import net.minecraft.server.v1_16_R3.World; -import net.minecraft.server.v1_16_R3.WorldServer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.craftbukkit.v1_16_R3.CraftServer; -import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory; -import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftContainer; -import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class PlayerDataManager implements IPlayerDataManager { - - private @Nullable Field bukkitEntity; - - public PlayerDataManager() { - try { - bukkitEntity = Entity.class.getDeclaredField("bukkitEntity"); - } catch (NoSuchFieldException e) { - System.out.println("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded."); - e.printStackTrace(); - bukkitEntity = null; - } - } - - public static @NotNull EntityPlayer getHandle(final Player player) { - if (player instanceof CraftPlayer) { - return ((CraftPlayer) player).getHandle(); - } - - Server server = player.getServer(); - EntityPlayer nmsPlayer = null; - - if (server instanceof CraftServer) { - nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getName()); - } - - if (nmsPlayer == null) { - // Could use reflection to examine fields, but it's honestly not worth the bother. - throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation"); - } - - return nmsPlayer; - } - - @Override - public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { - // Ensure player has data - if (!offline.hasPlayedBefore()) { - return null; - } - - // Create a profile and entity to load the player data - // See net.minecraft.server.PlayerList#attemptLogin - GameProfile profile = new GameProfile(offline.getUniqueId(), - offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - WorldServer worldServer = server.getWorldServer(World.OVERWORLD); - - if (worldServer == null) { - return null; - } - - EntityPlayer entity = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); - - try { - injectPlayer(entity); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - - // Get the bukkit entity - Player target = entity.getBukkitEntity(); - if (target != null) { - // Load data - target.loadData(); - } - // Return the entity - return target; - } - - void injectPlayer(EntityPlayer player) throws IllegalAccessException { - if (bukkitEntity == null) { - return; - } - - bukkitEntity.setAccessible(true); - - bukkitEntity.set(player, new OpenPlayer(player.server.server, player)); - } - - @NotNull - @Override - public Player inject(@NotNull Player player) { - try { - EntityPlayer nmsPlayer = getHandle(player); - injectPlayer(nmsPlayer); - return nmsPlayer.getBukkitEntity(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - return player; - } - } - - @Nullable - @Override - public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) { - - EntityPlayer nmsPlayer = getHandle(player); - - if (nmsPlayer.playerConnection == null) { - return null; - } - - InventoryView view = getView(player, inventory); - - if (view == null) { - return player.openInventory(inventory.getBukkitInventory()); - } - - Container container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { - @Override - public Containers getType() { - return getContainers(inventory.getBukkitInventory().getSize()); - } - }; - - container.setTitle(new ChatComponentText(view.getTitle())); - container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); - - if (container == null) { - return null; - } - - nmsPlayer.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, container.getType(), - new ChatComponentText(container.getBukkitView().getTitle()))); - nmsPlayer.activeContainer = container; - container.addSlotListener(nmsPlayer); - - return container.getBukkitView(); - - } - - private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) { - if (inventory instanceof SpecialEnderChest) { - return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest"); - } else if (inventory instanceof SpecialPlayerInventory) { - return new OpenInventoryView(player, inventory, "container.player", "'s Inventory"); - } else { - return null; - } - } - - static @NotNull Containers getContainers(int inventorySize) { - switch (inventorySize) { - case 9: - return Containers.GENERIC_9X1; - case 18: - return Containers.GENERIC_9X2; - case 36: - return Containers.GENERIC_9X4; - case 41: // PLAYER - case 45: - return Containers.GENERIC_9X5; - case 54: - return Containers.GENERIC_9X6; - case 27: - default: - return Containers.GENERIC_9X3; - } - } - - @Override - public int convertToPlayerSlot(InventoryView view, int rawSlot) { - int topSize = view.getTopInventory().getSize(); - if (topSize <= rawSlot) { - // Slot is not inside special inventory, use Bukkit logic. - return view.convertSlot(rawSlot); - } - - // Main inventory, slots 0-26 -> 9-35 - if (rawSlot < 27) { - return rawSlot + 9; - } - // Hotbar, slots 27-35 -> 0-8 - if (rawSlot < 36) { - return rawSlot - 27; - } - // Armor, slots 36-39 -> 39-36 - if (rawSlot < 40) { - return 36 + (39 - rawSlot); - } - // Off hand - if (rawSlot == 40) { - return 40; - } - // Drop slots, "out of inventory" - return -1; - } - -} diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialEnderChest.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialEnderChest.java deleted file mode 100644 index c2bf061..0000000 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialEnderChest.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2011-2021 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_16_R3; - -import com.lishid.openinv.internal.ISpecialEnderChest; -import java.util.List; -import net.minecraft.server.v1_16_R3.AutoRecipeStackManager; -import net.minecraft.server.v1_16_R3.ContainerUtil; -import net.minecraft.server.v1_16_R3.EntityHuman; -import net.minecraft.server.v1_16_R3.EntityPlayer; -import net.minecraft.server.v1_16_R3.IInventoryListener; -import net.minecraft.server.v1_16_R3.InventoryEnderChest; -import net.minecraft.server.v1_16_R3.ItemStack; -import net.minecraft.server.v1_16_R3.NonNullList; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_16_R3.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftInventory; -import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryHolder; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEnderChest { - - private final CraftInventory inventory; - private EntityPlayer owner; - private NonNullList items; - private boolean playerOnline; - - public SpecialEnderChest(final Player player, final Boolean online) { - super(PlayerDataManager.getHandle(player)); - this.inventory = new CraftInventory(this); - this.owner = PlayerDataManager.getHandle(player); - this.playerOnline = online; - this.items = this.owner.getEnderChest().items; - } - - @Override - public @NotNull CraftInventory getBukkitInventory() { - return inventory; - } - - @Override - public boolean isInUse() { - return !this.getViewers().isEmpty(); - } - - @Override - public void setPlayerOffline() { - this.playerOnline = false; - } - - @Override - public void setPlayerOnline(@NotNull final Player player) { - if (!this.playerOnline) { - try { - this.owner = PlayerDataManager.getHandle(player); - InventoryEnderChest enderChest = owner.getEnderChest(); - for (int i = 0; i < enderChest.getSize(); ++i) { - enderChest.setItem(i, this.items.get(i)); - } - this.items = enderChest.items; - } catch (Exception ignored) {} - this.playerOnline = true; - } - } - - @Override - public @NotNull Player getPlayer() { - return owner.getBukkitEntity(); - } - - @Override - public void update() { - this.owner.getEnderChest().update(); - } - - @Override - public List getContents() { - return this.items; - } - - @Override - public void onOpen(CraftHumanEntity who) { - this.owner.getEnderChest().onOpen(who); - } - - @Override - public void onClose(CraftHumanEntity who) { - this.owner.getEnderChest().onClose(who); - } - - @Override - public List getViewers() { - return this.owner.getEnderChest().getViewers(); - } - - @Override - public void setMaxStackSize(int i) { - this.owner.getEnderChest().setMaxStackSize(i); - } - - @Override - public InventoryHolder getOwner() { - return this.owner.getEnderChest().getOwner(); - } - - @Override - public @Nullable Location getLocation() { - return null; - } - - @Override - public void a(IInventoryListener iinventorylistener) { - this.owner.getEnderChest().a(iinventorylistener); - } - - @Override - public void b(IInventoryListener iinventorylistener) { - this.owner.getEnderChest().b(iinventorylistener); - } - - @Override - public ItemStack getItem(int i) { - return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.b; - } - - @Override - public ItemStack splitStack(int i, int j) { - ItemStack itemstack = ContainerUtil.a(this.items, i, j); - if (!itemstack.isEmpty()) { - this.update(); - } - - return itemstack; - } - - @Override - public ItemStack a(ItemStack itemstack) { - ItemStack itemstack1 = itemstack.cloneItemStack(); - - for (int i = 0; i < this.getSize(); ++i) { - ItemStack itemstack2 = this.getItem(i); - if (itemstack2.isEmpty()) { - this.setItem(i, itemstack1); - this.update(); - return ItemStack.b; - } - - if (ItemStack.c(itemstack2, itemstack1)) { - int j = Math.min(this.getMaxStackSize(), itemstack2.getMaxStackSize()); - int k = Math.min(itemstack1.getCount(), j - itemstack2.getCount()); - if (k > 0) { - itemstack2.add(k); - itemstack1.subtract(k); - if (itemstack1.isEmpty()) { - this.update(); - return ItemStack.b; - } - } - } - } - - if (itemstack1.getCount() != itemstack.getCount()) { - this.update(); - } - - return itemstack1; - } - - @Override - public ItemStack splitWithoutUpdate(int i) { - ItemStack itemstack = this.items.get(i); - if (itemstack.isEmpty()) { - return ItemStack.b; - } else { - this.items.set(i, ItemStack.b); - return itemstack; - } - } - - @Override - public void setItem(int i, ItemStack itemstack) { - this.items.set(i, itemstack); - if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { - itemstack.setCount(this.getMaxStackSize()); - } - - this.update(); - } - - @Override - public int getSize() { - return this.owner.getEnderChest().getSize(); - } - - @Override - public boolean isEmpty() { - - for (ItemStack itemstack : this.items) { - if (!itemstack.isEmpty()) { - return false; - } - } - - return true; - } - - @Override - public int getMaxStackSize() { - return 64; - } - - @Override - public boolean a(EntityHuman entityhuman) { - return true; - } - - @Override - public void startOpen(EntityHuman entityhuman) { - } - - @Override - public void closeContainer(EntityHuman entityhuman) { - } - - @Override - public boolean b(int i, ItemStack itemstack) { - return true; - } - - @Override - public void clear() { - this.items.clear(); - } - - @Override - public void a(AutoRecipeStackManager autorecipestackmanager) { - - for (ItemStack itemstack : this.items) { - autorecipestackmanager.b(itemstack); - } - - } - -} diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialPlayerInventory.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialPlayerInventory.java deleted file mode 100644 index df9325c..0000000 --- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/SpecialPlayerInventory.java +++ /dev/null @@ -1,738 +0,0 @@ -/* - * Copyright (C) 2011-2021 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_16_R3; - -import com.google.common.collect.ImmutableList; -import com.lishid.openinv.internal.ISpecialPlayerInventory; -import java.util.Iterator; -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import net.minecraft.server.v1_16_R3.AutoRecipeStackManager; -import net.minecraft.server.v1_16_R3.ChatMessage; -import net.minecraft.server.v1_16_R3.ContainerUtil; -import net.minecraft.server.v1_16_R3.CrashReport; -import net.minecraft.server.v1_16_R3.CrashReportSystemDetails; -import net.minecraft.server.v1_16_R3.DamageSource; -import net.minecraft.server.v1_16_R3.EntityHuman; -import net.minecraft.server.v1_16_R3.EntityPlayer; -import net.minecraft.server.v1_16_R3.EnumItemSlot; -import net.minecraft.server.v1_16_R3.IBlockData; -import net.minecraft.server.v1_16_R3.IChatBaseComponent; -import net.minecraft.server.v1_16_R3.IInventory; -import net.minecraft.server.v1_16_R3.Item; -import net.minecraft.server.v1_16_R3.ItemArmor; -import net.minecraft.server.v1_16_R3.ItemStack; -import net.minecraft.server.v1_16_R3.NBTTagCompound; -import net.minecraft.server.v1_16_R3.NBTTagList; -import net.minecraft.server.v1_16_R3.NonNullList; -import net.minecraft.server.v1_16_R3.PacketPlayOutSetSlot; -import net.minecraft.server.v1_16_R3.PlayerInventory; -import net.minecraft.server.v1_16_R3.ReportedException; -import net.minecraft.server.v1_16_R3.World; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_16_R3.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftInventory; -import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryHolder; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory { - - private final CraftInventory inventory; - private boolean playerOnline; - private EntityHuman player; - private NonNullList items, armor, extraSlots; - private List> f; - - public SpecialPlayerInventory(final Player bukkitPlayer, final Boolean online) { - super(PlayerDataManager.getHandle(bukkitPlayer)); - this.inventory = new CraftInventory(this); - this.playerOnline = online; - this.player = super.player; - this.items = this.player.inventory.items; - this.armor = this.player.inventory.armor; - this.extraSlots = this.player.inventory.extraSlots; - this.f = ImmutableList.of(this.items, this.armor, this.extraSlots); - } - - @Override - public void setPlayerOnline(@NotNull final Player player) { - if (!this.playerOnline) { - EntityPlayer entityPlayer = PlayerDataManager.getHandle(player); - entityPlayer.inventory.transaction.addAll(this.transaction); - this.player = entityPlayer; - for (int i = 0; i < getSize(); ++i) { - this.player.inventory.setItem(i, getRawItem(i)); - } - this.player.inventory.itemInHandIndex = this.itemInHandIndex; - this.items = this.player.inventory.items; - this.armor = this.player.inventory.armor; - this.extraSlots = this.player.inventory.extraSlots; - this.f = ImmutableList.of(this.items, this.armor, this.extraSlots); - this.playerOnline = true; - } - } - - @Override - public boolean a(final EntityHuman entityhuman) { - return true; - } - - @Override - public @NotNull CraftInventory getBukkitInventory() { - return this.inventory; - } - - @Override - public ItemStack getItem(int i) { - List list = this.items; - - if (i >= list.size()) { - i -= list.size(); - list = this.armor; - } else { - i = this.getReversedItemSlotNum(i); - } - - if (i >= list.size()) { - i -= list.size(); - list = this.extraSlots; - } else if (list == this.armor) { - i = this.getReversedArmorSlotNum(i); - } - - if (i >= list.size()) { - return ItemStack.b; - } - - return list.get(i); - } - - private ItemStack getRawItem(int i) { - NonNullList list = null; - for (NonNullList next : this.f) { - if (i < next.size()) { - list = next; - break; - } - i -= next.size(); - } - - return list == null ? ItemStack.b : list.get(i); - } - - @Override - public IChatBaseComponent getDisplayName() { - return new ChatMessage(this.player.getName()); - } - - @Override - public boolean hasCustomName() { - return false; - } - - private int getReversedArmorSlotNum(final int i) { - if (i == 0) { - return 3; - } - if (i == 1) { - return 2; - } - if (i == 2) { - return 1; - } - if (i == 3) { - return 0; - } - return i; - } - - private int getReversedItemSlotNum(final int i) { - if (i >= 27) { - return i - 27; - } - return i + 9; - } - - @Override - public int getSize() { - return 45; - } - - @Override - public boolean isInUse() { - return !this.getViewers().isEmpty(); - } - - @Override - public void setItem(int i, final ItemStack itemstack) { - List list = this.items; - - if (i >= list.size()) { - i -= list.size(); - list = this.armor; - } else { - i = this.getReversedItemSlotNum(i); - } - - if (i >= list.size()) { - i -= list.size(); - list = this.extraSlots; - } else if (list == this.armor) { - i = this.getReversedArmorSlotNum(i); - } - - if (i >= list.size()) { - this.player.drop(itemstack, true); - return; - } - - list.set(i, itemstack); - } - - @Override - public void setPlayerOffline() { - this.playerOnline = false; - } - - @Override - public @NotNull HumanEntity getPlayer() { - return this.player.getBukkitEntity(); - } - - @Override - public ItemStack splitStack(int i, final int j) { - List list = this.items; - - if (i >= list.size()) { - i -= list.size(); - list = this.armor; - } else { - i = this.getReversedItemSlotNum(i); - } - - if (i >= list.size()) { - i -= list.size(); - list = this.extraSlots; - } else if (list == this.armor) { - i = this.getReversedArmorSlotNum(i); - } - - if (i >= list.size()) { - return ItemStack.b; - } - - return list.get(i).isEmpty() ? ItemStack.b : ContainerUtil.a(list, i, j); - } - - @Override - public ItemStack splitWithoutUpdate(int i) { - List list = this.items; - - if (i >= list.size()) { - i -= list.size(); - list = this.armor; - } else { - i = this.getReversedItemSlotNum(i); - } - - if (i >= list.size()) { - i -= list.size(); - list = this.extraSlots; - } else if (list == this.armor) { - i = this.getReversedArmorSlotNum(i); - } - - if (i >= list.size()) { - return ItemStack.b; - } - - if (!list.get(i).isEmpty()) { - ItemStack itemstack = list.get(i); - - list.set(i, ItemStack.b); - return itemstack; - } - - return ItemStack.b; - } - - @Override - public List getContents() { - return this.f.stream().flatMap(List::stream).collect(Collectors.toList()); - } - - @Override - public List getArmorContents() { - return this.armor; - } - - @Override - public void onOpen(CraftHumanEntity who) { - this.transaction.add(who); - } - - @Override - public void onClose(CraftHumanEntity who) { - this.transaction.remove(who); - } - - @Override - public List getViewers() { - return this.transaction; - } - - @Override - public InventoryHolder getOwner() { - return this.player.getBukkitEntity(); - } - - @Override - public Location getLocation() { - return this.player.getBukkitEntity().getLocation(); - } - - @Override - public ItemStack getItemInHand() { - return d(this.itemInHandIndex) ? this.items.get(this.itemInHandIndex) : ItemStack.b; - } - - private boolean isSimilarAndNotFull(ItemStack itemstack, ItemStack itemstack1) { - return !itemstack.isEmpty() && this.b(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); - } - - private boolean b(ItemStack itemstack, ItemStack itemstack1) { - return itemstack.getItem() == itemstack1.getItem() && ItemStack.equals(itemstack, itemstack1); - } - - @Override - public int canHold(ItemStack itemstack) { - int remains = itemstack.getCount(); - - for (int i = 0; i < this.items.size(); ++i) { - ItemStack itemstack1 = this.getItem(i); - if (itemstack1.isEmpty()) { - return itemstack.getCount(); - } - - if (!this.isSimilarAndNotFull(itemstack, itemstack1)) { - remains -= Math.min(itemstack1.getMaxStackSize(), this.getMaxStackSize()) - itemstack1.getCount(); - } - - if (remains <= 0) { - return itemstack.getCount(); - } - } - - ItemStack offhandItemStack = this.getItem(this.items.size() + this.armor.size()); - if (this.isSimilarAndNotFull(offhandItemStack, itemstack)) { - remains -= Math.min(offhandItemStack.getMaxStackSize(), this.getMaxStackSize()) - offhandItemStack.getCount(); - } - - return itemstack.getCount() - remains; - } - - @Override - public int getFirstEmptySlotIndex() { - for (int i = 0; i < this.items.size(); ++i) { - if (this.items.get(i).isEmpty()) { - return i; - } - } - - return -1; - } - - @Override - public void c(int i) { - this.itemInHandIndex = this.i(); - ItemStack itemstack = this.items.get(this.itemInHandIndex); - this.items.set(this.itemInHandIndex, this.items.get(i)); - this.items.set(i, itemstack); - } - - @Override - public int c(ItemStack itemstack) { - for (int i = 0; i < this.items.size(); ++i) { - ItemStack itemstack1 = this.items.get(i); - if (!this.items.get(i).isEmpty() && this.b(itemstack, this.items.get(i)) && !this.items.get(i).f() && !itemstack1.hasEnchantments() && !itemstack1.hasName()) { - return i; - } - } - - return -1; - } - - @Override - public int i() { - int i; - int j; - for (j = 0; j < 9; ++j) { - i = (this.itemInHandIndex + j) % 9; - if (this.items.get(i).isEmpty()) { - return i; - } - } - - for (j = 0; j < 9; ++j) { - i = (this.itemInHandIndex + j) % 9; - if (!this.items.get(i).hasEnchantments()) { - return i; - } - } - - return this.itemInHandIndex; - } - - @Override - public int a(Predicate predicate, int i, IInventory iinventory) { - byte b0 = 0; - boolean flag = i == 0; - int j = b0 + ContainerUtil.a(this, predicate, i - b0, flag); - j += ContainerUtil.a(iinventory, predicate, i - j, flag); - j += ContainerUtil.a(this.getCarried(), predicate, i - j, flag); - if (this.getCarried().isEmpty()) { - this.setCarried(ItemStack.b); - } - - return j; - } - - private int i(ItemStack itemstack) { - int i = this.firstPartial(itemstack); - if (i == -1) { - i = this.getFirstEmptySlotIndex(); - } - - return i == -1 ? itemstack.getCount() : this.d(i, itemstack); - } - - private int d(int i, ItemStack itemstack) { - Item item = itemstack.getItem(); - int j = itemstack.getCount(); - ItemStack itemstack1 = this.getItem(i); - if (itemstack1.isEmpty()) { - itemstack1 = new ItemStack(item, 0); - NBTTagCompound tag = itemstack.getTag(); - if (tag != null) { - itemstack1.setTag(tag.clone()); - } - - this.setItem(i, itemstack1); - } - - int k = j; - if (j > itemstack1.getMaxStackSize() - itemstack1.getCount()) { - k = itemstack1.getMaxStackSize() - itemstack1.getCount(); - } - - if (k > this.getMaxStackSize() - itemstack1.getCount()) { - k = this.getMaxStackSize() - itemstack1.getCount(); - } - - if (k != 0) { - j -= k; - itemstack1.add(k); - itemstack1.d(5); - } - return j; - } - - @Override - public int firstPartial(ItemStack itemstack) { - if (this.isSimilarAndNotFull(this.getItem(this.itemInHandIndex), itemstack)) { - return this.itemInHandIndex; - } else if (this.isSimilarAndNotFull(this.getItem(40), itemstack)) { - return 40; - } else { - for (int i = 0; i < this.items.size(); ++i) { - if (this.isSimilarAndNotFull(this.items.get(i), itemstack)) { - return i; - } - } - - return -1; - } - } - - @Override - public void j() { - - for (List itemStacks : this.f) { - for (int i = 0; i < itemStacks.size(); ++i) { - if (!itemStacks.get(i).isEmpty()) { - itemStacks.get(i).a(this.player.world, this.player, i, this.itemInHandIndex == i); - } - } - } - - } - - @Override - public boolean pickup(ItemStack itemstack) { - return this.c(-1, itemstack); - } - - @Override - public boolean c(int i, ItemStack itemstack) { - if (itemstack.isEmpty()) { - return false; - } else { - try { - if (itemstack.f()) { - if (i == -1) { - i = this.getFirstEmptySlotIndex(); - } - - if (i >= 0) { - this.items.set(i, itemstack.cloneItemStack()); - this.items.get(i).d(5); - itemstack.setCount(0); - return true; - } else if (this.player.abilities.canInstantlyBuild) { - itemstack.setCount(0); - return true; - } else { - return false; - } - } else { - int j; - do { - j = itemstack.getCount(); - if (i == -1) { - itemstack.setCount(this.i(itemstack)); - } else { - itemstack.setCount(this.d(i, itemstack)); - } - } while(!itemstack.isEmpty() && itemstack.getCount() < j); - - if (itemstack.getCount() == j && this.player.abilities.canInstantlyBuild) { - itemstack.setCount(0); - return true; - } else { - return itemstack.getCount() < j; - } - } - } catch (Throwable var6) { - CrashReport crashreport = CrashReport.a(var6, "Adding item to inventory"); - CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Item being added"); - crashreportsystemdetails.a("Item ID", Item.getId(itemstack.getItem())); - crashreportsystemdetails.a("Item data", itemstack.getDamage()); - crashreportsystemdetails.a("Item name", () -> itemstack.getName().getString()); - throw new ReportedException(crashreport); - } - } - } - - @Override - public void a(World world, ItemStack itemstack) { - if (!world.isClientSide) { - while(!itemstack.isEmpty()) { - int i = this.firstPartial(itemstack); - if (i == -1) { - i = this.getFirstEmptySlotIndex(); - } - - if (i == -1) { - this.player.drop(itemstack, false); - break; - } - - int j = itemstack.getMaxStackSize() - this.getItem(i).getCount(); - if (this.c(i, itemstack.cloneAndSubtract(j))) { - ((EntityPlayer)this.player).playerConnection.sendPacket(new PacketPlayOutSetSlot(-2, i, this.getItem(i))); - } - } - } - - } - - @Override - public void f(ItemStack itemstack) { - - for (List list : this.f) { - for (int i = 0; i < list.size(); ++i) { - if (list.get(i) == itemstack) { - list.set(i, ItemStack.b); - break; - } - } - } - } - - @Override - public float a(IBlockData iblockdata) { - return this.items.get(this.itemInHandIndex).a(iblockdata); - } - - @Override - public NBTTagList a(NBTTagList nbttaglist) { - NBTTagCompound nbttagcompound; - int i; - for (i = 0; i < this.items.size(); ++i) { - if (!this.items.get(i).isEmpty()) { - nbttagcompound = new NBTTagCompound(); - nbttagcompound.setByte("Slot", (byte) i); - this.items.get(i).save(nbttagcompound); - nbttaglist.add(nbttagcompound); - } - } - - for (i = 0; i < this.armor.size(); ++i) { - if (!this.armor.get(i).isEmpty()) { - nbttagcompound = new NBTTagCompound(); - nbttagcompound.setByte("Slot", (byte) (i + 100)); - this.armor.get(i).save(nbttagcompound); - nbttaglist.add(nbttagcompound); - } - } - - for (i = 0; i < this.extraSlots.size(); ++i) { - if (!this.extraSlots.get(i).isEmpty()) { - nbttagcompound = new NBTTagCompound(); - nbttagcompound.setByte("Slot", (byte) (i + 150)); - this.extraSlots.get(i).save(nbttagcompound); - nbttaglist.add(nbttagcompound); - } - } - - return nbttaglist; - } - - @Override - public void b(NBTTagList nbttaglist) { - this.items.clear(); - this.armor.clear(); - this.extraSlots.clear(); - - for(int i = 0; i < nbttaglist.size(); ++i) { - NBTTagCompound nbttagcompound = nbttaglist.getCompound(i); - int j = nbttagcompound.getByte("Slot") & 255; - ItemStack itemstack = ItemStack.a(nbttagcompound); - if (!itemstack.isEmpty()) { - if (j < this.items.size()) { - this.items.set(j, itemstack); - } else if (j >= 100 && j < this.armor.size() + 100) { - this.armor.set(j - 100, itemstack); - } else if (j >= 150 && j < this.extraSlots.size() + 150) { - this.extraSlots.set(j - 150, itemstack); - } - } - } - - } - - @Override - public boolean isEmpty() { - Iterator iterator = this.items.iterator(); - - ItemStack itemstack; - while (iterator.hasNext()) { - itemstack = iterator.next(); - if (!itemstack.isEmpty()) { - return false; - } - } - - iterator = this.armor.iterator(); - - while (iterator.hasNext()) { - itemstack = iterator.next(); - if (!itemstack.isEmpty()) { - return false; - } - } - - iterator = this.extraSlots.iterator(); - - while (iterator.hasNext()) { - itemstack = iterator.next(); - if (!itemstack.isEmpty()) { - return false; - } - } - - return true; - } - - @Nullable - @Override - public IChatBaseComponent getCustomName() { - return null; - } - - @Override - public void a(DamageSource damagesource, float f) { - if (f > 0.0F) { - f /= 4.0F; - if (f < 1.0F) { - f = 1.0F; - } - - for (int i = 0; i < this.armor.size(); ++i) { - ItemStack itemstack = this.armor.get(0); - int index = i; - if ((!damagesource.isFire() || !itemstack.getItem().u()) && itemstack.getItem() instanceof ItemArmor) { - itemstack.damage((int) f, this.player, (entityHuman) -> entityHuman.broadcastItemBreak(EnumItemSlot.a(EnumItemSlot.Function.ARMOR, index))); - } - } - } - } - - @Override - public void dropContents() { - for (List itemStacks : this.f) { - for (int i = 0; i < itemStacks.size(); ++i) { - ItemStack itemstack = itemStacks.get(i); - if (!itemstack.isEmpty()) { - itemStacks.set(i, ItemStack.b); - this.player.a(itemstack, true, false); - } - } - } - } - - @Override - public boolean h(ItemStack itemstack) { - return this.f.stream().flatMap(List::stream).anyMatch(itemStack1 -> !itemStack1.isEmpty() && itemStack1.doMaterialsMatch(itemstack)); - } - - @Override - public void a(PlayerInventory playerinventory) { - for (int i = 0; i < playerinventory.getSize(); ++i) { - this.setItem(i, playerinventory.getItem(i)); - } - - this.itemInHandIndex = playerinventory.itemInHandIndex; - } - - @Override - public void clear() { - this.f.forEach(List::clear); - } - - @Override - public void a(AutoRecipeStackManager autorecipestackmanager) { - for (ItemStack itemstack : this.items) { - autorecipestackmanager.a(itemstack); - } - } - -} diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index 2c06c72..613aa38 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -40,6 +40,7 @@ org.spigotmc provided 1.17.1-R0.1-SNAPSHOT + remapped-mojang openinvapi @@ -67,6 +68,38 @@ maven-compiler-plugin + + net.md-5 + specialsource-maven-plugin + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.17.1-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.17.1-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:1.17.1-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.17.1-R0.1-SNAPSHOT:jar:remapped-obf + + + + diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java index 672e890..514aa92 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java @@ -18,75 +18,102 @@ package com.lishid.openinv.internal.v1_17_R1; import com.lishid.openinv.OpenInv; import com.lishid.openinv.internal.IAnySilentContainer; +import com.lishid.openinv.util.ReflectionHelper; import java.lang.reflect.Field; +import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; -import net.minecraft.core.BlockPosition; -import net.minecraft.network.chat.ChatMessage; -import net.minecraft.network.chat.IChatBaseComponent; -import net.minecraft.server.level.EntityPlayer; -import net.minecraft.server.level.PlayerInteractManager; -import net.minecraft.world.ITileInventory; -import net.minecraft.world.InventoryLargeChest; -import net.minecraft.world.TileInventory; -import net.minecraft.world.entity.player.EntityHuman; -import net.minecraft.world.entity.player.PlayerInventory; -import net.minecraft.world.inventory.Container; -import net.minecraft.world.inventory.ContainerChest; -import net.minecraft.world.inventory.Containers; -import net.minecraft.world.inventory.InventoryEnderChest; -import net.minecraft.world.level.EnumGamemode; -import net.minecraft.world.level.World; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.CompoundContainer; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.monster.Shulker; +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.block.BarrelBlock; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.BlockBarrel; -import net.minecraft.world.level.block.BlockChest; -import net.minecraft.world.level.block.BlockChestTrapped; -import net.minecraft.world.level.block.BlockShulkerBox; -import net.minecraft.world.level.block.entity.TileEntity; -import net.minecraft.world.level.block.entity.TileEntityChest; -import net.minecraft.world.level.block.entity.TileEntityEnderChest; -import net.minecraft.world.level.block.entity.TileEntityLootable; -import net.minecraft.world.level.block.state.IBlockData; -import net.minecraft.world.level.block.state.properties.BlockPropertyChestType; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.DoubleBlockCombiner; +import net.minecraft.world.level.block.ShulkerBoxBlock; +import net.minecraft.world.level.block.TrappedChestBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Statistic; +import org.bukkit.block.ShulkerBox; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class AnySilentContainer implements IAnySilentContainer { - private Field playerInteractManagerGamemode; + private @Nullable Field serverPlayerGameModeGameType; public AnySilentContainer() { try { - this.playerInteractManagerGamemode = PlayerInteractManager.class.getDeclaredField("b"); - this.playerInteractManagerGamemode.setAccessible(true); - } catch (NoSuchFieldException | SecurityException e) { + try { + // IDE warns about field not existing, but SpecialSource does not remap strings used in reflection. + // The warning is not suppressed as a reminder that it must manually be checked on updates. + this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("b"); + this.serverPlayerGameModeGameType.setAccessible(true); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("ServerPlayerGameMode#gameModeForPlayer's obfuscated name has changed!"); + logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues"); + logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail."); + // N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break. + this.serverPlayerGameModeGameType = ReflectionHelper.grabFieldByType(ServerPlayerGameMode.class, GameType.class); + } + } catch (SecurityException e) { Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); - logger.warning("Unable to directly write player gamemode! SilentChest will fail."); - logger.log(Level.WARNING, "Error obtaining gamemode field", e); + logger.warning("Unable to directly write player game mode! SilentContainer will fail."); + logger.log(Level.WARNING, "Error obtaining GameType field", e); } } @Override - public boolean isShulkerIgnoreBoundingBox(org.bukkit.block.Block bukkitBlock) { - org.bukkit.World bukkitWorld = bukkitBlock.getWorld(); + public boolean isShulkerBlocked(ShulkerBox box) { + org.bukkit.World bukkitWorld = box.getWorld(); if (!(bukkitWorld instanceof CraftWorld)) { bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); } - if (!(bukkitWorld instanceof CraftWorld)) { + + if (!(bukkitWorld instanceof CraftWorld craftWorld)) { Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); OpenInv.getPlugin(OpenInv.class).getLogger().log(Level.WARNING, exception.getMessage(), exception); return false; } - final World world = ((CraftWorld) bukkitWorld).getHandle(); - final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); - // isLargeVoxelShape - return world.getType(blockPosition).d(); + final ServerLevel world = craftWorld.getHandle(); + final BlockPos blockPosition = new BlockPos(box.getX(), box.getY(), box.getZ()); + final BlockEntity tile = world.getBlockEntity(blockPosition); + + if (!(tile instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) + || shulkerBoxBlockEntity.getAnimationStatus() != ShulkerBoxBlockEntity.AnimationStatus.CLOSED) { + return false; + } + + BlockState blockState = world.getBlockState(blockPosition); + + // See net.minecraft.world.level.block.ShulkerBoxBlock#canOpen + AABB boundingBox = Shulker.getProgressDeltaAabb(blockState.getValue(ShulkerBoxBlock.FACING), 0.0F, 0.5F) + .move(blockPosition) + .deflate(1.0E-6D); + return !world.noCollision(boundingBox); } @Override @@ -102,128 +129,109 @@ public class AnySilentContainer implements IAnySilentContainer { return true; } - EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); - final World world = player.getWorld(); - final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); - final TileEntity tile = world.getTileEntity(blockPosition); + final ServerLevel level = player.getLevel(); + final BlockPos blockPos = new BlockPos(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + final BlockEntity blockEntity = level.getBlockEntity(blockPos); - if (tile == null) { + if (blockEntity == null) { return false; } - if (tile instanceof TileEntityEnderChest) { + if (blockEntity instanceof EnderChestBlockEntity enderChestTile) { // Anychest ender chest. See net.minecraft.world.level.block.BlockEnderChest - InventoryEnderChest enderChest = player.getEnderChest(); - enderChest.a((TileEntityEnderChest) tile); - player.openContainer(new TileInventory((containerCounter, playerInventory, ignored) -> { - Containers containers = PlayerDataManager.getContainers(enderChest.getSize()); - int rows = enderChest.getSize() / 9; - return new ContainerChest(containers, containerCounter, playerInventory, enderChest, rows); - }, new ChatMessage("container.enderchest"))); + PlayerEnderChestContainer enderChest = player.getEnderChestInventory(); + enderChest.setActiveChest(enderChestTile); + player.openMenu(new SimpleMenuProvider((containerCounter, playerInventory, ignored) -> { + MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); + int rows = enderChest.getContainerSize() / 9; + return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); + }, new TextComponent("container.enderchest"))); bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); return true; } - if (!(tile instanceof ITileInventory tileInventory)) { + if (!(blockEntity instanceof MenuProvider menuProvider)) { return false; } - IBlockData blockData = world.getType(blockPosition); - Block block = blockData.getBlock(); + BlockState blockState = level.getBlockState(blockPos); + Block block = blockState.getBlock(); - if (block instanceof BlockChest) { + if (block instanceof ChestBlock chestBlock) { - BlockPropertyChestType chestType = blockData.get(BlockChest.c); - - if (chestType != BlockPropertyChestType.a) { - - BlockPosition adjacentBlockPosition = blockPosition.shift(BlockChest.h(blockData)); - IBlockData adjacentBlockData = world.getType(adjacentBlockPosition); - - if (adjacentBlockData.getBlock() == block) { - - BlockPropertyChestType adjacentChestType = adjacentBlockData.get(BlockChest.c); - - if (adjacentChestType != BlockPropertyChestType.a && chestType != adjacentChestType - && adjacentBlockData.get(BlockChest.b) == blockData.get(BlockChest.b)) { - - TileEntity adjacentTile = world.getTileEntity(adjacentBlockPosition); - - if (adjacentTile instanceof TileEntityChest && tileInventory instanceof TileEntityChest) { - TileEntityChest rightChest = chestType == BlockPropertyChestType.c ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile; - TileEntityChest leftChest = chestType == BlockPropertyChestType.c ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory); - - if (silentchest && (rightChest.g != null || leftChest.g != null)) { - OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); - return false; - } - - tileInventory = new ITileInventory() { - public Container createMenu(int containerCounter, PlayerInventory playerInventory, EntityHuman entityHuman) { - leftChest.d(playerInventory.l); - rightChest.d(playerInventory.l); - return ContainerChest.b(containerCounter, playerInventory, new InventoryLargeChest(rightChest, leftChest)); - } - - public IChatBaseComponent getScoreboardDisplayName() { - if (leftChest.hasCustomName()) { - return leftChest.getScoreboardDisplayName(); - } - if (rightChest.hasCustomName()) { - return rightChest.getScoreboardDisplayName(); - } - return new ChatMessage("container.chestDouble"); - } - }; + // boolean flag: check if chest is blocked + Optional menuOptional = chestBlock.combine(blockState, level, blockPos, false).apply( + // Combiner is a copy of private ChestBlock.MENU_PROVIDER_COMBINER + new DoubleBlockCombiner.Combiner>() { + @Override + public Optional acceptDouble(ChestBlockEntity localChest1, ChestBlockEntity localChest2) { + CompoundContainer doubleChest = new CompoundContainer(localChest1, localChest2); + return Optional.of(new ChestBlock.DoubleInventory(localChest1, localChest2, doubleChest)); } - } - } + + @Override + public Optional acceptSingle(ChestBlockEntity localChest) { + return Optional.of(localChest); + } + + @Override + public Optional acceptNone() { + return Optional.empty(); + } + }); + + if (menuOptional.isEmpty()) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; } - if (block instanceof BlockChestTrapped) { + menuProvider = menuOptional.get(); + + if (block instanceof TrappedChestBlock) { bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); } else { bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED); } } - if (block instanceof BlockShulkerBox) { + if (block instanceof ShulkerBoxBlock) { bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED); } - if (block instanceof BlockBarrel) { + if (block instanceof BarrelBlock) { bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL); } // AnyChest only - SilentChest not active, container unsupported, or unnecessary. - if (!silentchest || player.d.getGameMode() == EnumGamemode.d) { - player.openContainer(tileInventory); + if (!silentchest || player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) { + player.openMenu(menuProvider); return true; } - // SilentChest requires access to setting players' gamemode directly. - if (this.playerInteractManagerGamemode == null) { + // SilentChest requires access to setting players' game mode directly. + if (this.serverPlayerGameModeGameType == null) { return false; } - if (tile instanceof TileEntityLootable lootable) { - if (lootable.g != null) { + if (blockEntity instanceof RandomizableContainerBlockEntity lootable) { + if (lootable.lootTable != null) { OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); return false; } } - EnumGamemode gamemode = player.d.getGameMode(); - this.forceGameMode(player, EnumGamemode.d); - player.openContainer(tileInventory); - this.forceGameMode(player, gamemode); + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); + player.openMenu(menuProvider); + this.forceGameType(player, gameType); return true; } @Override public void deactivateContainer(@NotNull final Player bukkitPlayer) { - if (this.playerInteractManagerGamemode == null) { + if (this.serverPlayerGameModeGameType == null) { return; } @@ -238,29 +246,29 @@ public class AnySilentContainer implements IAnySilentContainer { return; } - EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); // Force game mode change without informing plugins or players. - EnumGamemode gamemode = player.d.getGameMode(); - this.forceGameMode(player, EnumGamemode.d); + // Regular game mode set calls GameModeChangeEvent and is cancellable. + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); - // See EntityPlayer#closeInventory - can't call or we'd recursively deactivate. - player.bV.b(player); - player.bU.a(player.bV); - player.bV = player.bU; + // Close container - note that this is very different from ServerPlayer#closeContainer! + // Triggering event must not be re-called or we'll enter an infinite loop. + player.doCloseContainer(); // Revert forced game mode. - this.forceGameMode(player, gamemode); + this.forceGameType(player, gameType); } - private void forceGameMode(final EntityPlayer player, final EnumGamemode gameMode) { - if (this.playerInteractManagerGamemode == null) { + private void forceGameType(final ServerPlayer player, final GameType gameMode) { + if (this.serverPlayerGameModeGameType == null) { // No need to warn repeatedly, error on startup and lack of function should be enough. return; } try { - this.playerInteractManagerGamemode.setAccessible(true); - this.playerInteractManagerGamemode.set(player.d, gameMode); + this.serverPlayerGameModeGameType.setAccessible(true); + this.serverPlayerGameModeGameType.set(player.gameMode, gameMode); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java index cf420ea..c4c17e8 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java @@ -17,25 +17,25 @@ package com.lishid.openinv.internal.v1_17_R1; import java.io.File; -import java.io.FileOutputStream; -import net.minecraft.nbt.NBTCompressedStreamTools; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.server.level.EntityPlayer; -import net.minecraft.world.level.storage.WorldNBTStorage; +import net.minecraft.Util; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.storage.PlayerDataStorage; import org.apache.logging.log4j.LogManager; import org.bukkit.craftbukkit.v1_17_R1.CraftServer; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; public class OpenPlayer extends CraftPlayer { - public OpenPlayer(CraftServer server, EntityPlayer entity) { + public OpenPlayer(CraftServer server, ServerPlayer entity) { super(server, entity); } @Override public void loadData() { // See CraftPlayer#loadData - NBTTagCompound loaded = this.server.getHandle().r.load(this.getHandle()); + CompoundTag loaded = this.server.getHandle().playerIo.load(this.getHandle()); if (loaded != null) { readExtraData(loaded); } @@ -43,35 +43,31 @@ public class OpenPlayer extends CraftPlayer { @Override public void saveData() { - EntityPlayer player = this.getHandle(); - // See net.minecraft.world.level.storage.WorldNBTStorage#save(EntityHuman) + ServerPlayer player = this.getHandle(); + // See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman) try { - WorldNBTStorage worldNBTStorage = player.c.getPlayerList().r; + PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; - NBTTagCompound playerData = player.save(new NBTTagCompound()); + CompoundTag playerData = player.saveWithoutId(new CompoundTag()); setExtraData(playerData); if (!isOnline()) { // Special case: save old vehicle data - NBTTagCompound oldData = worldNBTStorage.load(player); + CompoundTag oldData = worldNBTStorage.load(player); - if (oldData != null && oldData.hasKeyOfType("RootVehicle", 10)) { + if (oldData != null && oldData.contains("RootVehicle", 10)) { // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound) - playerData.set("RootVehicle", oldData.getCompound("RootVehicle")); + playerData.put("RootVehicle", oldData.getCompound("RootVehicle")); } } - File file = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat.tmp"); - File file1 = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat"); - - NBTCompressedStreamTools.a(playerData, new FileOutputStream(file)); - - if (file1.exists() && !file1.delete() || !file.renameTo(file1)) { - LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString()); - } - + File file = File.createTempFile(player.getStringUUID() + "-", ".dat", worldNBTStorage.getPlayerDir()); + NbtIo.writeCompressed(playerData, file); + File file1 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat"); + File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); + Util.safeReplaceFile(file1, file, file2); } catch (Exception e) { - LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString()); + LogManager.getLogger().warn("Failed to save player data for {}", player.getName().getString()); } } diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java index 4071eec..df7697e 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java @@ -22,17 +22,16 @@ import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.internal.OpenInventoryView; import com.mojang.authlib.GameProfile; import java.lang.reflect.Field; -import java.util.logging.Level; import java.util.logging.Logger; -import net.minecraft.network.chat.ChatComponentText; -import net.minecraft.network.protocol.game.PacketPlayOutOpenWindow; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.EntityPlayer; -import net.minecraft.server.level.WorldServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; -import net.minecraft.world.inventory.Container; -import net.minecraft.world.inventory.Containers; -import net.minecraft.world.level.World; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.Server; @@ -55,21 +54,21 @@ public class PlayerDataManager implements IPlayerDataManager { } catch (NoSuchFieldException e) { Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); logger.warning("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded."); - logger.log(Level.WARNING, e.getMessage(), e); + logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); bukkitEntity = null; } } - public static @NotNull EntityPlayer getHandle(final Player player) { + public static @NotNull ServerPlayer getHandle(final Player player) { if (player instanceof CraftPlayer) { return ((CraftPlayer) player).getHandle(); } Server server = player.getServer(); - EntityPlayer nmsPlayer = null; + ServerPlayer nmsPlayer = null; if (server instanceof CraftServer) { - nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getName()); + nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getUniqueId()); } if (nmsPlayer == null) { @@ -92,13 +91,13 @@ public class PlayerDataManager implements IPlayerDataManager { GameProfile profile = new GameProfile(offline.getUniqueId(), offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - WorldServer worldServer = server.getWorldServer(World.f); + ServerLevel worldServer = server.getLevel(Level.OVERWORLD); if (worldServer == null) { return null; } - EntityPlayer entity = new EntityPlayer(server, worldServer, profile); + ServerPlayer entity = new ServerPlayer(server, worldServer, profile); try { injectPlayer(entity); @@ -116,21 +115,21 @@ public class PlayerDataManager implements IPlayerDataManager { return target; } - void injectPlayer(EntityPlayer player) throws IllegalAccessException { + void injectPlayer(ServerPlayer player) throws IllegalAccessException { if (bukkitEntity == null) { return; } bukkitEntity.setAccessible(true); - bukkitEntity.set(player, new OpenPlayer(player.c.server, player)); + bukkitEntity.set(player, new OpenPlayer(player.server.server, player)); } @NotNull @Override public Player inject(@NotNull Player player) { try { - EntityPlayer nmsPlayer = getHandle(player); + ServerPlayer nmsPlayer = getHandle(player); injectPlayer(nmsPlayer); return nmsPlayer.getBukkitEntity(); } catch (IllegalAccessException e) { @@ -143,9 +142,9 @@ public class PlayerDataManager implements IPlayerDataManager { @Override public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) { - EntityPlayer nmsPlayer = getHandle(player); + ServerPlayer nmsPlayer = getHandle(player); - if (nmsPlayer.b == null) { + if (nmsPlayer.connection == null) { return null; } @@ -155,23 +154,23 @@ public class PlayerDataManager implements IPlayerDataManager { return player.openInventory(inventory.getBukkitInventory()); } - Container container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { + AbstractContainerMenu container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { @Override - public Containers getType() { + public MenuType getType() { return getContainers(inventory.getBukkitInventory().getSize()); } }; - container.setTitle(new ChatComponentText(view.getTitle())); + container.setTitle(new TextComponent(view.getTitle())); container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); if (container == null) { return null; } - nmsPlayer.b.sendPacket(new PacketPlayOutOpenWindow(container.j, container.getType(), - new ChatComponentText(container.getBukkitView().getTitle()))); - nmsPlayer.bV = container; + nmsPlayer.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), + new TextComponent(container.getBukkitView().getTitle()))); + nmsPlayer.containerMenu = container; nmsPlayer.initMenu(container); return container.getBukkitView(); @@ -188,15 +187,15 @@ public class PlayerDataManager implements IPlayerDataManager { } } - static @NotNull Containers getContainers(int inventorySize) { + static @NotNull MenuType getContainers(int inventorySize) { return switch (inventorySize) { - case 9 -> Containers.a; - case 18 -> Containers.b; - case 36 -> Containers.d; // PLAYER - case 41, 45 -> Containers.e; - case 54 -> Containers.f; - default -> Containers.c; // 9x3 + case 9 -> MenuType.GENERIC_9x1; + case 18 -> MenuType.GENERIC_9x2; + case 36 -> MenuType.GENERIC_9x4; // PLAYER + case 41, 45 -> MenuType.GENERIC_9x5; + case 54 -> MenuType.GENERIC_9x6; + default -> MenuType.GENERIC_9x3; // Default 27-slot inventory }; } diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java index 6a6a592..fed9b56 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java @@ -21,38 +21,38 @@ import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; import net.minecraft.core.NonNullList; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.server.level.EntityPlayer; -import net.minecraft.world.ContainerUtil; -import net.minecraft.world.IInventoryListener; -import net.minecraft.world.entity.player.AutoRecipeStackManager; -import net.minecraft.world.entity.player.EntityHuman; -import net.minecraft.world.inventory.InventoryEnderChest; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.ContainerListener; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.inventory.PlayerEnderChestContainer; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.TileEntityEnderChest; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftHumanEntity; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventory; import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEnderChest { +public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpecialEnderChest { private final CraftInventory inventory; - private EntityPlayer owner; - private NonNullList c; + private ServerPlayer owner; + private NonNullList items; private boolean playerOnline; - public SpecialEnderChest(final Player player, final Boolean online) { + public SpecialEnderChest(final org.bukkit.entity.Player player, final Boolean online) { super(PlayerDataManager.getHandle(player)); this.inventory = new CraftInventory(this); this.owner = PlayerDataManager.getHandle(player); this.playerOnline = online; - this.c = this.owner.getEnderChest().c; + this.items = this.owner.getEnderChestInventory().items; } @Override @@ -71,15 +71,15 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn } @Override - public void setPlayerOnline(@NotNull final Player player) { + public void setPlayerOnline(@NotNull final org.bukkit.entity.Player player) { if (!this.playerOnline) { try { this.owner = PlayerDataManager.getHandle(player); - InventoryEnderChest enderChest = owner.getEnderChest(); - for (int i = 0; i < enderChest.getSize(); ++i) { - enderChest.setItem(i, this.c.get(i)); + PlayerEnderChestContainer enderChest = owner.getEnderChestInventory(); + for (int i = 0; i < enderChest.getContainerSize(); ++i) { + enderChest.setItem(i, this.items.get(i)); } - this.c = enderChest.c; + this.items = enderChest.items; enderChest.transaction.addAll(this.transaction); } catch (Exception ignored) {} this.playerOnline = true; @@ -87,65 +87,63 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn } @Override - public @NotNull Player getPlayer() { + public @NotNull org.bukkit.entity.Player getPlayer() { return owner.getBukkitEntity(); } @Override - public void update() { - this.owner.getEnderChest().update(); + public void setChanged() { + this.owner.getEnderChestInventory().setChanged(); } @Override public List getContents() { - return this.c; + return this.items; } @Override public void onOpen(CraftHumanEntity who) { - super.onOpen(who); - this.owner.getEnderChest().onOpen(who); + this.owner.getEnderChestInventory().onOpen(who); } @Override public void onClose(CraftHumanEntity who) { - super.onClose(who); - this.owner.getEnderChest().onClose(who); + this.owner.getEnderChestInventory().onClose(who); } @Override public List getViewers() { - return this.owner.getEnderChest().getViewers(); + return this.owner.getEnderChestInventory().getViewers(); } @Override - public boolean a(EntityHuman entityhuman) { + public boolean stillValid(Player player) { return true; } @Override - public void a(TileEntityEnderChest tileentityenderchest) { - this.owner.getEnderChest().a(tileentityenderchest); + public void setActiveChest(EnderChestBlockEntity enderChest) { + this.owner.getEnderChestInventory().setActiveChest(enderChest); } @Override - public boolean b(TileEntityEnderChest tileentityenderchest) { - return this.owner.getEnderChest().b(tileentityenderchest); + public boolean isActiveChest(EnderChestBlockEntity enderChest) { + return this.owner.getEnderChestInventory().isActiveChest(enderChest); } @Override public int getMaxStackSize() { - return this.owner.getEnderChest().getMaxStackSize(); + return this.owner.getEnderChestInventory().getMaxStackSize(); } @Override public void setMaxStackSize(int i) { - this.owner.getEnderChest().setMaxStackSize(i); + this.owner.getEnderChestInventory().setMaxStackSize(i); } @Override public InventoryHolder getOwner() { - return this.owner.getEnderChest().getOwner(); + return this.owner.getEnderChestInventory().getOwner(); } @Override @@ -154,167 +152,46 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn } @Override - public void a(IInventoryListener iinventorylistener) { - this.owner.getEnderChest().a(iinventorylistener); + public void addListener(ContainerListener listener) { + this.owner.getEnderChestInventory().addListener(listener); } @Override - public void b(IInventoryListener iinventorylistener) { - this.owner.getEnderChest().b(iinventorylistener); + public void removeListener(ContainerListener listener) { + this.owner.getEnderChestInventory().removeListener(listener); } @Override public ItemStack getItem(int i) { - return i >= 0 && i < this.c.size() ? this.c.get(i) : ItemStack.b; + return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.EMPTY; } @Override - public ItemStack splitStack(int i, int j) { - ItemStack itemstack = ContainerUtil.a(this.c, i, j); + public ItemStack removeItem(int i, int j) { + ItemStack itemstack = ContainerHelper.removeItem(this.items, i, j); if (!itemstack.isEmpty()) { - this.update(); + this.setChanged(); } return itemstack; } @Override - public ItemStack a(ItemStack itemstack) { - ItemStack itemstack1 = itemstack.cloneItemStack(); - this.d(itemstack1); - if (itemstack1.isEmpty()) { - return ItemStack.b; + public ItemStack addItem(ItemStack itemstack) { + ItemStack localItem = itemstack.copy(); + this.moveItemToOccupiedSlotsWithSameType(localItem); + if (localItem.isEmpty()) { + return ItemStack.EMPTY; } else { - this.c(itemstack1); - return itemstack1.isEmpty() ? ItemStack.b : itemstack1; - } - } - - private void c(ItemStack itemstack) { - for(int i = 0; i < this.getSize(); ++i) { - ItemStack itemstack1 = this.getItem(i); - if (itemstack1.isEmpty()) { - this.setItem(i, itemstack.cloneItemStack()); - itemstack.setCount(0); - return; - } - } - } - - private void d(ItemStack itemstack) { - for(int i = 0; i < this.getSize(); ++i) { - ItemStack itemstack1 = this.getItem(i); - if (ItemStack.e(itemstack1, itemstack)) { - this.a(itemstack, itemstack1); - if (itemstack.isEmpty()) { - return; - } - } - } - } - - private void a(ItemStack itemstack, ItemStack itemstack1) { - int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize()); - int j = Math.min(itemstack.getCount(), i - itemstack1.getCount()); - if (j > 0) { - itemstack1.add(j); - itemstack.subtract(j); - this.update(); + this.moveItemToEmptySlots(localItem); + return localItem.isEmpty() ? ItemStack.EMPTY : localItem; } } @Override - public ItemStack splitWithoutUpdate(int i) { - ItemStack itemstack = this.c.get(i); - if (itemstack.isEmpty()) { - return ItemStack.b; - } else { - this.c.set(i, ItemStack.b); - return itemstack; - } - } - - @Override - public void setItem(int i, ItemStack itemstack) { - this.c.set(i, itemstack); - if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { - itemstack.setCount(this.getMaxStackSize()); - } - - this.update(); - } - - @Override - public int getSize() { - return this.owner.getEnderChest().getSize(); - } - - @Override - public boolean isEmpty() { - return this.c.stream().allMatch(ItemStack::isEmpty); - } - - @Override - public void startOpen(EntityHuman entityhuman) { - } - - @Override - public void closeContainer(EntityHuman entityhuman) { - } - - @Override - public boolean b(int i, ItemStack itemstack) { - return true; - } - - @Override - public void clear() { - this.c.clear(); - this.update(); - } - - @Override - public void a(AutoRecipeStackManager autorecipestackmanager) { - for (ItemStack itemstack : this.c) { - autorecipestackmanager.b(itemstack); - } - - } - - @Override - public List f() { - List list = this.c.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList()); - this.clear(); - return list; - } - - @Override - public ItemStack a(Item item, int i) { - ItemStack itemstack = new ItemStack(item, 0); - - for(int j = this.getSize() - 1; j >= 0; --j) { - ItemStack itemstack1 = this.getItem(j); - if (itemstack1.getItem().equals(item)) { - int k = i - itemstack.getCount(); - ItemStack itemstack2 = itemstack1.cloneAndSubtract(k); - itemstack.add(itemstack2.getCount()); - if (itemstack.getCount() == i) { - break; - } - } - } - - if (!itemstack.isEmpty()) { - this.update(); - } - - return itemstack; - } - - @Override - public boolean b(ItemStack itemStack) { - for (ItemStack itemStack1 : this.c) { - if (itemStack1.isEmpty() || ItemStack.e(itemStack1, itemStack) && itemStack1.getCount() < itemStack1.getMaxStackSize()) { + public boolean canAddItem(ItemStack itemstack) { + for (ItemStack itemstack1 : this.items) { + if (itemstack1.isEmpty() || ItemStack.isSameItemSameTags(itemstack1, itemstack) && itemstack1.getCount() < itemstack1.getMaxStackSize()) { return true; } } @@ -322,17 +199,143 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn return false; } - @Override - public String toString() { - return this.c.stream().filter((itemStack) -> !itemStack.isEmpty()).collect(Collectors.toList()).toString(); + private void moveItemToEmptySlots(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (localItem.isEmpty()) { + this.setItem(i, itemstack.copy()); + itemstack.setCount(0); + return; + } + } + } + + private void moveItemToOccupiedSlotsWithSameType(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (ItemStack.isSameItemSameTags(localItem, itemstack)) { + this.moveItemsBetweenStacks(itemstack, localItem); + if (itemstack.isEmpty()) { + return; + } + } + } + } + + private void moveItemsBetweenStacks(ItemStack itemstack, ItemStack itemstack1) { + int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize()); + int j = Math.min(itemstack.getCount(), i - itemstack1.getCount()); + if (j > 0) { + itemstack1.grow(j); + itemstack.shrink(j); + this.setChanged(); + } } @Override - public void a(NBTTagList nbttaglist) { - for(int i = 0; i < nbttaglist.size(); ++i) { - ItemStack itemstack = ItemStack.a(nbttaglist.getCompound(i)); - if (!itemstack.isEmpty()) { - this.a(itemstack); + public ItemStack removeItemNoUpdate(int i) { + ItemStack itemstack = this.items.get(i); + if (itemstack.isEmpty()) { + return ItemStack.EMPTY; + } else { + this.items.set(i, ItemStack.EMPTY); + return itemstack; + } + } + + @Override + public void setItem(int i, ItemStack itemstack) { + this.items.set(i, itemstack); + if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { + itemstack.setCount(this.getMaxStackSize()); + } + + this.setChanged(); + } + + @Override + public int getContainerSize() { + return this.owner.getEnderChestInventory().getContainerSize(); + } + + @Override + public boolean isEmpty() { + return this.items.stream().allMatch(ItemStack::isEmpty); + } + + @Override + public void startOpen(Player player) { + } + + @Override + public void stopOpen(Player player) { + } + + @Override + public boolean canPlaceItem(int i, ItemStack itemstack) { + return true; + } + + @Override + public void clearContent() { + this.items.clear(); + this.setChanged(); + } + + @Override + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountStack(itemstack); + } + + } + + @Override + public List removeAllItems() { + List list = this.items.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList()); + this.clearContent(); + return list; + } + + @Override + public ItemStack removeItemType(Item item, int i) { + ItemStack itemstack = new ItemStack(item, 0); + + for(int j = this.getContainerSize() - 1; j >= 0; --j) { + ItemStack localItem = this.getItem(j); + if (localItem.getItem().equals(item)) { + int k = i - itemstack.getCount(); + ItemStack splitItem = localItem.split(k); + itemstack.grow(splitItem.getCount()); + if (itemstack.getCount() == i) { + break; + } + } + } + + if (!itemstack.isEmpty()) { + this.setChanged(); + } + + return itemstack; + } + + @Override + public String toString() { + return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).collect(Collectors.toList()).toString(); + } + + @Override + public void fromTag(ListTag listTag) { + for (int i = 0; i < this.getContainerSize(); ++i) { + this.setItem(i, ItemStack.EMPTY); + } + + for (int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + if (j < this.getContainerSize()) { + this.setItem(j, ItemStack.of(compoundTag)); } } diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java index 0cf6972..8b2f24a 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java @@ -20,134 +20,128 @@ import com.google.common.collect.ImmutableList; import com.lishid.openinv.internal.ISpecialPlayerInventory; import java.util.Collection; import java.util.List; -import java.util.Objects; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import net.minecraft.CrashReport; -import net.minecraft.CrashReportSystemDetails; +import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; import net.minecraft.core.NonNullList; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.network.chat.ChatMessage; -import net.minecraft.network.chat.IChatBaseComponent; -import net.minecraft.network.protocol.game.PacketPlayOutSetSlot; -import net.minecraft.server.level.EntityPlayer; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.Tag; -import net.minecraft.world.ContainerUtil; -import net.minecraft.world.IInventory; +import net.minecraft.world.Container; +import net.minecraft.world.ContainerHelper; import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EnumItemSlot; -import net.minecraft.world.entity.player.AutoRecipeStackManager; -import net.minecraft.world.entity.player.EntityHuman; -import net.minecraft.world.entity.player.PlayerInventory; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemArmor; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.IBlockData; +import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftHumanEntity; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventory; import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory { +public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerInventory { private final CraftInventory inventory; private boolean playerOnline; - private EntityHuman l; - private NonNullList h; - private NonNullList i; - private NonNullList j; - private List> n; + private Player player; + private NonNullList items; + private NonNullList armor; + private NonNullList offhand; + private List> compartments; - public SpecialPlayerInventory(final Player bukkitPlayer, final Boolean online) { + public SpecialPlayerInventory(@NotNull org.bukkit.entity.Player bukkitPlayer, @NotNull Boolean online) { super(PlayerDataManager.getHandle(bukkitPlayer)); this.inventory = new CraftInventory(this); this.playerOnline = online; - this.l = super.l; - this.h = this.l.getInventory().h; - this.i = this.l.getInventory().i; - this.j = this.l.getInventory().j; - this.n = ImmutableList.of(this.h, this.i, this.j); + this.player = super.player; + this.selected = player.getInventory().selected; + this.items = this.player.getInventory().items; + this.armor = this.player.getInventory().armor; + this.offhand = this.player.getInventory().offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); } @Override - public void setPlayerOnline(@NotNull final Player player) { + public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) { if (!this.playerOnline) { - EntityPlayer entityPlayer = PlayerDataManager.getHandle(player); + Player entityPlayer = PlayerDataManager.getHandle(player); entityPlayer.getInventory().transaction.addAll(this.transaction); - this.l = entityPlayer; - for (int i = 0; i < getSize(); ++i) { - this.l.getInventory().setItem(i, getRawItem(i)); + this.player = entityPlayer; + for (int i = 0; i < getContainerSize(); ++i) { + this.player.getInventory().setItem(i, getRawItem(i)); } - this.l.getInventory().k = this.k; - this.h = this.l.getInventory().h; - this.i = this.l.getInventory().i; - this.j = this.l.getInventory().j; - this.n = ImmutableList.of(this.h, this.i, this.j); + this.player.getInventory().selected = this.selected; + this.items = this.player.getInventory().items; + this.armor = this.player.getInventory().armor; + this.offhand = this.player.getInventory().offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); this.playerOnline = true; } } - @Override - public boolean a(final EntityHuman entityhuman) { - return true; - } - @Override public @NotNull CraftInventory getBukkitInventory() { return this.inventory; } @Override - public ItemStack getItem(int i) { - List list = this.h; - - if (i >= list.size()) { - i -= list.size(); - list = this.i; - } else { - i = this.getReversedItemSlotNum(i); - } - - if (i >= list.size()) { - i -= list.size(); - list = this.j; - } else if (list == this.i) { - i = this.getReversedArmorSlotNum(i); - } - - if (i >= list.size()) { - return ItemStack.b; - } - - return list.get(i); - } - - private ItemStack getRawItem(int i) { - NonNullList list = null; - for (NonNullList next : this.n) { - if (i < next.size()) { - list = next; - break; - } - i -= next.size(); - } - - return list == null ? ItemStack.b : list.get(i); + public void setPlayerOffline() { + this.playerOnline = false; } @Override - public IChatBaseComponent getDisplayName() { - return new ChatMessage(this.l.getName()); + public boolean isInUse() { + return !this.getViewers().isEmpty(); } @Override - public boolean hasCustomName() { - return false; + public @NotNull HumanEntity getPlayer() { + return this.player.getBukkitEntity(); + } + + private @NotNull ItemStack getRawItem(int i) { + return super.getItem(i); + } + + private void setRawItem(int i, @NotNull ItemStack itemStack) { + super.setItem(i, itemStack); + } + + private static record IndexedCompartment(@Nullable NonNullList compartment, int index) {} + + private @NotNull SpecialPlayerInventory.IndexedCompartment getIndexedContent(int index) { + if (index < items.size()) { + return new IndexedCompartment(items, getReversedItemSlotNum(index)); + } + + index -= items.size(); + + if (index < armor.size()) { + return new IndexedCompartment(armor, getReversedArmorSlotNum(index)); + } + + index -= armor.size(); + + if (index < offhand.size()) { + return new IndexedCompartment(offhand, index); + } + + index -= offhand.size(); + + return new IndexedCompartment(null, index); } private int getReversedArmorSlotNum(final int i) { @@ -173,173 +167,81 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP return i + 9; } - @Override - public int getSize() { - return 45; - } - - @Override - public boolean isInUse() { - return !this.getViewers().isEmpty(); - } - - @Override - public void setItem(int i, final ItemStack itemstack) { - List list = this.h; - - if (i >= list.size()) { - i -= list.size(); - list = this.i; - } else { - i = this.getReversedItemSlotNum(i); - } - - if (i >= list.size()) { - i -= list.size(); - list = this.j; - } else if (list == this.i) { - i = this.getReversedArmorSlotNum(i); - } - - if (i >= list.size()) { - this.l.drop(itemstack, true); - return; - } - - list.set(i, itemstack); - } - - @Override - public void setPlayerOffline() { - this.playerOnline = false; - } - - @Override - public @NotNull HumanEntity getPlayer() { - return this.l.getBukkitEntity(); - } - - @Override - public ItemStack splitStack(int i, final int j) { - List list = this.h; - - if (i >= list.size()) { - i -= list.size(); - list = this.i; - } else { - i = this.getReversedItemSlotNum(i); - } - - if (i >= list.size()) { - i -= list.size(); - list = this.j; - } else if (list == this.i) { - i = this.getReversedArmorSlotNum(i); - } - - if (i >= list.size()) { - return ItemStack.b; - } - - return list.get(i).isEmpty() ? ItemStack.b : ContainerUtil.a(list, i, j); - } - - @Override - public ItemStack splitWithoutUpdate(int i) { - List list = this.h; - - if (i >= list.size()) { - i -= list.size(); - list = this.i; - } else { - i = this.getReversedItemSlotNum(i); - } - - if (i >= list.size()) { - i -= list.size(); - list = this.j; - } else if (list == this.i) { - i = this.getReversedArmorSlotNum(i); - } - - if (i >= list.size()) { - return ItemStack.b; - } - - if (!list.get(i).isEmpty()) { - ItemStack itemstack = list.get(i); - - list.set(i, ItemStack.b); - return itemstack; - } - - return ItemStack.b; - } - - @Override - public List getContents() { - return this.n.stream().flatMap(Collection::stream).collect(Collectors.toList()); - } - - @Override - public boolean isEmpty() { - return this.n.stream().flatMap(Collection::stream).allMatch(ItemStack::isEmpty); + private boolean contains(Predicate predicate) { + return this.compartments.stream().flatMap(NonNullList::stream).anyMatch(predicate); } @Override public List getArmorContents() { - return this.i; + return this.armor; } @Override public void onOpen(CraftHumanEntity who) { - this.transaction.add(who); - this.l.getInventory().transaction.add(who); + this.player.getInventory().onOpen(who); } @Override public void onClose(CraftHumanEntity who) { - this.transaction.remove(who); - this.l.getInventory().transaction.remove(who); + this.player.getInventory().onClose(who); } @Override public List getViewers() { - return this.transaction; + return this.player.getInventory().getViewers(); } @Override public InventoryHolder getOwner() { - return this.l.getBukkitEntity(); + return this.player.getBukkitEntity(); } - public Location getLocation() { - return this.l.getBukkitEntity().getLocation(); - } - - /* Below this point largely just copied out of NMS to redirect to our overridden variables. */ - @Override - public ItemStack getItemInHand() { - return d(this.k) ? this.h.get(this.k) : ItemStack.b; + public int getMaxStackSize() { + return this.player.getInventory().getMaxStackSize(); } - private boolean isSimilarAndNotFull(ItemStack itemstack, ItemStack itemstack1) { - return !itemstack.isEmpty() && ItemStack.e(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); + @Override + public void setMaxStackSize(int size) { + this.player.getInventory().setMaxStackSize(size); + } + + @Override + public Location getLocation() { + return this.player.getBukkitEntity().getLocation(); + } + + @Override + public boolean hasCustomName() { + return false; + } + + @Override + public List getContents() { + return this.compartments.stream().flatMap(Collection::stream).collect(Collectors.toList()); + } + + @Override + public ItemStack getSelected() { + return isHotbarSlot(this.selected) ? this.items.get(this.selected) : ItemStack.EMPTY; + } + + private boolean hasRemainingSpaceForItem(ItemStack itemstack, ItemStack itemstack1) { + return !itemstack.isEmpty() && ItemStack.isSameItemSameTags(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); } @Override public int canHold(ItemStack itemstack) { int remains = itemstack.getCount(); - for(int i = 0; i < this.h.size(); ++i) { - ItemStack itemstack1 = this.getItem(i); + for (int i = 0; i < this.items.size(); ++i) { + ItemStack itemstack1 = this.getRawItem(i); if (itemstack1.isEmpty()) { return itemstack.getCount(); } - if (this.isSimilarAndNotFull(itemstack1, itemstack)) { - remains -= (Math.min(itemstack1.getMaxStackSize(), this.getMaxStackSize())) - itemstack1.getCount(); + if (this.hasRemainingSpaceForItem(itemstack1, itemstack)) { + remains -= (itemstack1.getMaxStackSize() < this.getMaxStackSize() ? itemstack1.getMaxStackSize() : this.getMaxStackSize()) - itemstack1.getCount(); } if (remains <= 0) { @@ -347,18 +249,18 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } } - ItemStack offhandItemStack = this.getItem(this.h.size() + this.i.size()); - if (this.isSimilarAndNotFull(offhandItemStack, itemstack)) { - remains -= (Math.min(offhandItemStack.getMaxStackSize(), this.getMaxStackSize())) - offhandItemStack.getCount(); + ItemStack offhandItemStack = this.getRawItem(this.items.size() + this.armor.size()); + if (this.hasRemainingSpaceForItem(offhandItemStack, itemstack)) { + remains -= (offhandItemStack.getMaxStackSize() < this.getMaxStackSize() ? offhandItemStack.getMaxStackSize() : this.getMaxStackSize()) - offhandItemStack.getCount(); } return remains <= 0 ? itemstack.getCount() : itemstack.getCount() - remains; } @Override - public int getFirstEmptySlotIndex() { - for(int i = 0; i < this.h.size(); ++i) { - if (this.h.get(i).isEmpty()) { + public int getFreeSlot() { + for(int i = 0; i < this.items.size(); ++i) { + if (this.items.get(i).isEmpty()) { return i; } } @@ -367,38 +269,38 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } @Override - public void a(ItemStack itemstack) { - int i = this.b(itemstack); - if (d(i)) { - this.k = i; + public void setPickedItem(ItemStack itemstack) { + int i = this.findSlotMatchingItem(itemstack); + if (isHotbarSlot(i)) { + this.selected = i; } else if (i == -1) { - this.k = this.i(); - if (!this.h.get(this.k).isEmpty()) { - int j = this.getFirstEmptySlotIndex(); + this.selected = this.getSuitableHotbarSlot(); + if (!this.items.get(this.selected).isEmpty()) { + int j = this.getFreeSlot(); if (j != -1) { - this.h.set(j, this.h.get(this.k)); + this.items.set(j, this.items.get(this.selected)); } } - this.h.set(this.k, itemstack); + this.items.set(this.selected, itemstack); } else { - this.c(i); + this.pickSlot(i); } } @Override - public void c(int i) { - this.k = this.i(); - ItemStack itemstack = this.h.get(this.k); - this.h.set(this.k, this.h.get(i)); - this.h.set(i, itemstack); + public void pickSlot(int i) { + this.selected = this.getSuitableHotbarSlot(); + ItemStack itemstack = this.items.get(this.selected); + this.items.set(this.selected, this.items.get(i)); + this.items.set(i, itemstack); } @Override - public int b(ItemStack itemstack) { - for (int i = 0; i < this.h.size(); ++i) { - if (!this.h.get(i).isEmpty() && ItemStack.e(itemstack, this.h.get(i))) { + public int findSlotMatchingItem(ItemStack itemstack) { + for(int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemstack, this.items.get(i))) { return i; } } @@ -407,10 +309,10 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } @Override - public int c(ItemStack itemstack) { - for (int i = 0; i < this.h.size(); ++i) { - ItemStack itemstack1 = this.h.get(i); - if (!this.h.get(i).isEmpty() && ItemStack.e(itemstack, this.h.get(i)) && !this.h.get(i).g() && !itemstack1.hasEnchantments() && !itemstack1.hasName()) { + public int findSlotMatchingUnusedItem(ItemStack itemStack) { + for(int i = 0; i < this.items.size(); ++i) { + ItemStack localItem = this.items.get(i); + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemStack, this.items.get(i)) && !this.items.get(i).isDamaged() && !localItem.isEnchanted() && !localItem.hasCustomHoverName()) { return i; } } @@ -419,28 +321,28 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } @Override - public int i() { + public int getSuitableHotbarSlot() { int i; int j; - for (j = 0; j < 9; ++j) { - i = (this.k + j) % 9; - if (this.h.get(i).isEmpty()) { + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (this.items.get(i).isEmpty()) { return i; } } - for (j = 0; j < 9; ++j) { - i = (this.k + j) % 9; - if (!this.h.get(i).hasEnchantments()) { + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (!this.items.get(i).isEnchanted()) { return i; } } - return this.k; + return this.selected; } @Override - public void a(double d0) { + public void swapPaint(double d0) { if (d0 > 0.0D) { d0 = 1.0D; } @@ -449,79 +351,80 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP d0 = -1.0D; } - this.k = (int) (this.k - d0); + this.selected = (int) (this.selected - d0); - while (this.k < 0) { - this.k += 9; + while (this.selected < 0) { + this.selected += 9; } - while (this.k >= 9) { - this.k -= 9; + while(this.selected >= 9) { + this.selected -= 9; } - } @Override - public int a(Predicate predicate, int i, IInventory iinventory) { + public int clearOrCountMatchingItems(Predicate predicate, int i, Container container) { byte b0 = 0; boolean flag = i == 0; - int j = b0 + ContainerUtil.a(this, predicate, i - b0, flag); - j += ContainerUtil.a(iinventory, predicate, i - j, flag); - ItemStack itemstack = this.l.bV.getCarried(); - j += ContainerUtil.a(itemstack, predicate, i - j, flag); + int j = b0 + ContainerHelper.clearOrCountMatchingItems(this, predicate, i - b0, flag); + j += ContainerHelper.clearOrCountMatchingItems(container, predicate, i - j, flag); + ItemStack itemstack = this.player.containerMenu.getCarried(); + j += ContainerHelper.clearOrCountMatchingItems(itemstack, predicate, i - j, flag); if (itemstack.isEmpty()) { - this.l.bV.setCarried(ItemStack.b); + this.player.containerMenu.setCarried(ItemStack.EMPTY); } return j; } - private int i(ItemStack itemstack) { - int i = this.firstPartial(itemstack); + private int addResource(ItemStack itemstack) { + int i = this.getSlotWithRemainingSpace(itemstack); if (i == -1) { - i = this.getFirstEmptySlotIndex(); + i = this.getFreeSlot(); } - return i == -1 ? itemstack.getCount() : this.d(i, itemstack); + return i == -1 ? itemstack.getCount() : this.addResource(i, itemstack); } - private int d(int i, ItemStack itemstack) { + private int addResource(int i, ItemStack itemstack) { Item item = itemstack.getItem(); int j = itemstack.getCount(); - ItemStack itemstack1 = this.getItem(i); - if (itemstack1.isEmpty()) { - itemstack1 = new ItemStack(item, 0); + ItemStack localItemStack = this.getRawItem(i); + if (localItemStack.isEmpty()) { + localItemStack = new ItemStack(item, 0); if (itemstack.hasTag()) { - itemstack1.setTag(Objects.requireNonNull(itemstack.getTag()).clone()); + // hasTag ensures tag not null + //noinspection ConstantConditions + localItemStack.setTag(itemstack.getTag().copy()); } - this.setItem(i, itemstack1); + this.setRawItem(i, localItemStack); } - k = Math.min(j, itemstack1.getMaxStackSize() - itemstack1.getCount()); + int k = Math.min(j, localItemStack.getMaxStackSize() - localItemStack.getCount()); - if (k > this.getMaxStackSize() - itemstack1.getCount()) { - k = this.getMaxStackSize() - itemstack1.getCount(); + if (k > this.getMaxStackSize() - localItemStack.getCount()) { + k = this.getMaxStackSize() - localItemStack.getCount(); } if (k != 0) { j -= k; - itemstack1.add(k); - itemstack1.d(5); + localItemStack.grow(k); + localItemStack.setPopTime(5); } return j; } @Override - public int firstPartial(ItemStack itemstack) { - if (this.isSimilarAndNotFull(this.getItem(this.k), itemstack)) { - return this.k; - } else if (this.isSimilarAndNotFull(this.getItem(40), itemstack)) { + public int getSlotWithRemainingSpace(ItemStack itemstack) { + if (this.hasRemainingSpaceForItem(this.getRawItem(this.selected), itemstack)) { + return this.selected; + } else if (this.hasRemainingSpaceForItem(this.getRawItem(40), itemstack)) { return 40; } else { - for(int i = 0; i < this.h.size(); ++i) { - if (this.isSimilarAndNotFull(this.h.get(i), itemstack)) { + for(int i = 0; i < this.items.size(); ++i) { + if (this.hasRemainingSpaceForItem(this.items.get(i), itemstack)) { return i; } } @@ -531,11 +434,11 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } @Override - public void j() { - for (NonNullList nonNullList : this.n) { - for (int i = 0; i < nonNullList.size(); ++i) { - if (!nonNullList.get(i).isEmpty()) { - nonNullList.get(i).a(this.l.t, this.l, i, this.k == i); + public void tick() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (!compartment.get(i).isEmpty()) { + compartment.get(i).inventoryTick(this.player.level, this.player, i, this.selected == i); } } } @@ -543,27 +446,27 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } @Override - public boolean pickup(ItemStack itemStack) { - return this.c(-1, itemStack); + public boolean add(ItemStack itemStack) { + return this.add(-1, itemStack); } @Override - public boolean c(int i, ItemStack itemStack) { + public boolean add(int i, ItemStack itemStack) { if (itemStack.isEmpty()) { return false; } else { try { - if (itemStack.g()) { + if (itemStack.isDamaged()) { if (i == -1) { - i = this.getFirstEmptySlotIndex(); + i = this.getFreeSlot(); } if (i >= 0) { - this.h.set(i, itemStack.cloneItemStack()); - this.h.get(i).d(5); + this.items.set(i, itemStack.copy()); + this.items.get(i).setPopTime(5); itemStack.setCount(0); return true; - } else if (this.l.getAbilities().d) { + } else if (this.player.getAbilities().instabuild) { itemStack.setCount(0); return true; } else { @@ -574,13 +477,13 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP do { j = itemStack.getCount(); if (i == -1) { - itemStack.setCount(this.i(itemStack)); + itemStack.setCount(this.addResource(itemStack)); } else { - itemStack.setCount(this.d(i, itemStack)); + itemStack.setCount(this.addResource(i, itemStack)); } } while(!itemStack.isEmpty() && itemStack.getCount() < j); - if (itemStack.getCount() == j && this.l.getAbilities().d) { + if (itemStack.getCount() == j && this.player.getAbilities().instabuild) { itemStack.setCount(0); return true; } else { @@ -588,39 +491,39 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } } } catch (Throwable var6) { - CrashReport crashreport = CrashReport.a(var6, "Adding item to inventory"); - CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Item being added"); - crashreportsystemdetails.a("Item ID", Item.getId(itemStack.getItem())); - crashreportsystemdetails.a("Item data", itemStack.getDamage()); - crashreportsystemdetails.a("Item name", () -> itemStack.getName().getString()); - throw new ReportedException(crashreport); + CrashReport crashReport = CrashReport.forThrowable(var6, "Adding item to inventory"); + CrashReportCategory crashReportCategory = crashReport.addCategory("Item being added"); + crashReportCategory.setDetail("Item ID", Item.getId(itemStack.getItem())); + crashReportCategory.setDetail("Item data", itemStack.getDamageValue()); + crashReportCategory.setDetail("Item name", () -> itemStack.getHoverName().getString()); + throw new ReportedException(crashReport); } } } @Override - public void f(ItemStack itemStack) { - this.a(itemStack, true); + public void placeItemBackInInventory(ItemStack itemStack) { + this.placeItemBackInInventory(itemStack, true); } @Override - public void a(ItemStack itemStack, boolean flag) { + public void placeItemBackInInventory(ItemStack itemStack, boolean flag) { while(true) { if (!itemStack.isEmpty()) { - int i = this.firstPartial(itemStack); + int i = this.getSlotWithRemainingSpace(itemStack); if (i == -1) { - i = this.getFirstEmptySlotIndex(); + i = this.getFreeSlot(); } if (i != -1) { - int j = itemStack.getMaxStackSize() - this.getItem(i).getCount(); - if (this.c(i, itemStack.cloneAndSubtract(j)) && flag && this.l instanceof EntityPlayer) { - ((EntityPlayer)this.l).b.sendPacket(new PacketPlayOutSetSlot(-2, i, this.getItem(i))); + int j = itemStack.getMaxStackSize() - this.getRawItem(i).getCount(); + if (this.add(i, itemStack.split(j)) && flag && this.player instanceof ServerPlayer) { + ((ServerPlayer)this.player).connection.send(new ClientboundContainerSetSlotPacket(-2, 0, i, this.getRawItem(i))); } continue; } - this.l.drop(itemStack, false); + this.player.drop(itemStack, false); } return; @@ -628,11 +531,23 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } @Override - public void g(ItemStack itemStack) { - for (NonNullList nonNullList : this.n) { - for (int i = 0; i < nonNullList.size(); ++i) { - if (nonNullList.get(i) == itemStack) { - nonNullList.set(i, ItemStack.b); + public ItemStack removeItem(int rawIndex, final int j) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null + || indexedCompartment.compartment().get(indexedCompartment.index()).isEmpty()) { + return ItemStack.EMPTY; + } + + return ContainerHelper.removeItem(indexedCompartment.compartment(), indexedCompartment.index(), j); + } + + @Override + public void removeItem(ItemStack itemStack) { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (compartment.get(i) == itemStack) { + compartment.set(i, ItemStack.EMPTY); break; } } @@ -640,61 +555,88 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } @Override - public float a(IBlockData iBlockData) { - return this.h.get(this.k).a(iBlockData); + public ItemStack removeItemNoUpdate(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + ItemStack removed = indexedCompartment.compartment().set(indexedCompartment.index(), ItemStack.EMPTY); + + if (removed.isEmpty()) { + return ItemStack.EMPTY; + } + + return removed; } @Override - public NBTTagList a(NBTTagList nbtTagList) { - NBTTagCompound nbttagcompound; - int i; - for(i = 0; i < this.h.size(); ++i) { - if (!this.h.get(i).isEmpty()) { - nbttagcompound = new NBTTagCompound(); - nbttagcompound.setByte("Slot", (byte)i); - this.h.get(i).save(nbttagcompound); - nbtTagList.add(nbttagcompound); - } + public void setItem(int rawIndex, final ItemStack itemStack) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + this.player.drop(itemStack, true); + return; } - for(i = 0; i < this.i.size(); ++i) { - if (!this.i.get(i).isEmpty()) { - nbttagcompound = new NBTTagCompound(); - nbttagcompound.setByte("Slot", (byte)(i + 100)); - this.i.get(i).save(nbttagcompound); - nbtTagList.add(nbttagcompound); - } - } - - for(i = 0; i < this.j.size(); ++i) { - if (!this.j.get(i).isEmpty()) { - nbttagcompound = new NBTTagCompound(); - nbttagcompound.setByte("Slot", (byte)(i + 150)); - this.j.get(i).save(nbttagcompound); - nbtTagList.add(nbttagcompound); - } - } - - return nbtTagList; + indexedCompartment.compartment().set(indexedCompartment.index(), itemStack); } @Override - public void b(NBTTagList nbtTagList) { - this.h.clear(); - this.i.clear(); - this.j.clear(); + public float getDestroySpeed(BlockState blockState) { + return this.items.get(this.selected).getDestroySpeed(blockState); + } - for(int i = 0; i < nbtTagList.size(); ++i) { - NBTTagCompound nbttagcompound = nbtTagList.getCompound(i); - int j = nbttagcompound.getByte("Slot") & 255; - ItemStack itemstack = ItemStack.a(nbttagcompound); + @Override + public ListTag save(ListTag listTag) { + for (int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)i); + this.items.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.armor.size(); ++i) { + if (!this.armor.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 100)); + this.armor.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.offhand.size(); ++i) { + if (!this.offhand.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 150)); + this.offhand.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + return listTag; + } + + @Override + public void load(ListTag listTag) { + this.items.clear(); + this.armor.clear(); + this.offhand.clear(); + + for(int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + ItemStack itemstack = ItemStack.of(compoundTag); if (!itemstack.isEmpty()) { - if (j < this.h.size()) { - this.h.set(j, itemstack); - } else if (j >= 100 && j < this.i.size() + 100) { - this.i.set(j - 100, itemstack); - } else if (j >= 150 && j < this.j.size() + 150) { - this.j.set(j - 150, itemstack); + if (j < this.items.size()) { + this.items.set(j, itemstack); + } else if (j >= 100 && j < this.armor.size() + 100) { + this.armor.set(j - 100, itemstack); + } else if (j >= 150 && j < this.offhand.size() + 150) { + this.offhand.set(j - 150, itemstack); } } } @@ -702,76 +644,126 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP } @Override - public ItemStack e(int i) { - return this.i.get(i); + public int getContainerSize() { + return 45; } @Override - public void a(DamageSource damageSource, float f, int[] intArray) { - if (f > 0.0F) { - f /= 4.0F; - if (f < 1.0F) { - f = 1.0F; + public boolean isEmpty() { + return !contains(itemStack -> !itemStack.isEmpty()); + } + + @Override + public ItemStack getItem(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + return indexedCompartment.compartment().get(indexedCompartment.index()); + } + + @Override + public Component getName() { + return this.player.getName(); + } + + @Override + public ItemStack getArmor(int index) { + return this.armor.get(index); + } + + @Override + public void hurtArmor(DamageSource damagesource, float damage, int[] armorIndices) { + if (damage > 0.0F) { + damage /= 4.0F; + if (damage < 1.0F) { + damage = 1.0F; } - for (int index : intArray) { - ItemStack itemstack = this.i.get(index); - if ((!damageSource.isFire() || !itemstack.getItem().w()) && itemstack.getItem() instanceof ItemArmor) { - itemstack.damage((int) f, this.l, (entityHuman) -> entityHuman.broadcastItemBreak(EnumItemSlot.a(EnumItemSlot.Function.b, index))); + for (int index : armorIndices) { + ItemStack itemstack = this.armor.get(index); + if ((!damagesource.isFire() || !itemstack.getItem().isFireResistant()) && itemstack.getItem() instanceof ArmorItem) { + itemstack.hurtAndBreak((int) damage, this.player, localPlayer -> localPlayer.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index))); } } } - } @Override - public void dropContents() { - for (List list : this.n) { - for (int i = 0; i < list.size(); ++i) { - ItemStack itemstack = list.get(i); + public void dropAll() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + ItemStack itemstack = compartment.get(i); if (!itemstack.isEmpty()) { - list.set(i, ItemStack.b); - this.l.a(itemstack, true, false); + this.player.drop(itemstack, true, false); + compartment.set(i, ItemStack.EMPTY); } } } } @Override - public boolean h(ItemStack itemStack) { - return this.n.stream() - .flatMap(Collection::stream) - .anyMatch(itemStack1 -> !itemStack1.isEmpty() && itemStack1.doMaterialsMatch(itemStack)); + public void setChanged() { + super.setChanged(); } @Override - public boolean a(Tag tag) { - return this.n.stream() - .flatMap(Collection::stream) - .anyMatch(itemStack -> !itemStack.isEmpty() && itemStack.a(tag)); + public int getTimesChanged() { + return super.getTimesChanged(); } @Override - public void a(PlayerInventory playerInventory) { - for(int i = 0; i < this.getSize(); ++i) { - this.setItem(i, playerInventory.getItem(i)); + public boolean stillValid(Player player) { + return true; + } + + @Override + public boolean contains(ItemStack itemstack) { + return contains(itemStack -> itemStack.isEmpty() && itemStack.sameItem(itemstack)); + } + + @Override + public boolean contains(Tag tag) { + return contains(itemStack -> !itemStack.isEmpty() && itemStack.is(tag)); + } + + @Override + public void replaceWith(Inventory inventory) { + Function getter; + + if (inventory instanceof SpecialPlayerInventory specialPlayerInventory) { + getter = specialPlayerInventory::getRawItem; + } else { + getter = inventory::getItem; } - this.k = playerInventory.k; + for(int i = 0; i < this.getContainerSize(); ++i) { + this.setRawItem(i, getter.apply(i)); + } + + this.selected = inventory.selected; } @Override - public void clear() { - for (List list : this.n) { - list.clear(); + public void clearContent() { + for (NonNullList compartment : this.compartments) { + compartment.clear(); } } @Override - public void a(AutoRecipeStackManager autoRecipeStackManager) { - for (ItemStack itemstack : this.h) { - autoRecipeStackManager.a(itemstack); + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountSimpleStack(itemstack); } } + @Override + public ItemStack removeFromSelected(boolean dropWholeStack) { + ItemStack itemstack = this.getSelected(); + return itemstack.isEmpty() ? ItemStack.EMPTY : this.removeItem(this.selected, dropWholeStack ? itemstack.getCount() : 1); + } + } diff --git a/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java b/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java index 4f05407..090f5cf 100644 --- a/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java +++ b/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java @@ -83,6 +83,8 @@ public class InternalAccessor { case "v1_16_R2": return "https://github.com/lishid/OpenInv/releases/tag/4.1.5"; case "v1_16_R3": + return "https://github.com/Jikoo/OpenInv/releases/tag/4.1.8"; + case "v1_17_R1": default: return "https://github.com/Jikoo/OpenInv/releases"; } diff --git a/pom.xml b/pom.xml index c26be77..ef04ab1 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,6 @@ api plugin - internal/v1_16_R3 internal/v1_17_R1 assembly @@ -139,6 +138,12 @@ org.apache.maven.plugins 3.3.0 + + + net.md-5 + specialsource-maven-plugin + 1.2.2 + diff --git a/scripts/get_spigot_versions.sh b/scripts/get_spigot_versions.sh index 29376e0..4dca717 100644 --- a/scripts/get_spigot_versions.sh +++ b/scripts/get_spigot_versions.sh @@ -15,8 +15,8 @@ # along with this program. If not, see . # -# TODO FIGURE OUT AND REMOVE WHEN LESS STRESS -hacky_versions=("1.16.5-R0.1-SNAPSHOT" "1.17.1-R0.1-SNAPSHOT") +# TODO Fix script for bash version used in Actions images +hacky_versions=("1.17.1-R0.1-SNAPSHOT") for hacky_version in "${hacky_versions[@]}"; do echo "$hacky_version" done diff --git a/scripts/install_spigot_dependencies.sh b/scripts/install_spigot_dependencies.sh index 0beac8f..336da7d 100644 --- a/scripts/install_spigot_dependencies.sh +++ b/scripts/install_spigot_dependencies.sh @@ -36,12 +36,12 @@ echo Found Spigot dependencies: "${versions[@]}" for version in "${versions[@]}"; do set -e exit_code=0 - mvn dependency:get -Dartifact=org.spigotmc:spigot:"$version" -q -o || exit_code=$? + mvn dependency:get -Dartifact=org.spigotmc:spigot:"$version":remapped-mojang -q -o || exit_code=$? if [ $exit_code -ne 0 ]; then echo Installing missing Spigot version "$version" revision=${version%%-R*} get_buildtools - java -jar $buildtools -rev "$revision" + java -jar $buildtools -rev "$revision" --remapped else echo Spigot "$version" is already installed fi -- 2.49.1 From e3d9cea0274a6b0ee2d883925913be9c165874c7 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 16 Oct 2021 17:54:30 -0400 Subject: [PATCH 038/139] Fix spigot dependency parsing * Re-add cache * Work around reflection issues with mvn help:evaluate on Java 9+ --- scripts/get_spigot_versions.sh | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/scripts/get_spigot_versions.sh b/scripts/get_spigot_versions.sh index 4dca717..1e079f3 100644 --- a/scripts/get_spigot_versions.sh +++ b/scripts/get_spigot_versions.sh @@ -15,21 +15,32 @@ # along with this program. If not, see . # -# TODO Fix script for bash version used in Actions images -hacky_versions=("1.17.1-R0.1-SNAPSHOT") -for hacky_version in "${hacky_versions[@]}"; do - echo "$hacky_version" -done - -exit 0 - # Note that this script is designed for use in GitHub Actions, and is not # particularly robust nor configurable. Run from project parent directory. +# Use a nameref as a cache - maven evaluation is pretty slow. +# Re-calling the script and relying on it to handle caching is way easier than passing around info. +declare -a spigot_versions + +# We don't care about concatenation - either it's not null and we handle entries or it's null and we instantiate. +# shellcheck disable=SC2199 +if [[ ${spigot_versions[@]} ]]; then + for spigot_version in "${spigot_versions[@]}"; do + echo "$spigot_version" + done + return +fi + +old_maven_opts=$MAVEN_OPTS +# Add JVM parameters to allow help plugin access to packages it needs. +export MAVEN_OPTS="$old_maven_opts --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED" + # Pull Spigot dependency information from Maven. # Since we only care about Spigot versions, only check modules in the folder internal. readarray -t modules <<< "$(mvn help:evaluate -Dexpression=project.modules -q -DforceStdout -P all | grep -oP '(?<=)(internal/.*)(?=)')" +declare -n versions="spigot_versions" + for module in "${modules[@]}"; do # Get number of dependencies declared in pom of specified internal module. max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl "$module" | grep -c "") @@ -48,3 +59,6 @@ for module in "${modules[@]}"; do fi done done + +# Reset JVM parameters +export MAVEN_OPTS=$old_maven_opts \ No newline at end of file -- 2.49.1 From b4601bb6c1e7f7e8fc53e448747477dd7b2e55f8 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 16 Oct 2021 19:16:08 -0400 Subject: [PATCH 039/139] Fix cached Spigot dependencies never being used Since plugins have not been downloaded, get always fails when running in offline mode. --- scripts/install_spigot_dependencies.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/install_spigot_dependencies.sh b/scripts/install_spigot_dependencies.sh index 336da7d..dd3cbfc 100644 --- a/scripts/install_spigot_dependencies.sh +++ b/scripts/install_spigot_dependencies.sh @@ -33,6 +33,11 @@ get_buildtools () { readarray -t versions <<< "$(. ./scripts/get_spigot_versions.sh)" echo Found Spigot dependencies: "${versions[@]}" +# Install dependencies aside from Spigot prior to running in offline mode. +# Note that the default SuperPOM declares maven-dependency-plugin 2.8.0. +# Unfortunately, we run into MDEP-204 and require a version >= 3.1.2. +mvn org.apache.maven.plugins:maven-dependency-plugin:3.2.0:go-offline -DexcludeArtifactIds=spigot + for version in "${versions[@]}"; do set -e exit_code=0 -- 2.49.1 From dd90b5281f6a966d99916dbf12d70e17755c9944 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 17 Nov 2021 10:41:53 -0500 Subject: [PATCH 040/139] Use Java 17 for CI --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49c156b..b190db2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,9 +12,10 @@ jobs: uses: actions/checkout@v2 - name: Set Up Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: - java-version: 16 + distribution: 'adopt' + java-version: '17' # Use cache to speed up build - name: Cache Maven Repo -- 2.49.1 From d236dd27b3760f4ac7d9a4c51b4b306577d03a80 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Tue, 23 Nov 2021 13:00:42 -0500 Subject: [PATCH 041/139] Update to 1.18-pre5 --- internal/v1_18_R1/pom.xml | 112 +++ .../internal/v1_18_R1/AnySilentContainer.java | 277 +++++++ .../openinv/internal/v1_18_R1/OpenPlayer.java | 74 ++ .../internal/v1_18_R1/PlayerDataManager.java | 230 ++++++ .../internal/v1_18_R1/SpecialEnderChest.java | 344 ++++++++ .../v1_18_R1/SpecialPlayerInventory.java | 769 ++++++++++++++++++ pom.xml | 1 + 7 files changed, 1807 insertions(+) create mode 100644 internal/v1_18_R1/pom.xml create mode 100644 internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java create mode 100644 internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java create mode 100644 internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java create mode 100644 internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java create mode 100644 internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_18_R1/pom.xml new file mode 100644 index 0000000..8629e1e --- /dev/null +++ b/internal/v1_18_R1/pom.xml @@ -0,0 +1,112 @@ + + + + + 4.0.0 + + + openinvparent + com.lishid + ../../pom.xml + 4.1.9-SNAPSHOT + + + openinvadapter1_18_R1 + OpenInvAdapter1_18_R1 + + + 17 + 17 + 1.18-pre5-R0.1-SNAPSHOT + + + + + org.spigotmc + spigot-api + ${spigot.version} + + + spigot + org.spigotmc + provided + ${spigot.version} + remapped-mojang + + + openinvapi + com.lishid + + + openinvplugincore + com.lishid + + + annotations + org.jetbrains + + + + + + + maven-shade-plugin + + + false + + + + maven-compiler-plugin + + + net.md-5 + specialsource-maven-plugin + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:${spigot.version}:txt:maps-mojang + true + org.spigotmc:spigot:${spigot.version}:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:${spigot.version}:csrg:maps-spigot + org.spigotmc:spigot:${spigot.version}:jar:remapped-obf + + + + + + + + diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java new file mode 100644 index 0000000..a1d8272 --- /dev/null +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R1; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IAnySilentContainer; +import com.lishid.openinv.util.ReflectionHelper; +import java.lang.reflect.Field; +import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.CompoundContainer; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.monster.Shulker; +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.block.BarrelBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.DoubleBlockCombiner; +import net.minecraft.world.level.block.ShulkerBoxBlock; +import net.minecraft.world.level.block.TrappedChestBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.block.ShulkerBox; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AnySilentContainer implements IAnySilentContainer { + + private @Nullable Field serverPlayerGameModeGameType; + + public AnySilentContainer() { + try { + try { + // IDE warns about field not existing, but SpecialSource does not remap strings used in reflection. + // The warning is not suppressed as a reminder that it must manually be checked on updates. + this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("b"); + this.serverPlayerGameModeGameType.setAccessible(true); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("ServerPlayerGameMode#gameModeForPlayer's obfuscated name has changed!"); + logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues"); + logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail."); + // N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break. + this.serverPlayerGameModeGameType = ReflectionHelper.grabFieldByType(ServerPlayerGameMode.class, GameType.class); + } + } catch (SecurityException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to directly write player game mode! SilentContainer will fail."); + logger.log(Level.WARNING, "Error obtaining GameType field", e); + } + } + + @Override + public boolean isShulkerBlocked(ShulkerBox box) { + org.bukkit.World bukkitWorld = box.getWorld(); + if (!(bukkitWorld instanceof CraftWorld)) { + bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); + } + + if (!(bukkitWorld instanceof CraftWorld craftWorld)) { + Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); + OpenInv.getPlugin(OpenInv.class).getLogger().log(Level.WARNING, exception.getMessage(), exception); + return false; + } + + final ServerLevel world = craftWorld.getHandle(); + final BlockPos blockPosition = new BlockPos(box.getX(), box.getY(), box.getZ()); + final BlockEntity tile = world.getBlockEntity(blockPosition); + + if (!(tile instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) + || shulkerBoxBlockEntity.getAnimationStatus() != ShulkerBoxBlockEntity.AnimationStatus.CLOSED) { + return false; + } + + BlockState blockState = world.getBlockState(blockPosition); + + // See net.minecraft.world.level.block.ShulkerBoxBlock#canOpen + AABB boundingBox = Shulker.getProgressDeltaAabb(blockState.getValue(ShulkerBoxBlock.FACING), 0.0F, 0.5F) + .move(blockPosition) + .deflate(1.0E-6D); + return !world.noCollision(boundingBox); + } + + @Override + public boolean activateContainer( + @NotNull final Player bukkitPlayer, + final boolean silentchest, + @NotNull final org.bukkit.block.Block bukkitBlock) { + + // Silent ender chest is API-only + if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) { + bukkitPlayer.openInventory(bukkitPlayer.getEnderChest()); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + final ServerLevel level = player.getLevel(); + final BlockPos blockPos = new BlockPos(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + final BlockEntity blockEntity = level.getBlockEntity(blockPos); + + if (blockEntity == null) { + return false; + } + + if (blockEntity instanceof EnderChestBlockEntity enderChestTile) { + // Anychest ender chest. See net.minecraft.world.level.block.BlockEnderChest + PlayerEnderChestContainer enderChest = player.getEnderChestInventory(); + enderChest.setActiveChest(enderChestTile); + player.openMenu(new SimpleMenuProvider((containerCounter, playerInventory, ignored) -> { + MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); + int rows = enderChest.getContainerSize() / 9; + return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); + }, new TextComponent("container.enderchest"))); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + if (!(blockEntity instanceof MenuProvider menuProvider)) { + return false; + } + + BlockState blockState = level.getBlockState(blockPos); + Block block = blockState.getBlock(); + + if (block instanceof ChestBlock chestBlock) { + + // boolean flag: check if chest is blocked + Optional menuOptional = chestBlock.combine(blockState, level, blockPos, false).apply( + // Combiner is a copy of private ChestBlock.MENU_PROVIDER_COMBINER + new DoubleBlockCombiner.Combiner>() { + @Override + public Optional acceptDouble(ChestBlockEntity localChest1, ChestBlockEntity localChest2) { + CompoundContainer doubleChest = new CompoundContainer(localChest1, localChest2); + return Optional.of(new ChestBlock.DoubleInventory(localChest1, localChest2, doubleChest)); + } + + @Override + public Optional acceptSingle(ChestBlockEntity localChest) { + return Optional.of(localChest); + } + + @Override + public Optional acceptNone() { + return Optional.empty(); + } + }); + + if (menuOptional.isEmpty()) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + + menuProvider = menuOptional.get(); + + if (block instanceof TrappedChestBlock) { + bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); + } else { + bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED); + } + } + + if (block instanceof ShulkerBoxBlock) { + bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED); + } + + if (block instanceof BarrelBlock) { + bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL); + } + + // AnyChest only - SilentChest not active, container unsupported, or unnecessary. + if (!silentchest || player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) { + player.openMenu(menuProvider); + return true; + } + + // SilentChest requires access to setting players' game mode directly. + if (this.serverPlayerGameModeGameType == null) { + return false; + } + + if (blockEntity instanceof RandomizableContainerBlockEntity lootable) { + if (lootable.lootTable != null) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + } + + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); + player.openMenu(menuProvider); + this.forceGameType(player, gameType); + return true; + } + + @Override + public void deactivateContainer(@NotNull final Player bukkitPlayer) { + if (this.serverPlayerGameModeGameType == null) { + return; + } + + InventoryView view = bukkitPlayer.getOpenInventory(); + switch (view.getType()) { + case CHEST: + case ENDER_CHEST: + case SHULKER_BOX: + case BARREL: + break; + default: + return; + } + + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + // Force game mode change without informing plugins or players. + // Regular game mode set calls GameModeChangeEvent and is cancellable. + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); + + // Close container - note that this is very different from ServerPlayer#closeContainer! + // Triggering event must not be re-called or we'll enter an infinite loop. + player.doCloseContainer(); + + // Revert forced game mode. + this.forceGameType(player, gameType); + } + + private void forceGameType(final ServerPlayer player, final GameType gameMode) { + if (this.serverPlayerGameModeGameType == null) { + // No need to warn repeatedly, error on startup and lack of function should be enough. + return; + } + try { + this.serverPlayerGameModeGameType.setAccessible(true); + this.serverPlayerGameModeGameType.set(player.gameMode, gameMode); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + +} diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java new file mode 100644 index 0000000..2a0a779 --- /dev/null +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R1; + +import java.io.File; +import net.minecraft.Util; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.storage.PlayerDataStorage; +import org.apache.logging.log4j.LogManager; +import org.bukkit.craftbukkit.v1_18_R1.CraftServer; +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer; + +public class OpenPlayer extends CraftPlayer { + + public OpenPlayer(CraftServer server, ServerPlayer entity) { + super(server, entity); + } + + @Override + public void loadData() { + // See CraftPlayer#loadData + CompoundTag loaded = this.server.getHandle().playerIo.load(this.getHandle()); + if (loaded != null) { + readExtraData(loaded); + } + } + + @Override + public void saveData() { + ServerPlayer player = this.getHandle(); + // See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman) + try { + PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; + + CompoundTag playerData = player.saveWithoutId(new CompoundTag()); + setExtraData(playerData); + + if (!isOnline()) { + // Special case: save old vehicle data + CompoundTag oldData = worldNBTStorage.load(player); + + if (oldData != null && oldData.contains("RootVehicle", 10)) { + // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound) + playerData.put("RootVehicle", oldData.getCompound("RootVehicle")); + } + } + + File file = File.createTempFile(player.getStringUUID() + "-", ".dat", worldNBTStorage.getPlayerDir()); + NbtIo.writeCompressed(playerData, file); + File file1 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat"); + File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); + Util.safeReplaceFile(file1, file, file2); + } catch (Exception e) { + LogManager.getLogger().warn("Failed to save player data for {}", player.getName().getString()); + } + } + +} diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java new file mode 100644 index 0000000..a982b99 --- /dev/null +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R1; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IPlayerDataManager; +import com.lishid.openinv.internal.ISpecialInventory; +import com.lishid.openinv.internal.OpenInventoryView; +import com.mojang.authlib.GameProfile; +import java.lang.reflect.Field; +import java.util.logging.Logger; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.craftbukkit.v1_18_R1.CraftServer; +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_18_R1.event.CraftEventFactory; +import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftContainer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PlayerDataManager implements IPlayerDataManager { + + private @Nullable Field bukkitEntity; + + public PlayerDataManager() { + try { + bukkitEntity = Entity.class.getDeclaredField("bukkitEntity"); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded."); + logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); + bukkitEntity = null; + } + } + + public static @NotNull ServerPlayer getHandle(final Player player) { + if (player instanceof CraftPlayer) { + return ((CraftPlayer) player).getHandle(); + } + + Server server = player.getServer(); + ServerPlayer nmsPlayer = null; + + if (server instanceof CraftServer) { + nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getUniqueId()); + } + + if (nmsPlayer == null) { + // Could use reflection to examine fields, but it's honestly not worth the bother. + throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation"); + } + + return nmsPlayer; + } + + @Override + public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { + // Ensure player has data + if (!offline.hasPlayedBefore()) { + return null; + } + + // Create a profile and entity to load the player data + // See net.minecraft.server.PlayerList#attemptLogin + GameProfile profile = new GameProfile(offline.getUniqueId(), + offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel worldServer = server.getLevel(Level.OVERWORLD); + + if (worldServer == null) { + return null; + } + + ServerPlayer entity = new ServerPlayer(server, worldServer, profile); + + try { + injectPlayer(entity); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + // Get the bukkit entity + Player target = entity.getBukkitEntity(); + if (target != null) { + // Load data + target.loadData(); + } + // Return the entity + return target; + } + + void injectPlayer(ServerPlayer player) throws IllegalAccessException { + if (bukkitEntity == null) { + return; + } + + bukkitEntity.setAccessible(true); + + bukkitEntity.set(player, new OpenPlayer(player.server.server, player)); + } + + @NotNull + @Override + public Player inject(@NotNull Player player) { + try { + ServerPlayer nmsPlayer = getHandle(player); + injectPlayer(nmsPlayer); + return nmsPlayer.getBukkitEntity(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return player; + } + } + + @Nullable + @Override + public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) { + + ServerPlayer nmsPlayer = getHandle(player); + + if (nmsPlayer.connection == null) { + return null; + } + + InventoryView view = getView(player, inventory); + + if (view == null) { + return player.openInventory(inventory.getBukkitInventory()); + } + + AbstractContainerMenu container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { + @Override + public MenuType getType() { + return getContainers(inventory.getBukkitInventory().getSize()); + } + }; + + container.setTitle(new TextComponent(view.getTitle())); + container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); + + if (container == null) { + return null; + } + + nmsPlayer.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), + new TextComponent(container.getBukkitView().getTitle()))); + nmsPlayer.containerMenu = container; + nmsPlayer.initMenu(container); + + return container.getBukkitView(); + + } + + private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) { + if (inventory instanceof SpecialEnderChest) { + return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest"); + } else if (inventory instanceof SpecialPlayerInventory) { + return new OpenInventoryView(player, inventory, "container.player", "'s Inventory"); + } else { + return null; + } + } + + static @NotNull MenuType getContainers(int inventorySize) { + + return switch (inventorySize) { + case 9 -> MenuType.GENERIC_9x1; + case 18 -> MenuType.GENERIC_9x2; + case 36 -> MenuType.GENERIC_9x4; // PLAYER + case 41, 45 -> MenuType.GENERIC_9x5; + case 54 -> MenuType.GENERIC_9x6; + default -> MenuType.GENERIC_9x3; // Default 27-slot inventory + }; + } + + @Override + public int convertToPlayerSlot(InventoryView view, int rawSlot) { + int topSize = view.getTopInventory().getSize(); + if (topSize <= rawSlot) { + // Slot is not inside special inventory, use Bukkit logic. + return view.convertSlot(rawSlot); + } + + // Main inventory, slots 0-26 -> 9-35 + if (rawSlot < 27) { + return rawSlot + 9; + } + // Hotbar, slots 27-35 -> 0-8 + if (rawSlot < 36) { + return rawSlot - 27; + } + // Armor, slots 36-39 -> 39-36 + if (rawSlot < 40) { + return 36 + (39 - rawSlot); + } + // Off hand + if (rawSlot == 40) { + return 40; + } + // Drop slots, "out of inventory" + return -1; + } + +} diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java new file mode 100644 index 0000000..d10bfdd --- /dev/null +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R1; + +import com.lishid.openinv.internal.ISpecialEnderChest; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.ContainerListener; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpecialEnderChest { + + private final CraftInventory inventory; + private ServerPlayer owner; + private NonNullList items; + private boolean playerOnline; + + public SpecialEnderChest(final org.bukkit.entity.Player player, final Boolean online) { + super(PlayerDataManager.getHandle(player)); + this.inventory = new CraftInventory(this); + this.owner = PlayerDataManager.getHandle(player); + this.playerOnline = online; + this.items = this.owner.getEnderChestInventory().items; + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return inventory; + } + + @Override + public boolean isInUse() { + return !this.getViewers().isEmpty(); + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public void setPlayerOnline(@NotNull final org.bukkit.entity.Player player) { + if (!this.playerOnline) { + try { + this.owner = PlayerDataManager.getHandle(player); + PlayerEnderChestContainer enderChest = owner.getEnderChestInventory(); + for (int i = 0; i < enderChest.getContainerSize(); ++i) { + enderChest.setItem(i, this.items.get(i)); + } + this.items = enderChest.items; + enderChest.transaction.addAll(this.transaction); + } catch (Exception ignored) {} + this.playerOnline = true; + } + } + + @Override + public @NotNull org.bukkit.entity.Player getPlayer() { + return owner.getBukkitEntity(); + } + + @Override + public void setChanged() { + this.owner.getEnderChestInventory().setChanged(); + } + + @Override + public List getContents() { + return this.items; + } + + @Override + public void onOpen(CraftHumanEntity who) { + this.owner.getEnderChestInventory().onOpen(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + this.owner.getEnderChestInventory().onClose(who); + } + + @Override + public List getViewers() { + return this.owner.getEnderChestInventory().getViewers(); + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public void setActiveChest(EnderChestBlockEntity enderChest) { + this.owner.getEnderChestInventory().setActiveChest(enderChest); + } + + @Override + public boolean isActiveChest(EnderChestBlockEntity enderChest) { + return this.owner.getEnderChestInventory().isActiveChest(enderChest); + } + + @Override + public int getMaxStackSize() { + return this.owner.getEnderChestInventory().getMaxStackSize(); + } + + @Override + public void setMaxStackSize(int i) { + this.owner.getEnderChestInventory().setMaxStackSize(i); + } + + @Override + public InventoryHolder getOwner() { + return this.owner.getEnderChestInventory().getOwner(); + } + + @Override + public @Nullable Location getLocation() { + return null; + } + + @Override + public void addListener(ContainerListener listener) { + this.owner.getEnderChestInventory().addListener(listener); + } + + @Override + public void removeListener(ContainerListener listener) { + this.owner.getEnderChestInventory().removeListener(listener); + } + + @Override + public ItemStack getItem(int i) { + return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.EMPTY; + } + + @Override + public ItemStack removeItem(int i, int j) { + ItemStack itemstack = ContainerHelper.removeItem(this.items, i, j); + if (!itemstack.isEmpty()) { + this.setChanged(); + } + + return itemstack; + } + + @Override + public ItemStack addItem(ItemStack itemstack) { + ItemStack localItem = itemstack.copy(); + this.moveItemToOccupiedSlotsWithSameType(localItem); + if (localItem.isEmpty()) { + return ItemStack.EMPTY; + } else { + this.moveItemToEmptySlots(localItem); + return localItem.isEmpty() ? ItemStack.EMPTY : localItem; + } + } + + @Override + public boolean canAddItem(ItemStack itemstack) { + for (ItemStack itemstack1 : this.items) { + if (itemstack1.isEmpty() || ItemStack.isSameItemSameTags(itemstack1, itemstack) && itemstack1.getCount() < itemstack1.getMaxStackSize()) { + return true; + } + } + + return false; + } + + private void moveItemToEmptySlots(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (localItem.isEmpty()) { + this.setItem(i, itemstack.copy()); + itemstack.setCount(0); + return; + } + } + } + + private void moveItemToOccupiedSlotsWithSameType(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (ItemStack.isSameItemSameTags(localItem, itemstack)) { + this.moveItemsBetweenStacks(itemstack, localItem); + if (itemstack.isEmpty()) { + return; + } + } + } + } + + private void moveItemsBetweenStacks(ItemStack itemstack, ItemStack itemstack1) { + int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize()); + int j = Math.min(itemstack.getCount(), i - itemstack1.getCount()); + if (j > 0) { + itemstack1.grow(j); + itemstack.shrink(j); + this.setChanged(); + } + } + + @Override + public ItemStack removeItemNoUpdate(int i) { + ItemStack itemstack = this.items.get(i); + if (itemstack.isEmpty()) { + return ItemStack.EMPTY; + } else { + this.items.set(i, ItemStack.EMPTY); + return itemstack; + } + } + + @Override + public void setItem(int i, ItemStack itemstack) { + this.items.set(i, itemstack); + if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { + itemstack.setCount(this.getMaxStackSize()); + } + + this.setChanged(); + } + + @Override + public int getContainerSize() { + return this.owner.getEnderChestInventory().getContainerSize(); + } + + @Override + public boolean isEmpty() { + return this.items.stream().allMatch(ItemStack::isEmpty); + } + + @Override + public void startOpen(Player player) { + } + + @Override + public void stopOpen(Player player) { + } + + @Override + public boolean canPlaceItem(int i, ItemStack itemstack) { + return true; + } + + @Override + public void clearContent() { + this.items.clear(); + this.setChanged(); + } + + @Override + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountStack(itemstack); + } + + } + + @Override + public List removeAllItems() { + List list = this.items.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList()); + this.clearContent(); + return list; + } + + @Override + public ItemStack removeItemType(Item item, int i) { + ItemStack itemstack = new ItemStack(item, 0); + + for(int j = this.getContainerSize() - 1; j >= 0; --j) { + ItemStack localItem = this.getItem(j); + if (localItem.getItem().equals(item)) { + int k = i - itemstack.getCount(); + ItemStack splitItem = localItem.split(k); + itemstack.grow(splitItem.getCount()); + if (itemstack.getCount() == i) { + break; + } + } + } + + if (!itemstack.isEmpty()) { + this.setChanged(); + } + + return itemstack; + } + + @Override + public String toString() { + return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).collect(Collectors.toList()).toString(); + } + + @Override + public void fromTag(ListTag listTag) { + for (int i = 0; i < this.getContainerSize(); ++i) { + this.setItem(i, ItemStack.EMPTY); + } + + for (int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + if (j < this.getContainerSize()) { + this.setItem(j, ItemStack.of(compoundTag)); + } + } + + } + +} diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java new file mode 100644 index 0000000..ffb96d3 --- /dev/null +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java @@ -0,0 +1,769 @@ +/* + * Copyright (C) 2011-2021 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R1; + +import com.google.common.collect.ImmutableList; +import com.lishid.openinv.internal.ISpecialPlayerInventory; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.tags.Tag; +import net.minecraft.world.Container; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerInventory { + + private final CraftInventory inventory; + private boolean playerOnline; + private Player player; + private NonNullList items; + private NonNullList armor; + private NonNullList offhand; + private List> compartments; + + public SpecialPlayerInventory(@NotNull org.bukkit.entity.Player bukkitPlayer, @NotNull Boolean online) { + super(PlayerDataManager.getHandle(bukkitPlayer)); + this.inventory = new CraftInventory(this); + this.playerOnline = online; + this.player = super.player; + this.selected = player.getInventory().selected; + this.items = this.player.getInventory().items; + this.armor = this.player.getInventory().armor; + this.offhand = this.player.getInventory().offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + } + + @Override + public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) { + if (!this.playerOnline) { + Player entityPlayer = PlayerDataManager.getHandle(player); + entityPlayer.getInventory().transaction.addAll(this.transaction); + this.player = entityPlayer; + for (int i = 0; i < getContainerSize(); ++i) { + this.player.getInventory().setItem(i, getRawItem(i)); + } + this.player.getInventory().selected = this.selected; + this.items = this.player.getInventory().items; + this.armor = this.player.getInventory().armor; + this.offhand = this.player.getInventory().offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + this.playerOnline = true; + } + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return this.inventory; + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public boolean isInUse() { + return !this.getViewers().isEmpty(); + } + + @Override + public @NotNull HumanEntity getPlayer() { + return this.player.getBukkitEntity(); + } + + private @NotNull ItemStack getRawItem(int i) { + return super.getItem(i); + } + + private void setRawItem(int i, @NotNull ItemStack itemStack) { + super.setItem(i, itemStack); + } + + private static record IndexedCompartment(@Nullable NonNullList compartment, int index) {} + + private @NotNull SpecialPlayerInventory.IndexedCompartment getIndexedContent(int index) { + if (index < items.size()) { + return new IndexedCompartment(items, getReversedItemSlotNum(index)); + } + + index -= items.size(); + + if (index < armor.size()) { + return new IndexedCompartment(armor, getReversedArmorSlotNum(index)); + } + + index -= armor.size(); + + if (index < offhand.size()) { + return new IndexedCompartment(offhand, index); + } + + index -= offhand.size(); + + return new IndexedCompartment(null, index); + } + + private int getReversedArmorSlotNum(final int i) { + if (i == 0) { + return 3; + } + if (i == 1) { + return 2; + } + if (i == 2) { + return 1; + } + if (i == 3) { + return 0; + } + return i; + } + + private int getReversedItemSlotNum(final int i) { + if (i >= 27) { + return i - 27; + } + return i + 9; + } + + private boolean contains(Predicate predicate) { + return this.compartments.stream().flatMap(NonNullList::stream).anyMatch(predicate); + } + + @Override + public List getArmorContents() { + return this.armor; + } + + @Override + public void onOpen(CraftHumanEntity who) { + this.player.getInventory().onOpen(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + this.player.getInventory().onClose(who); + } + + @Override + public List getViewers() { + return this.player.getInventory().getViewers(); + } + + @Override + public InventoryHolder getOwner() { + return this.player.getBukkitEntity(); + } + + @Override + public int getMaxStackSize() { + return this.player.getInventory().getMaxStackSize(); + } + + @Override + public void setMaxStackSize(int size) { + this.player.getInventory().setMaxStackSize(size); + } + + @Override + public Location getLocation() { + return this.player.getBukkitEntity().getLocation(); + } + + @Override + public boolean hasCustomName() { + return false; + } + + @Override + public List getContents() { + return this.compartments.stream().flatMap(Collection::stream).collect(Collectors.toList()); + } + + @Override + public ItemStack getSelected() { + return isHotbarSlot(this.selected) ? this.items.get(this.selected) : ItemStack.EMPTY; + } + + private boolean hasRemainingSpaceForItem(ItemStack itemstack, ItemStack itemstack1) { + return !itemstack.isEmpty() && ItemStack.isSameItemSameTags(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); + } + + @Override + public int canHold(ItemStack itemstack) { + int remains = itemstack.getCount(); + + for (int i = 0; i < this.items.size(); ++i) { + ItemStack itemstack1 = this.getRawItem(i); + if (itemstack1.isEmpty()) { + return itemstack.getCount(); + } + + if (this.hasRemainingSpaceForItem(itemstack1, itemstack)) { + remains -= (itemstack1.getMaxStackSize() < this.getMaxStackSize() ? itemstack1.getMaxStackSize() : this.getMaxStackSize()) - itemstack1.getCount(); + } + + if (remains <= 0) { + return itemstack.getCount(); + } + } + + ItemStack offhandItemStack = this.getRawItem(this.items.size() + this.armor.size()); + if (this.hasRemainingSpaceForItem(offhandItemStack, itemstack)) { + remains -= (offhandItemStack.getMaxStackSize() < this.getMaxStackSize() ? offhandItemStack.getMaxStackSize() : this.getMaxStackSize()) - offhandItemStack.getCount(); + } + + return remains <= 0 ? itemstack.getCount() : itemstack.getCount() - remains; + } + + @Override + public int getFreeSlot() { + for(int i = 0; i < this.items.size(); ++i) { + if (this.items.get(i).isEmpty()) { + return i; + } + } + + return -1; + } + + @Override + public void setPickedItem(ItemStack itemstack) { + int i = this.findSlotMatchingItem(itemstack); + if (isHotbarSlot(i)) { + this.selected = i; + } else if (i == -1) { + this.selected = this.getSuitableHotbarSlot(); + if (!this.items.get(this.selected).isEmpty()) { + int j = this.getFreeSlot(); + if (j != -1) { + this.items.set(j, this.items.get(this.selected)); + } + } + + this.items.set(this.selected, itemstack); + } else { + this.pickSlot(i); + } + + } + + @Override + public void pickSlot(int i) { + this.selected = this.getSuitableHotbarSlot(); + ItemStack itemstack = this.items.get(this.selected); + this.items.set(this.selected, this.items.get(i)); + this.items.set(i, itemstack); + } + + @Override + public int findSlotMatchingItem(ItemStack itemstack) { + for(int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemstack, this.items.get(i))) { + return i; + } + } + + return -1; + } + + @Override + public int findSlotMatchingUnusedItem(ItemStack itemStack) { + for(int i = 0; i < this.items.size(); ++i) { + ItemStack localItem = this.items.get(i); + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemStack, this.items.get(i)) && !this.items.get(i).isDamaged() && !localItem.isEnchanted() && !localItem.hasCustomHoverName()) { + return i; + } + } + + return -1; + } + + @Override + public int getSuitableHotbarSlot() { + int i; + int j; + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (this.items.get(i).isEmpty()) { + return i; + } + } + + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (!this.items.get(i).isEnchanted()) { + return i; + } + } + + return this.selected; + } + + @Override + public void swapPaint(double d0) { + if (d0 > 0.0D) { + d0 = 1.0D; + } + + if (d0 < 0.0D) { + d0 = -1.0D; + } + + this.selected = (int) (this.selected - d0); + + while (this.selected < 0) { + this.selected += 9; + } + + while(this.selected >= 9) { + this.selected -= 9; + } + } + + @Override + public int clearOrCountMatchingItems(Predicate predicate, int i, Container container) { + byte b0 = 0; + boolean flag = i == 0; + int j = b0 + ContainerHelper.clearOrCountMatchingItems(this, predicate, i - b0, flag); + j += ContainerHelper.clearOrCountMatchingItems(container, predicate, i - j, flag); + ItemStack itemstack = this.player.containerMenu.getCarried(); + j += ContainerHelper.clearOrCountMatchingItems(itemstack, predicate, i - j, flag); + if (itemstack.isEmpty()) { + this.player.containerMenu.setCarried(ItemStack.EMPTY); + } + + return j; + } + + private int addResource(ItemStack itemstack) { + int i = this.getSlotWithRemainingSpace(itemstack); + if (i == -1) { + i = this.getFreeSlot(); + } + + return i == -1 ? itemstack.getCount() : this.addResource(i, itemstack); + } + + private int addResource(int i, ItemStack itemstack) { + Item item = itemstack.getItem(); + int j = itemstack.getCount(); + ItemStack localItemStack = this.getRawItem(i); + if (localItemStack.isEmpty()) { + localItemStack = new ItemStack(item, 0); + if (itemstack.hasTag()) { + // hasTag ensures tag not null + //noinspection ConstantConditions + localItemStack.setTag(itemstack.getTag().copy()); + } + + this.setRawItem(i, localItemStack); + } + + int k = Math.min(j, localItemStack.getMaxStackSize() - localItemStack.getCount()); + + if (k > this.getMaxStackSize() - localItemStack.getCount()) { + k = this.getMaxStackSize() - localItemStack.getCount(); + } + + if (k != 0) { + j -= k; + localItemStack.grow(k); + localItemStack.setPopTime(5); + } + + return j; + } + + @Override + public int getSlotWithRemainingSpace(ItemStack itemstack) { + if (this.hasRemainingSpaceForItem(this.getRawItem(this.selected), itemstack)) { + return this.selected; + } else if (this.hasRemainingSpaceForItem(this.getRawItem(40), itemstack)) { + return 40; + } else { + for(int i = 0; i < this.items.size(); ++i) { + if (this.hasRemainingSpaceForItem(this.items.get(i), itemstack)) { + return i; + } + } + + return -1; + } + } + + @Override + public void tick() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (!compartment.get(i).isEmpty()) { + compartment.get(i).inventoryTick(this.player.level, this.player, i, this.selected == i); + } + } + } + + } + + @Override + public boolean add(ItemStack itemStack) { + return this.add(-1, itemStack); + } + + @Override + public boolean add(int i, ItemStack itemStack) { + if (itemStack.isEmpty()) { + return false; + } else { + try { + if (itemStack.isDamaged()) { + if (i == -1) { + i = this.getFreeSlot(); + } + + if (i >= 0) { + this.items.set(i, itemStack.copy()); + this.items.get(i).setPopTime(5); + itemStack.setCount(0); + return true; + } else if (this.player.getAbilities().instabuild) { + itemStack.setCount(0); + return true; + } else { + return false; + } + } else { + int j; + do { + j = itemStack.getCount(); + if (i == -1) { + itemStack.setCount(this.addResource(itemStack)); + } else { + itemStack.setCount(this.addResource(i, itemStack)); + } + } while(!itemStack.isEmpty() && itemStack.getCount() < j); + + if (itemStack.getCount() == j && this.player.getAbilities().instabuild) { + itemStack.setCount(0); + return true; + } else { + return itemStack.getCount() < j; + } + } + } catch (Throwable var6) { + CrashReport crashReport = CrashReport.forThrowable(var6, "Adding item to inventory"); + CrashReportCategory crashReportCategory = crashReport.addCategory("Item being added"); + crashReportCategory.setDetail("Item ID", Item.getId(itemStack.getItem())); + crashReportCategory.setDetail("Item data", itemStack.getDamageValue()); + crashReportCategory.setDetail("Item name", () -> itemStack.getHoverName().getString()); + throw new ReportedException(crashReport); + } + } + } + + @Override + public void placeItemBackInInventory(ItemStack itemStack) { + this.placeItemBackInInventory(itemStack, true); + } + + @Override + public void placeItemBackInInventory(ItemStack itemStack, boolean flag) { + while(true) { + if (!itemStack.isEmpty()) { + int i = this.getSlotWithRemainingSpace(itemStack); + if (i == -1) { + i = this.getFreeSlot(); + } + + if (i != -1) { + int j = itemStack.getMaxStackSize() - this.getRawItem(i).getCount(); + if (this.add(i, itemStack.split(j)) && flag && this.player instanceof ServerPlayer) { + ((ServerPlayer)this.player).connection.send(new ClientboundContainerSetSlotPacket(-2, 0, i, this.getRawItem(i))); + } + continue; + } + + this.player.drop(itemStack, false); + } + + return; + } + } + + @Override + public ItemStack removeItem(int rawIndex, final int j) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null + || indexedCompartment.compartment().get(indexedCompartment.index()).isEmpty()) { + return ItemStack.EMPTY; + } + + return ContainerHelper.removeItem(indexedCompartment.compartment(), indexedCompartment.index(), j); + } + + @Override + public void removeItem(ItemStack itemStack) { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (compartment.get(i) == itemStack) { + compartment.set(i, ItemStack.EMPTY); + break; + } + } + } + } + + @Override + public ItemStack removeItemNoUpdate(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + ItemStack removed = indexedCompartment.compartment().set(indexedCompartment.index(), ItemStack.EMPTY); + + if (removed.isEmpty()) { + return ItemStack.EMPTY; + } + + return removed; + } + + @Override + public void setItem(int rawIndex, final ItemStack itemStack) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + this.player.drop(itemStack, true); + return; + } + + indexedCompartment.compartment().set(indexedCompartment.index(), itemStack); + } + + @Override + public float getDestroySpeed(BlockState blockState) { + return this.items.get(this.selected).getDestroySpeed(blockState); + } + + @Override + public ListTag save(ListTag listTag) { + for (int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)i); + this.items.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.armor.size(); ++i) { + if (!this.armor.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 100)); + this.armor.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.offhand.size(); ++i) { + if (!this.offhand.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 150)); + this.offhand.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + return listTag; + } + + @Override + public void load(ListTag listTag) { + this.items.clear(); + this.armor.clear(); + this.offhand.clear(); + + for(int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + ItemStack itemstack = ItemStack.of(compoundTag); + if (!itemstack.isEmpty()) { + if (j < this.items.size()) { + this.items.set(j, itemstack); + } else if (j >= 100 && j < this.armor.size() + 100) { + this.armor.set(j - 100, itemstack); + } else if (j >= 150 && j < this.offhand.size() + 150) { + this.offhand.set(j - 150, itemstack); + } + } + } + + } + + @Override + public int getContainerSize() { + return 45; + } + + @Override + public boolean isEmpty() { + return !contains(itemStack -> !itemStack.isEmpty()); + } + + @Override + public ItemStack getItem(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + return indexedCompartment.compartment().get(indexedCompartment.index()); + } + + @Override + public Component getName() { + return this.player.getName(); + } + + @Override + public ItemStack getArmor(int index) { + return this.armor.get(index); + } + + @Override + public void hurtArmor(DamageSource damagesource, float damage, int[] armorIndices) { + if (damage > 0.0F) { + damage /= 4.0F; + if (damage < 1.0F) { + damage = 1.0F; + } + + for (int index : armorIndices) { + ItemStack itemstack = this.armor.get(index); + if ((!damagesource.isFire() || !itemstack.getItem().isFireResistant()) && itemstack.getItem() instanceof ArmorItem) { + itemstack.hurtAndBreak((int) damage, this.player, localPlayer -> localPlayer.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index))); + } + } + } + } + + @Override + public void dropAll() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + ItemStack itemstack = compartment.get(i); + if (!itemstack.isEmpty()) { + this.player.drop(itemstack, true, false); + compartment.set(i, ItemStack.EMPTY); + } + } + } + } + + @Override + public void setChanged() { + super.setChanged(); + } + + @Override + public int getTimesChanged() { + return super.getTimesChanged(); + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public boolean contains(ItemStack itemstack) { + return contains(itemStack -> itemStack.isEmpty() && itemStack.sameItem(itemstack)); + } + + @Override + public boolean contains(Tag tag) { + return contains(itemStack -> !itemStack.isEmpty() && itemStack.is(tag)); + } + + @Override + public void replaceWith(Inventory inventory) { + Function getter; + + if (inventory instanceof SpecialPlayerInventory specialPlayerInventory) { + getter = specialPlayerInventory::getRawItem; + } else { + getter = inventory::getItem; + } + + for(int i = 0; i < this.getContainerSize(); ++i) { + this.setRawItem(i, getter.apply(i)); + } + + this.selected = inventory.selected; + } + + @Override + public void clearContent() { + for (NonNullList compartment : this.compartments) { + compartment.clear(); + } + } + + @Override + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountSimpleStack(itemstack); + } + } + + @Override + public ItemStack removeFromSelected(boolean dropWholeStack) { + ItemStack itemstack = this.getSelected(); + return itemstack.isEmpty() ? ItemStack.EMPTY : this.removeItem(this.selected, dropWholeStack ? itemstack.getCount() : 1); + } + +} diff --git a/pom.xml b/pom.xml index ef04ab1..ceb20dd 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,7 @@ api plugin internal/v1_17_R1 + internal/v1_18_R1 assembly -- 2.49.1 From 98fbcebfd950c9db6faf7b713c0b6b5b58c38ab8 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Thu, 2 Dec 2021 15:44:19 -0500 Subject: [PATCH 042/139] Fix non-translatable component, wrong flag value --- .../openinv/internal/v1_17_R1/AnySilentContainer.java | 8 ++++---- internal/v1_18_R1/pom.xml | 2 +- .../openinv/internal/v1_18_R1/AnySilentContainer.java | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java index 514aa92..53feec8 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java @@ -24,7 +24,7 @@ import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayerGameMode; @@ -147,7 +147,7 @@ public class AnySilentContainer implements IAnySilentContainer { MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); int rows = enderChest.getContainerSize() / 9; return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); - }, new TextComponent("container.enderchest"))); + }, new TranslatableComponent("container.enderchest"))); bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); return true; } @@ -161,8 +161,8 @@ public class AnySilentContainer implements IAnySilentContainer { if (block instanceof ChestBlock chestBlock) { - // boolean flag: check if chest is blocked - Optional menuOptional = chestBlock.combine(blockState, level, blockPos, false).apply( + // boolean flag: do not check if chest is blocked + Optional menuOptional = chestBlock.combine(blockState, level, blockPos, true).apply( // Combiner is a copy of private ChestBlock.MENU_PROVIDER_COMBINER new DoubleBlockCombiner.Combiner>() { @Override diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_18_R1/pom.xml index 8629e1e..e702bb0 100644 --- a/internal/v1_18_R1/pom.xml +++ b/internal/v1_18_R1/pom.xml @@ -32,7 +32,7 @@ 17 17 - 1.18-pre5-R0.1-SNAPSHOT + 1.18-R0.1-SNAPSHOT diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java index a1d8272..793283b 100644 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java @@ -24,7 +24,7 @@ import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayerGameMode; @@ -140,14 +140,14 @@ public class AnySilentContainer implements IAnySilentContainer { } if (blockEntity instanceof EnderChestBlockEntity enderChestTile) { - // Anychest ender chest. See net.minecraft.world.level.block.BlockEnderChest + // Anychest ender chest. See net.minecraft.world.level.block.EnderChestBlock PlayerEnderChestContainer enderChest = player.getEnderChestInventory(); enderChest.setActiveChest(enderChestTile); player.openMenu(new SimpleMenuProvider((containerCounter, playerInventory, ignored) -> { MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); int rows = enderChest.getContainerSize() / 9; return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); - }, new TextComponent("container.enderchest"))); + }, new TranslatableComponent("container.enderchest"))); bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); return true; } @@ -161,8 +161,8 @@ public class AnySilentContainer implements IAnySilentContainer { if (block instanceof ChestBlock chestBlock) { - // boolean flag: check if chest is blocked - Optional menuOptional = chestBlock.combine(blockState, level, blockPos, false).apply( + // boolean flag: do not check if chest is blocked + Optional menuOptional = chestBlock.combine(blockState, level, blockPos, true).apply( // Combiner is a copy of private ChestBlock.MENU_PROVIDER_COMBINER new DoubleBlockCombiner.Combiner>() { @Override -- 2.49.1 From 160ae47bf534a0f86e4859fe1f8415eaed8a8ed4 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Thu, 2 Dec 2021 16:12:53 -0500 Subject: [PATCH 043/139] Correct wrong item list usage --- .../v1_17_R1/SpecialPlayerInventory.java | 27 +++++++++++++++++-- .../v1_18_R1/SpecialPlayerInventory.java | 27 +++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java index 8b2f24a..3fc5c02 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java @@ -19,6 +19,7 @@ package com.lishid.openinv.internal.v1_17_R1; import com.google.common.collect.ImmutableList; import com.lishid.openinv.internal.ISpecialPlayerInventory; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; @@ -113,11 +114,33 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI } private @NotNull ItemStack getRawItem(int i) { - return super.getItem(i); + if (i < 0) { + return ItemStack.EMPTY; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + return list.get(i); + } + } + + return ItemStack.EMPTY; } private void setRawItem(int i, @NotNull ItemStack itemStack) { - super.setItem(i, itemStack); + if (i < 0) { + return; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + list.set(i, itemStack); + } + } } private static record IndexedCompartment(@Nullable NonNullList compartment, int index) {} diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java index ffb96d3..9324231 100644 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java @@ -19,6 +19,7 @@ package com.lishid.openinv.internal.v1_18_R1; import com.google.common.collect.ImmutableList; import com.lishid.openinv.internal.ISpecialPlayerInventory; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; @@ -113,11 +114,33 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI } private @NotNull ItemStack getRawItem(int i) { - return super.getItem(i); + if (i < 0) { + return ItemStack.EMPTY; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + return list.get(i); + } + } + + return ItemStack.EMPTY; } private void setRawItem(int i, @NotNull ItemStack itemStack) { - super.setItem(i, itemStack); + if (i < 0) { + return; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + list.set(i, itemStack); + } + } } private static record IndexedCompartment(@Nullable NonNullList compartment, int index) {} -- 2.49.1 From 3e2b60199700fc1cd13de150f834a5e0ba6a216e Mon Sep 17 00:00:00 2001 From: Jikoo Date: Thu, 2 Dec 2021 16:15:22 -0500 Subject: [PATCH 044/139] Bump version to 4.1.9 for release --- .github/workflows/release.yml | 2 +- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_17_R1/pom.xml | 2 +- internal/v1_18_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5b78047..1a984a4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: - name: Create CurseForge Release uses: itsmeow/curseforge-upload@v3 with: - token: ${{ secrets.CURSEFORGE_TOKEN }} + token: "${{ secrets.CURSEFORGE_TOKEN }}" project_id: 31432 game_endpoint: minecraft file_path: ./OpenInv.jar diff --git a/api/pom.xml b/api/pom.xml index b8f6259..0180dcf 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.9-SNAPSHOT + 4.1.9 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 53bd6f5..7765f2f 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.9-SNAPSHOT + 4.1.9 openinvassembly diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index 613aa38..d33be5f 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.9-SNAPSHOT + 4.1.9 openinvadapter1_17_R1 diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_18_R1/pom.xml index e702bb0..0f36843 100644 --- a/internal/v1_18_R1/pom.xml +++ b/internal/v1_18_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.9-SNAPSHOT + 4.1.9 openinvadapter1_18_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index 9a8a538..efcde10 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.9-SNAPSHOT + 4.1.9 openinvplugincore diff --git a/pom.xml b/pom.xml index ceb20dd..ec7a3f3 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.9-SNAPSHOT + 4.1.9 pom @@ -81,13 +81,13 @@ openinvapi com.lishid compile - 4.1.9-SNAPSHOT + 4.1.9 openinvplugincore com.lishid compile - 4.1.9-SNAPSHOT + 4.1.9 -- 2.49.1 From 6a31015ee2a4991293b5533428455a8a51e4ed49 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Thu, 2 Dec 2021 16:15:34 -0500 Subject: [PATCH 045/139] Bump version to 4.1.10-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_17_R1/pom.xml | 2 +- internal/v1_18_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 0180dcf..eaab029 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.9 + 4.1.10-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 7765f2f..2f13444 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.9 + 4.1.10-SNAPSHOT openinvassembly diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index d33be5f..1059633 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.9 + 4.1.10-SNAPSHOT openinvadapter1_17_R1 diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_18_R1/pom.xml index 0f36843..adb2a7d 100644 --- a/internal/v1_18_R1/pom.xml +++ b/internal/v1_18_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.9 + 4.1.10-SNAPSHOT openinvadapter1_18_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index efcde10..d56caa9 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.9 + 4.1.10-SNAPSHOT openinvplugincore diff --git a/pom.xml b/pom.xml index ec7a3f3..181b7d7 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.9 + 4.1.10-SNAPSHOT pom @@ -81,13 +81,13 @@ openinvapi com.lishid compile - 4.1.9 + 4.1.10-SNAPSHOT openinvplugincore com.lishid compile - 4.1.9 + 4.1.10-SNAPSHOT -- 2.49.1 From f8fb8cd03403d76c6710d4763f73c71042af3427 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 19 Jan 2022 10:11:16 -0500 Subject: [PATCH 046/139] Reduce duplicate configuration details Adapters must now declare a `spigot.version` property. * Greatly simplifies and speeds up retrieval of Spigot versions --- internal/v1_17_R1/pom.xml | 33 +++------------------------------ internal/v1_18_R1/pom.xml | 28 ---------------------------- pom.xml | 32 +++++++++++++++++++++++++++++++- scripts/get_spigot_versions.sh | 22 +++++----------------- 4 files changed, 39 insertions(+), 76 deletions(-) diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index 1059633..789a56e 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -1,6 +1,6 @@ + unknown @@ -144,6 +146,34 @@ net.md-5 specialsource-maven-plugin 1.2.2 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:${spigot.version}:txt:maps-mojang + true + org.spigotmc:spigot:${spigot.version}:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:${spigot.version}:csrg:maps-spigot + org.spigotmc:spigot:${spigot.version}:jar:remapped-obf + + + diff --git a/scripts/get_spigot_versions.sh b/scripts/get_spigot_versions.sh index 1e079f3..c4e7b26 100644 --- a/scripts/get_spigot_versions.sh +++ b/scripts/get_spigot_versions.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (C) 2011-2021 lishid. All rights reserved. +# Copyright (C) 2011-2022 lishid. All rights reserved. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -42,22 +42,10 @@ readarray -t modules <<< "$(mvn help:evaluate -Dexpression=project.modules -q -D declare -n versions="spigot_versions" for module in "${modules[@]}"; do - # Get number of dependencies declared in pom of specified internal module. - max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl "$module" | grep -c "") - - for ((i=0; i < max_index; i++)); do - # Get artifactId of dependency. - artifact_id=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].artifactId -q -DforceStdout -P all -pl "$module") - - # Ensure dependency is Spigot. - if [[ "$artifact_id" == spigot ]]; then - # Get Spigot version. - spigot_version=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].version -q -DforceStdout -P all -pl "$module") - versions+=("$spigot_version") - echo "$spigot_version" - break - fi - done + # Get Spigot version. + spigot_version=$(mvn help:evaluate -Dexpression=spigot.version -q -DforceStdout -P all -pl "$module") + versions+=("$spigot_version") + echo "$spigot_version" done # Reset JVM parameters -- 2.49.1 From 027d4e56378d1a05be5cc538f7ceb74a2b2d8807 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 19 Jan 2022 10:21:54 -0500 Subject: [PATCH 047/139] Bump Spigot version to 1.18.1 --- internal/v1_18_R1/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_18_R1/pom.xml index 8617dca..d0486df 100644 --- a/internal/v1_18_R1/pom.xml +++ b/internal/v1_18_R1/pom.xml @@ -1,6 +1,6 @@ + + + 4.0.0 + + + openinvparent + com.lishid + ../../pom.xml + 4.1.10-SNAPSHOT + + + openinvadapter1_18_R2 + OpenInvAdapter1_18_R2 + + + 17 + 17 + 1.18.2-R0.1-SNAPSHOT + + + + + org.spigotmc + spigot-api + ${spigot.version} + + + spigot + org.spigotmc + provided + ${spigot.version} + remapped-mojang + + + openinvapi + com.lishid + + + openinvplugincore + com.lishid + + + annotations + org.jetbrains + + + + + + + maven-shade-plugin + + + false + + + + maven-compiler-plugin + + + net.md-5 + specialsource-maven-plugin + + + + + diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/AnySilentContainer.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/AnySilentContainer.java new file mode 100644 index 0000000..45930cd --- /dev/null +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/AnySilentContainer.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R2; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IAnySilentContainer; +import com.lishid.openinv.util.ReflectionHelper; +import java.lang.reflect.Field; +import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.CompoundContainer; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.monster.Shulker; +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.block.BarrelBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.DoubleBlockCombiner; +import net.minecraft.world.level.block.ShulkerBoxBlock; +import net.minecraft.world.level.block.TrappedChestBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.block.ShulkerBox; +import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AnySilentContainer implements IAnySilentContainer { + + private @Nullable Field serverPlayerGameModeGameType; + + public AnySilentContainer() { + try { + try { + // IDE warns about field not existing, but SpecialSource does not remap strings used in reflection. + // The warning is not suppressed as a reminder that it must manually be checked on updates. + this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("b"); + this.serverPlayerGameModeGameType.setAccessible(true); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("ServerPlayerGameMode#gameModeForPlayer's obfuscated name has changed!"); + logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues"); + logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail."); + // N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break. + this.serverPlayerGameModeGameType = ReflectionHelper.grabFieldByType(ServerPlayerGameMode.class, GameType.class); + } + } catch (SecurityException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to directly write player game mode! SilentContainer will fail."); + logger.log(Level.WARNING, "Error obtaining GameType field", e); + } + } + + @Override + public boolean isShulkerBlocked(ShulkerBox box) { + org.bukkit.World bukkitWorld = box.getWorld(); + if (!(bukkitWorld instanceof CraftWorld)) { + bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); + } + + if (!(bukkitWorld instanceof CraftWorld craftWorld)) { + Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); + OpenInv.getPlugin(OpenInv.class).getLogger().log(Level.WARNING, exception.getMessage(), exception); + return false; + } + + final ServerLevel world = craftWorld.getHandle(); + final BlockPos blockPosition = new BlockPos(box.getX(), box.getY(), box.getZ()); + final BlockEntity tile = world.getBlockEntity(blockPosition); + + if (!(tile instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) + || shulkerBoxBlockEntity.getAnimationStatus() != ShulkerBoxBlockEntity.AnimationStatus.CLOSED) { + return false; + } + + BlockState blockState = world.getBlockState(blockPosition); + + // See net.minecraft.world.level.block.ShulkerBoxBlock#canOpen + AABB boundingBox = Shulker.getProgressDeltaAabb(blockState.getValue(ShulkerBoxBlock.FACING), 0.0F, 0.5F) + .move(blockPosition) + .deflate(1.0E-6D); + return !world.noCollision(boundingBox); + } + + @Override + public boolean activateContainer( + @NotNull final Player bukkitPlayer, + final boolean silentchest, + @NotNull final org.bukkit.block.Block bukkitBlock) { + + // Silent ender chest is API-only + if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) { + bukkitPlayer.openInventory(bukkitPlayer.getEnderChest()); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + final ServerLevel level = player.getLevel(); + final BlockPos blockPos = new BlockPos(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + final BlockEntity blockEntity = level.getBlockEntity(blockPos); + + if (blockEntity == null) { + return false; + } + + if (blockEntity instanceof EnderChestBlockEntity enderChestTile) { + // Anychest ender chest. See net.minecraft.world.level.block.EnderChestBlock + PlayerEnderChestContainer enderChest = player.getEnderChestInventory(); + enderChest.setActiveChest(enderChestTile); + player.openMenu(new SimpleMenuProvider((containerCounter, playerInventory, ignored) -> { + MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); + int rows = enderChest.getContainerSize() / 9; + return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); + }, new TranslatableComponent("container.enderchest"))); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + if (!(blockEntity instanceof MenuProvider menuProvider)) { + return false; + } + + BlockState blockState = level.getBlockState(blockPos); + Block block = blockState.getBlock(); + + if (block instanceof ChestBlock chestBlock) { + + // boolean flag: do not check if chest is blocked + Optional menuOptional = chestBlock.combine(blockState, level, blockPos, true).apply( + // Combiner is a copy of private ChestBlock.MENU_PROVIDER_COMBINER + new DoubleBlockCombiner.Combiner>() { + @Override + public Optional acceptDouble(ChestBlockEntity localChest1, ChestBlockEntity localChest2) { + CompoundContainer doubleChest = new CompoundContainer(localChest1, localChest2); + return Optional.of(new ChestBlock.DoubleInventory(localChest1, localChest2, doubleChest)); + } + + @Override + public Optional acceptSingle(ChestBlockEntity localChest) { + return Optional.of(localChest); + } + + @Override + public Optional acceptNone() { + return Optional.empty(); + } + }); + + if (menuOptional.isEmpty()) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + + menuProvider = menuOptional.get(); + + if (block instanceof TrappedChestBlock) { + bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); + } else { + bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED); + } + } + + if (block instanceof ShulkerBoxBlock) { + bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED); + } + + if (block instanceof BarrelBlock) { + bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL); + } + + // AnyChest only - SilentChest not active, container unsupported, or unnecessary. + if (!silentchest || player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) { + player.openMenu(menuProvider); + return true; + } + + // SilentChest requires access to setting players' game mode directly. + if (this.serverPlayerGameModeGameType == null) { + return false; + } + + if (blockEntity instanceof RandomizableContainerBlockEntity lootable) { + if (lootable.lootTable != null) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + } + + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); + player.openMenu(menuProvider); + this.forceGameType(player, gameType); + return true; + } + + @Override + public void deactivateContainer(@NotNull final Player bukkitPlayer) { + if (this.serverPlayerGameModeGameType == null) { + return; + } + + InventoryView view = bukkitPlayer.getOpenInventory(); + switch (view.getType()) { + case CHEST: + case ENDER_CHEST: + case SHULKER_BOX: + case BARREL: + break; + default: + return; + } + + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + // Force game mode change without informing plugins or players. + // Regular game mode set calls GameModeChangeEvent and is cancellable. + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); + + // ServerPlayer#closeContainer cannot be called without entering an + // infinite loop because this method is called during inventory close. + // From ServerPlayer#closeContainer -> CraftEventFactory#handleInventoryCloseEvent + player.containerMenu.transferTo(player.inventoryMenu, player.getBukkitEntity()); + // From ServerPlayer#closeContainer + player.doCloseContainer(); + // Regular inventory close will handle the rest - packet sending, etc. + + // Revert forced game mode. + this.forceGameType(player, gameType); + } + + private void forceGameType(final ServerPlayer player, final GameType gameMode) { + if (this.serverPlayerGameModeGameType == null) { + // No need to warn repeatedly, error on startup and lack of function should be enough. + return; + } + try { + this.serverPlayerGameModeGameType.setAccessible(true); + this.serverPlayerGameModeGameType.set(player.gameMode, gameMode); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + +} diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java new file mode 100644 index 0000000..aeaf545 --- /dev/null +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R2; + +import java.io.File; +import net.minecraft.Util; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.storage.PlayerDataStorage; +import org.apache.logging.log4j.LogManager; +import org.bukkit.craftbukkit.v1_18_R2.CraftServer; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; + +public class OpenPlayer extends CraftPlayer { + + public OpenPlayer(CraftServer server, ServerPlayer entity) { + super(server, entity); + } + + @Override + public void loadData() { + // See CraftPlayer#loadData + CompoundTag loaded = this.server.getHandle().playerIo.load(this.getHandle()); + if (loaded != null) { + readExtraData(loaded); + } + } + + @Override + public void saveData() { + ServerPlayer player = this.getHandle(); + // See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman) + try { + PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; + + CompoundTag playerData = player.saveWithoutId(new CompoundTag()); + setExtraData(playerData); + + if (!isOnline()) { + // Special case: save old vehicle data + CompoundTag oldData = worldNBTStorage.load(player); + + if (oldData != null && oldData.contains("RootVehicle", 10)) { + // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound) + playerData.put("RootVehicle", oldData.getCompound("RootVehicle")); + } + } + + File file = File.createTempFile(player.getStringUUID() + "-", ".dat", worldNBTStorage.getPlayerDir()); + NbtIo.writeCompressed(playerData, file); + File file1 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat"); + File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); + Util.safeReplaceFile(file1, file, file2); + } catch (Exception e) { + LogManager.getLogger().warn("Failed to save player data for {}", player.getName().getString()); + } + } + +} diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java new file mode 100644 index 0000000..40d6e8e --- /dev/null +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R2; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IPlayerDataManager; +import com.lishid.openinv.internal.ISpecialInventory; +import com.lishid.openinv.internal.OpenInventoryView; +import com.mojang.authlib.GameProfile; +import java.lang.reflect.Field; +import java.util.logging.Logger; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.craftbukkit.v1_18_R2.CraftServer; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_18_R2.event.CraftEventFactory; +import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftContainer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PlayerDataManager implements IPlayerDataManager { + + private @Nullable Field bukkitEntity; + + public PlayerDataManager() { + try { + bukkitEntity = Entity.class.getDeclaredField("bukkitEntity"); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded."); + logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); + bukkitEntity = null; + } + } + + public static @NotNull ServerPlayer getHandle(final Player player) { + if (player instanceof CraftPlayer) { + return ((CraftPlayer) player).getHandle(); + } + + Server server = player.getServer(); + ServerPlayer nmsPlayer = null; + + if (server instanceof CraftServer) { + nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getUniqueId()); + } + + if (nmsPlayer == null) { + // Could use reflection to examine fields, but it's honestly not worth the bother. + throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation"); + } + + return nmsPlayer; + } + + @Override + public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { + // Ensure player has data + if (!offline.hasPlayedBefore()) { + return null; + } + + // Create a profile and entity to load the player data + // See net.minecraft.server.PlayerList#attemptLogin + GameProfile profile = new GameProfile(offline.getUniqueId(), + offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel worldServer = server.getLevel(Level.OVERWORLD); + + if (worldServer == null) { + return null; + } + + ServerPlayer entity = new ServerPlayer(server, worldServer, profile); + + try { + injectPlayer(entity); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + // Get the bukkit entity + Player target = entity.getBukkitEntity(); + if (target != null) { + // Load data + target.loadData(); + } + // Return the entity + return target; + } + + void injectPlayer(ServerPlayer player) throws IllegalAccessException { + if (bukkitEntity == null) { + return; + } + + bukkitEntity.setAccessible(true); + + bukkitEntity.set(player, new OpenPlayer(player.server.server, player)); + } + + @NotNull + @Override + public Player inject(@NotNull Player player) { + try { + ServerPlayer nmsPlayer = getHandle(player); + injectPlayer(nmsPlayer); + return nmsPlayer.getBukkitEntity(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return player; + } + } + + @Nullable + @Override + public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) { + + ServerPlayer nmsPlayer = getHandle(player); + + if (nmsPlayer.connection == null) { + return null; + } + + InventoryView view = getView(player, inventory); + + if (view == null) { + return player.openInventory(inventory.getBukkitInventory()); + } + + AbstractContainerMenu container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { + @Override + public MenuType getType() { + return getContainers(inventory.getBukkitInventory().getSize()); + } + }; + + container.setTitle(new TextComponent(view.getTitle())); + container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); + + if (container == null) { + return null; + } + + nmsPlayer.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), + new TextComponent(container.getBukkitView().getTitle()))); + nmsPlayer.containerMenu = container; + nmsPlayer.initMenu(container); + + return container.getBukkitView(); + + } + + private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) { + if (inventory instanceof SpecialEnderChest) { + return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest"); + } else if (inventory instanceof SpecialPlayerInventory) { + return new OpenInventoryView(player, inventory, "container.player", "'s Inventory"); + } else { + return null; + } + } + + static @NotNull MenuType getContainers(int inventorySize) { + + return switch (inventorySize) { + case 9 -> MenuType.GENERIC_9x1; + case 18 -> MenuType.GENERIC_9x2; + case 36 -> MenuType.GENERIC_9x4; // PLAYER + case 41, 45 -> MenuType.GENERIC_9x5; + case 54 -> MenuType.GENERIC_9x6; + default -> MenuType.GENERIC_9x3; // Default 27-slot inventory + }; + } + + @Override + public int convertToPlayerSlot(InventoryView view, int rawSlot) { + int topSize = view.getTopInventory().getSize(); + if (topSize <= rawSlot) { + // Slot is not inside special inventory, use Bukkit logic. + return view.convertSlot(rawSlot); + } + + // Main inventory, slots 0-26 -> 9-35 + if (rawSlot < 27) { + return rawSlot + 9; + } + // Hotbar, slots 27-35 -> 0-8 + if (rawSlot < 36) { + return rawSlot - 27; + } + // Armor, slots 36-39 -> 39-36 + if (rawSlot < 40) { + return 36 + (39 - rawSlot); + } + // Off hand + if (rawSlot == 40) { + return 40; + } + // Drop slots, "out of inventory" + return -1; + } + +} diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java new file mode 100644 index 0000000..d9518f5 --- /dev/null +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R2; + +import com.lishid.openinv.internal.ISpecialEnderChest; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.ContainerListener; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpecialEnderChest { + + private final CraftInventory inventory; + private ServerPlayer owner; + private NonNullList items; + private boolean playerOnline; + + public SpecialEnderChest(final org.bukkit.entity.Player player, final Boolean online) { + super(PlayerDataManager.getHandle(player)); + this.inventory = new CraftInventory(this); + this.owner = PlayerDataManager.getHandle(player); + this.playerOnline = online; + this.items = this.owner.getEnderChestInventory().items; + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return inventory; + } + + @Override + public boolean isInUse() { + return !this.getViewers().isEmpty(); + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public void setPlayerOnline(@NotNull final org.bukkit.entity.Player player) { + if (!this.playerOnline) { + try { + this.owner = PlayerDataManager.getHandle(player); + PlayerEnderChestContainer enderChest = owner.getEnderChestInventory(); + for (int i = 0; i < enderChest.getContainerSize(); ++i) { + enderChest.setItem(i, this.items.get(i)); + } + this.items = enderChest.items; + enderChest.transaction.addAll(this.transaction); + } catch (Exception ignored) {} + this.playerOnline = true; + } + } + + @Override + public @NotNull org.bukkit.entity.Player getPlayer() { + return owner.getBukkitEntity(); + } + + @Override + public void setChanged() { + this.owner.getEnderChestInventory().setChanged(); + } + + @Override + public List getContents() { + return this.items; + } + + @Override + public void onOpen(CraftHumanEntity who) { + this.owner.getEnderChestInventory().onOpen(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + this.owner.getEnderChestInventory().onClose(who); + } + + @Override + public List getViewers() { + return this.owner.getEnderChestInventory().getViewers(); + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public void setActiveChest(EnderChestBlockEntity enderChest) { + this.owner.getEnderChestInventory().setActiveChest(enderChest); + } + + @Override + public boolean isActiveChest(EnderChestBlockEntity enderChest) { + return this.owner.getEnderChestInventory().isActiveChest(enderChest); + } + + @Override + public int getMaxStackSize() { + return this.owner.getEnderChestInventory().getMaxStackSize(); + } + + @Override + public void setMaxStackSize(int i) { + this.owner.getEnderChestInventory().setMaxStackSize(i); + } + + @Override + public InventoryHolder getOwner() { + return this.owner.getEnderChestInventory().getOwner(); + } + + @Override + public @Nullable Location getLocation() { + return null; + } + + @Override + public void addListener(ContainerListener listener) { + this.owner.getEnderChestInventory().addListener(listener); + } + + @Override + public void removeListener(ContainerListener listener) { + this.owner.getEnderChestInventory().removeListener(listener); + } + + @Override + public ItemStack getItem(int i) { + return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.EMPTY; + } + + @Override + public ItemStack removeItem(int i, int j) { + ItemStack itemstack = ContainerHelper.removeItem(this.items, i, j); + if (!itemstack.isEmpty()) { + this.setChanged(); + } + + return itemstack; + } + + @Override + public ItemStack addItem(ItemStack itemstack) { + ItemStack localItem = itemstack.copy(); + this.moveItemToOccupiedSlotsWithSameType(localItem); + if (localItem.isEmpty()) { + return ItemStack.EMPTY; + } else { + this.moveItemToEmptySlots(localItem); + return localItem.isEmpty() ? ItemStack.EMPTY : localItem; + } + } + + @Override + public boolean canAddItem(ItemStack itemstack) { + for (ItemStack itemstack1 : this.items) { + if (itemstack1.isEmpty() || ItemStack.isSameItemSameTags(itemstack1, itemstack) && itemstack1.getCount() < itemstack1.getMaxStackSize()) { + return true; + } + } + + return false; + } + + private void moveItemToEmptySlots(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (localItem.isEmpty()) { + this.setItem(i, itemstack.copy()); + itemstack.setCount(0); + return; + } + } + } + + private void moveItemToOccupiedSlotsWithSameType(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (ItemStack.isSameItemSameTags(localItem, itemstack)) { + this.moveItemsBetweenStacks(itemstack, localItem); + if (itemstack.isEmpty()) { + return; + } + } + } + } + + private void moveItemsBetweenStacks(ItemStack itemstack, ItemStack itemstack1) { + int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize()); + int j = Math.min(itemstack.getCount(), i - itemstack1.getCount()); + if (j > 0) { + itemstack1.grow(j); + itemstack.shrink(j); + this.setChanged(); + } + } + + @Override + public ItemStack removeItemNoUpdate(int i) { + ItemStack itemstack = this.items.get(i); + if (itemstack.isEmpty()) { + return ItemStack.EMPTY; + } else { + this.items.set(i, ItemStack.EMPTY); + return itemstack; + } + } + + @Override + public void setItem(int i, ItemStack itemstack) { + this.items.set(i, itemstack); + if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { + itemstack.setCount(this.getMaxStackSize()); + } + + this.setChanged(); + } + + @Override + public int getContainerSize() { + return this.owner.getEnderChestInventory().getContainerSize(); + } + + @Override + public boolean isEmpty() { + return this.items.stream().allMatch(ItemStack::isEmpty); + } + + @Override + public void startOpen(Player player) { + } + + @Override + public void stopOpen(Player player) { + } + + @Override + public boolean canPlaceItem(int i, ItemStack itemstack) { + return true; + } + + @Override + public void clearContent() { + this.items.clear(); + this.setChanged(); + } + + @Override + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountStack(itemstack); + } + + } + + @Override + public List removeAllItems() { + List list = this.items.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList()); + this.clearContent(); + return list; + } + + @Override + public ItemStack removeItemType(Item item, int i) { + ItemStack itemstack = new ItemStack(item, 0); + + for(int j = this.getContainerSize() - 1; j >= 0; --j) { + ItemStack localItem = this.getItem(j); + if (localItem.getItem().equals(item)) { + int k = i - itemstack.getCount(); + ItemStack splitItem = localItem.split(k); + itemstack.grow(splitItem.getCount()); + if (itemstack.getCount() == i) { + break; + } + } + } + + if (!itemstack.isEmpty()) { + this.setChanged(); + } + + return itemstack; + } + + @Override + public String toString() { + return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).collect(Collectors.toList()).toString(); + } + + @Override + public void fromTag(ListTag listTag) { + for (int i = 0; i < this.getContainerSize(); ++i) { + this.setItem(i, ItemStack.EMPTY); + } + + for (int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + if (j < this.getContainerSize()) { + this.setItem(j, ItemStack.of(compoundTag)); + } + } + + } + +} diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java new file mode 100644 index 0000000..3b410e9 --- /dev/null +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java @@ -0,0 +1,794 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_18_R2; + +import com.google.common.collect.ImmutableList; +import com.lishid.openinv.internal.ISpecialPlayerInventory; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.tags.TagKey; +import net.minecraft.world.Container; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerInventory { + + private final CraftInventory inventory; + private boolean playerOnline; + private Player player; + private NonNullList items; + private NonNullList armor; + private NonNullList offhand; + private List> compartments; + + public SpecialPlayerInventory(@NotNull org.bukkit.entity.Player bukkitPlayer, @NotNull Boolean online) { + super(PlayerDataManager.getHandle(bukkitPlayer)); + this.inventory = new CraftInventory(this); + this.playerOnline = online; + this.player = super.player; + this.selected = player.getInventory().selected; + this.items = this.player.getInventory().items; + this.armor = this.player.getInventory().armor; + this.offhand = this.player.getInventory().offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + } + + @Override + public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) { + if (!this.playerOnline) { + Player entityPlayer = PlayerDataManager.getHandle(player); + entityPlayer.getInventory().transaction.addAll(this.transaction); + this.player = entityPlayer; + for (int i = 0; i < getContainerSize(); ++i) { + this.player.getInventory().setItem(i, getRawItem(i)); + } + this.player.getInventory().selected = this.selected; + this.items = this.player.getInventory().items; + this.armor = this.player.getInventory().armor; + this.offhand = this.player.getInventory().offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + this.playerOnline = true; + } + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return this.inventory; + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public boolean isInUse() { + List viewers = this.getViewers(); + return viewers.size() > 1 || !viewers.isEmpty() && !viewers.get(0).getUniqueId().equals(this.player.getUUID()); + } + + @Override + public @NotNull HumanEntity getPlayer() { + return this.player.getBukkitEntity(); + } + + private @NotNull ItemStack getRawItem(int i) { + if (i < 0) { + return ItemStack.EMPTY; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + return list.get(i); + } + } + + return ItemStack.EMPTY; + } + + private void setRawItem(int i, @NotNull ItemStack itemStack) { + if (i < 0) { + return; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + list.set(i, itemStack); + } + } + } + + private static record IndexedCompartment(@Nullable NonNullList compartment, int index) {} + + private @NotNull SpecialPlayerInventory.IndexedCompartment getIndexedContent(int index) { + if (index < items.size()) { + return new IndexedCompartment(items, getReversedItemSlotNum(index)); + } + + index -= items.size(); + + if (index < armor.size()) { + return new IndexedCompartment(armor, getReversedArmorSlotNum(index)); + } + + index -= armor.size(); + + if (index < offhand.size()) { + return new IndexedCompartment(offhand, index); + } + + index -= offhand.size(); + + return new IndexedCompartment(null, index); + } + + private int getReversedArmorSlotNum(final int i) { + if (i == 0) { + return 3; + } + if (i == 1) { + return 2; + } + if (i == 2) { + return 1; + } + if (i == 3) { + return 0; + } + return i; + } + + private int getReversedItemSlotNum(final int i) { + if (i >= 27) { + return i - 27; + } + return i + 9; + } + + private boolean contains(Predicate predicate) { + return this.compartments.stream().flatMap(NonNullList::stream).anyMatch(predicate); + } + + @Override + public List getArmorContents() { + return this.armor; + } + + @Override + public void onOpen(CraftHumanEntity who) { + this.player.getInventory().onOpen(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + this.player.getInventory().onClose(who); + } + + @Override + public List getViewers() { + return this.player.getInventory().getViewers(); + } + + @Override + public InventoryHolder getOwner() { + return this.player.getBukkitEntity(); + } + + @Override + public int getMaxStackSize() { + return this.player.getInventory().getMaxStackSize(); + } + + @Override + public void setMaxStackSize(int size) { + this.player.getInventory().setMaxStackSize(size); + } + + @Override + public Location getLocation() { + return this.player.getBukkitEntity().getLocation(); + } + + @Override + public boolean hasCustomName() { + return false; + } + + @Override + public List getContents() { + return this.compartments.stream().flatMap(Collection::stream).collect(Collectors.toList()); + } + + @Override + public ItemStack getSelected() { + return isHotbarSlot(this.selected) ? this.items.get(this.selected) : ItemStack.EMPTY; + } + + private boolean hasRemainingSpaceForItem(ItemStack itemstack, ItemStack itemstack1) { + return !itemstack.isEmpty() && ItemStack.isSameItemSameTags(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); + } + + @Override + public int canHold(ItemStack itemstack) { + int remains = itemstack.getCount(); + + for (int i = 0; i < this.items.size(); ++i) { + ItemStack itemstack1 = this.getRawItem(i); + if (itemstack1.isEmpty()) { + return itemstack.getCount(); + } + + if (this.hasRemainingSpaceForItem(itemstack1, itemstack)) { + remains -= (itemstack1.getMaxStackSize() < this.getMaxStackSize() ? itemstack1.getMaxStackSize() : this.getMaxStackSize()) - itemstack1.getCount(); + } + + if (remains <= 0) { + return itemstack.getCount(); + } + } + + ItemStack offhandItemStack = this.getRawItem(this.items.size() + this.armor.size()); + if (this.hasRemainingSpaceForItem(offhandItemStack, itemstack)) { + remains -= (offhandItemStack.getMaxStackSize() < this.getMaxStackSize() ? offhandItemStack.getMaxStackSize() : this.getMaxStackSize()) - offhandItemStack.getCount(); + } + + return remains <= 0 ? itemstack.getCount() : itemstack.getCount() - remains; + } + + @Override + public int getFreeSlot() { + for(int i = 0; i < this.items.size(); ++i) { + if (this.items.get(i).isEmpty()) { + return i; + } + } + + return -1; + } + + @Override + public void setPickedItem(ItemStack itemstack) { + int i = this.findSlotMatchingItem(itemstack); + if (isHotbarSlot(i)) { + this.selected = i; + } else if (i == -1) { + this.selected = this.getSuitableHotbarSlot(); + if (!this.items.get(this.selected).isEmpty()) { + int j = this.getFreeSlot(); + if (j != -1) { + this.items.set(j, this.items.get(this.selected)); + } + } + + this.items.set(this.selected, itemstack); + } else { + this.pickSlot(i); + } + + } + + @Override + public void pickSlot(int i) { + this.selected = this.getSuitableHotbarSlot(); + ItemStack itemstack = this.items.get(this.selected); + this.items.set(this.selected, this.items.get(i)); + this.items.set(i, itemstack); + } + + @Override + public int findSlotMatchingItem(ItemStack itemstack) { + for(int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemstack, this.items.get(i))) { + return i; + } + } + + return -1; + } + + @Override + public int findSlotMatchingUnusedItem(ItemStack itemStack) { + for(int i = 0; i < this.items.size(); ++i) { + ItemStack localItem = this.items.get(i); + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemStack, this.items.get(i)) && !this.items.get(i).isDamaged() && !localItem.isEnchanted() && !localItem.hasCustomHoverName()) { + return i; + } + } + + return -1; + } + + @Override + public int getSuitableHotbarSlot() { + int i; + int j; + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (this.items.get(i).isEmpty()) { + return i; + } + } + + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (!this.items.get(i).isEnchanted()) { + return i; + } + } + + return this.selected; + } + + @Override + public void swapPaint(double d0) { + if (d0 > 0.0D) { + d0 = 1.0D; + } + + if (d0 < 0.0D) { + d0 = -1.0D; + } + + this.selected = (int) (this.selected - d0); + + while (this.selected < 0) { + this.selected += 9; + } + + while(this.selected >= 9) { + this.selected -= 9; + } + } + + @Override + public int clearOrCountMatchingItems(Predicate predicate, int i, Container container) { + byte b0 = 0; + boolean flag = i == 0; + int j = b0 + ContainerHelper.clearOrCountMatchingItems(this, predicate, i - b0, flag); + j += ContainerHelper.clearOrCountMatchingItems(container, predicate, i - j, flag); + ItemStack itemstack = this.player.containerMenu.getCarried(); + j += ContainerHelper.clearOrCountMatchingItems(itemstack, predicate, i - j, flag); + if (itemstack.isEmpty()) { + this.player.containerMenu.setCarried(ItemStack.EMPTY); + } + + return j; + } + + private int addResource(ItemStack itemstack) { + int i = this.getSlotWithRemainingSpace(itemstack); + if (i == -1) { + i = this.getFreeSlot(); + } + + return i == -1 ? itemstack.getCount() : this.addResource(i, itemstack); + } + + private int addResource(int i, ItemStack itemstack) { + Item item = itemstack.getItem(); + int j = itemstack.getCount(); + ItemStack localItemStack = this.getRawItem(i); + if (localItemStack.isEmpty()) { + localItemStack = new ItemStack(item, 0); + if (itemstack.hasTag()) { + // hasTag ensures tag not null + //noinspection ConstantConditions + localItemStack.setTag(itemstack.getTag().copy()); + } + + this.setRawItem(i, localItemStack); + } + + int k = Math.min(j, localItemStack.getMaxStackSize() - localItemStack.getCount()); + + if (k > this.getMaxStackSize() - localItemStack.getCount()) { + k = this.getMaxStackSize() - localItemStack.getCount(); + } + + if (k != 0) { + j -= k; + localItemStack.grow(k); + localItemStack.setPopTime(5); + } + + return j; + } + + @Override + public int getSlotWithRemainingSpace(ItemStack itemstack) { + if (this.hasRemainingSpaceForItem(this.getRawItem(this.selected), itemstack)) { + return this.selected; + } else if (this.hasRemainingSpaceForItem(this.getRawItem(40), itemstack)) { + return 40; + } else { + for(int i = 0; i < this.items.size(); ++i) { + if (this.hasRemainingSpaceForItem(this.items.get(i), itemstack)) { + return i; + } + } + + return -1; + } + } + + @Override + public void tick() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (!compartment.get(i).isEmpty()) { + compartment.get(i).inventoryTick(this.player.level, this.player, i, this.selected == i); + } + } + } + + } + + @Override + public boolean add(ItemStack itemStack) { + return this.add(-1, itemStack); + } + + @Override + public boolean add(int i, ItemStack itemStack) { + if (itemStack.isEmpty()) { + return false; + } else { + try { + if (itemStack.isDamaged()) { + if (i == -1) { + i = this.getFreeSlot(); + } + + if (i >= 0) { + this.items.set(i, itemStack.copy()); + this.items.get(i).setPopTime(5); + itemStack.setCount(0); + return true; + } else if (this.player.getAbilities().instabuild) { + itemStack.setCount(0); + return true; + } else { + return false; + } + } else { + int j; + do { + j = itemStack.getCount(); + if (i == -1) { + itemStack.setCount(this.addResource(itemStack)); + } else { + itemStack.setCount(this.addResource(i, itemStack)); + } + } while(!itemStack.isEmpty() && itemStack.getCount() < j); + + if (itemStack.getCount() == j && this.player.getAbilities().instabuild) { + itemStack.setCount(0); + return true; + } else { + return itemStack.getCount() < j; + } + } + } catch (Throwable var6) { + CrashReport crashReport = CrashReport.forThrowable(var6, "Adding item to inventory"); + CrashReportCategory crashReportCategory = crashReport.addCategory("Item being added"); + crashReportCategory.setDetail("Item ID", Item.getId(itemStack.getItem())); + crashReportCategory.setDetail("Item data", itemStack.getDamageValue()); + crashReportCategory.setDetail("Item name", () -> itemStack.getHoverName().getString()); + throw new ReportedException(crashReport); + } + } + } + + @Override + public void placeItemBackInInventory(ItemStack itemStack) { + this.placeItemBackInInventory(itemStack, true); + } + + @Override + public void placeItemBackInInventory(ItemStack itemStack, boolean flag) { + while(true) { + if (!itemStack.isEmpty()) { + int i = this.getSlotWithRemainingSpace(itemStack); + if (i == -1) { + i = this.getFreeSlot(); + } + + if (i != -1) { + int j = itemStack.getMaxStackSize() - this.getRawItem(i).getCount(); + if (this.add(i, itemStack.split(j)) && flag && this.player instanceof ServerPlayer) { + ((ServerPlayer)this.player).connection.send(new ClientboundContainerSetSlotPacket(-2, 0, i, this.getRawItem(i))); + } + continue; + } + + this.player.drop(itemStack, false); + } + + return; + } + } + + @Override + public ItemStack removeItem(int rawIndex, final int j) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null + || indexedCompartment.compartment().get(indexedCompartment.index()).isEmpty()) { + return ItemStack.EMPTY; + } + + return ContainerHelper.removeItem(indexedCompartment.compartment(), indexedCompartment.index(), j); + } + + @Override + public void removeItem(ItemStack itemStack) { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (compartment.get(i) == itemStack) { + compartment.set(i, ItemStack.EMPTY); + break; + } + } + } + } + + @Override + public ItemStack removeItemNoUpdate(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + ItemStack removed = indexedCompartment.compartment().set(indexedCompartment.index(), ItemStack.EMPTY); + + if (removed.isEmpty()) { + return ItemStack.EMPTY; + } + + return removed; + } + + @Override + public void setItem(int rawIndex, final ItemStack itemStack) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + this.player.drop(itemStack, true); + return; + } + + indexedCompartment.compartment().set(indexedCompartment.index(), itemStack); + } + + @Override + public float getDestroySpeed(BlockState blockState) { + return this.items.get(this.selected).getDestroySpeed(blockState); + } + + @Override + public ListTag save(ListTag listTag) { + for (int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)i); + this.items.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.armor.size(); ++i) { + if (!this.armor.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 100)); + this.armor.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.offhand.size(); ++i) { + if (!this.offhand.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 150)); + this.offhand.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + return listTag; + } + + @Override + public void load(ListTag listTag) { + this.items.clear(); + this.armor.clear(); + this.offhand.clear(); + + for(int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + ItemStack itemstack = ItemStack.of(compoundTag); + if (!itemstack.isEmpty()) { + if (j < this.items.size()) { + this.items.set(j, itemstack); + } else if (j >= 100 && j < this.armor.size() + 100) { + this.armor.set(j - 100, itemstack); + } else if (j >= 150 && j < this.offhand.size() + 150) { + this.offhand.set(j - 150, itemstack); + } + } + } + + } + + @Override + public int getContainerSize() { + return 45; + } + + @Override + public boolean isEmpty() { + return !contains(itemStack -> !itemStack.isEmpty()); + } + + @Override + public ItemStack getItem(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + return indexedCompartment.compartment().get(indexedCompartment.index()); + } + + @Override + public Component getName() { + return this.player.getName(); + } + + @Override + public ItemStack getArmor(int index) { + return this.armor.get(index); + } + + @Override + public void hurtArmor(DamageSource damagesource, float damage, int[] armorIndices) { + if (damage > 0.0F) { + damage /= 4.0F; + if (damage < 1.0F) { + damage = 1.0F; + } + + for (int index : armorIndices) { + ItemStack itemstack = this.armor.get(index); + if ((!damagesource.isFire() || !itemstack.getItem().isFireResistant()) && itemstack.getItem() instanceof ArmorItem) { + itemstack.hurtAndBreak((int) damage, this.player, localPlayer -> localPlayer.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index))); + } + } + } + } + + @Override + public void dropAll() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + ItemStack itemstack = compartment.get(i); + if (!itemstack.isEmpty()) { + this.player.drop(itemstack, true, false); + compartment.set(i, ItemStack.EMPTY); + } + } + } + } + + @Override + public void setChanged() { + super.setChanged(); + } + + @Override + public int getTimesChanged() { + return super.getTimesChanged(); + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public boolean contains(ItemStack itemstack) { + return contains(itemStack -> itemStack.isEmpty() && itemStack.sameItem(itemstack)); + } + + @Override + public boolean contains(TagKey tagKey) { + + return contains(itemStack -> !itemStack.isEmpty() && itemStack.is(tagKey)); + } + + @Override + public void replaceWith(Inventory inventory) { + Function getter; + + if (inventory instanceof SpecialPlayerInventory specialPlayerInventory) { + getter = specialPlayerInventory::getRawItem; + } else { + getter = inventory::getItem; + } + + for(int i = 0; i < this.getContainerSize(); ++i) { + this.setRawItem(i, getter.apply(i)); + } + + this.selected = inventory.selected; + } + + @Override + public void clearContent() { + for (NonNullList compartment : this.compartments) { + compartment.clear(); + } + } + + @Override + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountSimpleStack(itemstack); + } + } + + @Override + public ItemStack removeFromSelected(boolean dropWholeStack) { + ItemStack itemstack = this.getSelected(); + return itemstack.isEmpty() ? ItemStack.EMPTY : this.removeItem(this.selected, dropWholeStack ? itemstack.getCount() : 1); + } + +} -- 2.49.1 From bb75c723a7ec2c9a0d67b7af4d8bb8d9d3ea6b42 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 28 Feb 2022 22:16:26 -0500 Subject: [PATCH 054/139] Actually build 1.18.2 module --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index d853514..25d6a29 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ plugin internal/v1_17_R1 internal/v1_18_R1 + internal/v1_18_R2 assembly -- 2.49.1 From a547ab79fb213fd84cfb4fb27ddac8fde2b44f3a Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 11 Mar 2022 08:31:11 -0500 Subject: [PATCH 055/139] Bump version to 4.1.10 for release --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_17_R1/pom.xml | 2 +- internal/v1_18_R1/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index eaab029..92d9985 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.10-SNAPSHOT + 4.1.10 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 2f13444..4f91c91 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.10-SNAPSHOT + 4.1.10 openinvassembly diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index 789a56e..28ea807 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.10-SNAPSHOT + 4.1.10 openinvadapter1_17_R1 diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_18_R1/pom.xml index d0486df..2ea2bd0 100644 --- a/internal/v1_18_R1/pom.xml +++ b/internal/v1_18_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.10-SNAPSHOT + 4.1.10 openinvadapter1_18_R1 diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 83724ee..1ffc636 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.10-SNAPSHOT + 4.1.10 openinvadapter1_18_R2 diff --git a/plugin/pom.xml b/plugin/pom.xml index d56caa9..549cff1 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.10-SNAPSHOT + 4.1.10 openinvplugincore diff --git a/pom.xml b/pom.xml index 25d6a29..313389c 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.10-SNAPSHOT + 4.1.10 pom @@ -84,13 +84,13 @@ openinvapi com.lishid compile - 4.1.10-SNAPSHOT + 4.1.10 openinvplugincore com.lishid compile - 4.1.10-SNAPSHOT + 4.1.10 -- 2.49.1 From 3103e8822b77d2292c526266f623d42a045d908a Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 11 Mar 2022 08:31:26 -0500 Subject: [PATCH 056/139] Bump version to 4.1.11-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_17_R1/pom.xml | 2 +- internal/v1_18_R1/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 92d9985..4e2a1a9 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.10 + 4.1.11-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 4f91c91..21f72f2 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.1.10 + 4.1.11-SNAPSHOT openinvassembly diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index 28ea807..f457607 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.10 + 4.1.11-SNAPSHOT openinvadapter1_17_R1 diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_18_R1/pom.xml index 2ea2bd0..866cb58 100644 --- a/internal/v1_18_R1/pom.xml +++ b/internal/v1_18_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.10 + 4.1.11-SNAPSHOT openinvadapter1_18_R1 diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 1ffc636..75363dc 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.1.10 + 4.1.11-SNAPSHOT openinvadapter1_18_R2 diff --git a/plugin/pom.xml b/plugin/pom.xml index 549cff1..a9d8ad3 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.1.10 + 4.1.11-SNAPSHOT openinvplugincore diff --git a/pom.xml b/pom.xml index 313389c..6d17320 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.1.10 + 4.1.11-SNAPSHOT pom @@ -84,13 +84,13 @@ openinvapi com.lishid compile - 4.1.10 + 4.1.11-SNAPSHOT openinvplugincore com.lishid compile - 4.1.10 + 4.1.11-SNAPSHOT -- 2.49.1 From 173f49680b6299d6a719f1a4806ec83cd1c4c964 Mon Sep 17 00:00:00 2001 From: Max Lee Date: Tue, 5 Apr 2022 23:10:58 +0200 Subject: [PATCH 057/139] Log error message when failing to save player data (#72) --- .../java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java | 2 +- .../java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java | 2 +- .../java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java index c4c17e8..a4bc700 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java @@ -67,7 +67,7 @@ public class OpenPlayer extends CraftPlayer { File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); Util.safeReplaceFile(file1, file, file2); } catch (Exception e) { - LogManager.getLogger().warn("Failed to save player data for {}", player.getName().getString()); + LogManager.getLogger().warn("Failed to save player data for {}: {}", player.getName().getString(), e.getMessage()); } } diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java index 2a0a779..adcb22c 100644 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java @@ -67,7 +67,7 @@ public class OpenPlayer extends CraftPlayer { File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); Util.safeReplaceFile(file1, file, file2); } catch (Exception e) { - LogManager.getLogger().warn("Failed to save player data for {}", player.getName().getString()); + LogManager.getLogger().warn("Failed to save player data for {}: {}", player.getName().getString(), e.getMessage()); } } diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java index aeaf545..4fdcfc0 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java @@ -67,7 +67,7 @@ public class OpenPlayer extends CraftPlayer { File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); Util.safeReplaceFile(file1, file, file2); } catch (Exception e) { - LogManager.getLogger().warn("Failed to save player data for {}", player.getName().getString()); + LogManager.getLogger().warn("Failed to save player data for {}: {}", player.getName().getString(), e.getMessage()); } } -- 2.49.1 From 22407aa8658e239e93866d1aee720108d56bb0d8 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 29 Apr 2022 13:32:48 -0400 Subject: [PATCH 058/139] Update dependencies, add Dependabot (#75) --- .github/dependabot.yml | 10 ++++++ .github/workflows/ci.yml | 64 ++++++++++++++++++++++++++------------- internal/v1_17_R1/pom.xml | 6 +--- internal/v1_18_R1/pom.xml | 6 +--- internal/v1_18_R2/pom.xml | 6 +--- pom.xml | 18 +++++++---- 6 files changed, 68 insertions(+), 42 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5ab4dca --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b190db2..5cacbe0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,25 +8,15 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: Checkout Code - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Set Up Java - uses: actions/setup-java@v2 + - uses: actions/setup-java@v3 with: distribution: 'adopt' java-version: '17' + cache: 'maven' - # Use cache to speed up build - - name: Cache Maven Repo - uses: actions/cache@v2 - id: cache - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - - # Install Spigot dependencies. - # This script uses Maven to check all required installations and ensure that they are present. + # Install Spigot dependencies if necessary. - name: Install Spigot Dependencies run: . scripts/install_spigot_dependencies.sh @@ -36,37 +26,69 @@ jobs: # Upload artifacts - name: Upload Distributable Jar id: upload-final - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: dist path: ./target/OpenInv.jar - name: Upload API Jar id: upload-api - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: api path: ./api/target/openinvapi*.jar + merge-dependabot: + name: Auto-merge Dependabot PRs + needs: [ build ] + if: github.event.name == 'pull_request_target' && github.actor == 'dependabot[bot]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + # Filter dependency changes based on path. + - uses: dorny/paths-filter@v2 + id: changes + with: + filters: | + maven: + - '**/pom.xml' + + # Only auto-merge Maven changes. + - if: steps.changes.outputs.maven == 'true' + name: Approve + uses: hmarr/auto-approve-action@v2.0.0 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + - if: steps.changes.outputs.maven == 'true' + name: Merge + uses: pascalgn/automerge-action@v0.15.2 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + MERGE_LABELS: "dependencies" + MERGE_METHOD: "squash" + release: name: Create Github Release needs: [ build ] if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: - - name: Checkout Code - uses: actions/checkout@v2 + # Fetch all history - used to assemble changelog. + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set Release Variables run: bash ./scripts/set_release_env.sh - - name: Download Artifacts - uses: actions/download-artifact@v2 + - name: Download Artifact + uses: actions/download-artifact@v3 + with: + name: dist + path: dist - name: Create Release id: create-release - uses: softprops/action-gh-release@v0.1.5 + uses: softprops/action-gh-release@v0.1.14 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index f457607..427a208 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -43,10 +43,6 @@ ${spigot.version} remapped-mojang - - openinvapi - com.lishid - openinvplugincore com.lishid @@ -61,7 +57,7 @@ maven-shade-plugin - + false diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_18_R1/pom.xml index 866cb58..3a62a7e 100644 --- a/internal/v1_18_R1/pom.xml +++ b/internal/v1_18_R1/pom.xml @@ -48,10 +48,6 @@ ${spigot.version} remapped-mojang - - openinvapi - com.lishid - openinvplugincore com.lishid @@ -66,7 +62,7 @@ maven-shade-plugin - + false diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 75363dc..0a0f429 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -48,10 +48,6 @@ ${spigot.version} remapped-mojang - - openinvapi - com.lishid - openinvplugincore com.lishid @@ -66,7 +62,7 @@ maven-shade-plugin - + false diff --git a/pom.xml b/pom.xml index 6d17320..2ef3c9f 100644 --- a/pom.xml +++ b/pom.xml @@ -27,8 +27,8 @@ UTF-8 - 1.8 - 1.8 + 16 + 16 unknown @@ -72,13 +72,13 @@ annotations org.jetbrains provided - 21.0.1 + 23.0.0 spigot-api org.spigotmc provided - 1.16.5-R0.1-SNAPSHOT + 1.17.1-R0.1-SNAPSHOT openinvapi @@ -91,6 +91,12 @@ com.lishid compile 4.1.11-SNAPSHOT + + + com.lishid + openinvapi + + @@ -128,7 +134,7 @@ org.apache.maven.plugins - 3.2.4 + 3.3.0 @@ -146,7 +152,7 @@ net.md-5 specialsource-maven-plugin - 1.2.2 + 1.2.4 package -- 2.49.1 From 7903942b51e04fdf6410ceb05a99067a8fd86c24 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 29 Apr 2022 13:40:00 -0400 Subject: [PATCH 059/139] Correct Action indentation Wish it was more clearly indicated that the action was failing anywhere but the actions tab. No notification even, kind of annoying to have actually made a PR to double-check and then still have it fail. --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5cacbe0..be78fba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,15 +56,15 @@ jobs: - if: steps.changes.outputs.maven == 'true' name: Approve uses: hmarr/auto-approve-action@v2.0.0 - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" - if: steps.changes.outputs.maven == 'true' name: Merge uses: pascalgn/automerge-action@v0.15.2 - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - MERGE_LABELS: "dependencies" - MERGE_METHOD: "squash" + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + MERGE_LABELS: "dependencies" + MERGE_METHOD: "squash" release: name: Create Github Release -- 2.49.1 From 60c1d91e25ae0f6c99007071b10d9cb6e3e3bc6d Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 29 Apr 2022 13:50:32 -0400 Subject: [PATCH 060/139] Simplify Maven check Apparently Dependabot actually manages language labels when multiple options are enabled. Convenient! --- .github/workflows/ci.yml | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be78fba..690504a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,26 +40,16 @@ jobs: merge-dependabot: name: Auto-merge Dependabot PRs needs: [ build ] - if: github.event.name == 'pull_request_target' && github.actor == 'dependabot[bot]' + if: "github.event.name == 'pull_request_target' + && github.actor == 'dependabot[bot]' + && contains( github.event.pull_request.labels.*.name, 'java')" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - # Filter dependency changes based on path. - - uses: dorny/paths-filter@v2 - id: changes - with: - filters: | - maven: - - '**/pom.xml' - - # Only auto-merge Maven changes. - - if: steps.changes.outputs.maven == 'true' - name: Approve + - name: Approve uses: hmarr/auto-approve-action@v2.0.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - - if: steps.changes.outputs.maven == 'true' - name: Merge + - name: Merge uses: pascalgn/automerge-action@v0.15.2 env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" -- 2.49.1 From cc3d96590f2dc649bcaf58008c933474b4fb509d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 13:19:34 -0400 Subject: [PATCH 061/139] Bump hmarr/auto-approve-action from 2.0.0 to 2.2.1 (#77) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 690504a..35cb2d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Approve - uses: hmarr/auto-approve-action@v2.0.0 + uses: hmarr/auto-approve-action@v2.2.1 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Merge -- 2.49.1 From d6152f2f245161771229b045df921197ca854808 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 17:28:42 -0400 Subject: [PATCH 062/139] Bump dsaltares/fetch-gh-release-asset from 0.0.5 to 1.0.0 (#83) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1a984a4..13c0997 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: fetch-depth: 0 - name: Fetch Github Release Asset - uses: dsaltares/fetch-gh-release-asset@0.0.5 + uses: dsaltares/fetch-gh-release-asset@1.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} version: ${{ github.event.release.id }} -- 2.49.1 From 65c3358b22f774f5f3047fc9f767d43bc2257afa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 17:29:37 -0400 Subject: [PATCH 063/139] Bump pascalgn/automerge-action from 0.15.2 to 0.15.3 (#82) Bumps [pascalgn/automerge-action](https://github.com/pascalgn/automerge-action) from 0.15.2 to 0.15.3. - [Release notes](https://github.com/pascalgn/automerge-action/releases) - [Commits](https://github.com/pascalgn/automerge-action/compare/v0.15.2...v0.15.3) --- updated-dependencies: - dependency-name: pascalgn/automerge-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35cb2d9..176cd38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Merge - uses: pascalgn/automerge-action@v0.15.2 + uses: pascalgn/automerge-action@v0.15.3 env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" MERGE_LABELS: "dependencies" -- 2.49.1 From 525982ce64022fcc0164e5d6a931ab3c3350dde6 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Thu, 12 May 2022 08:48:51 -0400 Subject: [PATCH 064/139] Harden event/internal access slightly --- .../openinv/{util => }/InternalAccessor.java | 94 +++++++------------ .../{listeners => }/InventoryListener.java | 17 +--- .../{listeners => }/PlayerListener.java | 20 ++-- 3 files changed, 43 insertions(+), 88 deletions(-) rename plugin/src/main/java/com/lishid/openinv/{util => }/InternalAccessor.java (70%) rename plugin/src/main/java/com/lishid/openinv/{listeners => }/InventoryListener.java (94%) rename plugin/src/main/java/com/lishid/openinv/{listeners => }/PlayerListener.java (86%) diff --git a/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java b/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java similarity index 70% rename from plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java rename to plugin/src/main/java/com/lishid/openinv/InternalAccessor.java index 399154a..dbe7e98 100644 --- a/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java +++ b/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java @@ -14,28 +14,28 @@ * along with this program. If not, see . */ -package com.lishid.openinv.util; +package com.lishid.openinv; import com.lishid.openinv.internal.IAnySilentContainer; import com.lishid.openinv.internal.IPlayerDataManager; import com.lishid.openinv.internal.ISpecialEnderChest; import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.internal.ISpecialPlayerInventory; +import com.lishid.openinv.util.InventoryAccess; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; -public class InternalAccessor { +class InternalAccessor { - private final Plugin plugin; + private final @NotNull Plugin plugin; private final String version; private boolean supported = false; private IPlayerDataManager playerDataManager; private IAnySilentContainer anySilentContainer; - public InternalAccessor(final Plugin plugin) { + InternalAccessor(@NotNull Plugin plugin) { this.plugin = plugin; String packageName = plugin.getServer().getClass().getPackage().getName(); @@ -51,58 +51,29 @@ public class InternalAccessor { } public String getReleasesLink() { - switch (version) { - case "1_4_5": - case "1_4_6": - case "v1_4_R1": - case "v1_5_R2": - case "v1_5_R3": - case "v1_6_R1": - case "v1_6_R2": - case "v1_6_R3": - case "v1_7_R1": - case "v1_7_R2": - case "v1_7_R3": - case "v1_7_R4": - case "v1_8_R1": - case "v1_8_R2": - case "v1_9_R1": - case "v1_9_R2": - case "v1_10_R1": - case "v1_11_R1": - case "v1_12_R1": - return "https://github.com/lishid/OpenInv/releases/tag/4.0.0 (OpenInv-legacy)"; - case "v1_13_R1": - return "https://github.com/lishid/OpenInv/releases/tag/4.0.0"; - case "v1_13_R2": - return "https://github.com/lishid/OpenInv/releases/tag/4.0.7"; - case "v1_14_R1": - return "https://github.com/lishid/OpenInv/releases/tag/4.1.1"; - case "v1_16_R1": - return "https://github.com/lishid/OpenInv/releases/tag/4.1.4"; - case "v1_8_R3": - case "v1_15_R1": - case "v1_16_R2": - return "https://github.com/lishid/OpenInv/releases/tag/4.1.5"; - case "v1_16_R3": - return "https://github.com/Jikoo/OpenInv/releases/tag/4.1.8"; - case "v1_17_R1": - default: - return "https://github.com/Jikoo/OpenInv/releases"; - } + + return switch (version) { + case "1_4_5", "1_4_6", "v1_4_R1", "v1_5_R2", "v1_5_R3", "v1_6_R1", "v1_6_R2", "v1_6_R3", + "v1_7_R1", "v1_7_R2", "v1_7_R3", "v1_7_R4", "v1_8_R1", "v1_8_R2", + "v1_9_R1", "v1_9_R2", "v1_10_R1", "v1_11_R1", "v1_12_R1" + -> "https://github.com/lishid/OpenInv/releases/tag/4.0.0 (OpenInv-legacy)"; + case "v1_13_R1" -> "https://github.com/lishid/OpenInv/releases/tag/4.0.0"; + case "v1_13_R2" -> "https://github.com/lishid/OpenInv/releases/tag/4.0.7"; + case "v1_14_R1" -> "https://github.com/lishid/OpenInv/releases/tag/4.1.1"; + case "v1_16_R1" -> "https://github.com/lishid/OpenInv/releases/tag/4.1.4"; + case "v1_8_R3", "v1_15_R1", "v1_16_R2" -> "https://github.com/lishid/OpenInv/releases/tag/4.1.5"; + case "v1_16_R3" -> "https://github.com/Jikoo/OpenInv/releases/tag/4.1.8"; + default -> "https://github.com/Jikoo/OpenInv/releases"; + }; } - private T createObject(final Class assignableClass, final String className, - final Object... params) throws ClassCastException, ClassNotFoundException, - InstantiationException, IllegalAccessException, IllegalArgumentException, - InvocationTargetException, NoSuchMethodException, SecurityException { + private @NotNull T createObject( + @NotNull Class assignableClass, + @NotNull String className, + @NotNull Object @NotNull ... params) + throws ClassCastException, ReflectiveOperationException { // Fetch internal class if it exists. Class internalClass = Class.forName("com.lishid.openinv.internal." + this.version + "." + className); - if (!assignableClass.isAssignableFrom(internalClass)) { - String message = String.format("Found class %s but cannot cast to %s!", internalClass.getName(), assignableClass.getName()); - this.plugin.getLogger().warning(message); - throw new IllegalStateException(message); - } // Quick return: no parameters, no need to fiddle about finding the correct constructor. if (params.length == 0) { @@ -133,10 +104,10 @@ public class InternalAccessor { String message = builder.append(']').toString(); this.plugin.getLogger().warning(message); - throw new IllegalArgumentException(message); + throw new NoSuchMethodException(message); } - private T createSpecialInventory( + private @NotNull T createSpecialInventory( @NotNull Class assignableClass, @NotNull String className, @NotNull Player player, @@ -159,7 +130,7 @@ public class InternalAccessor { * @return the IAnySilentContainer * @throws IllegalStateException if server version is unsupported */ - public IAnySilentContainer getAnySilentContainer() { + public @NotNull IAnySilentContainer getAnySilentContainer() { if (!this.supported) { throw new IllegalStateException(String.format("Unsupported server version %s!", this.version)); } @@ -172,7 +143,7 @@ public class InternalAccessor { * @return the IPlayerDataManager * @throws IllegalStateException if server version is unsupported */ - public IPlayerDataManager getPlayerDataManager() { + public @NotNull IPlayerDataManager getPlayerDataManager() { if (!this.supported) { throw new IllegalStateException(String.format("Unsupported server version %s!", this.version)); } @@ -180,13 +151,12 @@ public class InternalAccessor { } /** - * Gets the server implementation version. If not initialized, returns the string "null" - * instead. + * Gets the server implementation version. * - * @return the version, or "null" + * @return the version */ - public String getVersion() { - return this.version != null ? this.version : "null"; + public @NotNull String getVersion() { + return this.version; } /** diff --git a/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java b/plugin/src/main/java/com/lishid/openinv/InventoryListener.java similarity index 94% rename from plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java rename to plugin/src/main/java/com/lishid/openinv/InventoryListener.java index ea8dad3..8e1c27e 100644 --- a/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java +++ b/plugin/src/main/java/com/lishid/openinv/InventoryListener.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,9 +14,8 @@ * along with this program. If not, see . */ -package com.lishid.openinv.listeners; +package com.lishid.openinv; -import com.lishid.openinv.OpenInv; import com.lishid.openinv.internal.ISpecialPlayerInventory; import com.lishid.openinv.util.InventoryAccess; import com.lishid.openinv.util.Permissions; @@ -45,22 +44,14 @@ import org.jetbrains.annotations.Nullable; * * @author Jikoo */ -public class InventoryListener implements Listener { - - private final OpenInv plugin; - - public InventoryListener(final OpenInv plugin) { - this.plugin = plugin; - } +record InventoryListener(OpenInv plugin) implements Listener { @EventHandler public void onInventoryClose(@NotNull final InventoryCloseEvent event) { - if (!(event.getPlayer() instanceof Player)) { + if (!(event.getPlayer() instanceof Player player)) { return; } - Player player = (Player) event.getPlayer(); - if (this.plugin.getPlayerSilentChestStatus(player)) { this.plugin.getAnySilentContainer().deactivateContainer(player); } diff --git a/plugin/src/main/java/com/lishid/openinv/listeners/PlayerListener.java b/plugin/src/main/java/com/lishid/openinv/PlayerListener.java similarity index 86% rename from plugin/src/main/java/com/lishid/openinv/listeners/PlayerListener.java rename to plugin/src/main/java/com/lishid/openinv/PlayerListener.java index ca5a23e..4ec2950 100644 --- a/plugin/src/main/java/com/lishid/openinv/listeners/PlayerListener.java +++ b/plugin/src/main/java/com/lishid/openinv/PlayerListener.java @@ -14,9 +14,8 @@ * along with this program. If not, see . */ -package com.lishid.openinv.listeners; +package com.lishid.openinv; -import com.lishid.openinv.OpenInv; import com.lishid.openinv.util.Permissions; import org.bukkit.entity.Player; import org.bukkit.event.Event.Result; @@ -28,32 +27,27 @@ import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.jetbrains.annotations.NotNull; -public class PlayerListener implements Listener { - - private final OpenInv plugin; - - public PlayerListener(OpenInv plugin) { - this.plugin = plugin; - } +record PlayerListener(OpenInv plugin) implements Listener { @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerJoin(final PlayerJoinEvent event) { + public void onPlayerJoin(@NotNull PlayerJoinEvent event) { plugin.setPlayerOnline(event.getPlayer()); } @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerQuit(PlayerQuitEvent event) { + public void onPlayerQuit(@NotNull PlayerQuitEvent event) { plugin.setPlayerOffline(event.getPlayer()); } @EventHandler - public void onWorldChange(PlayerChangedWorldEvent event) { + public void onWorldChange(@NotNull PlayerChangedWorldEvent event) { plugin.changeWorld(event.getPlayer()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onPlayerInteract(PlayerInteractEvent event) { + public void onPlayerInteract(@NotNull PlayerInteractEvent event) { // Do not cancel 3rd party plugins' custom events if (!PlayerInteractEvent.class.equals(event.getClass())) { -- 2.49.1 From f21019eba822fca6d3dcfd211c2dc553ef50393d Mon Sep 17 00:00:00 2001 From: Jikoo Date: Thu, 12 May 2022 09:53:51 -0400 Subject: [PATCH 065/139] Extract help to location of use --- .../main/java/com/lishid/openinv/OpenInv.java | 35 ------------ .../openinv/commands/OpenInvCommand.java | 53 ++++++++++++++----- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index 680683d..238b5a2 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -510,41 +510,6 @@ public class OpenInv extends JavaPlugin implements IOpenInv { this.saveConfig(); } - /** - * Displays all applicable help for OpenInv commands. - * - * @param player the Player to help - */ - public void showHelp(final Player player) { - // Get registered commands - for (String commandName : this.getDescription().getCommands().keySet()) { - PluginCommand command = this.getCommand(commandName); - - // Ensure command is successfully registered and player can use it - if (command == null || !command.testPermissionSilent(player)) { - continue; - } - - // Send usage - player.sendMessage(command.getUsage().replace("", commandName)); - - List aliases = command.getAliases(); - if (aliases.isEmpty()) { - continue; - } - - // Assemble alias list - StringBuilder aliasBuilder = new StringBuilder(" (aliases: "); - for (String alias : aliases) { - aliasBuilder.append(alias).append(", "); - } - aliasBuilder.delete(aliasBuilder.length() - 2, aliasBuilder.length()).append(')'); - - // Send all aliases - player.sendMessage(aliasBuilder.toString()); - } - } - @Override public void unload(@NotNull final OfflinePlayer offline) { this.playerCache.invalidate(this.getPlayerID(offline)); diff --git a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java index 3eaa5e6..c97b154 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java @@ -23,9 +23,11 @@ import com.lishid.openinv.util.TabCompleter; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.StringJoiner; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; @@ -43,25 +45,24 @@ public class OpenInvCommand implements TabExecutor { @Override public boolean onCommand(@NotNull final CommandSender sender, @NotNull final Command command, @NotNull final String label, @NotNull final String[] args) { - if (!(sender instanceof Player)) { + boolean openInv = command.getName().equals("openinv"); + + if (openInv && args.length > 0 && (args[0].equalsIgnoreCase("help") || args[0].equals("?"))) { + this.showHelp(sender); + return true; + } + + if (!(sender instanceof Player player)) { plugin.sendMessage(sender, "messages.error.consoleUnsupported"); return true; } - if (args.length > 0 && (args[0].equalsIgnoreCase("help") || args[0].equals("?"))) { - this.plugin.showHelp((Player) sender); - return true; - } - - final Player player = (Player) sender; - final boolean openinv = command.getName().equals("openinv"); - // History management - String history = (openinv ? this.openInvHistory : this.openEnderHistory).get(player); + String history = (openInv ? this.openInvHistory : this.openEnderHistory).get(player); if (history == null || history.isEmpty()) { history = player.getName(); - (openinv ? this.openInvHistory : this.openEnderHistory).put(player, history); + (openInv ? this.openInvHistory : this.openEnderHistory).put(player, history); } final String name; @@ -89,7 +90,7 @@ public class OpenInvCommand implements TabExecutor { if (!player.isOnline()) { return; } - OpenInvCommand.this.openInventory(player, offlinePlayer, openinv); + OpenInvCommand.this.openInventory(player, offlinePlayer, openInv); } }.runTask(OpenInvCommand.this.plugin); @@ -99,6 +100,34 @@ public class OpenInvCommand implements TabExecutor { return true; } + private void showHelp(final CommandSender sender) { + // Get registered commands + for (String commandName : plugin.getDescription().getCommands().keySet()) { + PluginCommand command = plugin.getCommand(commandName); + + // Ensure command is successfully registered and sender can use it + if (command == null || !command.testPermissionSilent(sender)) { + continue; + } + + // Send usage + sender.sendMessage(command.getUsage().replace("", commandName)); + + List aliases = command.getAliases(); + if (!aliases.isEmpty()) { + // Assemble alias list + StringJoiner aliasJoiner = new StringJoiner(", ", " (aliases: ", ")"); + for (String alias : aliases) { + aliasJoiner.add(alias); + } + + // Send all aliases + sender.sendMessage(aliasJoiner.toString()); + } + + } + } + private void openInventory(final Player player, final OfflinePlayer target, boolean openinv) { Player onlineTarget; boolean online = target.isOnline(); -- 2.49.1 From ac00261afb8a76c99c6841d2e936ac36ea4e70fb Mon Sep 17 00:00:00 2001 From: Jikoo Date: Thu, 12 May 2022 12:18:18 -0400 Subject: [PATCH 066/139] Note Spigot requirement --- .../main/java/com/lishid/openinv/OpenInv.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index 238b5a2..3ad4f5c 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -112,6 +112,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { private InternalAccessor accessor; private LanguageManager languageManager; + private boolean isSpigot = false; /** * Evicts all viewers lacking cross-world permissions from a Player's inventory. @@ -355,8 +356,16 @@ public class OpenInv extends JavaPlugin implements IOpenInv { this.languageManager = new LanguageManager(this, "en_us"); + try { + Class.forName("org.bukkit.entity.Player$Spigot"); + isSpigot = true; + } catch (ClassNotFoundException e) { + e.printStackTrace(); + isSpigot = false; + } + // Version check - if (this.accessor.isSupported()) { + if (isSpigot && this.accessor.isSupported()) { // Update existing configuration. May require internal access. new ConfigUpdater(this).checkForUpdates(); @@ -379,8 +388,16 @@ public class OpenInv extends JavaPlugin implements IOpenInv { } private void sendVersionError(Consumer messageMethod) { - messageMethod.accept("Your server version (" + this.accessor.getVersion() + ") is not supported."); - messageMethod.accept("Please obtain an appropriate version here: " + accessor.getReleasesLink()); + if (!this.accessor.isSupported()) { + messageMethod.accept("Your server version (" + this.accessor.getVersion() + ") is not supported."); + messageMethod.accept("Please obtain an appropriate version here: " + this.accessor.getReleasesLink()); + } + if (!isSpigot) { + messageMethod.accept("OpenInv requires that you use Spigot or a Spigot fork. Per the 1.14 update thread"); + messageMethod.accept("(https://www.spigotmc.org/threads/369724/ \"A Note on CraftBukkit\"), if you are"); + messageMethod.accept("encountering an inconsistency with vanilla that prevents you from using Spigot,"); + messageMethod.accept("that is considered a Spigot bug and should be reported as such."); + } } private void setCommandExecutor(CommandExecutor executor, String... commands) { @@ -394,7 +411,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if (!this.accessor.isSupported()) { + if (!isSpigot || !this.accessor.isSupported()) { this.sendVersionError(sender::sendMessage); return true; } -- 2.49.1 From b6e8e2ba42bdb71019b87ac2a28acf82f56587c2 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 13 May 2022 09:11:12 -0400 Subject: [PATCH 067/139] Extract some duplicate code from internal implementations --- .../openinv/internal/ISpecialInventory.java | 8 +++-- .../internal/ISpecialPlayerInventory.java | 31 ++++++++++++++++++- .../internal/v1_17_R1/SpecialEnderChest.java | 7 +---- .../v1_17_R1/SpecialPlayerInventory.java | 6 ---- .../internal/v1_18_R1/SpecialEnderChest.java | 7 +---- .../v1_18_R1/SpecialPlayerInventory.java | 6 ---- .../internal/v1_18_R2/SpecialEnderChest.java | 5 --- .../v1_18_R2/SpecialPlayerInventory.java | 6 ---- 8 files changed, 37 insertions(+), 39 deletions(-) diff --git a/api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java b/api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java index 86a2dc1..dc94ce4 100644 --- a/api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java +++ b/api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,11 +43,13 @@ public interface ISpecialInventory { void setPlayerOffline(); /** - * Gets whether or not this ISpecialInventory is in use. + * Gets whether this ISpecialInventory is in use. * * @return true if the ISpecialInventory is in use */ - boolean isInUse(); + default boolean isInUse() { + return !getBukkitInventory().getViewers().isEmpty(); + } /** * Gets the Player associated with this ISpecialInventory. diff --git a/api/src/main/java/com/lishid/openinv/internal/ISpecialPlayerInventory.java b/api/src/main/java/com/lishid/openinv/internal/ISpecialPlayerInventory.java index f15bc1a..412656c 100644 --- a/api/src/main/java/com/lishid/openinv/internal/ISpecialPlayerInventory.java +++ b/api/src/main/java/com/lishid/openinv/internal/ISpecialPlayerInventory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +16,35 @@ package com.lishid.openinv.internal; +import java.util.List; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.Inventory; + +/** + * Interface defining behavior specific to a player inventory. + */ public interface ISpecialPlayerInventory extends ISpecialInventory { + /* + * Player inventory usage varies from all other inventories - as the inventory is technically open at all times, + * if the player is online or has been online while the inventory is open, they are in the viewer list. + */ + @Override + default boolean isInUse() { + Inventory inventory = getBukkitInventory(); + List viewers = inventory.getViewers(); + + if (viewers.size() != 1) { + return !viewers.isEmpty(); + } + + HumanEntity viewer = viewers.get(0); + + if (!viewer.getUniqueId().equals(getPlayer().getUniqueId())) { + return true; + } + + return viewer.getOpenInventory().getTopInventory().equals(inventory); + } + } diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java index fed9b56..6d48d54 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,11 +60,6 @@ public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpe return inventory; } - @Override - public boolean isInUse() { - return !this.getViewers().isEmpty(); - } - @Override public void setPlayerOffline() { this.playerOnline = false; diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java index 1a85469..af7d5cb 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java @@ -103,12 +103,6 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI this.playerOnline = false; } - @Override - public boolean isInUse() { - List viewers = this.getViewers(); - return viewers.size() > 1 || !viewers.isEmpty() && !viewers.get(0).getUniqueId().equals(this.player.getUUID()); - } - @Override public @NotNull HumanEntity getPlayer() { return this.player.getBukkitEntity(); diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java index d10bfdd..ea67c5f 100644 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,11 +60,6 @@ public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpe return inventory; } - @Override - public boolean isInUse() { - return !this.getViewers().isEmpty(); - } - @Override public void setPlayerOffline() { this.playerOnline = false; diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java index 7133f80..6508f3d 100644 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java @@ -103,12 +103,6 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI this.playerOnline = false; } - @Override - public boolean isInUse() { - List viewers = this.getViewers(); - return viewers.size() > 1 || !viewers.isEmpty() && !viewers.get(0).getUniqueId().equals(this.player.getUUID()); - } - @Override public @NotNull HumanEntity getPlayer() { return this.player.getBukkitEntity(); diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java index d9518f5..f46ff61 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java @@ -60,11 +60,6 @@ public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpe return inventory; } - @Override - public boolean isInUse() { - return !this.getViewers().isEmpty(); - } - @Override public void setPlayerOffline() { this.playerOnline = false; diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java index 3b410e9..04c2c5f 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java @@ -103,12 +103,6 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI this.playerOnline = false; } - @Override - public boolean isInUse() { - List viewers = this.getViewers(); - return viewers.size() > 1 || !viewers.isEmpty() && !viewers.get(0).getUniqueId().equals(this.player.getUUID()); - } - @Override public @NotNull HumanEntity getPlayer() { return this.player.getBukkitEntity(); -- 2.49.1 From c9ba401a6e383f2611477b4a2c3d24e294b7ae33 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 13 May 2022 11:14:45 -0400 Subject: [PATCH 068/139] Don't inject player if unnecessary --- .../lishid/openinv/internal/v1_17_R1/PlayerDataManager.java | 5 ++++- .../lishid/openinv/internal/v1_18_R1/PlayerDataManager.java | 5 ++++- .../lishid/openinv/internal/v1_18_R2/PlayerDataManager.java | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java index df7697e..e17c144 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java +++ b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -130,6 +130,9 @@ public class PlayerDataManager implements IPlayerDataManager { public Player inject(@NotNull Player player) { try { ServerPlayer nmsPlayer = getHandle(player); + if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) { + return openPlayer; + } injectPlayer(nmsPlayer); return nmsPlayer.getBukkitEntity(); } catch (IllegalAccessException e) { diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java index a982b99..75f18d5 100644 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java +++ b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -130,6 +130,9 @@ public class PlayerDataManager implements IPlayerDataManager { public Player inject(@NotNull Player player) { try { ServerPlayer nmsPlayer = getHandle(player); + if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) { + return openPlayer; + } injectPlayer(nmsPlayer); return nmsPlayer.getBukkitEntity(); } catch (IllegalAccessException e) { diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java index 40d6e8e..1be5f57 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java @@ -130,6 +130,9 @@ public class PlayerDataManager implements IPlayerDataManager { public Player inject(@NotNull Player player) { try { ServerPlayer nmsPlayer = getHandle(player); + if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) { + return openPlayer; + } injectPlayer(nmsPlayer); return nmsPlayer.getBukkitEntity(); } catch (IllegalAccessException e) { -- 2.49.1 From 9502b29fe3b15fc02d28928b7fffe4ed43891c8f Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 13 May 2022 11:15:40 -0400 Subject: [PATCH 069/139] Clean up compiler warnings Compiler doesn't understand that api is provided by plugin during build process --- internal/v1_17_R1/pom.xml | 5 +++++ internal/v1_18_R1/pom.xml | 5 +++++ internal/v1_18_R2/pom.xml | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/internal/v1_17_R1/pom.xml b/internal/v1_17_R1/pom.xml index 427a208..8dcdec4 100644 --- a/internal/v1_17_R1/pom.xml +++ b/internal/v1_17_R1/pom.xml @@ -43,6 +43,11 @@ ${spigot.version} remapped-mojang + + openinvapi + com.lishid + provided + openinvplugincore com.lishid diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_18_R1/pom.xml index 3a62a7e..9cbf09b 100644 --- a/internal/v1_18_R1/pom.xml +++ b/internal/v1_18_R1/pom.xml @@ -48,6 +48,11 @@ ${spigot.version} remapped-mojang + + openinvapi + com.lishid + provided + openinvplugincore com.lishid diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 0a0f429..c0d4b2e 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -48,6 +48,11 @@ ${spigot.version} remapped-mojang + + openinvapi + com.lishid + provided + openinvplugincore com.lishid -- 2.49.1 From fdf920062b75932c9a290a4125d201384f9001cb Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 13 May 2022 11:49:48 -0400 Subject: [PATCH 070/139] Remove cache, add disable-offline-access config node Fixes various permissions not being respected during login/logout with inventories already open. This will result in a performance hit for repeated open/closes - there will be significantly more disk I/O. Closes lishid#171 Closes #56 --- .../java/com/lishid/openinv/IOpenInv.java | 98 +++--- .../com/lishid/openinv/InventoryListener.java | 17 +- .../com/lishid/openinv/OfflineHandler.java | 41 +++ .../main/java/com/lishid/openinv/OpenInv.java | 325 +++++++++--------- .../com/lishid/openinv/PlayerListener.java | 8 +- .../openinv/commands/OpenInvCommand.java | 4 +- .../openinv/listeners/PluginListener.java | 42 --- .../java/com/lishid/openinv/util/Cache.java | 187 ---------- .../lishid/openinv/util/ConfigUpdater.java | 20 +- .../com/lishid/openinv/util/Permissions.java | 5 +- plugin/src/main/resources/config.yml | 3 +- 11 files changed, 290 insertions(+), 460 deletions(-) create mode 100644 plugin/src/main/java/com/lishid/openinv/OfflineHandler.java delete mode 100644 plugin/src/main/java/com/lishid/openinv/listeners/PluginListener.java delete mode 100644 plugin/src/main/java/com/lishid/openinv/util/Cache.java diff --git a/api/src/main/java/com/lishid/openinv/IOpenInv.java b/api/src/main/java/com/lishid/openinv/IOpenInv.java index 64697ff..5b12e6a 100644 --- a/api/src/main/java/com/lishid/openinv/IOpenInv.java +++ b/api/src/main/java/com/lishid/openinv/IOpenInv.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,15 +42,23 @@ import org.jetbrains.annotations.Nullable; public interface IOpenInv { /** - * Check the configuration value for whether or not OpenInv saves player data when unloading - * players. This is exclusively for users who do not allow editing of inventories, only viewing, - * and wish to prevent any possibility of bugs such as lishid#40. If true, OpenInv will not ever - * save any edits made to players. + * Check the configuration value for whether OpenInv saves player data when unloading players. This is exclusively + * for users who do not allow editing of inventories, only viewing, and wish to prevent any possibility of bugs such + * as lishid#40. If true, OpenInv will not ever save any edits made to players. * * @return false unless configured otherwise */ boolean disableSaving(); + /** + * Check the configuration value for whether OpenInv allows offline access. This does not prevent other plugins from + * using existing loaded players while offline. + * + * @return false unless configured otherwise + * @since 4.2.0 + */ + boolean disableOfflineAccess(); + /** * Gets the active ISilentContainer implementation. * @@ -60,12 +68,9 @@ public interface IOpenInv { @NotNull IAnySilentContainer getAnySilentContainer(); /** - * Gets the active IInventoryAccess implementation. - * - * @return the IInventoryAccess - * @throws IllegalStateException if the server version is unsupported + * @deprecated Use static {@link InventoryAccess} methods. */ - @Deprecated + @Deprecated(forRemoval = true) default @NotNull IInventoryAccess getInventoryAccess() { return new InventoryAccess(); } @@ -129,6 +134,15 @@ public interface IOpenInv { */ boolean isSupportedVersion(); + /** + * Check if a {@link Player} is currently loaded by OpenInv. + * + * @param playerUuid the {@link UUID} of the {@code Player} + * @return whether the {@code Player} is loaded + * @since 4.2.0 + */ + boolean isPlayerLoaded(@NotNull UUID playerUuid); + /** * Load a Player from an OfflinePlayer. May return null under some circumstances. * @@ -227,57 +241,51 @@ public interface IOpenInv { * @return true unless configured otherwise * @deprecated OpenInv uses action bar chat for notifications. Whether or not they show is based on language settings. */ - @Deprecated + @Deprecated(forRemoval = true) default boolean notifyAnyChest() { return true; } /** - * Check the configuration value for whether or not OpenInv displays a notification to the user - * when a container is activated with SilentChest. - * - * @return true unless configured otherwise - * @deprecated OpenInv uses action bar chat for notifications. Whether or not they show is based on language settings. + * @deprecated OpenInv uses action bar chat for notifications. Whether they show is based on language settings. */ - @Deprecated + @Deprecated(forRemoval = true) default boolean notifySilentChest() { return true; } /** - * Mark a Player as no longer in use by a Plugin to allow OpenInv to remove it from the cache - * when eligible. - * - * @param player the Player - * @param plugin the Plugin no longer holding a reference to the Player - * @throws IllegalStateException if the server version is unsupported + * @deprecated see {@link #retainPlayer(Player, Plugin)} */ - void releasePlayer(@NotNull Player player, @NotNull Plugin plugin); + @Deprecated(forRemoval = true, since = "4.2.0") + default void releasePlayer(@NotNull Player player, @NotNull Plugin plugin) {} /** - * Mark a Player as in use by a Plugin to prevent it from being removed from the cache. Used to - * prevent issues with multiple copies of the same Player being loaded such as lishid#49. - * Changes made to loaded copies overwrite changes to the others when saved, leading to - * duplication bugs and more. - *

- * When finished with the Player object, be sure to call {@link #releasePlayer(Player, Plugin)} - * to prevent the cache from keeping it stored until the plugin is disabled. - *

- * When using a Player object from OpenInv, you must handle the Player coming online, replacing - * your Player reference with the Player from the PlayerJoinEvent. In addition, you must change - * any values in the Player to reflect any unsaved alterations to the existing Player which do - * not affect the inventory or ender chest contents. - *

- * OpenInv only saves player data when unloading a Player from the cache, and then only if - * {@link #disableSaving()} returns false. If you are making changes that OpenInv does not cause - * to persist when a Player logs in as noted above, it is suggested that you manually call - * {@link Player#saveData()} when releasing your reference to ensure your changes persist. + * @deprecated OpenInv no longer uses an internal cache beyond maintaining copies of currently open inventories. + * If you wish to use/modify a player, ensure either {@link IOpenInv#isPlayerLoaded(UUID)} is false or the player + * instance is the same memory address as the one in use by OpenInv. + *

+     *  public @NotNull Player savePlayerData(@NotNull Player player) {
+     *     IOpenInv openInv = ...
+     *     if (!openInv.disableSaving() && openInv.isPlayerLoaded(player.getUniqueId())) {
+     *         Player openInvLoadedPlayer = openInv.loadPlayer(myInUsePlayer);
+     *         if (openInvLoadedPlayer != player) {
+     *             // The copy loaded by OpenInv is not the same as our loaded copy. Push our changes.
+     *             copyPlayerModifications(player, openInvLoadedPlayer);
+     *         }
+     *         // OpenInv will handle saving data when the player is unloaded.
+     *         // Optionally, to be sure our changes will persist, save now.
+     *         // openInvLoadedPlayer.saveData();
+     *         return openInvLoadedPlayer;
+     *     }
      *
-     * @param player the Player
-     * @param plugin the Plugin holding the reference to the Player
-     * @throws IllegalStateException if the server version is unsupported
+     *     player.saveData();
+     *     return player;
+     * }
+     * 
*/ - void retainPlayer(@NotNull Player player, @NotNull Plugin plugin); + @Deprecated(forRemoval = true, since = "4.2.0") + default void retainPlayer(@NotNull Player player, @NotNull Plugin plugin) {} /** * Sets a player's AnyChest setting. diff --git a/plugin/src/main/java/com/lishid/openinv/InventoryListener.java b/plugin/src/main/java/com/lishid/openinv/InventoryListener.java index 8e1c27e..1a6a799 100644 --- a/plugin/src/main/java/com/lishid/openinv/InventoryListener.java +++ b/plugin/src/main/java/com/lishid/openinv/InventoryListener.java @@ -16,6 +16,7 @@ package com.lishid.openinv; +import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.internal.ISpecialPlayerInventory; import com.lishid.openinv.util.InventoryAccess; import com.lishid.openinv.util.Permissions; @@ -47,7 +48,7 @@ import org.jetbrains.annotations.Nullable; record InventoryListener(OpenInv plugin) implements Listener { @EventHandler - public void onInventoryClose(@NotNull final InventoryCloseEvent event) { + private void onInventoryClose(@NotNull final InventoryCloseEvent event) { if (!(event.getPlayer() instanceof Player player)) { return; } @@ -55,10 +56,20 @@ record InventoryListener(OpenInv plugin) implements Listener { if (this.plugin.getPlayerSilentChestStatus(player)) { this.plugin.getAnySilentContainer().deactivateContainer(player); } + + ISpecialInventory specialInventory = InventoryAccess.getEnderChest(event.getInventory()); + if (specialInventory != null) { + this.plugin.handleCloseInventory(event.getPlayer(), specialInventory); + } else { + specialInventory = InventoryAccess.getPlayerInventory(event.getInventory()); + if (specialInventory != null) { + this.plugin.handleCloseInventory(event.getPlayer(), specialInventory); + } + } } @EventHandler(priority = EventPriority.LOWEST) - public void onInventoryClick(@NotNull final InventoryClickEvent event) { + private void onInventoryClick(@NotNull final InventoryClickEvent event) { if (handleInventoryInteract(event)) { return; } @@ -92,7 +103,7 @@ record InventoryListener(OpenInv plugin) implements Listener { } @EventHandler(priority = EventPriority.LOWEST) - public void onInventoryDrag(@NotNull final InventoryDragEvent event) { + private void onInventoryDrag(@NotNull final InventoryDragEvent event) { if (handleInventoryInteract(event)) { return; } diff --git a/plugin/src/main/java/com/lishid/openinv/OfflineHandler.java b/plugin/src/main/java/com/lishid/openinv/OfflineHandler.java new file mode 100644 index 0000000..ea0e8c3 --- /dev/null +++ b/plugin/src/main/java/com/lishid/openinv/OfflineHandler.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv; + +import com.lishid.openinv.internal.ISpecialInventory; +import com.lishid.openinv.util.Permissions; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import org.jetbrains.annotations.NotNull; + +record OfflineHandler( + @NotNull BiFunction, UUID, ISpecialInventory> fetch, + @NotNull Consumer<@NotNull ISpecialInventory> handle) { + + static final OfflineHandler REMOVE_AND_CLOSE = new OfflineHandler( + Map::remove, + inventory -> OpenInv.ejectViewers(inventory, viewer -> true) + ); + + static final OfflineHandler REQUIRE_PERMISSIONS = new OfflineHandler( + Map::get, + inventory -> OpenInv.ejectViewers(inventory, viewer -> !Permissions.OPENOFFLINE.hasPermission(viewer)) + ); + +} diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index 3ad4f5c..5e3591b 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,8 +16,6 @@ package com.lishid.openinv; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; import com.lishid.openinv.commands.ContainerSettingCommand; import com.lishid.openinv.commands.OpenInvCommand; import com.lishid.openinv.commands.SearchContainerCommand; @@ -27,23 +25,19 @@ import com.lishid.openinv.internal.IAnySilentContainer; import com.lishid.openinv.internal.ISpecialEnderChest; import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.internal.ISpecialPlayerInventory; -import com.lishid.openinv.listeners.InventoryListener; -import com.lishid.openinv.listeners.PlayerListener; -import com.lishid.openinv.listeners.PluginListener; -import com.lishid.openinv.util.Cache; import com.lishid.openinv.util.ConfigUpdater; -import com.lishid.openinv.util.InternalAccessor; import com.lishid.openinv.util.LanguageManager; import com.lishid.openinv.util.Permissions; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Bukkit; @@ -56,10 +50,8 @@ import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; -import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -70,63 +62,21 @@ import org.jetbrains.annotations.Nullable; */ public class OpenInv extends JavaPlugin implements IOpenInv { - private final Map inventories = new HashMap<>(); - private final Map enderChests = new HashMap<>(); - private final Multimap> pluginUsage = HashMultimap.create(); - - private final Cache playerCache = new Cache<>(300000L, - value -> { - String key = OpenInv.this.getPlayerID(value); - - return OpenInv.this.inventories.containsKey(key) - && OpenInv.this.inventories.get(key).isInUse() - || OpenInv.this.enderChests.containsKey(key) - && OpenInv.this.enderChests.get(key).isInUse() - || OpenInv.this.pluginUsage.containsKey(key); - }, - value -> { - String key = OpenInv.this.getPlayerID(value); - - // Check if inventory is stored, and if it is, remove it and eject all viewers - if (OpenInv.this.inventories.containsKey(key)) { - Inventory inv = OpenInv.this.inventories.remove(key).getBukkitInventory(); - List viewers = new ArrayList<>(inv.getViewers()); - for (HumanEntity entity : viewers.toArray(new HumanEntity[0])) { - entity.closeInventory(); - } - } - - // Check if ender chest is stored, and if it is, remove it and eject all viewers - if (OpenInv.this.enderChests.containsKey(key)) { - Inventory inv = OpenInv.this.enderChests.remove(key).getBukkitInventory(); - List viewers = new ArrayList<>(inv.getViewers()); - for (HumanEntity entity : viewers.toArray(new HumanEntity[0])) { - entity.closeInventory(); - } - } - - if (!OpenInv.this.disableSaving() && !value.isOnline()) { - value.saveData(); - } - }); + private final Map inventories = new ConcurrentHashMap<>(); + private final Map enderChests = new ConcurrentHashMap<>(); private InternalAccessor accessor; private LanguageManager languageManager; private boolean isSpigot = false; + private OfflineHandler offlineHandler; /** - * Evicts all viewers lacking cross-world permissions from a Player's inventory. + * Evict all viewers lacking cross-world permissions from a Player's inventory. * * @param player the Player */ - public void changeWorld(final Player player) { - - String key = this.getPlayerID(player); - - // Check if the player is cached. If not, neither of their inventories is open. - if (!this.playerCache.containsKey(key)) { - return; - } + void changeWorld(@NotNull Player player) { + UUID key = player.getUniqueId(); if (this.inventories.containsKey(key)) { kickCrossWorldViewers(player, this.inventories.get(key)); @@ -137,15 +87,19 @@ public class OpenInv extends JavaPlugin implements IOpenInv { } } - private void kickCrossWorldViewers(Player player, ISpecialInventory inventory) { - List viewers = new ArrayList<>(inventory.getBukkitInventory().getViewers()); - for (HumanEntity human : viewers) { - // If player has permission or is in the same world, allow continued access - // Just in case, also allow null worlds. - if (Permissions.CROSSWORLD.hasPermission(human) || Objects.equals(human.getWorld(), player.getWorld())) { - continue; + private void kickCrossWorldViewers(@NotNull Player player, @NotNull ISpecialInventory inventory) { + ejectViewers( + inventory, + viewer -> + !Permissions.CROSSWORLD.hasPermission(viewer) + && Objects.equals(viewer.getWorld(), player.getWorld())); + } + + static void ejectViewers(@NotNull ISpecialInventory inventory, Predicate predicate) { + for (HumanEntity viewer : new ArrayList<>(inventory.getBukkitInventory().getViewers())) { + if (predicate.test(viewer)) { + viewer.closeInventory(); } - human.closeInventory(); } } @@ -159,7 +113,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { * @param rawSlot the raw slot in the view * @return the converted slot number */ - public int convertToPlayerSlot(InventoryView view, int rawSlot) { + int convertToPlayerSlot(InventoryView view, int rawSlot) { return this.accessor.getPlayerDataManager().convertToPlayerSlot(view, rawSlot); } @@ -168,9 +122,13 @@ public class OpenInv extends JavaPlugin implements IOpenInv { return this.getConfig().getBoolean("settings.disable-saving", false); } - @NotNull @Override - public IAnySilentContainer getAnySilentContainer() { + public boolean disableOfflineAccess() { + return this.getConfig().getBoolean("settings.disable-offline-access", false); + } + + @Override + public @NotNull IAnySilentContainer getAnySilentContainer() { return this.accessor.getAnySilentContainer(); } @@ -202,31 +160,31 @@ public class OpenInv extends JavaPlugin implements IOpenInv { return this.getConfig().getBoolean("toggles.silent-chest." + this.getPlayerID(offline), defaultState); } - @NotNull @Override - public ISpecialEnderChest getSpecialEnderChest(@NotNull final Player player, final boolean online) + public @NotNull ISpecialEnderChest getSpecialEnderChest(@NotNull final Player player, final boolean online) throws InstantiationException { - String id = this.getPlayerID(player); - if (this.enderChests.containsKey(id)) { - return this.enderChests.get(id); + UUID key = player.getUniqueId(); + + if (this.enderChests.containsKey(key)) { + return this.enderChests.get(key); } + ISpecialEnderChest inv = this.accessor.newSpecialEnderChest(player, online); - this.enderChests.put(id, inv); - this.playerCache.put(id, player); + this.enderChests.put(key, inv); return inv; } - @NotNull @Override - public ISpecialPlayerInventory getSpecialInventory(@NotNull final Player player, final boolean online) + public @NotNull ISpecialPlayerInventory getSpecialInventory(@NotNull final Player player, final boolean online) throws InstantiationException { - String id = this.getPlayerID(player); - if (this.inventories.containsKey(id)) { - return this.inventories.get(id); + UUID key = player.getUniqueId(); + + if (this.inventories.containsKey(key)) { + return this.inventories.get(key); } + ISpecialPlayerInventory inv = this.accessor.newSpecialPlayerInventory(player, online); - this.inventories.put(id, inv); - this.playerCache.put(id, player); + this.inventories.put(key, inv); return inv; } @@ -236,20 +194,28 @@ public class OpenInv extends JavaPlugin implements IOpenInv { } @Override - public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { + public boolean isPlayerLoaded(@NotNull UUID playerUuid) { + return this.inventories.containsKey(playerUuid) || this.enderChests.containsKey(playerUuid); + } - String key = this.getPlayerID(offline); - if (this.playerCache.containsKey(key)) { - return this.playerCache.get(key); + @Override + public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { + UUID key = offline.getUniqueId(); + + if (this.inventories.containsKey(key)) { + return (Player) this.inventories.get(key).getPlayer(); + } + + if (this.enderChests.containsKey(key)) { + return (Player) this.enderChests.get(key).getPlayer(); } Player player = offline.getPlayer(); if (player != null) { - this.playerCache.put(key, player); return player; } - if (!this.isSupportedVersion()) { + if (disableOfflineAccess() || !this.isSupportedVersion()) { return null; } @@ -267,10 +233,6 @@ public class OpenInv extends JavaPlugin implements IOpenInv { return null; } - if (player != null) { - this.playerCache.put(key, player); - } - return player; } @@ -338,9 +300,23 @@ public class OpenInv extends JavaPlugin implements IOpenInv { return; } - if (this.isSupportedVersion()) { - this.playerCache.invalidateAll(); - } + Stream.concat(inventories.values().stream(), enderChests.values().stream()) + .map(inventory -> { + // Cheat a bit - rather than stream twice, evict all viewers during remapping. + ejectViewers(inventory, viewer -> true); + if (inventory.getPlayer() instanceof Player player) { + return player; + } + return null; + }) + .filter(Objects::nonNull) + .distinct() + .forEach(player -> { + if (!player.isOnline()) { + player = accessor.getPlayerDataManager().inject(player); + } + player.saveData(); + }); } @Override @@ -355,6 +331,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { this.accessor = new InternalAccessor(this); this.languageManager = new LanguageManager(this, "en_us"); + this.offlineHandler = disableOfflineAccess() ? OfflineHandler.REMOVE_AND_CLOSE : OfflineHandler.REQUIRE_PERMISSIONS; try { Class.forName("org.bukkit.entity.Player$Spigot"); @@ -371,7 +348,6 @@ public class OpenInv extends JavaPlugin implements IOpenInv { // Register listeners pm.registerEvents(new PlayerListener(this), this); - pm.registerEvents(new PluginListener(this), this); pm.registerEvents(new InventoryListener(this), this); // Register commands to their executors @@ -390,7 +366,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { private void sendVersionError(Consumer messageMethod) { if (!this.accessor.isSupported()) { messageMethod.accept("Your server version (" + this.accessor.getVersion() + ") is not supported."); - messageMethod.accept("Please obtain an appropriate version here: " + this.accessor.getReleasesLink()); + messageMethod.accept("Please download the correct version of OpenInv here: " + this.accessor.getReleasesLink()); } if (!isSpigot) { messageMethod.accept("OpenInv requires that you use Spigot or a Spigot fork. Per the 1.14 update thread"); @@ -418,40 +394,10 @@ public class OpenInv extends JavaPlugin implements IOpenInv { return false; } - public void releaseAllPlayers(final Plugin plugin) { - Iterator>> iterator = this.pluginUsage.entries().iterator(); - - if (!iterator.hasNext()) { - return; - } - - for (Map.Entry> entry = iterator.next(); iterator.hasNext(); entry = iterator.next()) { - if (entry.getValue().equals(plugin.getClass())) { - iterator.remove(); - } - } - } - @Override - public void releasePlayer(@NotNull final Player player, @NotNull final Plugin plugin) { - String key = this.getPlayerID(player); - - if (!this.pluginUsage.containsEntry(key, plugin.getClass())) { - return; - } - - this.pluginUsage.remove(key, plugin.getClass()); - } - - @Override - public void retainPlayer(@NotNull final Player player, @NotNull final Plugin plugin) { - String key = this.getPlayerID(player); - - if (this.pluginUsage.containsEntry(key, plugin.getClass())) { - return; - } - - this.pluginUsage.put(key, plugin.getClass()); + public void reloadConfig() { + super.reloadConfig(); + this.offlineHandler = disableOfflineAccess() ? OfflineHandler.REMOVE_AND_CLOSE : OfflineHandler.REQUIRE_PERMISSIONS; } @Override @@ -464,27 +410,71 @@ public class OpenInv extends JavaPlugin implements IOpenInv { * Method for handling a Player going offline. * * @param player the Player - * @throws IllegalStateException if the server version is unsupported */ - public void setPlayerOffline(final Player player) { + void setPlayerOffline(@NotNull Player player) { + setPlayerOffline(player, offlineHandler); + } - String key = this.getPlayerID(player); + private void setPlayerOffline(@NotNull OfflinePlayer player, @NotNull OfflineHandler handler) { + UUID key = player.getUniqueId(); - // Check if the player is cached. If not, neither of their inventories is open. - if (!this.playerCache.containsKey(key)) { + setPlayerOffline(inventories, key, handler); + setPlayerOffline(enderChests, key, handler); + } + + private void setPlayerOffline( + @NotNull Map map, + @NotNull UUID key, + @NotNull OfflineHandler handler) { + ISpecialInventory inventory = handler.fetch().apply(map, key); + if (inventory == null) { + return; + } + inventory.setPlayerOffline(); + if (!inventory.isInUse()) { + map.remove(key); + } else { + handler.handle().accept(inventory); + } + } + + void handleCloseInventory(@NotNull HumanEntity exViewer, @NotNull ISpecialInventory inventory) { + Map map = inventory instanceof ISpecialPlayerInventory ? inventories : enderChests; + UUID key = inventory.getPlayer().getUniqueId(); + @Nullable ISpecialInventory loaded = map.get(key); + + if (loaded == null) { + // Loaded inventory has already been removed. Removal will handle saving if necessary. return; } - // Replace stored player with our own version - this.playerCache.put(key, this.accessor.getPlayerDataManager().inject(player)); - - if (this.inventories.containsKey(key)) { - this.inventories.get(key).setPlayerOffline(); + if (loaded != inventory) { + Inventory bukkitInventory = inventory.getBukkitInventory(); + // Just in case, respect contents of the inventory that was just used. + loaded.getBukkitInventory().setContents(bukkitInventory.getContents()); + // We need to close this inventory to reduce risk of duplication bugs if the user is offline. + // We don't want to risk recursively closing the same inventory repeatedly, so we schedule dumping viewers. + // Worst case we schedule a couple redundant tasks if several people had the inventory open. + if (!bukkitInventory.getViewers().isEmpty()) { + getServer().getScheduler().runTask(this, () -> ejectViewers(inventory, viewer -> true)); + } } - if (this.enderChests.containsKey(key)) { - this.enderChests.get(key).setPlayerOffline(); - } + // Schedule task to check in use status later this tick. Closing user is still in viewer list. + getServer().getScheduler().runTask(this, () -> { + if (loaded.isInUse()) { + return; + } + + // Re-fetch from map - prevents duplicate saves on multi-close. + ISpecialInventory current = map.remove(key); + + if (!disableSaving() + && current != null + && current.getPlayer() instanceof Player player && !player.isOnline()) { + this.accessor.getPlayerDataManager().inject(player).saveData(); + } + }); } /** @@ -493,31 +483,34 @@ public class OpenInv extends JavaPlugin implements IOpenInv { * @param player the Player * @throws IllegalStateException if the server version is unsupported */ - public void setPlayerOnline(final Player player) { + void setPlayerOnline(@NotNull Player player) { + setPlayerOnline(inventories, player, player::updateInventory); + setPlayerOnline(enderChests, player, null); + } - String key = this.getPlayerID(player); + private void setPlayerOnline( + @NotNull Map map, + @NotNull Player player, + @Nullable Runnable task) { + ISpecialInventory inventory = map.get(player.getUniqueId()); - // Check if the player is cached. If not, neither of their inventories is open. - if (!this.playerCache.containsKey(key)) { + if (inventory == null) { + // Inventory not open. return; } - this.playerCache.put(key, player); + inventory.setPlayerOnline(player); - if (this.inventories.containsKey(key)) { - this.inventories.get(key).setPlayerOnline(player); - new BukkitRunnable() { - @Override - public void run() { - if (player.isOnline()) { - player.updateInventory(); - } - } - }.runTask(this); - } + // Eject viewers lacking permission. + ejectViewers( + inventory, + viewer -> + !Permissions.OPENONLINE.hasPermission(viewer) + || !Permissions.CROSSWORLD.hasPermission(viewer) + && !Objects.equals(viewer.getWorld(), inventory.getPlayer().getWorld())); - if (this.enderChests.containsKey(key)) { - this.enderChests.get(key).setPlayerOnline(player); + if (task != null) { + getServer().getScheduler().runTask(this, task); } } @@ -529,7 +522,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { @Override public void unload(@NotNull final OfflinePlayer offline) { - this.playerCache.invalidate(this.getPlayerID(offline)); + setPlayerOffline(offline, OfflineHandler.REMOVE_AND_CLOSE); } } diff --git a/plugin/src/main/java/com/lishid/openinv/PlayerListener.java b/plugin/src/main/java/com/lishid/openinv/PlayerListener.java index 4ec2950..61a5f7d 100644 --- a/plugin/src/main/java/com/lishid/openinv/PlayerListener.java +++ b/plugin/src/main/java/com/lishid/openinv/PlayerListener.java @@ -32,22 +32,22 @@ import org.jetbrains.annotations.NotNull; record PlayerListener(OpenInv plugin) implements Listener { @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerJoin(@NotNull PlayerJoinEvent event) { + private void onPlayerJoin(@NotNull PlayerJoinEvent event) { plugin.setPlayerOnline(event.getPlayer()); } @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerQuit(@NotNull PlayerQuitEvent event) { + private void onPlayerQuit(@NotNull PlayerQuitEvent event) { plugin.setPlayerOffline(event.getPlayer()); } @EventHandler - public void onWorldChange(@NotNull PlayerChangedWorldEvent event) { + private void onWorldChange(@NotNull PlayerChangedWorldEvent event) { plugin.changeWorld(event.getPlayer()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onPlayerInteract(@NotNull PlayerInteractEvent event) { + private void onPlayerInteract(@NotNull PlayerInteractEvent event) { // Do not cancel 3rd party plugins' custom events if (!PlayerInteractEvent.class.equals(event.getClass())) { diff --git a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java index c97b154..189a41d 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -133,7 +133,7 @@ public class OpenInvCommand implements TabExecutor { boolean online = target.isOnline(); if (!online) { - if (Permissions.OPENOFFLINE.hasPermission(player)) { + if (!plugin.disableOfflineAccess() && Permissions.OPENOFFLINE.hasPermission(player)) { // Try loading the player's data onlineTarget = this.plugin.loadPlayer(target); } else { diff --git a/plugin/src/main/java/com/lishid/openinv/listeners/PluginListener.java b/plugin/src/main/java/com/lishid/openinv/listeners/PluginListener.java deleted file mode 100644 index 850c988..0000000 --- a/plugin/src/main/java/com/lishid/openinv/listeners/PluginListener.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011-2021 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.listeners; - -import com.lishid.openinv.OpenInv; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginDisableEvent; - -/** - * Listener for plugin-related events. - * - * @author Jikoo - */ -public class PluginListener implements Listener { - - private final OpenInv plugin; - - public PluginListener(OpenInv plugin) { - this.plugin = plugin; - } - - @EventHandler - public void onPluginDisable(PluginDisableEvent event) { - plugin.releaseAllPlayers(event.getPlugin()); - } - -} diff --git a/plugin/src/main/java/com/lishid/openinv/util/Cache.java b/plugin/src/main/java/com/lishid/openinv/util/Cache.java deleted file mode 100644 index 5f2e8dc..0000000 --- a/plugin/src/main/java/com/lishid/openinv/util/Cache.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2011-2021 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.util; - -import com.google.common.collect.Multimap; -import com.google.common.collect.TreeMultimap; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Predicate; - -/** - * A minimal thread-safe time-based cache implementation backed by a HashMap and TreeMultimap. - * - * @author Jikoo - */ -public class Cache { - - private final Map internal; - private final Multimap expiry; - private final long retention; - private final Predicate inUseCheck; - private final Consumer postRemoval; - - /** - * Constructs a Cache with the specified retention duration, in use function, and post-removal function. - * - * @param retention duration after which keys are automatically invalidated if not in use - * @param inUseCheck Predicate used to check if a key is considered in use - * @param postRemoval Consumer used to perform any operations required when a key is invalidated - */ - public Cache(final long retention, final Predicate inUseCheck, final Consumer postRemoval) { - this.internal = new HashMap<>(); - - this.expiry = TreeMultimap.create(Long::compareTo, (k1, k2) -> Objects.equals(k1, k2) ? 0 : 1); - - this.retention = retention; - this.inUseCheck = inUseCheck; - this.postRemoval = postRemoval; - } - - /** - * Set a key and value pair. Keys are unique. Using an existing key will cause the old value to - * be overwritten and the expiration timer to be reset. - * - * @param key key with which the specified value is to be associated - * @param value value to be associated with the specified key - */ - public void put(final K key, final V value) { - // Invalidate key - runs lazy check and ensures value won't be cleaned up early - this.invalidate(key); - - synchronized (this.internal) { - this.internal.put(key, value); - this.expiry.put(System.currentTimeMillis() + this.retention, key); - } - } - - /** - * Returns the value to which the specified key is mapped, or null if no value is mapped for the key. - * - * @param key the key whose associated value is to be returned - * @return the value to which the specified key is mapped, or null if no value is mapped for the key - */ - public V get(final K key) { - // Run lazy check to clean cache - this.lazyCheck(); - - synchronized (this.internal) { - return this.internal.get(key); - } - } - - /** - * Returns true if the specified key is mapped to a value. - * - * @param key key to check if a mapping exists for - * @return true if a mapping exists for the specified key - */ - public boolean containsKey(final K key) { - // Run lazy check to clean cache - this.lazyCheck(); - - synchronized (this.internal) { - return this.internal.containsKey(key); - } - } - - /** - * Forcibly invalidates a key, even if it is considered to be in use. - * - * @param key key to invalidate - */ - public void invalidate(final K key) { - // Run lazy check to clean cache - this.lazyCheck(); - - synchronized (this.internal) { - if (!this.internal.containsKey(key)) { - // Value either not present or cleaned by lazy check. Either way, we're good - return; - } - - // Remove stored object - this.internal.remove(key); - - // Remove expiration entry - prevents more work later, plus prevents issues with values invalidating early - for (Iterator> iterator = this.expiry.entries().iterator(); iterator.hasNext();) { - if (key.equals(iterator.next().getValue())) { - iterator.remove(); - break; - } - } - } - } - - /** - * Forcibly invalidates all keys, even if they are considered to be in use. - */ - public void invalidateAll() { - synchronized (this.internal) { - for (V value : this.internal.values()) { - this.postRemoval.accept(value); - } - this.expiry.clear(); - this.internal.clear(); - } - } - - /** - * Invalidate all expired keys that are not considered in use. If a key is expired but is - * considered in use by the provided Function, its expiration time is reset. - */ - private void lazyCheck() { - long now = System.currentTimeMillis(); - synchronized (this.internal) { - List inUse = new ArrayList<>(); - for (Iterator> iterator = this.expiry.entries().iterator(); iterator - .hasNext();) { - Map.Entry entry = iterator.next(); - - if (entry.getKey() > now) { - break; - } - - iterator.remove(); - - if (this.inUseCheck.test(this.internal.get(entry.getValue()))) { - inUse.add(entry.getValue()); - continue; - } - - V value = this.internal.remove(entry.getValue()); - - if (value == null) { - continue; - } - - this.postRemoval.accept(value); - } - - long nextExpiry = now + this.retention; - for (K value : inUse) { - this.expiry.put(nextExpiry, value); - } - } - } - -} diff --git a/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java b/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java index 9ed6fb8..6883999 100644 --- a/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java +++ b/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,13 +25,7 @@ import java.util.Set; import org.bukkit.OfflinePlayer; import org.bukkit.configuration.ConfigurationSection; -public class ConfigUpdater { - - private final OpenInv plugin; - - public ConfigUpdater(OpenInv plugin) { - this.plugin = plugin; - } +public record ConfigUpdater(OpenInv plugin) { public void checkForUpdates() { final int version = plugin.getConfig().getInt("config-version", 1); @@ -60,6 +54,9 @@ public class ConfigUpdater { if (version < 4) { updateConfig3To4(); } + if (version < 5) { + updateConfig4To5(); + } plugin.getServer().getScheduler().runTask(plugin, () -> { plugin.saveConfig(); @@ -68,6 +65,13 @@ public class ConfigUpdater { }); } + private void updateConfig4To5() { + plugin.getServer().getScheduler().runTask(plugin, () -> { + plugin.getConfig().set("settings.disable-offline-access", false); + plugin.getConfig().set("config-version", 5); + }); + } + private void updateConfig3To4() { plugin.getServer().getScheduler().runTask(plugin, () -> { plugin.getConfig().set("notify", null); diff --git a/plugin/src/main/java/com/lishid/openinv/util/Permissions.java b/plugin/src/main/java/com/lishid/openinv/util/Permissions.java index 7876af3..c2af2e1 100644 --- a/plugin/src/main/java/com/lishid/openinv/util/Permissions.java +++ b/plugin/src/main/java/com/lishid/openinv/util/Permissions.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,7 @@ package com.lishid.openinv.util; import org.bukkit.permissions.Permissible; +import org.jetbrains.annotations.NotNull; public enum Permissions { @@ -50,7 +51,7 @@ public enum Permissions { this.uninheritable = uninheritable; } - public boolean hasPermission(Permissible permissible) { + public boolean hasPermission(@NotNull Permissible permissible) { boolean hasPermission = permissible.hasPermission(permission); if (uninheritable || hasPermission || permissible.isPermissionSet(permission)) { diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index d8bc7bb..f0b56f0 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -1,4 +1,5 @@ -config-version: 4 +config-version: 5 settings: + disable-offline-access: false disable-saving: false locale: 'en_us' -- 2.49.1 From 6ad6e0c6bc84f670dbd1535e986db3e5799018f8 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 13 May 2022 11:50:50 -0400 Subject: [PATCH 071/139] Bump version to 4.2.0-SNAPSHOT --- api/pom.xml | 4 ++-- assembly/pom.xml | 4 ++-- internal/v1_17_R1/pom.xml | 2 +- internal/v1_18_R1/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- plugin/pom.xml | 4 ++-- pom.xml | 6 +++--- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 4e2a1a9..d815843 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -1,5 +1,5 @@ - - - 4.0.0 - - - openinvparent - com.lishid - ../../pom.xml - 4.2.0-SNAPSHOT - - - openinvadapter1_17_R1 - OpenInvAdapter1_17_R1 - - - 16 - 16 - 1.17.1-R0.1-SNAPSHOT - - - - - spigot - org.spigotmc - provided - ${spigot.version} - remapped-mojang - - - openinvapi - com.lishid - provided - - - openinvplugincore - com.lishid - - - annotations - org.jetbrains - - - - - - - maven-shade-plugin - - - false - - - - maven-compiler-plugin - - - net.md-5 - specialsource-maven-plugin - - - - - diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java deleted file mode 100644 index 61d4a20..0000000 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/AnySilentContainer.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (C) 2011-2022 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_17_R1; - -import com.lishid.openinv.OpenInv; -import com.lishid.openinv.internal.IAnySilentContainer; -import com.lishid.openinv.util.ReflectionHelper; -import java.lang.reflect.Field; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.ServerPlayerGameMode; -import net.minecraft.world.CompoundContainer; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.SimpleMenuProvider; -import net.minecraft.world.entity.monster.Shulker; -import net.minecraft.world.inventory.ChestMenu; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.PlayerEnderChestContainer; -import net.minecraft.world.level.GameType; -import net.minecraft.world.level.block.BarrelBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.ChestBlock; -import net.minecraft.world.level.block.DoubleBlockCombiner; -import net.minecraft.world.level.block.ShulkerBoxBlock; -import net.minecraft.world.level.block.TrappedChestBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.ChestBlockEntity; -import net.minecraft.world.level.block.entity.EnderChestBlockEntity; -import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; -import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.Statistic; -import org.bukkit.block.ShulkerBox; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class AnySilentContainer implements IAnySilentContainer { - - private @Nullable Field serverPlayerGameModeGameType; - - public AnySilentContainer() { - try { - try { - // IDE warns about field not existing, but SpecialSource does not remap strings used in reflection. - // The warning is not suppressed as a reminder that it must manually be checked on updates. - this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("b"); - this.serverPlayerGameModeGameType.setAccessible(true); - } catch (NoSuchFieldException e) { - Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); - logger.warning("ServerPlayerGameMode#gameModeForPlayer's obfuscated name has changed!"); - logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues"); - logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail."); - // N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break. - this.serverPlayerGameModeGameType = ReflectionHelper.grabFieldByType(ServerPlayerGameMode.class, GameType.class); - } - } catch (SecurityException e) { - Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); - logger.warning("Unable to directly write player game mode! SilentContainer will fail."); - logger.log(Level.WARNING, "Error obtaining GameType field", e); - } - } - - @Override - public boolean isShulkerBlocked(@NotNull ShulkerBox shulkerBox) { - org.bukkit.World bukkitWorld = shulkerBox.getWorld(); - if (!(bukkitWorld instanceof CraftWorld)) { - bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); - } - - if (!(bukkitWorld instanceof CraftWorld craftWorld)) { - Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); - OpenInv.getPlugin(OpenInv.class).getLogger().log(Level.WARNING, exception.getMessage(), exception); - return false; - } - - final ServerLevel world = craftWorld.getHandle(); - final BlockPos blockPosition = new BlockPos(shulkerBox.getX(), shulkerBox.getY(), shulkerBox.getZ()); - final BlockEntity tile = world.getBlockEntity(blockPosition); - - if (!(tile instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) - || shulkerBoxBlockEntity.getAnimationStatus() != ShulkerBoxBlockEntity.AnimationStatus.CLOSED) { - return false; - } - - BlockState blockState = world.getBlockState(blockPosition); - - // See net.minecraft.world.level.block.ShulkerBoxBlock#canOpen - AABB boundingBox = Shulker.getProgressDeltaAabb(blockState.getValue(ShulkerBoxBlock.FACING), 0.0F, 0.5F) - .move(blockPosition) - .deflate(1.0E-6D); - return !world.noCollision(boundingBox); - } - - @Override - public boolean activateContainer( - @NotNull final Player bukkitPlayer, - final boolean silentchest, - @NotNull final org.bukkit.block.Block bukkitBlock) { - - // Silent ender chest is API-only - if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) { - bukkitPlayer.openInventory(bukkitPlayer.getEnderChest()); - bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); - return true; - } - - ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); - - final ServerLevel level = player.getLevel(); - final BlockPos blockPos = new BlockPos(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); - final BlockEntity blockEntity = level.getBlockEntity(blockPos); - - if (blockEntity == null) { - return false; - } - - if (blockEntity instanceof EnderChestBlockEntity enderChestTile) { - // Anychest ender chest. See net.minecraft.world.level.block.BlockEnderChest - PlayerEnderChestContainer enderChest = player.getEnderChestInventory(); - enderChest.setActiveChest(enderChestTile); - player.openMenu(new SimpleMenuProvider((containerCounter, playerInventory, ignored) -> { - MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); - int rows = enderChest.getContainerSize() / 9; - return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); - }, new TranslatableComponent("container.enderchest"))); - bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); - return true; - } - - if (!(blockEntity instanceof MenuProvider menuProvider)) { - return false; - } - - BlockState blockState = level.getBlockState(blockPos); - Block block = blockState.getBlock(); - - if (block instanceof ChestBlock chestBlock) { - - // boolean flag: do not check if chest is blocked - Optional menuOptional = chestBlock.combine(blockState, level, blockPos, true).apply( - // Combiner is a copy of private ChestBlock.MENU_PROVIDER_COMBINER - new DoubleBlockCombiner.Combiner>() { - @Override - public Optional acceptDouble(ChestBlockEntity localChest1, ChestBlockEntity localChest2) { - CompoundContainer doubleChest = new CompoundContainer(localChest1, localChest2); - return Optional.of(new ChestBlock.DoubleInventory(localChest1, localChest2, doubleChest)); - } - - @Override - public Optional acceptSingle(ChestBlockEntity localChest) { - return Optional.of(localChest); - } - - @Override - public Optional acceptNone() { - return Optional.empty(); - } - }); - - if (menuOptional.isEmpty()) { - OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); - return false; - } - - menuProvider = menuOptional.get(); - - if (block instanceof TrappedChestBlock) { - bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); - } else { - bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED); - } - } - - if (block instanceof ShulkerBoxBlock) { - bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED); - } - - if (block instanceof BarrelBlock) { - bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL); - } - - // AnyChest only - SilentChest not active, container unsupported, or unnecessary. - if (!silentchest || player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) { - player.openMenu(menuProvider); - return true; - } - - // SilentChest requires access to setting players' game mode directly. - if (this.serverPlayerGameModeGameType == null) { - return false; - } - - if (blockEntity instanceof RandomizableContainerBlockEntity lootable) { - if (lootable.lootTable != null) { - OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); - return false; - } - } - - GameType gameType = player.gameMode.getGameModeForPlayer(); - this.forceGameType(player, GameType.SPECTATOR); - player.openMenu(menuProvider); - this.forceGameType(player, gameType); - return true; - } - - @Override - public void deactivateContainer(@NotNull final Player bukkitPlayer) { - if (this.serverPlayerGameModeGameType == null) { - return; - } - - InventoryView view = bukkitPlayer.getOpenInventory(); - switch (view.getType()) { - case CHEST: - case ENDER_CHEST: - case SHULKER_BOX: - case BARREL: - break; - default: - return; - } - - ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); - - // Force game mode change without informing plugins or players. - // Regular game mode set calls GameModeChangeEvent and is cancellable. - GameType gameType = player.gameMode.getGameModeForPlayer(); - this.forceGameType(player, GameType.SPECTATOR); - - // ServerPlayer#closeContainer cannot be called without entering an - // infinite loop because this method is called during inventory close. - // From ServerPlayer#closeContainer -> CraftEventFactory#handleInventoryCloseEvent - player.containerMenu.transferTo(player.inventoryMenu, player.getBukkitEntity()); - // From ServerPlayer#closeContainer - player.doCloseContainer(); - // Regular inventory close will handle the rest - packet sending, etc. - - // Revert forced game mode. - this.forceGameType(player, gameType); - } - - private void forceGameType(final ServerPlayer player, final GameType gameMode) { - if (this.serverPlayerGameModeGameType == null) { - // No need to warn repeatedly, error on startup and lack of function should be enough. - return; - } - try { - this.serverPlayerGameModeGameType.setAccessible(true); - this.serverPlayerGameModeGameType.set(player.gameMode, gameMode); - } catch (IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - } - } - -} diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java b/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java deleted file mode 100644 index e17c144..0000000 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/PlayerDataManager.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2011-2022 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_17_R1; - -import com.lishid.openinv.OpenInv; -import com.lishid.openinv.internal.IPlayerDataManager; -import com.lishid.openinv.internal.ISpecialInventory; -import com.lishid.openinv.internal.OpenInventoryView; -import com.mojang.authlib.GameProfile; -import java.lang.reflect.Field; -import java.util.logging.Logger; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_17_R1.event.CraftEventFactory; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftContainer; -import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class PlayerDataManager implements IPlayerDataManager { - - private @Nullable Field bukkitEntity; - - public PlayerDataManager() { - try { - bukkitEntity = Entity.class.getDeclaredField("bukkitEntity"); - } catch (NoSuchFieldException e) { - Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); - logger.warning("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded."); - logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); - bukkitEntity = null; - } - } - - public static @NotNull ServerPlayer getHandle(final Player player) { - if (player instanceof CraftPlayer) { - return ((CraftPlayer) player).getHandle(); - } - - Server server = player.getServer(); - ServerPlayer nmsPlayer = null; - - if (server instanceof CraftServer) { - nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getUniqueId()); - } - - if (nmsPlayer == null) { - // Could use reflection to examine fields, but it's honestly not worth the bother. - throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation"); - } - - return nmsPlayer; - } - - @Override - public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { - // Ensure player has data - if (!offline.hasPlayedBefore()) { - return null; - } - - // Create a profile and entity to load the player data - // See net.minecraft.server.PlayerList#attemptLogin - GameProfile profile = new GameProfile(offline.getUniqueId(), - offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel worldServer = server.getLevel(Level.OVERWORLD); - - if (worldServer == null) { - return null; - } - - ServerPlayer entity = new ServerPlayer(server, worldServer, profile); - - try { - injectPlayer(entity); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - - // Get the bukkit entity - Player target = entity.getBukkitEntity(); - if (target != null) { - // Load data - target.loadData(); - } - // Return the entity - return target; - } - - void injectPlayer(ServerPlayer player) throws IllegalAccessException { - if (bukkitEntity == null) { - return; - } - - bukkitEntity.setAccessible(true); - - bukkitEntity.set(player, new OpenPlayer(player.server.server, player)); - } - - @NotNull - @Override - public Player inject(@NotNull Player player) { - try { - ServerPlayer nmsPlayer = getHandle(player); - if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) { - return openPlayer; - } - injectPlayer(nmsPlayer); - return nmsPlayer.getBukkitEntity(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - return player; - } - } - - @Nullable - @Override - public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) { - - ServerPlayer nmsPlayer = getHandle(player); - - if (nmsPlayer.connection == null) { - return null; - } - - InventoryView view = getView(player, inventory); - - if (view == null) { - return player.openInventory(inventory.getBukkitInventory()); - } - - AbstractContainerMenu container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { - @Override - public MenuType getType() { - return getContainers(inventory.getBukkitInventory().getSize()); - } - }; - - container.setTitle(new TextComponent(view.getTitle())); - container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); - - if (container == null) { - return null; - } - - nmsPlayer.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), - new TextComponent(container.getBukkitView().getTitle()))); - nmsPlayer.containerMenu = container; - nmsPlayer.initMenu(container); - - return container.getBukkitView(); - - } - - private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) { - if (inventory instanceof SpecialEnderChest) { - return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest"); - } else if (inventory instanceof SpecialPlayerInventory) { - return new OpenInventoryView(player, inventory, "container.player", "'s Inventory"); - } else { - return null; - } - } - - static @NotNull MenuType getContainers(int inventorySize) { - - return switch (inventorySize) { - case 9 -> MenuType.GENERIC_9x1; - case 18 -> MenuType.GENERIC_9x2; - case 36 -> MenuType.GENERIC_9x4; // PLAYER - case 41, 45 -> MenuType.GENERIC_9x5; - case 54 -> MenuType.GENERIC_9x6; - default -> MenuType.GENERIC_9x3; // Default 27-slot inventory - }; - } - - @Override - public int convertToPlayerSlot(InventoryView view, int rawSlot) { - int topSize = view.getTopInventory().getSize(); - if (topSize <= rawSlot) { - // Slot is not inside special inventory, use Bukkit logic. - return view.convertSlot(rawSlot); - } - - // Main inventory, slots 0-26 -> 9-35 - if (rawSlot < 27) { - return rawSlot + 9; - } - // Hotbar, slots 27-35 -> 0-8 - if (rawSlot < 36) { - return rawSlot - 27; - } - // Armor, slots 36-39 -> 39-36 - if (rawSlot < 40) { - return 36 + (39 - rawSlot); - } - // Off hand - if (rawSlot == 40) { - return 40; - } - // Drop slots, "out of inventory" - return -1; - } - -} diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java deleted file mode 100644 index adcb22c..0000000 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/OpenPlayer.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2011-2021 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_18_R1; - -import java.io.File; -import net.minecraft.Util; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.storage.PlayerDataStorage; -import org.apache.logging.log4j.LogManager; -import org.bukkit.craftbukkit.v1_18_R1.CraftServer; -import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer; - -public class OpenPlayer extends CraftPlayer { - - public OpenPlayer(CraftServer server, ServerPlayer entity) { - super(server, entity); - } - - @Override - public void loadData() { - // See CraftPlayer#loadData - CompoundTag loaded = this.server.getHandle().playerIo.load(this.getHandle()); - if (loaded != null) { - readExtraData(loaded); - } - } - - @Override - public void saveData() { - ServerPlayer player = this.getHandle(); - // See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman) - try { - PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; - - CompoundTag playerData = player.saveWithoutId(new CompoundTag()); - setExtraData(playerData); - - if (!isOnline()) { - // Special case: save old vehicle data - CompoundTag oldData = worldNBTStorage.load(player); - - if (oldData != null && oldData.contains("RootVehicle", 10)) { - // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound) - playerData.put("RootVehicle", oldData.getCompound("RootVehicle")); - } - } - - File file = File.createTempFile(player.getStringUUID() + "-", ".dat", worldNBTStorage.getPlayerDir()); - NbtIo.writeCompressed(playerData, file); - File file1 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat"); - File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); - Util.safeReplaceFile(file1, file, file2); - } catch (Exception e) { - LogManager.getLogger().warn("Failed to save player data for {}: {}", player.getName().getString(), e.getMessage()); - } - } - -} diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java deleted file mode 100644 index ea67c5f..0000000 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialEnderChest.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2011-2022 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_18_R1; - -import com.lishid.openinv.internal.ISpecialEnderChest; -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.ContainerHelper; -import net.minecraft.world.ContainerListener; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.player.StackedContents; -import net.minecraft.world.inventory.PlayerEnderChestContainer; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.EnderChestBlockEntity; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_18_R1.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftInventory; -import org.bukkit.entity.HumanEntity; -import org.bukkit.inventory.InventoryHolder; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpecialEnderChest { - - private final CraftInventory inventory; - private ServerPlayer owner; - private NonNullList items; - private boolean playerOnline; - - public SpecialEnderChest(final org.bukkit.entity.Player player, final Boolean online) { - super(PlayerDataManager.getHandle(player)); - this.inventory = new CraftInventory(this); - this.owner = PlayerDataManager.getHandle(player); - this.playerOnline = online; - this.items = this.owner.getEnderChestInventory().items; - } - - @Override - public @NotNull CraftInventory getBukkitInventory() { - return inventory; - } - - @Override - public void setPlayerOffline() { - this.playerOnline = false; - } - - @Override - public void setPlayerOnline(@NotNull final org.bukkit.entity.Player player) { - if (!this.playerOnline) { - try { - this.owner = PlayerDataManager.getHandle(player); - PlayerEnderChestContainer enderChest = owner.getEnderChestInventory(); - for (int i = 0; i < enderChest.getContainerSize(); ++i) { - enderChest.setItem(i, this.items.get(i)); - } - this.items = enderChest.items; - enderChest.transaction.addAll(this.transaction); - } catch (Exception ignored) {} - this.playerOnline = true; - } - } - - @Override - public @NotNull org.bukkit.entity.Player getPlayer() { - return owner.getBukkitEntity(); - } - - @Override - public void setChanged() { - this.owner.getEnderChestInventory().setChanged(); - } - - @Override - public List getContents() { - return this.items; - } - - @Override - public void onOpen(CraftHumanEntity who) { - this.owner.getEnderChestInventory().onOpen(who); - } - - @Override - public void onClose(CraftHumanEntity who) { - this.owner.getEnderChestInventory().onClose(who); - } - - @Override - public List getViewers() { - return this.owner.getEnderChestInventory().getViewers(); - } - - @Override - public boolean stillValid(Player player) { - return true; - } - - @Override - public void setActiveChest(EnderChestBlockEntity enderChest) { - this.owner.getEnderChestInventory().setActiveChest(enderChest); - } - - @Override - public boolean isActiveChest(EnderChestBlockEntity enderChest) { - return this.owner.getEnderChestInventory().isActiveChest(enderChest); - } - - @Override - public int getMaxStackSize() { - return this.owner.getEnderChestInventory().getMaxStackSize(); - } - - @Override - public void setMaxStackSize(int i) { - this.owner.getEnderChestInventory().setMaxStackSize(i); - } - - @Override - public InventoryHolder getOwner() { - return this.owner.getEnderChestInventory().getOwner(); - } - - @Override - public @Nullable Location getLocation() { - return null; - } - - @Override - public void addListener(ContainerListener listener) { - this.owner.getEnderChestInventory().addListener(listener); - } - - @Override - public void removeListener(ContainerListener listener) { - this.owner.getEnderChestInventory().removeListener(listener); - } - - @Override - public ItemStack getItem(int i) { - return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.EMPTY; - } - - @Override - public ItemStack removeItem(int i, int j) { - ItemStack itemstack = ContainerHelper.removeItem(this.items, i, j); - if (!itemstack.isEmpty()) { - this.setChanged(); - } - - return itemstack; - } - - @Override - public ItemStack addItem(ItemStack itemstack) { - ItemStack localItem = itemstack.copy(); - this.moveItemToOccupiedSlotsWithSameType(localItem); - if (localItem.isEmpty()) { - return ItemStack.EMPTY; - } else { - this.moveItemToEmptySlots(localItem); - return localItem.isEmpty() ? ItemStack.EMPTY : localItem; - } - } - - @Override - public boolean canAddItem(ItemStack itemstack) { - for (ItemStack itemstack1 : this.items) { - if (itemstack1.isEmpty() || ItemStack.isSameItemSameTags(itemstack1, itemstack) && itemstack1.getCount() < itemstack1.getMaxStackSize()) { - return true; - } - } - - return false; - } - - private void moveItemToEmptySlots(ItemStack itemstack) { - for(int i = 0; i < this.getContainerSize(); ++i) { - ItemStack localItem = this.getItem(i); - if (localItem.isEmpty()) { - this.setItem(i, itemstack.copy()); - itemstack.setCount(0); - return; - } - } - } - - private void moveItemToOccupiedSlotsWithSameType(ItemStack itemstack) { - for(int i = 0; i < this.getContainerSize(); ++i) { - ItemStack localItem = this.getItem(i); - if (ItemStack.isSameItemSameTags(localItem, itemstack)) { - this.moveItemsBetweenStacks(itemstack, localItem); - if (itemstack.isEmpty()) { - return; - } - } - } - } - - private void moveItemsBetweenStacks(ItemStack itemstack, ItemStack itemstack1) { - int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize()); - int j = Math.min(itemstack.getCount(), i - itemstack1.getCount()); - if (j > 0) { - itemstack1.grow(j); - itemstack.shrink(j); - this.setChanged(); - } - } - - @Override - public ItemStack removeItemNoUpdate(int i) { - ItemStack itemstack = this.items.get(i); - if (itemstack.isEmpty()) { - return ItemStack.EMPTY; - } else { - this.items.set(i, ItemStack.EMPTY); - return itemstack; - } - } - - @Override - public void setItem(int i, ItemStack itemstack) { - this.items.set(i, itemstack); - if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { - itemstack.setCount(this.getMaxStackSize()); - } - - this.setChanged(); - } - - @Override - public int getContainerSize() { - return this.owner.getEnderChestInventory().getContainerSize(); - } - - @Override - public boolean isEmpty() { - return this.items.stream().allMatch(ItemStack::isEmpty); - } - - @Override - public void startOpen(Player player) { - } - - @Override - public void stopOpen(Player player) { - } - - @Override - public boolean canPlaceItem(int i, ItemStack itemstack) { - return true; - } - - @Override - public void clearContent() { - this.items.clear(); - this.setChanged(); - } - - @Override - public void fillStackedContents(StackedContents stackedContents) { - for (ItemStack itemstack : this.items) { - stackedContents.accountStack(itemstack); - } - - } - - @Override - public List removeAllItems() { - List list = this.items.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList()); - this.clearContent(); - return list; - } - - @Override - public ItemStack removeItemType(Item item, int i) { - ItemStack itemstack = new ItemStack(item, 0); - - for(int j = this.getContainerSize() - 1; j >= 0; --j) { - ItemStack localItem = this.getItem(j); - if (localItem.getItem().equals(item)) { - int k = i - itemstack.getCount(); - ItemStack splitItem = localItem.split(k); - itemstack.grow(splitItem.getCount()); - if (itemstack.getCount() == i) { - break; - } - } - } - - if (!itemstack.isEmpty()) { - this.setChanged(); - } - - return itemstack; - } - - @Override - public String toString() { - return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).collect(Collectors.toList()).toString(); - } - - @Override - public void fromTag(ListTag listTag) { - for (int i = 0; i < this.getContainerSize(); ++i) { - this.setItem(i, ItemStack.EMPTY); - } - - for (int i = 0; i < listTag.size(); ++i) { - CompoundTag compoundTag = listTag.getCompound(i); - int j = compoundTag.getByte("Slot") & 255; - if (j < this.getContainerSize()) { - this.setItem(j, ItemStack.of(compoundTag)); - } - } - - } - -} diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java b/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java deleted file mode 100644 index 6508f3d..0000000 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/SpecialPlayerInventory.java +++ /dev/null @@ -1,787 +0,0 @@ -/* - * Copyright (C) 2011-2022 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_18_R1; - -import com.google.common.collect.ImmutableList; -import com.lishid.openinv.internal.ISpecialPlayerInventory; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import net.minecraft.CrashReport; -import net.minecraft.CrashReportCategory; -import net.minecraft.ReportedException; -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.tags.Tag; -import net.minecraft.world.Container; -import net.minecraft.world.ContainerHelper; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.player.StackedContents; -import net.minecraft.world.item.ArmorItem; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_18_R1.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftInventory; -import org.bukkit.entity.HumanEntity; -import org.bukkit.inventory.InventoryHolder; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerInventory { - - private final CraftInventory inventory; - private boolean playerOnline; - private Player player; - private NonNullList items; - private NonNullList armor; - private NonNullList offhand; - private List> compartments; - - public SpecialPlayerInventory(@NotNull org.bukkit.entity.Player bukkitPlayer, @NotNull Boolean online) { - super(PlayerDataManager.getHandle(bukkitPlayer)); - this.inventory = new CraftInventory(this); - this.playerOnline = online; - this.player = super.player; - this.selected = player.getInventory().selected; - this.items = this.player.getInventory().items; - this.armor = this.player.getInventory().armor; - this.offhand = this.player.getInventory().offhand; - this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); - } - - @Override - public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) { - if (!this.playerOnline) { - Player entityPlayer = PlayerDataManager.getHandle(player); - entityPlayer.getInventory().transaction.addAll(this.transaction); - this.player = entityPlayer; - for (int i = 0; i < getContainerSize(); ++i) { - this.player.getInventory().setItem(i, getRawItem(i)); - } - this.player.getInventory().selected = this.selected; - this.items = this.player.getInventory().items; - this.armor = this.player.getInventory().armor; - this.offhand = this.player.getInventory().offhand; - this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); - this.playerOnline = true; - } - } - - @Override - public @NotNull CraftInventory getBukkitInventory() { - return this.inventory; - } - - @Override - public void setPlayerOffline() { - this.playerOnline = false; - } - - @Override - public @NotNull HumanEntity getPlayer() { - return this.player.getBukkitEntity(); - } - - private @NotNull ItemStack getRawItem(int i) { - if (i < 0) { - return ItemStack.EMPTY; - } - - NonNullList list; - for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { - list = iterator.next(); - if (i < list.size()) { - return list.get(i); - } - } - - return ItemStack.EMPTY; - } - - private void setRawItem(int i, @NotNull ItemStack itemStack) { - if (i < 0) { - return; - } - - NonNullList list; - for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { - list = iterator.next(); - if (i < list.size()) { - list.set(i, itemStack); - } - } - } - - private static record IndexedCompartment(@Nullable NonNullList compartment, int index) {} - - private @NotNull SpecialPlayerInventory.IndexedCompartment getIndexedContent(int index) { - if (index < items.size()) { - return new IndexedCompartment(items, getReversedItemSlotNum(index)); - } - - index -= items.size(); - - if (index < armor.size()) { - return new IndexedCompartment(armor, getReversedArmorSlotNum(index)); - } - - index -= armor.size(); - - if (index < offhand.size()) { - return new IndexedCompartment(offhand, index); - } - - index -= offhand.size(); - - return new IndexedCompartment(null, index); - } - - private int getReversedArmorSlotNum(final int i) { - if (i == 0) { - return 3; - } - if (i == 1) { - return 2; - } - if (i == 2) { - return 1; - } - if (i == 3) { - return 0; - } - return i; - } - - private int getReversedItemSlotNum(final int i) { - if (i >= 27) { - return i - 27; - } - return i + 9; - } - - private boolean contains(Predicate predicate) { - return this.compartments.stream().flatMap(NonNullList::stream).anyMatch(predicate); - } - - @Override - public List getArmorContents() { - return this.armor; - } - - @Override - public void onOpen(CraftHumanEntity who) { - this.player.getInventory().onOpen(who); - } - - @Override - public void onClose(CraftHumanEntity who) { - this.player.getInventory().onClose(who); - } - - @Override - public List getViewers() { - return this.player.getInventory().getViewers(); - } - - @Override - public InventoryHolder getOwner() { - return this.player.getBukkitEntity(); - } - - @Override - public int getMaxStackSize() { - return this.player.getInventory().getMaxStackSize(); - } - - @Override - public void setMaxStackSize(int size) { - this.player.getInventory().setMaxStackSize(size); - } - - @Override - public Location getLocation() { - return this.player.getBukkitEntity().getLocation(); - } - - @Override - public boolean hasCustomName() { - return false; - } - - @Override - public List getContents() { - return this.compartments.stream().flatMap(Collection::stream).collect(Collectors.toList()); - } - - @Override - public ItemStack getSelected() { - return isHotbarSlot(this.selected) ? this.items.get(this.selected) : ItemStack.EMPTY; - } - - private boolean hasRemainingSpaceForItem(ItemStack itemstack, ItemStack itemstack1) { - return !itemstack.isEmpty() && ItemStack.isSameItemSameTags(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); - } - - @Override - public int canHold(ItemStack itemstack) { - int remains = itemstack.getCount(); - - for (int i = 0; i < this.items.size(); ++i) { - ItemStack itemstack1 = this.getRawItem(i); - if (itemstack1.isEmpty()) { - return itemstack.getCount(); - } - - if (this.hasRemainingSpaceForItem(itemstack1, itemstack)) { - remains -= (itemstack1.getMaxStackSize() < this.getMaxStackSize() ? itemstack1.getMaxStackSize() : this.getMaxStackSize()) - itemstack1.getCount(); - } - - if (remains <= 0) { - return itemstack.getCount(); - } - } - - ItemStack offhandItemStack = this.getRawItem(this.items.size() + this.armor.size()); - if (this.hasRemainingSpaceForItem(offhandItemStack, itemstack)) { - remains -= (offhandItemStack.getMaxStackSize() < this.getMaxStackSize() ? offhandItemStack.getMaxStackSize() : this.getMaxStackSize()) - offhandItemStack.getCount(); - } - - return remains <= 0 ? itemstack.getCount() : itemstack.getCount() - remains; - } - - @Override - public int getFreeSlot() { - for(int i = 0; i < this.items.size(); ++i) { - if (this.items.get(i).isEmpty()) { - return i; - } - } - - return -1; - } - - @Override - public void setPickedItem(ItemStack itemstack) { - int i = this.findSlotMatchingItem(itemstack); - if (isHotbarSlot(i)) { - this.selected = i; - } else if (i == -1) { - this.selected = this.getSuitableHotbarSlot(); - if (!this.items.get(this.selected).isEmpty()) { - int j = this.getFreeSlot(); - if (j != -1) { - this.items.set(j, this.items.get(this.selected)); - } - } - - this.items.set(this.selected, itemstack); - } else { - this.pickSlot(i); - } - - } - - @Override - public void pickSlot(int i) { - this.selected = this.getSuitableHotbarSlot(); - ItemStack itemstack = this.items.get(this.selected); - this.items.set(this.selected, this.items.get(i)); - this.items.set(i, itemstack); - } - - @Override - public int findSlotMatchingItem(ItemStack itemstack) { - for(int i = 0; i < this.items.size(); ++i) { - if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemstack, this.items.get(i))) { - return i; - } - } - - return -1; - } - - @Override - public int findSlotMatchingUnusedItem(ItemStack itemStack) { - for(int i = 0; i < this.items.size(); ++i) { - ItemStack localItem = this.items.get(i); - if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemStack, this.items.get(i)) && !this.items.get(i).isDamaged() && !localItem.isEnchanted() && !localItem.hasCustomHoverName()) { - return i; - } - } - - return -1; - } - - @Override - public int getSuitableHotbarSlot() { - int i; - int j; - for(j = 0; j < 9; ++j) { - i = (this.selected + j) % 9; - if (this.items.get(i).isEmpty()) { - return i; - } - } - - for(j = 0; j < 9; ++j) { - i = (this.selected + j) % 9; - if (!this.items.get(i).isEnchanted()) { - return i; - } - } - - return this.selected; - } - - @Override - public void swapPaint(double d0) { - if (d0 > 0.0D) { - d0 = 1.0D; - } - - if (d0 < 0.0D) { - d0 = -1.0D; - } - - this.selected = (int) (this.selected - d0); - - while (this.selected < 0) { - this.selected += 9; - } - - while(this.selected >= 9) { - this.selected -= 9; - } - } - - @Override - public int clearOrCountMatchingItems(Predicate predicate, int i, Container container) { - byte b0 = 0; - boolean flag = i == 0; - int j = b0 + ContainerHelper.clearOrCountMatchingItems(this, predicate, i - b0, flag); - j += ContainerHelper.clearOrCountMatchingItems(container, predicate, i - j, flag); - ItemStack itemstack = this.player.containerMenu.getCarried(); - j += ContainerHelper.clearOrCountMatchingItems(itemstack, predicate, i - j, flag); - if (itemstack.isEmpty()) { - this.player.containerMenu.setCarried(ItemStack.EMPTY); - } - - return j; - } - - private int addResource(ItemStack itemstack) { - int i = this.getSlotWithRemainingSpace(itemstack); - if (i == -1) { - i = this.getFreeSlot(); - } - - return i == -1 ? itemstack.getCount() : this.addResource(i, itemstack); - } - - private int addResource(int i, ItemStack itemstack) { - Item item = itemstack.getItem(); - int j = itemstack.getCount(); - ItemStack localItemStack = this.getRawItem(i); - if (localItemStack.isEmpty()) { - localItemStack = new ItemStack(item, 0); - if (itemstack.hasTag()) { - // hasTag ensures tag not null - //noinspection ConstantConditions - localItemStack.setTag(itemstack.getTag().copy()); - } - - this.setRawItem(i, localItemStack); - } - - int k = Math.min(j, localItemStack.getMaxStackSize() - localItemStack.getCount()); - - if (k > this.getMaxStackSize() - localItemStack.getCount()) { - k = this.getMaxStackSize() - localItemStack.getCount(); - } - - if (k != 0) { - j -= k; - localItemStack.grow(k); - localItemStack.setPopTime(5); - } - - return j; - } - - @Override - public int getSlotWithRemainingSpace(ItemStack itemstack) { - if (this.hasRemainingSpaceForItem(this.getRawItem(this.selected), itemstack)) { - return this.selected; - } else if (this.hasRemainingSpaceForItem(this.getRawItem(40), itemstack)) { - return 40; - } else { - for(int i = 0; i < this.items.size(); ++i) { - if (this.hasRemainingSpaceForItem(this.items.get(i), itemstack)) { - return i; - } - } - - return -1; - } - } - - @Override - public void tick() { - for (NonNullList compartment : this.compartments) { - for (int i = 0; i < compartment.size(); ++i) { - if (!compartment.get(i).isEmpty()) { - compartment.get(i).inventoryTick(this.player.level, this.player, i, this.selected == i); - } - } - } - - } - - @Override - public boolean add(ItemStack itemStack) { - return this.add(-1, itemStack); - } - - @Override - public boolean add(int i, ItemStack itemStack) { - if (itemStack.isEmpty()) { - return false; - } else { - try { - if (itemStack.isDamaged()) { - if (i == -1) { - i = this.getFreeSlot(); - } - - if (i >= 0) { - this.items.set(i, itemStack.copy()); - this.items.get(i).setPopTime(5); - itemStack.setCount(0); - return true; - } else if (this.player.getAbilities().instabuild) { - itemStack.setCount(0); - return true; - } else { - return false; - } - } else { - int j; - do { - j = itemStack.getCount(); - if (i == -1) { - itemStack.setCount(this.addResource(itemStack)); - } else { - itemStack.setCount(this.addResource(i, itemStack)); - } - } while(!itemStack.isEmpty() && itemStack.getCount() < j); - - if (itemStack.getCount() == j && this.player.getAbilities().instabuild) { - itemStack.setCount(0); - return true; - } else { - return itemStack.getCount() < j; - } - } - } catch (Throwable var6) { - CrashReport crashReport = CrashReport.forThrowable(var6, "Adding item to inventory"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Item being added"); - crashReportCategory.setDetail("Item ID", Item.getId(itemStack.getItem())); - crashReportCategory.setDetail("Item data", itemStack.getDamageValue()); - crashReportCategory.setDetail("Item name", () -> itemStack.getHoverName().getString()); - throw new ReportedException(crashReport); - } - } - } - - @Override - public void placeItemBackInInventory(ItemStack itemStack) { - this.placeItemBackInInventory(itemStack, true); - } - - @Override - public void placeItemBackInInventory(ItemStack itemStack, boolean flag) { - while(true) { - if (!itemStack.isEmpty()) { - int i = this.getSlotWithRemainingSpace(itemStack); - if (i == -1) { - i = this.getFreeSlot(); - } - - if (i != -1) { - int j = itemStack.getMaxStackSize() - this.getRawItem(i).getCount(); - if (this.add(i, itemStack.split(j)) && flag && this.player instanceof ServerPlayer) { - ((ServerPlayer)this.player).connection.send(new ClientboundContainerSetSlotPacket(-2, 0, i, this.getRawItem(i))); - } - continue; - } - - this.player.drop(itemStack, false); - } - - return; - } - } - - @Override - public ItemStack removeItem(int rawIndex, final int j) { - IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); - - if (indexedCompartment.compartment() == null - || indexedCompartment.compartment().get(indexedCompartment.index()).isEmpty()) { - return ItemStack.EMPTY; - } - - return ContainerHelper.removeItem(indexedCompartment.compartment(), indexedCompartment.index(), j); - } - - @Override - public void removeItem(ItemStack itemStack) { - for (NonNullList compartment : this.compartments) { - for (int i = 0; i < compartment.size(); ++i) { - if (compartment.get(i) == itemStack) { - compartment.set(i, ItemStack.EMPTY); - break; - } - } - } - } - - @Override - public ItemStack removeItemNoUpdate(int rawIndex) { - IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); - - if (indexedCompartment.compartment() == null) { - return ItemStack.EMPTY; - } - - ItemStack removed = indexedCompartment.compartment().set(indexedCompartment.index(), ItemStack.EMPTY); - - if (removed.isEmpty()) { - return ItemStack.EMPTY; - } - - return removed; - } - - @Override - public void setItem(int rawIndex, final ItemStack itemStack) { - IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); - - if (indexedCompartment.compartment() == null) { - this.player.drop(itemStack, true); - return; - } - - indexedCompartment.compartment().set(indexedCompartment.index(), itemStack); - } - - @Override - public float getDestroySpeed(BlockState blockState) { - return this.items.get(this.selected).getDestroySpeed(blockState); - } - - @Override - public ListTag save(ListTag listTag) { - for (int i = 0; i < this.items.size(); ++i) { - if (!this.items.get(i).isEmpty()) { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putByte("Slot", (byte)i); - this.items.get(i).save(compoundTag); - listTag.add(compoundTag); - } - } - - for (int i = 0; i < this.armor.size(); ++i) { - if (!this.armor.get(i).isEmpty()) { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putByte("Slot", (byte)(i + 100)); - this.armor.get(i).save(compoundTag); - listTag.add(compoundTag); - } - } - - for (int i = 0; i < this.offhand.size(); ++i) { - if (!this.offhand.get(i).isEmpty()) { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putByte("Slot", (byte)(i + 150)); - this.offhand.get(i).save(compoundTag); - listTag.add(compoundTag); - } - } - - return listTag; - } - - @Override - public void load(ListTag listTag) { - this.items.clear(); - this.armor.clear(); - this.offhand.clear(); - - for(int i = 0; i < listTag.size(); ++i) { - CompoundTag compoundTag = listTag.getCompound(i); - int j = compoundTag.getByte("Slot") & 255; - ItemStack itemstack = ItemStack.of(compoundTag); - if (!itemstack.isEmpty()) { - if (j < this.items.size()) { - this.items.set(j, itemstack); - } else if (j >= 100 && j < this.armor.size() + 100) { - this.armor.set(j - 100, itemstack); - } else if (j >= 150 && j < this.offhand.size() + 150) { - this.offhand.set(j - 150, itemstack); - } - } - } - - } - - @Override - public int getContainerSize() { - return 45; - } - - @Override - public boolean isEmpty() { - return !contains(itemStack -> !itemStack.isEmpty()); - } - - @Override - public ItemStack getItem(int rawIndex) { - IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); - - if (indexedCompartment.compartment() == null) { - return ItemStack.EMPTY; - } - - return indexedCompartment.compartment().get(indexedCompartment.index()); - } - - @Override - public Component getName() { - return this.player.getName(); - } - - @Override - public ItemStack getArmor(int index) { - return this.armor.get(index); - } - - @Override - public void hurtArmor(DamageSource damagesource, float damage, int[] armorIndices) { - if (damage > 0.0F) { - damage /= 4.0F; - if (damage < 1.0F) { - damage = 1.0F; - } - - for (int index : armorIndices) { - ItemStack itemstack = this.armor.get(index); - if ((!damagesource.isFire() || !itemstack.getItem().isFireResistant()) && itemstack.getItem() instanceof ArmorItem) { - itemstack.hurtAndBreak((int) damage, this.player, localPlayer -> localPlayer.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index))); - } - } - } - } - - @Override - public void dropAll() { - for (NonNullList compartment : this.compartments) { - for (int i = 0; i < compartment.size(); ++i) { - ItemStack itemstack = compartment.get(i); - if (!itemstack.isEmpty()) { - this.player.drop(itemstack, true, false); - compartment.set(i, ItemStack.EMPTY); - } - } - } - } - - @Override - public void setChanged() { - super.setChanged(); - } - - @Override - public int getTimesChanged() { - return super.getTimesChanged(); - } - - @Override - public boolean stillValid(Player player) { - return true; - } - - @Override - public boolean contains(ItemStack itemstack) { - return contains(itemStack -> itemStack.isEmpty() && itemStack.sameItem(itemstack)); - } - - @Override - public boolean contains(Tag tag) { - return contains(itemStack -> !itemStack.isEmpty() && itemStack.is(tag)); - } - - @Override - public void replaceWith(Inventory inventory) { - Function getter; - - if (inventory instanceof SpecialPlayerInventory specialPlayerInventory) { - getter = specialPlayerInventory::getRawItem; - } else { - getter = inventory::getItem; - } - - for(int i = 0; i < this.getContainerSize(); ++i) { - this.setRawItem(i, getter.apply(i)); - } - - this.selected = inventory.selected; - } - - @Override - public void clearContent() { - for (NonNullList compartment : this.compartments) { - compartment.clear(); - } - } - - @Override - public void fillStackedContents(StackedContents stackedContents) { - for (ItemStack itemstack : this.items) { - stackedContents.accountSimpleStack(itemstack); - } - } - - @Override - public ItemStack removeFromSelected(boolean dropWholeStack) { - ItemStack itemstack = this.getSelected(); - return itemstack.isEmpty() ? ItemStack.EMPTY : this.removeItem(this.selected, dropWholeStack ? itemstack.getCount() : 1); - } - -} diff --git a/internal/v1_18_R1/pom.xml b/internal/v1_19_R1/pom.xml similarity index 94% rename from internal/v1_18_R1/pom.xml rename to internal/v1_19_R1/pom.xml index 1c938b6..67fd1cb 100644 --- a/internal/v1_18_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -26,13 +26,13 @@ 4.2.0-SNAPSHOT - openinvadapter1_18_R1 - OpenInvAdapter1_18_R1 + openinvadapter1_19_R1 + OpenInvAdapter1_19_R1 17 17 - 1.18.1-R0.1-SNAPSHOT + 1.19-R0.1-SNAPSHOT diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/AnySilentContainer.java similarity index 98% rename from internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java rename to internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/AnySilentContainer.java index f7eb658..df53746 100644 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/AnySilentContainer.java +++ b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/AnySilentContainer.java @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -package com.lishid.openinv.internal.v1_18_R1; +package com.lishid.openinv.internal.v1_19_R1; import com.lishid.openinv.OpenInv; import com.lishid.openinv.internal.IAnySilentContainer; @@ -24,7 +24,7 @@ import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayerGameMode; @@ -53,7 +53,7 @@ import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Statistic; import org.bukkit.block.ShulkerBox; -import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.NotNull; @@ -147,7 +147,7 @@ public class AnySilentContainer implements IAnySilentContainer { MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); int rows = enderChest.getContainerSize() / 9; return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); - }, new TranslatableComponent("container.enderchest"))); + }, Component.translatable(("container.enderchest")))); bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); return true; } diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/OpenPlayer.java similarity index 92% rename from internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java rename to internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/OpenPlayer.java index a4bc700..bc1781a 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/OpenPlayer.java +++ b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/OpenPlayer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -package com.lishid.openinv.internal.v1_17_R1; +package com.lishid.openinv.internal.v1_19_R1; import java.io.File; import net.minecraft.Util; @@ -23,8 +23,8 @@ import net.minecraft.nbt.NbtIo; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.storage.PlayerDataStorage; import org.apache.logging.log4j.LogManager; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.CraftServer; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; public class OpenPlayer extends CraftPlayer { diff --git a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/PlayerDataManager.java similarity index 92% rename from internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java rename to internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/PlayerDataManager.java index 75f18d5..da0232a 100644 --- a/internal/v1_18_R1/src/main/java/com/lishid/openinv/internal/v1_18_R1/PlayerDataManager.java +++ b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/PlayerDataManager.java @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -package com.lishid.openinv.internal.v1_18_R1; +package com.lishid.openinv.internal.v1_19_R1; import com.lishid.openinv.OpenInv; import com.lishid.openinv.internal.IPlayerDataManager; @@ -23,7 +23,7 @@ import com.lishid.openinv.internal.OpenInventoryView; import com.mojang.authlib.GameProfile; import java.lang.reflect.Field; import java.util.logging.Logger; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -35,10 +35,10 @@ import net.minecraft.world.level.Level; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.Server; -import org.bukkit.craftbukkit.v1_18_R1.CraftServer; -import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_18_R1.event.CraftEventFactory; -import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftContainer; +import org.bukkit.craftbukkit.v1_19_R1.CraftServer; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.event.CraftEventFactory; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftContainer; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.NotNull; @@ -87,7 +87,8 @@ public class PlayerDataManager implements IPlayerDataManager { } // Create a profile and entity to load the player data - // See net.minecraft.server.PlayerList#attemptLogin + // See net.minecraft.server.players.PlayerList#canPlayerLogin + // and net.minecraft.server.network.ServerLoginPacketListenerImpl#handleHello GameProfile profile = new GameProfile(offline.getUniqueId(), offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); @@ -97,7 +98,7 @@ public class PlayerDataManager implements IPlayerDataManager { return null; } - ServerPlayer entity = new ServerPlayer(server, worldServer, profile); + ServerPlayer entity = new ServerPlayer(server, worldServer, profile, null); try { injectPlayer(entity); @@ -164,7 +165,7 @@ public class PlayerDataManager implements IPlayerDataManager { } }; - container.setTitle(new TextComponent(view.getTitle())); + container.setTitle(Component.literal(view.getTitle())); container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); if (container == null) { @@ -172,7 +173,7 @@ public class PlayerDataManager implements IPlayerDataManager { } nmsPlayer.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), - new TextComponent(container.getBukkitView().getTitle()))); + Component.literal(container.getBukkitView().getTitle()))); nmsPlayer.containerMenu = container; nmsPlayer.initMenu(container); diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialEnderChest.java similarity index 97% rename from internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java rename to internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialEnderChest.java index 6d48d54..e2a5546 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialEnderChest.java +++ b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialEnderChest.java @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -package com.lishid.openinv.internal.v1_17_R1; +package com.lishid.openinv.internal.v1_19_R1; import com.lishid.openinv.internal.ISpecialEnderChest; import java.util.List; @@ -33,8 +33,8 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.EnderChestBlockEntity; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventory; import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.InventoryHolder; import org.jetbrains.annotations.NotNull; @@ -317,7 +317,7 @@ public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpe @Override public String toString() { - return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).collect(Collectors.toList()).toString(); + return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).toList().toString(); } @Override diff --git a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialPlayerInventory.java similarity index 98% rename from internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java rename to internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialPlayerInventory.java index af7d5cb..d819e35 100644 --- a/internal/v1_17_R1/src/main/java/com/lishid/openinv/internal/v1_17_R1/SpecialPlayerInventory.java +++ b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialPlayerInventory.java @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -package com.lishid.openinv.internal.v1_17_R1; +package com.lishid.openinv.internal.v1_19_R1; import com.google.common.collect.ImmutableList; import com.lishid.openinv.internal.ISpecialPlayerInventory; @@ -33,7 +33,7 @@ import net.minecraft.nbt.ListTag; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.tags.Tag; +import net.minecraft.tags.TagKey; import net.minecraft.world.Container; import net.minecraft.world.ContainerHelper; import net.minecraft.world.damagesource.DamageSource; @@ -46,8 +46,8 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventory; import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.InventoryHolder; import org.jetbrains.annotations.NotNull; @@ -138,7 +138,7 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI } } - private static record IndexedCompartment(@Nullable NonNullList compartment, int index) {} + private record IndexedCompartment(@Nullable NonNullList compartment, int index) {} private @NotNull SpecialPlayerInventory.IndexedCompartment getIndexedContent(int index) { if (index < items.size()) { @@ -743,8 +743,9 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI } @Override - public boolean contains(Tag tag) { - return contains(itemStack -> !itemStack.isEmpty() && itemStack.is(tag)); + public boolean contains(TagKey tagKey) { + + return contains(itemStack -> !itemStack.isEmpty() && itemStack.is(tagKey)); } @Override diff --git a/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java b/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java index dbe7e98..d1dbf4a 100644 --- a/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java +++ b/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java @@ -63,6 +63,7 @@ class InternalAccessor { case "v1_16_R1" -> "https://github.com/lishid/OpenInv/releases/tag/4.1.4"; case "v1_8_R3", "v1_15_R1", "v1_16_R2" -> "https://github.com/lishid/OpenInv/releases/tag/4.1.5"; case "v1_16_R3" -> "https://github.com/Jikoo/OpenInv/releases/tag/4.1.8"; + case "v1_17_R1", "v1_18_R1" -> "https://github.com/Jikoo/OpenInv/releases/tag/4.1.10"; default -> "https://github.com/Jikoo/OpenInv/releases"; }; } diff --git a/pom.xml b/pom.xml index 5d5ee6a..e09b7e7 100644 --- a/pom.xml +++ b/pom.xml @@ -39,9 +39,8 @@ api plugin - internal/v1_17_R1 - internal/v1_18_R1 internal/v1_18_R2 + internal/v1_19_R1 assembly -- 2.49.1 From 9c934e440d5bfe9c00bf525ba305c8f871340442 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Tue, 7 Jun 2022 14:09:51 -0400 Subject: [PATCH 080/139] Update main plugin to Java 17 All supported versions require Java 17, there's no reason the plugin should not. Swap to Temurin for CI, Adopt is dead. --- .github/workflows/ci.yml | 2 +- pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 176cd38..09682ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/setup-java@v3 with: - distribution: 'adopt' + distribution: 'temurin' java-version: '17' cache: 'maven' diff --git a/pom.xml b/pom.xml index e09b7e7..037125f 100644 --- a/pom.xml +++ b/pom.xml @@ -27,8 +27,8 @@ UTF-8 - 16 - 16 + 17 + 17 unknown -- 2.49.1 From fcb9ccb6e64d1e9c10a7759fc09a0f61529875a5 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Tue, 7 Jun 2022 19:41:39 -0400 Subject: [PATCH 081/139] Bump version to 4.2.0 for release --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- internal/v1_19_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index d815843..5d907ec 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.0-SNAPSHOT + 4.2.0 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 9afb4be..7a25390 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.2.0-SNAPSHOT + 4.2.0 openinvassembly diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 67cb8cc..0d2487e 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.0-SNAPSHOT + 4.2.0 openinvadapter1_18_R2 diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R1/pom.xml index 67fd1cb..728b361 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.0-SNAPSHOT + 4.2.0 openinvadapter1_19_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index 4f0c33d..a03873f 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.0-SNAPSHOT + 4.2.0 openinvplugincore diff --git a/pom.xml b/pom.xml index 037125f..309bef5 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.2.0-SNAPSHOT + 4.2.0 pom @@ -83,13 +83,13 @@ openinvapi com.lishid compile - 4.2.0-SNAPSHOT + 4.2.0
openinvplugincore com.lishid compile - 4.2.0-SNAPSHOT + 4.2.0 com.lishid -- 2.49.1 From 89db744113500c5d26ca60f637131d55422e03d5 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Tue, 7 Jun 2022 19:41:52 -0400 Subject: [PATCH 082/139] Bump version to 4.2.1-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- internal/v1_19_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 5d907ec..fd7a2f8 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.0 + 4.2.1-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 7a25390..eea02a4 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.2.0 + 4.2.1-SNAPSHOT openinvassembly diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 0d2487e..9e7e94e 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.0 + 4.2.1-SNAPSHOT openinvadapter1_18_R2 diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R1/pom.xml index 728b361..63e19bc 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.0 + 4.2.1-SNAPSHOT openinvadapter1_19_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index a03873f..aaf3501 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.0 + 4.2.1-SNAPSHOT openinvplugincore diff --git a/pom.xml b/pom.xml index 309bef5..5f73e61 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.2.0 + 4.2.1-SNAPSHOT pom @@ -83,13 +83,13 @@ openinvapi com.lishid compile - 4.2.0 + 4.2.1-SNAPSHOT openinvplugincore com.lishid compile - 4.2.0 + 4.2.1-SNAPSHOT com.lishid -- 2.49.1 From 1093b6d9111a6540a31c217b2c8cabde8d51e8bf Mon Sep 17 00:00:00 2001 From: Elioby <7284033+Elioby@users.noreply.github.com> Date: Sun, 31 Jul 2022 02:04:40 +0100 Subject: [PATCH 083/139] Update to 1.19.1 (#89) --- internal/v1_19_R1/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R1/pom.xml index 63e19bc..9e4773e 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -32,7 +32,7 @@ 17 17 - 1.19-R0.1-SNAPSHOT + 1.19.1-R0.1-SNAPSHOT -- 2.49.1 From 23e2a7e5342603afeb8c885f0f7c378b348eeeb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 13:32:56 -0400 Subject: [PATCH 084/139] Bump maven-assembly-plugin from 3.3.0 to 3.4.2 (#94) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f73e61..72ebd0e 100644 --- a/pom.xml +++ b/pom.xml @@ -145,7 +145,7 @@ maven-assembly-plugin org.apache.maven.plugins - 3.3.0 + 3.4.2 -- 2.49.1 From 6b38cb72017f45d956bc5f2160c11482e084ea1c Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 1 Aug 2022 13:35:00 -0400 Subject: [PATCH 085/139] Bump version to 4.2.1 for release --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- internal/v1_19_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index fd7a2f8..700c995 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.1-SNAPSHOT + 4.2.1 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index eea02a4..ed10314 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.2.1-SNAPSHOT + 4.2.1 openinvassembly diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 9e7e94e..803b888 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.1-SNAPSHOT + 4.2.1 openinvadapter1_18_R2 diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R1/pom.xml index 9e4773e..76da41d 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.1-SNAPSHOT + 4.2.1 openinvadapter1_19_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index aaf3501..9198f35 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.1-SNAPSHOT + 4.2.1 openinvplugincore diff --git a/pom.xml b/pom.xml index 72ebd0e..4c956ce 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.2.1-SNAPSHOT + 4.2.1 pom @@ -83,13 +83,13 @@ openinvapi com.lishid compile - 4.2.1-SNAPSHOT + 4.2.1 openinvplugincore com.lishid compile - 4.2.1-SNAPSHOT + 4.2.1 com.lishid -- 2.49.1 From 8c7698b40ed7d5af1df418e4ccc0bb1e48f57e3f Mon Sep 17 00:00:00 2001 From: Jikoo Date: Mon, 1 Aug 2022 13:35:25 -0400 Subject: [PATCH 086/139] Bump version to 4.2.2-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- internal/v1_19_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 700c995..540de2a 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.1 + 4.2.2-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index ed10314..fb22eb6 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.2.1 + 4.2.2-SNAPSHOT openinvassembly diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 803b888..f99be39 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.1 + 4.2.2-SNAPSHOT openinvadapter1_18_R2 diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R1/pom.xml index 76da41d..d0ebc5e 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.1 + 4.2.2-SNAPSHOT openinvadapter1_19_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index 9198f35..43948c4 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.1 + 4.2.2-SNAPSHOT openinvplugincore diff --git a/pom.xml b/pom.xml index 4c956ce..6a76cb2 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.2.1 + 4.2.2-SNAPSHOT pom @@ -83,13 +83,13 @@ openinvapi com.lishid compile - 4.2.1 + 4.2.2-SNAPSHOT openinvplugincore com.lishid compile - 4.2.1 + 4.2.2-SNAPSHOT com.lishid -- 2.49.1 From 1e0fb7bdb195ffff80d392e1f4b16f1c07c44a92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 10 Sep 2022 14:52:17 -0400 Subject: [PATCH 087/139] Bump hmarr/auto-approve-action from 2.2.1 to 2.4.0 (#99) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09682ef..2fe5f9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Approve - uses: hmarr/auto-approve-action@v2.2.1 + uses: hmarr/auto-approve-action@v2.4.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Merge -- 2.49.1 From 1ceaf296f255cf8a7af8787c057816af10af6733 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 12:36:48 -0400 Subject: [PATCH 088/139] Bump maven-compiler-plugin from 3.8.1 to 3.10.1 (#76) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6a76cb2..6b3943b 100644 --- a/pom.xml +++ b/pom.xml @@ -139,7 +139,7 @@ maven-compiler-plugin org.apache.maven.plugins - 3.8.1 + 3.10.1 -- 2.49.1 From d0648cc463c27781fd501dcd0179c5c6b0e55075 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 1 Oct 2022 12:43:57 -0400 Subject: [PATCH 089/139] Fix incorrect player's locale used in view title (#101) --- .../java/com/lishid/openinv/internal/OpenInventoryView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java index f1aaadb..7087e3d 100644 --- a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java +++ b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java @@ -67,7 +67,7 @@ public class OpenInventoryView extends InventoryView { String localTitle = OpenInv.getPlugin(OpenInv.class) .getLocalizedMessage( - owner, + player, titleKey, "%player%", owner.getName()); -- 2.49.1 From 2679a520a58fed372d2bc81934bc8523af2aac7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 15:12:52 -0400 Subject: [PATCH 090/139] Bump actions/checkout from 2 to 3 (#103) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 13c0997..c633e68 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 -- 2.49.1 From b872f94855a32c020882aa6969bc95469ed55315 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 15:13:03 -0400 Subject: [PATCH 091/139] Bump maven-shade-plugin from 3.3.0 to 3.4.0 (#102) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6b3943b..3dbb75a 100644 --- a/pom.xml +++ b/pom.xml @@ -133,7 +133,7 @@ org.apache.maven.plugins - 3.3.0 + 3.4.0 -- 2.49.1 From c443615c1d23f88cca93c7db14786b2119b33232 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 14 Oct 2022 13:45:26 -0400 Subject: [PATCH 092/139] Fix cache never being used for Spigot dependencies (#105) --- pom.xml | 10 ++++++++++ scripts/install_spigot_dependencies.sh | 6 ++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 3dbb75a..b6f15d5 100644 --- a/pom.xml +++ b/pom.xml @@ -103,6 +103,16 @@ + + + maven-dependency-plugin + org.apache.maven.plugins + 3.3.0 + + maven-shade-plugin diff --git a/scripts/install_spigot_dependencies.sh b/scripts/install_spigot_dependencies.sh index dd3cbfc..61668d4 100644 --- a/scripts/install_spigot_dependencies.sh +++ b/scripts/install_spigot_dependencies.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (C) 2011-2021 lishid. All rights reserved. +# Copyright (C) 2011-2022 lishid. All rights reserved. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -34,9 +34,7 @@ readarray -t versions <<< "$(. ./scripts/get_spigot_versions.sh)" echo Found Spigot dependencies: "${versions[@]}" # Install dependencies aside from Spigot prior to running in offline mode. -# Note that the default SuperPOM declares maven-dependency-plugin 2.8.0. -# Unfortunately, we run into MDEP-204 and require a version >= 3.1.2. -mvn org.apache.maven.plugins:maven-dependency-plugin:3.2.0:go-offline -DexcludeArtifactIds=spigot +mvn dependency:go-offline -DexcludeArtifactIds=spigot for version in "${versions[@]}"; do set -e -- 2.49.1 From 0120d35a9aa7753d6642b41dc2da0b1bec97e718 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 14 Oct 2022 16:40:33 -0400 Subject: [PATCH 093/139] Fix advancement-related memory leak (#104) Fix memory leak with loaded players' advancements Fix missing transaction transfer for player inventories Fix incorrect transaction transfer for ender chests Minor code health --- .../internal/v1_18_R2/PlayerDataManager.java | 3 ++ .../internal/v1_18_R2/SpecialEnderChest.java | 35 ++++++++++----- .../v1_18_R2/SpecialPlayerInventory.java | 45 +++++++++++++------ .../internal/v1_19_R1/PlayerDataManager.java | 3 ++ .../internal/v1_19_R1/SpecialEnderChest.java | 33 +++++++++----- .../v1_19_R1/SpecialPlayerInventory.java | 43 ++++++++++++------ .../main/java/com/lishid/openinv/OpenInv.java | 5 ++- .../openinv/internal/IPlayerDataManager.java | 2 +- .../openinv/internal/OpenInventoryView.java | 14 +++--- 9 files changed, 125 insertions(+), 58 deletions(-) diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java index 1be5f57..127e39c 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java @@ -99,6 +99,9 @@ public class PlayerDataManager implements IPlayerDataManager { ServerPlayer entity = new ServerPlayer(server, worldServer, profile); + // Stop listening for advancement progression - if this is not cleaned up, loading causes a memory leak. + entity.getAdvancements().stopListening(); + try { injectPlayer(entity); } catch (IllegalAccessException e) { diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java index f46ff61..e0e00a8 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialEnderChest.java @@ -67,18 +67,29 @@ public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpe @Override public void setPlayerOnline(@NotNull final org.bukkit.entity.Player player) { - if (!this.playerOnline) { - try { - this.owner = PlayerDataManager.getHandle(player); - PlayerEnderChestContainer enderChest = owner.getEnderChestInventory(); - for (int i = 0; i < enderChest.getContainerSize(); ++i) { - enderChest.setItem(i, this.items.get(i)); - } - this.items = enderChest.items; - enderChest.transaction.addAll(this.transaction); - } catch (Exception ignored) {} - this.playerOnline = true; + if (this.playerOnline) { + return; } + + ServerPlayer offlinePlayer = this.owner; + ServerPlayer onlinePlayer = PlayerDataManager.getHandle(player); + + // Set owner to new player. + this.owner = onlinePlayer; + + // Set player's ender chest contents to our modified contents. + PlayerEnderChestContainer onlineEnderChest = onlinePlayer.getEnderChestInventory(); + for (int i = 0; i < onlineEnderChest.getContainerSize(); ++i) { + onlineEnderChest.setItem(i, this.items.get(i)); + } + + // Set our item array to the new inventory's array. + this.items = onlineEnderChest.items; + + // Add viewers to new inventory. + onlineEnderChest.transaction.addAll(offlinePlayer.getEnderChestInventory().transaction); + + this.playerOnline = true; } @Override @@ -317,7 +328,7 @@ public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpe @Override public String toString() { - return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).collect(Collectors.toList()).toString(); + return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).toList().toString(); } @Override diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java index 04c2c5f..b007155 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/SpecialPlayerInventory.java @@ -77,20 +77,37 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI @Override public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) { - if (!this.playerOnline) { - Player entityPlayer = PlayerDataManager.getHandle(player); - entityPlayer.getInventory().transaction.addAll(this.transaction); - this.player = entityPlayer; - for (int i = 0; i < getContainerSize(); ++i) { - this.player.getInventory().setItem(i, getRawItem(i)); - } - this.player.getInventory().selected = this.selected; - this.items = this.player.getInventory().items; - this.armor = this.player.getInventory().armor; - this.offhand = this.player.getInventory().offhand; - this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); - this.playerOnline = true; + if (this.playerOnline) { + return; } + + Player offlinePlayer = this.player; + Player onlinePlayer = PlayerDataManager.getHandle(player); + onlinePlayer.getInventory().transaction.addAll(this.transaction); + + // Set owner to new player. + this.player = onlinePlayer; + + // Set player's inventory contents to our modified contents. + Inventory onlineInventory = onlinePlayer.getInventory(); + for (int i = 0; i < getContainerSize(); ++i) { + onlineInventory.setItem(i, getRawItem(i)); + } + onlineInventory.selected = this.selected; + + // Set our item arrays to the new inventory's arrays. + this.items = onlineInventory.items; + this.armor = onlineInventory.armor; + this.offhand = onlineInventory.offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + + // Add existing viewers to new viewer list. + Inventory offlineInventory = offlinePlayer.getInventory(); + // Remove self from listing - player is always a viewer of their own inventory, prevent duplicates. + offlineInventory.transaction.remove(offlinePlayer.getBukkitEntity()); + onlineInventory.transaction.addAll(offlineInventory.transaction); + + this.playerOnline = true; } @Override @@ -138,7 +155,7 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI } } - private static record IndexedCompartment(@Nullable NonNullList compartment, int index) {} + private record IndexedCompartment(@Nullable NonNullList compartment, int index) {} private @NotNull SpecialPlayerInventory.IndexedCompartment getIndexedContent(int index) { if (index < items.size()) { diff --git a/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/PlayerDataManager.java b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/PlayerDataManager.java index da0232a..3534485 100644 --- a/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/PlayerDataManager.java +++ b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/PlayerDataManager.java @@ -100,6 +100,9 @@ public class PlayerDataManager implements IPlayerDataManager { ServerPlayer entity = new ServerPlayer(server, worldServer, profile, null); + // Stop listening for advancement progression - if this is not cleaned up, loading causes a memory leak. + entity.getAdvancements().stopListening(); + try { injectPlayer(entity); } catch (IllegalAccessException e) { diff --git a/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialEnderChest.java b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialEnderChest.java index e2a5546..d46583f 100644 --- a/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialEnderChest.java +++ b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialEnderChest.java @@ -67,18 +67,29 @@ public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpe @Override public void setPlayerOnline(@NotNull final org.bukkit.entity.Player player) { - if (!this.playerOnline) { - try { - this.owner = PlayerDataManager.getHandle(player); - PlayerEnderChestContainer enderChest = owner.getEnderChestInventory(); - for (int i = 0; i < enderChest.getContainerSize(); ++i) { - enderChest.setItem(i, this.items.get(i)); - } - this.items = enderChest.items; - enderChest.transaction.addAll(this.transaction); - } catch (Exception ignored) {} - this.playerOnline = true; + if (this.playerOnline) { + return; } + + ServerPlayer offlinePlayer = this.owner; + ServerPlayer onlinePlayer = PlayerDataManager.getHandle(player); + + // Set owner to new player. + this.owner = onlinePlayer; + + // Set player's ender chest contents to our modified contents. + PlayerEnderChestContainer onlineEnderChest = onlinePlayer.getEnderChestInventory(); + for (int i = 0; i < onlineEnderChest.getContainerSize(); ++i) { + onlineEnderChest.setItem(i, this.items.get(i)); + } + + // Set our item array to the new inventory's array. + this.items = onlineEnderChest.items; + + // Add viewers to new inventory. + onlineEnderChest.transaction.addAll(offlinePlayer.getEnderChestInventory().transaction); + + this.playerOnline = true; } @Override diff --git a/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialPlayerInventory.java b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialPlayerInventory.java index d819e35..cc5ecbd 100644 --- a/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialPlayerInventory.java +++ b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/SpecialPlayerInventory.java @@ -77,20 +77,37 @@ public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerI @Override public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) { - if (!this.playerOnline) { - Player entityPlayer = PlayerDataManager.getHandle(player); - entityPlayer.getInventory().transaction.addAll(this.transaction); - this.player = entityPlayer; - for (int i = 0; i < getContainerSize(); ++i) { - this.player.getInventory().setItem(i, getRawItem(i)); - } - this.player.getInventory().selected = this.selected; - this.items = this.player.getInventory().items; - this.armor = this.player.getInventory().armor; - this.offhand = this.player.getInventory().offhand; - this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); - this.playerOnline = true; + if (this.playerOnline) { + return; } + + Player offlinePlayer = this.player; + Player onlinePlayer = PlayerDataManager.getHandle(player); + onlinePlayer.getInventory().transaction.addAll(this.transaction); + + // Set owner to new player. + this.player = onlinePlayer; + + // Set player's inventory contents to our modified contents. + Inventory onlineInventory = onlinePlayer.getInventory(); + for (int i = 0; i < getContainerSize(); ++i) { + onlineInventory.setItem(i, getRawItem(i)); + } + onlineInventory.selected = this.selected; + + // Set our item arrays to the new inventory's arrays. + this.items = onlineInventory.items; + this.armor = onlineInventory.armor; + this.offhand = onlineInventory.offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + + // Add existing viewers to new viewer list. + Inventory offlineInventory = offlinePlayer.getInventory(); + // Remove self from listing - player is always a viewer of their own inventory, prevent duplicates. + offlineInventory.transaction.remove(offlinePlayer.getBukkitEntity()); + onlineInventory.transaction.addAll(offlineInventory.transaction); + + this.playerOnline = true; } @Override diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index 06cc68f..98b634e 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -476,8 +476,9 @@ public class OpenInv extends JavaPlugin implements IOpenInv { if (!disableSaving() && current != null - && current.getPlayer() instanceof Player player && !player.isOnline()) { - this.accessor.getPlayerDataManager().inject(player).saveData(); + && current.getPlayer() instanceof Player player + && !player.isOnline()) { + this.accessor.getPlayerDataManager().inject(player).saveData(); } }); } diff --git a/plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java b/plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java index 3778054..ca66932 100644 --- a/plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java +++ b/plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java index 7087e3d..a7f4a95 100644 --- a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java +++ b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java @@ -27,13 +27,17 @@ import org.jetbrains.annotations.NotNull; public class OpenInventoryView extends InventoryView { - private final Player player; - private final ISpecialInventory inventory; - private final String titleKey; - private final String titleDefaultSuffix; + private final @NotNull Player player; + private final @NotNull ISpecialInventory inventory; + private final @NotNull String titleKey; + private final @NotNull String titleDefaultSuffix; private String title; - public OpenInventoryView(Player player, ISpecialInventory inventory, String titleKey, String titleDefaultSuffix) { + public OpenInventoryView( + @NotNull Player player, + @NotNull ISpecialInventory inventory, + @NotNull String titleKey, + @NotNull String titleDefaultSuffix) { this.player = player; this.inventory = inventory; this.titleKey = titleKey; -- 2.49.1 From 961a9006329a24b90beb339a6953f2a934e02a77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Dec 2022 09:45:43 -0500 Subject: [PATCH 094/139] Bump maven-dependency-plugin from 3.3.0 to 3.4.0 (#108) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b6f15d5..43077ec 100644 --- a/pom.xml +++ b/pom.xml @@ -110,7 +110,7 @@ --> maven-dependency-plugin org.apache.maven.plugins - 3.3.0 + 3.4.0 -- 2.49.1 From 1efc0d49047ca00a1c9c6a1183d44b120786d1f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Dec 2022 09:45:59 -0500 Subject: [PATCH 095/139] Bump maven-shade-plugin from 3.4.0 to 3.4.1 (#112) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 43077ec..e4d0494 100644 --- a/pom.xml +++ b/pom.xml @@ -143,7 +143,7 @@ org.apache.maven.plugins - 3.4.0 + 3.4.1 -- 2.49.1 From e5128fa8db461dca98b78c77a61207fb08375df7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Dec 2022 09:46:12 -0500 Subject: [PATCH 096/139] Bump pascalgn/automerge-action from 0.15.3 to 0.15.5 (#109) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2fe5f9f..f2046b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Merge - uses: pascalgn/automerge-action@v0.15.3 + uses: pascalgn/automerge-action@v0.15.5 env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" MERGE_LABELS: "dependencies" -- 2.49.1 From d7e78177e076fad396abd87e7d3ed0104f285ab7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Dec 2022 09:46:26 -0500 Subject: [PATCH 097/139] Bump softprops/action-gh-release from 0.1.14 to 0.1.15 (#110) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2046b8..6ed1dae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,7 +78,7 @@ jobs: - name: Create Release id: create-release - uses: softprops/action-gh-release@v0.1.14 + uses: softprops/action-gh-release@v0.1.15 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: -- 2.49.1 From 801530490da957aa3b6c4925759a4d4e4695a0e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Dec 2022 09:46:55 -0500 Subject: [PATCH 098/139] Bump dsaltares/fetch-gh-release-asset from 1.0.0 to 1.1.0 (#111) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c633e68..e74709e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: fetch-depth: 0 - name: Fetch Github Release Asset - uses: dsaltares/fetch-gh-release-asset@1.0.0 + uses: dsaltares/fetch-gh-release-asset@1.1.0 with: token: ${{ secrets.GITHUB_TOKEN }} version: ${{ github.event.release.id }} -- 2.49.1 From 7b16391a80ecf3aff61243b12e8696bfa9d3db1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Dec 2022 09:47:23 -0500 Subject: [PATCH 099/139] Bump hmarr/auto-approve-action from 2.4.0 to 3.1.0 (#113) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ed1dae..3005d7a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Approve - uses: hmarr/auto-approve-action@v2.4.0 + uses: hmarr/auto-approve-action@v3.1.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Merge -- 2.49.1 From 46f3396b47b7b4626771ffd01617ffdce42e0ee9 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 10 Dec 2022 15:57:33 -0500 Subject: [PATCH 100/139] Update to Minecraft 1.19.3 1.19.2 is still supported - 1.19.1 was only dropped because there was no Spigot NMS revision bump. --- internal/v1_19_R2/pom.xml | 85 ++ .../internal/v1_19_R2/AnySilentContainer.java | 277 ++++++ .../openinv/internal/v1_19_R2/OpenPlayer.java | 74 ++ .../internal/v1_19_R2/PlayerDataManager.java | 234 ++++++ .../internal/v1_19_R2/SpecialEnderChest.java | 339 ++++++++ .../v1_19_R2/SpecialPlayerInventory.java | 788 ++++++++++++++++++ pom.xml | 1 + 7 files changed, 1798 insertions(+) create mode 100644 internal/v1_19_R2/pom.xml create mode 100644 internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java create mode 100644 internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/OpenPlayer.java create mode 100644 internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/PlayerDataManager.java create mode 100644 internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialEnderChest.java create mode 100644 internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialPlayerInventory.java diff --git a/internal/v1_19_R2/pom.xml b/internal/v1_19_R2/pom.xml new file mode 100644 index 0000000..3e96c74 --- /dev/null +++ b/internal/v1_19_R2/pom.xml @@ -0,0 +1,85 @@ + + + + + 4.0.0 + + + openinvparent + com.lishid + ../../pom.xml + 4.2.2-SNAPSHOT + + + openinvadapter1_19_R2 + OpenInvAdapter1_19_R2 + + + 17 + 17 + 1.19.3-R0.1-SNAPSHOT + + + + + org.spigotmc + spigot-api + ${spigot.version} + + + spigot + org.spigotmc + provided + ${spigot.version} + remapped-mojang + + + openinvapi + com.lishid + provided + + + openinvplugincore + com.lishid + + + annotations + org.jetbrains + + + + + + + maven-shade-plugin + + + false + + + + maven-compiler-plugin + + + net.md-5 + specialsource-maven-plugin + + + + + diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java new file mode 100644 index 0000000..3abd77a --- /dev/null +++ b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_19_R2; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IAnySilentContainer; +import com.lishid.openinv.util.ReflectionHelper; +import java.lang.reflect.Field; +import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.CompoundContainer; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.monster.Shulker; +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.block.BarrelBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.DoubleBlockCombiner; +import net.minecraft.world.level.block.ShulkerBoxBlock; +import net.minecraft.world.level.block.TrappedChestBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.block.ShulkerBox; +import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AnySilentContainer implements IAnySilentContainer { + + private @Nullable Field serverPlayerGameModeGameType; + + public AnySilentContainer() { + try { + this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("b"); + this.serverPlayerGameModeGameType.setAccessible(true); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("ServerPlayerGameMode#gameModeForPlayer's obfuscated name has changed!"); + logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues"); + logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail."); + // N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break. + this.serverPlayerGameModeGameType = ReflectionHelper.grabFieldByType(ServerPlayerGameMode.class, GameType.class); + } catch (SecurityException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to directly write player game mode! SilentContainer will fail."); + logger.log(Level.WARNING, "Error obtaining GameType field", e); + } + } + + @Override + public boolean isShulkerBlocked(@NotNull ShulkerBox shulkerBox) { + org.bukkit.World bukkitWorld = shulkerBox.getWorld(); + if (!(bukkitWorld instanceof CraftWorld)) { + bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); + } + + if (!(bukkitWorld instanceof CraftWorld craftWorld)) { + Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); + OpenInv.getPlugin(OpenInv.class).getLogger().log(Level.WARNING, exception.getMessage(), exception); + return false; + } + + final ServerLevel world = craftWorld.getHandle(); + final BlockPos blockPosition = new BlockPos(shulkerBox.getX(), shulkerBox.getY(), shulkerBox.getZ()); + final BlockEntity tile = world.getBlockEntity(blockPosition); + + if (!(tile instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) + || shulkerBoxBlockEntity.getAnimationStatus() != ShulkerBoxBlockEntity.AnimationStatus.CLOSED) { + return false; + } + + BlockState blockState = world.getBlockState(blockPosition); + + // See net.minecraft.world.level.block.ShulkerBoxBlock#canOpen + AABB boundingBox = Shulker.getProgressDeltaAabb(blockState.getValue(ShulkerBoxBlock.FACING), 0.0F, 0.5F) + .move(blockPosition) + .deflate(1.0E-6D); + return !world.noCollision(boundingBox); + } + + @Override + public boolean activateContainer( + @NotNull final Player bukkitPlayer, + final boolean silentchest, + @NotNull final org.bukkit.block.Block bukkitBlock) { + + // Silent ender chest is API-only + if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) { + bukkitPlayer.openInventory(bukkitPlayer.getEnderChest()); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + final ServerLevel level = player.getLevel(); + final BlockPos blockPos = new BlockPos(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + final BlockEntity blockEntity = level.getBlockEntity(blockPos); + + if (blockEntity == null) { + return false; + } + + if (blockEntity instanceof EnderChestBlockEntity enderChestTile) { + // Anychest ender chest. See net.minecraft.world.level.block.EnderChestBlock + PlayerEnderChestContainer enderChest = player.getEnderChestInventory(); + enderChest.setActiveChest(enderChestTile); + player.openMenu(new SimpleMenuProvider((containerCounter, playerInventory, ignored) -> { + MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); + int rows = enderChest.getContainerSize() / 9; + return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); + }, Component.translatable(("container.enderchest")))); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + if (!(blockEntity instanceof MenuProvider menuProvider)) { + return false; + } + + BlockState blockState = level.getBlockState(blockPos); + Block block = blockState.getBlock(); + + if (block instanceof ChestBlock chestBlock) { + + // boolean flag: do not check if chest is blocked + Optional menuOptional = chestBlock.combine(blockState, level, blockPos, true).apply( + // Combiner is a copy of private ChestBlock.MENU_PROVIDER_COMBINER + new DoubleBlockCombiner.Combiner>() { + @Override + public Optional acceptDouble(ChestBlockEntity localChest1, ChestBlockEntity localChest2) { + CompoundContainer doubleChest = new CompoundContainer(localChest1, localChest2); + return Optional.of(new ChestBlock.DoubleInventory(localChest1, localChest2, doubleChest)); + } + + @Override + public Optional acceptSingle(ChestBlockEntity localChest) { + return Optional.of(localChest); + } + + @Override + public Optional acceptNone() { + return Optional.empty(); + } + }); + + if (menuOptional.isEmpty()) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + + menuProvider = menuOptional.get(); + + if (block instanceof TrappedChestBlock) { + bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); + } else { + bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED); + } + } + + if (block instanceof ShulkerBoxBlock) { + bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED); + } + + if (block instanceof BarrelBlock) { + bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL); + } + + // AnyChest only - SilentChest not active, container unsupported, or unnecessary. + if (!silentchest || player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) { + player.openMenu(menuProvider); + return true; + } + + // SilentChest requires access to setting players' game mode directly. + if (this.serverPlayerGameModeGameType == null) { + return false; + } + + if (blockEntity instanceof RandomizableContainerBlockEntity lootable) { + if (lootable.lootTable != null) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + } + + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); + player.openMenu(menuProvider); + this.forceGameType(player, gameType); + return true; + } + + @Override + public void deactivateContainer(@NotNull final Player bukkitPlayer) { + if (this.serverPlayerGameModeGameType == null) { + return; + } + + InventoryView view = bukkitPlayer.getOpenInventory(); + switch (view.getType()) { + case CHEST: + case ENDER_CHEST: + case SHULKER_BOX: + case BARREL: + break; + default: + return; + } + + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + // Force game mode change without informing plugins or players. + // Regular game mode set calls GameModeChangeEvent and is cancellable. + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); + + // ServerPlayer#closeContainer cannot be called without entering an + // infinite loop because this method is called during inventory close. + // From ServerPlayer#closeContainer -> CraftEventFactory#handleInventoryCloseEvent + player.containerMenu.transferTo(player.inventoryMenu, player.getBukkitEntity()); + // From ServerPlayer#closeContainer + player.doCloseContainer(); + // Regular inventory close will handle the rest - packet sending, etc. + + // Revert forced game mode. + this.forceGameType(player, gameType); + } + + private void forceGameType(final ServerPlayer player, final GameType gameMode) { + if (this.serverPlayerGameModeGameType == null) { + // No need to warn repeatedly, error on startup and lack of function should be enough. + return; + } + try { + this.serverPlayerGameModeGameType.setAccessible(true); + this.serverPlayerGameModeGameType.set(player.gameMode, gameMode); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + +} diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/OpenPlayer.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/OpenPlayer.java new file mode 100644 index 0000000..4dab334 --- /dev/null +++ b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/OpenPlayer.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_19_R2; + +import java.io.File; +import net.minecraft.Util; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.storage.PlayerDataStorage; +import org.apache.logging.log4j.LogManager; +import org.bukkit.craftbukkit.v1_19_R2.CraftServer; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; + +public class OpenPlayer extends CraftPlayer { + + public OpenPlayer(CraftServer server, ServerPlayer entity) { + super(server, entity); + } + + @Override + public void loadData() { + // See CraftPlayer#loadData + CompoundTag loaded = this.server.getHandle().playerIo.load(this.getHandle()); + if (loaded != null) { + readExtraData(loaded); + } + } + + @Override + public void saveData() { + ServerPlayer player = this.getHandle(); + // See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman) + try { + PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; + + CompoundTag playerData = player.saveWithoutId(new CompoundTag()); + setExtraData(playerData); + + if (!isOnline()) { + // Special case: save old vehicle data + CompoundTag oldData = worldNBTStorage.load(player); + + if (oldData != null && oldData.contains("RootVehicle", 10)) { + // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound) + playerData.put("RootVehicle", oldData.getCompound("RootVehicle")); + } + } + + File file = File.createTempFile(player.getStringUUID() + "-", ".dat", worldNBTStorage.getPlayerDir()); + NbtIo.writeCompressed(playerData, file); + File file1 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat"); + File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); + Util.safeReplaceFile(file1, file, file2); + } catch (Exception e) { + LogManager.getLogger().warn("Failed to save player data for {}: {}", player.getName().getString(), e.getMessage()); + } + } + +} diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/PlayerDataManager.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/PlayerDataManager.java new file mode 100644 index 0000000..4cc6939 --- /dev/null +++ b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/PlayerDataManager.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_19_R2; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IPlayerDataManager; +import com.lishid.openinv.internal.ISpecialInventory; +import com.lishid.openinv.internal.OpenInventoryView; +import com.mojang.authlib.GameProfile; +import java.lang.reflect.Field; +import java.util.logging.Logger; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.craftbukkit.v1_19_R2.CraftServer; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory; +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftContainer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PlayerDataManager implements IPlayerDataManager { + + private @Nullable Field bukkitEntity; + + public PlayerDataManager() { + try { + bukkitEntity = Entity.class.getDeclaredField("bukkitEntity"); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded."); + logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); + bukkitEntity = null; + } + } + + public static @NotNull ServerPlayer getHandle(final Player player) { + if (player instanceof CraftPlayer) { + return ((CraftPlayer) player).getHandle(); + } + + Server server = player.getServer(); + ServerPlayer nmsPlayer = null; + + if (server instanceof CraftServer) { + nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getUniqueId()); + } + + if (nmsPlayer == null) { + // Could use reflection to examine fields, but it's honestly not worth the bother. + throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation"); + } + + return nmsPlayer; + } + + @Override + public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { + // Ensure player has data + if (!offline.hasPlayedBefore()) { + return null; + } + + // Create a profile and entity to load the player data + // See net.minecraft.server.players.PlayerList#canPlayerLogin + // and net.minecraft.server.network.ServerLoginPacketListenerImpl#handleHello + GameProfile profile = new GameProfile(offline.getUniqueId(), + offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel worldServer = server.getLevel(Level.OVERWORLD); + + if (worldServer == null) { + return null; + } + + ServerPlayer entity = new ServerPlayer(server, worldServer, profile); + + try { + injectPlayer(entity); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + // Get the bukkit entity + Player target = entity.getBukkitEntity(); + if (target != null) { + // Load data + target.loadData(); + } + // Return the entity + return target; + } + + void injectPlayer(ServerPlayer player) throws IllegalAccessException { + if (bukkitEntity == null) { + return; + } + + bukkitEntity.setAccessible(true); + + bukkitEntity.set(player, new OpenPlayer(player.server.server, player)); + } + + @NotNull + @Override + public Player inject(@NotNull Player player) { + try { + ServerPlayer nmsPlayer = getHandle(player); + if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) { + return openPlayer; + } + injectPlayer(nmsPlayer); + return nmsPlayer.getBukkitEntity(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return player; + } + } + + @Nullable + @Override + public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) { + + ServerPlayer nmsPlayer = getHandle(player); + + if (nmsPlayer.connection == null) { + return null; + } + + InventoryView view = getView(player, inventory); + + if (view == null) { + return player.openInventory(inventory.getBukkitInventory()); + } + + AbstractContainerMenu container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { + @Override + public MenuType getType() { + return getContainers(inventory.getBukkitInventory().getSize()); + } + }; + + container.setTitle(Component.literal(view.getTitle())); + container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); + + if (container == null) { + return null; + } + + nmsPlayer.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), + Component.literal(container.getBukkitView().getTitle()))); + nmsPlayer.containerMenu = container; + nmsPlayer.initMenu(container); + + return container.getBukkitView(); + + } + + private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) { + if (inventory instanceof SpecialEnderChest) { + return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest"); + } else if (inventory instanceof SpecialPlayerInventory) { + return new OpenInventoryView(player, inventory, "container.player", "'s Inventory"); + } else { + return null; + } + } + + static @NotNull MenuType getContainers(int inventorySize) { + + return switch (inventorySize) { + case 9 -> MenuType.GENERIC_9x1; + case 18 -> MenuType.GENERIC_9x2; + case 36 -> MenuType.GENERIC_9x4; // PLAYER + case 41, 45 -> MenuType.GENERIC_9x5; + case 54 -> MenuType.GENERIC_9x6; + default -> MenuType.GENERIC_9x3; // Default 27-slot inventory + }; + } + + @Override + public int convertToPlayerSlot(InventoryView view, int rawSlot) { + int topSize = view.getTopInventory().getSize(); + if (topSize <= rawSlot) { + // Slot is not inside special inventory, use Bukkit logic. + return view.convertSlot(rawSlot); + } + + // Main inventory, slots 0-26 -> 9-35 + if (rawSlot < 27) { + return rawSlot + 9; + } + // Hotbar, slots 27-35 -> 0-8 + if (rawSlot < 36) { + return rawSlot - 27; + } + // Armor, slots 36-39 -> 39-36 + if (rawSlot < 40) { + return 36 + (39 - rawSlot); + } + // Off hand + if (rawSlot == 40) { + return 40; + } + // Drop slots, "out of inventory" + return -1; + } + +} diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialEnderChest.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialEnderChest.java new file mode 100644 index 0000000..bb5680c --- /dev/null +++ b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialEnderChest.java @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_19_R2; + +import com.lishid.openinv.internal.ISpecialEnderChest; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.ContainerListener; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpecialEnderChest { + + private final CraftInventory inventory; + private ServerPlayer owner; + private NonNullList items; + private boolean playerOnline; + + public SpecialEnderChest(final org.bukkit.entity.Player player, final Boolean online) { + super(PlayerDataManager.getHandle(player)); + this.inventory = new CraftInventory(this); + this.owner = PlayerDataManager.getHandle(player); + this.playerOnline = online; + this.items = this.owner.getEnderChestInventory().items; + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return inventory; + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public void setPlayerOnline(@NotNull final org.bukkit.entity.Player player) { + if (!this.playerOnline) { + try { + this.owner = PlayerDataManager.getHandle(player); + PlayerEnderChestContainer enderChest = owner.getEnderChestInventory(); + for (int i = 0; i < enderChest.getContainerSize(); ++i) { + enderChest.setItem(i, this.items.get(i)); + } + this.items = enderChest.items; + enderChest.transaction.addAll(this.transaction); + } catch (Exception ignored) {} + this.playerOnline = true; + } + } + + @Override + public @NotNull org.bukkit.entity.Player getPlayer() { + return owner.getBukkitEntity(); + } + + @Override + public void setChanged() { + this.owner.getEnderChestInventory().setChanged(); + } + + @Override + public List getContents() { + return this.items; + } + + @Override + public void onOpen(CraftHumanEntity who) { + this.owner.getEnderChestInventory().onOpen(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + this.owner.getEnderChestInventory().onClose(who); + } + + @Override + public List getViewers() { + return this.owner.getEnderChestInventory().getViewers(); + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public void setActiveChest(EnderChestBlockEntity enderChest) { + this.owner.getEnderChestInventory().setActiveChest(enderChest); + } + + @Override + public boolean isActiveChest(EnderChestBlockEntity enderChest) { + return this.owner.getEnderChestInventory().isActiveChest(enderChest); + } + + @Override + public int getMaxStackSize() { + return this.owner.getEnderChestInventory().getMaxStackSize(); + } + + @Override + public void setMaxStackSize(int i) { + this.owner.getEnderChestInventory().setMaxStackSize(i); + } + + @Override + public InventoryHolder getOwner() { + return this.owner.getEnderChestInventory().getOwner(); + } + + @Override + public @Nullable Location getLocation() { + return null; + } + + @Override + public void addListener(ContainerListener listener) { + this.owner.getEnderChestInventory().addListener(listener); + } + + @Override + public void removeListener(ContainerListener listener) { + this.owner.getEnderChestInventory().removeListener(listener); + } + + @Override + public ItemStack getItem(int i) { + return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.EMPTY; + } + + @Override + public ItemStack removeItem(int i, int j) { + ItemStack itemstack = ContainerHelper.removeItem(this.items, i, j); + if (!itemstack.isEmpty()) { + this.setChanged(); + } + + return itemstack; + } + + @Override + public ItemStack addItem(ItemStack itemstack) { + ItemStack localItem = itemstack.copy(); + this.moveItemToOccupiedSlotsWithSameType(localItem); + if (localItem.isEmpty()) { + return ItemStack.EMPTY; + } else { + this.moveItemToEmptySlots(localItem); + return localItem.isEmpty() ? ItemStack.EMPTY : localItem; + } + } + + @Override + public boolean canAddItem(ItemStack itemstack) { + for (ItemStack itemstack1 : this.items) { + if (itemstack1.isEmpty() || ItemStack.isSameItemSameTags(itemstack1, itemstack) && itemstack1.getCount() < itemstack1.getMaxStackSize()) { + return true; + } + } + + return false; + } + + private void moveItemToEmptySlots(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (localItem.isEmpty()) { + this.setItem(i, itemstack.copy()); + itemstack.setCount(0); + return; + } + } + } + + private void moveItemToOccupiedSlotsWithSameType(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (ItemStack.isSameItemSameTags(localItem, itemstack)) { + this.moveItemsBetweenStacks(itemstack, localItem); + if (itemstack.isEmpty()) { + return; + } + } + } + } + + private void moveItemsBetweenStacks(ItemStack itemstack, ItemStack itemstack1) { + int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize()); + int j = Math.min(itemstack.getCount(), i - itemstack1.getCount()); + if (j > 0) { + itemstack1.grow(j); + itemstack.shrink(j); + this.setChanged(); + } + } + + @Override + public ItemStack removeItemNoUpdate(int i) { + ItemStack itemstack = this.items.get(i); + if (itemstack.isEmpty()) { + return ItemStack.EMPTY; + } else { + this.items.set(i, ItemStack.EMPTY); + return itemstack; + } + } + + @Override + public void setItem(int i, ItemStack itemstack) { + this.items.set(i, itemstack); + if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { + itemstack.setCount(this.getMaxStackSize()); + } + + this.setChanged(); + } + + @Override + public int getContainerSize() { + return this.owner.getEnderChestInventory().getContainerSize(); + } + + @Override + public boolean isEmpty() { + return this.items.stream().allMatch(ItemStack::isEmpty); + } + + @Override + public void startOpen(Player player) { + } + + @Override + public void stopOpen(Player player) { + } + + @Override + public boolean canPlaceItem(int i, ItemStack itemstack) { + return true; + } + + @Override + public void clearContent() { + this.items.clear(); + this.setChanged(); + } + + @Override + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountStack(itemstack); + } + + } + + @Override + public List removeAllItems() { + List list = this.items.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList()); + this.clearContent(); + return list; + } + + @Override + public ItemStack removeItemType(Item item, int i) { + ItemStack itemstack = new ItemStack(item, 0); + + for(int j = this.getContainerSize() - 1; j >= 0; --j) { + ItemStack localItem = this.getItem(j); + if (localItem.getItem().equals(item)) { + int k = i - itemstack.getCount(); + ItemStack splitItem = localItem.split(k); + itemstack.grow(splitItem.getCount()); + if (itemstack.getCount() == i) { + break; + } + } + } + + if (!itemstack.isEmpty()) { + this.setChanged(); + } + + return itemstack; + } + + @Override + public String toString() { + return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).toList().toString(); + } + + @Override + public void fromTag(ListTag listTag) { + for (int i = 0; i < this.getContainerSize(); ++i) { + this.setItem(i, ItemStack.EMPTY); + } + + for (int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + if (j < this.getContainerSize()) { + this.setItem(j, ItemStack.of(compoundTag)); + } + } + + } + +} diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialPlayerInventory.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialPlayerInventory.java new file mode 100644 index 0000000..ef0cca6 --- /dev/null +++ b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialPlayerInventory.java @@ -0,0 +1,788 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_19_R2; + +import com.google.common.collect.ImmutableList; +import com.lishid.openinv.internal.ISpecialPlayerInventory; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.tags.TagKey; +import net.minecraft.world.Container; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerInventory { + + private final CraftInventory inventory; + private boolean playerOnline; + private Player player; + private NonNullList items; + private NonNullList armor; + private NonNullList offhand; + private List> compartments; + + public SpecialPlayerInventory(@NotNull org.bukkit.entity.Player bukkitPlayer, @NotNull Boolean online) { + super(PlayerDataManager.getHandle(bukkitPlayer)); + this.inventory = new CraftInventory(this); + this.playerOnline = online; + this.player = super.player; + this.selected = player.getInventory().selected; + this.items = this.player.getInventory().items; + this.armor = this.player.getInventory().armor; + this.offhand = this.player.getInventory().offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + } + + @Override + public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) { + if (!this.playerOnline) { + Player entityPlayer = PlayerDataManager.getHandle(player); + entityPlayer.getInventory().transaction.addAll(this.transaction); + this.player = entityPlayer; + for (int i = 0; i < getContainerSize(); ++i) { + this.player.getInventory().setItem(i, getRawItem(i)); + } + this.player.getInventory().selected = this.selected; + this.items = this.player.getInventory().items; + this.armor = this.player.getInventory().armor; + this.offhand = this.player.getInventory().offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + this.playerOnline = true; + } + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return this.inventory; + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public @NotNull HumanEntity getPlayer() { + return this.player.getBukkitEntity(); + } + + private @NotNull ItemStack getRawItem(int i) { + if (i < 0) { + return ItemStack.EMPTY; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + return list.get(i); + } + } + + return ItemStack.EMPTY; + } + + private void setRawItem(int i, @NotNull ItemStack itemStack) { + if (i < 0) { + return; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + list.set(i, itemStack); + } + } + } + + private record IndexedCompartment(@Nullable NonNullList compartment, int index) {} + + private @NotNull SpecialPlayerInventory.IndexedCompartment getIndexedContent(int index) { + if (index < items.size()) { + return new IndexedCompartment(items, getReversedItemSlotNum(index)); + } + + index -= items.size(); + + if (index < armor.size()) { + return new IndexedCompartment(armor, getReversedArmorSlotNum(index)); + } + + index -= armor.size(); + + if (index < offhand.size()) { + return new IndexedCompartment(offhand, index); + } + + index -= offhand.size(); + + return new IndexedCompartment(null, index); + } + + private int getReversedArmorSlotNum(final int i) { + if (i == 0) { + return 3; + } + if (i == 1) { + return 2; + } + if (i == 2) { + return 1; + } + if (i == 3) { + return 0; + } + return i; + } + + private int getReversedItemSlotNum(final int i) { + if (i >= 27) { + return i - 27; + } + return i + 9; + } + + private boolean contains(Predicate predicate) { + return this.compartments.stream().flatMap(NonNullList::stream).anyMatch(predicate); + } + + @Override + public List getArmorContents() { + return this.armor; + } + + @Override + public void onOpen(CraftHumanEntity who) { + this.player.getInventory().onOpen(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + this.player.getInventory().onClose(who); + } + + @Override + public List getViewers() { + return this.player.getInventory().getViewers(); + } + + @Override + public InventoryHolder getOwner() { + return this.player.getBukkitEntity(); + } + + @Override + public int getMaxStackSize() { + return this.player.getInventory().getMaxStackSize(); + } + + @Override + public void setMaxStackSize(int size) { + this.player.getInventory().setMaxStackSize(size); + } + + @Override + public Location getLocation() { + return this.player.getBukkitEntity().getLocation(); + } + + @Override + public boolean hasCustomName() { + return false; + } + + @Override + public List getContents() { + return this.compartments.stream().flatMap(Collection::stream).collect(Collectors.toList()); + } + + @Override + public ItemStack getSelected() { + return isHotbarSlot(this.selected) ? this.items.get(this.selected) : ItemStack.EMPTY; + } + + private boolean hasRemainingSpaceForItem(ItemStack itemstack, ItemStack itemstack1) { + return !itemstack.isEmpty() && ItemStack.isSameItemSameTags(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); + } + + @Override + public int canHold(ItemStack itemstack) { + int remains = itemstack.getCount(); + + for (int i = 0; i < this.items.size(); ++i) { + ItemStack itemstack1 = this.getRawItem(i); + if (itemstack1.isEmpty()) { + return itemstack.getCount(); + } + + if (this.hasRemainingSpaceForItem(itemstack1, itemstack)) { + remains -= (itemstack1.getMaxStackSize() < this.getMaxStackSize() ? itemstack1.getMaxStackSize() : this.getMaxStackSize()) - itemstack1.getCount(); + } + + if (remains <= 0) { + return itemstack.getCount(); + } + } + + ItemStack offhandItemStack = this.getRawItem(this.items.size() + this.armor.size()); + if (this.hasRemainingSpaceForItem(offhandItemStack, itemstack)) { + remains -= (offhandItemStack.getMaxStackSize() < this.getMaxStackSize() ? offhandItemStack.getMaxStackSize() : this.getMaxStackSize()) - offhandItemStack.getCount(); + } + + return remains <= 0 ? itemstack.getCount() : itemstack.getCount() - remains; + } + + @Override + public int getFreeSlot() { + for(int i = 0; i < this.items.size(); ++i) { + if (this.items.get(i).isEmpty()) { + return i; + } + } + + return -1; + } + + @Override + public void setPickedItem(ItemStack itemstack) { + int i = this.findSlotMatchingItem(itemstack); + if (isHotbarSlot(i)) { + this.selected = i; + } else if (i == -1) { + this.selected = this.getSuitableHotbarSlot(); + if (!this.items.get(this.selected).isEmpty()) { + int j = this.getFreeSlot(); + if (j != -1) { + this.items.set(j, this.items.get(this.selected)); + } + } + + this.items.set(this.selected, itemstack); + } else { + this.pickSlot(i); + } + + } + + @Override + public void pickSlot(int i) { + this.selected = this.getSuitableHotbarSlot(); + ItemStack itemstack = this.items.get(this.selected); + this.items.set(this.selected, this.items.get(i)); + this.items.set(i, itemstack); + } + + @Override + public int findSlotMatchingItem(ItemStack itemstack) { + for(int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemstack, this.items.get(i))) { + return i; + } + } + + return -1; + } + + @Override + public int findSlotMatchingUnusedItem(ItemStack itemStack) { + for(int i = 0; i < this.items.size(); ++i) { + ItemStack localItem = this.items.get(i); + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemStack, this.items.get(i)) && !this.items.get(i).isDamaged() && !localItem.isEnchanted() && !localItem.hasCustomHoverName()) { + return i; + } + } + + return -1; + } + + @Override + public int getSuitableHotbarSlot() { + int i; + int j; + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (this.items.get(i).isEmpty()) { + return i; + } + } + + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (!this.items.get(i).isEnchanted()) { + return i; + } + } + + return this.selected; + } + + @Override + public void swapPaint(double d0) { + if (d0 > 0.0D) { + d0 = 1.0D; + } + + if (d0 < 0.0D) { + d0 = -1.0D; + } + + this.selected = (int) (this.selected - d0); + + while (this.selected < 0) { + this.selected += 9; + } + + while(this.selected >= 9) { + this.selected -= 9; + } + } + + @Override + public int clearOrCountMatchingItems(Predicate predicate, int i, Container container) { + byte b0 = 0; + boolean flag = i == 0; + int j = b0 + ContainerHelper.clearOrCountMatchingItems(this, predicate, i - b0, flag); + j += ContainerHelper.clearOrCountMatchingItems(container, predicate, i - j, flag); + ItemStack itemstack = this.player.containerMenu.getCarried(); + j += ContainerHelper.clearOrCountMatchingItems(itemstack, predicate, i - j, flag); + if (itemstack.isEmpty()) { + this.player.containerMenu.setCarried(ItemStack.EMPTY); + } + + return j; + } + + private int addResource(ItemStack itemstack) { + int i = this.getSlotWithRemainingSpace(itemstack); + if (i == -1) { + i = this.getFreeSlot(); + } + + return i == -1 ? itemstack.getCount() : this.addResource(i, itemstack); + } + + private int addResource(int i, ItemStack itemstack) { + Item item = itemstack.getItem(); + int j = itemstack.getCount(); + ItemStack localItemStack = this.getRawItem(i); + if (localItemStack.isEmpty()) { + localItemStack = new ItemStack(item, 0); + if (itemstack.hasTag()) { + // hasTag ensures tag not null + //noinspection ConstantConditions + localItemStack.setTag(itemstack.getTag().copy()); + } + + this.setRawItem(i, localItemStack); + } + + int k = Math.min(j, localItemStack.getMaxStackSize() - localItemStack.getCount()); + + if (k > this.getMaxStackSize() - localItemStack.getCount()) { + k = this.getMaxStackSize() - localItemStack.getCount(); + } + + if (k != 0) { + j -= k; + localItemStack.grow(k); + localItemStack.setPopTime(5); + } + + return j; + } + + @Override + public int getSlotWithRemainingSpace(ItemStack itemstack) { + if (this.hasRemainingSpaceForItem(this.getRawItem(this.selected), itemstack)) { + return this.selected; + } else if (this.hasRemainingSpaceForItem(this.getRawItem(40), itemstack)) { + return 40; + } else { + for(int i = 0; i < this.items.size(); ++i) { + if (this.hasRemainingSpaceForItem(this.items.get(i), itemstack)) { + return i; + } + } + + return -1; + } + } + + @Override + public void tick() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (!compartment.get(i).isEmpty()) { + compartment.get(i).inventoryTick(this.player.level, this.player, i, this.selected == i); + } + } + } + + } + + @Override + public boolean add(ItemStack itemStack) { + return this.add(-1, itemStack); + } + + @Override + public boolean add(int i, ItemStack itemStack) { + if (itemStack.isEmpty()) { + return false; + } else { + try { + if (itemStack.isDamaged()) { + if (i == -1) { + i = this.getFreeSlot(); + } + + if (i >= 0) { + this.items.set(i, itemStack.copy()); + this.items.get(i).setPopTime(5); + itemStack.setCount(0); + return true; + } else if (this.player.getAbilities().instabuild) { + itemStack.setCount(0); + return true; + } else { + return false; + } + } else { + int j; + do { + j = itemStack.getCount(); + if (i == -1) { + itemStack.setCount(this.addResource(itemStack)); + } else { + itemStack.setCount(this.addResource(i, itemStack)); + } + } while(!itemStack.isEmpty() && itemStack.getCount() < j); + + if (itemStack.getCount() == j && this.player.getAbilities().instabuild) { + itemStack.setCount(0); + return true; + } else { + return itemStack.getCount() < j; + } + } + } catch (Throwable var6) { + CrashReport crashReport = CrashReport.forThrowable(var6, "Adding item to inventory"); + CrashReportCategory crashReportCategory = crashReport.addCategory("Item being added"); + crashReportCategory.setDetail("Item ID", Item.getId(itemStack.getItem())); + crashReportCategory.setDetail("Item data", itemStack.getDamageValue()); + crashReportCategory.setDetail("Item name", () -> itemStack.getHoverName().getString()); + throw new ReportedException(crashReport); + } + } + } + + @Override + public void placeItemBackInInventory(ItemStack itemStack) { + this.placeItemBackInInventory(itemStack, true); + } + + @Override + public void placeItemBackInInventory(ItemStack itemStack, boolean flag) { + while(true) { + if (!itemStack.isEmpty()) { + int i = this.getSlotWithRemainingSpace(itemStack); + if (i == -1) { + i = this.getFreeSlot(); + } + + if (i != -1) { + int j = itemStack.getMaxStackSize() - this.getRawItem(i).getCount(); + if (this.add(i, itemStack.split(j)) && flag && this.player instanceof ServerPlayer) { + ((ServerPlayer)this.player).connection.send(new ClientboundContainerSetSlotPacket(-2, 0, i, this.getRawItem(i))); + } + continue; + } + + this.player.drop(itemStack, false); + } + + return; + } + } + + @Override + public ItemStack removeItem(int rawIndex, final int j) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null + || indexedCompartment.compartment().get(indexedCompartment.index()).isEmpty()) { + return ItemStack.EMPTY; + } + + return ContainerHelper.removeItem(indexedCompartment.compartment(), indexedCompartment.index(), j); + } + + @Override + public void removeItem(ItemStack itemStack) { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (compartment.get(i) == itemStack) { + compartment.set(i, ItemStack.EMPTY); + break; + } + } + } + } + + @Override + public ItemStack removeItemNoUpdate(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + ItemStack removed = indexedCompartment.compartment().set(indexedCompartment.index(), ItemStack.EMPTY); + + if (removed.isEmpty()) { + return ItemStack.EMPTY; + } + + return removed; + } + + @Override + public void setItem(int rawIndex, final ItemStack itemStack) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + this.player.drop(itemStack, true); + return; + } + + indexedCompartment.compartment().set(indexedCompartment.index(), itemStack); + } + + @Override + public float getDestroySpeed(BlockState blockState) { + return this.items.get(this.selected).getDestroySpeed(blockState); + } + + @Override + public ListTag save(ListTag listTag) { + for (int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)i); + this.items.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.armor.size(); ++i) { + if (!this.armor.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 100)); + this.armor.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.offhand.size(); ++i) { + if (!this.offhand.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 150)); + this.offhand.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + return listTag; + } + + @Override + public void load(ListTag listTag) { + this.items.clear(); + this.armor.clear(); + this.offhand.clear(); + + for(int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + ItemStack itemstack = ItemStack.of(compoundTag); + if (!itemstack.isEmpty()) { + if (j < this.items.size()) { + this.items.set(j, itemstack); + } else if (j >= 100 && j < this.armor.size() + 100) { + this.armor.set(j - 100, itemstack); + } else if (j >= 150 && j < this.offhand.size() + 150) { + this.offhand.set(j - 150, itemstack); + } + } + } + + } + + @Override + public int getContainerSize() { + return 45; + } + + @Override + public boolean isEmpty() { + return !contains(itemStack -> !itemStack.isEmpty()); + } + + @Override + public ItemStack getItem(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + return indexedCompartment.compartment().get(indexedCompartment.index()); + } + + @Override + public Component getName() { + return this.player.getName(); + } + + @Override + public ItemStack getArmor(int index) { + return this.armor.get(index); + } + + @Override + public void hurtArmor(DamageSource damagesource, float damage, int[] armorIndices) { + if (damage > 0.0F) { + damage /= 4.0F; + if (damage < 1.0F) { + damage = 1.0F; + } + + for (int index : armorIndices) { + ItemStack itemstack = this.armor.get(index); + if ((!damagesource.isFire() || !itemstack.getItem().isFireResistant()) && itemstack.getItem() instanceof ArmorItem) { + itemstack.hurtAndBreak((int) damage, this.player, localPlayer -> localPlayer.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index))); + } + } + } + } + + @Override + public void dropAll() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + ItemStack itemstack = compartment.get(i); + if (!itemstack.isEmpty()) { + this.player.drop(itemstack, true, false); + compartment.set(i, ItemStack.EMPTY); + } + } + } + } + + @Override + public void setChanged() { + super.setChanged(); + } + + @Override + public int getTimesChanged() { + return super.getTimesChanged(); + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public boolean contains(ItemStack itemstack) { + return contains(itemStack -> itemStack.isEmpty() && itemStack.sameItem(itemstack)); + } + + @Override + public boolean contains(TagKey tagKey) { + + return contains(itemStack -> !itemStack.isEmpty() && itemStack.is(tagKey)); + } + + @Override + public void replaceWith(Inventory inventory) { + Function getter; + + if (inventory instanceof SpecialPlayerInventory specialPlayerInventory) { + getter = specialPlayerInventory::getRawItem; + } else { + getter = inventory::getItem; + } + + for(int i = 0; i < this.getContainerSize(); ++i) { + this.setRawItem(i, getter.apply(i)); + } + + this.selected = inventory.selected; + } + + @Override + public void clearContent() { + for (NonNullList compartment : this.compartments) { + compartment.clear(); + } + } + + @Override + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountSimpleStack(itemstack); + } + } + + @Override + public ItemStack removeFromSelected(boolean dropWholeStack) { + ItemStack itemstack = this.getSelected(); + return itemstack.isEmpty() ? ItemStack.EMPTY : this.removeItem(this.selected, dropWholeStack ? itemstack.getCount() : 1); + } + +} diff --git a/pom.xml b/pom.xml index e4d0494..8eef7ca 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ plugin internal/v1_18_R2 internal/v1_19_R1 + internal/v1_19_R2 assembly -- 2.49.1 From 381dbb2a7821dbb280b27befe612b114fb3e2988 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 10 Dec 2022 16:11:00 -0500 Subject: [PATCH 101/139] Don't disable minimizeJar in internal modules MSHADE-366 was fixed in maven-shade-plugin 3.4.1. This is technically unnecessary either way as the only things currently being shaded are all our own modules. --- internal/v1_18_R2/pom.xml | 4 ---- internal/v1_19_R1/pom.xml | 4 ---- internal/v1_19_R2/pom.xml | 4 ---- 3 files changed, 12 deletions(-) diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index f99be39..2460477 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -67,10 +67,6 @@ maven-shade-plugin - - - false - maven-compiler-plugin diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R1/pom.xml index d0ebc5e..2294135 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -67,10 +67,6 @@ maven-shade-plugin - - - false - maven-compiler-plugin diff --git a/internal/v1_19_R2/pom.xml b/internal/v1_19_R2/pom.xml index 3e96c74..cdfd0e6 100644 --- a/internal/v1_19_R2/pom.xml +++ b/internal/v1_19_R2/pom.xml @@ -67,10 +67,6 @@ maven-shade-plugin - - - false - maven-compiler-plugin -- 2.49.1 From 86bf24e7afaf298210eb83e003b5065458396cbe Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sun, 11 Dec 2022 11:35:21 -0500 Subject: [PATCH 102/139] Bump version to 4.2.2 for release --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- internal/v1_19_R1/pom.xml | 2 +- internal/v1_19_R2/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 540de2a..bbe290b 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.2-SNAPSHOT + 4.2.2 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index fb22eb6..e4321a8 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.2.2-SNAPSHOT + 4.2.2 openinvassembly diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 2460477..2515cd0 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.2-SNAPSHOT + 4.2.2 openinvadapter1_18_R2 diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R1/pom.xml index 2294135..a735e75 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.2-SNAPSHOT + 4.2.2 openinvadapter1_19_R1 diff --git a/internal/v1_19_R2/pom.xml b/internal/v1_19_R2/pom.xml index cdfd0e6..9441856 100644 --- a/internal/v1_19_R2/pom.xml +++ b/internal/v1_19_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.2-SNAPSHOT + 4.2.2 openinvadapter1_19_R2 diff --git a/plugin/pom.xml b/plugin/pom.xml index 43948c4..e8a92fb 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.2-SNAPSHOT + 4.2.2 openinvplugincore diff --git a/pom.xml b/pom.xml index 8eef7ca..ea063f6 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.2.2-SNAPSHOT + 4.2.2 pom @@ -84,13 +84,13 @@ openinvapi com.lishid compile - 4.2.2-SNAPSHOT + 4.2.2 openinvplugincore com.lishid compile - 4.2.2-SNAPSHOT + 4.2.2 com.lishid -- 2.49.1 From 4816737b903bdec2dd22db45902c440c273e1610 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sun, 11 Dec 2022 11:35:36 -0500 Subject: [PATCH 103/139] Bump version to 4.2.3-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- internal/v1_19_R1/pom.xml | 2 +- internal/v1_19_R2/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index bbe290b..38684dd 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.2 + 4.2.3-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index e4321a8..c816a3e 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.2.2 + 4.2.3-SNAPSHOT openinvassembly diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index 2515cd0..deec362 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.2 + 4.2.3-SNAPSHOT openinvadapter1_18_R2 diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R1/pom.xml index a735e75..3d2ae4f 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.2 + 4.2.3-SNAPSHOT openinvadapter1_19_R1 diff --git a/internal/v1_19_R2/pom.xml b/internal/v1_19_R2/pom.xml index 9441856..3a49ce8 100644 --- a/internal/v1_19_R2/pom.xml +++ b/internal/v1_19_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.2 + 4.2.3-SNAPSHOT openinvadapter1_19_R2 diff --git a/plugin/pom.xml b/plugin/pom.xml index e8a92fb..8b600c3 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.2 + 4.2.3-SNAPSHOT openinvplugincore diff --git a/pom.xml b/pom.xml index ea063f6..49ad657 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.2.2 + 4.2.3-SNAPSHOT pom @@ -84,13 +84,13 @@ openinvapi com.lishid compile - 4.2.2 + 4.2.3-SNAPSHOT openinvplugincore com.lishid compile - 4.2.2 + 4.2.3-SNAPSHOT com.lishid -- 2.49.1 From e39f092f14c15767c2d49bb4214c8aba6e5010e5 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 20 Dec 2022 11:54:12 -0500 Subject: [PATCH 104/139] Add lookup cache, option to open self with no args (#115) Add a cache for the last 10 offline lookups done by OpenInv#matchPlayer(String) to reduce the performance hit of repeat opens Add config option to open self with no-arg command --- api/pom.xml | 2 +- .../java/com/lishid/openinv/IOpenInv.java | 80 ++-------- assembly/pom.xml | 2 +- internal/v1_18_R2/pom.xml | 2 +- internal/v1_19_R1/pom.xml | 2 +- internal/v1_19_R2/pom.xml | 2 +- plugin/pom.xml | 2 +- .../main/java/com/lishid/openinv/OpenInv.java | 140 ++++++++++++++++++ .../openinv/commands/OpenInvCommand.java | 24 +-- .../lishid/openinv/util/ConfigUpdater.java | 10 ++ plugin/src/main/resources/config.yml | 5 +- pom.xml | 8 +- 12 files changed, 189 insertions(+), 90 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 38684dd..c85e9b4 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT openinvapi diff --git a/api/src/main/java/com/lishid/openinv/IOpenInv.java b/api/src/main/java/com/lishid/openinv/IOpenInv.java index 9909a98..d71828f 100644 --- a/api/src/main/java/com/lishid/openinv/IOpenInv.java +++ b/api/src/main/java/com/lishid/openinv/IOpenInv.java @@ -22,9 +22,7 @@ import com.lishid.openinv.internal.ISpecialEnderChest; import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.internal.ISpecialPlayerInventory; import com.lishid.openinv.util.InventoryAccess; -import com.lishid.openinv.util.StringMetric; import java.util.UUID; -import java.util.logging.Level; import java.util.logging.Logger; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; @@ -65,6 +63,15 @@ public interface IOpenInv { */ boolean disableOfflineAccess(); + /** + * Check the configuration value for whether OpenInv uses history for opening commands. If false, OpenInv will use + * the previous parameterized search when no parameters are provided. + * + * @return false unless configured otherwise + * @since 4.3.0 + */ + boolean noArgsOpensSelf(); + /** * Get the active {@link IAnySilentContainer} implementation. * @@ -219,74 +226,7 @@ public interface IOpenInv { * @param name the string to match * @return the user with the closest matching name */ - default @Nullable OfflinePlayer matchPlayer(@NotNull String name) { - - // Warn if called on the main thread - if we resort to searching offline players, this may take several seconds. - if (Bukkit.getServer().isPrimaryThread()) { - this.getLogger().warning("Call to OpenInv#matchPlayer made on the main thread!"); - this.getLogger().warning("This can cause the server to hang, potentially severely."); - this.getLogger().log(Level.WARNING, "Current stack trace", new Throwable("Current stack trace")); - } - - OfflinePlayer player; - - try { - UUID uuid = UUID.fromString(name); - player = Bukkit.getOfflinePlayer(uuid); - // Ensure player is an existing player. - if (player.hasPlayedBefore() || player.isOnline()) { - return player; - } - // Return null otherwise. - return null; - } catch (IllegalArgumentException ignored) { - // Not a UUID - } - - // Exact online match first. - player = Bukkit.getServer().getPlayerExact(name); - - if (player != null) { - return player; - } - - // Exact offline match second - ensure offline access works when matchable users are online. - player = Bukkit.getServer().getOfflinePlayer(name); - - if (player.hasPlayedBefore()) { - return player; - } - - // Inexact online match. - player = Bukkit.getServer().getPlayer(name); - - if (player != null) { - return player; - } - - // Finally, inexact offline match. - float bestMatch = 0; - for (OfflinePlayer offline : Bukkit.getServer().getOfflinePlayers()) { - if (offline.getName() == null) { - // Loaded by UUID only, name has never been looked up. - continue; - } - - float currentMatch = StringMetric.compareJaroWinkler(name, offline.getName()); - - if (currentMatch == 1.0F) { - return offline; - } - - if (currentMatch > bestMatch) { - bestMatch = currentMatch; - player = offline; - } - } - - // Only null if no players have played ever, otherwise even the worst match will do. - return player; - } + @Nullable OfflinePlayer matchPlayer(@NotNull String name); /** * @deprecated OpenInv uses action bar chat for notifications. Whether they show is based on language settings. diff --git a/assembly/pom.xml b/assembly/pom.xml index c816a3e..8bb8011 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT openinvassembly diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_18_R2/pom.xml index deec362..29b5e58 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_18_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT openinvadapter1_18_R2 diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R1/pom.xml index 3d2ae4f..df50f14 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT openinvadapter1_19_R1 diff --git a/internal/v1_19_R2/pom.xml b/internal/v1_19_R2/pom.xml index 3a49ce8..1a66835 100644 --- a/internal/v1_19_R2/pom.xml +++ b/internal/v1_19_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT openinvadapter1_19_R2 diff --git a/plugin/pom.xml b/plugin/pom.xml index 8b600c3..d984530 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT openinvplugincore diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index 98b634e..cfca819 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -16,6 +16,8 @@ package com.lishid.openinv; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.lishid.openinv.commands.ContainerSettingCommand; import com.lishid.openinv.commands.OpenInvCommand; import com.lishid.openinv.commands.SearchContainerCommand; @@ -28,7 +30,9 @@ import com.lishid.openinv.internal.ISpecialPlayerInventory; import com.lishid.openinv.util.ConfigUpdater; import com.lishid.openinv.util.LanguageManager; import com.lishid.openinv.util.Permissions; +import com.lishid.openinv.util.StringMetric; import java.util.ArrayList; +import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.UUID; @@ -37,6 +41,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.logging.Level; import java.util.stream.Stream; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; @@ -52,6 +57,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.profile.PlayerProfile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -62,6 +68,7 @@ import org.jetbrains.annotations.Nullable; */ public class OpenInv extends JavaPlugin implements IOpenInv { + private final Cache offlineLookUpCache = CacheBuilder.newBuilder().maximumSize(10).build(); private final Map inventories = new ConcurrentHashMap<>(); private final Map enderChests = new ConcurrentHashMap<>(); @@ -190,6 +197,11 @@ public class OpenInv extends JavaPlugin implements IOpenInv { return this.getConfig().getBoolean("settings.disable-offline-access", false); } + @Override + public boolean noArgsOpensSelf() { + return this.getConfig().getBoolean("settings.command.open.no-args-opens-self", false); + } + @Override public @NotNull IAnySilentContainer getAnySilentContainer() { return this.accessor.getAnySilentContainer(); @@ -311,6 +323,95 @@ public class OpenInv extends JavaPlugin implements IOpenInv { return player; } + @Override + public @Nullable OfflinePlayer matchPlayer(@NotNull String name) { + + // Warn if called on the main thread - if we resort to searching offline players, this may take several seconds. + if (Bukkit.getServer().isPrimaryThread()) { + this.getLogger().warning("Call to OpenInv#matchPlayer made on the main thread!"); + this.getLogger().warning("This can cause the server to hang, potentially severely."); + this.getLogger().log(Level.WARNING, "Current stack trace", new Throwable("Current stack trace")); + } + + OfflinePlayer player; + + try { + UUID uuid = UUID.fromString(name); + player = Bukkit.getOfflinePlayer(uuid); + // Ensure player is an existing player. + if (player.hasPlayedBefore() || player.isOnline()) { + return player; + } + // Return null otherwise. + return null; + } catch (IllegalArgumentException ignored) { + // Not a UUID + } + + // Exact online match first. + player = Bukkit.getServer().getPlayerExact(name); + + if (player != null) { + return player; + } + + // Cached offline match. + PlayerProfile cachedResult = offlineLookUpCache.getIfPresent(name); + if (cachedResult != null && cachedResult.getUniqueId() != null) { + player = Bukkit.getOfflinePlayer(cachedResult.getUniqueId()); + // Ensure player is an existing player. + if (player.hasPlayedBefore() || player.isOnline()) { + return player; + } + // Return null otherwise. + return null; + } + + // Exact offline match second - ensure offline access works when matchable users are online. + player = Bukkit.getServer().getOfflinePlayer(name); + + if (player.hasPlayedBefore()) { + offlineLookUpCache.put(name, player.getPlayerProfile()); + return player; + } + + // Inexact online match. + player = Bukkit.getServer().getPlayer(name); + + if (player != null) { + return player; + } + + // Finally, inexact offline match. + float bestMatch = 0; + for (OfflinePlayer offline : Bukkit.getServer().getOfflinePlayers()) { + if (offline.getName() == null) { + // Loaded by UUID only, name has never been looked up. + continue; + } + + float currentMatch = StringMetric.compareJaroWinkler(name, offline.getName()); + + if (currentMatch == 1.0F) { + return offline; + } + + if (currentMatch > bestMatch) { + bestMatch = currentMatch; + player = offline; + } + } + + if (player != null) { + // If a match was found, store it. + offlineLookUpCache.put(name, player.getPlayerProfile()); + return player; + } + + // No players have ever joined the server. + return null; + } + @Override public void unload(@NotNull final OfflinePlayer offline) { setPlayerOffline(offline, OfflineHandler.REMOVE_AND_CLOSE); @@ -492,6 +593,45 @@ public class OpenInv extends JavaPlugin implements IOpenInv { void setPlayerOnline(@NotNull Player player) { setPlayerOnline(inventories, player, player::updateInventory); setPlayerOnline(enderChests, player, null); + + if (player.hasPlayedBefore()) { + return; + } + + // New player may have a name that already points to someone else in lookup cache. + String name = player.getName(); + this.offlineLookUpCache.invalidate(name); + + // If no offline matches are mapped, don't hit scheduler. + if (this.offlineLookUpCache.size() == 0) { + return; + } + + // New player may also be a more exact match than one already in the cache. + // I.e. new player "lava1" is a better match for "lava" than "lava123" + // Player joins are already quite intensive, so this is run on a delay. + this.getServer().getScheduler().runTaskLaterAsynchronously(this, () -> { + Iterator> iterator = this.offlineLookUpCache.asMap().entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + String oldMatch = entry.getValue().getName(); + + // Shouldn't be possible - all profiles should be complete. + if (oldMatch == null) { + iterator.remove(); + continue; + } + + String lookup = entry.getKey(); + float oldMatchScore = StringMetric.compareJaroWinkler(lookup, oldMatch); + float newMatchScore = StringMetric.compareJaroWinkler(lookup, name); + + // If new match exceeds old match, delete old match. + if (newMatchScore > oldMatchScore) { + iterator.remove(); + } + } + }, 101L); // Odd delay for pseudo load balancing; Player tasks are usually scheduled with full seconds. } private void setPlayerOnline( diff --git a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java index 5d3b986..8117697 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java @@ -57,19 +57,23 @@ public class OpenInvCommand implements TabExecutor { return true; } - // History management - String history = (openInv ? this.openInvHistory : this.openEnderHistory).get(player); + String noArgValue; + if (plugin.noArgsOpensSelf()) { + noArgValue = player.getUniqueId().toString(); + } else { + // History management + noArgValue = (openInv ? this.openInvHistory : this.openEnderHistory).get(player); - if (history == null || history.isEmpty()) { - history = player.getName(); - (openInv ? this.openInvHistory : this.openEnderHistory).put(player, history); + if (noArgValue == null || noArgValue.isEmpty()) { + noArgValue = player.getUniqueId().toString(); + (openInv ? this.openInvHistory : this.openEnderHistory).put(player, noArgValue); + } } final String name; - // Read from history if target is not named if (args.length < 1) { - name = history; + name = noArgValue; } else { name = args[0]; } @@ -185,8 +189,10 @@ public class OpenInvCommand implements TabExecutor { } } - // Record the target - (openinv ? this.openInvHistory : this.openEnderHistory).put(player, target.getUniqueId().toString()); + if (!plugin.noArgsOpensSelf()) { + // Record the target + (openinv ? this.openInvHistory : this.openEnderHistory).put(player, target.getUniqueId().toString()); + } // Create the inventory final ISpecialInventory inv; diff --git a/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java b/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java index 6f8a595..6c74613 100644 --- a/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java +++ b/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java @@ -57,6 +57,9 @@ public record ConfigUpdater(OpenInv plugin) { if (version < 5) { updateConfig4To5(); } + if (version < 6) { + updateConfig5To6(); + } plugin.getServer().getScheduler().runTask(plugin, () -> { plugin.saveConfig(); @@ -65,6 +68,13 @@ public record ConfigUpdater(OpenInv plugin) { }); } + private void updateConfig5To6() { + plugin.getServer().getScheduler().runTask(plugin, () -> { + plugin.getConfig().set("settings.command.open.no-args-opens-self", false); + plugin.getConfig().set("config-version", 6); + }); + } + private void updateConfig4To5() { plugin.getServer().getScheduler().runTask(plugin, () -> { plugin.getConfig().set("settings.disable-offline-access", false); diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index f0b56f0..38edd51 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -1,5 +1,8 @@ -config-version: 5 +config-version: 6 settings: + command: + open: + no-args-opens-self: false disable-offline-access: false disable-saving: false locale: 'en_us' diff --git a/pom.xml b/pom.xml index 49ad657..a5e856a 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT pom @@ -78,19 +78,19 @@ spigot-api org.spigotmc provided - 1.17.1-R0.1-SNAPSHOT + 1.18.2-R0.1-SNAPSHOT openinvapi com.lishid compile - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT openinvplugincore com.lishid compile - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT com.lishid -- 2.49.1 From 81eb60f628752e8653b07148c45e6f768d13754f Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 20 Dec 2022 15:54:30 -0500 Subject: [PATCH 105/139] Improve language manager (#116) * Clarify replacements internally to reduce the likelihood of messing up when including new ones * Fix missing keys not being written to disk for easy translation * Use a guessfile-like system where missing translation keys are inserted into a separate section for easy identification * Reduce verbosity of missing keys warning --- .../main/java/com/lishid/openinv/OpenInv.java | 7 +- .../commands/ContainerSettingCommand.java | 7 +- .../openinv/commands/OpenInvCommand.java | 13 +- .../commands/SearchContainerCommand.java | 19 +- .../commands/SearchEnchantCommand.java | 15 +- .../openinv/commands/SearchInvCommand.java | 26 ++- .../openinv/internal/OpenInventoryView.java | 4 +- .../lishid/openinv/util/LanguageManager.java | 168 -------------- .../openinv/util/lang/LanguageManager.java | 217 ++++++++++++++++++ .../lishid/openinv/util/lang/Replacement.java | 29 +++ 10 files changed, 310 insertions(+), 195 deletions(-) delete mode 100644 plugin/src/main/java/com/lishid/openinv/util/LanguageManager.java create mode 100644 plugin/src/main/java/com/lishid/openinv/util/lang/LanguageManager.java create mode 100644 plugin/src/main/java/com/lishid/openinv/util/lang/Replacement.java diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index cfca819..25b28aa 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -28,9 +28,10 @@ import com.lishid.openinv.internal.ISpecialEnderChest; import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.internal.ISpecialPlayerInventory; import com.lishid.openinv.util.ConfigUpdater; -import com.lishid.openinv.util.LanguageManager; import com.lishid.openinv.util.Permissions; import com.lishid.openinv.util.StringMetric; +import com.lishid.openinv.util.lang.LanguageManager; +import com.lishid.openinv.util.lang.Replacement; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; @@ -463,7 +464,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { public @Nullable String getLocalizedMessage( @NotNull CommandSender sender, @NotNull String key, - String @NotNull ... replacements) { + Replacement @NotNull ... replacements) { return this.languageManager.getValue(key, getLocale(sender), replacements); } @@ -483,7 +484,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { } } - public void sendMessage(@NotNull CommandSender sender, @NotNull String key, String @NotNull... replacements) { + public void sendMessage(@NotNull CommandSender sender, @NotNull String key, Replacement @NotNull... replacements) { String message = getLocalizedMessage(sender, key, replacements); if (message != null && !message.isEmpty()) { diff --git a/plugin/src/main/java/com/lishid/openinv/commands/ContainerSettingCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/ContainerSettingCommand.java index 406b472..c8dd3c7 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/ContainerSettingCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/ContainerSettingCommand.java @@ -18,6 +18,7 @@ package com.lishid.openinv.commands; import com.lishid.openinv.OpenInv; import com.lishid.openinv.util.TabCompleter; +import com.lishid.openinv.util.lang.Replacement; import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; @@ -69,7 +70,11 @@ public class ContainerSettingCommand implements TabExecutor { onOff = String.valueOf(getSetting.test(player)); } - plugin.sendMessage(sender, "messages.info.settingState","%setting%", any ? "AnyContainer" : "SilentContainer", "%state%", onOff); + plugin.sendMessage( + sender, + "messages.info.settingState", + new Replacement("%setting%", any ? "AnyContainer" : "SilentContainer"), + new Replacement("%state%", onOff)); return true; } diff --git a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java index 8117697..d4f193a 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/OpenInvCommand.java @@ -20,6 +20,7 @@ import com.lishid.openinv.OpenInv; import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.util.Permissions; import com.lishid.openinv.util.TabCompleter; +import com.lishid.openinv.util.lang.Replacement; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -175,16 +176,20 @@ public class OpenInvCommand implements TabExecutor { // Protected check if (!Permissions.OVERRIDE.hasPermission(player) && Permissions.EXEMPT.hasPermission(onlineTarget)) { - plugin.sendMessage(player, "messages.error.permissionExempt", - "%target%", onlineTarget.getDisplayName()); + plugin.sendMessage( + player, + "messages.error.permissionExempt", + new Replacement("%target%", onlineTarget.getDisplayName())); return; } // Crossworld check if (!Permissions.CROSSWORLD.hasPermission(player) && !onlineTarget.getWorld().equals(player.getWorld())) { - plugin.sendMessage(player, "messages.error.permissionCrossWorld", - "%target%", onlineTarget.getDisplayName()); + plugin.sendMessage( + player, + "messages.error.permissionCrossWorld", + new Replacement("%target%", onlineTarget.getDisplayName())); return; } } diff --git a/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java index 37e7c53..bef78bb 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java @@ -18,6 +18,7 @@ package com.lishid.openinv.commands; import com.lishid.openinv.OpenInv; import com.lishid.openinv.util.TabCompleter; +import com.lishid.openinv.util.lang.Replacement; import java.util.Collections; import java.util.List; import org.bukkit.Chunk; @@ -57,7 +58,10 @@ public class SearchContainerCommand implements TabExecutor { Material material = Material.getMaterial(args[0].toUpperCase()); if (material == null) { - plugin.sendMessage(sender, "messages.error.invalidMaterial", "%target%", args[0]); + plugin.sendMessage( + sender, + "messages.error.invalidMaterial", + new Replacement("%target%", args[0])); return false; } @@ -100,13 +104,18 @@ public class SearchContainerCommand implements TabExecutor { if (locations.length() > 0) { locations.delete(locations.length() - 2, locations.length()); } else { - plugin.sendMessage(sender, "messages.info.container.noMatches", - "%target%", material.name()); + plugin.sendMessage( + sender, + "messages.info.container.noMatches", + new Replacement("%target%", material.name())); return true; } - plugin.sendMessage(sender, "messages.info.container.matches", - "%target%", material.name(), "%detail%", locations.toString()); + plugin.sendMessage( + sender, + "messages.info.container.matches", + new Replacement("%target%", material.name()), + new Replacement("%detail%", locations.toString())); return true; } diff --git a/plugin/src/main/java/com/lishid/openinv/commands/SearchEnchantCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/SearchEnchantCommand.java index c79aa43..2c52f5d 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/SearchEnchantCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/SearchEnchantCommand.java @@ -18,6 +18,7 @@ package com.lishid.openinv.commands; import com.lishid.openinv.OpenInv; import com.lishid.openinv.util.TabCompleter; +import com.lishid.openinv.util.lang.Replacement; import java.util.Collections; import java.util.List; import org.bukkit.Material; @@ -114,14 +115,18 @@ public class SearchEnchantCommand implements TabExecutor { // Matches found, delete trailing comma and space players.delete(players.length() - 2, players.length()); } else { - plugin.sendMessage(sender, "messages.info.player.noMatches", - "%target%", (enchant != null ? enchant.getKey().toString() : "") + " >= " + level); + plugin.sendMessage( + sender, + "messages.info.player.noMatches", + new Replacement("%target%", (enchant != null ? enchant.getKey().toString() : "") + " >= " + level)); return true; } - plugin.sendMessage(sender, "messages.info.player.matches", - "%target%", (enchant != null ? enchant.getKey().toString() : "") + " >= " + level, - "%detail%", players.toString()); + plugin.sendMessage( + sender, + "messages.info.player.matches", + new Replacement("%target%", (enchant != null ? enchant.getKey().toString() : "") + " >= " + level), + new Replacement("%detail%", players.toString())); return true; } diff --git a/plugin/src/main/java/com/lishid/openinv/commands/SearchInvCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/SearchInvCommand.java index 3b2cbfb..60235bd 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/SearchInvCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/SearchInvCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 lishid. All rights reserved. + * Copyright (C) 2011-2022 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ package com.lishid.openinv.commands; import com.lishid.openinv.OpenInv; import com.lishid.openinv.util.TabCompleter; +import com.lishid.openinv.util.lang.Replacement; import java.util.Collections; import java.util.List; import org.bukkit.Material; @@ -46,7 +47,10 @@ public class SearchInvCommand implements TabExecutor { } if (material == null) { - plugin.sendMessage(sender, "messages.error.invalidMaterial", "%target%", args.length > 0 ? args[0] : "null"); + plugin.sendMessage( + sender, + "messages.error.invalidMaterial", + new Replacement("%target%", args.length > 0 ? args[0] : "null")); return false; } @@ -56,7 +60,10 @@ public class SearchInvCommand implements TabExecutor { try { count = Integer.parseInt(args[1]); } catch (NumberFormatException ex) { - plugin.sendMessage(sender, "messages.error.invalidNumber", "%target%", args[1]); + plugin.sendMessage( + sender, + "messages.error.invalidNumber", + new Replacement("%target%", args[1])); return false; } } @@ -74,13 +81,18 @@ public class SearchInvCommand implements TabExecutor { if (players.length() > 0) { players.delete(players.length() - 2, players.length()); } else { - plugin.sendMessage(sender, "messages.info.player.noMatches", - "%target%", material.name()); + plugin.sendMessage( + sender, + "messages.info.player.noMatches", + new Replacement("%target%", material.name())); return true; } - plugin.sendMessage(sender, "messages.info.player.matches", - "%target%", material.name(), "%detail%", players.toString()); + plugin.sendMessage( + sender, + "messages.info.player.matches", + new Replacement("%target%", material.name()), + new Replacement("%detail%", players.toString())); return true; } diff --git a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java index a7f4a95..ea7c438 100644 --- a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java +++ b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java @@ -17,6 +17,7 @@ package com.lishid.openinv.internal; import com.lishid.openinv.OpenInv; +import com.lishid.openinv.util.lang.Replacement; import java.util.Objects; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; @@ -73,8 +74,7 @@ public class OpenInventoryView extends InventoryView { .getLocalizedMessage( player, titleKey, - "%player%", - owner.getName()); + new Replacement("%player%", owner.getName())); title = Objects.requireNonNullElseGet(localTitle, () -> owner.getName() + titleDefaultSuffix); } diff --git a/plugin/src/main/java/com/lishid/openinv/util/LanguageManager.java b/plugin/src/main/java/com/lishid/openinv/util/LanguageManager.java deleted file mode 100644 index ff526b1..0000000 --- a/plugin/src/main/java/com/lishid/openinv/util/LanguageManager.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2011-2022 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.util; - -import com.lishid.openinv.OpenInv; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import org.bukkit.ChatColor; -import org.bukkit.configuration.file.YamlConfiguration; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * A simple language manager supporting both custom and bundled languages. - * - * @author Jikoo - */ -public class LanguageManager { - - private final OpenInv plugin; - private final String defaultLocale; - private final Map locales; - - public LanguageManager(@NotNull OpenInv plugin, @NotNull String defaultLocale) { - this.plugin = plugin; - this.defaultLocale = defaultLocale; - this.locales = new HashMap<>(); - getOrLoadLocale(defaultLocale); - } - - private @NotNull YamlConfiguration getOrLoadLocale(@NotNull String locale) { - YamlConfiguration loaded = locales.get(locale); - if (loaded != null) { - return loaded; - } - - InputStream resourceStream = plugin.getResource("locale/" + locale + ".yml"); - YamlConfiguration localeConfigDefaults; - if (resourceStream == null) { - localeConfigDefaults = new YamlConfiguration(); - } else { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceStream))) { - localeConfigDefaults = YamlConfiguration.loadConfiguration(reader); - } catch (IOException e) { - plugin.getLogger().log(Level.WARNING, "[LanguageManager] Unable to load resource " + locale + ".yml", e); - localeConfigDefaults = new YamlConfiguration(); - } - } - - File file = new File(plugin.getDataFolder(), locale + ".yml"); - YamlConfiguration localeConfig; - - if (!file.exists()) { - localeConfig = localeConfigDefaults; - try { - localeConfigDefaults.save(file); - } catch (IOException e) { - plugin.getLogger().log(Level.WARNING, "[LanguageManager] Unable to save resource " + locale + ".yml", e); - } - } else { - localeConfig = YamlConfiguration.loadConfiguration(file); - - // Add new language keys - List newKeys = new ArrayList<>(); - for (String key : localeConfigDefaults.getKeys(true)) { - if (localeConfigDefaults.isConfigurationSection(key)) { - continue; - } - - if (localeConfig.isSet(key)) { - continue; - } - - localeConfig.set(key, localeConfigDefaults.get(key)); - newKeys.add(key); - } - - if (!newKeys.isEmpty()) { - plugin.getLogger().info("[LanguageManager] Added new language keys: " + String.join(", ", newKeys)); - try { - localeConfig.save(file); - } catch (IOException e) { - plugin.getLogger().log(Level.WARNING, "[LanguageManager] Unable to save resource " + locale + ".yml", e); - } - } - } - - if (!locale.equals(defaultLocale)) { - localeConfigDefaults = locales.get(defaultLocale); - - // Check for missing keys - List newKeys = new ArrayList<>(); - for (String key : localeConfigDefaults.getKeys(true)) { - if (localeConfigDefaults.isConfigurationSection(key)) { - continue; - } - - if (localeConfig.isSet(key)) { - continue; - } - - newKeys.add(key); - } - - if (!newKeys.isEmpty()) { - plugin.getLogger().info("[LanguageManager] Missing translations from " + locale + ".yml: " + String.join(", ", newKeys)); - } - - // Fall through to default locale - localeConfig.setDefaults(localeConfigDefaults); - } - - locales.put(locale, localeConfig); - return localeConfig; - } - - public @Nullable String getValue(@NotNull String key, @Nullable String locale) { - String value = getOrLoadLocale(locale == null ? defaultLocale : locale.toLowerCase()).getString(key); - if (value == null || value.isEmpty()) { - return null; - } - - value = ChatColor.translateAlternateColorCodes('&', value); - - return value; - } - - public @Nullable String getValue(@NotNull String key, @Nullable String locale, String @NotNull ... replacements) { - if (replacements.length % 2 != 0) { - plugin.getLogger().log(Level.WARNING, "[LanguageManager] Replacement data is uneven", new Exception()); - } - - String value = getValue(key, locale); - - if (value == null) { - return null; - } - - for (int i = 0; i < replacements.length; i += 2) { - value = value.replace(replacements[i], replacements[i + 1]); - } - - return value; - } - -} diff --git a/plugin/src/main/java/com/lishid/openinv/util/lang/LanguageManager.java b/plugin/src/main/java/com/lishid/openinv/util/lang/LanguageManager.java new file mode 100644 index 0000000..239031e --- /dev/null +++ b/plugin/src/main/java/com/lishid/openinv/util/lang/LanguageManager.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.util.lang; + +import com.lishid.openinv.OpenInv; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.logging.Level; +import org.bukkit.ChatColor; +import org.bukkit.configuration.Configuration; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * A simple language manager supporting both custom and bundled languages. + * + * @author Jikoo + */ +public class LanguageManager { + + private final OpenInv plugin; + private final String defaultLocale; + private final Map locales; + + public LanguageManager(@NotNull OpenInv plugin, @NotNull String defaultLocale) { + this.plugin = plugin; + this.defaultLocale = defaultLocale; + this.locales = new HashMap<>(); + getOrLoadLocale(defaultLocale); + } + + private @NotNull YamlConfiguration getOrLoadLocale(@NotNull String locale) { + YamlConfiguration loaded = locales.get(locale); + if (loaded != null) { + return loaded; + } + + File file = new File(plugin.getDataFolder(), locale + ".yml"); + + // Load locale config from disk and bundled locale defaults. + YamlConfiguration localeConfig = loadLocale(locale, file); + + // If the locale is not the default locale, also handle any missing translations from the default locale. + if (!locale.equals(defaultLocale)) { + addTranslationFallthrough(locale, localeConfig, file); + + if (plugin.getConfig().getBoolean("settings.secret.warn-about-guess-section", true) + && localeConfig.isConfigurationSection("guess")) { + // Warn that guess section exists. This should run once per language per server restart + // when accessed by a user to hint to server owners that they can make UX improvements. + plugin.getLogger().info(() -> "[LanguageManager] Missing translations from " + locale + ".yml! Check the guess section!"); + } + } + + locales.put(locale, localeConfig); + return localeConfig; + } + + private @NotNull YamlConfiguration loadLocale( + @NotNull String locale, + @NotNull File file) { + // Load defaults from the plugin's bundled resources. + InputStream resourceStream = plugin.getResource("locale/" + locale + ".yml"); + YamlConfiguration localeConfigDefaults; + if (resourceStream == null) { + localeConfigDefaults = new YamlConfiguration(); + } else { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceStream))) { + localeConfigDefaults = YamlConfiguration.loadConfiguration(reader); + } catch (IOException e) { + plugin.getLogger().log(Level.WARNING, e, () -> "[LanguageManager] Unable to load resource " + locale + ".yml"); + localeConfigDefaults = new YamlConfiguration(); + } + } + + if (!file.exists()) { + // If the file does not exist on disk, save bundled defaults. + try { + localeConfigDefaults.save(file); + } catch (IOException e) { + plugin.getLogger().log(Level.WARNING, e, () -> "[LanguageManager] Unable to save resource " + locale + ".yml"); + } + // Return loaded bundled locale. + return localeConfigDefaults; + } + + // If the file does exist on disk, load it. + YamlConfiguration localeConfig = YamlConfiguration.loadConfiguration(file); + // Check for missing translations from the bundled file. + List newKeys = getMissingKeys(localeConfigDefaults, localeConfig::isSet); + + if (newKeys.isEmpty()) { + return localeConfig; + } + + // Get guess section for missing keys. + ConfigurationSection guess = localeConfig.getConfigurationSection("guess"); + + for (String newKey : newKeys) { + // Set all missing keys to defaults. + localeConfig.set(newKey, localeConfigDefaults.get(newKey)); + + // Delete relevant guess keys in case this is a new translation. + if (guess != null) { + guess.set(newKey, null); + } + } + + // If guess section is empty, delete it. + if (guess != null && guess.getKeys(false).isEmpty()) { + localeConfig.set("guess", null); + } + + plugin.getLogger().info(() -> "[LanguageManager] Added new translation keys to " + locale + ".yml: " + String.join(", ", newKeys)); + + // Write new keys to disk. + try { + localeConfig.save(file); + } catch (IOException e) { + plugin.getLogger().log(Level.WARNING, e, () -> "[LanguageManager] Unable to save resource " + locale + ".yml"); + } + + return localeConfig; + } + + private void addTranslationFallthrough( + @NotNull String locale, + @NotNull YamlConfiguration localeConfig, + @NotNull File file) { + YamlConfiguration defaultLocaleConfig = locales.get(defaultLocale); + + // Get missing keys. Keys that already have a guess value are not new and don't need to trigger another write. + List missingKeys = getMissingKeys( + defaultLocaleConfig, + key -> localeConfig.isSet(key) || localeConfig.isSet("guess." + key)); + + if (!missingKeys.isEmpty()) { + // Set up guess section for missing keys. + for (String key : missingKeys) { + localeConfig.set("guess." + key, defaultLocaleConfig.get(key)); + } + + // Write modified guess section to disk. + try { + localeConfig.save(file); + } catch (IOException e) { + plugin.getLogger().log(Level.WARNING, e, () -> "[LanguageManager] Unable to save resource " + locale + ".yml"); + } + } + + // Fall through to default locale. + localeConfig.setDefaults(defaultLocaleConfig); + } + + private @NotNull List getMissingKeys( + @NotNull Configuration configurationDefault, + @NotNull Predicate nodeSetPredicate) { + List missingKeys = new ArrayList<>(); + for (String key : configurationDefault.getKeys(true)) { + if (!configurationDefault.isConfigurationSection(key) && !nodeSetPredicate.test(key)) { + // Missing keys are non-section keys that fail the predicate. + missingKeys.add(key); + } + } + return missingKeys; + } + + public @Nullable String getValue(@NotNull String key, @Nullable String locale) { + String value = getOrLoadLocale(locale == null ? defaultLocale : locale.toLowerCase()).getString(key); + if (value == null || value.isEmpty()) { + return null; + } + + value = ChatColor.translateAlternateColorCodes('&', value); + + return value; + } + + public @Nullable String getValue(@NotNull String key, @Nullable String locale, Replacement @NotNull ... replacements) { + String value = getValue(key, locale); + + if (value == null) { + return null; + } + + for (Replacement replacement : replacements) { + value = value.replace(replacement.placeholder(), replacement.value()); + } + + return value; + } + +} diff --git a/plugin/src/main/java/com/lishid/openinv/util/lang/Replacement.java b/plugin/src/main/java/com/lishid/openinv/util/lang/Replacement.java new file mode 100644 index 0000000..6753044 --- /dev/null +++ b/plugin/src/main/java/com/lishid/openinv/util/lang/Replacement.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011-2022 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.util.lang; + +import org.jetbrains.annotations.NotNull; + +/** + * A data holder for string replacement in translations. + * + * @param placeholder the placeholder to be replaced + * @param value the value to insert + */ +public record Replacement(@NotNull String placeholder, @NotNull String value) { + +} -- 2.49.1 From 79b2a97c9e84a7b3fe19e166a54b88967452f59d Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 20 Dec 2022 16:44:49 -0500 Subject: [PATCH 106/139] Clamp /searchcontainer radius (#117) Default max is 10 because that's the default server view distance. --- .../com/lishid/openinv/commands/SearchContainerCommand.java | 4 ++++ .../src/main/java/com/lishid/openinv/util/ConfigUpdater.java | 1 + plugin/src/main/resources/config.yml | 2 ++ 3 files changed, 7 insertions(+) diff --git a/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java b/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java index bef78bb..161dfed 100644 --- a/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java +++ b/plugin/src/main/java/com/lishid/openinv/commands/SearchContainerCommand.java @@ -76,6 +76,10 @@ public class SearchContainerCommand implements TabExecutor { } } + // Clamp radius. + int configMax = plugin.getConfig().getInt("settings.command.searchcontainer.max-radius", 10); + radius = Math.max(0, Math.min(radius, configMax)); + World world = senderPlayer.getWorld(); Chunk centerChunk = senderPlayer.getLocation().getChunk(); StringBuilder locations = new StringBuilder(); diff --git a/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java b/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java index 6c74613..a657f84 100644 --- a/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java +++ b/plugin/src/main/java/com/lishid/openinv/util/ConfigUpdater.java @@ -71,6 +71,7 @@ public record ConfigUpdater(OpenInv plugin) { private void updateConfig5To6() { plugin.getServer().getScheduler().runTask(plugin, () -> { plugin.getConfig().set("settings.command.open.no-args-opens-self", false); + plugin.getConfig().set("settings.command.searchcontainer.max-radius", 10); plugin.getConfig().set("config-version", 6); }); } diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index 38edd51..6a68c9c 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -3,6 +3,8 @@ settings: command: open: no-args-opens-self: false + searchcontainer: + max-radius: 10 disable-offline-access: false disable-saving: false locale: 'en_us' -- 2.49.1 From dc8e36d11fc10eb30880d5ec5cd83e80337b04c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Jan 2023 19:13:14 -0500 Subject: [PATCH 107/139] Bump annotations from 23.0.0 to 23.1.0 (#121) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a5e856a..8568e4a 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ annotations org.jetbrains provided - 23.0.0 + 23.1.0 spigot-api -- 2.49.1 From 767476a7590471a9b6192a30b55cf92a44b27387 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Feb 2023 09:01:06 -0500 Subject: [PATCH 108/139] Bump annotations from 23.1.0 to 24.0.0 (#122) Bumps [annotations](https://github.com/JetBrains/java-annotations) from 23.1.0 to 24.0.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/23.1.0...24.0.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8568e4a..3d9cfb7 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ annotations org.jetbrains provided - 23.1.0 + 24.0.0 spigot-api -- 2.49.1 From 2fe0322570cfa61f5013fdc7e86ff021544c3d8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Feb 2023 09:01:16 -0500 Subject: [PATCH 109/139] Bump maven-dependency-plugin from 3.4.0 to 3.5.0 (#123) Bumps [maven-dependency-plugin](https://github.com/apache/maven-dependency-plugin) from 3.4.0 to 3.5.0. - [Release notes](https://github.com/apache/maven-dependency-plugin/releases) - [Commits](https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.4.0...maven-dependency-plugin-3.5.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-dependency-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3d9cfb7..7a303a3 100644 --- a/pom.xml +++ b/pom.xml @@ -111,7 +111,7 @@ --> maven-dependency-plugin org.apache.maven.plugins - 3.4.0 + 3.5.0 -- 2.49.1 From bd5e47760e0f10b447cd34f8fb6d19e069e035c7 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 18 Feb 2023 14:10:36 -0500 Subject: [PATCH 110/139] Fix duplicate closes swapping players to spectate (#125) --- .../openinv/internal/IAnySilentContainer.java | 24 ++++++++++++------- .../internal/v1_18_R2/AnySilentContainer.java | 17 +++---------- .../internal/v1_19_R1/AnySilentContainer.java | 17 +++---------- .../internal/v1_19_R2/AnySilentContainer.java | 17 +++---------- .../com/lishid/openinv/InventoryListener.java | 7 ++++-- 5 files changed, 29 insertions(+), 53 deletions(-) diff --git a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java index 8c59530..f87ac6b 100644 --- a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java +++ b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,7 +16,6 @@ package com.lishid.openinv.internal; -import org.bukkit.Material; import org.bukkit.block.Barrel; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -148,13 +147,20 @@ public interface IAnySilentContainer { * @return true if the type is a supported container */ default boolean isAnySilentContainer(@NotNull Block block) { - if (block.getType() == Material.ENDER_CHEST) { - return true; - } - BlockState state = block.getState(); - return state instanceof org.bukkit.block.Chest - || state instanceof org.bukkit.block.ShulkerBox - || state instanceof org.bukkit.block.Barrel; + return isAnySilentContainer(block.getState()); + } + + /** + * Check if the given {@link BlockState} is a container which can be unblocked or silenced. + * + * @param blockState the potential container + * @return true if the type is a supported container + */ + default boolean isAnySilentContainer(@NotNull BlockState blockState) { + return blockState instanceof org.bukkit.block.EnderChest + || blockState instanceof org.bukkit.block.Chest + || blockState instanceof org.bukkit.block.ShulkerBox + || blockState instanceof org.bukkit.block.Barrel; } } diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/AnySilentContainer.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/AnySilentContainer.java index 7fae7c5..77aac17 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/AnySilentContainer.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/AnySilentContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,12 +50,12 @@ import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.Statistic; import org.bukkit.block.ShulkerBox; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -231,21 +231,10 @@ public class AnySilentContainer implements IAnySilentContainer { @Override public void deactivateContainer(@NotNull final Player bukkitPlayer) { - if (this.serverPlayerGameModeGameType == null) { + if (this.serverPlayerGameModeGameType == null || bukkitPlayer.getGameMode() == GameMode.SPECTATOR) { return; } - InventoryView view = bukkitPlayer.getOpenInventory(); - switch (view.getType()) { - case CHEST: - case ENDER_CHEST: - case SHULKER_BOX: - case BARREL: - break; - default: - return; - } - ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); // Force game mode change without informing plugins or players. diff --git a/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/AnySilentContainer.java b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/AnySilentContainer.java index df53746..9d4be84 100644 --- a/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/AnySilentContainer.java +++ b/internal/v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1/AnySilentContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,12 +50,12 @@ import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.Statistic; import org.bukkit.block.ShulkerBox; import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -231,21 +231,10 @@ public class AnySilentContainer implements IAnySilentContainer { @Override public void deactivateContainer(@NotNull final Player bukkitPlayer) { - if (this.serverPlayerGameModeGameType == null) { + if (this.serverPlayerGameModeGameType == null || bukkitPlayer.getGameMode() == GameMode.SPECTATOR) { return; } - InventoryView view = bukkitPlayer.getOpenInventory(); - switch (view.getType()) { - case CHEST: - case ENDER_CHEST: - case SHULKER_BOX: - case BARREL: - break; - default: - return; - } - ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); // Force game mode change without informing plugins or players. diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java index 3abd77a..37f1325 100644 --- a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java +++ b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,12 +50,12 @@ import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.Statistic; import org.bukkit.block.ShulkerBox; import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -227,21 +227,10 @@ public class AnySilentContainer implements IAnySilentContainer { @Override public void deactivateContainer(@NotNull final Player bukkitPlayer) { - if (this.serverPlayerGameModeGameType == null) { + if (this.serverPlayerGameModeGameType == null || bukkitPlayer.getGameMode() == GameMode.SPECTATOR) { return; } - InventoryView view = bukkitPlayer.getOpenInventory(); - switch (view.getType()) { - case CHEST: - case ENDER_CHEST: - case SHULKER_BOX: - case BARREL: - break; - default: - return; - } - ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); // Force game mode change without informing plugins or players. diff --git a/plugin/src/main/java/com/lishid/openinv/InventoryListener.java b/plugin/src/main/java/com/lishid/openinv/InventoryListener.java index 61a08a4..cf59582 100644 --- a/plugin/src/main/java/com/lishid/openinv/InventoryListener.java +++ b/plugin/src/main/java/com/lishid/openinv/InventoryListener.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.bukkit.GameMode; +import org.bukkit.block.Container; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -53,7 +54,9 @@ record InventoryListener(OpenInv plugin) implements Listener { return; } - if (this.plugin.getSilentContainerStatus(player)) { + if (this.plugin.getSilentContainerStatus(player) + && event.getInventory().getHolder() instanceof Container container + && this.plugin.getAnySilentContainer().isAnySilentContainer(container)) { this.plugin.getAnySilentContainer().deactivateContainer(player); } -- 2.49.1 From c1ffd09d50a19333366302357aa8834a398124e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:20:31 -0500 Subject: [PATCH 111/139] Bump pascalgn/automerge-action from 0.15.5 to 0.15.6 (#126) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3005d7a..e872fd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Merge - uses: pascalgn/automerge-action@v0.15.5 + uses: pascalgn/automerge-action@v0.15.6 env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" MERGE_LABELS: "dependencies" -- 2.49.1 From e15c566b82676e9fc5a689befac4b0d49069db54 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:20:50 -0500 Subject: [PATCH 112/139] Bump maven-compiler-plugin from 3.10.1 to 3.11.0 (#128) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7a303a3..fbde3d2 100644 --- a/pom.xml +++ b/pom.xml @@ -150,7 +150,7 @@ maven-compiler-plugin org.apache.maven.plugins - 3.10.1 + 3.11.0 -- 2.49.1 From e885bf9a65d357d6ebc5de7024c2449a9a6fe83d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:21:01 -0500 Subject: [PATCH 113/139] Bump maven-assembly-plugin from 3.4.2 to 3.5.0 (#127) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fbde3d2..4bad510 100644 --- a/pom.xml +++ b/pom.xml @@ -156,7 +156,7 @@ maven-assembly-plugin org.apache.maven.plugins - 3.4.2 + 3.5.0 -- 2.49.1 From 3d4bed04d5816b58857f3260b8c775a326fb3a51 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 15 Mar 2023 08:13:33 -0400 Subject: [PATCH 114/139] Split up actions (#129) * Refactor conditional dependent jobs into separate actions * Fix incorrect usage of pull_request_target * Fix Dependabot not merging due to labels being absent when issue is created * Prettify supported version listing --- .github/workflows/automerge_dependabot.yml | 26 +++++++++ .github/workflows/ci.yml | 53 +------------------ .github/workflows/draft_release.yml | 44 +++++++++++++++ .../{release.yml => external_release.yml} | 0 scripts/generate_changelog.sh | 4 +- 5 files changed, 73 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/automerge_dependabot.yml create mode 100644 .github/workflows/draft_release.yml rename .github/workflows/{release.yml => external_release.yml} (100%) diff --git a/.github/workflows/automerge_dependabot.yml b/.github/workflows/automerge_dependabot.yml new file mode 100644 index 0000000..94083be --- /dev/null +++ b/.github/workflows/automerge_dependabot.yml @@ -0,0 +1,26 @@ +name: Auto-merge Dependabot PRs + +on: + workflow_run: + workflows: [ "OpenInv CI" ] + types: [ completed ] + +jobs: + merge-dependabot: + if: "github.actor == 'dependabot[bot]' + && github.event.workflow_run.event == 'pull_request' + && github.event.workflow_run.conclusion == 'success'" + runs-on: ubuntu-latest + steps: + - name: Approve + uses: hmarr/auto-approve-action@v3.1.0 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + pull-request-number: "${{ github.event.workflow_run.event.pull_request.id }}" + - name: Merge + uses: pascalgn/automerge-action@v0.15.6 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + MERGE_LABELS: "dependencies,java" + MERGE_METHOD: "squash" + PULL_REQUEST: "${{ github.event.workflow_run.event.pull_request.id }}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e872fd0..62cbfa2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: OpenInv CI on: push: - pull_request_target: + pull_request: jobs: build: @@ -36,54 +36,3 @@ jobs: with: name: api path: ./api/target/openinvapi*.jar - - merge-dependabot: - name: Auto-merge Dependabot PRs - needs: [ build ] - if: "github.event.name == 'pull_request_target' - && github.actor == 'dependabot[bot]' - && contains( github.event.pull_request.labels.*.name, 'java')" - runs-on: ubuntu-latest - steps: - - name: Approve - uses: hmarr/auto-approve-action@v3.1.0 - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" - - name: Merge - uses: pascalgn/automerge-action@v0.15.6 - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - MERGE_LABELS: "dependencies" - MERGE_METHOD: "squash" - - release: - name: Create Github Release - needs: [ build ] - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') - runs-on: ubuntu-latest - steps: - # Fetch all history - used to assemble changelog. - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Set Release Variables - run: bash ./scripts/set_release_env.sh - - - name: Download Artifact - uses: actions/download-artifact@v3 - with: - name: dist - path: dist - - - name: Create Release - id: create-release - uses: softprops/action-gh-release@v0.1.15 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - name: ${{ env.VERSIONED_NAME }} - body: ${{ env.GENERATED_CHANGELOG }} - draft: true - prerelease: false - files: ./dist/OpenInv.jar diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml new file mode 100644 index 0000000..a3ffdcd --- /dev/null +++ b/.github/workflows/draft_release.yml @@ -0,0 +1,44 @@ +name: Draft Github Release + +on: + workflow_run: + workflows: [ "OpenInv CI" ] + types: [ completed ] + +jobs: + draft_release: + if: "github.event.workflow_run.event == 'push' + && github.event.workflow_run.conclusion == 'success' + && startsWith(github.event.workflow_run.event.push.ref, 'refs/tags/')" + runs-on: ubuntu-latest + steps: + # Fetch all history - used to assemble changelog. + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set Release Variables + run: bash ./scripts/set_release_env.sh + + - name: Download Artifact + # Unfortunately actions/download-artifact cannot fetch from other workflow runs. + uses: dawidd6/action-download-artifact@v2.26.0 + with: + name: dist + path: dist + run_id: "${{ github.event.workflow_run.id }}" + run_number: "${{ github.event.workflow_run.run_number }}" + # Searching for a specific run ID that we know was successful, unset 'success' default. + workflow_conclusion: "" + + - name: Create Release + id: create-release + uses: softprops/action-gh-release@v0.1.15 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + name: ${{ env.VERSIONED_NAME }} + body: ${{ env.GENERATED_CHANGELOG }} + draft: true + prerelease: false + files: ./dist/OpenInv.jar diff --git a/.github/workflows/release.yml b/.github/workflows/external_release.yml similarity index 100% rename from .github/workflows/release.yml rename to .github/workflows/external_release.yml diff --git a/scripts/generate_changelog.sh b/scripts/generate_changelog.sh index d2261f1..bc234b9 100644 --- a/scripts/generate_changelog.sh +++ b/scripts/generate_changelog.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (C) 2011-2021 lishid. All rights reserved. +# Copyright (C) 2011-2023 lishid. All rights reserved. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -36,7 +36,7 @@ function get_minecraft_versions() { for version in "${versions[@]}"; do # Append comma if variable is set, then append version - minecraft_versions="${minecraft_versions:+${minecraft_versions},}${version%%-R*}" + minecraft_versions="${minecraft_versions:+${minecraft_versions}, }${version%%-R*}" done echo "${minecraft_versions}" -- 2.49.1 From 0e6acdff362bc0f4f097628165ffd6b7360b8216 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 16 Mar 2023 16:30:43 -0400 Subject: [PATCH 115/139] Update to 1.19.4 (#130) * Improve data load/save slightly * Fix longstanding issue with opening players in deleted worlds on Paper --- .../openinv/internal/v1_18_R2/OpenPlayer.java | 7 ++-- .../internal/v1_18_R2/PlayerDataManager.java | 28 +++++++++---- .../openinv/internal/v1_19_R2/OpenPlayer.java | 4 +- .../internal/v1_19_R2/PlayerDataManager.java | 31 ++++++++++---- internal/{v1_19_R1 => v1_19_R3}/pom.xml | 8 ++-- .../v1_19_R3}/AnySilentContainer.java | 6 +-- .../internal/v1_19_R3}/OpenPlayer.java | 12 +++--- .../internal/v1_19_R3}/PlayerDataManager.java | 40 ++++++++++++------- .../internal/v1_19_R3}/SpecialEnderChest.java | 8 ++-- .../v1_19_R3}/SpecialPlayerInventory.java | 11 ++--- .../com/lishid/openinv/InternalAccessor.java | 3 +- pom.xml | 4 +- 12 files changed, 100 insertions(+), 62 deletions(-) rename internal/{v1_19_R1 => v1_19_R3}/pom.xml (92%) rename internal/{v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1 => v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3}/AnySilentContainer.java (97%) rename internal/{v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1 => v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3}/OpenPlayer.java (89%) rename internal/{v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1 => v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3}/PlayerDataManager.java (88%) rename internal/{v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1 => v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3}/SpecialEnderChest.java (97%) rename internal/{v1_19_R1/src/main/java/com/lishid/openinv/internal/v1_19_R1 => v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3}/SpecialPlayerInventory.java (98%) diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java index 4fdcfc0..10929eb 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ public class OpenPlayer extends CraftPlayer { // See CraftPlayer#loadData CompoundTag loaded = this.server.getHandle().playerIo.load(this.getHandle()); if (loaded != null) { - readExtraData(loaded); + getHandle().readAdditionalSaveData(loaded); } } @@ -49,7 +49,6 @@ public class OpenPlayer extends CraftPlayer { PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; CompoundTag playerData = player.saveWithoutId(new CompoundTag()); - setExtraData(playerData); if (!isOnline()) { // Special case: save old vehicle data @@ -67,7 +66,7 @@ public class OpenPlayer extends CraftPlayer { File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); Util.safeReplaceFile(file1, file, file2); } catch (Exception e) { - LogManager.getLogger().warn("Failed to save player data for {}: {}", player.getName().getString(), e.getMessage()); + LogManager.getLogger().warn("Failed to save player data for {}: {}", player.getScoreboardName(), e); } } diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java index 127e39c..ae02e79 100644 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java +++ b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ import com.lishid.openinv.internal.OpenInventoryView; import com.mojang.authlib.GameProfile; import java.lang.reflect.Field; import java.util.logging.Logger; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.TextComponent; import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; import net.minecraft.server.MinecraftServer; @@ -108,14 +109,25 @@ public class PlayerDataManager implements IPlayerDataManager { e.printStackTrace(); } - // Get the bukkit entity - Player target = entity.getBukkitEntity(); - if (target != null) { - // Load data - target.loadData(); + // Load data. This also reads basic data into the player. + // See CraftPlayer#loadData + CompoundTag loadedData = server.getPlayerList().playerIo.load(entity); + + if (loadedData == null) { + // Exceptions with loading are logged by Mojang. + return null; } - // Return the entity - return target; + + // Also read "extra" data. + entity.readAdditionalSaveData(loadedData); + + if (entity.level == null) { + // Paper: Move player to spawn + entity.spawnIn(null); + } + + // Return the Bukkit entity. + return entity.getBukkitEntity(); } void injectPlayer(ServerPlayer player) throws IllegalAccessException { diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/OpenPlayer.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/OpenPlayer.java index 4dab334..721c7fc 100644 --- a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/OpenPlayer.java +++ b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/OpenPlayer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ public class OpenPlayer extends CraftPlayer { // See CraftPlayer#loadData CompoundTag loaded = this.server.getHandle().playerIo.load(this.getHandle()); if (loaded != null) { - readExtraData(loaded); + getHandle().readAdditionalSaveData(loaded); } } diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/PlayerDataManager.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/PlayerDataManager.java index 4cc6939..423411a 100644 --- a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/PlayerDataManager.java +++ b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/PlayerDataManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ import com.lishid.openinv.internal.OpenInventoryView; import com.mojang.authlib.GameProfile; import java.lang.reflect.Field; import java.util.logging.Logger; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; import net.minecraft.server.MinecraftServer; @@ -100,20 +101,34 @@ public class PlayerDataManager implements IPlayerDataManager { ServerPlayer entity = new ServerPlayer(server, worldServer, profile); + // Stop listening for advancement progression - if this is not cleaned up, loading causes a memory leak. + entity.getAdvancements().stopListening(); + try { injectPlayer(entity); } catch (IllegalAccessException e) { e.printStackTrace(); } - // Get the bukkit entity - Player target = entity.getBukkitEntity(); - if (target != null) { - // Load data - target.loadData(); + // Load data. This also reads basic data into the player. + // See CraftPlayer#loadData + CompoundTag loadedData = server.getPlayerList().playerIo.load(entity); + + if (loadedData == null) { + // Exceptions with loading are logged by Mojang. + return null; } - // Return the entity - return target; + + // Also read "extra" data. + entity.readAdditionalSaveData(loadedData); + + if (entity.level == null) { + // Paper: Move player to spawn + entity.spawnIn(null); + } + + // Return the Bukkit entity. + return entity.getBukkitEntity(); } void injectPlayer(ServerPlayer player) throws IllegalAccessException { diff --git a/internal/v1_19_R1/pom.xml b/internal/v1_19_R3/pom.xml similarity index 92% rename from internal/v1_19_R1/pom.xml rename to internal/v1_19_R3/pom.xml index df50f14..66769d9 100644 --- a/internal/v1_19_R1/pom.xml +++ b/internal/v1_19_R3/pom.xml @@ -1,6 +1,6 @@ maven-dependency-plugin org.apache.maven.plugins - 3.5.0 + 3.6.0 -- 2.49.1 From cc7481fa9ab750c2d40975a39fcc97bf3e6dd862 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 10 Jun 2023 11:06:41 -0400 Subject: [PATCH 126/139] Update to Minecraft 1.20 (#148) --- .../java/com/lishid/openinv/IOpenInv.java | 3 +- .../openinv/internal/IAnySilentContainer.java | 20 +- .../openinv/internal/v1_18_R2/OpenPlayer.java | 73 -- .../internal/v1_18_R2/PlayerDataManager.java | 263 ------ internal/v1_19_R2/pom.xml | 81 -- .../internal/v1_19_R2/AnySilentContainer.java | 266 ------ .../internal/v1_19_R2/SpecialEnderChest.java | 339 -------- .../v1_19_R2/SpecialPlayerInventory.java | 788 ------------------ .../internal/v1_19_R3/AnySilentContainer.java | 28 +- internal/{v1_18_R2 => v1_20_R1}/pom.xml | 8 +- .../v1_20_R1}/AnySilentContainer.java | 45 +- .../internal/v1_20_R1}/OpenPlayer.java | 10 +- .../internal/v1_20_R1}/PlayerDataManager.java | 29 +- .../internal/v1_20_R1}/SpecialEnderChest.java | 8 +- .../v1_20_R1}/SpecialPlayerInventory.java | 15 +- .../com/lishid/openinv/InternalAccessor.java | 1 + .../com/lishid/openinv/InventoryListener.java | 7 +- pom.xml | 4 +- 18 files changed, 64 insertions(+), 1924 deletions(-) delete mode 100644 internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java delete mode 100644 internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java delete mode 100644 internal/v1_19_R2/pom.xml delete mode 100644 internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java delete mode 100644 internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialEnderChest.java delete mode 100644 internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialPlayerInventory.java rename internal/{v1_18_R2 => v1_20_R1}/pom.xml (92%) rename internal/{v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2 => v1_20_R1/src/main/java/com/lishid/openinv/internal/v1_20_R1}/AnySilentContainer.java (82%) rename internal/{v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2 => v1_20_R1/src/main/java/com/lishid/openinv/internal/v1_20_R1}/OpenPlayer.java (89%) rename internal/{v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2 => v1_20_R1/src/main/java/com/lishid/openinv/internal/v1_20_R1}/PlayerDataManager.java (87%) rename internal/{v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2 => v1_20_R1/src/main/java/com/lishid/openinv/internal/v1_20_R1}/SpecialEnderChest.java (97%) rename internal/{v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2 => v1_20_R1/src/main/java/com/lishid/openinv/internal/v1_20_R1}/SpecialPlayerInventory.java (98%) diff --git a/api/src/main/java/com/lishid/openinv/IOpenInv.java b/api/src/main/java/com/lishid/openinv/IOpenInv.java index d71828f..d1e0155 100644 --- a/api/src/main/java/com/lishid/openinv/IOpenInv.java +++ b/api/src/main/java/com/lishid/openinv/IOpenInv.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2022 lishid. All rights reserved. + * Copyright (C) 2011-2023 lishid. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -161,6 +161,7 @@ public interface IOpenInv { * @return the identifier * @throws IllegalStateException if the server version is unsupported */ + @Deprecated(forRemoval = true) default @NotNull String getPlayerID(@NotNull OfflinePlayer offline) { return offline.getUniqueId().toString(); } diff --git a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java index f87ac6b..82b629f 100644 --- a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java +++ b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java @@ -26,6 +26,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Chest; import org.bukkit.entity.Cat; import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; import org.bukkit.util.BoundingBox; import org.jetbrains.annotations.NotNull; @@ -157,10 +158,21 @@ public interface IAnySilentContainer { * @return true if the type is a supported container */ default boolean isAnySilentContainer(@NotNull BlockState blockState) { - return blockState instanceof org.bukkit.block.EnderChest - || blockState instanceof org.bukkit.block.Chest - || blockState instanceof org.bukkit.block.ShulkerBox - || blockState instanceof org.bukkit.block.Barrel; + return blockState instanceof InventoryHolder holder && isAnySilentContainer(holder); + } + + /** + * Check if the given {@link InventoryHolder} is a container which can be unblocked or silenced. + * + * @param holder the potential container + * @return true if the type is a supported container + */ + default boolean isAnySilentContainer(@NotNull InventoryHolder holder) { + return holder instanceof org.bukkit.block.EnderChest + || holder instanceof org.bukkit.block.Chest + || holder instanceof org.bukkit.block.DoubleChest + || holder instanceof org.bukkit.block.ShulkerBox + || holder instanceof org.bukkit.block.Barrel; } } diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java deleted file mode 100644 index 10929eb..0000000 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/OpenPlayer.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2011-2023 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_18_R2; - -import java.io.File; -import net.minecraft.Util; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.storage.PlayerDataStorage; -import org.apache.logging.log4j.LogManager; -import org.bukkit.craftbukkit.v1_18_R2.CraftServer; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; - -public class OpenPlayer extends CraftPlayer { - - public OpenPlayer(CraftServer server, ServerPlayer entity) { - super(server, entity); - } - - @Override - public void loadData() { - // See CraftPlayer#loadData - CompoundTag loaded = this.server.getHandle().playerIo.load(this.getHandle()); - if (loaded != null) { - getHandle().readAdditionalSaveData(loaded); - } - } - - @Override - public void saveData() { - ServerPlayer player = this.getHandle(); - // See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman) - try { - PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; - - CompoundTag playerData = player.saveWithoutId(new CompoundTag()); - - if (!isOnline()) { - // Special case: save old vehicle data - CompoundTag oldData = worldNBTStorage.load(player); - - if (oldData != null && oldData.contains("RootVehicle", 10)) { - // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound) - playerData.put("RootVehicle", oldData.getCompound("RootVehicle")); - } - } - - File file = File.createTempFile(player.getStringUUID() + "-", ".dat", worldNBTStorage.getPlayerDir()); - NbtIo.writeCompressed(playerData, file); - File file1 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat"); - File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); - Util.safeReplaceFile(file1, file, file2); - } catch (Exception e) { - LogManager.getLogger().warn("Failed to save player data for {}: {}", player.getScoreboardName(), e); - } - } - -} diff --git a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java b/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java deleted file mode 100644 index a6145d5..0000000 --- a/internal/v1_18_R2/src/main/java/com/lishid/openinv/internal/v1_18_R2/PlayerDataManager.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2011-2023 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_18_R2; - -import com.lishid.openinv.OpenInv; -import com.lishid.openinv.internal.IPlayerDataManager; -import com.lishid.openinv.internal.ISpecialInventory; -import com.lishid.openinv.internal.OpenInventoryView; -import com.mojang.authlib.GameProfile; -import java.lang.reflect.Field; -import java.util.logging.Logger; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.craftbukkit.v1_18_R2.CraftServer; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_18_R2.event.CraftEventFactory; -import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftContainer; -import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class PlayerDataManager implements IPlayerDataManager { - - private @Nullable Field bukkitEntity; - - public PlayerDataManager() { - try { - bukkitEntity = Entity.class.getDeclaredField("bukkitEntity"); - } catch (NoSuchFieldException e) { - Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); - logger.warning("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded."); - logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); - bukkitEntity = null; - } - } - - public static @NotNull ServerPlayer getHandle(final Player player) { - if (player instanceof CraftPlayer) { - return ((CraftPlayer) player).getHandle(); - } - - Server server = player.getServer(); - ServerPlayer nmsPlayer = null; - - if (server instanceof CraftServer) { - nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getUniqueId()); - } - - if (nmsPlayer == null) { - // Could use reflection to examine fields, but it's honestly not worth the bother. - throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation"); - } - - return nmsPlayer; - } - - @Override - public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { - // Ensure player has data - if (!offline.hasPlayedBefore()) { - return null; - } - - // Create a profile and entity to load the player data - // See net.minecraft.server.PlayerList#attemptLogin - GameProfile profile = new GameProfile(offline.getUniqueId(), - offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel worldServer = server.getLevel(Level.OVERWORLD); - - if (worldServer == null) { - return null; - } - - ServerPlayer entity = new ServerPlayer(server, worldServer, profile); - - // Stop listening for advancement progression - if this is not cleaned up, loading causes a memory leak. - entity.getAdvancements().stopListening(); - - try { - injectPlayer(entity); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - - // Load data. This also reads basic data into the player. - // See CraftPlayer#loadData - CompoundTag loadedData = server.getPlayerList().playerIo.load(entity); - - if (loadedData == null) { - // Exceptions with loading are logged by Mojang. - return null; - } - - // Also read "extra" data. - entity.readAdditionalSaveData(loadedData); - - if (entity.level == null) { - // Paper: Move player to spawn - ServerLevel level = null; - Vec3 position = null; - if (entity.getRespawnDimension() != null) { - level = entity.server.getLevel(entity.getRespawnDimension()); - if (level != null && entity.getRespawnPosition() != null) { - position = net.minecraft.world.entity.player.Player.findRespawnPositionAndUseSpawnBlock(level, entity.getRespawnPosition(), entity.getRespawnAngle(), false, false).orElse(null); - } - } - if (level == null || position == null) { - level = ((CraftWorld) server.server.getWorlds().get(0)).getHandle(); - position = Vec3.atCenterOf(level.getSharedSpawnPos()); - } - entity.level = level; - entity.setPos(position); - } - - // Return the Bukkit entity. - return entity.getBukkitEntity(); - } - - void injectPlayer(ServerPlayer player) throws IllegalAccessException { - if (bukkitEntity == null) { - return; - } - - bukkitEntity.setAccessible(true); - - bukkitEntity.set(player, new OpenPlayer(player.server.server, player)); - } - - @NotNull - @Override - public Player inject(@NotNull Player player) { - try { - ServerPlayer nmsPlayer = getHandle(player); - if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) { - return openPlayer; - } - injectPlayer(nmsPlayer); - return nmsPlayer.getBukkitEntity(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - return player; - } - } - - @Nullable - @Override - public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) { - - ServerPlayer nmsPlayer = getHandle(player); - - if (nmsPlayer.connection == null) { - return null; - } - - InventoryView view = getView(player, inventory); - - if (view == null) { - return player.openInventory(inventory.getBukkitInventory()); - } - - AbstractContainerMenu container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { - @Override - public MenuType getType() { - return getContainers(inventory.getBukkitInventory().getSize()); - } - }; - - container.setTitle(new TextComponent(view.getTitle())); - container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); - - if (container == null) { - return null; - } - - nmsPlayer.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), - new TextComponent(container.getBukkitView().getTitle()))); - nmsPlayer.containerMenu = container; - nmsPlayer.initMenu(container); - - return container.getBukkitView(); - - } - - private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) { - if (inventory instanceof SpecialEnderChest) { - return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest"); - } else if (inventory instanceof SpecialPlayerInventory) { - return new OpenInventoryView(player, inventory, "container.player", "'s Inventory"); - } else { - return null; - } - } - - static @NotNull MenuType getContainers(int inventorySize) { - - return switch (inventorySize) { - case 9 -> MenuType.GENERIC_9x1; - case 18 -> MenuType.GENERIC_9x2; - case 36 -> MenuType.GENERIC_9x4; // PLAYER - case 41, 45 -> MenuType.GENERIC_9x5; - case 54 -> MenuType.GENERIC_9x6; - default -> MenuType.GENERIC_9x3; // Default 27-slot inventory - }; - } - - @Override - public int convertToPlayerSlot(InventoryView view, int rawSlot) { - int topSize = view.getTopInventory().getSize(); - if (topSize <= rawSlot) { - // Slot is not inside special inventory, use Bukkit logic. - return view.convertSlot(rawSlot); - } - - // Main inventory, slots 0-26 -> 9-35 - if (rawSlot < 27) { - return rawSlot + 9; - } - // Hotbar, slots 27-35 -> 0-8 - if (rawSlot < 36) { - return rawSlot - 27; - } - // Armor, slots 36-39 -> 39-36 - if (rawSlot < 40) { - return 36 + (39 - rawSlot); - } - // Off hand - if (rawSlot == 40) { - return 40; - } - // Drop slots, "out of inventory" - return -1; - } - -} diff --git a/internal/v1_19_R2/pom.xml b/internal/v1_19_R2/pom.xml deleted file mode 100644 index 2302185..0000000 --- a/internal/v1_19_R2/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - 4.0.0 - - - openinvparent - com.lishid - ../../pom.xml - 4.3.1-SNAPSHOT - - - openinvadapter1_19_R2 - OpenInvAdapter1_19_R2 - - - 17 - 17 - 1.19.3-R0.1-SNAPSHOT - - - - - org.spigotmc - spigot-api - ${spigot.version} - - - spigot - org.spigotmc - provided - ${spigot.version} - remapped-mojang - - - openinvapi - com.lishid - provided - - - openinvplugincore - com.lishid - - - annotations - org.jetbrains - - - - - - - maven-shade-plugin - - - maven-compiler-plugin - - - net.md-5 - specialsource-maven-plugin - - - - - diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java deleted file mode 100644 index 37f1325..0000000 --- a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/AnySilentContainer.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2011-2023 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_19_R2; - -import com.lishid.openinv.OpenInv; -import com.lishid.openinv.internal.IAnySilentContainer; -import com.lishid.openinv.util.ReflectionHelper; -import java.lang.reflect.Field; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.ServerPlayerGameMode; -import net.minecraft.world.CompoundContainer; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.SimpleMenuProvider; -import net.minecraft.world.entity.monster.Shulker; -import net.minecraft.world.inventory.ChestMenu; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.PlayerEnderChestContainer; -import net.minecraft.world.level.GameType; -import net.minecraft.world.level.block.BarrelBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.ChestBlock; -import net.minecraft.world.level.block.DoubleBlockCombiner; -import net.minecraft.world.level.block.ShulkerBoxBlock; -import net.minecraft.world.level.block.TrappedChestBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.ChestBlockEntity; -import net.minecraft.world.level.block.entity.EnderChestBlockEntity; -import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; -import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.Material; -import org.bukkit.Statistic; -import org.bukkit.block.ShulkerBox; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class AnySilentContainer implements IAnySilentContainer { - - private @Nullable Field serverPlayerGameModeGameType; - - public AnySilentContainer() { - try { - this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("b"); - this.serverPlayerGameModeGameType.setAccessible(true); - } catch (NoSuchFieldException e) { - Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); - logger.warning("ServerPlayerGameMode#gameModeForPlayer's obfuscated name has changed!"); - logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues"); - logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail."); - // N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break. - this.serverPlayerGameModeGameType = ReflectionHelper.grabFieldByType(ServerPlayerGameMode.class, GameType.class); - } catch (SecurityException e) { - Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); - logger.warning("Unable to directly write player game mode! SilentContainer will fail."); - logger.log(Level.WARNING, "Error obtaining GameType field", e); - } - } - - @Override - public boolean isShulkerBlocked(@NotNull ShulkerBox shulkerBox) { - org.bukkit.World bukkitWorld = shulkerBox.getWorld(); - if (!(bukkitWorld instanceof CraftWorld)) { - bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); - } - - if (!(bukkitWorld instanceof CraftWorld craftWorld)) { - Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); - OpenInv.getPlugin(OpenInv.class).getLogger().log(Level.WARNING, exception.getMessage(), exception); - return false; - } - - final ServerLevel world = craftWorld.getHandle(); - final BlockPos blockPosition = new BlockPos(shulkerBox.getX(), shulkerBox.getY(), shulkerBox.getZ()); - final BlockEntity tile = world.getBlockEntity(blockPosition); - - if (!(tile instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) - || shulkerBoxBlockEntity.getAnimationStatus() != ShulkerBoxBlockEntity.AnimationStatus.CLOSED) { - return false; - } - - BlockState blockState = world.getBlockState(blockPosition); - - // See net.minecraft.world.level.block.ShulkerBoxBlock#canOpen - AABB boundingBox = Shulker.getProgressDeltaAabb(blockState.getValue(ShulkerBoxBlock.FACING), 0.0F, 0.5F) - .move(blockPosition) - .deflate(1.0E-6D); - return !world.noCollision(boundingBox); - } - - @Override - public boolean activateContainer( - @NotNull final Player bukkitPlayer, - final boolean silentchest, - @NotNull final org.bukkit.block.Block bukkitBlock) { - - // Silent ender chest is API-only - if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) { - bukkitPlayer.openInventory(bukkitPlayer.getEnderChest()); - bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); - return true; - } - - ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); - - final ServerLevel level = player.getLevel(); - final BlockPos blockPos = new BlockPos(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); - final BlockEntity blockEntity = level.getBlockEntity(blockPos); - - if (blockEntity == null) { - return false; - } - - if (blockEntity instanceof EnderChestBlockEntity enderChestTile) { - // Anychest ender chest. See net.minecraft.world.level.block.EnderChestBlock - PlayerEnderChestContainer enderChest = player.getEnderChestInventory(); - enderChest.setActiveChest(enderChestTile); - player.openMenu(new SimpleMenuProvider((containerCounter, playerInventory, ignored) -> { - MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); - int rows = enderChest.getContainerSize() / 9; - return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); - }, Component.translatable(("container.enderchest")))); - bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); - return true; - } - - if (!(blockEntity instanceof MenuProvider menuProvider)) { - return false; - } - - BlockState blockState = level.getBlockState(blockPos); - Block block = blockState.getBlock(); - - if (block instanceof ChestBlock chestBlock) { - - // boolean flag: do not check if chest is blocked - Optional menuOptional = chestBlock.combine(blockState, level, blockPos, true).apply( - // Combiner is a copy of private ChestBlock.MENU_PROVIDER_COMBINER - new DoubleBlockCombiner.Combiner>() { - @Override - public Optional acceptDouble(ChestBlockEntity localChest1, ChestBlockEntity localChest2) { - CompoundContainer doubleChest = new CompoundContainer(localChest1, localChest2); - return Optional.of(new ChestBlock.DoubleInventory(localChest1, localChest2, doubleChest)); - } - - @Override - public Optional acceptSingle(ChestBlockEntity localChest) { - return Optional.of(localChest); - } - - @Override - public Optional acceptNone() { - return Optional.empty(); - } - }); - - if (menuOptional.isEmpty()) { - OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); - return false; - } - - menuProvider = menuOptional.get(); - - if (block instanceof TrappedChestBlock) { - bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); - } else { - bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED); - } - } - - if (block instanceof ShulkerBoxBlock) { - bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED); - } - - if (block instanceof BarrelBlock) { - bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL); - } - - // AnyChest only - SilentChest not active, container unsupported, or unnecessary. - if (!silentchest || player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) { - player.openMenu(menuProvider); - return true; - } - - // SilentChest requires access to setting players' game mode directly. - if (this.serverPlayerGameModeGameType == null) { - return false; - } - - if (blockEntity instanceof RandomizableContainerBlockEntity lootable) { - if (lootable.lootTable != null) { - OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); - return false; - } - } - - GameType gameType = player.gameMode.getGameModeForPlayer(); - this.forceGameType(player, GameType.SPECTATOR); - player.openMenu(menuProvider); - this.forceGameType(player, gameType); - return true; - } - - @Override - public void deactivateContainer(@NotNull final Player bukkitPlayer) { - if (this.serverPlayerGameModeGameType == null || bukkitPlayer.getGameMode() == GameMode.SPECTATOR) { - return; - } - - ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); - - // Force game mode change without informing plugins or players. - // Regular game mode set calls GameModeChangeEvent and is cancellable. - GameType gameType = player.gameMode.getGameModeForPlayer(); - this.forceGameType(player, GameType.SPECTATOR); - - // ServerPlayer#closeContainer cannot be called without entering an - // infinite loop because this method is called during inventory close. - // From ServerPlayer#closeContainer -> CraftEventFactory#handleInventoryCloseEvent - player.containerMenu.transferTo(player.inventoryMenu, player.getBukkitEntity()); - // From ServerPlayer#closeContainer - player.doCloseContainer(); - // Regular inventory close will handle the rest - packet sending, etc. - - // Revert forced game mode. - this.forceGameType(player, gameType); - } - - private void forceGameType(final ServerPlayer player, final GameType gameMode) { - if (this.serverPlayerGameModeGameType == null) { - // No need to warn repeatedly, error on startup and lack of function should be enough. - return; - } - try { - this.serverPlayerGameModeGameType.setAccessible(true); - this.serverPlayerGameModeGameType.set(player.gameMode, gameMode); - } catch (IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - } - } - -} diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialEnderChest.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialEnderChest.java deleted file mode 100644 index bb5680c..0000000 --- a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialEnderChest.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2011-2022 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_19_R2; - -import com.lishid.openinv.internal.ISpecialEnderChest; -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.ContainerHelper; -import net.minecraft.world.ContainerListener; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.player.StackedContents; -import net.minecraft.world.inventory.PlayerEnderChestContainer; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.EnderChestBlockEntity; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftInventory; -import org.bukkit.entity.HumanEntity; -import org.bukkit.inventory.InventoryHolder; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpecialEnderChest { - - private final CraftInventory inventory; - private ServerPlayer owner; - private NonNullList items; - private boolean playerOnline; - - public SpecialEnderChest(final org.bukkit.entity.Player player, final Boolean online) { - super(PlayerDataManager.getHandle(player)); - this.inventory = new CraftInventory(this); - this.owner = PlayerDataManager.getHandle(player); - this.playerOnline = online; - this.items = this.owner.getEnderChestInventory().items; - } - - @Override - public @NotNull CraftInventory getBukkitInventory() { - return inventory; - } - - @Override - public void setPlayerOffline() { - this.playerOnline = false; - } - - @Override - public void setPlayerOnline(@NotNull final org.bukkit.entity.Player player) { - if (!this.playerOnline) { - try { - this.owner = PlayerDataManager.getHandle(player); - PlayerEnderChestContainer enderChest = owner.getEnderChestInventory(); - for (int i = 0; i < enderChest.getContainerSize(); ++i) { - enderChest.setItem(i, this.items.get(i)); - } - this.items = enderChest.items; - enderChest.transaction.addAll(this.transaction); - } catch (Exception ignored) {} - this.playerOnline = true; - } - } - - @Override - public @NotNull org.bukkit.entity.Player getPlayer() { - return owner.getBukkitEntity(); - } - - @Override - public void setChanged() { - this.owner.getEnderChestInventory().setChanged(); - } - - @Override - public List getContents() { - return this.items; - } - - @Override - public void onOpen(CraftHumanEntity who) { - this.owner.getEnderChestInventory().onOpen(who); - } - - @Override - public void onClose(CraftHumanEntity who) { - this.owner.getEnderChestInventory().onClose(who); - } - - @Override - public List getViewers() { - return this.owner.getEnderChestInventory().getViewers(); - } - - @Override - public boolean stillValid(Player player) { - return true; - } - - @Override - public void setActiveChest(EnderChestBlockEntity enderChest) { - this.owner.getEnderChestInventory().setActiveChest(enderChest); - } - - @Override - public boolean isActiveChest(EnderChestBlockEntity enderChest) { - return this.owner.getEnderChestInventory().isActiveChest(enderChest); - } - - @Override - public int getMaxStackSize() { - return this.owner.getEnderChestInventory().getMaxStackSize(); - } - - @Override - public void setMaxStackSize(int i) { - this.owner.getEnderChestInventory().setMaxStackSize(i); - } - - @Override - public InventoryHolder getOwner() { - return this.owner.getEnderChestInventory().getOwner(); - } - - @Override - public @Nullable Location getLocation() { - return null; - } - - @Override - public void addListener(ContainerListener listener) { - this.owner.getEnderChestInventory().addListener(listener); - } - - @Override - public void removeListener(ContainerListener listener) { - this.owner.getEnderChestInventory().removeListener(listener); - } - - @Override - public ItemStack getItem(int i) { - return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.EMPTY; - } - - @Override - public ItemStack removeItem(int i, int j) { - ItemStack itemstack = ContainerHelper.removeItem(this.items, i, j); - if (!itemstack.isEmpty()) { - this.setChanged(); - } - - return itemstack; - } - - @Override - public ItemStack addItem(ItemStack itemstack) { - ItemStack localItem = itemstack.copy(); - this.moveItemToOccupiedSlotsWithSameType(localItem); - if (localItem.isEmpty()) { - return ItemStack.EMPTY; - } else { - this.moveItemToEmptySlots(localItem); - return localItem.isEmpty() ? ItemStack.EMPTY : localItem; - } - } - - @Override - public boolean canAddItem(ItemStack itemstack) { - for (ItemStack itemstack1 : this.items) { - if (itemstack1.isEmpty() || ItemStack.isSameItemSameTags(itemstack1, itemstack) && itemstack1.getCount() < itemstack1.getMaxStackSize()) { - return true; - } - } - - return false; - } - - private void moveItemToEmptySlots(ItemStack itemstack) { - for(int i = 0; i < this.getContainerSize(); ++i) { - ItemStack localItem = this.getItem(i); - if (localItem.isEmpty()) { - this.setItem(i, itemstack.copy()); - itemstack.setCount(0); - return; - } - } - } - - private void moveItemToOccupiedSlotsWithSameType(ItemStack itemstack) { - for(int i = 0; i < this.getContainerSize(); ++i) { - ItemStack localItem = this.getItem(i); - if (ItemStack.isSameItemSameTags(localItem, itemstack)) { - this.moveItemsBetweenStacks(itemstack, localItem); - if (itemstack.isEmpty()) { - return; - } - } - } - } - - private void moveItemsBetweenStacks(ItemStack itemstack, ItemStack itemstack1) { - int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize()); - int j = Math.min(itemstack.getCount(), i - itemstack1.getCount()); - if (j > 0) { - itemstack1.grow(j); - itemstack.shrink(j); - this.setChanged(); - } - } - - @Override - public ItemStack removeItemNoUpdate(int i) { - ItemStack itemstack = this.items.get(i); - if (itemstack.isEmpty()) { - return ItemStack.EMPTY; - } else { - this.items.set(i, ItemStack.EMPTY); - return itemstack; - } - } - - @Override - public void setItem(int i, ItemStack itemstack) { - this.items.set(i, itemstack); - if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { - itemstack.setCount(this.getMaxStackSize()); - } - - this.setChanged(); - } - - @Override - public int getContainerSize() { - return this.owner.getEnderChestInventory().getContainerSize(); - } - - @Override - public boolean isEmpty() { - return this.items.stream().allMatch(ItemStack::isEmpty); - } - - @Override - public void startOpen(Player player) { - } - - @Override - public void stopOpen(Player player) { - } - - @Override - public boolean canPlaceItem(int i, ItemStack itemstack) { - return true; - } - - @Override - public void clearContent() { - this.items.clear(); - this.setChanged(); - } - - @Override - public void fillStackedContents(StackedContents stackedContents) { - for (ItemStack itemstack : this.items) { - stackedContents.accountStack(itemstack); - } - - } - - @Override - public List removeAllItems() { - List list = this.items.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList()); - this.clearContent(); - return list; - } - - @Override - public ItemStack removeItemType(Item item, int i) { - ItemStack itemstack = new ItemStack(item, 0); - - for(int j = this.getContainerSize() - 1; j >= 0; --j) { - ItemStack localItem = this.getItem(j); - if (localItem.getItem().equals(item)) { - int k = i - itemstack.getCount(); - ItemStack splitItem = localItem.split(k); - itemstack.grow(splitItem.getCount()); - if (itemstack.getCount() == i) { - break; - } - } - } - - if (!itemstack.isEmpty()) { - this.setChanged(); - } - - return itemstack; - } - - @Override - public String toString() { - return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).toList().toString(); - } - - @Override - public void fromTag(ListTag listTag) { - for (int i = 0; i < this.getContainerSize(); ++i) { - this.setItem(i, ItemStack.EMPTY); - } - - for (int i = 0; i < listTag.size(); ++i) { - CompoundTag compoundTag = listTag.getCompound(i); - int j = compoundTag.getByte("Slot") & 255; - if (j < this.getContainerSize()) { - this.setItem(j, ItemStack.of(compoundTag)); - } - } - - } - -} diff --git a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialPlayerInventory.java b/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialPlayerInventory.java deleted file mode 100644 index ef0cca6..0000000 --- a/internal/v1_19_R2/src/main/java/com/lishid/openinv/internal/v1_19_R2/SpecialPlayerInventory.java +++ /dev/null @@ -1,788 +0,0 @@ -/* - * Copyright (C) 2011-2022 lishid. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lishid.openinv.internal.v1_19_R2; - -import com.google.common.collect.ImmutableList; -import com.lishid.openinv.internal.ISpecialPlayerInventory; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import net.minecraft.CrashReport; -import net.minecraft.CrashReportCategory; -import net.minecraft.ReportedException; -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.tags.TagKey; -import net.minecraft.world.Container; -import net.minecraft.world.ContainerHelper; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.player.StackedContents; -import net.minecraft.world.item.ArmorItem; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftInventory; -import org.bukkit.entity.HumanEntity; -import org.bukkit.inventory.InventoryHolder; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerInventory { - - private final CraftInventory inventory; - private boolean playerOnline; - private Player player; - private NonNullList items; - private NonNullList armor; - private NonNullList offhand; - private List> compartments; - - public SpecialPlayerInventory(@NotNull org.bukkit.entity.Player bukkitPlayer, @NotNull Boolean online) { - super(PlayerDataManager.getHandle(bukkitPlayer)); - this.inventory = new CraftInventory(this); - this.playerOnline = online; - this.player = super.player; - this.selected = player.getInventory().selected; - this.items = this.player.getInventory().items; - this.armor = this.player.getInventory().armor; - this.offhand = this.player.getInventory().offhand; - this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); - } - - @Override - public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) { - if (!this.playerOnline) { - Player entityPlayer = PlayerDataManager.getHandle(player); - entityPlayer.getInventory().transaction.addAll(this.transaction); - this.player = entityPlayer; - for (int i = 0; i < getContainerSize(); ++i) { - this.player.getInventory().setItem(i, getRawItem(i)); - } - this.player.getInventory().selected = this.selected; - this.items = this.player.getInventory().items; - this.armor = this.player.getInventory().armor; - this.offhand = this.player.getInventory().offhand; - this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); - this.playerOnline = true; - } - } - - @Override - public @NotNull CraftInventory getBukkitInventory() { - return this.inventory; - } - - @Override - public void setPlayerOffline() { - this.playerOnline = false; - } - - @Override - public @NotNull HumanEntity getPlayer() { - return this.player.getBukkitEntity(); - } - - private @NotNull ItemStack getRawItem(int i) { - if (i < 0) { - return ItemStack.EMPTY; - } - - NonNullList list; - for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { - list = iterator.next(); - if (i < list.size()) { - return list.get(i); - } - } - - return ItemStack.EMPTY; - } - - private void setRawItem(int i, @NotNull ItemStack itemStack) { - if (i < 0) { - return; - } - - NonNullList list; - for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { - list = iterator.next(); - if (i < list.size()) { - list.set(i, itemStack); - } - } - } - - private record IndexedCompartment(@Nullable NonNullList compartment, int index) {} - - private @NotNull SpecialPlayerInventory.IndexedCompartment getIndexedContent(int index) { - if (index < items.size()) { - return new IndexedCompartment(items, getReversedItemSlotNum(index)); - } - - index -= items.size(); - - if (index < armor.size()) { - return new IndexedCompartment(armor, getReversedArmorSlotNum(index)); - } - - index -= armor.size(); - - if (index < offhand.size()) { - return new IndexedCompartment(offhand, index); - } - - index -= offhand.size(); - - return new IndexedCompartment(null, index); - } - - private int getReversedArmorSlotNum(final int i) { - if (i == 0) { - return 3; - } - if (i == 1) { - return 2; - } - if (i == 2) { - return 1; - } - if (i == 3) { - return 0; - } - return i; - } - - private int getReversedItemSlotNum(final int i) { - if (i >= 27) { - return i - 27; - } - return i + 9; - } - - private boolean contains(Predicate predicate) { - return this.compartments.stream().flatMap(NonNullList::stream).anyMatch(predicate); - } - - @Override - public List getArmorContents() { - return this.armor; - } - - @Override - public void onOpen(CraftHumanEntity who) { - this.player.getInventory().onOpen(who); - } - - @Override - public void onClose(CraftHumanEntity who) { - this.player.getInventory().onClose(who); - } - - @Override - public List getViewers() { - return this.player.getInventory().getViewers(); - } - - @Override - public InventoryHolder getOwner() { - return this.player.getBukkitEntity(); - } - - @Override - public int getMaxStackSize() { - return this.player.getInventory().getMaxStackSize(); - } - - @Override - public void setMaxStackSize(int size) { - this.player.getInventory().setMaxStackSize(size); - } - - @Override - public Location getLocation() { - return this.player.getBukkitEntity().getLocation(); - } - - @Override - public boolean hasCustomName() { - return false; - } - - @Override - public List getContents() { - return this.compartments.stream().flatMap(Collection::stream).collect(Collectors.toList()); - } - - @Override - public ItemStack getSelected() { - return isHotbarSlot(this.selected) ? this.items.get(this.selected) : ItemStack.EMPTY; - } - - private boolean hasRemainingSpaceForItem(ItemStack itemstack, ItemStack itemstack1) { - return !itemstack.isEmpty() && ItemStack.isSameItemSameTags(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); - } - - @Override - public int canHold(ItemStack itemstack) { - int remains = itemstack.getCount(); - - for (int i = 0; i < this.items.size(); ++i) { - ItemStack itemstack1 = this.getRawItem(i); - if (itemstack1.isEmpty()) { - return itemstack.getCount(); - } - - if (this.hasRemainingSpaceForItem(itemstack1, itemstack)) { - remains -= (itemstack1.getMaxStackSize() < this.getMaxStackSize() ? itemstack1.getMaxStackSize() : this.getMaxStackSize()) - itemstack1.getCount(); - } - - if (remains <= 0) { - return itemstack.getCount(); - } - } - - ItemStack offhandItemStack = this.getRawItem(this.items.size() + this.armor.size()); - if (this.hasRemainingSpaceForItem(offhandItemStack, itemstack)) { - remains -= (offhandItemStack.getMaxStackSize() < this.getMaxStackSize() ? offhandItemStack.getMaxStackSize() : this.getMaxStackSize()) - offhandItemStack.getCount(); - } - - return remains <= 0 ? itemstack.getCount() : itemstack.getCount() - remains; - } - - @Override - public int getFreeSlot() { - for(int i = 0; i < this.items.size(); ++i) { - if (this.items.get(i).isEmpty()) { - return i; - } - } - - return -1; - } - - @Override - public void setPickedItem(ItemStack itemstack) { - int i = this.findSlotMatchingItem(itemstack); - if (isHotbarSlot(i)) { - this.selected = i; - } else if (i == -1) { - this.selected = this.getSuitableHotbarSlot(); - if (!this.items.get(this.selected).isEmpty()) { - int j = this.getFreeSlot(); - if (j != -1) { - this.items.set(j, this.items.get(this.selected)); - } - } - - this.items.set(this.selected, itemstack); - } else { - this.pickSlot(i); - } - - } - - @Override - public void pickSlot(int i) { - this.selected = this.getSuitableHotbarSlot(); - ItemStack itemstack = this.items.get(this.selected); - this.items.set(this.selected, this.items.get(i)); - this.items.set(i, itemstack); - } - - @Override - public int findSlotMatchingItem(ItemStack itemstack) { - for(int i = 0; i < this.items.size(); ++i) { - if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemstack, this.items.get(i))) { - return i; - } - } - - return -1; - } - - @Override - public int findSlotMatchingUnusedItem(ItemStack itemStack) { - for(int i = 0; i < this.items.size(); ++i) { - ItemStack localItem = this.items.get(i); - if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemStack, this.items.get(i)) && !this.items.get(i).isDamaged() && !localItem.isEnchanted() && !localItem.hasCustomHoverName()) { - return i; - } - } - - return -1; - } - - @Override - public int getSuitableHotbarSlot() { - int i; - int j; - for(j = 0; j < 9; ++j) { - i = (this.selected + j) % 9; - if (this.items.get(i).isEmpty()) { - return i; - } - } - - for(j = 0; j < 9; ++j) { - i = (this.selected + j) % 9; - if (!this.items.get(i).isEnchanted()) { - return i; - } - } - - return this.selected; - } - - @Override - public void swapPaint(double d0) { - if (d0 > 0.0D) { - d0 = 1.0D; - } - - if (d0 < 0.0D) { - d0 = -1.0D; - } - - this.selected = (int) (this.selected - d0); - - while (this.selected < 0) { - this.selected += 9; - } - - while(this.selected >= 9) { - this.selected -= 9; - } - } - - @Override - public int clearOrCountMatchingItems(Predicate predicate, int i, Container container) { - byte b0 = 0; - boolean flag = i == 0; - int j = b0 + ContainerHelper.clearOrCountMatchingItems(this, predicate, i - b0, flag); - j += ContainerHelper.clearOrCountMatchingItems(container, predicate, i - j, flag); - ItemStack itemstack = this.player.containerMenu.getCarried(); - j += ContainerHelper.clearOrCountMatchingItems(itemstack, predicate, i - j, flag); - if (itemstack.isEmpty()) { - this.player.containerMenu.setCarried(ItemStack.EMPTY); - } - - return j; - } - - private int addResource(ItemStack itemstack) { - int i = this.getSlotWithRemainingSpace(itemstack); - if (i == -1) { - i = this.getFreeSlot(); - } - - return i == -1 ? itemstack.getCount() : this.addResource(i, itemstack); - } - - private int addResource(int i, ItemStack itemstack) { - Item item = itemstack.getItem(); - int j = itemstack.getCount(); - ItemStack localItemStack = this.getRawItem(i); - if (localItemStack.isEmpty()) { - localItemStack = new ItemStack(item, 0); - if (itemstack.hasTag()) { - // hasTag ensures tag not null - //noinspection ConstantConditions - localItemStack.setTag(itemstack.getTag().copy()); - } - - this.setRawItem(i, localItemStack); - } - - int k = Math.min(j, localItemStack.getMaxStackSize() - localItemStack.getCount()); - - if (k > this.getMaxStackSize() - localItemStack.getCount()) { - k = this.getMaxStackSize() - localItemStack.getCount(); - } - - if (k != 0) { - j -= k; - localItemStack.grow(k); - localItemStack.setPopTime(5); - } - - return j; - } - - @Override - public int getSlotWithRemainingSpace(ItemStack itemstack) { - if (this.hasRemainingSpaceForItem(this.getRawItem(this.selected), itemstack)) { - return this.selected; - } else if (this.hasRemainingSpaceForItem(this.getRawItem(40), itemstack)) { - return 40; - } else { - for(int i = 0; i < this.items.size(); ++i) { - if (this.hasRemainingSpaceForItem(this.items.get(i), itemstack)) { - return i; - } - } - - return -1; - } - } - - @Override - public void tick() { - for (NonNullList compartment : this.compartments) { - for (int i = 0; i < compartment.size(); ++i) { - if (!compartment.get(i).isEmpty()) { - compartment.get(i).inventoryTick(this.player.level, this.player, i, this.selected == i); - } - } - } - - } - - @Override - public boolean add(ItemStack itemStack) { - return this.add(-1, itemStack); - } - - @Override - public boolean add(int i, ItemStack itemStack) { - if (itemStack.isEmpty()) { - return false; - } else { - try { - if (itemStack.isDamaged()) { - if (i == -1) { - i = this.getFreeSlot(); - } - - if (i >= 0) { - this.items.set(i, itemStack.copy()); - this.items.get(i).setPopTime(5); - itemStack.setCount(0); - return true; - } else if (this.player.getAbilities().instabuild) { - itemStack.setCount(0); - return true; - } else { - return false; - } - } else { - int j; - do { - j = itemStack.getCount(); - if (i == -1) { - itemStack.setCount(this.addResource(itemStack)); - } else { - itemStack.setCount(this.addResource(i, itemStack)); - } - } while(!itemStack.isEmpty() && itemStack.getCount() < j); - - if (itemStack.getCount() == j && this.player.getAbilities().instabuild) { - itemStack.setCount(0); - return true; - } else { - return itemStack.getCount() < j; - } - } - } catch (Throwable var6) { - CrashReport crashReport = CrashReport.forThrowable(var6, "Adding item to inventory"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Item being added"); - crashReportCategory.setDetail("Item ID", Item.getId(itemStack.getItem())); - crashReportCategory.setDetail("Item data", itemStack.getDamageValue()); - crashReportCategory.setDetail("Item name", () -> itemStack.getHoverName().getString()); - throw new ReportedException(crashReport); - } - } - } - - @Override - public void placeItemBackInInventory(ItemStack itemStack) { - this.placeItemBackInInventory(itemStack, true); - } - - @Override - public void placeItemBackInInventory(ItemStack itemStack, boolean flag) { - while(true) { - if (!itemStack.isEmpty()) { - int i = this.getSlotWithRemainingSpace(itemStack); - if (i == -1) { - i = this.getFreeSlot(); - } - - if (i != -1) { - int j = itemStack.getMaxStackSize() - this.getRawItem(i).getCount(); - if (this.add(i, itemStack.split(j)) && flag && this.player instanceof ServerPlayer) { - ((ServerPlayer)this.player).connection.send(new ClientboundContainerSetSlotPacket(-2, 0, i, this.getRawItem(i))); - } - continue; - } - - this.player.drop(itemStack, false); - } - - return; - } - } - - @Override - public ItemStack removeItem(int rawIndex, final int j) { - IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); - - if (indexedCompartment.compartment() == null - || indexedCompartment.compartment().get(indexedCompartment.index()).isEmpty()) { - return ItemStack.EMPTY; - } - - return ContainerHelper.removeItem(indexedCompartment.compartment(), indexedCompartment.index(), j); - } - - @Override - public void removeItem(ItemStack itemStack) { - for (NonNullList compartment : this.compartments) { - for (int i = 0; i < compartment.size(); ++i) { - if (compartment.get(i) == itemStack) { - compartment.set(i, ItemStack.EMPTY); - break; - } - } - } - } - - @Override - public ItemStack removeItemNoUpdate(int rawIndex) { - IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); - - if (indexedCompartment.compartment() == null) { - return ItemStack.EMPTY; - } - - ItemStack removed = indexedCompartment.compartment().set(indexedCompartment.index(), ItemStack.EMPTY); - - if (removed.isEmpty()) { - return ItemStack.EMPTY; - } - - return removed; - } - - @Override - public void setItem(int rawIndex, final ItemStack itemStack) { - IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); - - if (indexedCompartment.compartment() == null) { - this.player.drop(itemStack, true); - return; - } - - indexedCompartment.compartment().set(indexedCompartment.index(), itemStack); - } - - @Override - public float getDestroySpeed(BlockState blockState) { - return this.items.get(this.selected).getDestroySpeed(blockState); - } - - @Override - public ListTag save(ListTag listTag) { - for (int i = 0; i < this.items.size(); ++i) { - if (!this.items.get(i).isEmpty()) { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putByte("Slot", (byte)i); - this.items.get(i).save(compoundTag); - listTag.add(compoundTag); - } - } - - for (int i = 0; i < this.armor.size(); ++i) { - if (!this.armor.get(i).isEmpty()) { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putByte("Slot", (byte)(i + 100)); - this.armor.get(i).save(compoundTag); - listTag.add(compoundTag); - } - } - - for (int i = 0; i < this.offhand.size(); ++i) { - if (!this.offhand.get(i).isEmpty()) { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putByte("Slot", (byte)(i + 150)); - this.offhand.get(i).save(compoundTag); - listTag.add(compoundTag); - } - } - - return listTag; - } - - @Override - public void load(ListTag listTag) { - this.items.clear(); - this.armor.clear(); - this.offhand.clear(); - - for(int i = 0; i < listTag.size(); ++i) { - CompoundTag compoundTag = listTag.getCompound(i); - int j = compoundTag.getByte("Slot") & 255; - ItemStack itemstack = ItemStack.of(compoundTag); - if (!itemstack.isEmpty()) { - if (j < this.items.size()) { - this.items.set(j, itemstack); - } else if (j >= 100 && j < this.armor.size() + 100) { - this.armor.set(j - 100, itemstack); - } else if (j >= 150 && j < this.offhand.size() + 150) { - this.offhand.set(j - 150, itemstack); - } - } - } - - } - - @Override - public int getContainerSize() { - return 45; - } - - @Override - public boolean isEmpty() { - return !contains(itemStack -> !itemStack.isEmpty()); - } - - @Override - public ItemStack getItem(int rawIndex) { - IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); - - if (indexedCompartment.compartment() == null) { - return ItemStack.EMPTY; - } - - return indexedCompartment.compartment().get(indexedCompartment.index()); - } - - @Override - public Component getName() { - return this.player.getName(); - } - - @Override - public ItemStack getArmor(int index) { - return this.armor.get(index); - } - - @Override - public void hurtArmor(DamageSource damagesource, float damage, int[] armorIndices) { - if (damage > 0.0F) { - damage /= 4.0F; - if (damage < 1.0F) { - damage = 1.0F; - } - - for (int index : armorIndices) { - ItemStack itemstack = this.armor.get(index); - if ((!damagesource.isFire() || !itemstack.getItem().isFireResistant()) && itemstack.getItem() instanceof ArmorItem) { - itemstack.hurtAndBreak((int) damage, this.player, localPlayer -> localPlayer.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index))); - } - } - } - } - - @Override - public void dropAll() { - for (NonNullList compartment : this.compartments) { - for (int i = 0; i < compartment.size(); ++i) { - ItemStack itemstack = compartment.get(i); - if (!itemstack.isEmpty()) { - this.player.drop(itemstack, true, false); - compartment.set(i, ItemStack.EMPTY); - } - } - } - } - - @Override - public void setChanged() { - super.setChanged(); - } - - @Override - public int getTimesChanged() { - return super.getTimesChanged(); - } - - @Override - public boolean stillValid(Player player) { - return true; - } - - @Override - public boolean contains(ItemStack itemstack) { - return contains(itemStack -> itemStack.isEmpty() && itemStack.sameItem(itemstack)); - } - - @Override - public boolean contains(TagKey tagKey) { - - return contains(itemStack -> !itemStack.isEmpty() && itemStack.is(tagKey)); - } - - @Override - public void replaceWith(Inventory inventory) { - Function getter; - - if (inventory instanceof SpecialPlayerInventory specialPlayerInventory) { - getter = specialPlayerInventory::getRawItem; - } else { - getter = inventory::getItem; - } - - for(int i = 0; i < this.getContainerSize(); ++i) { - this.setRawItem(i, getter.apply(i)); - } - - this.selected = inventory.selected; - } - - @Override - public void clearContent() { - for (NonNullList compartment : this.compartments) { - compartment.clear(); - } - } - - @Override - public void fillStackedContents(StackedContents stackedContents) { - for (ItemStack itemstack : this.items) { - stackedContents.accountSimpleStack(itemstack); - } - } - - @Override - public ItemStack removeFromSelected(boolean dropWholeStack) { - ItemStack itemstack = this.getSelected(); - return itemstack.isEmpty() ? ItemStack.EMPTY : this.removeItem(this.selected, dropWholeStack ? itemstack.getCount() : 1); - } - -} diff --git a/internal/v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3/AnySilentContainer.java b/internal/v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3/AnySilentContainer.java index 93e8d03..b78bb39 100644 --- a/internal/v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3/AnySilentContainer.java +++ b/internal/v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3/AnySilentContainer.java @@ -20,7 +20,6 @@ import com.lishid.openinv.OpenInv; import com.lishid.openinv.internal.IAnySilentContainer; import com.lishid.openinv.util.ReflectionHelper; import java.lang.reflect.Field; -import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; import net.minecraft.core.BlockPos; @@ -28,7 +27,6 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayerGameMode; -import net.minecraft.world.CompoundContainer; import net.minecraft.world.MenuProvider; import net.minecraft.world.SimpleMenuProvider; import net.minecraft.world.entity.monster.Shulker; @@ -39,11 +37,9 @@ import net.minecraft.world.level.GameType; import net.minecraft.world.level.block.BarrelBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.ChestBlock; -import net.minecraft.world.level.block.DoubleBlockCombiner; import net.minecraft.world.level.block.ShulkerBoxBlock; import net.minecraft.world.level.block.TrappedChestBlock; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.ChestBlockEntity; import net.minecraft.world.level.block.entity.EnderChestBlockEntity; import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; @@ -160,33 +156,13 @@ public class AnySilentContainer implements IAnySilentContainer { if (block instanceof ChestBlock chestBlock) { // boolean flag: do not check if chest is blocked - Optional menuOptional = chestBlock.combine(blockState, level, blockPos, true).apply( - // Combiner is a copy of private ChestBlock.MENU_PROVIDER_COMBINER - new DoubleBlockCombiner.Combiner>() { - @Override - public Optional acceptDouble(ChestBlockEntity localChest1, ChestBlockEntity localChest2) { - CompoundContainer doubleChest = new CompoundContainer(localChest1, localChest2); - return Optional.of(new ChestBlock.DoubleInventory(localChest1, localChest2, doubleChest)); - } + menuProvider = chestBlock.getMenuProvider(blockState, level, blockPos, true); - @Override - public Optional acceptSingle(ChestBlockEntity localChest) { - return Optional.of(localChest); - } - - @Override - public Optional acceptNone() { - return Optional.empty(); - } - }); - - if (menuOptional.isEmpty()) { + if (menuProvider == null) { OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); return false; } - menuProvider = menuOptional.get(); - if (block instanceof TrappedChestBlock) { bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); } else { diff --git a/internal/v1_18_R2/pom.xml b/internal/v1_20_R1/pom.xml similarity index 92% rename from internal/v1_18_R2/pom.xml rename to internal/v1_20_R1/pom.xml index 7569fc0..b7e1d54 100644 --- a/internal/v1_18_R2/pom.xml +++ b/internal/v1_20_R1/pom.xml @@ -1,6 +1,6 @@ unknown @@ -39,9 +40,8 @@ api plugin - internal/v1_18_R2 - internal/v1_19_R2 internal/v1_19_R3 + internal/v1_20_R1 assembly -- 2.49.1 From 5a7d1399b56d9f38ead566d62b82e364e3f1d14b Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 10 Jun 2023 11:09:30 -0400 Subject: [PATCH 127/139] Bump version to 4.3.1 for release --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_19_R3/pom.xml | 2 +- internal/v1_20_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index c2e74f7..e474913 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.3.1-SNAPSHOT + 4.3.1 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 2a0a0cf..4a8cdbc 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.3.1-SNAPSHOT + 4.3.1 openinvassembly diff --git a/internal/v1_19_R3/pom.xml b/internal/v1_19_R3/pom.xml index 4413745..6e9a6c1 100644 --- a/internal/v1_19_R3/pom.xml +++ b/internal/v1_19_R3/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.3.1-SNAPSHOT + 4.3.1 openinvadapter1_19_R3 diff --git a/internal/v1_20_R1/pom.xml b/internal/v1_20_R1/pom.xml index b7e1d54..0b3600f 100644 --- a/internal/v1_20_R1/pom.xml +++ b/internal/v1_20_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.3.1-SNAPSHOT + 4.3.1 openinvadapter1_20_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index dd31501..0b757e3 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.3.1-SNAPSHOT + 4.3.1 openinvplugincore diff --git a/pom.xml b/pom.xml index 2347d3e..d2384bf 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.3.1-SNAPSHOT + 4.3.1 pom @@ -84,13 +84,13 @@ openinvapi com.lishid compile - 4.3.1-SNAPSHOT + 4.3.1 openinvplugincore com.lishid compile - 4.3.1-SNAPSHOT + 4.3.1 com.lishid -- 2.49.1 From 9ec7bebecbb0967bb39efaff6c6098f2aa5f125a Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sat, 10 Jun 2023 11:09:43 -0400 Subject: [PATCH 128/139] Bump version to 4.3.2-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_19_R3/pom.xml | 2 +- internal/v1_20_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index e474913..fe0552d 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.3.1 + 4.3.2-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 4a8cdbc..54f94a1 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.3.1 + 4.3.2-SNAPSHOT openinvassembly diff --git a/internal/v1_19_R3/pom.xml b/internal/v1_19_R3/pom.xml index 6e9a6c1..8e940b6 100644 --- a/internal/v1_19_R3/pom.xml +++ b/internal/v1_19_R3/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.3.1 + 4.3.2-SNAPSHOT openinvadapter1_19_R3 diff --git a/internal/v1_20_R1/pom.xml b/internal/v1_20_R1/pom.xml index 0b3600f..cabff6b 100644 --- a/internal/v1_20_R1/pom.xml +++ b/internal/v1_20_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.3.1 + 4.3.2-SNAPSHOT openinvadapter1_20_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index 0b757e3..77fb5af 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.3.1 + 4.3.2-SNAPSHOT openinvplugincore diff --git a/pom.xml b/pom.xml index d2384bf..f910362 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.3.1 + 4.3.2-SNAPSHOT pom @@ -84,13 +84,13 @@ openinvapi com.lishid compile - 4.3.1 + 4.3.2-SNAPSHOT openinvplugincore com.lishid compile - 4.3.1 + 4.3.2-SNAPSHOT com.lishid -- 2.49.1 From 922586c92532ccfcda41c974fd8bbf10607b0f8c Mon Sep 17 00:00:00 2001 From: XPYEX <50171612+0XPYEX0@users.noreply.github.com> Date: Sat, 17 Jun 2023 19:35:21 +0800 Subject: [PATCH 129/139] Improve support for non-UTF-8 systems (#151) --- .../java/com/lishid/openinv/util/lang/LanguageManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/lishid/openinv/util/lang/LanguageManager.java b/plugin/src/main/java/com/lishid/openinv/util/lang/LanguageManager.java index 239031e..4438977 100644 --- a/plugin/src/main/java/com/lishid/openinv/util/lang/LanguageManager.java +++ b/plugin/src/main/java/com/lishid/openinv/util/lang/LanguageManager.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -89,7 +90,7 @@ public class LanguageManager { if (resourceStream == null) { localeConfigDefaults = new YamlConfiguration(); } else { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceStream))) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceStream, StandardCharsets.UTF_8))) { localeConfigDefaults = YamlConfiguration.loadConfiguration(reader); } catch (IOException e) { plugin.getLogger().log(Level.WARNING, e, () -> "[LanguageManager] Unable to load resource " + locale + ".yml"); -- 2.49.1 From 57caf855002c5534f9e3b4bb64168f50d8f7f3d1 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Sun, 10 Sep 2023 11:23:49 -0400 Subject: [PATCH 130/139] Update Spigot --- internal/v1_20_R1/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/v1_20_R1/pom.xml b/internal/v1_20_R1/pom.xml index cabff6b..5f004c5 100644 --- a/internal/v1_20_R1/pom.xml +++ b/internal/v1_20_R1/pom.xml @@ -32,7 +32,7 @@ 17 17 - 1.20-R0.1-SNAPSHOT + 1.20.1-R0.1-SNAPSHOT -- 2.49.1 From 1bebdb56028132151b921cf276c4977278ea8719 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 22 Sep 2023 23:06:05 -0400 Subject: [PATCH 131/139] Add OpenPlayerSaveEvent Closes #156 --- api/pom.xml | 2 +- .../openinv/event/OpenPlayerSaveEvent.java | 74 +++++++++++++++++++ assembly/pom.xml | 2 +- internal/v1_19_R3/pom.xml | 2 +- internal/v1_20_R1/pom.xml | 2 +- plugin/pom.xml | 2 +- .../com/lishid/openinv/InventoryListener.java | 4 +- .../main/java/com/lishid/openinv/OpenInv.java | 20 +++-- pom.xml | 6 +- 9 files changed, 98 insertions(+), 16 deletions(-) create mode 100644 api/src/main/java/com/lishid/openinv/event/OpenPlayerSaveEvent.java diff --git a/api/pom.xml b/api/pom.xml index fe0552d..eeee22d 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.3.2-SNAPSHOT + 4.4.0-SNAPSHOT openinvapi diff --git a/api/src/main/java/com/lishid/openinv/event/OpenPlayerSaveEvent.java b/api/src/main/java/com/lishid/openinv/event/OpenPlayerSaveEvent.java new file mode 100644 index 0000000..a36a6c9 --- /dev/null +++ b/api/src/main/java/com/lishid/openinv/event/OpenPlayerSaveEvent.java @@ -0,0 +1,74 @@ +package com.lishid.openinv.event; + +import com.lishid.openinv.internal.ISpecialInventory; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +/** + * Event fired before OpenInv saves a player's data. + */ +public class OpenPlayerSaveEvent extends Event implements Cancellable { + + private static final HandlerList HANDLERS = new HandlerList(); + + private final Player player; + private final ISpecialInventory inventory; + private boolean cancelled = false; + + public OpenPlayerSaveEvent(@NotNull Player player, @NotNull ISpecialInventory inventory) { + this.player = player; + this.inventory = inventory; + } + + /** + * Get the {@link Player} whose data is being saved. + * + * @return player the Player whose data is being saved + */ + public @NotNull Player getPlayer() { + return player; + } + + /** + * Get the {@link ISpecialInventory} that triggered the save by being closed. + * + * @return the special inventory + */ + public @NotNull ISpecialInventory getInventory() { + return inventory; + } + + /** + * Get whether the event is cancelled. + * + * @return true if the event is cancelled + */ + @Override + public boolean isCancelled() { + return cancelled; + } + + /** + * Set whether the event is cancelled. + * + * @param cancel whether the event is cancelled + */ + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return HANDLERS; + } + + public static HandlerList getHandlerList() { + return HANDLERS; + } + +} diff --git a/assembly/pom.xml b/assembly/pom.xml index 54f94a1..2a69091 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.3.2-SNAPSHOT + 4.4.0-SNAPSHOT openinvassembly diff --git a/internal/v1_19_R3/pom.xml b/internal/v1_19_R3/pom.xml index 8e940b6..56acad9 100644 --- a/internal/v1_19_R3/pom.xml +++ b/internal/v1_19_R3/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.3.2-SNAPSHOT + 4.4.0-SNAPSHOT openinvadapter1_19_R3 diff --git a/internal/v1_20_R1/pom.xml b/internal/v1_20_R1/pom.xml index 5f004c5..acb7f21 100644 --- a/internal/v1_20_R1/pom.xml +++ b/internal/v1_20_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.3.2-SNAPSHOT + 4.4.0-SNAPSHOT openinvadapter1_20_R1 diff --git a/plugin/pom.xml b/plugin/pom.xml index 77fb5af..dbaccf9 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.3.2-SNAPSHOT + 4.4.0-SNAPSHOT openinvplugincore diff --git a/plugin/src/main/java/com/lishid/openinv/InventoryListener.java b/plugin/src/main/java/com/lishid/openinv/InventoryListener.java index 7101fa4..ef15931 100644 --- a/plugin/src/main/java/com/lishid/openinv/InventoryListener.java +++ b/plugin/src/main/java/com/lishid/openinv/InventoryListener.java @@ -63,11 +63,11 @@ record InventoryListener(OpenInv plugin) implements Listener { ISpecialInventory specialInventory = InventoryAccess.getEnderChest(event.getInventory()); if (specialInventory != null) { - this.plugin.handleCloseInventory(event.getPlayer(), specialInventory); + this.plugin.handleCloseInventory(specialInventory); } else { specialInventory = InventoryAccess.getPlayerInventory(event.getInventory()); if (specialInventory != null) { - this.plugin.handleCloseInventory(event.getPlayer(), specialInventory); + this.plugin.handleCloseInventory(specialInventory); } } } diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java index 25b28aa..9ff7ee5 100644 --- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java +++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java @@ -23,6 +23,7 @@ import com.lishid.openinv.commands.OpenInvCommand; import com.lishid.openinv.commands.SearchContainerCommand; import com.lishid.openinv.commands.SearchEnchantCommand; import com.lishid.openinv.commands.SearchInvCommand; +import com.lishid.openinv.event.OpenPlayerSaveEvent; import com.lishid.openinv.internal.IAnySilentContainer; import com.lishid.openinv.internal.ISpecialEnderChest; import com.lishid.openinv.internal.ISpecialInventory; @@ -544,7 +545,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv { } } - void handleCloseInventory(@NotNull HumanEntity exViewer, @NotNull ISpecialInventory inventory) { + void handleCloseInventory(@NotNull ISpecialInventory inventory) { Map map = inventory instanceof ISpecialPlayerInventory ? inventories : enderChests; UUID key = inventory.getPlayer().getUniqueId(); @Nullable ISpecialInventory loaded = map.get(key); @@ -576,11 +577,18 @@ public class OpenInv extends JavaPlugin implements IOpenInv { // Re-fetch from map - prevents duplicate saves on multi-close. ISpecialInventory current = map.remove(key); - if (!disableSaving() - && current != null - && current.getPlayer() instanceof Player player - && !player.isOnline()) { - this.accessor.getPlayerDataManager().inject(player).saveData(); + if (disableSaving() + || current == null + || !(current.getPlayer() instanceof Player player) + || player.isOnline()) { + return; + } + + OpenPlayerSaveEvent event = new OpenPlayerSaveEvent(player, current); + getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + this.accessor.getPlayerDataManager().inject(player).saveData(); } }); } diff --git a/pom.xml b/pom.xml index f910362..f7271e0 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.3.2-SNAPSHOT + 4.4.0-SNAPSHOT pom @@ -84,13 +84,13 @@ openinvapi com.lishid compile - 4.3.2-SNAPSHOT + 4.4.0-SNAPSHOT openinvplugincore com.lishid compile - 4.3.2-SNAPSHOT + 4.4.0-SNAPSHOT com.lishid -- 2.49.1 From d636cdd8394a15ca9042b12e461f1a36932b59d3 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 22 Sep 2023 23:14:07 -0400 Subject: [PATCH 132/139] Add support for 1.20.2 --- internal/v1_20_R2/pom.xml | 81 ++ .../internal/v1_20_R2/AnySilentContainer.java | 243 ++++++ .../openinv/internal/v1_20_R2/OpenPlayer.java | 74 ++ .../internal/v1_20_R2/PlayerDataManager.java | 249 ++++++ .../internal/v1_20_R2/SpecialEnderChest.java | 350 ++++++++ .../v1_20_R2/SpecialPlayerInventory.java | 806 ++++++++++++++++++ pom.xml | 1 + 7 files changed, 1804 insertions(+) create mode 100644 internal/v1_20_R2/pom.xml create mode 100644 internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/AnySilentContainer.java create mode 100644 internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/OpenPlayer.java create mode 100644 internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/PlayerDataManager.java create mode 100644 internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/SpecialEnderChest.java create mode 100644 internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/SpecialPlayerInventory.java diff --git a/internal/v1_20_R2/pom.xml b/internal/v1_20_R2/pom.xml new file mode 100644 index 0000000..edfe39e --- /dev/null +++ b/internal/v1_20_R2/pom.xml @@ -0,0 +1,81 @@ + + + + + 4.0.0 + + + openinvparent + com.lishid + ../../pom.xml + 4.4.0-SNAPSHOT + + + openinvadapter1_20_R2 + OpenInvAdapter1_20_R2 + + + 17 + 17 + 1.20.2-R0.1-SNAPSHOT + + + + + org.spigotmc + spigot-api + ${spigot.version} + + + spigot + org.spigotmc + provided + ${spigot.version} + remapped-mojang + + + openinvapi + com.lishid + provided + + + openinvplugincore + com.lishid + + + annotations + org.jetbrains + + + + + + + maven-shade-plugin + + + maven-compiler-plugin + + + net.md-5 + specialsource-maven-plugin + + + + + diff --git a/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/AnySilentContainer.java b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/AnySilentContainer.java new file mode 100644 index 0000000..c3de0eb --- /dev/null +++ b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/AnySilentContainer.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2011-2023 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_20_R2; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IAnySilentContainer; +import com.lishid.openinv.util.ReflectionHelper; +import java.lang.reflect.Field; +import java.util.logging.Logger; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.monster.Shulker; +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.block.BarrelBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.ShulkerBoxBlock; +import net.minecraft.world.level.block.TrappedChestBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.block.ShulkerBox; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AnySilentContainer implements IAnySilentContainer { + + private @Nullable Field serverPlayerGameModeGameType; + + public AnySilentContainer() { + try { + try { + this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("b"); + this.serverPlayerGameModeGameType.setAccessible(true); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("ServerPlayerGameMode#gameModeForPlayer's obfuscated name has changed!"); + logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues"); + logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail."); + // N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break. + this.serverPlayerGameModeGameType = ReflectionHelper.grabFieldByType(ServerPlayerGameMode.class, GameType.class); + } + } catch (SecurityException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to directly write player game mode! SilentContainer will fail."); + logger.log(java.util.logging.Level.WARNING, "Error obtaining GameType field", e); + } + } + + @Override + public boolean isShulkerBlocked(@NotNull ShulkerBox shulkerBox) { + org.bukkit.World bukkitWorld = shulkerBox.getWorld(); + if (!(bukkitWorld instanceof CraftWorld)) { + bukkitWorld = Bukkit.getWorld(bukkitWorld.getUID()); + } + + if (!(bukkitWorld instanceof CraftWorld craftWorld)) { + Exception exception = new IllegalStateException("AnySilentContainer access attempted on an unknown world!"); + OpenInv.getPlugin(OpenInv.class).getLogger().log(java.util.logging.Level.WARNING, exception.getMessage(), exception); + return false; + } + + final ServerLevel world = craftWorld.getHandle(); + final BlockPos blockPosition = new BlockPos(shulkerBox.getX(), shulkerBox.getY(), shulkerBox.getZ()); + final BlockEntity tile = world.getBlockEntity(blockPosition); + + if (!(tile instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) + || shulkerBoxBlockEntity.getAnimationStatus() != ShulkerBoxBlockEntity.AnimationStatus.CLOSED) { + return false; + } + + BlockState blockState = world.getBlockState(blockPosition); + + // See net.minecraft.world.level.block.ShulkerBoxBlock#canOpen + AABB boundingBox = Shulker.getProgressDeltaAabb(blockState.getValue(ShulkerBoxBlock.FACING), 0.0F, 0.5F) + .move(blockPosition) + .deflate(1.0E-6D); + return !world.noCollision(boundingBox); + } + + @Override + public boolean activateContainer( + @NotNull final Player bukkitPlayer, + final boolean silentchest, + @NotNull final org.bukkit.block.Block bukkitBlock) { + + // Silent ender chest is API-only + if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) { + bukkitPlayer.openInventory(bukkitPlayer.getEnderChest()); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + final net.minecraft.world.level.Level level = player.level(); + final BlockPos blockPos = new BlockPos(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + final BlockEntity blockEntity = level.getBlockEntity(blockPos); + + if (blockEntity == null) { + return false; + } + + if (blockEntity instanceof EnderChestBlockEntity enderChestTile) { + // Anychest ender chest. See net.minecraft.world.level.block.EnderChestBlock + PlayerEnderChestContainer enderChest = player.getEnderChestInventory(); + enderChest.setActiveChest(enderChestTile); + player.openMenu(new SimpleMenuProvider((containerCounter, playerInventory, ignored) -> { + MenuType containers = PlayerDataManager.getContainers(enderChest.getContainerSize()); + int rows = enderChest.getContainerSize() / 9; + return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows); + }, Component.translatable(("container.enderchest")))); + bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); + return true; + } + + if (!(blockEntity instanceof MenuProvider menuProvider)) { + return false; + } + + BlockState blockState = level.getBlockState(blockPos); + Block block = blockState.getBlock(); + + if (block instanceof ChestBlock chestBlock) { + + // boolean flag: do not check if chest is blocked + menuProvider = chestBlock.getMenuProvider(blockState, level, blockPos, true); + + if (menuProvider == null) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + + if (block instanceof TrappedChestBlock) { + bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED); + } else { + bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED); + } + } + + if (block instanceof ShulkerBoxBlock) { + bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED); + } + + if (block instanceof BarrelBlock) { + bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL); + } + + // AnyChest only - SilentChest not active, container unsupported, or unnecessary. + if (!silentchest || player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) { + player.openMenu(menuProvider); + return true; + } + + // SilentChest requires access to setting players' game mode directly. + if (this.serverPlayerGameModeGameType == null) { + return false; + } + + if (blockEntity instanceof RandomizableContainerBlockEntity lootable) { + if (lootable.lootTable != null) { + OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated"); + return false; + } + } + + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); + player.openMenu(menuProvider); + this.forceGameType(player, gameType); + return true; + } + + @Override + public void deactivateContainer(@NotNull final Player bukkitPlayer) { + if (this.serverPlayerGameModeGameType == null || bukkitPlayer.getGameMode() == GameMode.SPECTATOR) { + return; + } + + ServerPlayer player = PlayerDataManager.getHandle(bukkitPlayer); + + // Force game mode change without informing plugins or players. + // Regular game mode set calls GameModeChangeEvent and is cancellable. + GameType gameType = player.gameMode.getGameModeForPlayer(); + this.forceGameType(player, GameType.SPECTATOR); + + // ServerPlayer#closeContainer cannot be called without entering an + // infinite loop because this method is called during inventory close. + // From ServerPlayer#closeContainer -> CraftEventFactory#handleInventoryCloseEvent + player.containerMenu.transferTo(player.inventoryMenu, player.getBukkitEntity()); + // From ServerPlayer#closeContainer + player.doCloseContainer(); + // Regular inventory close will handle the rest - packet sending, etc. + + // Revert forced game mode. + this.forceGameType(player, gameType); + } + + private void forceGameType(final ServerPlayer player, final GameType gameMode) { + if (this.serverPlayerGameModeGameType == null) { + // No need to warn repeatedly, error on startup and lack of function should be enough. + return; + } + try { + this.serverPlayerGameModeGameType.setAccessible(true); + this.serverPlayerGameModeGameType.set(player.gameMode, gameMode); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + +} diff --git a/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/OpenPlayer.java b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/OpenPlayer.java new file mode 100644 index 0000000..fc70dec --- /dev/null +++ b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/OpenPlayer.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011-2023 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_20_R2; + +import com.mojang.logging.LogUtils; +import java.io.File; +import net.minecraft.Util; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.storage.PlayerDataStorage; +import org.bukkit.craftbukkit.v1_20_R2.CraftServer; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; + +public class OpenPlayer extends CraftPlayer { + + public OpenPlayer(CraftServer server, ServerPlayer entity) { + super(server, entity); + } + + @Override + public void loadData() { + // See CraftPlayer#loadData + CompoundTag loaded = this.server.getHandle().playerIo.load(this.getHandle()); + if (loaded != null) { + getHandle().readAdditionalSaveData(loaded); + } + } + + @Override + public void saveData() { + ServerPlayer player = this.getHandle(); + // See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman) + try { + PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; + + CompoundTag playerData = player.saveWithoutId(new CompoundTag()); + setExtraData(playerData); + + if (!isOnline()) { + // Special case: save old vehicle data + CompoundTag oldData = worldNBTStorage.load(player); + + if (oldData != null && oldData.contains("RootVehicle", 10)) { + // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound) + playerData.put("RootVehicle", oldData.getCompound("RootVehicle")); + } + } + + File file = File.createTempFile(player.getStringUUID() + "-", ".dat", worldNBTStorage.getPlayerDir()); + NbtIo.writeCompressed(playerData, file); + File file1 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat"); + File file2 = new File(worldNBTStorage.getPlayerDir(), player.getStringUUID() + ".dat_old"); + Util.safeReplaceFile(file1, file, file2); + } catch (Exception e) { + LogUtils.getLogger().warn("Failed to save player data for {}: {}", player.getScoreboardName(), e); + } + } + +} diff --git a/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/PlayerDataManager.java b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/PlayerDataManager.java new file mode 100644 index 0000000..9d6ec28 --- /dev/null +++ b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/PlayerDataManager.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2011-2023 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_20_R2; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IPlayerDataManager; +import com.lishid.openinv.internal.ISpecialInventory; +import com.lishid.openinv.internal.OpenInventoryView; +import com.mojang.authlib.GameProfile; +import java.lang.reflect.Field; +import java.util.logging.Logger; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.craftbukkit.v1_20_R2.CraftServer; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftContainer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PlayerDataManager implements IPlayerDataManager { + + private @Nullable Field bukkitEntity; + + public PlayerDataManager() { + try { + bukkitEntity = Entity.class.getDeclaredField("bukkitEntity"); + } catch (NoSuchFieldException e) { + Logger logger = OpenInv.getPlugin(OpenInv.class).getLogger(); + logger.warning("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded."); + logger.log(java.util.logging.Level.WARNING, e.getMessage(), e); + bukkitEntity = null; + } + } + + public static @NotNull ServerPlayer getHandle(final Player player) { + if (player instanceof CraftPlayer) { + return ((CraftPlayer) player).getHandle(); + } + + Server server = player.getServer(); + ServerPlayer nmsPlayer = null; + + if (server instanceof CraftServer) { + nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getUniqueId()); + } + + if (nmsPlayer == null) { + // Could use reflection to examine fields, but it's honestly not worth the bother. + throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation"); + } + + return nmsPlayer; + } + + @Override + public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) { + // Ensure player has data + if (!offline.hasPlayedBefore()) { + return null; + } + + // Create a profile and entity to load the player data + // See net.minecraft.server.players.PlayerList#canPlayerLogin + // and net.minecraft.server.network.ServerLoginPacketListenerImpl#handleHello + GameProfile profile = new GameProfile(offline.getUniqueId(), + offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel worldServer = server.getLevel(Level.OVERWORLD); + + if (worldServer == null) { + return null; + } + + ServerPlayer entity = new ServerPlayer(server, worldServer, profile, null); + + // Stop listening for advancement progression - if this is not cleaned up, loading causes a memory leak. + entity.getAdvancements().stopListening(); + + try { + injectPlayer(entity); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + // Load data. This also reads basic data into the player. + // See CraftPlayer#loadData + CompoundTag loadedData = server.getPlayerList().playerIo.load(entity); + + if (loadedData == null) { + // Exceptions with loading are logged by Mojang. + return null; + } + + // Also read "extra" data. + entity.readAdditionalSaveData(loadedData); + + if (entity.level() == null) { + // Paper: Move player to spawn + entity.spawnIn(null); + } + + // Return the Bukkit entity. + return entity.getBukkitEntity(); + } + + void injectPlayer(ServerPlayer player) throws IllegalAccessException { + if (bukkitEntity == null) { + return; + } + + bukkitEntity.setAccessible(true); + + bukkitEntity.set(player, new OpenPlayer(player.server.server, player)); + } + + @NotNull + @Override + public Player inject(@NotNull Player player) { + try { + ServerPlayer nmsPlayer = getHandle(player); + if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) { + return openPlayer; + } + injectPlayer(nmsPlayer); + return nmsPlayer.getBukkitEntity(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return player; + } + } + + @Nullable + @Override + public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) { + + ServerPlayer nmsPlayer = getHandle(player); + + if (nmsPlayer.connection == null) { + return null; + } + + InventoryView view = getView(player, inventory); + + if (view == null) { + return player.openInventory(inventory.getBukkitInventory()); + } + + AbstractContainerMenu container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) { + @Override + public MenuType getType() { + return getContainers(inventory.getBukkitInventory().getSize()); + } + }; + + container.setTitle(Component.literal(view.getTitle())); + container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container); + + if (container == null) { + return null; + } + + nmsPlayer.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), + Component.literal(container.getBukkitView().getTitle()))); + nmsPlayer.containerMenu = container; + nmsPlayer.initMenu(container); + + return container.getBukkitView(); + + } + + private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) { + if (inventory instanceof SpecialEnderChest) { + return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest"); + } else if (inventory instanceof SpecialPlayerInventory) { + return new OpenInventoryView(player, inventory, "container.player", "'s Inventory"); + } else { + return null; + } + } + + static @NotNull MenuType getContainers(int inventorySize) { + + return switch (inventorySize) { + case 9 -> MenuType.GENERIC_9x1; + case 18 -> MenuType.GENERIC_9x2; + case 36 -> MenuType.GENERIC_9x4; // PLAYER + case 41, 45 -> MenuType.GENERIC_9x5; + case 54 -> MenuType.GENERIC_9x6; + default -> MenuType.GENERIC_9x3; // Default 27-slot inventory + }; + } + + @Override + public int convertToPlayerSlot(InventoryView view, int rawSlot) { + int topSize = view.getTopInventory().getSize(); + if (topSize <= rawSlot) { + // Slot is not inside special inventory, use Bukkit logic. + return view.convertSlot(rawSlot); + } + + // Main inventory, slots 0-26 -> 9-35 + if (rawSlot < 27) { + return rawSlot + 9; + } + // Hotbar, slots 27-35 -> 0-8 + if (rawSlot < 36) { + return rawSlot - 27; + } + // Armor, slots 36-39 -> 39-36 + if (rawSlot < 40) { + return 36 + (39 - rawSlot); + } + // Off hand + if (rawSlot == 40) { + return 40; + } + // Drop slots, "out of inventory" + return -1; + } + +} diff --git a/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/SpecialEnderChest.java b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/SpecialEnderChest.java new file mode 100644 index 0000000..5987e9b --- /dev/null +++ b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/SpecialEnderChest.java @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2011-2023 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_20_R2; + +import com.lishid.openinv.internal.ISpecialEnderChest; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.ContainerListener; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SpecialEnderChest extends PlayerEnderChestContainer implements ISpecialEnderChest { + + private final CraftInventory inventory; + private ServerPlayer owner; + private NonNullList items; + private boolean playerOnline; + + public SpecialEnderChest(final org.bukkit.entity.Player player, final Boolean online) { + super(PlayerDataManager.getHandle(player)); + this.inventory = new CraftInventory(this); + this.owner = PlayerDataManager.getHandle(player); + this.playerOnline = online; + this.items = this.owner.getEnderChestInventory().items; + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return inventory; + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public void setPlayerOnline(@NotNull final org.bukkit.entity.Player player) { + if (this.playerOnline) { + return; + } + + ServerPlayer offlinePlayer = this.owner; + ServerPlayer onlinePlayer = PlayerDataManager.getHandle(player); + + // Set owner to new player. + this.owner = onlinePlayer; + + // Set player's ender chest contents to our modified contents. + PlayerEnderChestContainer onlineEnderChest = onlinePlayer.getEnderChestInventory(); + for (int i = 0; i < onlineEnderChest.getContainerSize(); ++i) { + onlineEnderChest.setItem(i, this.items.get(i)); + } + + // Set our item array to the new inventory's array. + this.items = onlineEnderChest.items; + + // Add viewers to new inventory. + onlineEnderChest.transaction.addAll(offlinePlayer.getEnderChestInventory().transaction); + + this.playerOnline = true; + } + + @Override + public @NotNull org.bukkit.entity.Player getPlayer() { + return owner.getBukkitEntity(); + } + + @Override + public void setChanged() { + this.owner.getEnderChestInventory().setChanged(); + } + + @Override + public List getContents() { + return this.items; + } + + @Override + public void onOpen(CraftHumanEntity who) { + this.owner.getEnderChestInventory().onOpen(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + this.owner.getEnderChestInventory().onClose(who); + } + + @Override + public List getViewers() { + return this.owner.getEnderChestInventory().getViewers(); + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public void setActiveChest(EnderChestBlockEntity enderChest) { + this.owner.getEnderChestInventory().setActiveChest(enderChest); + } + + @Override + public boolean isActiveChest(EnderChestBlockEntity enderChest) { + return this.owner.getEnderChestInventory().isActiveChest(enderChest); + } + + @Override + public int getMaxStackSize() { + return this.owner.getEnderChestInventory().getMaxStackSize(); + } + + @Override + public void setMaxStackSize(int i) { + this.owner.getEnderChestInventory().setMaxStackSize(i); + } + + @Override + public InventoryHolder getOwner() { + return this.owner.getEnderChestInventory().getOwner(); + } + + @Override + public @Nullable Location getLocation() { + return null; + } + + @Override + public void addListener(ContainerListener listener) { + this.owner.getEnderChestInventory().addListener(listener); + } + + @Override + public void removeListener(ContainerListener listener) { + this.owner.getEnderChestInventory().removeListener(listener); + } + + @Override + public ItemStack getItem(int i) { + return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.EMPTY; + } + + @Override + public ItemStack removeItem(int i, int j) { + ItemStack itemstack = ContainerHelper.removeItem(this.items, i, j); + if (!itemstack.isEmpty()) { + this.setChanged(); + } + + return itemstack; + } + + @Override + public ItemStack addItem(ItemStack itemstack) { + ItemStack localItem = itemstack.copy(); + this.moveItemToOccupiedSlotsWithSameType(localItem); + if (localItem.isEmpty()) { + return ItemStack.EMPTY; + } else { + this.moveItemToEmptySlots(localItem); + return localItem.isEmpty() ? ItemStack.EMPTY : localItem; + } + } + + @Override + public boolean canAddItem(ItemStack itemstack) { + for (ItemStack itemstack1 : this.items) { + if (itemstack1.isEmpty() || ItemStack.isSameItemSameTags(itemstack1, itemstack) && itemstack1.getCount() < itemstack1.getMaxStackSize()) { + return true; + } + } + + return false; + } + + private void moveItemToEmptySlots(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (localItem.isEmpty()) { + this.setItem(i, itemstack.copy()); + itemstack.setCount(0); + return; + } + } + } + + private void moveItemToOccupiedSlotsWithSameType(ItemStack itemstack) { + for(int i = 0; i < this.getContainerSize(); ++i) { + ItemStack localItem = this.getItem(i); + if (ItemStack.isSameItemSameTags(localItem, itemstack)) { + this.moveItemsBetweenStacks(itemstack, localItem); + if (itemstack.isEmpty()) { + return; + } + } + } + } + + private void moveItemsBetweenStacks(ItemStack itemstack, ItemStack itemstack1) { + int i = Math.min(this.getMaxStackSize(), itemstack1.getMaxStackSize()); + int j = Math.min(itemstack.getCount(), i - itemstack1.getCount()); + if (j > 0) { + itemstack1.grow(j); + itemstack.shrink(j); + this.setChanged(); + } + } + + @Override + public ItemStack removeItemNoUpdate(int i) { + ItemStack itemstack = this.items.get(i); + if (itemstack.isEmpty()) { + return ItemStack.EMPTY; + } else { + this.items.set(i, ItemStack.EMPTY); + return itemstack; + } + } + + @Override + public void setItem(int i, ItemStack itemstack) { + this.items.set(i, itemstack); + if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) { + itemstack.setCount(this.getMaxStackSize()); + } + + this.setChanged(); + } + + @Override + public int getContainerSize() { + return this.owner.getEnderChestInventory().getContainerSize(); + } + + @Override + public boolean isEmpty() { + return this.items.stream().allMatch(ItemStack::isEmpty); + } + + @Override + public void startOpen(Player player) { + } + + @Override + public void stopOpen(Player player) { + } + + @Override + public boolean canPlaceItem(int i, ItemStack itemstack) { + return true; + } + + @Override + public void clearContent() { + this.items.clear(); + this.setChanged(); + } + + @Override + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountStack(itemstack); + } + + } + + @Override + public List removeAllItems() { + List list = this.items.stream().filter(Predicate.not(ItemStack::isEmpty)).collect(Collectors.toList()); + this.clearContent(); + return list; + } + + @Override + public ItemStack removeItemType(Item item, int i) { + ItemStack itemstack = new ItemStack(item, 0); + + for(int j = this.getContainerSize() - 1; j >= 0; --j) { + ItemStack localItem = this.getItem(j); + if (localItem.getItem().equals(item)) { + int k = i - itemstack.getCount(); + ItemStack splitItem = localItem.split(k); + itemstack.grow(splitItem.getCount()); + if (itemstack.getCount() == i) { + break; + } + } + } + + if (!itemstack.isEmpty()) { + this.setChanged(); + } + + return itemstack; + } + + @Override + public String toString() { + return this.items.stream().filter((itemStack) -> !itemStack.isEmpty()).toList().toString(); + } + + @Override + public void fromTag(ListTag listTag) { + for (int i = 0; i < this.getContainerSize(); ++i) { + this.setItem(i, ItemStack.EMPTY); + } + + for (int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + if (j < this.getContainerSize()) { + this.setItem(j, ItemStack.of(compoundTag)); + } + } + + } + +} diff --git a/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/SpecialPlayerInventory.java b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/SpecialPlayerInventory.java new file mode 100644 index 0000000..3e527ea --- /dev/null +++ b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/SpecialPlayerInventory.java @@ -0,0 +1,806 @@ +/* + * Copyright (C) 2011-2023 lishid. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lishid.openinv.internal.v1_20_R2; + +import com.google.common.collect.ImmutableList; +import com.lishid.openinv.internal.ISpecialPlayerInventory; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.tags.DamageTypeTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.Container; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftInventory; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SpecialPlayerInventory extends Inventory implements ISpecialPlayerInventory { + + private final CraftInventory inventory; + private boolean playerOnline; + private Player player; + private NonNullList items; + private NonNullList armor; + private NonNullList offhand; + private List> compartments; + + public SpecialPlayerInventory(@NotNull org.bukkit.entity.Player bukkitPlayer, @NotNull Boolean online) { + super(PlayerDataManager.getHandle(bukkitPlayer)); + this.inventory = new CraftInventory(this); + this.playerOnline = online; + this.player = super.player; + this.selected = player.getInventory().selected; + this.items = this.player.getInventory().items; + this.armor = this.player.getInventory().armor; + this.offhand = this.player.getInventory().offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + } + + @Override + public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) { + if (this.playerOnline) { + return; + } + + Player offlinePlayer = this.player; + Player onlinePlayer = PlayerDataManager.getHandle(player); + onlinePlayer.getInventory().transaction.addAll(this.transaction); + + // Set owner to new player. + this.player = onlinePlayer; + + // Set player's inventory contents to our modified contents. + Inventory onlineInventory = onlinePlayer.getInventory(); + for (int i = 0; i < getContainerSize(); ++i) { + onlineInventory.setItem(i, getRawItem(i)); + } + onlineInventory.selected = this.selected; + + // Set our item arrays to the new inventory's arrays. + this.items = onlineInventory.items; + this.armor = onlineInventory.armor; + this.offhand = onlineInventory.offhand; + this.compartments = ImmutableList.of(this.items, this.armor, this.offhand); + + // Add existing viewers to new viewer list. + Inventory offlineInventory = offlinePlayer.getInventory(); + // Remove self from listing - player is always a viewer of their own inventory, prevent duplicates. + offlineInventory.transaction.remove(offlinePlayer.getBukkitEntity()); + onlineInventory.transaction.addAll(offlineInventory.transaction); + + this.playerOnline = true; + } + + @Override + public @NotNull CraftInventory getBukkitInventory() { + return this.inventory; + } + + @Override + public void setPlayerOffline() { + this.playerOnline = false; + } + + @Override + public @NotNull HumanEntity getPlayer() { + return this.player.getBukkitEntity(); + } + + private @NotNull ItemStack getRawItem(int i) { + if (i < 0) { + return ItemStack.EMPTY; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + return list.get(i); + } + } + + return ItemStack.EMPTY; + } + + private void setRawItem(int i, @NotNull ItemStack itemStack) { + if (i < 0) { + return; + } + + NonNullList list; + for (Iterator> iterator = this.compartments.iterator(); iterator.hasNext(); i -= list.size()) { + list = iterator.next(); + if (i < list.size()) { + list.set(i, itemStack); + } + } + } + + private record IndexedCompartment(@Nullable NonNullList compartment, int index) {} + + private @NotNull SpecialPlayerInventory.IndexedCompartment getIndexedContent(int index) { + if (index < items.size()) { + return new IndexedCompartment(items, getReversedItemSlotNum(index)); + } + + index -= items.size(); + + if (index < armor.size()) { + return new IndexedCompartment(armor, getReversedArmorSlotNum(index)); + } + + index -= armor.size(); + + if (index < offhand.size()) { + return new IndexedCompartment(offhand, index); + } + + index -= offhand.size(); + + return new IndexedCompartment(null, index); + } + + private int getReversedArmorSlotNum(final int i) { + if (i == 0) { + return 3; + } + if (i == 1) { + return 2; + } + if (i == 2) { + return 1; + } + if (i == 3) { + return 0; + } + return i; + } + + private int getReversedItemSlotNum(final int i) { + if (i >= 27) { + return i - 27; + } + return i + 9; + } + + private boolean contains(Predicate predicate) { + return this.compartments.stream().flatMap(NonNullList::stream).anyMatch(predicate); + } + + @Override + public List getArmorContents() { + return this.armor; + } + + @Override + public void onOpen(CraftHumanEntity who) { + this.player.getInventory().onOpen(who); + } + + @Override + public void onClose(CraftHumanEntity who) { + this.player.getInventory().onClose(who); + } + + @Override + public List getViewers() { + return this.player.getInventory().getViewers(); + } + + @Override + public InventoryHolder getOwner() { + return this.player.getBukkitEntity(); + } + + @Override + public int getMaxStackSize() { + return this.player.getInventory().getMaxStackSize(); + } + + @Override + public void setMaxStackSize(int size) { + this.player.getInventory().setMaxStackSize(size); + } + + @Override + public Location getLocation() { + return this.player.getBukkitEntity().getLocation(); + } + + @Override + public boolean hasCustomName() { + return false; + } + + @Override + public List getContents() { + return this.compartments.stream().flatMap(Collection::stream).collect(Collectors.toList()); + } + + @Override + public ItemStack getSelected() { + return isHotbarSlot(this.selected) ? this.items.get(this.selected) : ItemStack.EMPTY; + } + + private boolean hasRemainingSpaceForItem(ItemStack itemstack, ItemStack itemstack1) { + return !itemstack.isEmpty() && ItemStack.isSameItemSameTags(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); + } + + @Override + public int canHold(ItemStack itemstack) { + int remains = itemstack.getCount(); + + for (int i = 0; i < this.items.size(); ++i) { + ItemStack itemstack1 = this.getRawItem(i); + if (itemstack1.isEmpty()) { + return itemstack.getCount(); + } + + if (this.hasRemainingSpaceForItem(itemstack1, itemstack)) { + remains -= (itemstack1.getMaxStackSize() < this.getMaxStackSize() ? itemstack1.getMaxStackSize() : this.getMaxStackSize()) - itemstack1.getCount(); + } + + if (remains <= 0) { + return itemstack.getCount(); + } + } + + ItemStack offhandItemStack = this.getRawItem(this.items.size() + this.armor.size()); + if (this.hasRemainingSpaceForItem(offhandItemStack, itemstack)) { + remains -= (offhandItemStack.getMaxStackSize() < this.getMaxStackSize() ? offhandItemStack.getMaxStackSize() : this.getMaxStackSize()) - offhandItemStack.getCount(); + } + + return remains <= 0 ? itemstack.getCount() : itemstack.getCount() - remains; + } + + @Override + public int getFreeSlot() { + for(int i = 0; i < this.items.size(); ++i) { + if (this.items.get(i).isEmpty()) { + return i; + } + } + + return -1; + } + + @Override + public void setPickedItem(ItemStack itemstack) { + int i = this.findSlotMatchingItem(itemstack); + if (isHotbarSlot(i)) { + this.selected = i; + } else if (i == -1) { + this.selected = this.getSuitableHotbarSlot(); + if (!this.items.get(this.selected).isEmpty()) { + int j = this.getFreeSlot(); + if (j != -1) { + this.items.set(j, this.items.get(this.selected)); + } + } + + this.items.set(this.selected, itemstack); + } else { + this.pickSlot(i); + } + + } + + @Override + public void pickSlot(int i) { + this.selected = this.getSuitableHotbarSlot(); + ItemStack itemstack = this.items.get(this.selected); + this.items.set(this.selected, this.items.get(i)); + this.items.set(i, itemstack); + } + + @Override + public int findSlotMatchingItem(ItemStack itemstack) { + for(int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemstack, this.items.get(i))) { + return i; + } + } + + return -1; + } + + @Override + public int findSlotMatchingUnusedItem(ItemStack itemStack) { + for(int i = 0; i < this.items.size(); ++i) { + ItemStack localItem = this.items.get(i); + if (!this.items.get(i).isEmpty() && ItemStack.isSameItemSameTags(itemStack, this.items.get(i)) && !this.items.get(i).isDamaged() && !localItem.isEnchanted() && !localItem.hasCustomHoverName()) { + return i; + } + } + + return -1; + } + + @Override + public int getSuitableHotbarSlot() { + int i; + int j; + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (this.items.get(i).isEmpty()) { + return i; + } + } + + for(j = 0; j < 9; ++j) { + i = (this.selected + j) % 9; + if (!this.items.get(i).isEnchanted()) { + return i; + } + } + + return this.selected; + } + + @Override + public void swapPaint(double d0) { + if (d0 > 0.0D) { + d0 = 1.0D; + } + + if (d0 < 0.0D) { + d0 = -1.0D; + } + + this.selected = (int) (this.selected - d0); + + while (this.selected < 0) { + this.selected += 9; + } + + while(this.selected >= 9) { + this.selected -= 9; + } + } + + @Override + public int clearOrCountMatchingItems(Predicate predicate, int i, Container container) { + byte b0 = 0; + boolean flag = i == 0; + int j = b0 + ContainerHelper.clearOrCountMatchingItems(this, predicate, i - b0, flag); + j += ContainerHelper.clearOrCountMatchingItems(container, predicate, i - j, flag); + ItemStack itemstack = this.player.containerMenu.getCarried(); + j += ContainerHelper.clearOrCountMatchingItems(itemstack, predicate, i - j, flag); + if (itemstack.isEmpty()) { + this.player.containerMenu.setCarried(ItemStack.EMPTY); + } + + return j; + } + + private int addResource(ItemStack itemstack) { + int i = this.getSlotWithRemainingSpace(itemstack); + if (i == -1) { + i = this.getFreeSlot(); + } + + return i == -1 ? itemstack.getCount() : this.addResource(i, itemstack); + } + + private int addResource(int i, ItemStack itemstack) { + Item item = itemstack.getItem(); + int j = itemstack.getCount(); + ItemStack localItemStack = this.getRawItem(i); + if (localItemStack.isEmpty()) { + localItemStack = new ItemStack(item, 0); + if (itemstack.hasTag()) { + // hasTag ensures tag not null + //noinspection ConstantConditions + localItemStack.setTag(itemstack.getTag().copy()); + } + + this.setRawItem(i, localItemStack); + } + + int k = Math.min(j, localItemStack.getMaxStackSize() - localItemStack.getCount()); + + if (k > this.getMaxStackSize() - localItemStack.getCount()) { + k = this.getMaxStackSize() - localItemStack.getCount(); + } + + if (k != 0) { + j -= k; + localItemStack.grow(k); + localItemStack.setPopTime(5); + } + + return j; + } + + @Override + public int getSlotWithRemainingSpace(ItemStack itemstack) { + if (this.hasRemainingSpaceForItem(this.getRawItem(this.selected), itemstack)) { + return this.selected; + } else if (this.hasRemainingSpaceForItem(this.getRawItem(40), itemstack)) { + return 40; + } else { + for(int i = 0; i < this.items.size(); ++i) { + if (this.hasRemainingSpaceForItem(this.items.get(i), itemstack)) { + return i; + } + } + + return -1; + } + } + + @Override + public void tick() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (!compartment.get(i).isEmpty()) { + compartment.get(i).inventoryTick(this.player.level(), this.player, i, this.selected == i); + } + } + } + + } + + @Override + public boolean add(ItemStack itemStack) { + return this.add(-1, itemStack); + } + + @Override + public boolean add(int i, ItemStack itemStack) { + if (itemStack.isEmpty()) { + return false; + } else { + try { + if (itemStack.isDamaged()) { + if (i == -1) { + i = this.getFreeSlot(); + } + + if (i >= 0) { + this.items.set(i, itemStack.copy()); + this.items.get(i).setPopTime(5); + itemStack.setCount(0); + return true; + } else if (this.player.getAbilities().instabuild) { + itemStack.setCount(0); + return true; + } else { + return false; + } + } else { + int j; + do { + j = itemStack.getCount(); + if (i == -1) { + itemStack.setCount(this.addResource(itemStack)); + } else { + itemStack.setCount(this.addResource(i, itemStack)); + } + } while(!itemStack.isEmpty() && itemStack.getCount() < j); + + if (itemStack.getCount() == j && this.player.getAbilities().instabuild) { + itemStack.setCount(0); + return true; + } else { + return itemStack.getCount() < j; + } + } + } catch (Throwable var6) { + CrashReport crashReport = CrashReport.forThrowable(var6, "Adding item to inventory"); + CrashReportCategory crashReportCategory = crashReport.addCategory("Item being added"); + crashReportCategory.setDetail("Item ID", Item.getId(itemStack.getItem())); + crashReportCategory.setDetail("Item data", itemStack.getDamageValue()); + crashReportCategory.setDetail("Item name", () -> itemStack.getHoverName().getString()); + throw new ReportedException(crashReport); + } + } + } + + @Override + public void placeItemBackInInventory(ItemStack itemStack) { + this.placeItemBackInInventory(itemStack, true); + } + + @Override + public void placeItemBackInInventory(ItemStack itemStack, boolean flag) { + while(true) { + if (!itemStack.isEmpty()) { + int i = this.getSlotWithRemainingSpace(itemStack); + if (i == -1) { + i = this.getFreeSlot(); + } + + if (i != -1) { + int j = itemStack.getMaxStackSize() - this.getRawItem(i).getCount(); + if (this.add(i, itemStack.split(j)) && flag && this.player instanceof ServerPlayer) { + ((ServerPlayer)this.player).connection.send(new ClientboundContainerSetSlotPacket(-2, 0, i, this.getRawItem(i))); + } + continue; + } + + this.player.drop(itemStack, false); + } + + return; + } + } + + @Override + public ItemStack removeItem(int rawIndex, final int j) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null + || indexedCompartment.compartment().get(indexedCompartment.index()).isEmpty()) { + return ItemStack.EMPTY; + } + + return ContainerHelper.removeItem(indexedCompartment.compartment(), indexedCompartment.index(), j); + } + + @Override + public void removeItem(ItemStack itemStack) { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + if (compartment.get(i) == itemStack) { + compartment.set(i, ItemStack.EMPTY); + break; + } + } + } + } + + @Override + public ItemStack removeItemNoUpdate(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + ItemStack removed = indexedCompartment.compartment().set(indexedCompartment.index(), ItemStack.EMPTY); + + if (removed.isEmpty()) { + return ItemStack.EMPTY; + } + + return removed; + } + + @Override + public void setItem(int rawIndex, final ItemStack itemStack) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + this.player.drop(itemStack, true); + return; + } + + indexedCompartment.compartment().set(indexedCompartment.index(), itemStack); + } + + @Override + public float getDestroySpeed(BlockState blockState) { + return this.items.get(this.selected).getDestroySpeed(blockState); + } + + @Override + public ListTag save(ListTag listTag) { + for (int i = 0; i < this.items.size(); ++i) { + if (!this.items.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)i); + this.items.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.armor.size(); ++i) { + if (!this.armor.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 100)); + this.armor.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + for (int i = 0; i < this.offhand.size(); ++i) { + if (!this.offhand.get(i).isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte)(i + 150)); + this.offhand.get(i).save(compoundTag); + listTag.add(compoundTag); + } + } + + return listTag; + } + + @Override + public void load(ListTag listTag) { + this.items.clear(); + this.armor.clear(); + this.offhand.clear(); + + for(int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + ItemStack itemstack = ItemStack.of(compoundTag); + if (!itemstack.isEmpty()) { + if (j < this.items.size()) { + this.items.set(j, itemstack); + } else if (j >= 100 && j < this.armor.size() + 100) { + this.armor.set(j - 100, itemstack); + } else if (j >= 150 && j < this.offhand.size() + 150) { + this.offhand.set(j - 150, itemstack); + } + } + } + + } + + @Override + public int getContainerSize() { + return 45; + } + + @Override + public boolean isEmpty() { + return !contains(itemStack -> !itemStack.isEmpty()); + } + + @Override + public ItemStack getItem(int rawIndex) { + IndexedCompartment indexedCompartment = getIndexedContent(rawIndex); + + if (indexedCompartment.compartment() == null) { + return ItemStack.EMPTY; + } + + return indexedCompartment.compartment().get(indexedCompartment.index()); + } + + @Override + public Component getName() { + return this.player.getName(); + } + + @Override + public ItemStack getArmor(int index) { + return this.armor.get(index); + } + + @Override + public void hurtArmor(DamageSource damagesource, float damage, int[] armorIndices) { + if (damage > 0.0F) { + damage /= 4.0F; + if (damage < 1.0F) { + damage = 1.0F; + } + + for (int index : armorIndices) { + ItemStack itemstack = this.armor.get(index); + if ((!damagesource.is(DamageTypeTags.IS_FIRE) || !itemstack.getItem().isFireResistant()) && itemstack.getItem() instanceof ArmorItem) { + itemstack.hurtAndBreak((int) damage, this.player, localPlayer -> localPlayer.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, index))); + } + } + } + } + + @Override + public void dropAll() { + for (NonNullList compartment : this.compartments) { + for (int i = 0; i < compartment.size(); ++i) { + ItemStack itemstack = compartment.get(i); + if (!itemstack.isEmpty()) { + this.player.drop(itemstack, true, false); + compartment.set(i, ItemStack.EMPTY); + } + } + } + } + + @Override + public void setChanged() { + super.setChanged(); + } + + @Override + public int getTimesChanged() { + return super.getTimesChanged(); + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public boolean contains(ItemStack itemstack) { + return contains(itemStack -> itemStack.isEmpty() && itemStack.is(itemstack.getItem())); + } + + @Override + public boolean contains(TagKey tagKey) { + + return contains(itemStack -> !itemStack.isEmpty() && itemStack.is(tagKey)); + } + + @Override + public void replaceWith(Inventory inventory) { + Function getter; + + if (inventory instanceof SpecialPlayerInventory specialPlayerInventory) { + getter = specialPlayerInventory::getRawItem; + } else { + getter = inventory::getItem; + } + + for(int i = 0; i < this.getContainerSize(); ++i) { + this.setRawItem(i, getter.apply(i)); + } + + this.selected = inventory.selected; + } + + @Override + public void clearContent() { + for (NonNullList compartment : this.compartments) { + compartment.clear(); + } + } + + @Override + public void fillStackedContents(StackedContents stackedContents) { + for (ItemStack itemstack : this.items) { + stackedContents.accountSimpleStack(itemstack); + } + } + + @Override + public ItemStack removeFromSelected(boolean dropWholeStack) { + ItemStack itemstack = this.getSelected(); + return itemstack.isEmpty() ? ItemStack.EMPTY : this.removeItem(this.selected, dropWholeStack ? itemstack.getCount() : 1); + } + +} diff --git a/pom.xml b/pom.xml index f7271e0..175c7cf 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,7 @@ plugin internal/v1_19_R3 internal/v1_20_R1 + internal/v1_20_R2 assembly -- 2.49.1 From 9d715b61c09cd601f5e8506db19a744cc224cd48 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 23:20:13 -0400 Subject: [PATCH 133/139] Bump maven-shade-plugin from 3.4.1 to 3.5.0 (#153) Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.1 to 3.5.0. - [Release notes](https://github.com/apache/maven-shade-plugin/releases) - [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.1...maven-shade-plugin-3.5.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-shade-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 175c7cf..dd6a98e 100644 --- a/pom.xml +++ b/pom.xml @@ -145,7 +145,7 @@ org.apache.maven.plugins - 3.4.1 + 3.5.0 -- 2.49.1 From 21cd52c16696aa5e809314b0fb463600f8083732 Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 22 Sep 2023 23:46:43 -0400 Subject: [PATCH 134/139] Fix probable NPE --- .../internal/v1_20_R2/PlayerDataManager.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/PlayerDataManager.java b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/PlayerDataManager.java index 9d6ec28..0f3d5ce 100644 --- a/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/PlayerDataManager.java +++ b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/PlayerDataManager.java @@ -21,15 +21,15 @@ import com.lishid.openinv.internal.IPlayerDataManager; import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.internal.OpenInventoryView; import com.mojang.authlib.GameProfile; -import java.lang.reflect.Field; -import java.util.logging.Logger; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.ChatVisiblity; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.level.Level; @@ -45,6 +45,9 @@ import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Field; +import java.util.logging.Logger; + public class PlayerDataManager implements IPlayerDataManager { private @Nullable Field bukkitEntity; @@ -99,7 +102,18 @@ public class PlayerDataManager implements IPlayerDataManager { return null; } - ServerPlayer entity = new ServerPlayer(server, worldServer, profile, null); + ClientInformation dummyInfo = new ClientInformation( + "en_us", + 1, // Reduce distance just in case. + ChatVisiblity.HIDDEN, // Don't accept chat. + false, + ServerPlayer.DEFAULT_MODEL_CUSTOMIZATION, + ServerPlayer.DEFAULT_MAIN_HAND, + true, + false // Don't list in player list (not that this player is in the list anyway). + ); + + ServerPlayer entity = new ServerPlayer(server, worldServer, profile, dummyInfo); // Stop listening for advancement progression - if this is not cleaned up, loading causes a memory leak. entity.getAdvancements().stopListening(); -- 2.49.1 From db628786810d5f3f9e1e27357d07f1566a73c42c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 17:45:00 +0000 Subject: [PATCH 135/139] Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.0 to 3.5.1 (#159) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dd6a98e..5bd966f 100644 --- a/pom.xml +++ b/pom.xml @@ -145,7 +145,7 @@ org.apache.maven.plugins - 3.5.0 + 3.5.1 -- 2.49.1 From 3cf1aae89b32e0507ff417d1e8e5b9115909028a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 21:52:28 -0400 Subject: [PATCH 136/139] Bump actions/checkout from 3 to 4 (#158) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/draft_release.yml | 2 +- .github/workflows/external_release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e961911..b382ede 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-java@v3 with: diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml index 037c22e..d9b480f 100644 --- a/.github/workflows/draft_release.yml +++ b/.github/workflows/draft_release.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: # Fetch all history - used to assemble changelog. - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/external_release.yml b/.github/workflows/external_release.yml index 94ac2e1..e748656 100644 --- a/.github/workflows/external_release.yml +++ b/.github/workflows/external_release.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 -- 2.49.1 From bfcf0233fa4a5b4b932d2a2a1b4e98980d86ab1d Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 4 Oct 2023 22:15:35 -0400 Subject: [PATCH 137/139] Fix ender chests not being silent --- .../java/com/lishid/openinv/internal/IAnySilentContainer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java index 82b629f..5758b2a 100644 --- a/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java +++ b/api/src/main/java/com/lishid/openinv/internal/IAnySilentContainer.java @@ -158,7 +158,8 @@ public interface IAnySilentContainer { * @return true if the type is a supported container */ default boolean isAnySilentContainer(@NotNull BlockState blockState) { - return blockState instanceof InventoryHolder holder && isAnySilentContainer(holder); + return blockState instanceof InventoryHolder holder && isAnySilentContainer(holder) + || blockState instanceof EnderChest; } /** -- 2.49.1 From 28fc5aea7034d642d64f4fec1aec0df647c38d4a Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 4 Oct 2023 22:18:38 -0400 Subject: [PATCH 138/139] Bump version to 4.4.0 for release --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_19_R3/pom.xml | 2 +- internal/v1_20_R1/pom.xml | 2 +- internal/v1_20_R2/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index eeee22d..aaadf8c 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.4.0-SNAPSHOT + 4.4.0 openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 2a69091..3795f12 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.4.0-SNAPSHOT + 4.4.0 openinvassembly diff --git a/internal/v1_19_R3/pom.xml b/internal/v1_19_R3/pom.xml index 56acad9..0447d13 100644 --- a/internal/v1_19_R3/pom.xml +++ b/internal/v1_19_R3/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.4.0-SNAPSHOT + 4.4.0 openinvadapter1_19_R3 diff --git a/internal/v1_20_R1/pom.xml b/internal/v1_20_R1/pom.xml index acb7f21..78c656a 100644 --- a/internal/v1_20_R1/pom.xml +++ b/internal/v1_20_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.4.0-SNAPSHOT + 4.4.0 openinvadapter1_20_R1 diff --git a/internal/v1_20_R2/pom.xml b/internal/v1_20_R2/pom.xml index edfe39e..aa2263a 100644 --- a/internal/v1_20_R2/pom.xml +++ b/internal/v1_20_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.4.0-SNAPSHOT + 4.4.0 openinvadapter1_20_R2 diff --git a/plugin/pom.xml b/plugin/pom.xml index dbaccf9..179d2f3 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.4.0-SNAPSHOT + 4.4.0 openinvplugincore diff --git a/pom.xml b/pom.xml index 5bd966f..b52364e 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.4.0-SNAPSHOT + 4.4.0 pom @@ -85,13 +85,13 @@ openinvapi com.lishid compile - 4.4.0-SNAPSHOT + 4.4.0 openinvplugincore com.lishid compile - 4.4.0-SNAPSHOT + 4.4.0 com.lishid -- 2.49.1 From deed277376a78c728ddc8bde3df007858efd793a Mon Sep 17 00:00:00 2001 From: Jikoo Date: Wed, 4 Oct 2023 22:19:02 -0400 Subject: [PATCH 139/139] Bump version to 4.4.1-SNAPSHOT for development --- api/pom.xml | 2 +- assembly/pom.xml | 2 +- internal/v1_19_R3/pom.xml | 2 +- internal/v1_20_R1/pom.xml | 2 +- internal/v1_20_R2/pom.xml | 2 +- plugin/pom.xml | 2 +- pom.xml | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index aaadf8c..569ba29 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.4.0 + 4.4.1-SNAPSHOT openinvapi diff --git a/assembly/pom.xml b/assembly/pom.xml index 3795f12..a987052 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ com.lishid openinvparent - 4.4.0 + 4.4.1-SNAPSHOT openinvassembly diff --git a/internal/v1_19_R3/pom.xml b/internal/v1_19_R3/pom.xml index 0447d13..5ad6522 100644 --- a/internal/v1_19_R3/pom.xml +++ b/internal/v1_19_R3/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.4.0 + 4.4.1-SNAPSHOT openinvadapter1_19_R3 diff --git a/internal/v1_20_R1/pom.xml b/internal/v1_20_R1/pom.xml index 78c656a..e5550f5 100644 --- a/internal/v1_20_R1/pom.xml +++ b/internal/v1_20_R1/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.4.0 + 4.4.1-SNAPSHOT openinvadapter1_20_R1 diff --git a/internal/v1_20_R2/pom.xml b/internal/v1_20_R2/pom.xml index aa2263a..e63be77 100644 --- a/internal/v1_20_R2/pom.xml +++ b/internal/v1_20_R2/pom.xml @@ -23,7 +23,7 @@ openinvparent com.lishid ../../pom.xml - 4.4.0 + 4.4.1-SNAPSHOT openinvadapter1_20_R2 diff --git a/plugin/pom.xml b/plugin/pom.xml index 179d2f3..f5d9eb2 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ openinvparent com.lishid - 4.4.0 + 4.4.1-SNAPSHOT openinvplugincore diff --git a/pom.xml b/pom.xml index b52364e..e25c8a9 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ openinvparent OpenInv http://dev.bukkit.org/bukkit-plugins/openinv/ - 4.4.0 + 4.4.1-SNAPSHOT pom @@ -85,13 +85,13 @@ openinvapi com.lishid compile - 4.4.0 + 4.4.1-SNAPSHOT openinvplugincore com.lishid compile - 4.4.0 + 4.4.1-SNAPSHOT com.lishid -- 2.49.1