Skip to content

Commit a709d54

Browse files
committed
Fix: Plugins not executed correctly
1 parent 5b92a61 commit a709d54

File tree

5 files changed

+59
-15
lines changed

5 files changed

+59
-15
lines changed

common/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ dependencies {
2424

2525
// Add Kotlin
2626
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion")
27+
implementation(kotlin("reflect"))
2728

2829
// Baritone
2930
modImplementation("baritone-api:baritone-api:1.10.2")

common/src/main/kotlin/com/lambda/core/Loader.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ import kotlin.system.measureTimeMillis
1414

1515
object Loader {
1616
private val loadables = listOf(
17-
PluginRegistry,
1817
ModuleRegistry,
1918
CommandManager,
2019
RotationManager,
2120
PlayerPacketManager,
2221
LambdaFont.Loader,
2322
GuiConfigurable,
2423
FriendManager,
24+
PluginRegistry, // The plugins must absolutely be loaded last
2525
)
2626

2727
fun initialize() {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.lambda.plugin
2+
3+
import java.util.jar.JarFile
4+
5+
class JarClassLoader(
6+
private val jarFile: JarFile,
7+
parent: ClassLoader,
8+
) : ClassLoader(parent) {
9+
private val classes = mutableMapOf<String, ByteArray>()
10+
private val resources = mutableMapOf<String, ByteArray>()
11+
12+
init {
13+
jarFile.entries().asSequence().forEach { entry ->
14+
if (entry.isDirectory) return@forEach
15+
16+
val bytes = jarFile.getInputStream(entry).use { it.readBytes() }
17+
if (entry.name.endsWith(".class")) {
18+
classes[
19+
entry.name.removeSuffix(".class")
20+
.replace('/', '.')
21+
] = bytes
22+
} else {
23+
resources[entry.name] = bytes
24+
}
25+
}
26+
}
27+
28+
public override fun findClass(name: String): Class<*> {
29+
val clazz = classes[name] ?: throw ClassNotFoundException(name)
30+
return defineClass(name, clazz, 0, clazz.size)
31+
}
32+
33+
fun close() {
34+
jarFile.close()
35+
}
36+
}

common/src/main/kotlin/com/lambda/plugin/PluginRegistry.kt

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
11
package com.lambda.plugin
22

3-
import com.lambda.Lambda
43
import com.lambda.Lambda.LOG
54
import com.lambda.core.Loadable
6-
import com.lambda.plugin.api.Plugin
7-
import com.lambda.util.Communication.warn
85
import com.lambda.util.FolderRegister.createIfNotExists
96
import com.lambda.util.FolderRegister.listRecursive
107
import com.lambda.util.FolderRegister.plugins
118
import java.io.File
12-
import java.net.URLClassLoader
139
import java.util.jar.JarFile
1410

1511
object PluginRegistry : Loadable {
1612
private fun loadPlugin(file: File) {
17-
val loader = URLClassLoader(arrayOf(file.toURI().toURL()))
18-
val manifest = JarFile(file).manifest
19-
val mainClass = manifest.mainAttributes.getValue("Main-Class")
13+
if (!file.name.endsWith(".jar")) return
14+
if (file.length() == 0L) return LOG.error("The plugin $file is empty")
2015

21-
val clazz = loader.loadClass(mainClass)
22-
val isObject = clazz.declaredFields.any { it.name == "INSTANCE" }
23-
val instance = if (isObject) clazz.getDeclaredField("INSTANCE").get(null)
24-
else clazz.getDeclaredConstructor().newInstance()
16+
val jar = JarFile(file)
17+
val loader = JarClassLoader(jar, this::class.java.classLoader)
18+
val mainClass = jar.manifest.mainAttributes.getValue("Main-Class")
19+
?: return LOG.error("The plugin $jar does not have a main class")
2520

26-
if (instance is Plugin) instance.load()
27-
else LOG.warn("Plugin $file is not a valid plugin")
21+
val clazz = loader.findClass(mainClass)
22+
val instance =
23+
clazz.declaredFields.firstOrNull { it.name == "INSTANCE" }?.get(null) ?: clazz.constructors.firstOrNull()
24+
?.newInstance()
25+
?: return LOG.error("The plugin $jar does not have an object instance or a public constructor")
26+
27+
val loadMethod =
28+
clazz.methods.find { it.name == "load" } ?: return LOG.warn("The plugin $jar does not have a load method")
29+
30+
loadMethod.invoke(instance)
31+
loader.close()
2832
}
2933

3034
override fun load(): String {

common/src/main/kotlin/com/lambda/util/FolderRegister.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ import java.net.InetSocketAddress
1111
/**
1212
* The [FolderRegister] object is responsible for managing the directory structure of the application.
1313
*
14-
* @property minecraft The root directory of the Minecraft client. It is retrieved using the [Platform.getGameFolder] function of the Architectury API.
14+
* @property minecraft The root directory of the Minecraft client.
1515
* @property lambda The directory for the Lambda client, located within the Minecraft directory.
1616
* @property config The directory for storing configuration files, located within the Lambda directory.
17+
* @property packetLogs The directory for storing packet logs, located within the Lambda directory.
18+
* @property replay The directory for storing replay files, located within the Lambda directory.
19+
* @property plugins The directory for storing plugin files, located within the Lambda directory.
1720
*/
1821
object FolderRegister {
1922
val minecraft: File = mc.runDirectory

0 commit comments

Comments
 (0)