Compare commits

...
39 Commits
Author SHA1 Message Date
Jikoo 5f04575780 Bump version to 5.3.2 for release 2026-05-22 10:05:43 -04:00
Jikoo 0f5368b134 Include release notes on Hangar 2026-05-22 10:05:09 -04:00
Camden Cove b43a32139d Fix missed copy sending contents to viewers (#401) 2026-05-18 16:23:34 -04:00
R00tB33rMan 98d819c49a Fix inventory access using incorrect schedulers (#400) 2026-05-17 13:09:59 +00:00
tonyjamesstark 8f058fb206 Change format of searchchest (#393)
Displays name if available, shows one entry per line.
2026-05-04 16:16:59 -04:00
dependabot[bot] 60a32b7af5 Bump softprops/action-gh-release from 2.6.1 to 3.0.0 (#395)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.6.1 to 3.0.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2.6.1...v3.0.0)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-01 18:52:41 -04:00
dependabot[bot] 61f7d5cee5 Bump actions/github-script from 8 to 9 (#394)
Bumps [actions/github-script](https://github.com/actions/github-script) from 8 to 9.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v8...v9)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '9'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-01 18:52:06 -04:00
dependabot[bot] 3d65681c6f Bump com.google.errorprone:error_prone_core from 2.48.0 to 2.49.0 (#398) 2026-05-01 20:43:44 +00:00
dependabot[bot] cf2f53f9e9 Bump gradle-wrapper from 9.4.1 to 9.5.0 (#397) 2026-05-01 20:43:22 +00:00
dependabot[bot] 95ae1cfa0a Bump net.ltgt.errorprone from 4.4.0 to 5.1.0 (#396) 2026-05-01 20:41:17 +00:00
Jikoo 07451de7a3 Bump version to 5.3.2-SNAPSHOT for development 2026-04-21 21:34:03 -04:00
Jikoo 872e14e1a6 Bump version to 5.3.1 for release 2026-04-21 21:33:41 -04:00
Adam f5e534f758 Port Bukkit data fix to Spigot (#391) 2026-04-22 01:23:07 +00:00
Adam 16a4c8f71b Update to Minecraft 26.1 (#385)
Also fixes issues with saving default Bukkit data

Closes #384
Closes #389
2026-04-21 21:05:00 -04:00
dependabot[bot] 7f4216995c Bump softprops/action-gh-release from 2.5.0 to 2.6.1 (#386)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.5.0 to 2.6.1.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2.5.0...v2.6.1)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 09:32:35 -04:00
dependabot[bot] f945868a21 Bump com.gradleup.shadow from 9.3.2 to 9.4.1 (#388) 2026-04-01 22:03:46 +00:00
Adam ee923c0881 Upgrade Gradle wrapper to 9.4.1 (#383) 2026-03-22 16:02:16 +00:00
Adam 80d48ed218 Improve InventoryHolder handling (#382)
* Improve InventoryHolder handling
  * Don't snapshot holder on Paper
  * Ensure viewer has silent enabled first to reduce impact on Spigot
* Remove BlockState reflection
2026-03-20 23:45:18 +00:00
dependabot[bot] 8de1f778f0 Bump net.md-5:SpecialSource from 1.11.5 to 1.11.6 (#379) 2026-03-02 17:24:53 +00:00
dependabot[bot] 8955882737 Bump com.google.errorprone:error_prone_core from 2.46.0 to 2.48.0 (#378) 2026-03-02 17:24:13 +00:00
dependabot[bot] 037b3f89cd Bump com.gradleup.shadow from 9.3.1 to 9.3.2 (#377) 2026-03-02 17:23:37 +00:00
dependabot[bot] 43b4360bb6 Bump org.jetbrains:annotations from 26.0.2-1 to 26.1.0 (#376) 2026-03-02 17:23:03 +00:00
dependabot[bot] e03c43555d Bump actions/upload-artifact from 6 to 7 (#375)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-02 12:20:05 -05:00
dependabot[bot] 43a13e6254 Bump actions/download-artifact from 7 to 8 (#374)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-02 12:19:50 -05:00
Jikoo ab3dddbc19 Update Spigot revision
This appears to compile, but will need testing before a release. Spigot removed the renames they used to apply to all internal classes.
2026-03-02 10:47:10 -05:00
Jikoo d35fc6713b Add links to all official download sources
Some are still pending approval that probably won't happen until Monday, but oh well.
2026-01-18 01:05:43 -05:00
Jikoo 9c8a16adc9 Fix external releases
Add loaders to mc-publish
Fix version parsing for Hangar. The trim command was added in jq 1.8.
2026-01-18 00:37:10 -05:00
Jikoo b93900cf3b Bump version to 5.3.1-SNAPSHOT for development 2026-01-17 23:57:47 -05:00
Jikoo 63fccdcf91 Bump version to 5.3.0 for release 2026-01-17 23:57:38 -05:00
dependabot[bot]andJikoo 960acbfe9d Bump errorprone versions (#370)
* Bump com.google.errorprone:error_prone_core from 2.45.0 to 2.46.0

Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.45.0 to 2.46.0.
- [Release notes](https://github.com/google/error-prone/releases)
- [Commits](https://github.com/google/error-prone/compare/v2.45.0...v2.46.0)

---
updated-dependencies:
- dependency-name: com.google.errorprone:error_prone_core
  dependency-version: 2.46.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump errorprone-gradle-plugin to 4.4.0

Resolves issues with missing flag required for errorprone-core

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jikoo <jikoo.games@gmail.com>
2026-01-18 02:37:20 +00:00
dependabot[bot] 3c904499c5 Bump com.gradleup.shadow from 9.2.2 to 9.3.1 (#369) 2026-01-17 16:54:05 +00:00
Adam baa6b3d734 Add profile cache (#368)
Instead of reading every single player file from disk when doing a fuzzy match, we now do a single lookup from a SQLite database. The database is populated once with all existing players' names on startup, then maintained when players join. This is a massive performance boost for servers that have high player counts or run on spinning disks.

Lookups now require that the first character of the target player's name be correct (case-insensitive). For Geyser-like names, this extends to the first character of their real name. For example, "XxXJohnMinecraftXxX" can no longer be located by a "johnminecraft" search. A search for "xjohnminecraft" could be used instead. A Geyser player ".FranMinecraft" would require ".f" to be eligible, i.e. "franmc" cannot produce the correct result while ".franmc" might.
2026-01-17 11:50:23 -05:00
Adam 7f6c339e06 Add option to check permissions with toggle (#361)
* Promote Permissions to API
* Document permissions
* Add method for checking a toggle with permissions
2026-01-03 12:20:58 -05:00
dependabot[bot] 00736c8d30 Bump actions/download-artifact from 6 to 7 (#364)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 12:12:35 -05:00
dependabot[bot] cb1ec77c24 Bump actions/upload-artifact from 5 to 6 (#363)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 12:12:25 -05:00
dependabot[bot] c8c8a72819 Bump actions/cache from 4 to 5 (#362)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 12:12:14 -05:00
Alessandro 16f91ddc9f feat: add use sub-permissions 2026-01-01 08:55:43 -05:00
Adam c83511e475 Upload to Modrinth and Hangar (#360)
* Replace curseforge-upload with mc-publish
* Use anchors for common configurations
* Convert script to a shared run step
2025-12-31 14:39:53 -05:00
Jikoo c095a78013 Bump version to 5.2.1-SNAPSHOT for development 2025-12-17 15:29:26 -05:00
156 changed files with 4270 additions and 2767 deletions

No files matched your search

+9
View File
@@ -8,3 +8,12 @@ updates:
directory: "/"
schedule:
interval: "monthly"
ignore:
# The SQLite JDBC is provided by Spigot and, for now, Paper.
# To ensure it is still present even if Paper stops providing it,
# we need to declare it as a library.
# To prevent needlessly downloading (and loading) a second copy,
# we want to ensure that we are using the provided version.
- dependency-name: "org.xerial:sqlite-jdbc"
# Spigot and Spigot API updates are manual.
- dependency-name: "org.spigotmc:*"
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
# Note: this is directly from GitHub's example for using data from a triggering workflow:
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow
- name: 'Download artifact'
uses: actions/github-script@v8
uses: actions/github-script@v9
with:
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
+3 -14
View File
@@ -20,28 +20,17 @@ jobs:
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
# We can't use 'maven' prebuilt cache setup because it requires that the project have a pom file.
# BuildTools installs to Maven local if available, so it's easier to just rely on that.
- name: Cache Spigot dependency
uses: actions/cache@v4
with:
path: |
~/.m2/repository/org/spigotmc/
key: ${{ runner.os }}-buildtools-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-buildtools-
java-version: '25'
- uses: gradle/actions/setup-gradle@v5
- name: Build with Gradle
run: ./gradlew clean build
run: ./gradlew build
# Upload artifacts
- name: Upload Distributable Jar
id: upload-final
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: dist
path: ./dist/*
+2 -2
View File
@@ -13,14 +13,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download build
uses: actions/download-artifact@v6
uses: actions/download-artifact@v8
with:
name: dist
path: dist
- name: Create Release
id: create-release
uses: softprops/action-gh-release@v2.5.0
uses: softprops/action-gh-release@v3.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
+91 -19
View File
@@ -1,4 +1,4 @@
name: Release to CurseForge
name: Release to external sites
on:
release:
@@ -8,30 +8,102 @@ jobs:
curseforge_release:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v6
with:
fetch-depth: 0
- &parse-paper-versions
name: Parse Paper Versions
id: parse_versions
run: |
# Find line declaring Paper versions.
raw=$(grep "\\*\\*Paper:\\*\\*" <<< "${{ github.event.release.body }}")
- name: Fetch Github Release Asset
# Enable extended glob pattern to match 0 or more whitespace characters.
shopt -s extglob
# Trim Paper versions identifier prefix.
raw=${raw/*([[:space:]])'**'Paper:'**'*([[:space:]])/}
# Replace commas and optional spaces with a newline.
raw=${raw//,*([[:space:]])/$'\n'}
# Turn extglob back off.
shopt -u extglob
echo "$raw"
printf "PAPER_VERSIONS<<EOF\n%s\nEOF\n" "$raw" >> "$GITHUB_OUTPUT"
- &fetch-release-asset
name: Fetch Github Release Asset
uses: dsaltares/fetch-gh-release-asset@1.1.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
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
uses: Kira-NT/mc-publish@v3.3
with:
token: "${{ secrets.CURSEFORGE_TOKEN }}"
project_id: 31432
game_endpoint: minecraft
file_path: ./OpenInv.jar
display_name: "${{ github.event.release.name }}"
game_versions: "${{ env.CURSEFORGE_MINECRAFT_VERSIONS }}"
release_type: release
changelog_type: markdown
changelog: "${{ github.event.release.body }}"
curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }}
curseforge-id: 31432
files: ./OpenInv.jar
game-versions: "${{ steps.parse_versions.outputs.PAPER_VERSIONS }}"
game-version-filter: releases
loaders: |
spigot
paper
folia
modrinth_release:
runs-on: ubuntu-latest
steps:
- *parse-paper-versions
- *fetch-release-asset
- name: Create Modrinth Release
uses: Kira-NT/mc-publish@v3.3
with:
modrinth-id: 1UlvXbzL
modrinth-featured: false
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
files: ./OpenInv.jar
game-versions: "${{ steps.parse_versions.outputs.PAPER_VERSIONS }}"
game-version-filter: releases
loaders: |
spigot
paper
folia
hangar_release:
runs-on: ubuntu-latest
steps:
- name: Parse Hangar Paper Versions
id: parse_versions
run: |
# Find line declaring Paper versions.
raw=$(grep "\\*\\*Paper:\\*\\*" <<< "${{ github.event.release.body }}")
# Trim Paper versions identifier prefix.
raw="${raw/'**'Paper:'**'/}"
# Trim leading and trailing spaces.
raw="${raw##[[:space:]]}"
raw="${raw%%[[:space:]]}"
# Generate JSON for Hangar. GitHub Actions provides jq 1.7 in the 24.04 image.
# Split on comma and optional spaces.
hangar_versions=$(jq -nc --arg versions "$raw" '{"PAPER": $versions | split(", *";null)}')
echo "$hangar_versions"
echo "HANGAR_PAPER_VERSIONS=$hangar_versions" >> "$GITHUB_OUTPUT"
- *fetch-release-asset
- name: Create Hangar Release
uses: benwoo1110/hangar-upload-action@v1
with:
api_token: ${{ secrets.HANGAR_TOKEN }}
slug: 'OpenInv'
version: ${{ github.event.release.tag_name }}
channel: release
description: "${{ github.event.release.body }}"
files: |-
[
{
"path": "./OpenInv.jar",
"platforms": ["PAPER"]
}
]
platform_dependencies: "${{ steps.parse_versions.outputs.HANGAR_PAPER_VERSIONS }}"
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
run: |
mkdir -p ./pr
echo ${{ github.event.number }} > ./pr/pr_number
- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v7
with:
name: pr_number
path: pr/
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
- name: Build resource pack
id: upload-resource-pack
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: openinv-legibility-pack
path: ./resource-pack/openinv-legibility-pack/
+1
View File
@@ -11,3 +11,4 @@
**/dist/
**/dependency-reduced-pom.xml
**/pom.xml.versionsBackup
**/.vscode/
+4 -1
View File
@@ -1,8 +1,10 @@
## About
OpenInv is a [Bukkit plugin](https://dev.bukkit.org/projects/openinv) which allows users to open and edit anyone's
OpenInv is a Bukkit plugin which allows users to open and edit anyone's
inventory or ender chest - online or not!
Downloads are available on [GitHub](https://github.com/Jikoo/OpenInv/releases), [DBO](https://dev.bukkit.org/projects/openinv)/[CurseForge](https://www.curseforge.com/minecraft/bukkit-plugins/openinv), [Modrinth](https://modrinth.com/plugin/openinv), and [Hangar](https://hangar.papermc.io/jikoo/OpenInv).
## Features
- **OpenInv**: Open anyone's inventory, even if they're offline.
@@ -17,6 +19,7 @@ inventory or ender chest - online or not!
- Cross-world support! Allow access only from the same world.
- **SilentContainer**: Open containers without displaying an animation or making sound.
- **AnyContainer**: Open containers, even if blocked by ocelots or blocks.
- **Resource Pack Support**: Personalize view using resource pack tricks like custom fonts and characters. See [the wiki](https://github.com/Jikoo/OpenInv/wiki/Customizing-Inventories) for details.
## Commands
+12 -2
View File
@@ -1,11 +1,21 @@
plugins {
`openinv-base`
repositories {
mavenCentral()
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
}
dependencies {
compileOnly(libs.spigotapi)
implementation(project(":openinvapi"))
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(21)
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
tasks.processResources {
expand("version" to version)
}
+17 -1
View File
@@ -1,8 +1,24 @@
plugins {
`openinv-base`
`maven-publish`
}
repositories {
mavenCentral()
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
}
dependencies {
compileOnly(libs.spigotapi)
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(21)
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
publishing {
publications {
create<MavenPublication>("jitpack") {
@@ -23,6 +23,7 @@ import org.bukkit.block.EnderChest;
import org.bukkit.block.data.Directional;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.util.BoundingBox;
import org.jetbrains.annotations.NotNull;
@@ -119,4 +120,12 @@ public interface IAnySilentContainer {
|| holder instanceof org.bukkit.block.Barrel;
}
/**
* Check if the given {@link Inventory} belongs to a container which can be unblocked or silenced.
*
* @param inventory the potential container inventory
* @return true if the type is a supported container
*/
boolean isAnySilentContainer(@NotNull Inventory inventory);
}
@@ -0,0 +1,128 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.util;
import org.bukkit.permissions.Permissible;
import org.jetbrains.annotations.NotNull;
/**
* An enum containing all permissions directly checked by OpenInv.
*
* <p>Note that this is not an exhaustive list! This does not contain
* all permissions managed by Bukkit, largely parent nodes.</p>
*/
public enum Permissions {
/// Permission to open one's own inventory.
INVENTORY_OPEN_SELF("inventory.open.self"),
/// Permission to open someone else's inventory.
INVENTORY_OPEN_OTHER("inventory.open.other"),
/**
* Permission to edit one's own inventory.
*
* <p>Note that this does not guarantee that the user has access to open the inventory!
* Be sure to check {@link #INVENTORY_OPEN_SELF} first.</p>
*/
INVENTORY_EDIT_SELF("inventory.edit.self"),
/**
* Permission to edit someone else's inventory.
*
* <p>Note that this does not guarantee that the user has access to open the inventory!
* Be sure to check {@link #INVENTORY_OPEN_OTHER} first.</p>
*/
INVENTORY_EDIT_OTHER("inventory.edit.other"),
/// Permission to insert any item into the head slot.
INVENTORY_SLOT_HEAD_ANY("inventory.slot.head.any"),
/// Permission to insert any item into the chest slot.
INVENTORY_SLOT_CHEST_ANY("inventory.slot.chest.any"),
/// Permission to insert any item into the legs slot.
INVENTORY_SLOT_LEGS_ANY("inventory.slot.legs.any"),
/// Permission to insert any item into the feet slot.
INVENTORY_SLOT_FEET_ANY("inventory.slot.feet.any"),
/// Permission to drop items as the player via the drop slot.
INVENTORY_SLOT_DROP("inventory.slot.drop"),
/// Permission to open one's own ender chest.
ENDERCHEST_OPEN_SELF("enderchest.open.self"),
/// Permission to open someone else's ender chest.
ENDERCHEST_OPEN_OTHER("enderchest.open.other"),
/**
* Permission to edit one's own ender chest.
*
* <p>Note that this does not guarantee that the user has access to open the inventory!
* Be sure to check {@link #ENDERCHEST_OPEN_SELF} first.</p>
*/
ENDERCHEST_EDIT_SELF("enderchest.edit.self"),
/**
* Permission to edit someone else's ender chest.
*
* <p>Note that this does not guarantee that the user has access to open the inventory!
* Be sure to check {@link #ENDERCHEST_OPEN_OTHER} first.</p>
*/
ENDERCHEST_EDIT_OTHER("enderchest.edit.other"),
/// Permission to clear one's own inventory.
CLEAR_SELF("clear.self"),
/// Permission to clear someone else's inventory.
CLEAR_OTHER("clear.other"),
/// Permission to view inventories and ender chests from other worlds.
ACCESS_CROSSWORLD("access.crossworld"),
/// Permission to access offline players' inventories and ender chests.
ACCESS_OFFLINE("access.offline"),
/// Permission to access online players' inventories and ender chests.
ACCESS_ONLINE("access.online"),
/// Permission granting the ability to edit players with the same access level.
ACCESS_EQUAL_EDIT("access.equal.edit"),
/// Permission to view, but not edit, players with the same access level.
ACCESS_EQUAL_VIEW("access.equal.view"),
/// Permission to deny access to players with the same access level.
ACCESS_EQUAL_DENY("access.equal.deny"),
/// Permission to perform inventory interaction while in spectator mode.
SPECTATE_CLICK("spectate.click"),
/// Permission to use the AnyContainer feature.
CONTAINER_ANY("container.any"),
/// Permission to use the AnyContainer feature but not the command to toggle it.
CONTAINER_ANY_USE("container.any.use"),
/// Permission to use the SilentContainer feature.
CONTAINER_SILENT("container.silent"),
/// Permission to use the SilentContainer feature but not the command to toggle it.
CONTAINER_SILENT_USE("container.silent.use"),
/// Permission to search inventories and ender chests.
SEARCH_INVENTORY("search.inventory"),
/// Permission to search containers.
SEARCH_CONTAINER("search.container");
private final String permission;
Permissions(String permission) {
this.permission = "openinv." + permission;
}
/**
* Check if a {@link Permissible} has this permission.
*
* @param permissible the Permissible
* @return true if the permission is granted
*/
public boolean hasPermission(@NotNull Permissible permissible) {
return permissible.hasPermission(permission);
}
}
@@ -1,5 +1,6 @@
package com.lishid.openinv.util.setting;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
@@ -24,6 +25,15 @@ public interface PlayerToggle {
*/
boolean is(@NotNull UUID uuid);
/**
* Get the state of the toggle for a particular {@link Player},
* accounting for permissions required to use the feature.
*
* @param player the player
* @return true if the setting is enabled and the player has the required permissions
*/
boolean is(@NotNull Player player);
/**
* Set the state of the toggle for a particular player ID.
*
@@ -1,5 +1,7 @@
package com.lishid.openinv.util.setting;
import com.lishid.openinv.util.Permissions;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView;
@@ -19,8 +21,20 @@ import java.util.UUID;
public final class PlayerToggles {
private static final Map<String, PlayerToggle> TOGGLES = new HashMap<>();
private static final PlayerToggle ANY = add(new MemoryToggle("AnyContainer"));
private static final PlayerToggle SILENT = add(new MemoryToggle("SilentContainer"));
private static final PlayerToggle ANY = add(new MemoryToggle("AnyContainer") {
@Override
public boolean is(@NotNull Player player) {
return is(player.getUniqueId())
&& (Permissions.CONTAINER_ANY.hasPermission(player) || Permissions.CONTAINER_ANY_USE.hasPermission(player));
}
});
private static final PlayerToggle SILENT = add(new MemoryToggle("SilentContainer") {
@Override
public boolean is(@NotNull Player player) {
return is(player.getUniqueId())
&& (Permissions.CONTAINER_SILENT.hasPermission(player) || Permissions.CONTAINER_SILENT_USE.hasPermission(player));
}
});
/**
* Get the AnyContainer toggle.
@@ -72,7 +86,7 @@ public final class PlayerToggles {
throw new IllegalStateException("Cannot create instance of utility class.");
}
private static class MemoryToggle implements PlayerToggle {
private static abstract class MemoryToggle implements PlayerToggle {
private final @NotNull Set<UUID> enabled;
private final @NotNull String name;
+25 -6
View File
@@ -2,21 +2,40 @@ plugins {
`java-library`
alias(libs.plugins.paperweight) apply false
alias(libs.plugins.shadow) apply false
id(libs.plugins.errorprone.gradle.get().pluginId) apply false
alias(libs.plugins.errorprone.gradle)
}
// Set by Spigot module, used by Paper module to convert to Spigot's version of Mojang mappings.
project.ext.set("craftbukkitPackage", "UNKNOWN")
repositories {
maven("https://repo.papermc.io/repository/maven-public/")
}
// Allow submodules to target higher Java release versions.
// Not currently necessary (as lowest supported version is in the 1.21 range)
// but may become relevant in the future.
java.disableAutoTargetJvm()
subprojects {
apply(plugin = "java-library")
apply(plugin = rootProject.libs.plugins.errorprone.gradle.get().pluginId)
repositories {
mavenCentral()
}
dependencies {
compileOnly(rootProject.libs.jspecify)
compileOnly(rootProject.libs.annotations)
errorprone(rootProject.libs.errorprone.core)
}
tasks {
withType<JavaCompile>().configureEach {
options.encoding = Charsets.UTF_8.name()
}
withType<Javadoc>().configureEach {
options.encoding = Charsets.UTF_8.name()
}
}
}
// Task to delete ./dist where final files are output.
tasks.register("cleanDist") {
delete("dist")
-6
View File
@@ -6,9 +6,3 @@ repositories {
gradlePluginPortal()
mavenCentral()
}
dependencies {
val libs = project.extensions.getByType(VersionCatalogsExtension::class.java).named("libs")
implementation(libs.findLibrary("specialsource").orElseThrow())
implementation(libs.findLibrary("errorprone-gradle").orElseThrow())
}
-7
View File
@@ -1,7 +0,0 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
@@ -16,7 +16,7 @@ abstract class BuildToolsValueSource : ValueSource<File, BuildToolsValueSource.P
abstract val exec: ExecOperations
interface Parameters : ValueSourceParameters {
val mavenLocal: Property<File>
val installDir: DirectoryProperty
val workingDir: DirectoryProperty
val spigotVersion: Property<String>
@@ -31,11 +31,11 @@ abstract class BuildToolsValueSource : ValueSource<File, BuildToolsValueSource.P
override fun obtain(): File {
val version = parameters.spigotVersion.get()
val revision = parameters.spigotRevision.get()
val installLocation = getInstallLocation(version)
val spigotLocation = parameters.installDir.get().asFile.resolve("spigot-$version.jar")
// If Spigot is already installed, don't reinstall.
if (!parameters.ignoreCached.get() && installLocation.exists()) {
if (!parameters.ignoreCached.get() && spigotLocation.exists()) {
println("Skipping Spigot installation, $version is present")
return installLocation
return spigotLocation
}
val buildTools = installBuildTools(parameters.workingDir.get().asFile)
@@ -47,22 +47,29 @@ abstract class BuildToolsValueSource : ValueSource<File, BuildToolsValueSource.P
executable = parameters.javaExecutable.get()
workingDir = buildTools.parentFile
classpath(buildTools)
args = listOf("--nogui", "--rev", revision, "--remapped")
args = listOf("--nogui", "--rev", revision)
}.rethrowFailure()
val spigotBuild = buildTools.parentFile.resolve("Spigot/Spigot-Server/target/spigot-$version.jar")
if (!spigotBuild.exists()) {
throw IllegalStateException(
"Spigot build completed, but $spigotBuild does not exist! Did BuildTools change output location?"
)
}
spigotBuild.copyTo(spigotLocation, overwrite = true)
// Mark work for delete.
cleanUp(buildTools.parentFile)
if (!installLocation.exists()) {
if (!spigotLocation.exists()) {
throw IllegalStateException(
"Failed to install Spigot $version from $revision. Does the revision point to a different version?"
)
}
return installLocation
}
private fun getInstallLocation(version: String): File {
return parameters.mavenLocal.get().resolve("org/spigotmc/spigot/$version/spigot-$version-remapped-mojang.jar")
return spigotLocation
}
private fun installBuildTools(workingDir: File): File {
@@ -12,9 +12,7 @@ abstract class SpigotDependencyExtension(
.convention(version.map {
it.replace("-R\\d+\\.\\d+-SNAPSHOT".toRegex(), "")
})
val configuration = objects.property(String::class.java)
val classifier = objects.property(String::class.java).convention("remapped-mojang")
val ext = objects.property(String::class.java)
val classifier = objects.property(String::class.java).convention("")
val java = objects.property(JavaToolchainSpec::class.java)
val ignoreCached = objects.property(Boolean::class.java).convention(false)
@@ -1,56 +0,0 @@
package com.github.jikoo.openinv
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.Usage
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.register
import java.nio.file.Paths
class SpigotReobf : Plugin<Project> {
companion object {
const val ARTIFACT_CONFIG = "reobf"
}
override fun apply(target: Project) {
// Re-use extension from Spigot dependency declaration if available to reduce configuration requirements.
val spigotExt = target.dependencies.extensions.findByType(SpigotDependencyExtension::class.java)
?: target.dependencies.extensions.create(
"spigot",
SpigotDependencyExtension::class.java,
target.objects
)
val mvnLocal = target.repositories.mavenLocal()
val reobfTask = target.tasks.register<SpigotReobfTask>("reobfTask") {
dependsOn(target.tasks.named("shadowJar"))
// ShadowJar extends Jar, so this should be a safe way to get the result without having
// to jump through hoops and shift around shadow declarations in the rest of the project.
inputFile.convention(target.tasks.named<Jar>("shadowJar").get().archiveFile)
spigotVersion.convention(spigotExt.version)
getMavenLocal().set(Paths.get(mvnLocal.url).toFile())
}
// Set up configuration for producing reobf jar.
target.configurations.consumable(ARTIFACT_CONFIG) {
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, target.objects.named(Category.LIBRARY))
attribute(Usage.USAGE_ATTRIBUTE, target.objects.named(Usage.JAVA_RUNTIME))
attribute(Bundling.BUNDLING_ATTRIBUTE, target.objects.named(Bundling.EXTERNAL))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, target.objects.named(LibraryElements.JAR))
}
}
// Add artifact from reobf task.
target.artifacts {
add(ARTIFACT_CONFIG, reobfTask)
}
}
}
@@ -1,85 +0,0 @@
package com.github.jikoo.openinv
import net.md_5.specialsource.Jar
import net.md_5.specialsource.JarMapping
import net.md_5.specialsource.JarRemapper
import net.md_5.specialsource.RemapperProcessor
import net.md_5.specialsource.provider.JarProvider
import net.md_5.specialsource.provider.JointProvider
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import java.io.File
abstract class SpigotReobfTask : org.gradle.api.tasks.bundling.Jar() {
@get:Input
val spigotVersion: Property<String> = objectFactory.property(String::class.java)
@get:InputFile
val inputFile: RegularFileProperty = objectFactory.fileProperty()
@get:Input
val intermediaryClassifier: Property<String> = objectFactory.property(String::class.java).convention("mojang-mapped")
private val mavenLocal: Property<File> = objectFactory.property(File::class.java)
init {
archiveClassifier.convention(SpigotReobf.ARTIFACT_CONFIG)
}
@TaskAction
override fun copy() {
val spigotVer = spigotVersion.get()
val inFile = inputFile.get().asFile
val obfPath = inFile.resolveSibling(inFile.name.replace(".jar", "-${intermediaryClassifier.get()}.jar"))
// https://www.spigotmc.org/threads/510208/#post-4184317
val repo = mavenLocal.get()
val spigotDir = repo.resolve("org/spigotmc/spigot/$spigotVer/")
val mappingDir = repo.resolve("org/spigotmc/minecraft-server/$spigotVer/")
// Remap original Mojang-mapped jar to obfuscated intermediary
val mojangServer = spigotDir.resolve("spigot-$spigotVer-remapped-mojang.jar")
val mojangMappings = mappingDir.resolve("minecraft-server-$spigotVer-maps-mojang.txt")
remapPartial(mojangServer, mojangMappings, inFile, obfPath, true)
// Remap obfuscated intermediary jar to Spigot and replace original
val obfServer = spigotDir.resolve("spigot-$spigotVer-remapped-obf.jar")
val spigotMappings = mappingDir.resolve("minecraft-server-$spigotVer-maps-spigot.csrg")
remapPartial(obfServer, spigotMappings, obfPath, archiveFile.get().asFile, false)
}
private fun remapPartial(server: File, mapping: File, input: File, output: File, reverse: Boolean) {
val jarMapping = JarMapping()
jarMapping.loadMappings(mapping.path, reverse, false, null, null)
val inheritance = JointProvider()
jarMapping.setFallbackInheritanceProvider(inheritance)
// Equivalent of --live with server jar on classpath.
val serverJar = Jar.init(server)
inheritance.add(JarProvider(serverJar))
val inputJar = Jar.init(input)
inheritance.add(JarProvider(inputJar))
// Remap reflective access.
val preprocessor = RemapperProcessor(null, jarMapping, null)
val remapper = JarRemapper(preprocessor, jarMapping, null)
remapper.remapJar(inputJar, output, emptySet())
serverJar.close()
inputJar.close()
}
@Internal
internal fun getMavenLocal(): Property<File> {
return mavenLocal
}
}
@@ -4,8 +4,7 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.kotlin.dsl.create
import java.nio.file.Paths
import java.io.File
import javax.inject.Inject
abstract class SpigotSetup : Plugin<Project> {
@@ -24,17 +23,15 @@ abstract class SpigotSetup : Plugin<Project> {
target.objects
)
val mvnLocal = target.repositories.mavenLocal()
target.afterEvaluate {
// Get Java requirements, defaulting to version used for compilation.
spigotExt.java.convention(target.extensions.getByType(JavaPluginExtension::class.java).toolchain)
val launcher = javaToolchainService.launcherFor(spigotExt.java.get()).get()
// Install Spigot with BuildTools.
target.providers.of(BuildToolsValueSource::class.java) {
val spigot: File = target.providers.of(BuildToolsValueSource::class.java) {
parameters {
mavenLocal.set(Paths.get(mvnLocal.url).toFile())
installDir.set(target.gradle.gradleUserHomeDir.resolve("caches/spigot"))
workingDir.set(target.layout.buildDirectory.dir("tmp/buildtools"))
spigotVersion.set(spigotExt.version)
spigotRevision.set(spigotExt.revision)
@@ -45,14 +42,7 @@ abstract class SpigotSetup : Plugin<Project> {
}.get()
// Add Spigot dependency.
val dependency = target.dependencies.create(
"org.spigotmc",
"spigot",
spigotExt.version.get(),
spigotExt.configuration.orNull,
spigotExt.classifier.orNull,
spigotExt.ext.orNull
)
val dependency = target.dependencies.create(files(spigot))
target.dependencies.add("compileOnly", dependency)
}
}
@@ -1,31 +0,0 @@
plugins {
`java-library`
id("net.ltgt.errorprone")
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(21)
}
repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
}
dependencies {
val libs = versionCatalogs.named("libs")
compileOnly(libs.findLibrary("annotations").orElseThrow())
compileOnly(libs.findLibrary("spigotapi").orElseThrow())
errorprone(libs.findLibrary("errorprone-core").orElseThrow())
}
tasks {
withType<JavaCompile>().configureEach {
options.release = 21
options.encoding = Charsets.UTF_8.name()
}
withType<Javadoc>().configureEach {
options.encoding = Charsets.UTF_8.name()
}
}
+14 -2
View File
@@ -1,5 +1,17 @@
plugins {
`openinv-base`
repositories {
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
}
dependencies {
compileOnly(libs.spigotapi)
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(21)
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
dependencies {
@@ -8,41 +8,15 @@ import org.bukkit.block.EnderChest;
import org.bukkit.block.ShulkerBox;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Chest;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Method;
public abstract class AnySilentContainerBase implements IAnySilentContainer {
private static final @Nullable Method BLOCK_GET_STATE_BOOLEAN;
static {
@Nullable Method getState;
try {
//noinspection JavaReflectionMemberAccess
getState = Block.class.getMethod("getState", boolean.class);
} catch (NoSuchMethodException e) {
getState = null;
}
BLOCK_GET_STATE_BOOLEAN = getState;
}
private static BlockState getBlockState(Block block) {
// Paper: Get state without snapshotting.
if (BLOCK_GET_STATE_BOOLEAN != null) {
try {
return (BlockState) BLOCK_GET_STATE_BOOLEAN.invoke(block, false);
} catch (ReflectiveOperationException ignored) {
// If we encounter an issue, fall through to regular snapshotting method.
}
}
return block.getState();
}
@Override
public boolean isAnyContainerNeeded(@NotNull Block block) {
BlockState blockState = getBlockState(block);
BlockState blockState = getState(block);
// Barrels do not require AnyContainer.
if (blockState instanceof Barrel) {
@@ -100,7 +74,16 @@ public abstract class AnySilentContainerBase implements IAnySilentContainer {
@Override
public boolean isAnySilentContainer(@NotNull Block block) {
return isAnySilentContainer(getBlockState(block));
return isAnySilentContainer(getState(block));
}
@Override
public boolean isAnySilentContainer(@NotNull Inventory inventory) {
return isAnySilentContainer(getHolder(inventory));
}
protected abstract BlockState getState(@NotNull Block block);
protected abstract InventoryHolder getHolder(@NotNull Inventory inventory);
}
@@ -1,66 +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 <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.util;
import org.bukkit.permissions.Permissible;
import org.jetbrains.annotations.NotNull;
public enum Permissions {
INVENTORY_OPEN_SELF("inventory.open.self"),
INVENTORY_OPEN_OTHER("inventory.open.other"),
INVENTORY_EDIT_SELF("inventory.edit.self"),
INVENTORY_EDIT_OTHER("inventory.edit.other"),
INVENTORY_SLOT_HEAD_ANY("inventory.slot.head.any"),
INVENTORY_SLOT_CHEST_ANY("inventory.slot.chest.any"),
INVENTORY_SLOT_LEGS_ANY("inventory.slot.legs.any"),
INVENTORY_SLOT_FEET_ANY("inventory.slot.feet.any"),
INVENTORY_SLOT_DROP("inventory.slot.drop"),
ENDERCHEST_OPEN_SELF("enderchest.open.self"),
ENDERCHEST_OPEN_OTHER("enderchest.open.other"),
ENDERCHEST_EDIT_SELF("enderchest.edit.self"),
ENDERCHEST_EDIT_OTHER("enderchest.edit.other"),
CLEAR_SELF("clear.self"),
CLEAR_OTHER("clear.other"),
ACCESS_CROSSWORLD("access.crossworld"),
ACCESS_OFFLINE("access.offline"),
ACCESS_ONLINE("access.online"),
ACCESS_EQUAL_EDIT("access.equal.edit"),
ACCESS_EQUAL_VIEW("access.equal.view"),
ACCESS_EQUAL_DENY("access.equal.deny"),
SPECTATE_CLICK("spectate.click"),
CONTAINER_ANY("container.any"),
CONTAINER_SILENT("container.silent"),
SEARCH_INVENTORY("search.inventory"),
SEARCH_CONTAINER("search.container");
private final String permission;
Permissions(String permission) {
this.permission = "openinv." + permission;
}
public boolean hasPermission(@NotNull Permissible permissible) {
return permissible.hasPermission(permission);
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
# Project meta
group=com.lishid.openinv
version=5.2.0
version=5.3.2
description=A Bukkit plugin for opening normally-inaccessible inventories.
# Gradle configuration
+9 -8
View File
@@ -1,24 +1,25 @@
[versions]
spigotapi = "1.21.5-R0.1-SNAPSHOT"
specialsource = "1.11.5"
planarwrappers = "3.3.0"
annotations = "26.0.2-1"
paperweight = "2.0.0-beta.17"
shadow = "9.2.2"
jspecify = "1.0.0"
annotations = "26.1.0"
paperweight = "2.0.0-beta.21"
shadow = "9.4.1"
folia-scheduler-wrapper = "v0.0.3"
errorprone-core = "2.45.0"
errorprone-gradle = "4.2.0"
errorprone-core = "2.49.0"
errorprone-gradle = "5.1.0"
slf4j = "2.0.17"
sqlite-jdbc = "3.49.1.0"
[libraries]
spigotapi = { module = "org.spigotmc:spigot-api", version.ref = "spigotapi" }
specialsource = { module = "net.md-5:SpecialSource", version.ref = "specialsource" }
planarwrappers = { module = "com.github.jikoo:planarwrappers", version.ref = "planarwrappers" }
jspecify = { module = "org.jspecify:jspecify", version.ref = "jspecify" }
annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" }
folia-scheduler-wrapper = { module = "com.github.NahuLD.folia-scheduler-wrapper:folia-scheduler-wrapper", version.ref = "folia-scheduler-wrapper" }
errorprone-core = { module = "com.google.errorprone:error_prone_core", version.ref = "errorprone-core" }
errorprone-gradle = { module = "net.ltgt.gradle:gradle-errorprone-plugin", version.ref = "errorprone-gradle" }
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
sqlite-jdbc = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite-jdbc" }
[plugins]
paperweight = { id = "io.papermc.paperweight.userdev", version.ref = "paperweight" }
Binary file not shown.
+3 -1
View File
@@ -1,7 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+4 -7
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -205,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
Vendored
+82 -94
View File
@@ -1,94 +1,82 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables, and ensure extensions are enabled
setlocal EnableExtensions
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
"%COMSPEC%" /c exit 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
"%COMSPEC%" /c exit 1
:execute
@rem Setup the command line
@rem Execute Gradle
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
:exitWithErrorLevel
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
"%COMSPEC%" /c exit %ERRORLEVEL%
-60
View File
@@ -1,60 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
`openinv-base`
alias(libs.plugins.paperweight)
}
//tasks {
// withType<JavaCompile> {
// // OpenPlayer unchecked warning is due to superclass' messy inheritance and legacy methods.
// options.compilerArgs.add("-Xlint:unchecked")
// // PlayerManager uses "deprecated" method matching vanilla to support legacy save data.
// // While vanilla still feels that it is appropriate to use in the load process, we will too.
// options.compilerArgs.add("-Xlint:deprecation")
// }
//}
configurations.all {
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
val paper = candidates.firstOrNull {
it.id.let { id ->
id is ModuleComponentIdentifier && id.module == "paper-api"
}
}
if (paper != null) {
select(paper)
}
because("module is written for Paper servers")
}
}
dependencies {
implementation(project(":openinvapi"))
implementation(project(":openinvcommon"))
paperweight.paperDevBundle("1.21.11-R0.1-SNAPSHOT")
}
val spigot = tasks.register<ShadowJar>("spigotRelocations") {
dependsOn(tasks.jar)
from(sourceSets.main.get().output)
relocate("com.lishid.openinv.internal.common", "com.lishid.openinv.internal.reobf")
relocate("org.bukkit.craftbukkit", "org.bukkit.craftbukkit.${rootProject.extra["craftbukkitPackage"]}")
archiveClassifier = "spigot"
}
configurations {
consumable("spigotRelocated") {
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
}
}
}
artifacts {
add("spigotRelocated", spigot)
}
@@ -1,50 +0,0 @@
package com.lishid.openinv.internal.common.player;
import com.mojang.logging.LogUtils;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.level.storage.PlayerDataStorage;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.level.storage.ValueOutput;
import org.bukkit.craftbukkit.CraftServer;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
public class OpenPlayer extends BaseOpenPlayer {
protected OpenPlayer(
CraftServer server,
ServerPlayer entity,
PlayerManager manager
) {
super(server, entity, manager);
}
@Override
protected void trySave(ServerPlayer player) {
Logger logger = LogUtils.getLogger();
// See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman)
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(player.problemPath(), logger)) {
PlayerDataStorage worldNbtStorage = server.getServer().getPlayerList().playerIo;
CompoundTag oldData = isOnline()
? null
: worldNbtStorage.load(player.nameAndId()).orElse(null);
CompoundTag playerData = getWritableTag(oldData);
ValueOutput valueOutput = TagValueOutput.createWrappingWithContext(scopedCollector, player.registryAccess(), playerData);
player.saveWithoutId(valueOutput);
saveSafe(player, oldData, playerData, worldNbtStorage);
} catch (Exception e) {
LogUtils.getLogger().warn("Failed to save player data for {}: {}", player.getScoreboardName(), e);
}
}
@Override
protected void remove(@NotNull CompoundTag tag, @NotNull String key) {
tag.remove(key);
}
}
-30
View File
@@ -1,30 +0,0 @@
plugins {
`openinv-base`
alias(libs.plugins.paperweight)
}
configurations.all {
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
val paper = candidates.firstOrNull {
it.id.let { id ->
id is ModuleComponentIdentifier && id.module == "paper-api"
}
}
if (paper != null) {
select(paper)
}
because("module is written for Paper servers")
}
}
dependencies {
implementation(project(":openinvapi"))
implementation(project(":openinvcommon"))
implementation(project(":openinvadaptercommon"))
implementation(project(":openinvadapterpaper1_21_8"))
implementation(project(":openinvadapterpaper1_21_5"))
implementation(project(":openinvadapterpaper1_21_4"))
implementation(project(":openinvadapterpaper1_21_3"))
paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT")
}
@@ -1,80 +0,0 @@
package com.lishid.openinv.internal.paper1_21_1;
import com.lishid.openinv.internal.Accessor;
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.internal.common.container.AnySilentContainer;
import com.lishid.openinv.internal.paper1_21_1.container.OpenInventory;
import com.lishid.openinv.internal.paper1_21_1.container.slot.placeholder.PlaceholderLoader;
import com.lishid.openinv.internal.paper1_21_1.player.PlayerManager;
import com.lishid.openinv.internal.paper1_21_4.container.OpenEnderChest;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.world.Container;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.logging.Level;
import java.util.logging.Logger;
public class InternalAccessor implements Accessor {
private final @NotNull Logger logger;
private final @NotNull PlayerManager manager;
private final @NotNull AnySilentContainer anySilentContainer;
public InternalAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
this.logger = logger;
this.manager = new PlayerManager(logger);
this.anySilentContainer = new AnySilentContainer(logger, lang);
}
@Override
public @NotNull PlayerManager getPlayerManager() {
return manager;
}
@Override
public @NotNull IAnySilentContainer getAnySilentContainer() {
return anySilentContainer;
}
@Override
public @NotNull ISpecialPlayerInventory createPlayerInventory(@NotNull Player player) {
return new OpenInventory(player);
}
@Override
public @NotNull ISpecialEnderChest createEnderChest(@NotNull Player player) {
return new OpenEnderChest(player);
}
@Override
public <T extends ISpecialInventory> @Nullable T get(@NotNull Inventory bukkitInventory, @NotNull Class<T> clazz) {
if (!(bukkitInventory instanceof CraftInventory craftInventory)) {
return null;
}
Container container = craftInventory.getInventory();
if (clazz.isInstance(container)) {
return clazz.cast(container);
}
return null;
}
@Override
public void reload(@NotNull ConfigurationSection config) {
ConfigurationSection placeholders = config.getConfigurationSection("placeholders");
try {
// Reset placeholders to defaults and try to load configuration.
new PlaceholderLoader().load(placeholders);
} catch (Exception e) {
logger.log(Level.WARNING, "Caught exception loading placeholder overrides!", e);
}
}
}
@@ -1,20 +0,0 @@
package com.lishid.openinv.internal.paper1_21_1.container;
import com.lishid.openinv.internal.common.container.slot.Content;
import com.lishid.openinv.internal.paper1_21_1.container.slot.ContentCraftingResult;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class OpenInventory extends com.lishid.openinv.internal.paper1_21_4.container.OpenInventory {
public OpenInventory(@NotNull Player bukkitPlayer) {
super(bukkitPlayer);
}
@Override
protected Content getCraftingResult(@NotNull ServerPlayer serverPlayer) {
return new ContentCraftingResult(serverPlayer);
}
}
@@ -1,74 +0,0 @@
package com.lishid.openinv.internal.paper1_21_1.container.slot.placeholder;
import com.lishid.openinv.internal.paper1_21_3.container.slot.placeholder.NumericDataPlaceholderLoader;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.Registries;
import net.minecraft.util.Unit;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.entity.BannerPattern;
import net.minecraft.world.level.block.entity.BannerPatternLayers;
import net.minecraft.world.level.block.entity.BannerPatterns;
import org.bukkit.craftbukkit.CraftRegistry;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class PlaceholderLoader extends NumericDataPlaceholderLoader {
@Override
protected @NotNull ItemStack defaultCursor() {
// Cursor-like banner with no tooltip
ItemStack itemStack = new ItemStack(Items.WHITE_BANNER);
RegistryAccess minecraftRegistry = CraftRegistry.getMinecraftRegistry();
Registry<BannerPattern> bannerPatterns = minecraftRegistry.registryOrThrow(Registries.BANNER_PATTERN);
BannerPattern halfDiagBottomRight = bannerPatterns.getOrThrow(BannerPatterns.DIAGONAL_RIGHT);
BannerPattern downRight = bannerPatterns.getOrThrow(BannerPatterns.STRIPE_DOWNRIGHT);
BannerPattern border = bannerPatterns.getOrThrow(BannerPatterns.BORDER);
itemStack.set(
DataComponents.BANNER_PATTERNS,
new BannerPatternLayers(
List.of(
new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(halfDiagBottomRight), DyeColor.GRAY),
new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(downRight), DyeColor.WHITE),
new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(border), DyeColor.GRAY)
)
)
);
addModelData(itemStack);
itemStack.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
return itemStack;
}
@Override
protected @NotNull ItemStack defaultShield() {
// Shield with "missing texture" pattern, magenta and black squares.
ItemStack itemStack = new ItemStack(Items.SHIELD);
itemStack.set(DataComponents.BASE_COLOR, DyeColor.MAGENTA);
RegistryAccess minecraftRegistry = CraftRegistry.getMinecraftRegistry();
Registry<BannerPattern> bannerPatterns = minecraftRegistry.registryOrThrow(Registries.BANNER_PATTERN);
BannerPattern halfLeft = bannerPatterns.getOrThrow(BannerPatterns.HALF_VERTICAL);
BannerPattern topLeft = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_TOP_LEFT);
BannerPattern topRight = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_TOP_RIGHT);
BannerPattern bottomLeft = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_BOTTOM_LEFT);
BannerPattern bottomRight = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_BOTTOM_RIGHT);
itemStack.set(DataComponents.BANNER_PATTERNS,
new BannerPatternLayers(
List.of(
new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(halfLeft), DyeColor.BLACK),
new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(topLeft), DyeColor.MAGENTA),
new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(bottomLeft), DyeColor.MAGENTA),
new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(topRight), DyeColor.BLACK),
new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(bottomRight), DyeColor.BLACK)
)
)
);
itemStack.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
addModelData(itemStack);
return itemStack;
}
}
@@ -1,58 +0,0 @@
package com.lishid.openinv.internal.paper1_21_1.player;
import com.mojang.authlib.GameProfile;
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.player.ChatVisiblity;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Logger;
public class PlayerManager extends com.lishid.openinv.internal.paper1_21_4.player.PlayerManager {
public PlayerManager(@NotNull Logger logger) {
super(logger);
}
@Override
protected @NotNull ServerPlayer createNewPlayer(
@NotNull MinecraftServer server,
@NotNull ServerLevel worldServer,
@NotNull final OfflinePlayer offline
) {
// See net.minecraft.server.players.PlayerList#canPlayerLogin(ServerLoginPacketListenerImpl, GameProfile)
// See net.minecraft.server.network.ServerLoginPacketListenerImpl#handleHello(ServerboundHelloPacket)
GameProfile profile = new GameProfile(offline.getUniqueId(),
offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()
);
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);
try {
injectPlayer(server, entity);
} catch (IllegalAccessException e) {
logger.log(
java.util.logging.Level.WARNING,
e,
() -> "Unable to inject ServerPlayer, certain player data may be lost when saving!"
);
}
return entity;
}
}
+18 -16
View File
@@ -1,26 +1,28 @@
plugins {
`openinv-base`
alias(libs.plugins.paperweight)
}
configurations.all {
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
val paper = candidates.firstOrNull {
it.id.let { id ->
id is ModuleComponentIdentifier && id.module == "paper-api"
}
}
if (paper != null) {
select(paper)
}
because("module is written for Paper servers")
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(21)
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
dependencies {
implementation(project(":openinvapi"))
implementation(project(":openinvcommon"))
implementation(project(":openinvadaptercommon"))
implementation(project(":openinvapi")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvcommon")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvadapterpaper26_1")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
implementation(project(":openinvadapterpaper1_21_11")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
paperweight.paperDevBundle("1.21.10-R0.1-SNAPSHOT")
}
@@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.logging.Logger;
public class InternalAccessor extends com.lishid.openinv.internal.common.InternalAccessor {
public class InternalAccessor extends com.lishid.openinv.internal.paper1_21_11.InternalAccessor {
private final @NotNull PlayerManager manager;
@@ -1,7 +1,8 @@
package com.lishid.openinv.internal.paper1_21_10.container;
import com.lishid.openinv.internal.common.container.BaseOpenInventory;
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper1_21_11.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FontDescription;
@@ -47,4 +48,12 @@ public class OpenInventory extends BaseOpenInventory {
return component;
}
@Override
public @Nullable OpenChestMenu<?> createMenu(net.minecraft.world.entity.player.Player player, int i, boolean viewOnly) {
if (player instanceof ServerPlayer serverPlayer) {
return new OpenInventoryMenu(this, serverPlayer, i, viewOnly);
}
return null;
}
}
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper1_21_10.player;
import com.lishid.openinv.internal.common.player.PlayerManager;
import com.lishid.openinv.internal.paper26_1.player.PlayerManager;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.craftbukkit.CraftServer;
@@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
public class OpenPlayer extends com.lishid.openinv.internal.common.player.OpenPlayer {
public class OpenPlayer extends com.lishid.openinv.internal.paper26_1.player.OpenPlayer {
protected OpenPlayer(
CraftServer server,
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.logging.Logger;
public class PlayerManager extends com.lishid.openinv.internal.common.player.PlayerManager {
public class PlayerManager extends com.lishid.openinv.internal.paper26_1.player.PlayerManager {
public PlayerManager(@NotNull Logger logger) {
super(logger);
+25
View File
@@ -0,0 +1,25 @@
plugins {
alias(libs.plugins.paperweight)
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(21)
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
dependencies {
implementation(project(":openinvapi")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvcommon")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvadapterpaper26_1")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
paperweight.paperDevBundle("1.21.11-R0.1-SNAPSHOT")
}
@@ -0,0 +1,29 @@
package com.lishid.openinv.internal.paper1_21_11;
import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.internal.paper1_21_11.container.OpenEnderChest;
import com.lishid.openinv.internal.paper1_21_11.container.OpenInventory;
import com.lishid.openinv.util.lang.LanguageManager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Logger;
public class InternalAccessor extends com.lishid.openinv.internal.paper26_1.InternalAccessor {
public InternalAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
super(logger, lang);
}
@Override
public @NotNull ISpecialEnderChest createEnderChest(@NotNull Player player) {
return new OpenEnderChest(player);
}
@Override
public @NotNull ISpecialPlayerInventory createPlayerInventory(@NotNull Player player) {
return new OpenInventory(player);
}
}
@@ -0,0 +1,25 @@
package com.lishid.openinv.internal.paper1_21_11.container;
import com.lishid.openinv.internal.paper1_21_11.container.menu.OpenEnderChestMenu;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenEnderChest extends com.lishid.openinv.internal.paper26_1.container.OpenEnderChest {
public OpenEnderChest(org.bukkit.entity.Player player) {
super(player);
}
@Override
public @Nullable OpenChestMenu<?> createMenu(Player player, int i, boolean viewOnly) {
if (player instanceof ServerPlayer serverPlayer) {
return new OpenEnderChestMenu(this, serverPlayer, i, viewOnly);
}
return null;
}
}
@@ -0,0 +1,25 @@
package com.lishid.openinv.internal.paper1_21_11.container;
import com.lishid.openinv.internal.paper1_21_11.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenInventory extends com.lishid.openinv.internal.paper26_1.container.OpenInventory {
public OpenInventory(org.bukkit.entity.Player bukkitPlayer) {
super(bukkitPlayer);
}
@Override
public @Nullable OpenChestMenu<?> createMenu(Player player, int i, boolean viewOnly) {
if (player instanceof ServerPlayer serverPlayer) {
return new OpenInventoryMenu(this, serverPlayer, i, viewOnly);
}
return null;
}
}
@@ -0,0 +1,68 @@
package com.lishid.openinv.internal.paper1_21_11.container.menu;
import com.lishid.openinv.internal.paper26_1.container.OpenEnderChest;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenSyncMenu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ClickType;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenEnderChestMenu extends OpenSyncMenu<OpenEnderChest> {
public OpenEnderChestMenu(
OpenEnderChest enderChest,
ServerPlayer viewer,
int containerId,
boolean viewOnly
) {
super(getChestMenuType(enderChest.getContainerSize()), containerId, enderChest, viewer, viewOnly);
}
@Override
public ItemStack quickMoveStack(Player player, int index) {
if (viewOnly) {
return ItemStack.EMPTY;
}
// See ChestMenu
Slot slot = this.slots.get(index);
if (slot.isFake() || !slot.hasItem()) {
return ItemStack.EMPTY;
}
ItemStack itemStack = slot.getItem();
ItemStack original = itemStack.copy();
if (index < topSize) {
if (!this.moveItemStackTo(itemStack, topSize, this.slots.size(), true)) {
return ItemStack.EMPTY;
}
} else if (!this.moveItemStackTo(itemStack, 0, topSize, false)) {
return ItemStack.EMPTY;
}
if (itemStack.isEmpty()) {
slot.setByPlayer(ItemStack.EMPTY);
} else {
slot.setChanged();
}
return original;
}
@Override
public void clicked(int i, int j, ClickType clickType, Player player) {
if (viewOnly) {
if (clickType == ClickType.QUICK_CRAFT) {
sendAllDataToRemote();
}
return;
}
super.clicked(i, j, clickType, player);
}
}
@@ -0,0 +1,28 @@
package com.lishid.openinv.internal.paper1_21_11.container.menu;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.menu.BaseOpenInventoryMenu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ClickType;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenInventoryMenu extends BaseOpenInventoryMenu {
public OpenInventoryMenu(BaseOpenInventory inventory, ServerPlayer viewer, int i, boolean viewOnly) {
super(inventory, viewer, i, viewOnly);
}
@Override
public void clicked(int i, int j, ClickType clickType, Player player) {
if (viewOnly) {
if (clickType == ClickType.QUICK_CRAFT) {
sendAllDataToRemote();
}
return;
}
super.clicked(i, j, clickType, player);
}
}
-29
View File
@@ -1,29 +0,0 @@
plugins {
`openinv-base`
alias(libs.plugins.paperweight)
}
configurations.all {
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
val paper = candidates.firstOrNull {
it.id.let { id ->
id is ModuleComponentIdentifier && id.module == "paper-api"
}
}
if (paper != null) {
select(paper)
}
because("module is written for Paper servers")
}
}
dependencies {
implementation(project(":openinvapi"))
implementation(project(":openinvcommon"))
implementation(project(":openinvadaptercommon"))
implementation(project(":openinvadapterpaper1_21_8"))
implementation(project(":openinvadapterpaper1_21_5"))
implementation(project(":openinvadapterpaper1_21_4"))
paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT")
}
@@ -1,28 +0,0 @@
package com.lishid.openinv.internal.paper1_21_3;
import com.lishid.openinv.internal.paper1_21_3.container.slot.placeholder.NumericDataPlaceholderLoader;
import com.lishid.openinv.util.lang.LanguageManager;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Level;
import java.util.logging.Logger;
public class InternalAccessor extends com.lishid.openinv.internal.paper1_21_4.InternalAccessor {
public InternalAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
super(logger, lang);
}
@Override
public void reload(@NotNull ConfigurationSection config) {
ConfigurationSection placeholders = config.getConfigurationSection("placeholders");
try {
// Reset placeholders to defaults and try to load configuration.
new NumericDataPlaceholderLoader().load(placeholders);
} catch (Exception e) {
logger.log(Level.WARNING, "Caught exception loading placeholder overrides!", e);
}
}
}
@@ -1,12 +0,0 @@
package com.lishid.openinv.internal.paper1_21_3.container.slot.placeholder;
import com.lishid.openinv.internal.paper1_21_4.container.slot.placeholder.CustomModelBase;
import net.minecraft.world.item.component.CustomModelData;
public class NumericDataPlaceholderLoader extends CustomModelBase {
public NumericDataPlaceholderLoader() {
super(new CustomModelData(9999));
}
}
-28
View File
@@ -1,28 +0,0 @@
plugins {
`openinv-base`
alias(libs.plugins.paperweight)
}
configurations.all {
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
val paper = candidates.firstOrNull {
it.id.let { id ->
id is ModuleComponentIdentifier && id.module == "paper-api"
}
}
if (paper != null) {
select(paper)
}
because("module is written for Paper servers")
}
}
dependencies {
implementation(project(":openinvapi"))
implementation(project(":openinvcommon"))
implementation(project(":openinvadaptercommon"))
implementation(project(":openinvadapterpaper1_21_8"))
implementation(project(":openinvadapterpaper1_21_5"))
paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT")
}
@@ -1,28 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.container;
import com.lishid.openinv.internal.paper1_21_4.container.menu.OpenEnderChestMenu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.AbstractContainerMenu;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class OpenEnderChest extends com.lishid.openinv.internal.common.container.OpenEnderChest {
public OpenEnderChest(@NotNull Player player) {
super(player);
}
@Override
public @Nullable OpenEnderChestMenu createMenu(
net.minecraft.world.entity.player.Player player,
int i,
boolean viewOnly
) {
if (player instanceof ServerPlayer serverPlayer) {
return new OpenEnderChestMenu(this, serverPlayer, i, viewOnly);
}
return null;
}
}
@@ -1,191 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.container;
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.common.container.slot.ContentCrafting;
import com.lishid.openinv.internal.common.container.slot.ContentCursor;
import com.lishid.openinv.internal.common.container.slot.ContentDrop;
import com.lishid.openinv.internal.common.container.slot.ContentList;
import com.lishid.openinv.internal.common.container.slot.ContentViewOnly;
import com.lishid.openinv.internal.common.container.slot.SlotViewOnly;
import com.lishid.openinv.internal.common.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper1_21_4.container.bukkit.OpenPlayerInventory;
import com.lishid.openinv.internal.paper1_21_4.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper1_21_4.container.slot.ContentEquipment;
import com.lishid.openinv.internal.paper1_21_4.container.slot.ContentOffHand;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class OpenInventory extends com.lishid.openinv.internal.paper1_21_8.container.OpenInventory {
public OpenInventory(@NotNull org.bukkit.entity.Player bukkitPlayer) {
super(bukkitPlayer);
}
@Override
protected void setupSlots() {
// Top of inventory: Regular contents.
int nextIndex = addMainInventory();
// If inventory is expected size, we can arrange slots to be pretty.
Inventory ownerInv = owner.getInventory();
if (ownerInv.items.size() == 36
&& ownerInv.armor.size() == 4
&& ownerInv.offhand.size() == 1
&& owner.inventoryMenu.getCraftSlots().getContainerSize() == 4) {
// Armor slots: Bottom left.
addArmor(36);
// Off-hand: Below chestplate.
addOffHand(46);
// Drop slot: Bottom right.
slots.set(53, new ContentDrop(owner));
// Cursor slot: Above drop.
slots.set(44, new ContentCursor(owner));
// Crafting is displayed in the bottom right corner.
// As we're using the pretty view, this is a 3x2.
addCrafting(41, true);
return;
}
// Otherwise we'll just add elements linearly.
nextIndex = addArmor(nextIndex);
nextIndex = addOffHand(nextIndex);
nextIndex = addCrafting(nextIndex, false);
slots.set(nextIndex, new ContentCursor(owner));
// Drop slot last.
slots.set(slots.size() - 1, new ContentDrop(owner));
}
private int addMainInventory() {
int listSize = owner.getInventory().items.size();
// Hotbar slots are 0-8. We want those to appear on the bottom of the inventory like a normal player inventory,
// so everything else needs to move up a row.
int hotbarDiff = listSize - 9;
for (int localIndex = 0; localIndex < listSize; ++localIndex) {
InventoryType.SlotType type;
int invIndex;
if (localIndex < hotbarDiff) {
invIndex = localIndex + 9;
type = InventoryType.SlotType.CONTAINER;
} else {
type = InventoryType.SlotType.QUICKBAR;
invIndex = localIndex - hotbarDiff;
}
slots.set(
localIndex,
new ContentList(owner, invIndex, type) {
@Override
public void setHolder(@NotNull ServerPlayer holder) {
items = holder.getInventory().items;
}
}
);
}
return listSize;
}
private int addArmor(int startIndex) {
int listSize = owner.getInventory().armor.size();
for (int i = 0; i < listSize; ++i) {
// Armor slots go bottom to top; boots are slot 0, helmet is slot 3.
// Since we have to display horizontally due to space restrictions,
// making the left side the "top" is more user-friendly.
int armorIndex;
EquipmentSlot slot;
switch (i) {
case 3 -> {
armorIndex = 0;
slot = EquipmentSlot.FEET;
}
case 2 -> {
armorIndex = 1;
slot = EquipmentSlot.LEGS;
}
case 1 -> {
armorIndex = 2;
slot = EquipmentSlot.CHEST;
}
case 0 -> {
armorIndex = 3;
slot = EquipmentSlot.HEAD;
}
default -> {
// In the event that new armor slots are added, they can be placed at the end.
armorIndex = i;
slot = EquipmentSlot.MAINHAND;
}
}
slots.set(startIndex + i, new ContentEquipment(owner, armorIndex, slot));
}
return startIndex + listSize;
}
private int addOffHand(int startIndex) {
int listSize = owner.getInventory().offhand.size();
for (int localIndex = 0; localIndex < listSize; ++localIndex) {
slots.set(startIndex + localIndex, new ContentOffHand(owner, localIndex));
}
return startIndex + listSize;
}
private int addCrafting(int startIndex, boolean pretty) {
int listSize = owner.inventoryMenu.getCraftSlots().getContents().size();
pretty &= listSize == 4;
for (int localIndex = 0; localIndex < listSize; ++localIndex) {
// Pretty display is a 2x2 rather than linear.
// If index is in top row, grid is not 2x2, or pretty is disabled, just use current index.
// Otherwise, subtract 2 and add 9 to start in the same position on the next row.
int modIndex = startIndex + (localIndex < 2 || !pretty ? localIndex : localIndex + 7);
slots.set(modIndex, new ContentCrafting(owner, localIndex));
}
if (pretty) {
slots.set(startIndex + 2, new ContentViewOnly(owner) {
@Override
public Slot asSlot(Container container, int slot, int x, int y) {
return new SlotViewOnly(container, slot, x, y) {
@Override
public ItemStack getOrDefault() {
return Placeholders.craftingOutput;
}
};
}
}
);
slots.set(startIndex + 11, getCraftingResult(owner));
}
return startIndex + listSize;
}
@Override
public @NotNull org.bukkit.inventory.Inventory getBukkitInventory() {
if (bukkitEntity == null) {
bukkitEntity = new OpenPlayerInventory(this);
}
return bukkitEntity;
}
@Override
public @Nullable OpenChestMenu<?> createMenu(Player player, int i, boolean viewOnly) {
if (player instanceof ServerPlayer serverPlayer) {
return new OpenInventoryMenu(this, serverPlayer, i, viewOnly);
}
return null;
}
}
@@ -1,225 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.container.bukkit;
import com.google.common.base.Preconditions;
import com.lishid.openinv.internal.paper1_21_4.container.OpenInventory;
import net.minecraft.core.NonNullList;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Inventory;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class OpenPlayerInventory extends CraftInventory implements PlayerInventory {
public OpenPlayerInventory(@NotNull OpenInventory inventory) {
super(inventory);
}
@Override
public @NotNull OpenInventory getInventory() {
return (OpenInventory) super.getInventory();
}
@Override
public ItemStack @NotNull [] getContents() {
return asCraftMirror(getInventory().getOwnerHandle().getInventory().getContents());
}
@Override
public void setContents(ItemStack[] items) {
Inventory internal = getInventory().getOwnerHandle().getInventory();
int size = internal.getContainerSize();
Preconditions.checkArgument(items.length <= size, "items.length must be <= %s", size);
for (int index = 0; index < size; ++index) {
if (index < items.length) {
internal.setItem(index, CraftItemStack.asNMSCopy(items[index]));
} else {
internal.setItem(index, net.minecraft.world.item.ItemStack.EMPTY);
}
}
}
@Override
public ItemStack @NotNull [] getStorageContents() {
return asCraftMirror(getInventory().getOwnerHandle().getInventory().items);
}
@Override
public void setStorageContents(ItemStack[] items) throws IllegalArgumentException {
NonNullList<net.minecraft.world.item.ItemStack> list = getInventory().getOwnerHandle().getInventory().items;
int size = list.size();
Preconditions.checkArgument(items.length <= size, "items.length must be <= %s", size);
for (int index = 0; index < items.length; ++index) {
list.set(index, CraftItemStack.asNMSCopy(items[index]));
}
}
@Override
public @NotNull InventoryType getType() {
return InventoryType.PLAYER;
}
@Override
public @NotNull Player getHolder() {
return getInventory().getOwner();
}
@Override
public @NotNull ItemStack @NotNull [] getArmorContents() {
return asCraftMirror(getInventory().getOwnerHandle().getInventory().armor);
}
@Override
public void setArmorContents(ItemStack @NotNull [] items) {
NonNullList<net.minecraft.world.item.ItemStack> list = getInventory().getOwnerHandle().getInventory().armor;
int size = list.size();
Preconditions.checkArgument(items.length <= size, "items.length must be <= %s", size);
for (int index = 0; index < items.length; ++index) {
list.set(index, CraftItemStack.asNMSCopy(items[index]));
}
}
@Override
public @NotNull ItemStack @NotNull [] getExtraContents() {
return asCraftMirror(getInventory().getOwnerHandle().getInventory().offhand);
}
@Override
public void setExtraContents(ItemStack @NotNull [] items) {
NonNullList<net.minecraft.world.item.ItemStack> list = getInventory().getOwnerHandle().getInventory().offhand;
int size = list.size();
Preconditions.checkArgument(items.length <= size, "items.length must be <= %s", size);
for (int index = 0; index < items.length; ++index) {
list.set(index, CraftItemStack.asNMSCopy(items[index]));
}
}
@Override
public @NotNull ItemStack getHelmet() {
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory()
.getArmor(EquipmentSlot.HEAD.getIndex()));
}
@Override
public void setHelmet(@Nullable ItemStack helmet) {
getInventory().getOwnerHandle().getInventory().armor
.set(EquipmentSlot.HEAD.getIndex(), CraftItemStack.asNMSCopy(helmet));
}
@Override
public @NotNull ItemStack getChestplate() {
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory()
.getArmor(EquipmentSlot.CHEST.getIndex()));
}
@Override
public void setChestplate(@Nullable ItemStack chestplate) {
getInventory().getOwnerHandle().getInventory().armor
.set(EquipmentSlot.CHEST.getIndex(), CraftItemStack.asNMSCopy(chestplate));
}
@Override
public @NotNull ItemStack getLeggings() {
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory()
.getArmor(EquipmentSlot.LEGS.getIndex()));
}
@Override
public void setLeggings(@Nullable ItemStack leggings) {
getInventory().getOwnerHandle().getInventory().armor
.set(EquipmentSlot.LEGS.getIndex(), CraftItemStack.asNMSCopy(leggings));
}
@Override
public @NotNull ItemStack getBoots() {
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory()
.getArmor(EquipmentSlot.FEET.getIndex()));
}
@Override
public void setBoots(@Nullable ItemStack boots) {
getInventory().getOwnerHandle().getInventory().armor
.set(EquipmentSlot.FEET.getIndex(), CraftItemStack.asNMSCopy(boots));
}
@Override
public @NotNull ItemStack getItemInMainHand() {
Inventory internal = getInventory().getOwnerHandle().getInventory();
return CraftItemStack.asCraftMirror(internal.getItem(internal.selected));
}
@Override
public void setItemInMainHand(@Nullable ItemStack item) {
Inventory internal = getInventory().getOwnerHandle().getInventory();
internal.setItem(internal.selected, CraftItemStack.asNMSCopy(item));
}
@Override
public @NotNull ItemStack getItemInOffHand() {
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory().offhand.getFirst());
}
@Override
public void setItemInOffHand(@Nullable ItemStack item) {
getInventory().getOwnerHandle().getInventory().offhand.set(0, CraftItemStack.asNMSCopy(item));
}
@SuppressWarnings("InlineMeSuggester")
@Deprecated
@Override
public @NotNull ItemStack getItemInHand() {
return getItemInMainHand();
}
@SuppressWarnings("InlineMeSuggester")
@Deprecated
@Override
public void setItemInHand(@Nullable ItemStack stack) {
setItemInMainHand(stack);
}
@Override
public int getHeldItemSlot() {
Inventory internal = getInventory().getOwnerHandle().getInventory();
return internal.items.size() - 9 + internal.selected;
}
@Override
public void setHeldItemSlot(int slot) {
slot %= 9;
getInventory().getOwnerHandle().getInventory().selected = slot;
}
@Override
public @NotNull ItemStack getItem(@NotNull org.bukkit.inventory.EquipmentSlot slot) {
return switch (slot) {
case HAND -> getItemInMainHand();
case OFF_HAND -> getItemInOffHand();
case FEET -> getBoots();
case LEGS -> getLeggings();
case CHEST -> getChestplate();
case HEAD -> getHelmet();
default -> throw new IllegalArgumentException("Unsupported EquipmentSlot " + slot);
};
}
@Override
public void setItem(@NotNull org.bukkit.inventory.EquipmentSlot slot, @Nullable ItemStack item) {
switch (slot) {
case HAND -> setItemInMainHand(item);
case OFF_HAND -> setItemInOffHand(item);
case FEET -> setBoots(item);
case LEGS -> setLeggings(item);
case CHEST -> setChestplate(item);
case HEAD -> setHelmet(item);
default -> throw new IllegalArgumentException("Unsupported EquipmentSlot " + slot);
}
}
}
@@ -1,229 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.container.menu;
import com.google.common.base.Suppliers;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.common.container.slot.SlotPlaceholder;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.inventory.ContainerListener;
import net.minecraft.world.inventory.ContainerSynchronizer;
import net.minecraft.world.inventory.DataSlot;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* An extension of {@link AbstractContainerMenu} that supports {@link SlotPlaceholder placeholders}.
*/
@SuppressWarnings("HidingField")
public abstract class OpenSyncMenu<T extends Container & ISpecialInventory & InternalOwned<ServerPlayer>>
extends OpenChestMenu<T> {
// Syncher fields
private @Nullable ContainerSynchronizer synchronizer;
private final List<DataSlot> dataSlots = new ArrayList<>();
private final IntList remoteDataSlots = new IntArrayList();
private final List<ContainerListener> containerListeners = new ArrayList<>();
private ItemStack remoteCarried = ItemStack.EMPTY;
private boolean suppressRemoteUpdates;
protected OpenSyncMenu(
@NotNull MenuType<ChestMenu> type,
int containerCounter,
@NotNull T container,
@NotNull ServerPlayer viewer,
boolean viewOnly
) {
super(type, containerCounter, container, viewer, viewOnly);
}
// Overrides from here on are purely to modify the sync process to send placeholder items.
@Override
protected @NotNull Slot addSlot(@NotNull Slot slot) {
slot.index = this.slots.size();
this.slots.add(slot);
this.lastSlots.add(ItemStack.EMPTY);
this.remoteSlots.add(ItemStack.EMPTY);
return slot;
}
@Override
protected @NotNull DataSlot addDataSlot(@NotNull DataSlot dataSlot) {
this.dataSlots.add(dataSlot);
this.remoteDataSlots.add(0);
return dataSlot;
}
@Override
protected void addDataSlots(ContainerData containerData) {
for (int i = 0; i < containerData.getCount(); i++) {
this.addDataSlot(DataSlot.forContainer(containerData, i));
}
}
@Override
public void addSlotListener(@NotNull ContainerListener containerListener) {
if (!this.containerListeners.contains(containerListener)) {
this.containerListeners.add(containerListener);
this.broadcastChanges();
}
}
@Override
public void setSynchronizer(@NotNull ContainerSynchronizer containerSynchronizer) {
this.synchronizer = containerSynchronizer;
this.sendAllDataToRemote();
}
@Override
public void sendAllDataToRemote() {
for (int index = 0; index < slots.size(); ++index) {
Slot slot = slots.get(index);
this.remoteSlots.set(index, (slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem()).copy());
}
remoteCarried = getCarried().copy();
for (int index = 0; index < this.dataSlots.size(); ++index) {
this.remoteDataSlots.set(index, this.dataSlots.get(index).get());
}
if (this.synchronizer != null) {
this.synchronizer.sendInitialData(this, this.remoteSlots, this.remoteCarried, this.remoteDataSlots.toIntArray());
}
}
@Override
public void broadcastCarriedItem() {
this.remoteCarried = this.getCarried().copy();
if (this.synchronizer != null) {
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
}
}
@Override
public void removeSlotListener(@NotNull ContainerListener containerListener) {
this.containerListeners.remove(containerListener);
}
@Override
public void broadcastChanges() {
for (int index = 0; index < this.slots.size(); ++index) {
Slot slot = this.slots.get(index);
ItemStack itemstack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
Supplier<ItemStack> supplier = Suppliers.memoize(itemstack::copy);
this.triggerSlotListeners(index, itemstack, supplier);
this.synchronizeSlotToRemote(index, itemstack, supplier);
}
this.synchronizeCarriedToRemote();
for (int index = 0; index < this.dataSlots.size(); ++index) {
DataSlot dataSlot = this.dataSlots.get(index);
int j = dataSlot.get();
if (dataSlot.checkAndClearUpdateFlag()) {
this.updateDataSlotListeners(index, j);
}
this.synchronizeDataSlotToRemote(index, j);
}
}
@Override
public void broadcastFullState() {
for (int index = 0; index < this.slots.size(); ++index) {
ItemStack itemstack = this.slots.get(index).getItem();
this.triggerSlotListeners(index, itemstack, itemstack::copy);
}
for (int index = 0; index < this.dataSlots.size(); ++index) {
DataSlot containerproperty = this.dataSlots.get(index);
if (containerproperty.checkAndClearUpdateFlag()) {
this.updateDataSlotListeners(index, containerproperty.get());
}
}
this.sendAllDataToRemote();
}
private void updateDataSlotListeners(int i, int j) {
for (ContainerListener containerListener : this.containerListeners) {
containerListener.dataChanged(this, i, j);
}
}
private void triggerSlotListeners(int index, ItemStack itemStack, Supplier<ItemStack> supplier) {
ItemStack itemStack1 = this.lastSlots.get(index);
if (!ItemStack.matches(itemStack1, itemStack)) {
ItemStack itemStack2 = supplier.get();
this.lastSlots.set(index, itemStack2);
for (ContainerListener containerListener : this.containerListeners) {
containerListener.slotChanged(this, index, itemStack2);
}
}
}
private void synchronizeSlotToRemote(int i, ItemStack itemStack, Supplier<ItemStack> supplier) {
if (!this.suppressRemoteUpdates) {
ItemStack itemStack1 = this.remoteSlots.get(i);
if (!ItemStack.matches(itemStack1, itemStack)) {
ItemStack itemstack2 = supplier.get();
this.remoteSlots.set(i, itemstack2);
if (this.synchronizer != null) {
this.synchronizer.sendSlotChange(this, i, itemstack2);
}
}
}
}
private void synchronizeDataSlotToRemote(int index, int value) {
if (!this.suppressRemoteUpdates) {
int existing = this.remoteDataSlots.getInt(index);
if (existing != value) {
this.remoteDataSlots.set(index, value);
if (this.synchronizer != null) {
this.synchronizer.sendDataChange(this, index, value);
}
}
}
}
private void synchronizeCarriedToRemote() {
if (!this.suppressRemoteUpdates && !ItemStack.matches(this.getCarried(), this.remoteCarried)) {
this.remoteCarried = this.getCarried().copy();
if (this.synchronizer != null) {
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
}
}
}
@Override
public void setRemoteCarried(ItemStack itemstack) {
this.remoteCarried = itemstack.copy();
}
@Override
public void suppressRemoteUpdates() {
this.suppressRemoteUpdates = true;
}
@Override
public void resumeRemoteUpdates() {
this.suppressRemoteUpdates = false;
}
}
@@ -1,80 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.container.slot;
import com.lishid.openinv.internal.common.container.slot.ContentList;
import com.lishid.openinv.internal.common.container.slot.SlotPlaceholder;
import com.lishid.openinv.internal.common.container.slot.placeholder.Placeholders;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
/**
* A slot for equipment that displays placeholders if empty.
*/
public class ContentEquipment extends ContentList {
private final ItemStack placeholder;
private final EquipmentSlot equipmentSlot;
public ContentEquipment(ServerPlayer holder, int index, EquipmentSlot equipmentSlot) {
super(holder, index, InventoryType.SlotType.ARMOR);
placeholder = switch (equipmentSlot) {
case HEAD -> Placeholders.emptyHelmet;
case CHEST -> Placeholders.emptyChestplate;
case LEGS -> Placeholders.emptyLeggings;
case FEET -> Placeholders.emptyBoots;
default -> Placeholders.emptyOffHand;
};
this.equipmentSlot = equipmentSlot;
}
@Override
public void setHolder(@NotNull ServerPlayer holder) {
this.items = holder.getInventory().armor;
}
@Override
public Slot asSlot(Container container, int slot, int x, int y) {
return new SlotEquipment(container, slot, x, y);
}
public class SlotEquipment extends SlotPlaceholder {
private ServerPlayer viewer;
SlotEquipment(Container container, int index, int x, int y) {
super(container, index, x, y);
}
@Override
public ItemStack getOrDefault() {
ItemStack itemStack = getItem();
if (!itemStack.isEmpty()) {
return itemStack;
}
return placeholder;
}
public EquipmentSlot getEquipmentSlot() {
return equipmentSlot;
}
public void onlyEquipmentFor(ServerPlayer viewer) {
this.viewer = viewer;
}
@Override
public boolean mayPlace(@NotNull ItemStack itemStack) {
if (viewer == null) {
return true;
}
return equipmentSlot == EquipmentSlot.OFFHAND || viewer.getEquipmentSlotForItem(itemStack) == equipmentSlot;
}
}
}
@@ -1,53 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.container.slot;
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.inventory.Slot;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
/**
* A slot for equipment that updates held items if necessary.
*/
public class ContentOffHand extends ContentEquipment {
private ServerPlayer holder;
public ContentOffHand(ServerPlayer holder, int localIndex) {
super(holder, localIndex, EquipmentSlot.OFFHAND);
}
@Override
public void setHolder(@NotNull ServerPlayer holder) {
this.items = holder.getInventory().offhand;
this.holder = holder;
}
@Override
public InventoryType.SlotType getSlotType() {
return InventoryType.SlotType.QUICKBAR;
}
@Override
public Slot asSlot(Container container, int slot, int x, int y) {
return new SlotEquipment(container, slot, x, y) {
@Override
public void setChanged() {
if (BaseOpenPlayer.isConnected(holder.connection) && holder.containerMenu != holder.inventoryMenu) {
holder.connection.send(
new ClientboundContainerSetSlotPacket(
holder.inventoryMenu.containerId,
holder.inventoryMenu.incrementStateId(),
InventoryMenu.SHIELD_SLOT,
holder.getOffhandItem()
));
}
}
};
}
}
@@ -1,41 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.container.slot.placeholder;
import com.lishid.openinv.internal.common.container.slot.placeholder.PlaceholderLoaderBase;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.TagParser;
import net.minecraft.util.Unit;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.CustomModelData;
import net.minecraft.world.item.component.DyedItemColor;
import org.jetbrains.annotations.NotNull;
public class CustomModelBase extends PlaceholderLoaderBase {
private final @NotNull CustomModelData defaultCustomModelData;
public CustomModelBase(@NotNull CustomModelData defaultCustomModelData) {
this.defaultCustomModelData = defaultCustomModelData;
}
@Override
protected @NotNull CompoundTag parseTag(@NotNull String itemText) throws Exception {
return TagParser.parseTag(itemText);
}
@Override
protected void addModelData(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.CUSTOM_MODEL_DATA, defaultCustomModelData);
}
@Override
protected void hideTooltip(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
}
@Override
protected DyedItemColor getDye(int rgb) {
return new DyedItemColor(rgb, false);
}
}
@@ -1,13 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.container.slot.placeholder;
import net.minecraft.world.item.component.CustomModelData;
import java.util.List;
public class CustomModelPlaceholderLoader extends CustomModelBase {
public CustomModelPlaceholderLoader() {
super(new CustomModelData(List.of(), List.of(), List.of("openinv:custom"), List.of()));
}
}
@@ -1,36 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.player;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.craftbukkit.CraftServer;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class OpenPlayer extends com.lishid.openinv.internal.paper1_21_5.player.OpenPlayer {
protected OpenPlayer(
CraftServer server, ServerPlayer entity,
PlayerManager manager
) {
super(server, entity, manager);
}
@Contract("null -> new")
@Override
protected @NotNull CompoundTag getWritableTag(@Nullable CompoundTag oldData) {
if (oldData == null) {
return new CompoundTag();
}
// Copy old data. This is a deep clone, so operating on it should be safe.
oldData = oldData.copy();
// Remove vanilla/server data that is not written every time.
oldData.getAllKeys()
.removeIf(key -> RESET_TAGS.contains(key) || key.startsWith("Bukkit"));
return oldData;
}
}
@@ -1,73 +0,0 @@
package com.lishid.openinv.internal.paper1_21_4.player;
import com.mojang.serialization.Dynamic;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.CraftWorld;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
import java.util.logging.Logger;
public class PlayerManager extends com.lishid.openinv.internal.paper1_21_5.player.PlayerManager {
public PlayerManager(@NotNull Logger logger) {
super(logger);
}
@Override
protected void parseWorld(@NotNull ServerPlayer player, @NotNull CompoundTag loadedData) {
// See PlayerList#placeNewPlayer
World bukkitWorld;
if (loadedData.contains("WorldUUIDMost") && loadedData.contains("WorldUUIDLeast")) {
// Modern Bukkit world.
bukkitWorld = Bukkit.getServer().getWorld(new UUID(loadedData.getLong("WorldUUIDMost"), loadedData.getLong("WorldUUIDLeast")));
} else if (loadedData.contains("world", net.minecraft.nbt.Tag.TAG_STRING)) {
// Legacy Bukkit world.
bukkitWorld = Bukkit.getServer().getWorld(loadedData.getString("world"));
} else {
// Vanilla player data.
DimensionType.parseLegacy(new Dynamic<>(NbtOps.INSTANCE, loadedData.get("Dimension")))
.resultOrPartial(logger::warning)
.map(player.server::getLevel)
// If ServerLevel exists, set, otherwise move to spawn.
.ifPresentOrElse(player::setServerLevel, () -> spawnInDefaultWorld(player.server, player));
return;
}
if (bukkitWorld == null) {
spawnInDefaultWorld(player.server, player);
return;
}
player.setServerLevel(((CraftWorld) bukkitWorld).getHandle());
}
@Override
protected void spawnInDefaultWorld(@NotNull MinecraftServer server, @NotNull ServerPlayer player) {
ServerLevel level = server.getLevel(Level.OVERWORLD);
if (level != null) {
// Adjust player to default spawn (in keeping with Paper handling) when world not found.
player.moveTo(player.adjustSpawnLocation(level, level.getSharedSpawnPos()).getBottomCenter(), level.getSharedSpawnAngle(), 0.0F);
player.spawnIn(level);
} else {
logger.warning("Tried to load player with invalid world when no fallback was available!");
}
}
@Override
protected void injectPlayer(@NotNull MinecraftServer server, @NotNull ServerPlayer player) throws IllegalAccessException {
if (bukkitEntity == null) {
return;
}
bukkitEntity.setAccessible(true);
bukkitEntity.set(player, new OpenPlayer(player.server.server, player, this));
}
}
-27
View File
@@ -1,27 +0,0 @@
plugins {
`openinv-base`
alias(libs.plugins.paperweight)
}
configurations.all {
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
val paper = candidates.firstOrNull {
it.id.let { id ->
id is ModuleComponentIdentifier && id.module == "paper-api"
}
}
if (paper != null) {
select(paper)
}
because("module is written for Paper servers")
}
}
dependencies {
implementation(project(":openinvapi"))
implementation(project(":openinvcommon"))
implementation(project(":openinvadaptercommon"))
implementation(project(":openinvadapterpaper1_21_8"))
paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT")
}
@@ -1,37 +0,0 @@
package com.lishid.openinv.internal.paper1_21_5;
import com.lishid.openinv.internal.paper1_21_5.container.slot.placeholder.PlaceholderLoaderLegacyParse;
import com.lishid.openinv.internal.paper1_21_5.player.PlayerManager;
import com.lishid.openinv.util.lang.LanguageManager;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Level;
import java.util.logging.Logger;
public class InternalAccessor extends com.lishid.openinv.internal.paper1_21_8.InternalAccessor {
private final @NotNull PlayerManager manager;
public InternalAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
super(logger, lang);
manager = new PlayerManager(logger);
}
@Override
public @NotNull PlayerManager getPlayerManager() {
return manager;
}
@Override
public void reload(@NotNull ConfigurationSection config) {
ConfigurationSection placeholders = config.getConfigurationSection("placeholders");
try {
// Reset placeholders to defaults and try to load configuration.
new PlaceholderLoaderLegacyParse().load(placeholders);
} catch (Exception e) {
logger.log(Level.WARNING, "Caught exception loading placeholder overrides!", e);
}
}
}
@@ -1,36 +0,0 @@
package com.lishid.openinv.internal.paper1_21_5.container.slot.placeholder;
import com.lishid.openinv.internal.common.container.slot.placeholder.PlaceholderLoader;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.craftbukkit.CraftRegistry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class PlaceholderLoaderLegacyParse extends PlaceholderLoader {
@Override
protected @NotNull ItemStack parse(
@Nullable ConfigurationSection section,
@NotNull String path,
@NotNull ItemStack defaultStack
) throws Exception {
if (section == null) {
return defaultStack;
}
String itemText = section.getString(path);
if (itemText == null) {
return defaultStack;
}
CompoundTag compoundTag = parseTag(itemText);
Optional<ItemStack> parsed = ItemStack.parse(CraftRegistry.getMinecraftRegistry(), compoundTag);
return parsed.filter(itemStack -> !itemStack.isEmpty()).orElse(defaultStack);
}
}
@@ -1,46 +0,0 @@
package com.lishid.openinv.internal.paper1_21_5.player;
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
import com.mojang.logging.LogUtils;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.storage.PlayerDataStorage;
import org.bukkit.craftbukkit.CraftServer;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
public class OpenPlayer extends BaseOpenPlayer {
protected OpenPlayer(CraftServer server, ServerPlayer entity, PlayerManager manager) {
super(server, entity, manager);
}
@Override
protected void trySave(ServerPlayer player) {
// See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman)
try {
PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo;
CompoundTag oldData = isOnline() ? null : worldNBTStorage.load(player.getName().getString(), player.getStringUUID()).orElse(null);
CompoundTag playerData = getWritableTag(oldData);
playerData = player.saveWithoutId(playerData);
saveSafe(player, oldData, playerData, worldNBTStorage);
} catch (Exception e) {
LogUtils.getLogger().warn("Failed to save player data for {}: {}", player.getScoreboardName(), e);
}
}
@Override
protected void safeReplaceFile(@NotNull Path dataFile, @NotNull Path tempFile, @NotNull Path backupFile) {
net.minecraft.Util.safeReplaceFile(dataFile, tempFile, backupFile);
}
@Override
protected void remove(@NotNull CompoundTag tag, @NotNull String key) {
tag.remove(key);
}
}
@@ -1,106 +0,0 @@
package com.lishid.openinv.internal.paper1_21_5.player;
import com.mojang.serialization.Dynamic;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.dimension.DimensionType;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.UUID;
import java.util.logging.Logger;
public class PlayerManager extends com.lishid.openinv.internal.paper1_21_8.player.PlayerManager {
public PlayerManager(@NotNull Logger logger) {
super(logger);
}
@Override
protected boolean loadData(@NotNull MinecraftServer server, @NotNull ServerPlayer player) {
// See CraftPlayer#loadData
CompoundTag loadedData = server.getPlayerList().playerIo.load(player).orElse(null);
if (loadedData == null) {
// Exceptions with loading are logged.
return false;
}
// Read basic data into the player.
player.load(loadedData);
// Game type settings are also loaded separately.
player.loadGameTypes(loadedData);
// World is not loaded by ServerPlayer#load(CompoundTag) on Paper.
parseWorld(player, loadedData);
return true;
}
protected void parseWorld(@NotNull ServerPlayer player, @NotNull CompoundTag loadedData) {
// See PlayerList#placeNewPlayer
World bukkitWorld;
Optional<Long> msbs = loadedData.getLong("WorldUUIDMost");
Optional<Long> lsbs = loadedData.getLong("WorldUUIDLeast");
if (msbs.isPresent() && lsbs.isPresent()) {
// Modern Bukkit world.
bukkitWorld = Bukkit.getServer().getWorld(new UUID(msbs.get(), lsbs.get()));
} else {
Optional<String> worldName = loadedData.getString("world");
if (worldName.isPresent()) {
// Legacy Bukkit world.
bukkitWorld = Bukkit.getServer().getWorld(worldName.get());
} else {
// Vanilla player data.
DimensionType.parseLegacy(new Dynamic<>(NbtOps.INSTANCE, loadedData.get("Dimension")))
.resultOrPartial(logger::warning)
.map(player.server::getLevel)
// If ServerLevel exists, set, otherwise move to spawn.
.ifPresentOrElse(player::setServerLevel, () -> spawnInDefaultWorld(player.server, player));
return;
}
}
if (bukkitWorld == null) {
spawnInDefaultWorld(player.server, player);
return;
}
player.setServerLevel(((CraftWorld) bukkitWorld).getHandle());
}
@Override
public @NotNull Player inject(@NotNull Player player) {
try {
ServerPlayer nmsPlayer = getHandle(player);
if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) {
return openPlayer;
}
injectPlayer(nmsPlayer.server, nmsPlayer);
return nmsPlayer.getBukkitEntity();
} catch (IllegalAccessException e) {
logger.log(
java.util.logging.Level.WARNING,
e,
() -> "Unable to inject ServerPlayer, certain player data may be lost when saving!"
);
return player;
}
}
@Override
protected void injectPlayer(@NotNull MinecraftServer server, @NotNull ServerPlayer player) throws IllegalAccessException {
if (bukkitEntity == null) {
return;
}
bukkitEntity.setAccessible(true);
bukkitEntity.set(player, new OpenPlayer(player.server.server, player, this));
}
}
+18 -16
View File
@@ -1,26 +1,28 @@
plugins {
`openinv-base`
alias(libs.plugins.paperweight)
}
configurations.all {
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
val paper = candidates.firstOrNull {
it.id.let { id ->
id is ModuleComponentIdentifier && id.module == "paper-api"
}
}
if (paper != null) {
select(paper)
}
because("module is written for Paper servers")
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(21)
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
dependencies {
implementation(project(":openinvapi"))
implementation(project(":openinvcommon"))
implementation(project(":openinvadaptercommon"))
implementation(project(":openinvapi")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvcommon")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvadapterpaper26_1")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
implementation(project(":openinvadapterpaper1_21_11")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
paperweight.paperDevBundle("1.21.8-R0.1-SNAPSHOT")
}
@@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.logging.Logger;
public class InternalAccessor extends com.lishid.openinv.internal.common.InternalAccessor {
public class InternalAccessor extends com.lishid.openinv.internal.paper1_21_11.InternalAccessor {
private final @NotNull PlayerManager manager;
@@ -1,7 +1,8 @@
package com.lishid.openinv.internal.paper1_21_8.container;
import com.lishid.openinv.internal.common.container.BaseOpenInventory;
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper1_21_11.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
@@ -46,4 +47,12 @@ public class OpenInventory extends BaseOpenInventory {
return component;
}
@Override
public @Nullable OpenChestMenu<?> createMenu(net.minecraft.world.entity.player.Player player, int i, boolean viewOnly) {
if (player instanceof ServerPlayer serverPlayer) {
return new OpenInventoryMenu(this, serverPlayer, i, viewOnly);
}
return null;
}
}
@@ -1,20 +1,16 @@
package com.lishid.openinv.internal.paper1_21_8.player;
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
import com.mojang.logging.LogUtils;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.level.storage.PlayerDataStorage;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.level.storage.ValueOutput;
import org.bukkit.craftbukkit.CraftServer;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import java.nio.file.Path;
import java.util.Optional;
public class OpenPlayer extends BaseOpenPlayer {
public class OpenPlayer extends com.lishid.openinv.internal.paper26_1.player.OpenPlayer {
protected OpenPlayer(
CraftServer server,
@@ -25,24 +21,12 @@ public class OpenPlayer extends BaseOpenPlayer {
}
@Override
protected void trySave(ServerPlayer player) {
Logger logger = LogUtils.getLogger();
// See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman)
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(player.problemPath(), logger)) {
PlayerDataStorage worldNbtStorage = server.getServer().getPlayerList().playerIo;
CompoundTag oldData = isOnline()
? null
: worldNbtStorage.load(player.getName().getString(), player.getStringUUID(), scopedCollector).orElse(null);
CompoundTag playerData = getWritableTag(oldData);
ValueOutput valueOutput = TagValueOutput.createWrappingWithContext(scopedCollector, player.registryAccess(), playerData);
player.saveWithoutId(valueOutput);
saveSafe(player, oldData, playerData, worldNbtStorage);
} catch (Exception e) {
LogUtils.getLogger().warn("Failed to save player data for {}: {}", player.getScoreboardName(), e);
}
protected Optional<CompoundTag> load(
PlayerDataStorage storage,
ServerPlayer player,
ProblemReporter.ScopedCollector collector
) {
return storage.load(player.getName().getString(), player.getStringUUID(), collector);
}
@Override
@@ -52,6 +36,8 @@ public class OpenPlayer extends BaseOpenPlayer {
@Override
protected void remove(@NotNull CompoundTag tag, @NotNull String key) {
// Note that the method signature here is different, though the usage
// appears identical. This version does not return the removed tag.
tag.remove(key);
}
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper1_21_8.player;
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import com.lishid.openinv.util.JulLoggerAdapter;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
@@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.logging.Logger;
public class PlayerManager extends com.lishid.openinv.internal.common.player.PlayerManager {
public class PlayerManager extends com.lishid.openinv.internal.paper26_1.player.PlayerManager {
public PlayerManager(@NotNull Logger logger) {
super(logger);
@@ -65,14 +65,14 @@ public class PlayerManager extends com.lishid.openinv.internal.common.player.Pla
bukkitEntity.setAccessible(true);
bukkitEntity.set(player, new OpenPlayer(server.server, player, this));
bukkitEntity.set(player, new com.lishid.openinv.internal.paper1_21_8.player.OpenPlayer(server.server, player, this));
}
@Override
public @NotNull Player inject(@NotNull Player player) {
try {
ServerPlayer nmsPlayer = getHandle(player);
if (nmsPlayer.getBukkitEntity() instanceof BaseOpenPlayer openPlayer) {
if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) {
return openPlayer;
}
MinecraftServer server = nmsPlayer.getServer();
+68
View File
@@ -0,0 +1,68 @@
import org.gradle.api.internal.attributes.DefaultCompatibilityRuleChain
plugins {
alias(libs.plugins.paperweight)
}
repositories {
maven("https://repo.papermc.io/repository/maven-public/")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(25))
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
class ToolchainJvmVersion: AttributeCompatibilityRule<Int> {
override fun execute(details: CompatibilityCheckDetails<Int>) {
if (details.consumerValue == details.producerValue) {
details.compatible()
return
}
if (details.producerValue == null) {
details.incompatible()
return
}
if (25 >= details.producerValue!!) {
details.compatible()
} else {
details.incompatible()
}
}
}
dependencies {
attributesSchema {
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE) {
// Gradle thinks that depending on a library with a certain language level requires
// any project that depends on it to also require that language level no matter what.
// This is a bit obnoxious when we're specifically adding compatiblity patches to shared common code.
// Realistically Gradle is correct and the chain should be reversed - the oldest, least common
// denominator should be targeted and patches should be slapped on top as necessary.
// However, I don't want to spend a week restructuring the project to cut a release.
// Hack out Gradle's rules and replace them with our own less-restrictive version.
val rules = compatibilityRules as DefaultCompatibilityRuleChain
rules.rules.clear()
compatibilityRules.add(ToolchainJvmVersion::class.java)
}
}
implementation(project(":openinvapi")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvcommon")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
paperweight.paperDevBundle("26.1.2.build.5-alpha")
}
tasks.reobfJar {
enabled = false
}
configurations.reobf.get().outgoing.artifacts.clear()
@@ -1,15 +1,15 @@
package com.lishid.openinv.internal.common;
package com.lishid.openinv.internal.paper26_1;
import com.lishid.openinv.internal.Accessor;
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.internal.common.container.AnySilentContainer;
import com.lishid.openinv.internal.common.container.OpenEnderChest;
import com.lishid.openinv.internal.common.container.OpenInventory;
import com.lishid.openinv.internal.common.container.slot.placeholder.PlaceholderLoader;
import com.lishid.openinv.internal.common.player.PlayerManager;
import com.lishid.openinv.internal.paper26_1.container.AnySilentContainer;
import com.lishid.openinv.internal.paper26_1.container.OpenEnderChest;
import com.lishid.openinv.internal.paper26_1.container.OpenInventory;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.PlaceholderLoader;
import com.lishid.openinv.internal.paper26_1.player.PlayerManager;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.world.Container;
import org.bukkit.configuration.ConfigurationSection;
@@ -14,11 +14,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.common.container;
package com.lishid.openinv.internal.paper26_1.container;
import com.lishid.openinv.internal.AnySilentContainerBase;
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.common.player.PlayerManager;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_1.player.PlayerManager;
import com.lishid.openinv.util.ReflectionHelper;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.core.BlockPos;
@@ -45,6 +45,8 @@ import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -213,4 +215,14 @@ public class AnySilentContainer extends AnySilentContainerBase {
}
}
@Override
protected org.bukkit.block.BlockState getState(@NotNull org.bukkit.block.Block block) {
return block.getState(false);
}
@Override
protected InventoryHolder getHolder(@NotNull Inventory inventory) {
return inventory.getHolder(false);
}
}
@@ -1,22 +1,22 @@
package com.lishid.openinv.internal.common.container;
package com.lishid.openinv.internal.paper26_1.container;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.common.container.bukkit.OpenPlayerInventory;
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.common.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.common.container.slot.Content;
import com.lishid.openinv.internal.common.container.slot.ContentCrafting;
import com.lishid.openinv.internal.common.container.slot.ContentCraftingResult;
import com.lishid.openinv.internal.common.container.slot.ContentCursor;
import com.lishid.openinv.internal.common.container.slot.ContentDrop;
import com.lishid.openinv.internal.common.container.slot.ContentEquipment;
import com.lishid.openinv.internal.common.container.slot.ContentList;
import com.lishid.openinv.internal.common.container.slot.ContentOffHand;
import com.lishid.openinv.internal.common.container.slot.ContentViewOnly;
import com.lishid.openinv.internal.common.container.slot.SlotViewOnly;
import com.lishid.openinv.internal.common.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.common.player.PlayerManager;
import com.lishid.openinv.internal.paper26_1.container.bukkit.OpenPlayerInventory;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper26_1.container.slot.Content;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentCrafting;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentCraftingResult;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentCursor;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentDrop;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentEquipment;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentList;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentOffHand;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentViewOnly;
import com.lishid.openinv.internal.paper26_1.container.slot.SlotViewOnly;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.player.PlayerManager;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component;
@@ -1,10 +1,10 @@
package com.lishid.openinv.internal.common.container;
package com.lishid.openinv.internal.paper26_1.container;
import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.common.container.menu.OpenEnderChestMenu;
import com.lishid.openinv.internal.common.player.PlayerManager;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenEnderChestMenu;
import com.lishid.openinv.internal.paper26_1.player.PlayerManager;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.common.container;
package com.lishid.openinv.internal.paper26_1.container;
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FontDescription;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.common.container.bukkit;
package com.lishid.openinv.internal.paper26_1.container.bukkit;
import com.lishid.openinv.internal.ViewOnly;
import net.minecraft.world.Container;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.common.container.bukkit;
package com.lishid.openinv.internal.paper26_1.container.bukkit;
import net.minecraft.world.Container;
import org.bukkit.Material;
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.common.container.bukkit;
package com.lishid.openinv.internal.paper26_1.container.bukkit;
import com.google.common.base.Preconditions;
import com.lishid.openinv.internal.common.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import net.minecraft.core.NonNullList;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Inventory;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.common.container.bukkit;
package com.lishid.openinv.internal.paper26_1.container.bukkit;
import com.lishid.openinv.internal.common.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -1,12 +1,12 @@
package com.lishid.openinv.internal.common.container.menu;
package com.lishid.openinv.internal.paper26_1.container.menu;
import com.google.common.base.Preconditions;
import com.lishid.openinv.internal.common.container.BaseOpenInventory;
import com.lishid.openinv.internal.common.container.bukkit.OpenDummyPlayerInventory;
import com.lishid.openinv.internal.common.container.bukkit.OpenPlayerInventorySelf;
import com.lishid.openinv.internal.common.container.slot.ContentDrop;
import com.lishid.openinv.internal.common.container.slot.ContentEquipment;
import com.lishid.openinv.internal.common.container.slot.SlotViewOnly;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.bukkit.OpenDummyPlayerInventory;
import com.lishid.openinv.internal.paper26_1.container.bukkit.OpenPlayerInventorySelf;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentDrop;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentEquipment;
import com.lishid.openinv.internal.paper26_1.container.slot.SlotViewOnly;
import com.lishid.openinv.util.Permissions;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EquipmentSlot;
@@ -20,14 +20,15 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
public class OpenInventoryMenu extends OpenSyncMenu<BaseOpenInventory> {
@NullMarked
public class BaseOpenInventoryMenu extends OpenSyncMenu<BaseOpenInventory> {
private int offset;
public OpenInventoryMenu(BaseOpenInventory inventory, ServerPlayer viewer, int i, boolean viewOnly) {
public BaseOpenInventoryMenu(BaseOpenInventory inventory, ServerPlayer viewer, int i, boolean viewOnly) {
super(getMenuType(inventory, viewer), i, inventory, viewer, viewOnly);
}
@@ -48,7 +49,7 @@ public class OpenInventoryMenu extends OpenSyncMenu<BaseOpenInventory> {
}
@Override
protected @NotNull Slot getUpperSlot(int index, int x, int y) {
protected Slot getUpperSlot(int index, int x, int y) {
index += offset;
Slot slot = container.getMenuSlot(index, x, y);
@@ -99,7 +100,7 @@ public class OpenInventoryMenu extends OpenSyncMenu<BaseOpenInventory> {
}
@Override
protected @NotNull CraftInventoryView<OpenChestMenu<BaseOpenInventory>, Inventory> createBukkitEntity() {
protected CraftInventoryView<OpenChestMenu<BaseOpenInventory>, Inventory> createBukkitEntity() {
org.bukkit.inventory.Inventory bukkitInventory;
if (viewOnly) {
bukkitInventory = new OpenDummyPlayerInventory(container);
@@ -111,7 +112,7 @@ public class OpenInventoryMenu extends OpenSyncMenu<BaseOpenInventory> {
return new CraftInventoryView<>(viewer.getBukkitEntity(), bukkitInventory, this) {
@Override
public org.bukkit.inventory.ItemStack getItem(int index) {
public org.bukkit.inventory.@Nullable ItemStack getItem(int index) {
if (viewOnly || index < 0) {
return null;
}
@@ -176,7 +177,7 @@ public class OpenInventoryMenu extends OpenSyncMenu<BaseOpenInventory> {
}
@Override
public @NotNull InventoryType.SlotType getSlotType(int slot) {
public InventoryType.SlotType getSlotType(int slot) {
if (viewOnly || slot < 0) {
return InventoryType.SlotType.OUTSIDE;
}
@@ -187,7 +188,7 @@ public class OpenInventoryMenu extends OpenSyncMenu<BaseOpenInventory> {
}
return InventoryType.SlotType.CONTAINER;
}
return OpenInventoryMenu.this.container.getSlotType(offset + slot);
return BaseOpenInventoryMenu.this.container.getSlotType(offset + slot);
}
@Override
@@ -198,7 +199,7 @@ public class OpenInventoryMenu extends OpenSyncMenu<BaseOpenInventory> {
}
@Override
public @NotNull ItemStack quickMoveStack(@NotNull Player player, int index) {
public ItemStack quickMoveStack(Player player, int index) {
if (viewOnly) {
return ItemStack.EMPTY;
}
@@ -0,0 +1,276 @@
package com.lishid.openinv.internal.paper26_1.container.menu;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.paper26_1.container.bukkit.OpenDummyInventory;
import com.lishid.openinv.internal.paper26_1.container.slot.SlotViewOnly;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.bukkit.craftbukkit.inventory.CraftInventoryView;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* An extension of {@link AbstractContainerMenu} storing and managing data common to all special inventories.
*/
@NullMarked
public abstract class OpenChestMenu<T extends Container & ISpecialInventory & InternalOwned<ServerPlayer>>
extends AbstractContainerMenu {
protected static final int BOTTOM_INVENTORY_SIZE = 36;
protected final T container;
protected final ServerPlayer viewer;
protected final boolean viewOnly;
protected final boolean ownContainer;
protected final int topSize;
private @Nullable CraftInventoryView<OpenChestMenu<T>, Inventory> bukkitEntity;
protected OpenChestMenu(
MenuType<ChestMenu> type,
int containerCounter,
T container,
ServerPlayer viewer,
boolean viewOnly
) {
super(type, containerCounter);
this.container = container;
this.viewer = viewer;
this.viewOnly = viewOnly;
ownContainer = container.getOwnerHandle().equals(viewer);
topSize = getTopSize(viewer);
preSlotSetup();
int upperRows = topSize / 9;
// View's upper inventory - our container
for (int row = 0; row < upperRows; ++row) {
for (int col = 0; col < 9; ++col) {
// x and y for client purposes, but hey, we're thorough here.
// Adapted from net.minecraft.world.inventory.ChestMenu
int x = 8 + col * 18;
int y = 18 + row * 18;
int index = row * 9 + col;
// Guard against weird inventory sizes.
if (index >= container.getContainerSize()) {
addSlot(new SlotViewOnly(container, index, x, y));
continue;
}
Slot slot = getUpperSlot(index, x, y);
addSlot(slot);
}
}
// View's lower inventory - viewer inventory
int playerInvPad = (upperRows - 4) * 18;
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 9; ++col) {
int x = 8 + col * 18;
int y = playerInvPad + row * 18 + 103;
addSlot(new Slot(viewer.getInventory(), row * 9 + col + 9, x, y));
}
}
// Hotbar
for (int col = 0; col < 9; ++col) {
int x = 8 + col * 18;
int y = playerInvPad + 161;
addSlot(new Slot(viewer.getInventory(), col, x, y));
}
}
public static MenuType<ChestMenu> getChestMenuType(int inventorySize) {
inventorySize = ((int) Math.ceil(inventorySize / 9.0)) * 9;
return switch (inventorySize) {
case 9 -> MenuType.GENERIC_9x1;
case 18 -> MenuType.GENERIC_9x2;
case 27 -> MenuType.GENERIC_9x3;
case 36 -> MenuType.GENERIC_9x4;
case 45 -> MenuType.GENERIC_9x5;
case 54 -> MenuType.GENERIC_9x6;
default -> throw new IllegalArgumentException("Inventory size unsupported: " + inventorySize);
};
}
protected void preSlotSetup() {
}
protected Slot getUpperSlot(int index, int x, int y) {
Slot slot = new Slot(container, index, x, y);
if (viewOnly) {
return SlotViewOnly.wrap(slot);
}
return slot;
}
public boolean isViewOnly() {
return viewOnly;
}
@Override
public final CraftInventoryView<OpenChestMenu<T>, Inventory> getBukkitView() {
if (bukkitEntity == null) {
bukkitEntity = createBukkitEntity();
}
return bukkitEntity;
}
protected CraftInventoryView<OpenChestMenu<T>, Inventory> createBukkitEntity() {
Inventory top;
if (viewOnly) {
top = new OpenDummyInventory(container, container.getBukkitType());
} else {
top = container.getBukkitInventory();
}
return new CraftInventoryView<>(viewer.getBukkitEntity(), top, this) {
@Override
public @Nullable Inventory getInventory(int rawSlot) {
if (viewOnly) {
return null;
}
return super.getInventory(rawSlot);
}
@Override
public int convertSlot(int rawSlot) {
if (viewOnly) {
return InventoryView.OUTSIDE;
}
return super.convertSlot(rawSlot);
}
@Override
public InventoryType.SlotType getSlotType(int slot) {
if (viewOnly) {
return InventoryType.SlotType.OUTSIDE;
}
return super.getSlotType(slot);
}
};
}
private int getTopSize(ServerPlayer viewer) {
MenuType<?> menuType = getType();
if (menuType == MenuType.GENERIC_9x1) {
return 9;
} else if (menuType == MenuType.GENERIC_9x2) {
return 18;
} else if (menuType == MenuType.GENERIC_9x3) {
return 27;
} else if (menuType == MenuType.GENERIC_9x4) {
return 36;
} else if (menuType == MenuType.GENERIC_9x5) {
return 45;
} else if (menuType == MenuType.GENERIC_9x6) {
return 54;
}
// This is a bit gross, but allows us a safe fallthrough.
return menuType.create(-1, viewer.getInventory()).slots.size() - BOTTOM_INVENTORY_SIZE;
}
/**
* Reimplementation of {@link AbstractContainerMenu#moveItemStackTo(ItemStack, int, int, boolean)} that ignores fake
* slots and respects {@link Slot#hasItem()}.
*
* @param itemStack the stack to quick-move
* @param rangeLow the start of the range of slots that can be moved to, inclusive
* @param rangeHigh the end of the range of slots that can be moved to, exclusive
* @param topDown whether to start at the top of the range or bottom
* @return whether the stack was modified as a result of being quick-moved
*/
@Override
protected boolean moveItemStackTo(ItemStack itemStack, int rangeLow, int rangeHigh, boolean topDown) {
boolean modified = false;
boolean stackable = itemStack.isStackable();
Slot firstEmpty = null;
for (int index = topDown ? rangeHigh - 1 : rangeLow;
!itemStack.isEmpty() && (topDown ? index >= rangeLow : index < rangeHigh);
index += topDown ? -1 : 1
) {
Slot slot = slots.get(index);
// If the slot cannot be added to, check the next slot.
if (slot.isFake() || !slot.mayPlace(itemStack)) {
continue;
}
if (slot.hasItem()) {
// If the item isn't stackable, check the next slot.
if (!stackable) {
continue;
}
// Otherwise, add as many as we can from our stack to the slot.
modified |= addToExistingStack(itemStack, slot);
} else {
// If this is the first empty slot, keep track of it for later use.
if (firstEmpty == null) {
firstEmpty = slot;
}
// If the item isn't stackable, we've located the slot we're adding it to, so we're done.
if (!stackable) {
break;
}
}
}
// If the item hasn't been fully added yet, add as many as we can to the first open slot.
if (!itemStack.isEmpty() && firstEmpty != null) {
firstEmpty.setByPlayer(itemStack.split(Math.min(itemStack.getCount(), firstEmpty.getMaxStackSize(itemStack))));
firstEmpty.setChanged();
modified = true;
}
return modified;
}
private static boolean addToExistingStack(ItemStack itemStack, Slot slot) {
ItemStack existing = slot.getItem();
// If the items aren't the same, we can't add our item.
if (!ItemStack.isSameItemSameComponents(itemStack, existing)) {
return false;
}
int max = slot.getMaxStackSize(existing);
int existingCount = existing.getCount();
// If the stack is already full, we can't add more.
if (existingCount >= max) {
return false;
}
int total = existingCount + itemStack.getCount();
// If the existing item can accept the entirety of our item, we're done!
if (total <= max) {
itemStack.setCount(0);
existing.setCount(total);
slot.setChanged();
return true;
}
// Otherwise, add as many as we can.
itemStack.shrink(max - existingCount);
existing.setCount(max);
slot.setChanged();
return true;
}
@Override
public boolean stillValid(Player player) {
return true;
}
}
@@ -1,32 +1,27 @@
package com.lishid.openinv.internal.paper1_21_4.container.menu;
package com.lishid.openinv.internal.paper26_1.container.menu;
import com.lishid.openinv.internal.common.container.OpenEnderChest;
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_1.container.OpenEnderChest;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ContainerInput;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenEnderChestMenu extends OpenSyncMenu<OpenEnderChest> {
public OpenEnderChestMenu(
@NotNull OpenEnderChest enderChest,
@NotNull ServerPlayer viewer,
OpenEnderChest enderChest,
ServerPlayer viewer,
int containerId,
boolean viewOnly
) {
super(
OpenChestMenu.getChestMenuType(enderChest.getContainerSize()),
containerId,
enderChest,
viewer,
viewOnly
);
super(getChestMenuType(enderChest.getContainerSize()), containerId, enderChest, viewer, viewOnly);
}
@Override
public @NotNull ItemStack quickMoveStack(@NotNull Player player, int index) {
public ItemStack quickMoveStack(Player player, int index) {
if (viewOnly) {
return ItemStack.EMPTY;
}
@@ -58,4 +53,14 @@ public class OpenEnderChestMenu extends OpenSyncMenu<OpenEnderChest> {
return original;
}
@Override
public void clicked(int slotIndex, int buttonNum, ContainerInput containerInput, Player player) {
if (viewOnly) {
if (containerInput == ContainerInput.QUICK_CRAFT) {
sendAllDataToRemote();
}
}
super.clicked(slotIndex, buttonNum, containerInput, player);
}
}
@@ -0,0 +1,26 @@
package com.lishid.openinv.internal.paper26_1.container.menu;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ContainerInput;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenInventoryMenu extends BaseOpenInventoryMenu {
public OpenInventoryMenu(BaseOpenInventory inventory, ServerPlayer viewer, int i, boolean viewOnly) {
super(inventory, viewer, i, viewOnly);
}
@Override
public void clicked(int slotIndex, int buttonNum, ContainerInput containerInput, Player player) {
if (viewOnly) {
if (containerInput == ContainerInput.QUICK_CRAFT) {
sendAllDataToRemote();
}
}
super.clicked(slotIndex, buttonNum, containerInput, player);
}
}
@@ -0,0 +1,166 @@
package com.lishid.openinv.internal.paper26_1.container.menu;
import com.google.common.base.Suppliers;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.paper26_1.container.slot.SlotPlaceholder;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.inventory.ContainerListener;
import net.minecraft.world.inventory.ContainerSynchronizer;
import net.minecraft.world.inventory.DataSlot;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.RemoteSlot;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* An extension of {@link OpenChestMenu} that supports {@link SlotPlaceholder placeholders}.
*/
@NullMarked
public abstract class OpenSyncMenu<T extends Container & ISpecialInventory & InternalOwned<ServerPlayer>>
extends OpenChestMenu<T> {
// Syncher fields required to send placeholder items.
// All fields intentionally shadow AbstractContainerMenu fields so that warnings
// will be generated if they are no longer necessary.
protected @Nullable ContainerSynchronizer synchronizer;
protected final List<ContainerListener> listeners = new ArrayList<>();
private @Nullable RemoteSlot remoteCarried = RemoteSlot.PLACEHOLDER;
protected boolean suppressRemoteUpdates;
protected OpenSyncMenu(
MenuType<ChestMenu> type,
int containerCounter,
T container,
ServerPlayer viewer,
boolean viewOnly
) {
super(type, containerCounter, container, viewer, viewOnly);
}
@Override
public void broadcastChanges() {
for (int index = 0; index < this.slots.size(); ++index) {
Slot slot = this.slots.get(index);
ItemStack itemstack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
Supplier<ItemStack> supplier = Suppliers.memoize(itemstack::copy);
this.triggerSlotListeners(index, itemstack, supplier);
this.synchronizeSlotToRemote(index, itemstack, supplier);
}
// See private synchronizeCarriedToRemote
if (!suppressRemoteUpdates && !getRemoteCarried().matches(getCarried())) {
this.broadcastCarriedItem();
}
for (int index = 0; index < this.dataSlots.size(); ++index) {
DataSlot dataSlot = this.dataSlots.get(index);
int current = dataSlot.get();
if (dataSlot.checkAndClearUpdateFlag()) {
// See private updateDataSlotListeners
for (ContainerListener containerListener : this.listeners) {
containerListener.dataChanged(this, index, current);
}
}
// See private synchronizeDataSlotToRemote
if (!suppressRemoteUpdates && remoteDataSlots.getInt(index) != current) {
remoteDataSlots.set(index, current);
if (synchronizer != null) {
synchronizer.sendDataChange(this, index, current);
}
}
}
}
@Override
public void sendAllDataToRemote() {
List<ItemStack> contentsCopy = new ArrayList<>();
for (int index = 0; index < slots.size(); ++index) {
Slot slot = slots.get(index);
ItemStack itemStack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
contentsCopy.add(itemStack.copy());
this.remoteSlots.get(index).force(itemStack);
}
getRemoteCarried().force(getCarried());
for (int index = 0; index < this.dataSlots.size(); ++index) {
this.remoteDataSlots.set(index, this.dataSlots.get(index).get());
}
if (this.synchronizer != null) {
this.synchronizer.sendInitialData(this, contentsCopy, this.getCarried().copy(), this.remoteDataSlots.toIntArray());
this.synchronizer.sendOffHandSlotChange();
}
}
protected RemoteSlot getRemoteCarried() {
if (remoteCarried != null) {
return remoteCarried;
}
try {
Field remoteCarried = AbstractContainerMenu.class.getDeclaredField("remoteCarried");
remoteCarried.setAccessible(true);
Object slot = remoteCarried.get(this);
if (slot instanceof RemoteSlot remoteSlot) {
this.remoteCarried = remoteSlot;
} else {
this.remoteCarried = RemoteSlot.PLACEHOLDER;
}
} catch (NoSuchFieldException | IllegalAccessException e) {
remoteCarried = RemoteSlot.PLACEHOLDER;
}
return remoteCarried;
}
// Overrides from here on are purely to capture the contents of fields that aren't exposed.
// Note that super calls should likely always be last! Some send data to remotes after updating state.
@Override
public void addSlotListener(ContainerListener containerListener) {
if (!this.listeners.contains(containerListener)) {
this.listeners.add(containerListener);
}
super.addSlotListener(containerListener);
}
@Override
public void setSynchronizer(ContainerSynchronizer containerSynchronizer) {
this.synchronizer = containerSynchronizer;
// Unset carried slot so we re-capture it when sending slots.
// setSynchronizer calls sendAllDataToRemote, so we can't just do the reflection here once after the fact.
this.remoteCarried = null;
super.setSynchronizer(containerSynchronizer);
}
@Override
public void removeSlotListener(ContainerListener containerListener) {
this.listeners.remove(containerListener);
super.removeSlotListener(containerListener);
}
@Override
public void suppressRemoteUpdates() {
this.suppressRemoteUpdates = true;
super.suppressRemoteUpdates();
}
@Override
public void resumeRemoteUpdates() {
this.suppressRemoteUpdates = false;
super.resumeRemoteUpdates();
}
}
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import com.lishid.openinv.internal.common.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
@@ -35,7 +35,7 @@ public class ContentCrafting implements Content {
// Player must be online and not in creative - since the creative client is (semi-)authoritative,
// it ignores changes without extra help, and will delete the item as a result.
// Spectator mode is technically possible but may cause the item to be dropped if the client opens an inventory.
return BaseOpenPlayer.isConnected(holder.connection) && holder.gameMode.isSurvival();
return OpenPlayer.isConnected(holder.connection) && holder.gameMode.isSurvival();
}
@Override
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import com.lishid.openinv.internal.common.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.InventoryMenu;
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import com.lishid.openinv.internal.common.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
@@ -64,7 +64,7 @@ public class ContentCursor implements Content {
// Player must be online and not in creative - since the creative client is (semi-)authoritative,
// it ignores changes without extra help, and will delete the item as a result.
// Spectator mode is technically possible but may cause the item to be dropped if the client opens an inventory.
return BaseOpenPlayer.isConnected(holder.connection) && holder.gameMode.isSurvival();
return OpenPlayer.isConnected(holder.connection) && holder.gameMode.isSurvival();
}
@Override
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import com.lishid.openinv.internal.common.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.Slot;
@@ -64,14 +64,14 @@ public class ContentDrop implements Content {
@Override
public ItemStack getOrDefault() {
return BaseOpenPlayer.isConnected(holder.connection)
return OpenPlayer.isConnected(holder.connection)
? Placeholders.drop
: Placeholders.blockedOffline;
}
@Override
public boolean mayPlace(@NotNull ItemStack itemStack) {
return BaseOpenPlayer.isConnected(holder.connection);
return OpenPlayer.isConnected(holder.connection);
}
@Override
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import com.lishid.openinv.internal.common.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.EntityEquipment;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -37,7 +37,7 @@ public class ContentOffHand extends ContentEquipment {
return new SlotEquipment(container, slot, x, y) {
@Override
public void setChanged() {
if (BaseOpenPlayer.isConnected(holder.connection) && holder.containerMenu != holder.inventoryMenu) {
if (OpenPlayer.isConnected(holder.connection) && holder.containerMenu != holder.inventoryMenu) {
holder.connection.send(
new ClientboundContainerSetSlotPacket(
holder.inventoryMenu.containerId,
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.common.container.slot;
package com.lishid.openinv.internal.paper26_1.container.slot;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.Slot;
Loaded 100 of 156 files, more files were not shown because too many files have changed in this diff. Show more