Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ bin
.settings
.classpath
.project
doc
doc
.claude/
nul
8 changes: 4 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ subprojects {
compileOnly("com.google.guava:guava:21.0")
compileOnly("com.google.code.gson:gson:2.8.7")
compileOnly("org.apache.commons:commons-lang3:3.5")
compileOnly("org.tabooproject.reflex:reflex:1.2.3")
compileOnly("org.tabooproject.reflex:analyser:1.2.3")
compileOnly("org.tabooproject.reflex:reflex:1.2.4")
compileOnly("org.tabooproject.reflex:analyser:1.2.4")
// 测试依赖
testImplementation(kotlin("stdlib"))
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
testImplementation("com.google.guava:guava:21.0")
testImplementation("com.google.code.gson:gson:2.8.7")
testImplementation("org.apache.commons:commons-lang3:3.5")
testImplementation("org.tabooproject.reflex:reflex:1.2.3")
testImplementation("org.tabooproject.reflex:analyser:1.2.3")
testImplementation("org.tabooproject.reflex:reflex:1.2.4")
testImplementation("org.tabooproject.reflex:analyser:1.2.4")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
}
Expand Down
8 changes: 4 additions & 4 deletions common-reflex/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

dependencies {
implementation("org.tabooproject.reflex:reflex:1.2.3")
implementation("org.tabooproject.reflex:analyser:1.2.3")
implementation("org.tabooproject.reflex:reflex:1.2.4")
implementation("org.tabooproject.reflex:analyser:1.2.4")
}

