From 1d45c1b718b8ac0349437334ccc0439784a76e44 Mon Sep 17 00:00:00 2001
From: Denis Istratov
Date: Tue, 22 Aug 2023 00:41:20 +0300
Subject: [PATCH] Added genref and messages modules
---
build.gradle.kts | 2 +
genref/.gitignore | 42 +++
genref/README.md | 34 +++
genref/build.gradle.kts | 116 ++++++++
.../carcadex/genref/plugin/PluginVisitor.kt | 99 +++++++
.../genref/plugin/annotations/OnDisable.kt | 5 +
.../genref/plugin/annotations/Plugin.kt | 5 +
.../genref/processor/GenRefProcessor.kt | 29 ++
.../genref/processor/ProcessorProvider.kt | 12 +
...ols.ksp.processing.SymbolProcessorProvider | 1 +
messages/.gitignore | 42 +++
messages/build.gradle.kts | 123 +++++++++
messages/libs/MiniMessages.jar | Bin 0 -> 766378 bytes
.../carcadex/messages/container/Messages.java | 257 ++++++++++++++++++
.../messages/container/impl/MessagesImpl.java | 120 ++++++++
.../messages/factory/MessageFactory.java | 17 ++
.../factory/impl/LegacyFactoryImpl.java | 45 +++
.../factory/impl/MessageFactoryImpl.java | 46 ++++
.../messages/kotlin/MessagesExtensions.kt | 32 +++
.../messages/kotlin/TriumphGuiExtensions.kt | 8 +
.../messages/model/AbstractMessage.java | 83 ++++++
.../carcadex/messages/model/Message.java | 79 ++++++
.../messages/model/impl/ComponentMessage.java | 31 +++
.../messages/model/impl/NullMessage.java | 47 ++++
.../impl/serialized/SerializedMessage.java | 33 +++
.../impl/serialized/impl/LegacyMessage.java | 13 +
.../messages/utils/MD5ColorUtils.java | 26 ++
.../messages/verifier/MessageVerifier.java | 7 +
.../verifier/impl/FileMessageVerifier.java | 39 +++
settings.gradle.kts | 2 +
30 files changed, 1395 insertions(+)
create mode 100644 genref/.gitignore
create mode 100644 genref/README.md
create mode 100644 genref/build.gradle.kts
create mode 100644 genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/PluginVisitor.kt
create mode 100644 genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/annotations/OnDisable.kt
create mode 100644 genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/annotations/Plugin.kt
create mode 100644 genref/src/main/kotlin/me/redtea/carcadex/genref/processor/GenRefProcessor.kt
create mode 100644 genref/src/main/kotlin/me/redtea/carcadex/genref/processor/ProcessorProvider.kt
create mode 100644 genref/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
create mode 100644 messages/.gitignore
create mode 100644 messages/build.gradle.kts
create mode 100644 messages/libs/MiniMessages.jar
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/container/Messages.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/container/impl/MessagesImpl.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/factory/MessageFactory.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/factory/impl/LegacyFactoryImpl.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/factory/impl/MessageFactoryImpl.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/kotlin/MessagesExtensions.kt
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/kotlin/TriumphGuiExtensions.kt
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/model/AbstractMessage.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/model/Message.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/model/impl/ComponentMessage.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/model/impl/NullMessage.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/model/impl/serialized/SerializedMessage.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/model/impl/serialized/impl/LegacyMessage.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/utils/MD5ColorUtils.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/verifier/MessageVerifier.java
create mode 100644 messages/src/main/java/me/redtea/carcadex/messages/verifier/impl/FileMessageVerifier.java
diff --git a/build.gradle.kts b/build.gradle.kts
index 25cfd6f..41b8049 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -32,4 +32,6 @@ tasks.register("publishAll") {
dependsOn(tasks.getByPath("architecture:publish"))
dependsOn(tasks.getByPath("extensions:publish"))
dependsOn(tasks.getByPath("serialization:publish"))
+ dependsOn(tasks.getByPath("genref:publish"))
+ dependsOn(tasks.getByPath("messages:publish"))
}
\ No newline at end of file
diff --git a/genref/.gitignore b/genref/.gitignore
new file mode 100644
index 0000000..b63da45
--- /dev/null
+++ b/genref/.gitignore
@@ -0,0 +1,42 @@
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/genref/README.md b/genref/README.md
new file mode 100644
index 0000000..ba5649c
--- /dev/null
+++ b/genref/README.md
@@ -0,0 +1,34 @@
+Instruction for kotlin v. 1.8.21
+Step 1 - configure build.gradle
+Add Kotlin 1.8.21 and KSP plugins:
+
+```kotlin
+kotlin("jvm") version "1.8.21"
+id("com.google.devtools.ksp") version "1.8.21-1.0.11"
+```
+
+Add CarcadeX GenRef and KotlinBukkitAPI to project:
+
+```kotlin
+dependencies {
+ implementation("br.com.devsrsouza.kotlinbukkitapi:architecture:1.0.0-SNAPSHOT")
+ compileOnly("io.github.iredtea:carcadex-genref:[LATEST_VERSION]")
+ ksp("io.github.iredtea:carcadex-genref:[LATEST_VERSION]")
+}
+```
+
+Step 2 - create plugin functions
+
+```kotlin
+@Plugin
+fun KotlinPlugin.start() {
+ // Plugin enable logic
+}
+
+
+//Optional
+@OnDisable
+fun KotlinPlugin.stop() {
+ // Disable enable logic
+}
+```
diff --git a/genref/build.gradle.kts b/genref/build.gradle.kts
new file mode 100644
index 0000000..3046568
--- /dev/null
+++ b/genref/build.gradle.kts
@@ -0,0 +1,116 @@
+plugins {
+ id("java")
+ kotlin("jvm")
+ id("maven-publish")
+ id("signing")
+ id("com.google.devtools.ksp") version "1.8.21-1.0.11"
+}
+
+group = "tech.carcadex"
+val globalArtifactId = "kotlinbukkitkit-genref"
+val globalName = "kotlinbukkitkit-genref"
+
+repositories {
+ mavenCentral()
+ maven {
+ name = "spigotmc-repo"
+ url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
+ }
+}
+
+dependencies {
+ implementation("org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT")
+ implementation(project(":architecture"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:1.8.21-1.0.11")
+ implementation("com.squareup:kotlinpoet:1.10.1")
+ implementation("com.squareup:kotlinpoet-ksp:1.10.1")
+
+}
+tasks.test {
+ useJUnitPlatform()
+}
+
+kotlin {
+ jvmToolchain(8)
+}
+
+kotlin {
+ sourceSets.main {
+ kotlin.srcDir("build/generated/ksp/main/kotlin")
+ }
+ sourceSets.test {
+ kotlin.srcDir("build/generated/ksp/test/kotlin")
+ }
+}
+
+java {
+ withJavadocJar()
+ withSourcesJar()
+}
+
+publishing {
+ publications {
+ create("maven") {
+ artifactId = globalArtifactId
+ groupId = "tech.carcadex"
+ version = version
+ from(components["java"])
+ versionMapping {
+ usage("java-api") {
+ fromResolutionOf("runtimeClasspath")
+ }
+ usage("java-runtime") {
+ fromResolutionResult()
+ }
+ }
+ pom {
+ artifactId = globalArtifactId
+ groupId = "tech.carcadex"
+ version = version
+ name.set(globalArtifactId)
+ description.set(globalArtifactId)
+ url.set("https://github.com/iRedTea/CarcadeX")
+
+ licenses {
+ license {
+ name.set("GNU General Public License v3.0")
+ url.set("https://www.gnu.org/licenses/gpl-3.0.en.html")
+ }
+ }
+ developers {
+ developer {
+ id.set("itzRedTea")
+ name.set("Red Tea")
+ email.set("red__tea@outlook.com")
+ }
+ }
+ scm {
+ connection.set("scm:https://github.com/CarcadeX/$globalName.git")
+ developerConnection.set("git@github.com:CarcadeX/$globalName.git")
+ url.set("https://github.com/iRedTea/CarcadeX")
+ }
+ }
+
+ }
+ }
+
+
+
+ repositories {
+ maven {
+ val releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
+ val snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
+ url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl)
+ credentials {
+ username = "itzRedTea"
+ password = project.findProperty("password").toString()
+ }
+ }
+
+ }
+}
+
+signing {
+ useGpgCmd()
+ sign(publishing.publications.getByName("maven"))
+}
diff --git a/genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/PluginVisitor.kt b/genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/PluginVisitor.kt
new file mode 100644
index 0000000..163190c
--- /dev/null
+++ b/genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/PluginVisitor.kt
@@ -0,0 +1,99 @@
+package me.redtea.carcadex.genref.plugin
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.getAnnotationsByType
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.KSPLogger
+import com.google.devtools.ksp.symbol.KSFile
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSVisitorVoid
+import com.squareup.kotlinpoet.*
+import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview
+import com.squareup.kotlinpoet.ksp.writeTo
+import me.redtea.carcadex.genref.plugin.annotations.OnDisable
+import me.redtea.carcadex.genref.plugin.annotations.Plugin
+import tech.carcadex.kotlinbukkitkit.architecture.KotlinPlugin
+
+@OptIn(KotlinPoetKspPreview::class)
+class PluginVisitor(private val codeGenerator: CodeGenerator,
+ private val logger: KSPLogger
+) : KSVisitorVoid() {
+
+ var funcs: MutableList = mutableListOf()
+
+ override fun visitFile(file: KSFile, data: Unit) {
+ file.declarations.filter { it is KSFunctionDeclaration }.forEach { it.accept(this, Unit) }
+
+ val packageName = file.packageName.asString()
+ val className = file.fileName.replace(
+ ".kt",
+ ""
+ ) + "Plugin"
+
+ val fileSpec = FileSpec.builder(packageName, className).apply {
+ addProperty(
+ PropertySpec.builder(
+ "plugin",
+ ClassName(packageName, className)
+ )
+ .mutable(true)
+ .setter(FunSpec.builder("set()").addModifiers(KModifier.PRIVATE).build())
+ .addModifiers(
+ listOf(
+ KModifier.LATEINIT
+ )
+ )
+ .build()
+ )
+ addType(
+ TypeSpec.Companion.classBuilder(className).primaryConstructor(
+ FunSpec.constructorBuilder().build()
+ )
+ .addFunctions(funcs)
+ .superclass(KotlinPlugin::class)
+ .build()
+ )
+ }.build()
+ try {
+ fileSpec.writeTo(codeGenerator, true)
+ } catch (ignored: FileAlreadyExistsException) {
+ }
+ }
+
+ @OptIn(KspExperimental::class)
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
+ if (function.getAnnotationsByType(OnDisable::class).any()) disable(function)
+
+ if(function.getAnnotationsByType(Plugin::class).any()) enable(function)
+
+
+ function.returnType!!.accept(this, Unit)
+ }
+
+ fun disable(function: KSFunctionDeclaration) {
+ funcs.add(FunSpec.builder("onPluginDisable")
+ .addCode(CodeBlock.of("""
+ ${function.simpleName.getShortName()}()
+ """.trimIndent()))
+ .returns(Unit::class)
+ .addModifiers(KModifier.OVERRIDE)
+ .build())
+
+ }
+
+ fun enable(function: KSFunctionDeclaration) {
+ funcs.add(FunSpec.builder("onPluginEnable")
+ .addCode(CodeBlock.of("""
+ plugin = this
+ ${function.simpleName.getShortName()}()
+
+ """.trimIndent()))
+ .returns(Unit::class)
+ .addModifiers(KModifier.OVERRIDE)
+ .build())
+ }
+
+
+}
+
+
diff --git a/genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/annotations/OnDisable.kt b/genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/annotations/OnDisable.kt
new file mode 100644
index 0000000..86adc59
--- /dev/null
+++ b/genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/annotations/OnDisable.kt
@@ -0,0 +1,5 @@
+package me.redtea.carcadex.genref.plugin.annotations
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.SOURCE)
+annotation class OnDisable()
diff --git a/genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/annotations/Plugin.kt b/genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/annotations/Plugin.kt
new file mode 100644
index 0000000..d28356f
--- /dev/null
+++ b/genref/src/main/kotlin/me/redtea/carcadex/genref/plugin/annotations/Plugin.kt
@@ -0,0 +1,5 @@
+package me.redtea.carcadex.genref.plugin.annotations
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.SOURCE)
+annotation class Plugin()
diff --git a/genref/src/main/kotlin/me/redtea/carcadex/genref/processor/GenRefProcessor.kt b/genref/src/main/kotlin/me/redtea/carcadex/genref/processor/GenRefProcessor.kt
new file mode 100644
index 0000000..579909c
--- /dev/null
+++ b/genref/src/main/kotlin/me/redtea/carcadex/genref/processor/GenRefProcessor.kt
@@ -0,0 +1,29 @@
+package me.redtea.carcadex.genref.processor
+
+import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.isAnnotationPresent
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.KSPLogger
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.validate
+import me.redtea.carcadex.genref.plugin.PluginVisitor
+import me.redtea.carcadex.genref.plugin.annotations.Plugin
+
+class GenRefProcessor(private val codeGenerator: CodeGenerator,
+ private val logger: KSPLogger) : SymbolProcessor {
+ @OptIn(KspExperimental::class)
+ override fun process(resolver: Resolver): List {
+ val files = resolver.getAllFiles().filter { it.declarations.any { it is KSFunctionDeclaration && it.validate()
+ && it.isAnnotationPresent(Plugin::class)} }
+
+ files.let { files -> files.forEach {
+ it.accept(PluginVisitor(codeGenerator, logger), Unit)
+ }
+ }
+ return files.filter { it.validate() }.toList()
+ }
+
+}
\ No newline at end of file
diff --git a/genref/src/main/kotlin/me/redtea/carcadex/genref/processor/ProcessorProvider.kt b/genref/src/main/kotlin/me/redtea/carcadex/genref/processor/ProcessorProvider.kt
new file mode 100644
index 0000000..0c583cc
--- /dev/null
+++ b/genref/src/main/kotlin/me/redtea/carcadex/genref/processor/ProcessorProvider.kt
@@ -0,0 +1,12 @@
+package me.redtea.carcadex.genref.processor
+
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+
+class ProcessorProvider : SymbolProcessorProvider {
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
+ return GenRefProcessor(environment.codeGenerator, environment.logger)
+ }
+
+}
\ No newline at end of file
diff --git a/genref/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/genref/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 0000000..3b1b8f6
--- /dev/null
+++ b/genref/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+me.redtea.carcadex.genref.processor.ProcessorProvider
\ No newline at end of file
diff --git a/messages/.gitignore b/messages/.gitignore
new file mode 100644
index 0000000..b63da45
--- /dev/null
+++ b/messages/.gitignore
@@ -0,0 +1,42 @@
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/messages/build.gradle.kts b/messages/build.gradle.kts
new file mode 100644
index 0000000..4432378
--- /dev/null
+++ b/messages/build.gradle.kts
@@ -0,0 +1,123 @@
+plugins {
+ id("java")
+ kotlin("jvm")
+ id("maven-publish")
+ id("signing")
+}
+
+group = "tech.carcadex"
+val globalArtifactId = "kotlinbukkitkit-messages"
+val globalName = "kotlinbukkitkit-messages"
+
+repositories {
+ mavenCentral()
+ maven {
+ name = "papermc-repo"
+ url = uri("https://repo.papermc.io/repository/maven-public/")
+ }
+}
+
+dependencies {
+ compileOnly("com.destroystokyo.paper:paper-api:1.16.5-R0.1-SNAPSHOT")
+
+ compileOnly("org.projectlombok:lombok:1.18.26")
+ annotationProcessor("org.projectlombok:lombok:1.18.26")
+
+ compileOnly("dev.triumphteam:triumph-gui:3.1.2")
+
+ compileOnly("com.github.cryptomorin:XSeries:9.2.0") //add to libs
+ compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1")
+
+ implementation("net.kyori:adventure-api:4.14.0")
+ implementation("net.kyori:adventure-platform-bukkit:4.3.0")
+ implementation(files(parent!!.files("messages/libs/MiniMessages.jar"))) //using universal minimessages,
+}
+
+tasks.test {
+ useJUnitPlatform()
+}
+
+kotlin {
+ jvmToolchain(8)
+}
+
+kotlin {
+ sourceSets.main {
+ kotlin.srcDir("build/generated/ksp/main/kotlin")
+ }
+ sourceSets.test {
+ kotlin.srcDir("build/generated/ksp/test/kotlin")
+ }
+}
+
+java {
+ withJavadocJar()
+ withSourcesJar()
+}
+
+publishing {
+ publications {
+ create("maven") {
+ artifactId = globalArtifactId
+ groupId = "tech.carcadex"
+ version = version
+ from(components["java"])
+ versionMapping {
+ usage("java-api") {
+ fromResolutionOf("runtimeClasspath")
+ }
+ usage("java-runtime") {
+ fromResolutionResult()
+ }
+ }
+ pom {
+ artifactId = globalArtifactId
+ groupId = "tech.carcadex"
+ version = version
+ name.set(globalArtifactId)
+ description.set(globalArtifactId)
+ url.set("https://github.com/iRedTea/CarcadeX")
+
+ licenses {
+ license {
+ name.set("GNU General Public License v3.0")
+ url.set("https://www.gnu.org/licenses/gpl-3.0.en.html")
+ }
+ }
+ developers {
+ developer {
+ id.set("itzRedTea")
+ name.set("Red Tea")
+ email.set("red__tea@outlook.com")
+ }
+ }
+ scm {
+ connection.set("scm:https://github.com/CarcadeX/$globalName.git")
+ developerConnection.set("git@github.com:CarcadeX/$globalName.git")
+ url.set("https://github.com/iRedTea/CarcadeX")
+ }
+ }
+
+ }
+ }
+
+
+
+ repositories {
+ maven {
+ val releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
+ val snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
+ url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl)
+ credentials {
+ username = "itzRedTea"
+ password = project.findProperty("password").toString()
+ }
+ }
+
+ }
+}
+
+signing {
+ useGpgCmd()
+ sign(publishing.publications.getByName("maven"))
+}
diff --git a/messages/libs/MiniMessages.jar b/messages/libs/MiniMessages.jar
new file mode 100644
index 0000000000000000000000000000000000000000..7bdeb9eb95619ec95314df9ccbbccd453db6de9e
GIT binary patch
literal 766378
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