支持 Leaf 1.21.11 并内置 TabooLib 依赖
This commit is contained in:
+125
-7
@@ -1,9 +1,7 @@
|
||||
import io.izzel.taboolib.gradle.*
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
id("io.izzel.taboolib") version "2.0.11"
|
||||
id("io.izzel.taboolib") version "2.0.2-community-1"
|
||||
id("org.jetbrains.kotlin.jvm") version "1.7.10"
|
||||
}
|
||||
|
||||
@@ -23,12 +21,27 @@ taboolib {
|
||||
bukkitNodes["update-info"] = "支持1.12.2物品附加值"
|
||||
}
|
||||
env {
|
||||
install(NMS_UTIL, UI)
|
||||
install(EXPANSION_COMMAND_HELPER, BUKKIT_ALL)
|
||||
install(DATABASE, CHAT, CONFIGURATION, LANG, NMS, KETHER)
|
||||
// TabooLib 6.2 split the legacy bundles into versioned modules. The
|
||||
// 6.2 platform contains the Bukkit 1.21 compatibility layer.
|
||||
install(
|
||||
"bukkit-ui",
|
||||
"minecraft-command-helper",
|
||||
"bukkit-hook",
|
||||
"bukkit-util",
|
||||
"bukkit-xseries",
|
||||
"platform-bukkit",
|
||||
"platform-bukkit-impl",
|
||||
"database",
|
||||
"minecraft-chat",
|
||||
"basic-configuration",
|
||||
"minecraft-i18n",
|
||||
"minecraft-kether"
|
||||
)
|
||||
|
||||
repoTabooLib = "https://maven.xbaimiao.com/repository/maven-public/"
|
||||
}
|
||||
version {
|
||||
taboolib = "6.1.1-beta17"
|
||||
taboolib = "6.2.0-beta33"
|
||||
}
|
||||
// relocate("kotlin", "libs.kotlin171")
|
||||
relocate("com.xbaimiao.ktor", "com.github.xbaimiao.shoppro.stat")
|
||||
@@ -40,6 +53,111 @@ repositories {
|
||||
maven("https://r.irepo.space/maven/")
|
||||
}
|
||||
|
||||
val bundledRuntime by configurations.creating
|
||||
|
||||
val taboolibRuntimeModules = listOf(
|
||||
"common",
|
||||
"platform-bukkit",
|
||||
"common-env",
|
||||
"common-util",
|
||||
"common-legacy-api",
|
||||
"common-platform-api",
|
||||
"bukkit-ui",
|
||||
"minecraft-command-helper",
|
||||
"bukkit-hook",
|
||||
"bukkit-util",
|
||||
"bukkit-xseries",
|
||||
"platform-bukkit-impl",
|
||||
"database",
|
||||
"minecraft-chat",
|
||||
"basic-configuration",
|
||||
"minecraft-i18n",
|
||||
"minecraft-kether"
|
||||
)
|
||||
|
||||
dependencies {
|
||||
// These files are embedded as resources and installed before TabooLib's
|
||||
// primitive loader runs, so a server can start without Maven access.
|
||||
add("bundledRuntime", "me.lucko:jar-relocator:1.7")
|
||||
add("bundledRuntime", "org.ow2.asm:asm:9.6")
|
||||
add("bundledRuntime", "org.ow2.asm:asm-util:9.6")
|
||||
add("bundledRuntime", "org.ow2.asm:asm-commons:9.6")
|
||||
add("bundledRuntime", "org.tabooproject.reflex:reflex:1.1.7")
|
||||
add("bundledRuntime", "org.tabooproject.reflex:analyser:1.1.7")
|
||||
add("bundledRuntime", "org.jetbrains.kotlin:kotlin-stdlib:1.7.10")
|
||||
add("bundledRuntime", "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10")
|
||||
add("bundledRuntime", "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3")
|
||||
taboolibRuntimeModules.forEach { module ->
|
||||
add("bundledRuntime", "io.izzel.taboolib:$module:6.2.0-beta33")
|
||||
}
|
||||
}
|
||||
|
||||
val prepareBundledRuntime by tasks.registering {
|
||||
val output = layout.buildDirectory.dir("generated/bundled-runtime")
|
||||
outputs.dir(output)
|
||||
doLast {
|
||||
val root = output.get().asFile
|
||||
root.deleteRecursively()
|
||||
val resourceRoot = root.resolve("META-INF/taboolib/bundled")
|
||||
val index = linkedMapOf<String, String>()
|
||||
configurations["bundledRuntime"].resolvedConfiguration.resolvedArtifacts.forEach { artifact ->
|
||||
val module = artifact.moduleVersion.id
|
||||
val relative = "${module.group.replace('.', '/')}/${module.name}/${module.version}/${module.name}-${module.version}.jar"
|
||||
val destination = resourceRoot.resolve(relative)
|
||||
destination.parentFile.mkdirs()
|
||||
artifact.file.copyTo(destination, overwrite = true)
|
||||
index[relative] = relative
|
||||
|
||||
// The TabooLib build metadata in this project is generated by the
|
||||
// Kotlin 1.7.10 Gradle plugin, while Reflex 1.1.7 resolves a newer
|
||||
// compatible stdlib transitively. Install the resolved bytes at
|
||||
// the exact paths PrimitiveSettings requests as well.
|
||||
if (module.group == "org.jetbrains.kotlin" &&
|
||||
(module.name == "kotlin-stdlib" || module.name == "kotlin-stdlib-jdk8")) {
|
||||
val requested = "${module.group.replace('.', '/')}/${module.name}/1.7.10/${module.name}-1.7.10.jar"
|
||||
val requestedDestination = resourceRoot.resolve(requested)
|
||||
requestedDestination.parentFile.mkdirs()
|
||||
artifact.file.copyTo(requestedDestination, overwrite = true)
|
||||
index[requested] = requested
|
||||
val requestedPom = requested.removeSuffix(".jar") + ".pom"
|
||||
val requestedPomFile = resourceRoot.resolve(requestedPom)
|
||||
requestedPomFile.parentFile.mkdirs()
|
||||
requestedPomFile.writeText(
|
||||
"<project><modelVersion>4.0.0</modelVersion>" +
|
||||
"<groupId>${module.group}</groupId><artifactId>${module.name}</artifactId>" +
|
||||
"<version>1.7.10</version></project>",
|
||||
Charsets.UTF_8
|
||||
)
|
||||
index[requestedPom] = requestedPom
|
||||
}
|
||||
|
||||
// RuntimeEnvDependency checks POM + SHA-1 files for Kotlin and
|
||||
// coroutine roots. A minimal local POM is sufficient because all
|
||||
// requested root JARs are bundled explicitly.
|
||||
if (module.group == "org.jetbrains.kotlin" || module.group == "org.jetbrains.kotlinx") {
|
||||
val pomRelative = relative.removeSuffix(".jar") + ".pom"
|
||||
val pom = resourceRoot.resolve(pomRelative)
|
||||
pom.parentFile.mkdirs()
|
||||
pom.writeText(
|
||||
"<project><modelVersion>4.0.0</modelVersion>" +
|
||||
"<groupId>${module.group}</groupId><artifactId>${module.name}</artifactId>" +
|
||||
"<version>${module.version}</version></project>",
|
||||
Charsets.UTF_8
|
||||
)
|
||||
index[pomRelative] = pomRelative
|
||||
}
|
||||
}
|
||||
val indexFile = root.resolve("META-INF/taboolib/bundled-libraries.properties")
|
||||
indexFile.parentFile.mkdirs()
|
||||
indexFile.writeText(index.entries.joinToString("\n") { (target, resource) -> "$target=$resource" } + "\n", Charsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
dependsOn(prepareBundledRuntime)
|
||||
from(prepareBundledRuntime)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("com.mojang:authlib:3.16.29")
|
||||
compileOnly("ink.ptms:nms-all:1.0.0")
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
group=com.github.xbaimiao.shoppro
|
||||
version=1.3.5-SNAPSHOT
|
||||
version=1.3.6-SNAPSHOT
|
||||
|
||||
+9
-1
@@ -1 +1,9 @@
|
||||
rootProject.name="ShopPro"
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven("https://maven.xbaimiao.com/repository/maven-public/")
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "ShopPro"
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
package taboolib.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Installs the libraries bundled by the build into TabooLib's normal cache
|
||||
* before PrimitiveLoader starts resolving dependencies.
|
||||
*/
|
||||
public final class BundledLibraryBootstrap {
|
||||
|
||||
private static final String INDEX = "META-INF/taboolib/bundled-libraries.properties";
|
||||
private static final String RESOURCE_PREFIX = "META-INF/taboolib/bundled/";
|
||||
|
||||
private BundledLibraryBootstrap() {
|
||||
}
|
||||
|
||||
public static void install() {
|
||||
Properties index = new Properties();
|
||||
try (InputStream input = BundledLibraryBootstrap.class.getClassLoader().getResourceAsStream(INDEX)) {
|
||||
if (input == null) {
|
||||
return;
|
||||
}
|
||||
index.load(input);
|
||||
} catch (IOException ignored) {
|
||||
return;
|
||||
}
|
||||
|
||||
String libraryRoot = "libraries";
|
||||
try (InputStream input = BundledLibraryBootstrap.class.getClassLoader()
|
||||
.getResourceAsStream("META-INF/taboolib/env.properties")) {
|
||||
if (input != null) {
|
||||
Properties env = new Properties();
|
||||
env.load(input);
|
||||
libraryRoot = env.getProperty("file-libs", libraryRoot);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
// The generated defaults already use "libraries".
|
||||
}
|
||||
|
||||
File root = new File(libraryRoot);
|
||||
for (String relativePath : index.stringPropertyNames()) {
|
||||
String resourcePath = index.getProperty(relativePath);
|
||||
if (resourcePath == null || resourcePath.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
File target = new File(root, relativePath.replace('/', File.separatorChar));
|
||||
try {
|
||||
boolean managedArtifact = relativePath.endsWith(".jar") || relativePath.endsWith(".pom");
|
||||
if (!target.isFile() || target.length() == 0L || (managedArtifact && !isSha1Valid(target))) {
|
||||
File parent = target.getParentFile();
|
||||
if (parent != null && !parent.exists() && !parent.mkdirs() && !parent.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
try (InputStream input = BundledLibraryBootstrap.class.getClassLoader()
|
||||
.getResourceAsStream(RESOURCE_PREFIX + resourcePath);
|
||||
OutputStream output = Files.newOutputStream(target.toPath())) {
|
||||
if (input == null) {
|
||||
continue;
|
||||
}
|
||||
byte[] buffer = new byte[8192];
|
||||
int read;
|
||||
while ((read = input.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (managedArtifact) {
|
||||
writeSha1(target);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
// PrimitiveLoader will report a clear download/load error if a
|
||||
// bundled file cannot be installed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeSha1(File file) throws IOException {
|
||||
File sha1 = new File(file.getPath() + ".sha1");
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||
try (InputStream input = Files.newInputStream(file.toPath())) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int read;
|
||||
while ((read = input.read(buffer)) != -1) {
|
||||
digest.update(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
StringBuilder value = new StringBuilder(40);
|
||||
for (byte part : digest.digest()) {
|
||||
value.append(String.format("%02x", part & 0xff));
|
||||
}
|
||||
Files.write(sha1.toPath(), value.toString().getBytes(java.nio.charset.StandardCharsets.US_ASCII));
|
||||
} catch (java.security.NoSuchAlgorithmException ex) {
|
||||
throw new IOException("SHA-1 is unavailable", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSha1Valid(File file) {
|
||||
File sha1 = new File(file.getPath() + ".sha1");
|
||||
if (!sha1.isFile() || sha1.length() == 0L) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
String expected = new String(Files.readAllBytes(sha1.toPath()), java.nio.charset.StandardCharsets.US_ASCII)
|
||||
.trim().toLowerCase(java.util.Locale.ROOT);
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||
try (InputStream input = Files.newInputStream(file.toPath())) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int read;
|
||||
while ((read = input.read(buffer)) != -1) {
|
||||
digest.update(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
StringBuilder actual = new StringBuilder(40);
|
||||
for (byte part : digest.digest()) {
|
||||
actual.append(String.format("%02x", part & 0xff));
|
||||
}
|
||||
return actual.toString().equals(expected);
|
||||
} catch (Exception ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package taboolib.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Properties;
|
||||
|
||||
import static java.lang.System.getProperty;
|
||||
|
||||
/** Runtime settings used by the embedded TabooLib primitive loader. */
|
||||
public class PrimitiveSettings {
|
||||
|
||||
static {
|
||||
// This runs before any PrimitiveLoader dependency check.
|
||||
BundledLibraryBootstrap.install();
|
||||
}
|
||||
|
||||
public static final String ID = "!taboolib".substring(1);
|
||||
public static final Properties RUNTIME_PROPERTIES = getProperties("env", true);
|
||||
public static final Properties VERSION_PROPERTIES = getProperties("version", false);
|
||||
|
||||
public static final String KOTLIN_VERSION = VERSION_PROPERTIES.getProperty(
|
||||
"!kotlin".substring(1), getProperty("taboolib.kotlin.stdlib", "1.8.22"));
|
||||
public static final String KOTLIN_COROUTINES_VERSION = VERSION_PROPERTIES.getProperty(
|
||||
"!kotlin-coroutines".substring(1), getProperty("taboolib.kotlin.coroutines", "1.7.3"));
|
||||
public static final String TABOOLIB_VERSION = VERSION_PROPERTIES.getProperty(
|
||||
ID, getProperty("taboolib.version", "skip"));
|
||||
public static final boolean SKIP_KOTLIN_RELOCATE = VERSION_PROPERTIES.getProperty(
|
||||
"skip-kotlin-relocate", getProperty("taboolib.skip-relocate.kotlin", "false")).equals("true");
|
||||
public static final boolean SKIP_TABOOLIB_RELOCATE = VERSION_PROPERTIES.getProperty(
|
||||
"skip-taboolib-relocate", getProperty("taboolib.skip-relocate.self", "false")).equals("true");
|
||||
public static final boolean IS_DEV_MODE = TABOOLIB_VERSION.endsWith("-dev")
|
||||
|| getProperty("taboolib.dev", "false").equals("true");
|
||||
public static final boolean IS_DEBUG_MODE = IS_DEV_MODE
|
||||
|| RUNTIME_PROPERTIES.getProperty("debug", getProperty("taboolib.debug", "false")).equals("true");
|
||||
public static final boolean IS_FORCE_DOWNLOAD_IN_DEV_MODE = RUNTIME_PROPERTIES
|
||||
.getProperty("force-download-in-dev", "true").equals("true");
|
||||
public static final String REPO_CENTRAL = RUNTIME_PROPERTIES.getProperty(
|
||||
"repo-central", getProperty("taboolib.repo.central", "https://maven.aliyun.com/repository/central"));
|
||||
public static final String REPO_TABOOLIB = RUNTIME_PROPERTIES.getProperty(
|
||||
"repo-taboolib", getProperty("taboolib.repo.self", "https://maven.xbaimiao.com/repository/maven-public/"));
|
||||
public static final String REPO_REFLEX = RUNTIME_PROPERTIES.getProperty(
|
||||
"repo-reflex", getProperty("taboolib.repo.reflex", REPO_TABOOLIB));
|
||||
public static final String FILE_LIBS = RUNTIME_PROPERTIES.getProperty("file-libs", "libraries");
|
||||
public static final String FILE_ASSETS = RUNTIME_PROPERTIES.getProperty("file-assets", "assets");
|
||||
public static boolean IS_ISOLATED_MODE = RUNTIME_PROPERTIES
|
||||
.getProperty("enable-isolated-classloader", "false").equals("true");
|
||||
public static final String[] INSTALL_MODULES = RUNTIME_PROPERTIES
|
||||
.getProperty("module", getProperty("taboolib.module", "")).split(",");
|
||||
|
||||
public static String formatVersion(String value) {
|
||||
return value.replaceAll("[._-]", "");
|
||||
}
|
||||
|
||||
public static String getRelocatedKotlinVersion() {
|
||||
return "kotlin" + formatVersion(KOTLIN_VERSION);
|
||||
}
|
||||
|
||||
public static String getRelocatedKotlinCoroutinesVersion() {
|
||||
return "kotlin" + formatVersion(KOTLIN_VERSION) + "x.coroutines"
|
||||
+ formatVersion(KOTLIN_COROUTINES_VERSION);
|
||||
}
|
||||
|
||||
private static Properties getProperties(String name, boolean allowGlobal) {
|
||||
Properties properties = new Properties();
|
||||
URL url = PrimitiveSettings.class.getClassLoader()
|
||||
.getResource("META-INF/taboolib/" + name + ".properties");
|
||||
if (url != null) {
|
||||
try (InputStreamHolder ignored = new InputStreamHolder(url.openStream())) {
|
||||
properties.load(ignored.input);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
if (allowGlobal) {
|
||||
File globalFile = new File(name + ".properties");
|
||||
if (globalFile.isFile()) {
|
||||
try (FileInputStream input = new FileInputStream(globalFile)) {
|
||||
properties.load(input);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/** Small closeable holder to keep the try-with-resources block Java 8 compatible. */
|
||||
private static final class InputStreamHolder implements AutoCloseable {
|
||||
private final java.io.InputStream input;
|
||||
|
||||
private InputStreamHolder(java.io.InputStream input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
input.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.github.xbaimiao.shoppro.util
|
||||
|
||||
import com.mojang.authlib.GameProfile
|
||||
import com.mojang.authlib.properties.Property
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.ChatColor
|
||||
import org.bukkit.Color
|
||||
import org.bukkit.Material
|
||||
@@ -18,6 +19,8 @@ import taboolib.library.reflex.Reflex.Companion.setProperty
|
||||
import taboolib.library.xseries.XMaterial
|
||||
import taboolib.module.chat.colored
|
||||
import taboolib.platform.util.isAir
|
||||
import java.net.URL
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.*
|
||||
|
||||
|
||||
@@ -195,6 +198,58 @@ open class ItemBuilder {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Bukkit 1.21 stores skull profiles as ResolvableProfile instead of the
|
||||
* authlib GameProfile used by older CraftBukkit versions. Prefer the
|
||||
* public PlayerProfile API when it is available and keep the reflective
|
||||
* field fallback for older servers.
|
||||
*/
|
||||
private fun setSkullTexture(skull: SkullMeta, texture: SkullTexture) {
|
||||
val applied = runCatching {
|
||||
val url = textureUrl(texture.textures) ?: return@runCatching false
|
||||
val createProfile = Bukkit::class.java.methods.firstOrNull {
|
||||
it.name == "createPlayerProfile" &&
|
||||
it.parameterTypes.size == 1 &&
|
||||
it.parameterTypes[0] == UUID::class.java
|
||||
} ?: return@runCatching false
|
||||
val profile = createProfile.invoke(null, texture.uuid ?: UUID.randomUUID())
|
||||
val textures = profile.javaClass.methods.firstOrNull {
|
||||
it.name == "getTextures" && it.parameterTypes.isEmpty()
|
||||
}?.invoke(profile) ?: return@runCatching false
|
||||
val setSkin = textures.javaClass.methods.firstOrNull {
|
||||
it.name == "setSkin" &&
|
||||
it.parameterTypes.size == 1 &&
|
||||
it.parameterTypes[0] == URL::class.java
|
||||
} ?: return@runCatching false
|
||||
setSkin.invoke(textures, URL(url))
|
||||
val setProfile = skull.javaClass.methods.firstOrNull {
|
||||
it.name == "setPlayerProfile" &&
|
||||
it.parameterTypes.size == 1
|
||||
} ?: return@runCatching false
|
||||
setProfile.invoke(skull, profile)
|
||||
true
|
||||
}.getOrDefault(false)
|
||||
|
||||
if (!applied) {
|
||||
runCatching {
|
||||
skull.setProperty("profile", GameProfile(texture.uuid, "test").also {
|
||||
it.properties.put("textures", Property("textures", texture.textures))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun textureUrl(value: String): String? {
|
||||
if (value.startsWith("http://") || value.startsWith("https://")) {
|
||||
return value
|
||||
}
|
||||
val decoded = runCatching {
|
||||
String(Base64.getDecoder().decode(value), StandardCharsets.UTF_8)
|
||||
}.getOrNull() ?: return null
|
||||
return Regex("\\\"url\\\"\\s*:\\s*\\\"([^\\\"]+)\\\"")
|
||||
.find(decoded)?.groupValues?.get(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 上色
|
||||
*/
|
||||
@@ -255,9 +310,7 @@ open class ItemBuilder {
|
||||
itemMeta.owner = skullOwner
|
||||
}
|
||||
if (skullTexture != null) {
|
||||
itemMeta.setProperty("profile", GameProfile(skullTexture!!.uuid, "test").also {
|
||||
it.properties.put("textures", Property("textures", skullTexture!!.textures))
|
||||
})
|
||||
setSkullTexture(itemMeta, skullTexture!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user