mirror of
https://github.com/Jikoo/OpenInv.git
synced 2026-11-04 16:50:04 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c2ec2121a | ||
|
|
ad06b46b37 | ||
|
|
05ac5c92c8 | ||
|
|
0c8c364c45 | ||
|
|
b89f34915e | ||
|
|
ada819b30a | ||
|
|
7a2cef50ec | ||
|
|
268e91007c | ||
|
|
f4ed616fb8 | ||
|
|
456909966f | ||
|
|
51649bf2ab | ||
|
|
e44697f856 | ||
|
|
414b141b37 | ||
|
|
0db487c6eb | ||
|
|
3b907e1b37 |
No files matched your search
@@ -22,9 +22,16 @@ jobs:
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
|
||||
# TODO convert to a Gradle plugin later for portability
|
||||
- name: Install Spigot dependency
|
||||
run: ./scripts/install_spigot.sh 1.21.4
|
||||
# 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-
|
||||
|
||||
- uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
|
||||
@@ -24,17 +24,11 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
name: ${{ env.VERSIONED_NAME }}
|
||||
# May actually want to manually specify Paper versions all the time; they won't all
|
||||
# need to be specified in code thanks to Mojang-mapped server internals.
|
||||
# A bit annoying, but not terribly so.
|
||||
# Instead, fetch min and max (which will also be Spigot version) and manually list intermediate versions?
|
||||
name: OpenInv ${{ env.VERSIONED_NAME }}
|
||||
body: |-
|
||||
## Supported server versions
|
||||
### Paper
|
||||
TODO COMMA-SEPARATED VERSIONS
|
||||
### Spigot
|
||||
TODO VERSION
|
||||
**Paper:** TODO VERSION, 1.21.4, 1.21.3, 1.21.1
|
||||
**Spigot:** TODO VERSION
|
||||
|
||||
TODO HELLO HUMAN, PRESS THE GENERATE CHANGELOG BUTTON PLEASE.
|
||||
draft: true
|
||||
|
||||
@@ -45,10 +45,7 @@ The OpenInv API is available via [JitPack](https://jitpack.io/).
|
||||
Note that since JitPack only builds the API now, the "full" OpenInv jar on JitPack is actually the openinvapi artifact. This is a change from previous dependency declaration that I hope to revert.
|
||||
|
||||
### Compilation
|
||||
To compile, the relevant Spigot jar must be installed in the local repository.
|
||||
As OpenInv is compiled against Mojang's mappings, you must run BuildTools with the `--remapped` argument:
|
||||
`java -jar BuildTools.jar --remapped --rev $serverVersion`
|
||||
`$serverVersion` is the version of the server, i.e. `1.21.4`
|
||||
|
||||
Once Spigot is installed, execute the gradle wrapper:
|
||||
Execute the gradle wrapper:
|
||||
`./gradlew build`
|
||||
|
||||
If you encounter issues with building the Spigot module, try running BuildTools manually.
|
||||
@@ -8,6 +8,7 @@ publishing {
|
||||
create<MavenPublication>("jitpack") {
|
||||
groupId = "com.github.Jikoo.OpenInv"
|
||||
artifactId = "openinvapi"
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,10 @@ plugins {
|
||||
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val libs = project.extensions.getByType(VersionCatalogsExtension::class.java).named("libs")
|
||||
implementation(libs.findLibrary("specialsource").orElseThrow())
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("../gradle/libs.versions.toml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import org.gradle.api.file.RegularFile
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
abstract class ReobfTask: Jar() {
|
||||
|
||||
@get:Input
|
||||
open val spigotVersion: Property<String> = objectFactory.property(String::class.java)
|
||||
|
||||
@get:InputFile
|
||||
open val inputFile: Property<RegularFile> = objectFactory.fileProperty()
|
||||
|
||||
@get:Input
|
||||
open val intermediaryClassifier: Property<String> = objectFactory.property(String::class.java).convention("mojang-mapped")
|
||||
|
||||
init {
|
||||
archiveClassifier.convention("reobf")
|
||||
}
|
||||
|
||||
@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 specialsource = project.configurations.named("spigotRemap").get().incoming.artifacts.artifacts
|
||||
.first { it.id.componentIdentifier.toString() == "net.md-5:SpecialSource:1.11.4" }.file.path
|
||||
val repo = Paths.get(project.repositories.mavenLocal().url)
|
||||
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(specialsource, 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(specialsource, obfServer, spigotMappings, obfPath, archiveFile.get().asFile, false)
|
||||
}
|
||||
|
||||
private fun remapPartial(specialSource: String, serverJar: Path, mapping: Path, input: File, output: File, reverse: Boolean) {
|
||||
project.providers.exec {
|
||||
commandLine("java", "-cp", "$specialSource${File.pathSeparator}$serverJar",
|
||||
"net.md_5.specialsource.SpecialSource", "--live",
|
||||
"-i", input.path, "-o", output.path,
|
||||
"-m", "$mapping",
|
||||
if (reverse) "--reverse" else "")
|
||||
}.result.get()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.github.jikoo.openinv
|
||||
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.ValueSource
|
||||
import org.gradle.api.provider.ValueSourceParameters
|
||||
import org.gradle.process.ExecOperations
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.nio.file.Files
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class BuildToolsValueSource: ValueSource<File, BuildToolsValueSource.Parameters> {
|
||||
|
||||
@get:Inject
|
||||
abstract val exec: ExecOperations
|
||||
|
||||
interface Parameters: ValueSourceParameters {
|
||||
val mavenLocal: Property<File>
|
||||
val workingDir: DirectoryProperty
|
||||
|
||||
val spigotVersion: Property<String>
|
||||
val spigotRevision: Property<String>
|
||||
|
||||
val ignoreCached: Property<Boolean>
|
||||
|
||||
val javaHome: DirectoryProperty
|
||||
val javaExecutable: Property<String>
|
||||
}
|
||||
|
||||
override fun obtain(): File {
|
||||
val version = parameters.spigotVersion.get()
|
||||
val revision = parameters.spigotRevision.get()
|
||||
val installLocation = getInstallLocation(version)
|
||||
// If Spigot is already installed, don't reinstall.
|
||||
if (!parameters.ignoreCached.get() && installLocation.exists()) {
|
||||
println("Skipping Spigot installation, $version is present")
|
||||
return installLocation
|
||||
}
|
||||
|
||||
val buildTools = installBuildTools(parameters.workingDir.get().asFile)
|
||||
|
||||
println("Installing Spigot $version (rev $revision)")
|
||||
|
||||
exec.javaexec {
|
||||
environment["JAVA_HOME"] = parameters.javaHome.get()
|
||||
executable = parameters.javaExecutable.get()
|
||||
workingDir = buildTools.parentFile
|
||||
classpath(buildTools)
|
||||
args = listOf("--nogui", "--rev", revision, "--remapped")
|
||||
}.rethrowFailure()
|
||||
|
||||
// Mark work for delete.
|
||||
cleanUp(buildTools.parentFile)
|
||||
|
||||
if (!installLocation.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")
|
||||
}
|
||||
|
||||
private fun installBuildTools(workingDir: File): File {
|
||||
val buildTools = workingDir.resolve("BuildTools.jar")
|
||||
if (buildTools.exists()) {
|
||||
return buildTools
|
||||
}
|
||||
|
||||
workingDir.mkdirs()
|
||||
|
||||
val buildToolsUrl = "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar"
|
||||
println("Downloading $buildToolsUrl")
|
||||
val stream = URI.create(buildToolsUrl).toURL().openStream()
|
||||
Files.copy(stream, buildTools.toPath())
|
||||
stream.close()
|
||||
|
||||
return buildTools
|
||||
}
|
||||
|
||||
private fun cleanUp(dir: File) {
|
||||
dir.deleteOnExit()
|
||||
if (!dir.isDirectory) {
|
||||
return
|
||||
}
|
||||
|
||||
dir.listFiles()?.forEach {
|
||||
if (it.isDirectory) {
|
||||
cleanUp(it)
|
||||
} else {
|
||||
it.deleteOnExit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.github.jikoo.openinv
|
||||
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.jvm.toolchain.JavaToolchainSpec
|
||||
|
||||
abstract class SpigotDependencyExtension (
|
||||
objects: ObjectFactory
|
||||
) {
|
||||
|
||||
val version = objects.property(String::class.java)
|
||||
val revision = objects.property(String::class.java)
|
||||
.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 java = objects.property(JavaToolchainSpec::class.java)
|
||||
val ignoreCached = objects.property(Boolean::class.java).convention(false)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.github.jikoo.openinv
|
||||
|
||||
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 javax.inject.Inject
|
||||
|
||||
abstract class SpigotSetup: Plugin<Project> {
|
||||
|
||||
@get:Inject
|
||||
abstract val javaToolchainService: JavaToolchainService
|
||||
|
||||
override fun apply(target: Project) {
|
||||
target.plugins.apply("java")
|
||||
|
||||
// Set up extension for configuring Spigot dependency.
|
||||
val spigotExt = target.dependencies.extensions.findByType(SpigotDependencyExtension::class.java)
|
||||
?: target.dependencies.extensions.create(
|
||||
"spigot",
|
||||
SpigotDependencyExtension::class.java,
|
||||
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) {
|
||||
parameters {
|
||||
mavenLocal.set(Paths.get(mvnLocal.url).toFile())
|
||||
workingDir.set(target.layout.buildDirectory.dir("tmp/buildtools"))
|
||||
spigotVersion.set(spigotExt.version)
|
||||
spigotRevision.set(spigotExt.revision)
|
||||
ignoreCached.set(spigotExt.ignoreCached)
|
||||
javaHome.set(launcher.metadata.installationPath)
|
||||
javaExecutable.set(launcher.executablePath.asFile.path)
|
||||
}
|
||||
}.get()
|
||||
|
||||
// Add Spigot dependency.
|
||||
val dependency = target.dependencies.create(
|
||||
"org.spigotmc",
|
||||
"spigot",
|
||||
spigotExt.version.get(),
|
||||
spigotExt.configuration.orNull,
|
||||
spigotExt.classifier.orNull,
|
||||
spigotExt.ext.orNull)
|
||||
target.dependencies.add("compileOnly", dependency)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Project meta
|
||||
group=com.lishid.openinv
|
||||
version=5.1.9
|
||||
version=5.1.10
|
||||
description=A Bukkit plugin for opening normally-inaccessible inventories.
|
||||
|
||||
# Gradle configuration
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
[versions]
|
||||
spigotapi = "1.21.4-R0.1-SNAPSHOT"
|
||||
specialsource = "1.11.4"
|
||||
spigotapi = "1.21.5-R0.1-SNAPSHOT"
|
||||
specialsource = "1.11.5"
|
||||
planarwrappers = "3.3.0"
|
||||
annotations = "26.0.2"
|
||||
paperweight = "2.0.0-beta.14"
|
||||
paperweight = "2.0.0-beta.16"
|
||||
shadow = "8.3.6"
|
||||
folia-scheduler-wrapper = "v0.0.3"
|
||||
|
||||
[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" }
|
||||
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" }
|
||||
|
||||
[plugins]
|
||||
paperweight = { id = "io.papermc.paperweight.userdev", version.ref = "paperweight" }
|
||||
|
||||
@@ -33,7 +33,7 @@ dependencies {
|
||||
implementation(project(":openinvapi"))
|
||||
implementation(project(":openinvcommon"))
|
||||
|
||||
paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT")
|
||||
paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT")
|
||||
}
|
||||
|
||||
val spigot = tasks.register<ShadowJar>("spigotRelocations") {
|
||||
|
||||
+39
-51
@@ -16,6 +16,7 @@ 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 it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@@ -38,13 +39,15 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class OpenInventory implements Container, InternalOwned<ServerPlayer>, ISpecialPlayerInventory {
|
||||
|
||||
private final List<Content> slots;
|
||||
protected final List<Content> slots;
|
||||
private final int size;
|
||||
private ServerPlayer owner;
|
||||
protected ServerPlayer owner;
|
||||
private int maxStackSize = 99;
|
||||
private CraftInventory bukkitEntity;
|
||||
public List<HumanEntity> transaction = new ArrayList<>();
|
||||
@@ -60,15 +63,14 @@ public class OpenInventory implements Container, InternalOwned<ServerPlayer>, IS
|
||||
setupSlots();
|
||||
}
|
||||
|
||||
private void setupSlots() {
|
||||
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
|
||||
if (ownerInv.getNonEquipmentItems().size() == 36
|
||||
&& Inventory.EQUIPMENT_SLOT_MAPPING.size() == 5
|
||||
&& owner.inventoryMenu.getCraftSlots().getContainerSize() == 4) {
|
||||
// Armor slots: Bottom left.
|
||||
addArmor(36);
|
||||
@@ -95,7 +97,7 @@ public class OpenInventory implements Container, InternalOwned<ServerPlayer>, IS
|
||||
}
|
||||
|
||||
private int addMainInventory() {
|
||||
int listSize = owner.getInventory().items.size();
|
||||
int listSize = owner.getInventory().getNonEquipmentItems().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;
|
||||
@@ -113,7 +115,7 @@ public class OpenInventory implements Container, InternalOwned<ServerPlayer>, IS
|
||||
slots.set(localIndex, new ContentList(owner, invIndex, type) {
|
||||
@Override
|
||||
public void setHolder(@NotNull ServerPlayer holder) {
|
||||
items = holder.getInventory().items;
|
||||
items = holder.getInventory().getNonEquipmentItems();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -121,50 +123,36 @@ public class OpenInventory implements Container, InternalOwned<ServerPlayer>, IS
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// Armor slots go bottom to top; boots are first and helmet is last.
|
||||
// Since we have to display horizontally due to space restrictions,
|
||||
// making the left side the "top" is more user-friendly.
|
||||
EquipmentSlot[] sorted = Inventory.EQUIPMENT_SLOT_MAPPING.int2ObjectEntrySet()
|
||||
.stream()
|
||||
.sorted(Comparator.comparingInt(Int2ObjectMap.Entry::getIntKey))
|
||||
.map(Map.Entry::getValue)
|
||||
.toArray(EquipmentSlot[]::new);
|
||||
int localIndex = 0;
|
||||
for (int i = sorted.length - 1; i >= 0; --i) {
|
||||
// Skip off-hand, handled separately.
|
||||
if (sorted[i] == EquipmentSlot.OFFHAND) {
|
||||
continue;
|
||||
}
|
||||
|
||||
slots.set(startIndex + i, new ContentEquipment(owner, armorIndex, slot));
|
||||
slots.set(startIndex + localIndex, new ContentEquipment(owner, sorted[i]));
|
||||
++localIndex;
|
||||
}
|
||||
|
||||
return startIndex + listSize;
|
||||
return startIndex + localIndex;
|
||||
}
|
||||
|
||||
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));
|
||||
// No off-hand?
|
||||
if (!Inventory.EQUIPMENT_SLOT_MAPPING.containsValue(EquipmentSlot.OFFHAND)) {
|
||||
return startIndex;
|
||||
}
|
||||
return startIndex + listSize;
|
||||
|
||||
slots.set(startIndex, new ContentOffHand(owner));
|
||||
return startIndex + 1;
|
||||
}
|
||||
|
||||
private int addCrafting(int startIndex, boolean pretty) {
|
||||
@@ -280,22 +268,22 @@ public class OpenInventory implements Container, InternalOwned<ServerPlayer>, IS
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int index) {
|
||||
public @NotNull ItemStack getItem(int index) {
|
||||
return slots.get(index).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItem(int index, int amount) {
|
||||
public @NotNull ItemStack removeItem(int index, int amount) {
|
||||
return slots.get(index).removePartial(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItemNoUpdate(int index) {
|
||||
public @NotNull ItemStack removeItemNoUpdate(int index) {
|
||||
return slots.get(index).remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int index, ItemStack itemStack) {
|
||||
public void setItem(int index, @NotNull ItemStack itemStack) {
|
||||
slots.get(index).set(itemStack);
|
||||
}
|
||||
|
||||
@@ -327,17 +315,17 @@ public class OpenInventory implements Container, InternalOwned<ServerPlayer>, IS
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(CraftHumanEntity viewer) {
|
||||
public void onOpen(@NotNull CraftHumanEntity viewer) {
|
||||
transaction.add(viewer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(CraftHumanEntity viewer) {
|
||||
public void onClose(@NotNull CraftHumanEntity viewer) {
|
||||
transaction.remove(viewer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HumanEntity> getViewers() {
|
||||
public @NotNull List<HumanEntity> getViewers() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -22,12 +22,12 @@ public class OpenDummyPlayerInventory extends OpenDummyInventory implements Play
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack[] getArmorContents() {
|
||||
public @NotNull ItemStack @NotNull [] getArmorContents() {
|
||||
return new ItemStack[4];
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack[] getExtraContents() {
|
||||
public @NotNull ItemStack @NotNull [] getExtraContents() {
|
||||
return new ItemStack[4];
|
||||
}
|
||||
|
||||
@@ -57,17 +57,17 @@ public class OpenDummyPlayerInventory extends OpenDummyInventory implements Play
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getItem(@NotNull EquipmentSlot slot) {
|
||||
return null;
|
||||
public @NotNull ItemStack getItem(@NotNull EquipmentSlot slot) {
|
||||
return new ItemStack(Material.AIR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArmorContents(@Nullable ItemStack[] items) {
|
||||
public void setArmorContents(ItemStack @NotNull [] items) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExtraContents(@Nullable ItemStack[] items) {
|
||||
public void setExtraContents(ItemStack @NotNull [] items) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
+48
-45
@@ -14,6 +14,8 @@ import org.bukkit.inventory.PlayerInventory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OpenPlayerInventory extends CraftInventory implements PlayerInventory {
|
||||
|
||||
public OpenPlayerInventory(@NotNull OpenInventory inventory) {
|
||||
@@ -26,7 +28,7 @@ public class OpenPlayerInventory extends CraftInventory implements PlayerInvento
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getContents() {
|
||||
public ItemStack @NotNull [] getContents() {
|
||||
return asCraftMirror(getInventory().getOwnerHandle().getInventory().getContents());
|
||||
}
|
||||
|
||||
@@ -46,13 +48,13 @@ public class OpenPlayerInventory extends CraftInventory implements PlayerInvento
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getStorageContents() {
|
||||
return asCraftMirror(getInventory().getOwnerHandle().getInventory().items);
|
||||
public ItemStack @NotNull [] getStorageContents() {
|
||||
return asCraftMirror(getInventory().getOwnerHandle().getInventory().getNonEquipmentItems());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStorageContents(ItemStack[] items) throws IllegalArgumentException {
|
||||
NonNullList<net.minecraft.world.item.ItemStack> list = getInventory().getOwnerHandle().getInventory().items;
|
||||
NonNullList<net.minecraft.world.item.ItemStack> list = getInventory().getOwnerHandle().getInventory().getNonEquipmentItems();
|
||||
int size = list.size();
|
||||
Preconditions.checkArgument(items.length <= size, "items.length must be <= %s", size);
|
||||
for (int index = 0; index < items.length; ++index) {
|
||||
@@ -71,103 +73,104 @@ public class OpenPlayerInventory extends CraftInventory implements PlayerInvento
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack[] getArmorContents() {
|
||||
return asCraftMirror(getInventory().getOwnerHandle().getInventory().armor);
|
||||
public @NotNull ItemStack @NotNull [] getArmorContents() {
|
||||
return asCraftMirror(getInventory().getOwnerHandle().getInventory().getArmorContents());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArmorContents(@Nullable ItemStack[] items) {
|
||||
NonNullList<net.minecraft.world.item.ItemStack> list = getInventory().getOwnerHandle().getInventory().armor;
|
||||
int size = list.size();
|
||||
public void setArmorContents(ItemStack @NotNull [] items) {
|
||||
int size = Inventory.EQUIPMENT_SLOTS_SORTED_BY_INDEX.length;
|
||||
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]));
|
||||
getInventory().getOwnerHandle().getInventory().equipment.set(
|
||||
Inventory.EQUIPMENT_SLOTS_SORTED_BY_INDEX[index],
|
||||
CraftItemStack.asNMSCopy(items[index]));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack[] getExtraContents() {
|
||||
return asCraftMirror(getInventory().getOwnerHandle().getInventory().offhand);
|
||||
public @NotNull ItemStack @NotNull [] getExtraContents() {
|
||||
return asCraftMirror(List.of(getInventory().getOwnerHandle().getInventory().equipment.get(EquipmentSlot.OFFHAND)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExtraContents(@Nullable ItemStack[] 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]));
|
||||
public void setExtraContents(ItemStack @NotNull [] items) {
|
||||
Preconditions.checkArgument(items.length <= 1, "items.length must be <= 1");
|
||||
for (ItemStack item : items) {
|
||||
getInventory().getOwnerHandle().getInventory().equipment.set(EquipmentSlot.OFFHAND, CraftItemStack.asNMSCopy(item));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getHelmet() {
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory()
|
||||
.getArmor(EquipmentSlot.HEAD.getIndex()));
|
||||
public @NotNull ItemStack getHelmet() {
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory().equipment
|
||||
.get(EquipmentSlot.HEAD));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHelmet(@Nullable ItemStack helmet) {
|
||||
getInventory().getOwnerHandle().getInventory().armor
|
||||
.set(EquipmentSlot.HEAD.getIndex(), CraftItemStack.asNMSCopy(helmet));
|
||||
getInventory().getOwnerHandle().getInventory().equipment
|
||||
.set(EquipmentSlot.HEAD, CraftItemStack.asNMSCopy(helmet));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getChestplate() {
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory()
|
||||
.getArmor(EquipmentSlot.HEAD.getIndex()));
|
||||
public @NotNull ItemStack getChestplate() {
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory().equipment
|
||||
.get(EquipmentSlot.CHEST));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChestplate(@Nullable ItemStack chestplate) {
|
||||
getInventory().getOwnerHandle().getInventory().armor
|
||||
.set(EquipmentSlot.CHEST.getIndex(), CraftItemStack.asNMSCopy(chestplate));
|
||||
getInventory().getOwnerHandle().getInventory().equipment
|
||||
.set(EquipmentSlot.CHEST, CraftItemStack.asNMSCopy(chestplate));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getLeggings() {
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory()
|
||||
.getArmor(EquipmentSlot.LEGS.getIndex()));
|
||||
public @NotNull ItemStack getLeggings() {
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory().equipment
|
||||
.get(EquipmentSlot.LEGS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLeggings(@Nullable ItemStack leggings) {
|
||||
getInventory().getOwnerHandle().getInventory().armor
|
||||
.set(EquipmentSlot.LEGS.getIndex(), CraftItemStack.asNMSCopy(leggings));
|
||||
getInventory().getOwnerHandle().getInventory().equipment
|
||||
.set(EquipmentSlot.LEGS, CraftItemStack.asNMSCopy(leggings));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getBoots() {
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory()
|
||||
.getArmor(EquipmentSlot.FEET.getIndex()));
|
||||
public @NotNull ItemStack getBoots() {
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory().equipment
|
||||
.get(EquipmentSlot.FEET));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoots(@Nullable ItemStack boots) {
|
||||
getInventory().getOwnerHandle().getInventory().armor
|
||||
.set(EquipmentSlot.FEET.getIndex(), CraftItemStack.asNMSCopy(boots));
|
||||
getInventory().getOwnerHandle().getInventory().equipment
|
||||
.set(EquipmentSlot.FEET, CraftItemStack.asNMSCopy(boots));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack getItemInMainHand() {
|
||||
Inventory internal = getInventory().getOwnerHandle().getInventory();
|
||||
return CraftItemStack.asCraftMirror(internal.getItem(internal.selected));
|
||||
return CraftItemStack.asCraftMirror(internal.getSelectedItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemInMainHand(@Nullable ItemStack item) {
|
||||
Inventory internal = getInventory().getOwnerHandle().getInventory();
|
||||
internal.setItem(internal.selected, CraftItemStack.asNMSCopy(item));
|
||||
internal.setSelectedItem(CraftItemStack.asNMSCopy(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack getItemInOffHand() {
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory().offhand.getFirst());
|
||||
return CraftItemStack.asCraftMirror(getInventory().getOwnerHandle().getInventory().equipment
|
||||
.get(EquipmentSlot.OFFHAND));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemInOffHand(@Nullable ItemStack item) {
|
||||
getInventory().getOwnerHandle().getInventory().offhand.set(0, CraftItemStack.asNMSCopy(item));
|
||||
getInventory().getOwnerHandle().getInventory().equipment
|
||||
.set(EquipmentSlot.OFFHAND, CraftItemStack.asNMSCopy(item));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -185,17 +188,17 @@ public class OpenPlayerInventory extends CraftInventory implements PlayerInvento
|
||||
@Override
|
||||
public int getHeldItemSlot() {
|
||||
Inventory internal = getInventory().getOwnerHandle().getInventory();
|
||||
return internal.items.size() - 9 + internal.selected;
|
||||
return internal.getNonEquipmentItems().size() - 9 + internal.getSelectedSlot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeldItemSlot(int slot) {
|
||||
slot %= 9;
|
||||
getInventory().getOwnerHandle().getInventory().selected = slot;
|
||||
getInventory().getOwnerHandle().getInventory().setSelectedSlot(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getItem(@NotNull org.bukkit.inventory.EquipmentSlot slot) {
|
||||
public @NotNull ItemStack getItem(@NotNull org.bukkit.inventory.EquipmentSlot slot) {
|
||||
return switch (slot) {
|
||||
case HAND -> getItemInMainHand();
|
||||
case OFF_HAND -> getItemInOffHand();
|
||||
|
||||
+33
-23
@@ -8,6 +8,7 @@ import com.lishid.openinv.internal.common.container.slot.SlotPlaceholder;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotViewOnly;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.network.HashedStack;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -19,6 +20,7 @@ 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.bukkit.craftbukkit.inventory.CraftInventoryView;
|
||||
@@ -47,12 +49,12 @@ public abstract class OpenChestMenu<T extends Container & ISpecialInventory & In
|
||||
protected final int topSize;
|
||||
private CraftInventoryView<OpenChestMenu<T>, Inventory> bukkitEntity;
|
||||
// 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 @Nullable ContainerSynchronizer synchronizer;
|
||||
protected final List<DataSlot> dataSlots = new ArrayList<>();
|
||||
protected final IntList remoteDataSlots = new IntArrayList();
|
||||
protected final List<ContainerListener> containerListeners = new ArrayList<>();
|
||||
private RemoteSlot remoteCarried = RemoteSlot.PLACEHOLDER;
|
||||
protected boolean suppressRemoteUpdates;
|
||||
|
||||
protected OpenChestMenu(
|
||||
@NotNull MenuType<ChestMenu> type,
|
||||
@@ -304,7 +306,7 @@ public abstract class OpenChestMenu<T extends Container & ISpecialInventory & In
|
||||
slot.index = this.slots.size();
|
||||
this.slots.add(slot);
|
||||
this.lastSlots.add(ItemStack.EMPTY);
|
||||
this.remoteSlots.add(ItemStack.EMPTY);
|
||||
this.remoteSlots.add(this.synchronizer != null ? this.synchronizer.createSlot() : RemoteSlot.PLACEHOLDER);
|
||||
return slot;
|
||||
}
|
||||
|
||||
@@ -333,32 +335,38 @@ public abstract class OpenChestMenu<T extends Container & ISpecialInventory & In
|
||||
@Override
|
||||
public void setSynchronizer(@NotNull ContainerSynchronizer containerSynchronizer) {
|
||||
this.synchronizer = containerSynchronizer;
|
||||
this.remoteCarried = synchronizer.createSlot();
|
||||
this.remoteSlots.replaceAll(slot -> synchronizer.createSlot());
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAllDataToRemote() {
|
||||
List<ItemStack> contentsCopy = new ArrayList<>();
|
||||
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());
|
||||
ItemStack itemStack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
|
||||
contentsCopy.add(itemStack);
|
||||
this.remoteSlots.get(index).force(itemStack);
|
||||
}
|
||||
|
||||
remoteCarried = getCarried().copy();
|
||||
remoteCarried.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, this.remoteSlots, this.remoteCarried, this.remoteDataSlots.toIntArray());
|
||||
this.synchronizer.sendInitialData(this, contentsCopy, this.getCarried().copy(), this.remoteDataSlots.toIntArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastCarriedItem() {
|
||||
this.remoteCarried = this.getCarried().copy();
|
||||
ItemStack carried = this.getCarried();
|
||||
this.remoteCarried.force(carried);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
|
||||
this.synchronizer.sendCarriedChange(this, carried.copy());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,12 +435,11 @@ public abstract class OpenChestMenu<T extends Container & ISpecialInventory & In
|
||||
|
||||
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);
|
||||
RemoteSlot slot = this.remoteSlots.get(i);
|
||||
if (!slot.matches(itemStack)) {
|
||||
slot.force(itemStack);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendSlotChange(this, i, itemstack2);
|
||||
this.synchronizer.sendSlotChange(this, i, supplier.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -451,17 +458,20 @@ public abstract class OpenChestMenu<T extends Container & ISpecialInventory & In
|
||||
}
|
||||
|
||||
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);
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
ItemStack carried = this.getCarried();
|
||||
if (!this.remoteCarried.matches(carried)) {
|
||||
this.remoteCarried.force(carried);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, carried.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoteCarried(ItemStack itemstack) {
|
||||
this.remoteCarried = itemstack.copy();
|
||||
public void setRemoteCarried(@NotNull HashedStack stack) {
|
||||
this.remoteCarried.receive(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-4
@@ -35,7 +35,7 @@ public class OpenInventoryMenu extends OpenChestMenu<OpenInventory> {
|
||||
int size = inventory.getContainerSize();
|
||||
// Disallow duplicate access to own main inventory contents.
|
||||
if (inventory.getOwnerHandle().equals(viewer)) {
|
||||
size -= viewer.getInventory().items.size();
|
||||
size -= viewer.getInventory().getNonEquipmentItems().size();
|
||||
size = ((int) Math.ceil(size / 9.0)) * 9;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class OpenInventoryMenu extends OpenChestMenu<OpenInventory> {
|
||||
|
||||
@Override
|
||||
protected void preSlotSetup() {
|
||||
offset = ownContainer ? viewer.getInventory().items.size() : 0;
|
||||
offset = ownContainer ? viewer.getInventory().getNonEquipmentItems().size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -221,7 +221,7 @@ public class OpenInventoryMenu extends OpenChestMenu<OpenInventory> {
|
||||
// If this is gear, try to move it to the correct slot first.
|
||||
case OFFHAND, FEET, LEGS, CHEST, HEAD -> {
|
||||
// Locate the correct slot in the contents following the main inventory.
|
||||
for (int extra = container.getOwnerHandle().getInventory().items.size() - offset; extra < topSize; ++extra) {
|
||||
for (int extra = container.getOwnerHandle().getInventory().getNonEquipmentItems().size() - offset; extra < topSize; ++extra) {
|
||||
Slot extraSlot = getSlot(extra);
|
||||
if (extraSlot instanceof ContentEquipment.SlotEquipment equipSlot
|
||||
&& equipSlot.getEquipmentSlot() == equipmentSlot) {
|
||||
@@ -244,7 +244,7 @@ public class OpenInventoryMenu extends OpenChestMenu<OpenInventory> {
|
||||
}
|
||||
} else {
|
||||
// If we didn't move to a gear slot, try to move to a main inventory slot.
|
||||
if (!movedGear && !this.moveItemStackTo(itemStack, 0, container.getOwnerHandle().getInventory().items.size(), true)) {
|
||||
if (!movedGear && !this.moveItemStackTo(itemStack, 0, container.getOwnerHandle().getInventory().getNonEquipmentItems().size(), true)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
+36
-4
@@ -3,6 +3,8 @@ package com.lishid.openinv.internal.common.container.slot;
|
||||
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.ContainerHelper;
|
||||
import net.minecraft.world.entity.EntityEquipment;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
@@ -12,13 +14,14 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* A slot for equipment that displays placeholders if empty.
|
||||
*/
|
||||
public class ContentEquipment extends ContentList {
|
||||
public class ContentEquipment implements Content {
|
||||
|
||||
private EntityEquipment equipment;
|
||||
private final ItemStack placeholder;
|
||||
private final EquipmentSlot equipmentSlot;
|
||||
|
||||
public ContentEquipment(ServerPlayer holder, int index, EquipmentSlot equipmentSlot) {
|
||||
super(holder, index, InventoryType.SlotType.ARMOR);
|
||||
public ContentEquipment(ServerPlayer holder, EquipmentSlot equipmentSlot) {
|
||||
setHolder(holder);
|
||||
placeholder = switch (equipmentSlot) {
|
||||
case HEAD -> Placeholders.emptyHelmet;
|
||||
case CHEST -> Placeholders.emptyChestplate;
|
||||
@@ -31,7 +34,31 @@ public class ContentEquipment extends ContentList {
|
||||
|
||||
@Override
|
||||
public void setHolder(@NotNull ServerPlayer holder) {
|
||||
this.items = holder.getInventory().armor;
|
||||
this.equipment = holder.getInventory().equipment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack get() {
|
||||
return equipment.get(equipmentSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack remove() {
|
||||
return equipment.set(equipmentSlot, ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removePartial(int amount) {
|
||||
ItemStack current = get();
|
||||
if (!current.isEmpty() && amount > 0) {
|
||||
return current.split(amount);
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(ItemStack itemStack) {
|
||||
equipment.set(equipmentSlot, itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,6 +66,11 @@ public class ContentEquipment extends ContentList {
|
||||
return new SlotEquipment(container, slot, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryType.SlotType getSlotType() {
|
||||
return InventoryType.SlotType.ARMOR;
|
||||
}
|
||||
|
||||
public class SlotEquipment extends SlotPlaceholder {
|
||||
|
||||
private ServerPlayer viewer;
|
||||
|
||||
+3
-3
@@ -17,13 +17,13 @@ public class ContentOffHand extends ContentEquipment {
|
||||
|
||||
private ServerPlayer holder;
|
||||
|
||||
public ContentOffHand(ServerPlayer holder, int localIndex) {
|
||||
super(holder, localIndex, EquipmentSlot.OFFHAND);
|
||||
public ContentOffHand(ServerPlayer holder) {
|
||||
super(holder, EquipmentSlot.OFFHAND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHolder(@NotNull ServerPlayer holder) {
|
||||
this.items = holder.getInventory().offhand;
|
||||
super.setHolder(holder);
|
||||
this.holder = holder;
|
||||
}
|
||||
|
||||
|
||||
+23
-1
@@ -1,18 +1,40 @@
|
||||
package com.lishid.openinv.internal.common.container.slot.placeholder;
|
||||
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.TagParser;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.component.CustomModelData;
|
||||
import net.minecraft.world.item.component.DyedItemColor;
|
||||
import net.minecraft.world.item.component.TooltipDisplay;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class PlaceholderLoader extends PlaceholderLoaderBase {
|
||||
|
||||
private static final CustomModelData DEFAULT_CUSTOM_MODEL_DATA = new CustomModelData(List.of(), List.of(), List.of("openinv:custom"), List.of());
|
||||
private static final TooltipDisplay HIDE_TOOLTIP = new TooltipDisplay(true, new LinkedHashSet<>());
|
||||
|
||||
@Override
|
||||
protected void addModelData(ItemStack itemStack) {
|
||||
protected @NotNull CompoundTag parseTag(@NotNull String itemText) throws Exception {
|
||||
return TagParser.parseCompoundFully(itemText);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addModelData(@NotNull ItemStack itemStack) {
|
||||
itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void hideTooltip(@NotNull ItemStack itemStack) {
|
||||
itemStack.set(DataComponents.TOOLTIP_DISPLAY, HIDE_TOOLTIP);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DyedItemColor getDye(int rgb) {
|
||||
return new DyedItemColor(rgb);
|
||||
}
|
||||
|
||||
}
|
||||
+14
-10
@@ -5,9 +5,7 @@ import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.TagParser;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
@@ -63,7 +61,7 @@ public abstract class PlaceholderLoaderBase {
|
||||
Placeholders.BLOCKED_GAME_TYPE.put(GameType.SPECTATOR, parse(section, "blocked.spectator", Placeholders.BLOCKED_GAME_TYPE.get(GameType.SPECTATOR)));
|
||||
}
|
||||
|
||||
private static @NotNull ItemStack parse(
|
||||
private @NotNull ItemStack parse(
|
||||
@Nullable ConfigurationSection section,
|
||||
@NotNull String path,
|
||||
@NotNull ItemStack defaultStack) throws Exception {
|
||||
@@ -77,12 +75,18 @@ public abstract class PlaceholderLoaderBase {
|
||||
return defaultStack;
|
||||
}
|
||||
|
||||
CompoundTag compoundTag = TagParser.parseTag(itemText);
|
||||
CompoundTag compoundTag = parseTag(itemText);
|
||||
Optional<ItemStack> parsed = ItemStack.parse(CraftRegistry.getMinecraftRegistry(), compoundTag);
|
||||
return parsed.filter(itemStack -> !itemStack.isEmpty()).orElse(defaultStack);
|
||||
}
|
||||
|
||||
protected abstract void addModelData(ItemStack itemStack);
|
||||
protected abstract @NotNull CompoundTag parseTag(@NotNull String itemText) throws Exception;
|
||||
|
||||
protected abstract void addModelData(@NotNull ItemStack itemStack);
|
||||
|
||||
protected abstract void hideTooltip(@NotNull ItemStack itemStack);
|
||||
|
||||
protected abstract DyedItemColor getDye(int rgb);
|
||||
|
||||
protected @NotNull ItemStack defaultCraftingOutput() {
|
||||
// Crafting table: "Crafting"
|
||||
@@ -106,7 +110,7 @@ public abstract class PlaceholderLoaderBase {
|
||||
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);
|
||||
hideTooltip(itemStack);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@@ -122,9 +126,9 @@ public abstract class PlaceholderLoaderBase {
|
||||
protected @NotNull ItemStack getEmptyArmor(@NotNull ItemLike item) {
|
||||
// Inventory-background-grey-ish leather armor with no tooltip
|
||||
ItemStack itemStack = new ItemStack(item);
|
||||
DyedItemColor color = new DyedItemColor(0xC8C8C8, false);
|
||||
DyedItemColor color = getDye(0xC8C8C8);
|
||||
itemStack.set(DataComponents.DYED_COLOR, color);
|
||||
itemStack.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
|
||||
hideTooltip(itemStack);
|
||||
addModelData(itemStack);
|
||||
return itemStack;
|
||||
}
|
||||
@@ -147,7 +151,7 @@ public abstract class PlaceholderLoaderBase {
|
||||
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);
|
||||
hideTooltip(itemStack);
|
||||
addModelData(itemStack);
|
||||
return itemStack;
|
||||
}
|
||||
@@ -155,7 +159,7 @@ public abstract class PlaceholderLoaderBase {
|
||||
protected @NotNull ItemStack defaultNotSlot() {
|
||||
// White pane with no tooltip
|
||||
ItemStack itemStack = new ItemStack(Items.WHITE_STAINED_GLASS_PANE);
|
||||
itemStack.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
|
||||
hideTooltip(itemStack);
|
||||
addModelData(itemStack);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
+14
-7
@@ -15,6 +15,7 @@ import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -30,7 +31,8 @@ public class OpenPlayer extends CraftPlayer {
|
||||
* @see net.minecraft.world.entity.player.Player#addAdditionalSaveData(CompoundTag)
|
||||
* @see net.minecraft.world.entity.LivingEntity#addAdditionalSaveData(CompoundTag)
|
||||
*/
|
||||
private static final Set<String> RESET_TAGS = Set.of(
|
||||
@Unmodifiable
|
||||
protected static final Set<String> RESET_TAGS = Set.of(
|
||||
// Entity#saveWithoutId(CompoundTag)
|
||||
"CustomName",
|
||||
"CustomNameVisible",
|
||||
@@ -43,6 +45,7 @@ public class OpenPlayer extends CraftPlayer {
|
||||
"Passengers",
|
||||
// ServerPlayer#addAdditionalSaveData(CompoundTag)
|
||||
// Intentional omissions to prevent mount loss: Attach, Entity, and RootVehicle
|
||||
// As of 1.21.5 only ender_pearls tag still needs to be reset. Rest are for backwards compatibility.
|
||||
"warden_spawn_tracker",
|
||||
"enteredNetherPosition",
|
||||
"SpawnX",
|
||||
@@ -57,18 +60,23 @@ public class OpenPlayer extends CraftPlayer {
|
||||
"ShoulderEntityLeft",
|
||||
"ShoulderEntityRight",
|
||||
"LastDeathLocation",
|
||||
"current_explosion_impact_pos",
|
||||
"current_explosion_impact_pos", // Unnecessary in 1.21.5
|
||||
// LivingEntity#addAdditionalSaveData(CompoundTag)
|
||||
"active_effects",
|
||||
"SleepingX",
|
||||
"SleepingY",
|
||||
"SleepingZ",
|
||||
"Brain"
|
||||
"Brain",
|
||||
"last_hurt_by_player",
|
||||
"last_hurt_by_player_memory_time",
|
||||
"last_hurt_by_mob",
|
||||
"ticks_since_last_hurt_by_mob",
|
||||
"equipment"
|
||||
);
|
||||
|
||||
private final PlayerManager manager;
|
||||
|
||||
OpenPlayer(CraftServer server, ServerPlayer entity, PlayerManager manager) {
|
||||
protected OpenPlayer(CraftServer server, ServerPlayer entity, PlayerManager manager) {
|
||||
super(server, entity);
|
||||
this.manager = manager;
|
||||
}
|
||||
@@ -111,7 +119,7 @@ public class OpenPlayer extends CraftPlayer {
|
||||
}
|
||||
|
||||
@Contract("null -> new")
|
||||
private @NotNull CompoundTag getWritableTag(@Nullable CompoundTag oldData) {
|
||||
protected @NotNull CompoundTag getWritableTag(@Nullable CompoundTag oldData) {
|
||||
if (oldData == null) {
|
||||
return new CompoundTag();
|
||||
}
|
||||
@@ -120,8 +128,7 @@ public class OpenPlayer extends CraftPlayer {
|
||||
oldData = oldData.copy();
|
||||
|
||||
// Remove vanilla/server data that is not written every time.
|
||||
oldData.getAllKeys()
|
||||
.removeIf(key -> RESET_TAGS.contains(key) || key.startsWith("Bukkit"));
|
||||
oldData.keySet().removeIf(key -> RESET_TAGS.contains(key) || key.startsWith("Bukkit") || key.startsWith("Paper") && key.length() > 5);
|
||||
|
||||
return oldData;
|
||||
}
|
||||
|
||||
+23
-15
@@ -34,13 +34,14 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PlayerManager implements com.lishid.openinv.internal.PlayerManager {
|
||||
|
||||
protected final @NotNull Logger logger;
|
||||
private @Nullable Field bukkitEntity;
|
||||
protected @Nullable Field bukkitEntity;
|
||||
|
||||
public PlayerManager(@NotNull Logger logger) {
|
||||
this.logger = logger;
|
||||
@@ -154,23 +155,28 @@ public class PlayerManager implements com.lishid.openinv.internal.PlayerManager
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseWorld(@NotNull ServerPlayer player, @NotNull CompoundTag loadedData) {
|
||||
protected void parseWorld(@NotNull ServerPlayer player, @NotNull CompoundTag loadedData) {
|
||||
// See PlayerList#placeNewPlayer
|
||||
World bukkitWorld;
|
||||
if (loadedData.contains("WorldUUIDMost") && loadedData.contains("WorldUUIDLeast")) {
|
||||
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(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"));
|
||||
bukkitWorld = Bukkit.getServer().getWorld(new UUID(msbs.get(), lsbs.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));
|
||||
return;
|
||||
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));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (bukkitWorld == null) {
|
||||
spawnInDefaultWorld(player);
|
||||
@@ -179,9 +185,11 @@ public class PlayerManager implements com.lishid.openinv.internal.PlayerManager
|
||||
player.setServerLevel(((CraftWorld) bukkitWorld).getHandle());
|
||||
}
|
||||
|
||||
private void spawnInDefaultWorld(ServerPlayer player) {
|
||||
protected void spawnInDefaultWorld(ServerPlayer player) {
|
||||
ServerLevel level = player.server.getLevel(Level.OVERWORLD);
|
||||
if (level != null) {
|
||||
// Adjust player to default spawn (in keeping with Paper handling) when world not found.
|
||||
player.snapTo(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!");
|
||||
|
||||
@@ -21,6 +21,7 @@ dependencies {
|
||||
implementation(project(":openinvapi"))
|
||||
implementation(project(":openinvcommon"))
|
||||
implementation(project(":openinvadaptercommon"))
|
||||
implementation(project(":openinvadapterpaper1_21_4"))
|
||||
implementation(project(":openinvadapterpaper1_21_3"))
|
||||
|
||||
paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT")
|
||||
|
||||
+1
-1
@@ -6,10 +6,10 @@ 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.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;
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class OpenInventory extends com.lishid.openinv.internal.common.container.OpenInventory {
|
||||
public class OpenInventory extends com.lishid.openinv.internal.paper1_21_4.container.OpenInventory {
|
||||
|
||||
public OpenInventory(@NotNull Player bukkitPlayer) {
|
||||
super(bukkitPlayer);
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@ 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.paper1_21_4.player.PlayerManager {
|
||||
|
||||
public PlayerManager(@NotNull Logger logger) {
|
||||
super(logger);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ dependencies {
|
||||
implementation(project(":openinvapi"))
|
||||
implementation(project(":openinvcommon"))
|
||||
implementation(project(":openinvadaptercommon"))
|
||||
implementation(project(":openinvadapterpaper1_21_4"))
|
||||
|
||||
paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT")
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.logging.Level;
|
||||
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_4.InternalAccessor {
|
||||
|
||||
public InternalAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
|
||||
super(logger, lang);
|
||||
|
||||
+4
-23
@@ -1,31 +1,12 @@
|
||||
package com.lishid.openinv.internal.paper1_21_3.container.slot.placeholder;
|
||||
|
||||
import com.lishid.openinv.internal.common.container.slot.placeholder.PlaceholderLoaderBase;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
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 com.lishid.openinv.internal.paper1_21_4.container.slot.placeholder.CustomModelBase;
|
||||
import net.minecraft.world.item.component.CustomModelData;
|
||||
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 NumericDataPlaceholderLoader extends CustomModelBase {
|
||||
|
||||
public class NumericDataPlaceholderLoader extends PlaceholderLoaderBase {
|
||||
|
||||
private static final CustomModelData DEFAULT_CUSTOM_MODEL_DATA = new CustomModelData(9999);
|
||||
|
||||
@Override
|
||||
protected void addModelData(ItemStack itemStack) {
|
||||
itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
|
||||
public NumericDataPlaceholderLoader() {
|
||||
super(new CustomModelData(9999));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
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"))
|
||||
|
||||
paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT")
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4;
|
||||
|
||||
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_4.container.OpenEnderChest;
|
||||
import com.lishid.openinv.internal.paper1_21_4.container.OpenInventory;
|
||||
import com.lishid.openinv.internal.paper1_21_4.container.slot.placeholder.CustomModelPlaceholderLoader;
|
||||
import com.lishid.openinv.internal.paper1_21_4.player.PlayerManager;
|
||||
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 {
|
||||
|
||||
protected 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;
|
||||
manager = new PlayerManager(logger);
|
||||
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 CustomModelPlaceholderLoader().load(placeholders);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "Caught exception loading placeholder overrides!", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
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);
|
||||
}
|
||||
|
||||
public @Nullable AbstractContainerMenu 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;
|
||||
}
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.container;
|
||||
|
||||
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.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.AbstractContainerMenu;
|
||||
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.common.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;
|
||||
}
|
||||
|
||||
public @Nullable AbstractContainerMenu createMenu(Player player, int i, boolean viewOnly) {
|
||||
if (player instanceof ServerPlayer serverPlayer) {
|
||||
return new OpenInventoryMenu(this, serverPlayer, i, viewOnly);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
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));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public @NotNull ItemStack getItemInHand() {
|
||||
return getItemInMainHand();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.container.bukkit;
|
||||
|
||||
import com.lishid.openinv.internal.paper1_21_4.container.OpenInventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class OpenPlayerInventorySelf extends OpenPlayerInventory {
|
||||
|
||||
private final int offset;
|
||||
|
||||
public OpenPlayerInventorySelf(@NotNull OpenInventory inventory, int offset) {
|
||||
super(inventory);
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int index) {
|
||||
return super.getItem(offset + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int index, ItemStack item) {
|
||||
super.setItem(offset + index, item);
|
||||
}
|
||||
|
||||
}
|
||||
+464
@@ -0,0 +1,464 @@
|
||||
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.bukkit.OpenDummyInventory;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotPlaceholder;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotViewOnly;
|
||||
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.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.ChestMenu;
|
||||
import net.minecraft.world.inventory.ClickType;
|
||||
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.bukkit.craftbukkit.inventory.CraftInventoryView;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* An extension of {@link AbstractContainerMenu} that supports {@link SlotPlaceholder placeholders}.
|
||||
*/
|
||||
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 CraftInventoryView<OpenChestMenu<T>, Inventory> bukkitEntity;
|
||||
// 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 OpenChestMenu(
|
||||
@NotNull MenuType<ChestMenu> type,
|
||||
int containerCounter,
|
||||
@NotNull T container,
|
||||
@NotNull 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));
|
||||
}
|
||||
}
|
||||
|
||||
protected void preSlotSetup() {}
|
||||
|
||||
protected @NotNull Slot getUpperSlot(int index, int x, int y) {
|
||||
Slot slot = new Slot(container, index, x, y);
|
||||
if (viewOnly) {
|
||||
return SlotViewOnly.wrap(slot);
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final @NotNull CraftInventoryView<OpenChestMenu<T>, Inventory> getBukkitView() {
|
||||
if (bukkitEntity == null) {
|
||||
bukkitEntity = createBukkitEntity();
|
||||
}
|
||||
|
||||
return bukkitEntity;
|
||||
}
|
||||
|
||||
protected @NotNull 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 @NotNull 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 void clicked(int i, int j, @NotNull ClickType clickType, @NotNull Player player) {
|
||||
if (viewOnly) {
|
||||
if (clickType == ClickType.QUICK_CRAFT) {
|
||||
sendAllDataToRemote();
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.clicked(i, j, clickType, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stillValid(@NotNull Player player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.container.menu;
|
||||
|
||||
import com.lishid.openinv.internal.common.container.OpenEnderChest;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class OpenEnderChestMenu extends OpenChestMenu<OpenEnderChest> {
|
||||
|
||||
public OpenEnderChestMenu(
|
||||
@NotNull OpenEnderChest enderChest,
|
||||
@NotNull ServerPlayer viewer,
|
||||
int containerId,
|
||||
boolean viewOnly) {
|
||||
super(
|
||||
com.lishid.openinv.internal.common.container.menu.OpenChestMenu.getChestMenuType(enderChest.getContainerSize()),
|
||||
containerId,
|
||||
enderChest,
|
||||
viewer,
|
||||
viewOnly
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack quickMoveStack(@NotNull 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;
|
||||
}
|
||||
|
||||
}
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.container.menu;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.lishid.openinv.internal.common.container.bukkit.OpenDummyPlayerInventory;
|
||||
import com.lishid.openinv.internal.common.container.slot.ContentDrop;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotViewOnly;
|
||||
import com.lishid.openinv.internal.paper1_21_4.container.OpenInventory;
|
||||
import com.lishid.openinv.internal.paper1_21_4.container.bukkit.OpenPlayerInventorySelf;
|
||||
import com.lishid.openinv.internal.paper1_21_4.container.slot.ContentEquipment;
|
||||
import com.lishid.openinv.util.Permissions;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
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.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;
|
||||
|
||||
public class OpenInventoryMenu extends OpenChestMenu<OpenInventory> {
|
||||
|
||||
private int offset;
|
||||
|
||||
public OpenInventoryMenu(OpenInventory inventory, ServerPlayer viewer, int i, boolean viewOnly) {
|
||||
super(getMenuType(inventory, viewer), i, inventory, viewer, viewOnly);
|
||||
}
|
||||
|
||||
private static MenuType<ChestMenu> getMenuType(OpenInventory inventory, ServerPlayer viewer) {
|
||||
int size = inventory.getContainerSize();
|
||||
// Disallow duplicate access to own main inventory contents.
|
||||
if (inventory.getOwnerHandle().equals(viewer)) {
|
||||
size -= viewer.getInventory().items.size();
|
||||
size = ((int) Math.ceil(size / 9.0)) * 9;
|
||||
}
|
||||
|
||||
return com.lishid.openinv.internal.common.container.menu.OpenChestMenu.getChestMenuType(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preSlotSetup() {
|
||||
offset = ownContainer ? viewer.getInventory().items.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull Slot getUpperSlot(int index, int x, int y) {
|
||||
index += offset;
|
||||
Slot slot = container.getMenuSlot(index, x, y);
|
||||
|
||||
// If the slot cannot be interacted with there's nothing to configure.
|
||||
if (slot.getClass().equals(SlotViewOnly.class)) {
|
||||
return slot;
|
||||
}
|
||||
|
||||
// Remove drop slot if viewer is not allowed to use it.
|
||||
if (slot instanceof ContentDrop.SlotDrop
|
||||
&& (viewOnly || !Permissions.INVENTORY_SLOT_DROP.hasPermission(viewer.getBukkitEntity()))) {
|
||||
return new SlotViewOnly(container, index, x, y);
|
||||
}
|
||||
|
||||
if (slot instanceof ContentEquipment.SlotEquipment equipment) {
|
||||
if (viewOnly) {
|
||||
return SlotViewOnly.wrap(slot);
|
||||
}
|
||||
|
||||
Permissions perm = switch (equipment.getEquipmentSlot()) {
|
||||
case HEAD -> Permissions.INVENTORY_SLOT_HEAD_ANY;
|
||||
case CHEST -> Permissions.INVENTORY_SLOT_CHEST_ANY;
|
||||
case LEGS -> Permissions.INVENTORY_SLOT_LEGS_ANY;
|
||||
case FEET -> Permissions.INVENTORY_SLOT_FEET_ANY;
|
||||
// Off-hand can hold anything, not just equipment.
|
||||
default -> null;
|
||||
};
|
||||
|
||||
// If the viewer doesn't have permission, only allow equipment the viewee can equip in the slot.
|
||||
if (perm != null && !perm.hasPermission(viewer.getBukkitEntity())) {
|
||||
equipment.onlyEquipmentFor(container.getOwnerHandle());
|
||||
}
|
||||
|
||||
// Equipment slots are a core part of the inventory, so they will always be shown.
|
||||
return slot;
|
||||
}
|
||||
|
||||
// When viewing own inventory, only allow access to equipment and drop slots (equipment allowed above).
|
||||
if (ownContainer && !(slot instanceof ContentDrop.SlotDrop)) {
|
||||
return new SlotViewOnly(container, index, x, y);
|
||||
}
|
||||
|
||||
if (viewOnly) {
|
||||
return SlotViewOnly.wrap(slot);
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull CraftInventoryView<OpenChestMenu<OpenInventory>, Inventory> createBukkitEntity() {
|
||||
org.bukkit.inventory.Inventory bukkitInventory;
|
||||
if (viewOnly) {
|
||||
bukkitInventory = new OpenDummyPlayerInventory(container);
|
||||
} else if (ownContainer) {
|
||||
bukkitInventory = new OpenPlayerInventorySelf(container, offset);
|
||||
} else {
|
||||
bukkitInventory = container.getBukkitInventory();
|
||||
}
|
||||
|
||||
return new CraftInventoryView<>(viewer.getBukkitEntity(), bukkitInventory, this) {
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack getItem(int index) {
|
||||
if (viewOnly || index < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Slot slot = slots.get(index);
|
||||
return CraftItemStack.asCraftMirror(slot.hasItem() ? slot.getItem() : ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInTop(int rawSlot) {
|
||||
return rawSlot < topSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Inventory getInventory(int rawSlot) {
|
||||
if (viewOnly) {
|
||||
return null;
|
||||
}
|
||||
if (rawSlot == InventoryView.OUTSIDE || rawSlot == -1) {
|
||||
return null;
|
||||
}
|
||||
Preconditions.checkArgument(rawSlot >= 0 && rawSlot < topSize + offset + BOTTOM_INVENTORY_SIZE,
|
||||
"Slot %s outside of inventory", rawSlot);
|
||||
if (rawSlot > topSize) {
|
||||
return getBottomInventory();
|
||||
}
|
||||
Slot slot = slots.get(rawSlot);
|
||||
if (slot.isFake()) {
|
||||
return null;
|
||||
}
|
||||
return getTopInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int convertSlot(int rawSlot) {
|
||||
if (viewOnly) {
|
||||
return InventoryView.OUTSIDE;
|
||||
}
|
||||
if (rawSlot < 0) {
|
||||
return rawSlot;
|
||||
}
|
||||
if (rawSlot < topSize) {
|
||||
Slot slot = slots.get(rawSlot);
|
||||
if (slot.isFake()) {
|
||||
return InventoryView.OUTSIDE;
|
||||
}
|
||||
return rawSlot;
|
||||
}
|
||||
|
||||
int slot = rawSlot - topSize;
|
||||
|
||||
if (slot >= 27) {
|
||||
slot -= 27;
|
||||
} else {
|
||||
slot += 9;
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull InventoryType.SlotType getSlotType(int slot) {
|
||||
if (viewOnly || slot < 0) {
|
||||
return InventoryType.SlotType.OUTSIDE;
|
||||
}
|
||||
if (slot >= topSize) {
|
||||
slot -= topSize;
|
||||
if (slot >= 27) {
|
||||
return InventoryType.SlotType.QUICKBAR;
|
||||
}
|
||||
return InventoryType.SlotType.CONTAINER;
|
||||
}
|
||||
return OpenInventoryMenu.this.container.getSlotType(offset + slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countSlots() {
|
||||
return topSize + BOTTOM_INVENTORY_SIZE;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack quickMoveStack(@NotNull Player player, int index) {
|
||||
if (viewOnly) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
// See ChestMenu and InventoryMenu
|
||||
Slot slot = this.slots.get(index);
|
||||
|
||||
if (!slot.hasItem() || slot.isFake()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
ItemStack itemStack = slot.getItem();
|
||||
ItemStack originalStack = itemStack.copy();
|
||||
|
||||
if (index < topSize) {
|
||||
// If we're moving top to bottom, do a normal transfer.
|
||||
if (!this.moveItemStackTo(itemStack, topSize, this.slots.size(), true)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else {
|
||||
EquipmentSlot equipmentSlot = player.getEquipmentSlotForItem(itemStack);
|
||||
boolean movedGear = switch (equipmentSlot) {
|
||||
// If this is gear, try to move it to the correct slot first.
|
||||
case OFFHAND, FEET, LEGS, CHEST, HEAD -> {
|
||||
// Locate the correct slot in the contents following the main inventory.
|
||||
for (int extra = container.getOwnerHandle().getInventory().items.size() - offset; extra < topSize; ++extra) {
|
||||
Slot extraSlot = getSlot(extra);
|
||||
if (extraSlot instanceof ContentEquipment.SlotEquipment equipSlot
|
||||
&& equipSlot.getEquipmentSlot() == equipmentSlot) {
|
||||
// If we've found a matching slot, try to move to it.
|
||||
// If this succeeds, even partially, we will not attempt to move to other slots.
|
||||
// Otherwise, armor is already occupied, so we'll fall through to main inventory.
|
||||
yield this.moveItemStackTo(itemStack, extra, extra + 1, false);
|
||||
}
|
||||
}
|
||||
yield false;
|
||||
}
|
||||
// Non-gear gets no special treatment.
|
||||
default -> false;
|
||||
};
|
||||
|
||||
// If main inventory is not available, there's nowhere else to move.
|
||||
if (offset != 0) {
|
||||
if (!movedGear) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else {
|
||||
// If we didn't move to a gear slot, try to move to a main inventory slot.
|
||||
if (!movedGear && !this.moveItemStackTo(itemStack, 0, container.getOwnerHandle().getInventory().items.size(), true)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (itemStack.isEmpty()) {
|
||||
slot.setByPlayer(ItemStack.EMPTY);
|
||||
} else {
|
||||
slot.setChanged();
|
||||
}
|
||||
|
||||
return originalStack;
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.container.slot;
|
||||
|
||||
import com.lishid.openinv.internal.common.player.OpenPlayer;
|
||||
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 (OpenPlayer.isConnected(holder.connection) && holder.containerMenu != holder.inventoryMenu) {
|
||||
holder.connection.send(
|
||||
new ClientboundContainerSetSlotPacket(
|
||||
holder.inventoryMenu.containerId,
|
||||
holder.inventoryMenu.incrementStateId(),
|
||||
InventoryMenu.SHIELD_SLOT,
|
||||
holder.getOffhandItem()));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
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()));
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.player;
|
||||
|
||||
import com.lishid.openinv.internal.common.player.PlayerManager;
|
||||
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.common.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;
|
||||
}
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
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.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.common.player.PlayerManager {
|
||||
|
||||
public PlayerManager(@NotNull Logger logger) {
|
||||
super(logger);
|
||||
}
|
||||
|
||||
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));
|
||||
return;
|
||||
}
|
||||
if (bukkitWorld == null) {
|
||||
spawnInDefaultWorld(player);
|
||||
return;
|
||||
}
|
||||
player.setServerLevel(((CraftWorld) bukkitWorld).getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnInDefaultWorld(ServerPlayer player) {
|
||||
ServerLevel level = player.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!");
|
||||
}
|
||||
}
|
||||
|
||||
protected void injectPlayer(ServerPlayer player) throws IllegalAccessException {
|
||||
if (bukkitEntity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
bukkitEntity.setAccessible(true);
|
||||
bukkitEntity.set(player, new OpenPlayer(player.server.server, player, this));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
import com.github.jikoo.openinv.SpigotDependencyExtension
|
||||
import com.github.jikoo.openinv.SpigotReobf
|
||||
import com.github.jikoo.openinv.SpigotSetup
|
||||
|
||||
plugins {
|
||||
`openinv-base`
|
||||
alias(libs.plugins.shadow)
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
}
|
||||
apply<SpigotSetup>()
|
||||
apply<SpigotReobf>()
|
||||
|
||||
val spigotVer = "1.21.4-R0.1-SNAPSHOT"
|
||||
rootProject.extra["spigotVersion"] = spigotVer
|
||||
rootProject.extra["craftbukkitPackage"] = "v1_21_R3"
|
||||
val spigotVer = "1.21.5-R0.1-SNAPSHOT"
|
||||
// Used by common adapter to relocate Craftbukkit classes to a versioned package.
|
||||
rootProject.extra["craftbukkitPackage"] = "v1_21_R4"
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
|
||||
@@ -25,12 +28,9 @@ configurations.all {
|
||||
}
|
||||
}
|
||||
|
||||
val spigotRemap = configurations.create("spigotRemap")
|
||||
|
||||
dependencies {
|
||||
spigotRemap("net.md-5:SpecialSource:1.11.4:shaded")
|
||||
compileOnly(libs.spigotapi)
|
||||
compileOnly(create("org.spigotmc", "spigot", spigotVer, classifier = "remapped-mojang"))
|
||||
extensions.getByType(SpigotDependencyExtension::class.java).version = spigotVer
|
||||
|
||||
compileOnly(project(":openinvapi"))
|
||||
compileOnly(project(":openinvcommon"))
|
||||
@@ -42,25 +42,3 @@ dependencies {
|
||||
tasks.shadowJar {
|
||||
relocate("com.lishid.openinv.internal.common", "com.lishid.openinv.internal.reobf")
|
||||
}
|
||||
|
||||
val reobfTask = tasks.register<ReobfTask>("reobfTask") {
|
||||
notCompatibleWithConfigurationCache("gradle is hard")
|
||||
dependsOn(tasks.shadowJar)
|
||||
inputFile.value(tasks.shadowJar.get().archiveFile.get())
|
||||
spigotVersion.value(spigotVer)
|
||||
}
|
||||
|
||||
configurations {
|
||||
consumable("reobf") {
|
||||
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("reobf", reobfTask)
|
||||
}
|
||||
+2
-2
@@ -45,10 +45,10 @@ public class AnySilentContainer extends AnySilentContainerBase {
|
||||
this.lang = lang;
|
||||
try {
|
||||
try {
|
||||
this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("b");
|
||||
this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("gameModeForPlayer");
|
||||
this.serverPlayerGameModeGameType.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
logger.warning("The mapping of ServerPlayerGameMode#gameModeForPlayer has changed!");
|
||||
logger.warning("The field ServerPlayerGameMode#gameModeForPlayer is no longer present!");
|
||||
logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues");
|
||||
logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail.");
|
||||
// N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break.
|
||||
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
package com.lishid.openinv.internal.reobf.container.bukkit;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.lishid.openinv.internal.reobf.container.OpenInventory;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import org.bukkit.craftbukkit.v1_21_R4.inventory.CraftInventory;
|
||||
import org.bukkit.craftbukkit.v1_21_R4.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().getNonEquipmentItems());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStorageContents(ItemStack[] items) throws IllegalArgumentException {
|
||||
NonNullList<net.minecraft.world.item.ItemStack> list = getInventory().getOwnerHandle().getInventory().getNonEquipmentItems();
|
||||
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 getInventory().getOwnerHandle().getBukkitEntity().getInventory().getArmorContents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArmorContents(ItemStack @NotNull [] items) {
|
||||
getInventory().getOwnerHandle().getBukkitEntity().getInventory().setArmorContents(items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack @NotNull [] getExtraContents() {
|
||||
return getInventory().getOwnerHandle().getBukkitEntity().getInventory().getExtraContents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExtraContents(ItemStack @NotNull [] items) {
|
||||
getInventory().getOwnerHandle().getBukkitEntity().getInventory().setExtraContents(items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getHelmet() {
|
||||
return getInventory().getOwnerHandle().getBukkitEntity().getInventory().getHelmet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHelmet(@Nullable ItemStack helmet) {
|
||||
getInventory().getOwnerHandle().getBukkitEntity().getInventory().setHelmet(helmet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getChestplate() {
|
||||
return getInventory().getOwnerHandle().getBukkitEntity().getInventory().getChestplate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChestplate(@Nullable ItemStack chestplate) {
|
||||
getInventory().getOwnerHandle().getBukkitEntity().getInventory().setChestplate(chestplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getLeggings() {
|
||||
return getInventory().getOwnerHandle().getBukkitEntity().getInventory().getLeggings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLeggings(@Nullable ItemStack leggings) {
|
||||
getInventory().getOwnerHandle().getBukkitEntity().getInventory().setLeggings(leggings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getBoots() {
|
||||
return getInventory().getOwnerHandle().getBukkitEntity().getInventory().getBoots();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoots(@Nullable ItemStack boots) {
|
||||
getInventory().getOwnerHandle().getBukkitEntity().getInventory().setBoots(boots);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack getItemInMainHand() {
|
||||
Inventory internal = getInventory().getOwnerHandle().getInventory();
|
||||
return CraftItemStack.asCraftMirror(internal.getSelectedItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemInMainHand(@Nullable ItemStack item) {
|
||||
Inventory internal = getInventory().getOwnerHandle().getInventory();
|
||||
internal.setSelectedItem(CraftItemStack.asNMSCopy(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack getItemInOffHand() {
|
||||
return getInventory().getOwnerHandle().getBukkitEntity().getInventory().getItemInOffHand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemInOffHand(@Nullable ItemStack item) {
|
||||
getInventory().getOwnerHandle().getBukkitEntity().getInventory().setItemInOffHand(item);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public @NotNull ItemStack getItemInHand() {
|
||||
return getItemInMainHand();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void setItemInHand(@Nullable ItemStack stack) {
|
||||
setItemInMainHand(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeldItemSlot() {
|
||||
Inventory internal = getInventory().getOwnerHandle().getInventory();
|
||||
return internal.getNonEquipmentItems().size() - 9 + internal.getSelectedSlot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeldItemSlot(int slot) {
|
||||
slot %= 9;
|
||||
getInventory().getOwnerHandle().getInventory().setSelectedSlot(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack getItem(@NotNull org.bukkit.inventory.EquipmentSlot slot) {
|
||||
return getInventory().getOwnerHandle().getBukkitEntity().getInventory().getItem(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(@NotNull org.bukkit.inventory.EquipmentSlot slot, @Nullable ItemStack item) {
|
||||
getInventory().getOwnerHandle().getBukkitEntity().getInventory().setItem(slot, item);
|
||||
}
|
||||
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.lishid.openinv.internal.reobf.container.slot;
|
||||
|
||||
import com.lishid.openinv.internal.reobf.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.craftbukkit.v1_21_R4.CraftEquipmentSlot;
|
||||
import org.bukkit.craftbukkit.v1_21_R4.inventory.CraftItemStack;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ContentEquipment implements Content {
|
||||
|
||||
private PlayerInventory equipment;
|
||||
private final ItemStack placeholder;
|
||||
private final org.bukkit.inventory.EquipmentSlot equipmentSlot;
|
||||
|
||||
public ContentEquipment(ServerPlayer holder, EquipmentSlot equipmentSlot) {
|
||||
setHolder(holder);
|
||||
placeholder = switch (equipmentSlot) {
|
||||
case HEAD -> Placeholders.emptyHelmet;
|
||||
case CHEST -> Placeholders.emptyChestplate;
|
||||
case LEGS -> Placeholders.emptyLeggings;
|
||||
case FEET -> Placeholders.emptyBoots;
|
||||
default -> Placeholders.emptyOffHand;
|
||||
};
|
||||
this.equipmentSlot = CraftEquipmentSlot.getSlot(equipmentSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHolder(@NotNull ServerPlayer holder) {
|
||||
this.equipment = holder.getBukkitEntity().getInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack get() {
|
||||
return CraftItemStack.asNMSCopy(equipment.getItem(equipmentSlot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack remove() {
|
||||
org.bukkit.inventory.ItemStack old = equipment.getItem(equipmentSlot);
|
||||
equipment.setItem(equipmentSlot, null);
|
||||
return CraftItemStack.asNMSCopy(old);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removePartial(int amount) {
|
||||
if (amount <= 0) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
ItemStack current = get();
|
||||
if (current.isEmpty()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
ItemStack split = current.split(amount);
|
||||
set(current);
|
||||
return split;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(ItemStack itemStack) {
|
||||
equipment.setItem(equipmentSlot, CraftItemStack.asCraftMirror(itemStack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slot asSlot(Container container, int slot, int x, int y) {
|
||||
return new SlotEquipment(container, slot, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryType.SlotType getSlotType() {
|
||||
return InventoryType.SlotType.ARMOR;
|
||||
}
|
||||
|
||||
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 CraftEquipmentSlot.getNMS(equipmentSlot);
|
||||
}
|
||||
|
||||
public void onlyEquipmentFor(ServerPlayer viewer) {
|
||||
this.viewer = viewer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPlace(@NotNull ItemStack itemStack) {
|
||||
if (viewer == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return equipmentSlot == org.bukkit.inventory.EquipmentSlot.OFF_HAND
|
||||
|| viewer.getEquipmentSlotForItem(itemStack) == CraftEquipmentSlot.getNMS(equipmentSlot);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.lishid.openinv.internal.reobf.container.slot;
|
||||
|
||||
import com.lishid.openinv.internal.reobf.player.OpenPlayer;
|
||||
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;
|
||||
|
||||
public class ContentOffHand extends ContentEquipment {
|
||||
|
||||
private ServerPlayer holder;
|
||||
|
||||
public ContentOffHand(ServerPlayer holder) {
|
||||
super(holder, EquipmentSlot.OFFHAND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHolder(@NotNull ServerPlayer holder) {
|
||||
super.setHolder(holder);
|
||||
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 (OpenPlayer.isConnected(holder.connection) && holder.containerMenu != holder.inventoryMenu) {
|
||||
holder.connection.send(
|
||||
new ClientboundContainerSetSlotPacket(
|
||||
holder.inventoryMenu.containerId,
|
||||
holder.inventoryMenu.incrementStateId(),
|
||||
InventoryMenu.SHIELD_SLOT,
|
||||
holder.getOffhandItem()));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -19,9 +19,9 @@ import net.minecraft.world.level.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.craftbukkit.v1_21_R3.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_21_R3.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_21_R3.event.CraftEventFactory;
|
||||
import org.bukkit.craftbukkit.v1_21_R4.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_21_R4.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_21_R4.event.CraftEventFactory;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ before_install:
|
||||
- sdk install java 21-tem
|
||||
- sdk use java 21-tem
|
||||
install:
|
||||
- ./gradlew :openinvapi:publishJitpackPublicationToMavenLocal
|
||||
- ./gradlew -Djitpack=true :openinvapi:publishJitpackPublicationToMavenLocal
|
||||
@@ -1,3 +1,5 @@
|
||||
import com.github.jikoo.openinv.SpigotReobf
|
||||
|
||||
plugins {
|
||||
`openinv-base`
|
||||
alias(libs.plugins.shadow)
|
||||
@@ -11,10 +13,12 @@ dependencies {
|
||||
implementation(project(":openinvapi"))
|
||||
implementation(project(":openinvcommon"))
|
||||
implementation(project(":openinvadaptercommon"))
|
||||
implementation(project(":openinvadapterpaper1_21_4"))
|
||||
implementation(project(":openinvadapterpaper1_21_3"))
|
||||
implementation(project(":openinvadapterpaper1_21_1"))
|
||||
implementation(project(":openinvadapterspigot", configuration = "reobf"))
|
||||
implementation(project(":openinvadapterspigot", configuration = SpigotReobf.ARTIFACT_CONFIG))
|
||||
implementation(libs.planarwrappers)
|
||||
implementation(libs.folia.scheduler.wrapper)
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
@@ -26,8 +30,11 @@ tasks.jar {
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
relocate("me.nahu.scheduler.wrapper", "com.github.jikoo.openinv.lib.nahu.scheduler-wrapper")
|
||||
relocate("com.github.jikoo.planarwrappers", "com.github.jikoo.openinv.lib.planarwrappers")
|
||||
minimize {
|
||||
exclude(":openinv**")
|
||||
exclude(dependency(libs.folia.scheduler.wrapper.get()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.lishid.openinv.util.lang.LangMigrator;
|
||||
import com.lishid.openinv.util.lang.LanguageManager;
|
||||
import com.lishid.openinv.util.setting.PlayerToggle;
|
||||
import com.lishid.openinv.util.setting.PlayerToggles;
|
||||
import me.nahu.scheduler.wrapper.FoliaWrappedJavaPlugin;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
@@ -59,7 +60,7 @@ import java.util.function.Consumer;
|
||||
/**
|
||||
* The main class for OpenInv.
|
||||
*/
|
||||
public class OpenInv extends JavaPlugin implements IOpenInv {
|
||||
public class OpenInv extends FoliaWrappedJavaPlugin implements IOpenInv {
|
||||
|
||||
private InternalAccessor accessor;
|
||||
private Config config;
|
||||
|
||||
@@ -26,13 +26,13 @@ import com.lishid.openinv.util.TabCompleter;
|
||||
import com.lishid.openinv.util.config.Config;
|
||||
import com.lishid.openinv.util.lang.LanguageManager;
|
||||
import com.lishid.openinv.util.lang.Replacement;
|
||||
import me.nahu.scheduler.wrapper.runnable.WrappedRunnable;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -99,7 +99,7 @@ public class OpenInvCommand implements TabExecutor {
|
||||
name = args[0];
|
||||
}
|
||||
|
||||
new BukkitRunnable() {
|
||||
new WrappedRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final OfflinePlayer offlinePlayer = playerLoader.match(name);
|
||||
@@ -109,7 +109,7 @@ public class OpenInvCommand implements TabExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
new BukkitRunnable() {
|
||||
new WrappedRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!player.isOnline()) {
|
||||
|
||||
@@ -64,7 +64,7 @@ public class InternalAccessor {
|
||||
}
|
||||
|
||||
private @Nullable Accessor getAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
|
||||
Version maxSupported = Version.of(1, 21, 4);
|
||||
Version maxSupported = Version.of(1, 21, 5);
|
||||
Version minSupported = Version.of(1, 21, 1);
|
||||
|
||||
// Ensure version is in supported range.
|
||||
@@ -84,14 +84,18 @@ public class InternalAccessor {
|
||||
}
|
||||
|
||||
// Paper or a Paper fork, can use Mojang-mapped internals.
|
||||
if (BukkitVersions.MINECRAFT.equals(maxSupported)) { // 1.21.4
|
||||
if (BukkitVersions.MINECRAFT.equals(maxSupported)) { // 1.21.5
|
||||
return new com.lishid.openinv.internal.common.InternalAccessor(logger, lang);
|
||||
} else if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 21, 3))) {
|
||||
}
|
||||
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 21, 4))) { // 1.21.4
|
||||
return new com.lishid.openinv.internal.paper1_21_4.InternalAccessor(logger, lang);
|
||||
}
|
||||
if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 21, 2))) {
|
||||
// 1.21.1-1.21.2 placeholder format
|
||||
return new com.lishid.openinv.internal.paper1_21_1.InternalAccessor(logger, lang);
|
||||
}
|
||||
|
||||
// 1.21.3
|
||||
// 1.21.2, 1.21.3
|
||||
return new com.lishid.openinv.internal.paper1_21_3.InternalAccessor(logger, lang);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.lishid.openinv.util;
|
||||
import com.github.jikoo.planarwrappers.util.version.BukkitVersions;
|
||||
import com.github.jikoo.planarwrappers.util.version.Version;
|
||||
import com.google.errorprone.annotations.Keep;
|
||||
import com.lishid.openinv.OpenInv;
|
||||
import com.lishid.openinv.event.OpenEvents;
|
||||
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||
import com.lishid.openinv.internal.ISpecialInventory;
|
||||
@@ -44,11 +45,11 @@ public class InventoryManager implements Listener {
|
||||
private final Map<UUID, ISpecialPlayerInventory> inventories = new ConcurrentHashMap<>();
|
||||
private final Map<UUID, ISpecialEnderChest> enderChests = new ConcurrentHashMap<>();
|
||||
private final Set<UUID> expectedCloses = new HashSet<>();
|
||||
private final @NotNull Plugin plugin;
|
||||
private final @NotNull OpenInv plugin;
|
||||
private final @NotNull Config config;
|
||||
private final @NotNull InternalAccessor accessor;
|
||||
|
||||
public InventoryManager(@NotNull Plugin plugin, @NotNull Config config, @NotNull InternalAccessor accessor) {
|
||||
public InventoryManager(@NotNull OpenInv plugin, @NotNull Config config, @NotNull InternalAccessor accessor) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.accessor = accessor;
|
||||
@@ -164,7 +165,7 @@ public class InventoryManager implements Listener {
|
||||
}
|
||||
|
||||
// Schedule task to check in use status later this tick. Closing user is still in viewer list.
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
if (loaded.isInUse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.lishid.openinv.util;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.errorprone.annotations.Keep;
|
||||
import com.lishid.openinv.OpenInv;
|
||||
import com.lishid.openinv.util.config.Config;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
@@ -18,6 +19,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.logging.Level;
|
||||
@@ -28,7 +30,7 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public class PlayerLoader implements Listener {
|
||||
|
||||
private final @NotNull Plugin plugin;
|
||||
private final @NotNull OpenInv plugin;
|
||||
private final @NotNull Config config;
|
||||
private final @NotNull InventoryManager inventoryManager;
|
||||
private final @NotNull InternalAccessor internalAccessor;
|
||||
@@ -36,7 +38,7 @@ public class PlayerLoader implements Listener {
|
||||
private final @NotNull Cache<String, PlayerProfile> lookupCache;
|
||||
|
||||
public PlayerLoader(
|
||||
@NotNull Plugin plugin,
|
||||
@NotNull OpenInv plugin,
|
||||
@NotNull Config config,
|
||||
@NotNull InventoryManager inventoryManager,
|
||||
@NotNull InternalAccessor internalAccessor,
|
||||
@@ -78,8 +80,8 @@ public class PlayerLoader implements Listener {
|
||||
return internalAccessor.getPlayerDataManager().loadPlayer(offline);
|
||||
}
|
||||
|
||||
Future<Player> future = Bukkit.getScheduler().callSyncMethod(plugin,
|
||||
() -> internalAccessor.getPlayerDataManager().loadPlayer(offline));
|
||||
CompletableFuture<Player> future = new CompletableFuture<>();
|
||||
plugin.getScheduler().runTask(() -> future.complete(internalAccessor.getPlayerDataManager().loadPlayer(offline)));
|
||||
|
||||
try {
|
||||
player = future.get();
|
||||
@@ -195,7 +197,7 @@ public class PlayerLoader implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, () -> {
|
||||
plugin.getScheduler().runTaskLaterAsynchronously(() -> {
|
||||
Iterator<Map.Entry<String, PlayerProfile>> iterator = lookupCache.asMap().entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, PlayerProfile> entry = iterator.next();
|
||||
|
||||
@@ -5,6 +5,7 @@ author: lishid
|
||||
authors: [Jikoo, ShadowRanger]
|
||||
description: Open a player's inventory as a chest and interact with it in real time.
|
||||
api-version: "1.13"
|
||||
folia-supported: true
|
||||
|
||||
permissions:
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"pack": {
|
||||
"description": "Improve OpenInv's legibility",
|
||||
"pack_format": 46,
|
||||
"supported_formats": [ 34, 46 ]
|
||||
"pack_format": 55,
|
||||
"supported_formats": [ 34, 55 ]
|
||||
},
|
||||
"overlays": {
|
||||
"entries": [
|
||||
{
|
||||
"formats": [ 44, 46 ],
|
||||
"formats": [ 44, 55 ],
|
||||
"directory": "openinv_44"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
buildtools_dir=~/buildtools
|
||||
buildtools=$buildtools_dir/BuildTools.jar
|
||||
|
||||
get_buildtools () {
|
||||
if [[ -d $buildtools_dir && -f $buildtools ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir $buildtools_dir
|
||||
wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O $buildtools
|
||||
}
|
||||
|
||||
if [[ ! $1 ]]; then
|
||||
echo "Please specify Spigot version to install."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
get_buildtools
|
||||
|
||||
pushd $buildtools_dir
|
||||
java -jar $buildtools -rev $1 --remapped
|
||||
popd
|
||||
@@ -18,26 +18,41 @@
|
||||
# Note that this script is designed for use in GitHub Actions, and is not
|
||||
# particularly robust nor configurable. Run from project parent directory.
|
||||
|
||||
# Parse Spigot dependency information into major Minecraft versions
|
||||
function get_curseforge_minecraft_versions() {
|
||||
# TODO convert to parsing event body
|
||||
readarray -t versions <<< "1.21.4"
|
||||
if [[ ! $1 ]]; then
|
||||
echo "No changelog, no Minecraft versions."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for version in "${versions[@]}"; do
|
||||
# Parse Minecraft major version
|
||||
version="${version%[.-]"${version#*.*[.-]}"}"
|
||||
# Find line declaring Paper versions.
|
||||
raw=$(grep "**Paper:**" <<< "$1")
|
||||
|
||||
# Skip already listed versions
|
||||
if [[ "$minecraft_versions" =~ "$version"($|,) ]]; then
|
||||
continue
|
||||
fi
|
||||
# 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
|
||||
|
||||
# Append comma if variable is set, then append version
|
||||
minecraft_versions="${minecraft_versions:+${minecraft_versions},}Minecraft ${version}"
|
||||
done
|
||||
# Split into an array on newlines.
|
||||
readarray -td $'\n' versions <<< "${raw}"
|
||||
|
||||
echo "${minecraft_versions}"
|
||||
}
|
||||
for version in "${versions[@]}"; do
|
||||
# Parse Minecraft minor version by dropping everything from the second period onward.
|
||||
# CurseForge doesn't usually add patch versions for Bukkit, so we're more likely to
|
||||
# hit a supported identifier this way.
|
||||
version="${version%[.-]"${version#*.*[.-]}"}"
|
||||
|
||||
minecraft_versions=$(get_curseforge_minecraft_versions)
|
||||
echo "CURSEFORGE_MINECRAFT_VERSIONS=$minecraft_versions" >> "$GITHUB_ENV"
|
||||
# Skip already listed versions
|
||||
if [[ "$minecraft_versions" =~ "$version"($|,) ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Append comma if variable is set, then append version.
|
||||
# Note that Minecraft versions on CurseForge are declared "Minecraft x.y.z"
|
||||
minecraft_versions="${minecraft_versions:+${minecraft_versions},}Minecraft ${version}"
|
||||
done
|
||||
|
||||
printf "$minecraft_versions\n"
|
||||
#echo "CURSEFORGE_MINECRAFT_VERSIONS=$minecraft_versions" >> "$GITHUB_ENV"
|
||||
+30
-27
@@ -3,31 +3,34 @@ rootProject.name = "openinvparent"
|
||||
include(":openinvapi")
|
||||
project(":openinvapi").projectDir = file("api")
|
||||
|
||||
val addons = listOf(
|
||||
"togglepersist"
|
||||
)
|
||||
for (addon in addons) {
|
||||
include(":addon$addon")
|
||||
val proj = project(":addon$addon")
|
||||
proj.projectDir = file("addon/$addon")
|
||||
proj.name = "openinv$addon"
|
||||
if (!java.lang.Boolean.getBoolean("jitpack")) {
|
||||
val addons = listOf(
|
||||
"togglepersist"
|
||||
)
|
||||
for (addon in addons) {
|
||||
include(":addon$addon")
|
||||
val proj = project(":addon$addon")
|
||||
proj.projectDir = file("addon/$addon")
|
||||
proj.name = "openinv$addon"
|
||||
}
|
||||
|
||||
include(":openinvcommon")
|
||||
project(":openinvcommon").projectDir = file("common")
|
||||
|
||||
val internals = listOf(
|
||||
"common",
|
||||
"paper1_21_4",
|
||||
"paper1_21_3",
|
||||
"paper1_21_1",
|
||||
"spigot"
|
||||
)
|
||||
for (internal in internals) {
|
||||
include(":openinvadapter$internal")
|
||||
project(":openinvadapter$internal").projectDir = file("internal/$internal")
|
||||
}
|
||||
|
||||
include(":resource-pack")
|
||||
|
||||
include(":plugin")
|
||||
project(":plugin").name = "openinvplugin"
|
||||
}
|
||||
|
||||
include(":openinvcommon")
|
||||
project(":openinvcommon").projectDir = file("common")
|
||||
|
||||
val internals = listOf(
|
||||
"common",
|
||||
"paper1_21_3",
|
||||
"paper1_21_1",
|
||||
"spigot"
|
||||
)
|
||||
for (internal in internals) {
|
||||
include(":openinvadapter$internal")
|
||||
project(":openinvadapter$internal").projectDir = file("internal/$internal")
|
||||
}
|
||||
|
||||
include(":resource-pack")
|
||||
|
||||
include(":plugin")
|
||||
project(":plugin").name = "openinvplugin"
|
||||
Reference in new issue
Block a user