
net.chestmc.common.annotations.Module.kt Maven / Gradle / Ivy
package net.chestmc.common.annotations
import com.google.auto.service.AutoService
import kotlinx.serialization.Serializable
import net.chestmc.common.extensions.transform
import org.bukkit.plugin.Plugin
import org.bukkit.plugin.PluginLoadOrder
import org.yaml.snakeyaml.Yaml
import javax.annotation.processing.Processor
import javax.annotation.processing.RoundEnvironment
import javax.annotation.processing.SupportedAnnotationTypes
import javax.annotation.processing.SupportedSourceVersion
import javax.lang.model.SourceVersion
import javax.lang.model.element.Element
import javax.lang.model.element.TypeElement
import javax.tools.StandardLocation
/**
* A module prototype for serializing plugin.yml with [Module].
*/
@Serializable
data class ModulePrototype(
val main: String = "",
val name: String = "",
val version: String = "1.0",
val author: String = "",
val description: String = "",
val website: String = "",
val load: PluginLoadOrder = PluginLoadOrder.POSTWORLD,
val authors: List = emptyList(),
val depend: List = emptyList(),
val softDepend: List = emptyList(),
val loadBefore: List = emptyList()
) {
constructor(template: TypeElement, module: Module) : this(
template.qualifiedName.toString(),
module.name.ifBlank { template.simpleName.toString() },
module.version,
module.author,
module.description,
module.website,
module.load,
module.authors.toList(),
module.depend.toList(),
module.softDepend.toList(),
module.loadBefore.toList()
)
fun toMap(): Map = LinkedHashMap().transform {
put("main", main)
put("name", name)
put("version", version)
put("author", author)
put("description", description)
put("website", website)
put("load", load.name)
put("authors", authors.toTypedArray())
put("depend", depend.toTypedArray())
put("softdepend", softDepend.toTypedArray())
put("loadbefore", loadBefore.toTypedArray())
}
}
/**
* A module annotation represents a plugin settings.
* All settings configured by this module will be inserted in the `plugin.yml`.
* Note that this will be processed in compile-time, using the [ModuleProcessor]
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class Module(
val name: String = "",
val version: String = "1.0",
val author: String = "",
val description: String = "",
val website: String = "",
val load: PluginLoadOrder = PluginLoadOrder.POSTWORLD,
val authors: Array = [],
val depend: Array = [],
val softDepend: Array = [],
val loadBefore: Array = []
)
/**
* A annotation processor for processing [Module] annotations.
* This processor is responsable to create the `plugin.yml` and
* inserts the values inside of them.
*/
@SupportedAnnotationTypes("net.chestmc.common.annotations.Module")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor::class)
class ModuleProcessor : StandardProcessor() {
override fun process(annotations: MutableSet, env: RoundEnvironment): Boolean {
val elements = env.getElementsAnnotatedWith(Module::class.java)
if (elements.isNullOrEmpty())
return false
if (!elements.verifyIfMoreThanOne())
return false
val type = elements.first() as TypeElement
if (!type.isSupported())
return false
create(type)
return true
}
/**
* Verify if a element is extending any of [Plugin] interface.
*/
fun TypeElement.isSupported(): Boolean {
val pluginType = elements.getTypeElement("org.bukkit.plugin.Plugin").asType()
return if (types.isAssignable(superclass, pluginType)) true
else error("The element annotated with @Module not extends any type of org.bukkit.plugin.Plugin")
}
/**
* Verify if this set of elements has more than one element.
*/
fun Set.verifyIfMoreThanOne(): Boolean {
if (size > 1) {
val all = map { it as TypeElement }.joinToString { it.qualifiedName.toString() }
return error("More than one @Module found. Elements annotateds with @Module: $all")
}
return true
}
/**
* Creates the plugin.yml.
*/
fun create(type: TypeElement) {
val prototype = ModulePrototype(type, type.getAnnotation(Module::class.java))
filer.createResource(StandardLocation.CLASS_OUTPUT, "", "plugin.yml")
.openWriter()
.use {
Yaml().dump(prototype.toMap(), it)
it.flush()
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy