@@ -2,89 +2,56 @@ package com.lambda.plugin
22
33import com.lambda.Lambda.LOG
44import com.lambda.core.Loadable
5+ import com.lambda.plugin.api.Plugin
56import com.lambda.util.FolderRegister.listRecursive
67import com.lambda.util.FolderRegister.mods
8+ import org.reflections.Reflections
9+ import org.reflections.scanners.Scanners
10+ import org.reflections.util.ConfigurationBuilder
711import java.io.File
12+ import java.lang.reflect.Method
13+ import java.net.URI
14+ import java.net.URL
15+ import java.net.URLClassLoader
816import java.util.jar.JarFile
917
1018object PluginRegistry : Loadable {
11- private val classLoaderError = """
12- An error occurred while retrieving the thread class loader.
13- This likely mean that newer versions of the mod loader
14- have changed the way mods are loaded, affecting the plugin system.
15- Please report this error to the Lambda developers with the following information:
16- - The version of Lambda
17- - The version of the mod loader (ex. Fabric, Forge, etc.)
18- - The version of Minecraft you are using
19- - The version of Java you are using
20-
21- Plugin: %s
22- Stacktrace:
23- %s
24- """ .trimIndent()
19+ val plugins = mutableListOf<Plugin >()
2520
2621 private val loadingError = """
2722 An error occurred while loading a plugin.
28- If you are a developer, please check the plugin's main class and load method.
23+ If you are a developer, please check the plugin's main class, instance or load method.
2924 If you are a regular user, please report this issue to the plugin developer.
3025
3126 Plugin: %s
3227 Error: %s
33- Stacktrace:
34- %s
3528 """ .trimIndent()
3629
37- private fun loadPlugin (file : File ) {
38- runCatching {
39- val jar = JarFile (file)
40-
41- val mainClass = jar.manifest.mainAttributes.getValue(" Main-Class" )
42- ? : return LOG .error(" The plugin $jar does not have a main class" )
43-
44- val loader = PluginLoader (jar,
45- Thread .currentThread().contextClassLoader ? :
46- return classLoaderError.format(
47- file,
48- Thread .currentThread().stackTrace.joinToString(" \n " )
49- )
50- .split(" \n " )
51- .forEach(LOG ::error))
52-
53- val loadClass = loader.loadClass(mainClass)
54-
55- val loadInstance =
56- loadClass.declaredFields.firstOrNull { it.name == " INSTANCE" }?.get(null )
57- ? : loadClass.constructors.firstOrNull()?.newInstance()
58- ? : return LOG .error(" The plugin $jar does not have an object instance or a public constructor" )
59- val loadMethod =
60- loadClass?.methods?.find { it.name == " load" }
61- ? : return LOG .warn(" The plugin $jar does not have a load method" )
62-
63- loadMethod.invoke(loadInstance)
64- }.onFailure {
65- loadingError.format(
66- file,
67- it.message,
68- it.stackTraceToString()
69- )
70- .split(" \n " )
71- .forEach(LOG ::error)
72- }
73- }
74-
7530 override fun load (): String {
76- val plugins = mods
77- .listRecursive {
78- it.isFile && it.extension == " jar"
79- // Not a fan of creating a new JarFile instance every iteration
80- && JarFile (it).manifest.mainAttributes.getValue(" Lambda-Plugin" ) == " true"
81- }
82- val size = plugins.count()
83-
84- plugins.forEach(::loadPlugin)
85-
86- val plural = if (size == 1 ) " " else " s"
31+ Reflections (
32+ ConfigurationBuilder ()
33+ .addUrls(
34+ mods.listRecursive { it.extension == " jar" }
35+ .map { it.toURI().toURL() }
36+ .toList()
37+ )
38+ .addScanners(Scanners .SubTypes )
39+ ).getSubTypesOf(Plugin ::class .java).forEach { pluginClass ->
40+ val instance = (pluginClass.declaredFields.find { it.name == " INSTANCE" }?.get(null )
41+ ? : pluginClass.constructors.firstOrNull()?.newInstance()) as ? Plugin
42+ ? : null .also {
43+ loadingError.format(
44+ pluginClass,
45+ " The plugin does not have an object instance or a public constructor"
46+ ).also { LOG .warn(it) }
47+ }
48+
49+ if (instance == null ) return @forEach
50+
51+ instance.load()
52+ plugins.add(instance)
53+ }
8754
88- return " Loaded $ size plugin $plural "
55+ return " Registered ${plugins. size} plugins "
8956 }
9057}
0 commit comments