tasks {
withType<ShadowJar> {
dependencies {
include(dependency("org.tabooproject.reflex:reflex:1.2.3"))
include(dependency("org.tabooproject.reflex:analyser:1.2.3"))
include(dependency("org.tabooproject.reflex:reflex:1.2.4"))
include(dependency("org.tabooproject.reflex:analyser:1.2.4"))
}
relocate("org.taboooproject", "taboolib.library")
}
Expand Down
24 changes: 6 additions & 18 deletions common-util/src/main/kotlin/taboolib/common/io/ProjectScanner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,6 @@ var extraLoadedClasses = ConcurrentHashMap<String, ReflexClass>()
*/
var extraLoadedResources = ConcurrentHashMap<String, ByteArray>()

/**
* Reflex 的二进制类缓存会在 JDK 8 读取时触发 ByteBuffer API 兼容问题,
* 因此在 JDK 8 下退回为即时扫描,避免第二次启动读取缓存时报错。
*/
private val isClassBinaryCacheSupported by lazy(LazyThreadSafetyMode.NONE) {
System.getProperty("java.specification.version") != "1.8"
}

/**
* 获取 URL 下的所有类
*/
Expand All @@ -162,14 +154,12 @@ fun URL.getClasses(classLoader: ClassLoader = ClassAppender.getClassLoader()): M
// 是文件
if (srcFile.isFile) {
val srcVersion = srcFile.digest()
if (isClassBinaryCacheSupported) {
// 从二进制缓存中读取
val classMap = BinaryCache.read(srcFile.nameWithoutExtension, srcVersion) {
ReflexClassMap.deserializeFromBytes(it) { name -> Class.forName(name, false, classLoader) }
// 注意:不再立即添加到 reflexClassCacheMap,延迟到访问时添加
}
if (classMap != null) return classMap
// 从二进制缓存中读取
val classMap = BinaryCache.read(srcFile.nameWithoutExtension, srcVersion) {
ReflexClassMap.deserializeFromBytes(it) { name -> Class.forName(name, false, classLoader) }
// 注意:不再立即添加到 reflexClassCacheMap,延迟到访问时添加
}
if (classMap != null) return classMap
// 从文件中解析
JarFile(srcFile).use { jar ->
jar.stream()
Expand All @@ -182,9 +172,7 @@ fun URL.getClasses(classLoader: ClassLoader = ClassAppender.getClassLoader()): M
}
}
// 保存
if (isClassBinaryCacheSupported) {
BinaryCache.save(srcFile.nameWithoutExtension, srcVersion) { ReflexClassMap.serializeToBytes(classes) }
}
BinaryCache.save(srcFile.nameWithoutExtension, srcVersion) { ReflexClassMap.serializeToBytes(classes) }
}
// 是目录
else {
Expand Down
8 changes: 4 additions & 4 deletions common/src/main/java/taboolib/common/ClassAppender.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,15 @@ private static void addURL(ClassLoader loader, Field ucpField, File file, boolea
throw new IllegalStateException("lookup not found");
}
Object ucp = unsafe.getObject(loader, unsafe.objectFieldOffset(ucpField));
MethodHandle methodHandle = lookup.findVirtual(ucp.getClass(), "addURL", MethodType.methodType(void.class, URL.class));
try {
MethodHandle methodHandle = lookup.findVirtual(ucp.getClass(), "addURL", MethodType.methodType(void.class, URL.class));
methodHandle.invoke(ucp, file.toURI().toURL());
for (Callback i : callbacks) {
i.add(loader, file, isExternal);
}
} catch (NoSuchMethodError e) {
throw new IllegalStateException("Unsupported (classloader: " + loader.getClass().getName() + ", ucp: " + ucp.getClass().getName() + ")", e);
}
for (Callback i : callbacks) {
i.add(loader, file, isExternal);
}
}

private static Field ucp(ClassLoader loader) {
Expand Down
7 changes: 5 additions & 2 deletions common/src/main/java/taboolib/common/PrimitiveLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ static List<String[]> deps() {
deps.add(new String[]{"!org.ow2.asm".substring(1), "asm", "9.8"});
deps.add(new String[]{"!org.ow2.asm".substring(1), "asm-util", "9.8"});
deps.add(new String[]{"!org.ow2.asm".substring(1), "asm-commons", "9.8"});
// 都是必要的 incision 强制依赖
deps.add(new String[]{"!org.ow2.asm".substring(1), "asm-tree", "9.8"});
deps.add(new String[]{"!org.ow2.asm".substring(1), "asm-analysis", "9.8"});
return deps;
}

Expand Down Expand Up @@ -97,8 +100,8 @@ public static void init() throws Throwable {
load(REPO_CENTRAL, i[0], i[1], i[2], IS_ISOLATED_MODE, true, rule());
}
// 加载反射模块
load(REPO_REFLEX, TABOOPROJECT_GROUP + ".reflex", "reflex", "1.2.3", IS_ISOLATED_MODE, true, rule());
load(REPO_REFLEX, TABOOPROJECT_GROUP + ".reflex", "analyser", "1.2.3", IS_ISOLATED_MODE, true, rule());
load(REPO_REFLEX, TABOOPROJECT_GROUP + ".reflex", "reflex", "1.2.4", IS_ISOLATED_MODE, true, rule());
load(REPO_REFLEX, TABOOPROJECT_GROUP + ".reflex", "analyser", "1.2.4", IS_ISOLATED_MODE, true, rule());
});
PrimitiveIO.debug("基础依赖加载完成,用时 {0} 毫秒。", time);
// 加载完整模块
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class AsmClassTranslation(val source: String) {
newBytes = remapper.applyRequireTransform(newBytes)
// 应用 dynamic 转换(检测并替换 dynamic() 调用为直接 JVM 指令)
newBytes = remapper.applyDynamicTransform(newBytes)
// 应用额外 transformer(incision 等模块在此织入)
newBytes = remapper.applyExtraTransforms(source, newBytes)
// 缓存
BinaryCache.save("remap/$source", combinedVersion) { newBytes }
// 保存字节码用于调试
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ object MinecraftVersion {
arrayOf("1.19", "1.19.1", "1.19.2", "1.19.3", "1.19.4"), // 11
arrayOf("1.20", "1.20.1", "1.20.2", "!1.20.3", "1.20.4", "!1.20.5", "1.20.6"), // 12 (跳过 1.20.3、1.20.5) NOTICE 从 1.20.5 开始, paper 进行了破坏性修改
arrayOf("!1.21", "1.21.1", "!1.21.2", "1.21.3", "1.21.4", "1.21.5", "!1.21.6", "!1.21.7", "1.21.8", "!1.21.9", "1.21.10", "1.21.11"), // 13 (跳过 1.21、1.21.2、1.21.6、1.21.7 和 1.21.9)
arrayOf("26.1", "26.1.1") // 14 NOTICE 从 26.1 开始, Minecraft 不再被混淆
arrayOf("!26.1", "!26.1.1", "26.1.2") // 14 (跳过 26.1、26.1.1) NOTICE 从 26.1 开始, Minecraft 不再被混淆
// @formatter:on
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import taboolib.common.reflect.ClassHelper
import taboolib.module.nms.MinecraftVersion
import java.util.concurrent.CopyOnWriteArrayList

/**
* 插件内部的类
Expand All @@ -29,6 +30,36 @@ open class RemapTranslation : Remapper() {
val obc2 = "org/bukkit/craftbukkit/${MinecraftVersion.minecraftVersion}/"
val obc3 = "org/bukkit/craftbukkit/"

companion object {

/**
* 额外的字节码变换器 —— 在 remap + require + dynamic 三步之后执行。
*
* 供 [taboolib.module.incision] 等模块在 NMSProxy 管线末端注入自定义织入逻辑。
* 每个 transformer 的签名:`(className, bytes) -> ByteArray?`;
* 返回 null 表示不修改,返回非 null 则替换当前字节码继续传递下一个 transformer。
*
* 线程安全:使用 [java.util.concurrent.CopyOnWriteArrayList]。
*/
@JvmStatic
val extraTransformers: MutableList<(String, ByteArray) -> ByteArray?> = CopyOnWriteArrayList()
}

/** 运行 [extraTransformers] 管线;供 [taboolib.module.nms.AsmClassTranslation] 调用。 */
fun applyExtraTransforms(className: String, classBytes: ByteArray): ByteArray {
if (extraTransformers.isEmpty()) return classBytes
var cur = classBytes
for (t in extraTransformers) {
try {
val out = t(className, cur)
if (out != null) cur = out
} catch (e: Throwable) {
e.printStackTrace()
}
}
return cur
}

override fun map(internalName: String): String {
return translate(internalName)
}
Expand Down Expand Up @@ -143,4 +174,4 @@ open class RemapTranslation : Remapper() {
classBytes
}
}
}
}
Loading
Loading