diff --git a/serialization/.gitignore b/serialization/.gitignore new file mode 100644 index 0000000..b63da45 --- /dev/null +++ b/serialization/.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/serialization/build.gradle.kts b/serialization/build.gradle.kts new file mode 100644 index 0000000..1ae9d80 --- /dev/null +++ b/serialization/build.gradle.kts @@ -0,0 +1,116 @@ +plugins { + id("java") + kotlin("jvm") + kotlin("plugin.serialization") version "1.8.21" + id("com.github.johnrengelman.shadow") version "7.1.2" + id("maven-publish") + id("signing") +} + +group = "me.redtea" +val globalArtifactId = "kotlinbukkitkit-serialization" +val globalName = "kotlinbukkitkit-serialization" + +repositories { + mavenCentral() + maven { + name = "spigotmc-repo" + url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") + } +} + +dependencies { + compileOnly("org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT") + api(project(":architecture")) + api(project(":extensions")) + compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.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 = "io.github.iredtea" + version = version + from(components["java"]) + versionMapping { + usage("java-api") { + fromResolutionOf("runtimeClasspath") + } + usage("java-runtime") { + fromResolutionResult() + } + } + pom { + artifactId = globalArtifactId + groupId = "io.github.iredtea" + 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/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/Annotations.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/Annotations.kt new file mode 100644 index 0000000..458eece --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/Annotations.kt @@ -0,0 +1,20 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + + +package me.redtea.kotlinbukkitkit.serialization + +import kotlinx.serialization.SerialInfo + +/** + * Annotation used to automatically translate color codes from the configuration texts + * when using Kotlinx.serialization and KotlinBukkitAPI [SerializtionConfig] ([KotlinPlugin.config]). + */ +@SerialInfo +@Target(AnnotationTarget.PROPERTY) +public annotation class ChangeColor diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/BukkitSerialModule.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/BukkitSerialModule.kt new file mode 100644 index 0000000..e03a239 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/BukkitSerialModule.kt @@ -0,0 +1,33 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + + +package me.redtea.kotlinbukkitkit.serialization + +import me.redtea.kotlinbukkitkit.serialization.serializers.BlockSerializer +import me.redtea.kotlinbukkitkit.serialization.serializers.ChunkSerializer +import me.redtea.kotlinbukkitkit.serialization.serializers.LocationSerializer +import me.redtea.kotlinbukkitkit.serialization.serializers.MaterialDataSerializer +import me.redtea.kotlinbukkitkit.serialization.serializers.MaterialSerializer +import me.redtea.kotlinbukkitkit.serialization.serializers.WorldSerializer +import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.modules.contextual + +/** + * All KotlinBukkitAPI already built Serializers for Kotlinx.serialization. + * + * Serializers for: Block, Chunk, Location, MaterialData, Material, World. + */ +public fun BukkitSerialModule(): SerializersModule = SerializersModule { + contextual(BlockSerializer) + contextual(ChunkSerializer) + contextual(LocationSerializer) + contextual(MaterialDataSerializer) + contextual(MaterialSerializer) + contextual(WorldSerializer) +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/SerializationConfig.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/SerializationConfig.kt new file mode 100644 index 0000000..a88bc60 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/SerializationConfig.kt @@ -0,0 +1,92 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization + +import me.redtea.kotlinbukkitkit.serialization.interceptor.bukkit.BukkitSerializationDecodeInterceptor +import me.redtea.kotlinbukkitkit.serialization.interceptor.bukkit.BukkitSerializationEncodeInterceptor +import me.redtea.kotlinbukkitkit.serialization.interceptor.impl.StringFormatInterceptor +import kotlinx.serialization.KSerializer +import kotlinx.serialization.StringFormat +import java.io.File + +public typealias KotlinConfigEventObservable = (me.redtea.kotlinbukkitkit.serialization.KotlinConfigEvent) -> Unit + +public enum class KotlinConfigEvent { SAVE, RELOAD } + +/** + * A helper class to work with Kotlinx.serialization for Bukkit plugins config. + * + * Additional features: Using a interceptor we are able to add new annotations to the Kotlinx.serialization. + * + * `@ChangeColor` in a String property translate the color codes from the Configuration, saves in `&` and loads in ``. + */ +public class SerializationConfig( + public val defaultModel: T, + public val file: File, + public val serializer: KSerializer, + stringFormat: StringFormat, + public val alwaysRestoreDefaults: Boolean, + public val eventObservable: me.redtea.kotlinbukkitkit.serialization.KotlinConfigEventObservable? = null, +) { + public lateinit var config: T private set + + public val stringFormat: StringFormat = StringFormatInterceptor( + stringFormat, + BukkitSerializationEncodeInterceptor, + BukkitSerializationDecodeInterceptor, + ) + + public fun load() { + createFileIfNotExist() + + loadFromFile() + } + + /** + * Save the current values of [model] in the configuration file. + */ + public fun save(): me.redtea.kotlinbukkitkit.serialization.SerializationConfig = apply { + saveToFile(config) + + eventObservable?.invoke(me.redtea.kotlinbukkitkit.serialization.KotlinConfigEvent.SAVE) + } + + /** + * Reloads the current values from the configuration to the [model]. + */ + public fun reload(): me.redtea.kotlinbukkitkit.serialization.SerializationConfig = apply { + loadFromFile() + + eventObservable?.invoke(me.redtea.kotlinbukkitkit.serialization.KotlinConfigEvent.RELOAD) + } + + private fun loadFromFile() { + config = stringFormat.decodeFromString(serializer, file.readText()) + + if (alwaysRestoreDefaults) { + saveToFile(config) + } + } + + private fun stringifyModel(value: T) = stringFormat.encodeToString(serializer, value) + + private fun saveToFile(value: T) { + val content = stringifyModel(value) + file.writeText(content) + } + + private fun createFileIfNotExist() { + if (!file.exists()) { + file.parentFile.mkdirs() + file.createNewFile() + + saveToFile(defaultModel) + } + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/architecture/ConfigLifecycle.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/architecture/ConfigLifecycle.kt new file mode 100644 index 0000000..af21844 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/architecture/ConfigLifecycle.kt @@ -0,0 +1,111 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.architecture + +import me.redtea.kotlinbukkitkit.architecture.KotlinPlugin +import me.redtea.kotlinbukkitkit.architecture.lifecycle.LifecycleListener +import me.redtea.kotlinbukkitkit.serialization.KotlinConfigEvent +import me.redtea.kotlinbukkitkit.serialization.SerializationConfig +import me.redtea.kotlinbukkitkit.serialization.architecture.impl.ConfigDelegate +import me.redtea.kotlinbukkitkit.serialization.architecture.impl.getOrInsertConfigLifecycle +import me.redtea.kotlinbukkitkit.serialization.architecture.impl.registerConfiguration +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.StringFormat +import kotlinx.serialization.serializer +import java.io.File +import kotlin.reflect.KType +import kotlin.reflect.typeOf + +/** + * Loads the file with the given [serializer]. + * + * If the file not exist, one will be created with the [defaultModel] serialize into it. + * + * If [KotlinPlugin.reloadConfig] get called will reload the Config. + * + * KotlinBukkitAPI provide Kotlinx.Serialization Contextual Serializers for a couple Bukkit objects, + * this is provided by the BukkitSerialModule(), if do you have a custom SerialModule you should add + * the BukkitSerialModule by `yourSerialModule + BukkitSerialModule()`. The provided Bukkit types are: + * Block, Chunk, Location, Material, MaterialData, World. + * + * Custom annotations: + * - `@ChangeColor` in a String property translate the color codes from the Configuration, saves in `&` and loads in ``. + * + * @param file: The file name in your [dataFolder] (like config.yml). + * @param loadOnEnable: If true, loads your configuration just when the server enable, + * otherwise, load at the call of this function. This could be usage if your configuration + * uses a parser that Parser a Location or a World that is not loaded yet. + * @param saveOnDisable: If true, saves the current [SerializationConfig.model] to the configuration file. + */ +public fun KotlinPlugin.config( + file: String, + defaultModel: T, + serializer: KSerializer, + type: StringFormat, + loadOnEnable: Boolean = false, + saveOnDisable: Boolean = false, + alwaysRestoreDefaults: Boolean = true, +): me.redtea.kotlinbukkitkit.serialization.SerializationConfig { + val configFile = File(dataFolder, file) + + return SerializationConfig( + defaultModel, + configFile, + serializer, + type, + alwaysRestoreDefaults, + eventObservable = { + if (it == KotlinConfigEvent.RELOAD) { + someConfigReloaded() + } + }, + ).also { + registerConfiguration(it as me.redtea.kotlinbukkitkit.serialization.SerializationConfig, loadOnEnable, saveOnDisable) + } +} + +/** + * Gets the config for the given [KType] + */ +public fun LifecycleListener<*>.getConfig(type: KType): me.redtea.kotlinbukkitkit.serialization.SerializationConfig<*> { + try { + val serialName = serializer(type).descriptor.serialName + val config = plugin.getOrInsertConfigLifecycle().serializationConfigurations[serialName] + + requireNotNull(config) { "Could not find this type registred as a Config." } + + return config + } catch (e: SerializationException) { + throw IllegalArgumentException("The config given type is not a serializable one.") + } +} + +/** + * Config delegate that caches the config reference. + */ + +public fun LifecycleListener<*>.config(type: KType): ConfigDelegate { + return config(type, { this }) +} + +@OptIn(ExperimentalStdlibApi::class) +public inline fun LifecycleListener<*>.config(): ConfigDelegate = config(typeOf()) + +public fun LifecycleListener<*>.config( + type: KType, + deep: T.() -> R, +): ConfigDelegate { + return ConfigDelegate(type, deep) +} + +@OptIn(ExperimentalStdlibApi::class) +public inline fun LifecycleListener<*>.config( + noinline deep: T.() -> R, +): ConfigDelegate = config(typeOf(), deep) diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/architecture/impl/ConfigLifecycle.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/architecture/impl/ConfigLifecycle.kt new file mode 100644 index 0000000..dc0b532 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/architecture/impl/ConfigLifecycle.kt @@ -0,0 +1,105 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.architecture.impl + +import me.redtea.kotlinbukkitkit.architecture.KotlinPlugin +import me.redtea.kotlinbukkitkit.architecture.extensions.WithPlugin +import me.redtea.kotlinbukkitkit.architecture.lifecycle.LifecycleEvent +import me.redtea.kotlinbukkitkit.architecture.lifecycle.LifecycleListener +import me.redtea.kotlinbukkitkit.architecture.lifecycle.PluginLifecycleListener +import me.redtea.kotlinbukkitkit.architecture.lifecycle.getOrInsertGenericLifecycle +import me.redtea.kotlinbukkitkit.serialization.SerializationConfig +import me.redtea.kotlinbukkitkit.serialization.architecture.getConfig +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty +import kotlin.reflect.KType + +internal fun KotlinPlugin.getOrInsertConfigLifecycle(): ConfigLifecycle { + // MAX_VALUE = the last to execute onDisable and the first to loaded + return getOrInsertGenericLifecycle(Int.MAX_VALUE) { + ConfigLifecycle(this) + } +} + +internal class ConfigLifecycle( + override val plugin: KotlinPlugin, +) : PluginLifecycleListener, WithPlugin { + // String = Descriptor name + internal val serializationConfigurations = hashMapOf>() + + internal val onEnableLoadSerializationConfigurations = mutableListOf>() + internal val onDisableSaveSerializationConfigurations = mutableListOf>() + + override fun invoke(event: LifecycleEvent) { + when (event) { + LifecycleEvent.ENABLE -> onPluginEnable() + LifecycleEvent.DISABLE -> onPluginDisable() + LifecycleEvent.ALL_CONFIG_RELOAD -> onConfigReload() + else -> {} + } + } + + fun onPluginEnable() { + for (config in onEnableLoadSerializationConfigurations) + config.load() + } + + fun onPluginDisable() { + for (config in onDisableSaveSerializationConfigurations) + config.save() + } + + fun onConfigReload() { + for (config in serializationConfigurations.values) + config.reload() + } +} + +internal fun KotlinPlugin.registerConfiguration( + config: me.redtea.kotlinbukkitkit.serialization.SerializationConfig, + loadOnEnable: Boolean, + saveOnDisable: Boolean, +) { + val lifecycle = getOrInsertConfigLifecycle() + + lifecycle.serializationConfigurations.put(config.serializer.descriptor.serialName, config) + + if (loadOnEnable) { + val configLifecycle = getOrInsertConfigLifecycle() + configLifecycle.onEnableLoadSerializationConfigurations.add(config) + } else { + config.load() + } + + if (saveOnDisable) { + val configLifecycle = getOrInsertConfigLifecycle() + configLifecycle.onDisableSaveSerializationConfigurations.add(config) + } +} + +public class ConfigDelegate( + public val type: KType, + public val deep: T.() -> R, +) : ReadOnlyProperty, R> { + private var configCache: me.redtea.kotlinbukkitkit.serialization.SerializationConfig<*>? = null + + override fun getValue( + thisRef: LifecycleListener<*>, + property: KProperty<*>, + ): R { + if (configCache == null) { + val config = thisRef.getConfig(type) + + configCache = config + // TODO: listen when the config reloads and update the cache value + } + + return deep(configCache!!.config as T) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/ClearSerializationDecodeInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/ClearSerializationDecodeInterceptor.kt new file mode 100644 index 0000000..9a9d736 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/ClearSerializationDecodeInterceptor.kt @@ -0,0 +1,31 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor + +import kotlinx.serialization.descriptors.SerialDescriptor + +internal class ClearSerializationDecodeInterceptor : SerializationDecodeInterceptor { + override fun decodeBoolean(descriptor: SerialDescriptor, index: Int, value: Boolean): Boolean = value + + override fun decodeByte(descriptor: SerialDescriptor, index: Int, value: Byte): Byte = value + + override fun decodeChar(descriptor: SerialDescriptor, index: Int, value: Char): Char = value + + override fun decodeDouble(descriptor: SerialDescriptor, index: Int, value: Double): Double = value + + override fun decodeFloat(descriptor: SerialDescriptor, index: Int, value: Float): Float = value + + override fun decodeInt(descriptor: SerialDescriptor, index: Int, value: Int): Int = value + + override fun decodeLong(descriptor: SerialDescriptor, index: Int, value: Long): Long = value + + override fun decodeShort(descriptor: SerialDescriptor, index: Int, value: Short): Short = value + + override fun decodeString(descriptor: SerialDescriptor, index: Int, value: String): String = value +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/ClearSerializationEncodeInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/ClearSerializationEncodeInterceptor.kt new file mode 100644 index 0000000..e15a154 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/ClearSerializationEncodeInterceptor.kt @@ -0,0 +1,31 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor + +import kotlinx.serialization.descriptors.SerialDescriptor + +internal class ClearSerializationEncodeInterceptor : SerializationEncodeInterceptor { + override fun encodeBoolean(descriptor: SerialDescriptor, index: Int, value: Boolean): Boolean = value + + override fun encodeByte(descriptor: SerialDescriptor, index: Int, value: Byte): Byte = value + + override fun encodeChar(descriptor: SerialDescriptor, index: Int, value: Char): Char = value + + override fun encodeDouble(descriptor: SerialDescriptor, index: Int, value: Double): Double = value + + override fun encodeFloat(descriptor: SerialDescriptor, index: Int, value: Float): Float = value + + override fun encodeInt(descriptor: SerialDescriptor, index: Int, value: Int): Int = value + + override fun encodeLong(descriptor: SerialDescriptor, index: Int, value: Long): Long = value + + override fun encodeShort(descriptor: SerialDescriptor, index: Int, value: Short): Short = value + + override fun encodeString(descriptor: SerialDescriptor, index: Int, value: String): String = value +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/SerializationDecodeInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/SerializationDecodeInterceptor.kt new file mode 100644 index 0000000..bd53ca2 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/SerializationDecodeInterceptor.kt @@ -0,0 +1,31 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor + +import kotlinx.serialization.descriptors.SerialDescriptor + +internal interface SerializationDecodeInterceptor { + fun decodeBoolean(descriptor: SerialDescriptor, index: Int, value: Boolean): Boolean + + fun decodeByte(descriptor: SerialDescriptor, index: Int, value: Byte): Byte + + fun decodeChar(descriptor: SerialDescriptor, index: Int, value: Char): Char + + fun decodeDouble(descriptor: SerialDescriptor, index: Int, value: Double): Double + + fun decodeFloat(descriptor: SerialDescriptor, index: Int, value: Float): Float + + fun decodeInt(descriptor: SerialDescriptor, index: Int, value: Int): Int + + fun decodeLong(descriptor: SerialDescriptor, index: Int, value: Long): Long + + fun decodeShort(descriptor: SerialDescriptor, index: Int, value: Short): Short + + fun decodeString(descriptor: SerialDescriptor, index: Int, value: String): String +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/SerializationEncodeInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/SerializationEncodeInterceptor.kt new file mode 100644 index 0000000..0fe60ad --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/SerializationEncodeInterceptor.kt @@ -0,0 +1,31 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor + +import kotlinx.serialization.descriptors.SerialDescriptor + +internal interface SerializationEncodeInterceptor { + fun encodeBoolean(descriptor: SerialDescriptor, index: Int, value: Boolean): Boolean + + fun encodeByte(descriptor: SerialDescriptor, index: Int, value: Byte): Byte + + fun encodeChar(descriptor: SerialDescriptor, index: Int, value: Char): Char + + fun encodeDouble(descriptor: SerialDescriptor, index: Int, value: Double): Double + + fun encodeFloat(descriptor: SerialDescriptor, index: Int, value: Float): Float + + fun encodeInt(descriptor: SerialDescriptor, index: Int, value: Int): Int + + fun encodeLong(descriptor: SerialDescriptor, index: Int, value: Long): Long + + fun encodeShort(descriptor: SerialDescriptor, index: Int, value: Short): Short + + fun encodeString(descriptor: SerialDescriptor, index: Int, value: String): String +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/bukkit/BukkitSerializationDecodeInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/bukkit/BukkitSerializationDecodeInterceptor.kt new file mode 100644 index 0000000..c2bfd45 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/bukkit/BukkitSerializationDecodeInterceptor.kt @@ -0,0 +1,28 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.bukkit + +import me.redtea.kotlinbukkitkit.extensions.translateColor +import me.redtea.kotlinbukkitkit.serialization.ChangeColor +import me.redtea.kotlinbukkitkit.serialization.interceptor.ClearSerializationDecodeInterceptor +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationDecodeInterceptor +import kotlinx.serialization.descriptors.SerialDescriptor + +public object BukkitSerializationDecodeInterceptor : SerializationDecodeInterceptor by ClearSerializationDecodeInterceptor() { + + override fun decodeString(descriptor: SerialDescriptor, index: Int, value: String): String { + return useChangeColor(descriptor, index, value) + } + + private fun useChangeColor(descriptor: SerialDescriptor, index: Int, value: String): String { + descriptor.findElementAnnotation(index) ?: return value + + return value.translateColor() + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/bukkit/BukkitSerializationEncodeInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/bukkit/BukkitSerializationEncodeInterceptor.kt new file mode 100644 index 0000000..783b832 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/bukkit/BukkitSerializationEncodeInterceptor.kt @@ -0,0 +1,28 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.bukkit + +import me.redtea.kotlinbukkitkit.extensions.reverseTranslateColor +import me.redtea.kotlinbukkitkit.serialization.ChangeColor +import me.redtea.kotlinbukkitkit.serialization.interceptor.ClearSerializationEncodeInterceptor +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationEncodeInterceptor +import kotlinx.serialization.descriptors.SerialDescriptor + +public object BukkitSerializationEncodeInterceptor : SerializationEncodeInterceptor by ClearSerializationEncodeInterceptor() { + + override fun encodeString(descriptor: SerialDescriptor, index: Int, value: String): String { + return useChangeColor(descriptor, index, value) + } + + private fun useChangeColor(descriptor: SerialDescriptor, index: Int, value: String): String { + descriptor.findElementAnnotation(index) ?: return value + + return value.reverseTranslateColor() + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/bukkit/Utils.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/bukkit/Utils.kt new file mode 100644 index 0000000..611c60f --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/bukkit/Utils.kt @@ -0,0 +1,21 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.bukkit + +import kotlinx.serialization.descriptors.SerialDescriptor + +internal inline fun SerialDescriptor.findElementAnnotation( + elementIndex: Int, +): A? { + return getElementAnnotations(elementIndex).find { it is A } as A? +} + +internal inline fun SerialDescriptor.findEntityAnnotation(): A? { + return annotations.find { it is A } as A? +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/StringFormatInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/StringFormatInterceptor.kt new file mode 100644 index 0000000..469a408 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/StringFormatInterceptor.kt @@ -0,0 +1,33 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.impl + +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationDecodeInterceptor +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationEncodeInterceptor +import me.redtea.kotlinbukkitkit.serialization.interceptor.impl.decoder.DeserializationStrategyInterceptor +import me.redtea.kotlinbukkitkit.serialization.interceptor.impl.encoder.SerializationStrategyInterceptor +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.StringFormat +import kotlinx.serialization.decodeFromString + +internal class StringFormatInterceptor( + private val delegate: StringFormat, + private val encodeInterceptor: SerializationEncodeInterceptor, + private val decodeInterceptor: SerializationDecodeInterceptor, +) : StringFormat by delegate { + + override fun decodeFromString(deserializer: DeserializationStrategy, raw: String): T { + return delegate.decodeFromString(DeserializationStrategyInterceptor(decodeInterceptor, deserializer), raw) + } + + override fun encodeToString(serializer: SerializationStrategy, value: T): String { + return delegate.encodeToString(SerializationStrategyInterceptor(encodeInterceptor, serializer), value) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/decoder/CompositeDecoderInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/decoder/CompositeDecoderInterceptor.kt new file mode 100644 index 0000000..f440728 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/decoder/CompositeDecoderInterceptor.kt @@ -0,0 +1,69 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.impl.decoder + +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationDecodeInterceptor +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.CompositeDecoder + +internal class CompositeDecoderInterceptor( + val interceptor: SerializationDecodeInterceptor, + val delegate: CompositeDecoder, +) : CompositeDecoder by delegate { + + override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean { + return interceptor.decodeBoolean(descriptor, index, delegate.decodeBooleanElement(descriptor, index)) + } + + override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte { + return interceptor.decodeByte(descriptor, index, delegate.decodeByteElement(descriptor, index)) + } + + override fun decodeCharElement(descriptor: SerialDescriptor, index: Int): Char { + return interceptor.decodeChar(descriptor, index, delegate.decodeCharElement(descriptor, index)) + } + + override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int): Double { + return interceptor.decodeDouble(descriptor, index, delegate.decodeDoubleElement(descriptor, index)) + } + + override fun decodeFloatElement(descriptor: SerialDescriptor, index: Int): Float { + return interceptor.decodeFloat(descriptor, index, delegate.decodeFloatElement(descriptor, index)) + } + + override fun decodeIntElement(descriptor: SerialDescriptor, index: Int): Int { + return interceptor.decodeInt(descriptor, index, delegate.decodeIntElement(descriptor, index)) + } + + override fun decodeLongElement(descriptor: SerialDescriptor, index: Int): Long { + return interceptor.decodeLong(descriptor, index, delegate.decodeLongElement(descriptor, index)) + } + + override fun decodeShortElement(descriptor: SerialDescriptor, index: Int): Short { + return interceptor.decodeShort(descriptor, index, delegate.decodeShortElement(descriptor, index)) + } + + override fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String { + return interceptor.decodeString(descriptor, index, delegate.decodeStringElement(descriptor, index)) + } + + override fun decodeSerializableElement( + descriptor: SerialDescriptor, + index: Int, + deserializer: DeserializationStrategy, + previousValue: T?, + ): T { + return delegate.decodeSerializableElement( + descriptor, + index, + DeserializationStrategyInterceptor(interceptor, deserializer), + ) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/decoder/DecoderInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/decoder/DecoderInterceptor.kt new file mode 100644 index 0000000..da14522 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/decoder/DecoderInterceptor.kt @@ -0,0 +1,28 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.impl.decoder + +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationDecodeInterceptor +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.CompositeDecoder +import kotlinx.serialization.encoding.Decoder + +internal class DecoderInterceptor( + val interceptor: SerializationDecodeInterceptor, + val delegate: Decoder, +) : Decoder by delegate { + override fun decodeSerializableValue(deserializer: DeserializationStrategy): T { + return deserializer.deserialize(this) + } + + override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder { + return CompositeDecoderInterceptor(interceptor, delegate.beginStructure(descriptor)) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/decoder/DeserializationStrategyInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/decoder/DeserializationStrategyInterceptor.kt new file mode 100644 index 0000000..440cf0b --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/decoder/DeserializationStrategyInterceptor.kt @@ -0,0 +1,22 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.impl.decoder + +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationDecodeInterceptor +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.encoding.Decoder + +internal class DeserializationStrategyInterceptor( + val interceptor: SerializationDecodeInterceptor, + val delegate: DeserializationStrategy, +) : DeserializationStrategy by delegate { + override fun deserialize(decoder: Decoder): T { + return delegate.deserialize(DecoderInterceptor(interceptor, decoder)) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/encoder/CompositeEncoderInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/encoder/CompositeEncoderInterceptor.kt new file mode 100644 index 0000000..0489093 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/encoder/CompositeEncoderInterceptor.kt @@ -0,0 +1,59 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.impl.encoder + +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationEncodeInterceptor +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.CompositeEncoder + +internal class CompositeEncoderInterceptor( + val interceptor: SerializationEncodeInterceptor, + val delegate: CompositeEncoder, +) : CompositeEncoder by delegate { + override fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean) { + delegate.encodeBooleanElement(descriptor, index, interceptor.encodeBoolean(descriptor, index, value)) + } + + override fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte) { + delegate.encodeByteElement(descriptor, index, interceptor.encodeByte(descriptor, index, value)) + } + + override fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char) { + delegate.encodeCharElement(descriptor, index, interceptor.encodeChar(descriptor, index, value)) + } + + override fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double) { + delegate.encodeDoubleElement(descriptor, index, interceptor.encodeDouble(descriptor, index, value)) + } + + override fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float) { + delegate.encodeFloatElement(descriptor, index, interceptor.encodeFloat(descriptor, index, value)) + } + + override fun encodeIntElement(descriptor: SerialDescriptor, index: Int, value: Int) { + delegate.encodeIntElement(descriptor, index, interceptor.encodeInt(descriptor, index, value)) + } + + override fun encodeLongElement(descriptor: SerialDescriptor, index: Int, value: Long) { + delegate.encodeLongElement(descriptor, index, interceptor.encodeLong(descriptor, index, value)) + } + + override fun encodeShortElement(descriptor: SerialDescriptor, index: Int, value: Short) { + delegate.encodeShortElement(descriptor, index, interceptor.encodeShort(descriptor, index, value)) + } + + override fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String) { + delegate.encodeStringElement(descriptor, index, interceptor.encodeString(descriptor, index, value)) + } + + override fun encodeSerializableElement(descriptor: SerialDescriptor, index: Int, serializer: SerializationStrategy, value: T) { + delegate.encodeSerializableElement(descriptor, index, SerializationStrategyInterceptor(interceptor, serializer), value) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/encoder/EncoderInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/encoder/EncoderInterceptor.kt new file mode 100644 index 0000000..18c4d7c --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/encoder/EncoderInterceptor.kt @@ -0,0 +1,33 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.impl.encoder + +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationEncodeInterceptor +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.CompositeEncoder +import kotlinx.serialization.encoding.Encoder + +internal class EncoderInterceptor( + val interceptor: SerializationEncodeInterceptor, + val delegate: Encoder, +) : Encoder by delegate { + + override fun encodeSerializableValue(serializer: SerializationStrategy, value: T) { + serializer.serialize(this, value) + } + + override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder { + return CompositeEncoderInterceptor(interceptor, delegate.beginStructure(descriptor)) + } + + override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder { + return CompositeEncoderInterceptor(interceptor, delegate.beginCollection(descriptor, collectionSize)) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/encoder/SerializationStrategyInterceptor.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/encoder/SerializationStrategyInterceptor.kt new file mode 100644 index 0000000..4d206a2 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/interceptor/impl/encoder/SerializationStrategyInterceptor.kt @@ -0,0 +1,22 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.interceptor.impl.encoder + +import me.redtea.kotlinbukkitkit.serialization.interceptor.SerializationEncodeInterceptor +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.encoding.Encoder + +internal class SerializationStrategyInterceptor( + val interceptor: SerializationEncodeInterceptor, + val delegate: SerializationStrategy, +) : SerializationStrategy by delegate { + override fun serialize(encoder: Encoder, value: T) { + delegate.serialize(EncoderInterceptor(interceptor, encoder), value) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/BlockSerializer.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/BlockSerializer.kt new file mode 100644 index 0000000..31f4c2b --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/BlockSerializer.kt @@ -0,0 +1,44 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.serializers + +import me.redtea.kotlinbukkitkit.serialization.serializers.exceptions.WorldNotFoundException +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import org.bukkit.Bukkit +import org.bukkit.block.Block + +public object BlockSerializer : KSerializer { + private const val BLOCK_SEPARATOR = ";" + + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("org.bukkit.block.Block", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): Block { + val raw = decoder.decodeString() + + val slices = raw.split(BLOCK_SEPARATOR) + val worldName = slices[0] + val world = Bukkit.getWorld(worldName) ?: throw WorldNotFoundException(worldName) + + return world.getBlockAt( + slices[1].toInt(), + slices[2].toInt(), + slices[3].toInt(), + ) + } + + override fun serialize(encoder: Encoder, value: Block) { + encoder.encodeString("${value.world.name}$BLOCK_SEPARATOR${value.x}$BLOCK_SEPARATOR${value.y}$BLOCK_SEPARATOR${value.z}") + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/ChunkSerializer.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/ChunkSerializer.kt new file mode 100644 index 0000000..1f1176a --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/ChunkSerializer.kt @@ -0,0 +1,43 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.serializers + +import me.redtea.kotlinbukkitkit.serialization.serializers.exceptions.WorldNotFoundException +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import org.bukkit.Bukkit +import org.bukkit.Chunk + +public object ChunkSerializer : KSerializer { + private const val CHUNK_SEPARATOR = ";" + + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("org.bukkit.Chunk", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): Chunk { + val raw = decoder.decodeString() + + val slices = raw.split(CHUNK_SEPARATOR) + val worldName = slices[0] + val world = Bukkit.getWorld(worldName) ?: throw WorldNotFoundException(worldName) + + return world.getChunkAt( + slices[1].toInt(), + slices[2].toInt(), + ) + } + + override fun serialize(encoder: Encoder, value: Chunk) { + encoder.encodeString("${value.world.name}$CHUNK_SEPARATOR${value.x}$CHUNK_SEPARATOR${value.z}") + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/ComponentSerializer.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/ComponentSerializer.kt new file mode 100644 index 0000000..3a3f78b --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/ComponentSerializer.kt @@ -0,0 +1,3 @@ +package me.redtea.kotlinbukkitkit.serialization.serializers + +// TODO: diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/ItemStackSerializer.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/ItemStackSerializer.kt new file mode 100644 index 0000000..5154afa --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/ItemStackSerializer.kt @@ -0,0 +1,38 @@ +package me.redtea.kotlinbukkitkit.serialization.serializers + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import org.bukkit.inventory.ItemStack +import org.bukkit.util.io.BukkitObjectInputStream +import org.bukkit.util.io.BukkitObjectOutputStream +import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream + + +public object ItemStackSerializer : KSerializer { + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("org.bukkit.inventory.ItemStack", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): ItemStack { + ByteArrayInputStream(Base64Coder.decode(decoder.decodeString())) + .use { inputStream -> + BukkitObjectInputStream(inputStream) + .use { dataInput -> return dataInput.readObject() as ItemStack } + } + } + + override fun serialize(encoder: Encoder, value: ItemStack) { + ByteArrayOutputStream().use { outputStream -> + BukkitObjectOutputStream(outputStream).use { dataOutput -> + dataOutput.writeObject(value) + encoder.encodeString(String(Base64Coder.encode(outputStream.toByteArray()))) + } + } + } +} + diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/LocationSerializer.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/LocationSerializer.kt new file mode 100644 index 0000000..1c435dc --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/LocationSerializer.kt @@ -0,0 +1,47 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.serializers + +import me.redtea.kotlinbukkitkit.serialization.serializers.exceptions.WorldNotFoundException +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import org.bukkit.Bukkit +import org.bukkit.Location + +public object LocationSerializer : KSerializer { + private const val LOCATION_SEPARATOR = ";" + + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("org.bukkit.Location", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): Location { + val raw = decoder.decodeString() + + val slices = raw.split(LOCATION_SEPARATOR) + val worldName = slices[0] + val world = Bukkit.getWorld(worldName) ?: throw WorldNotFoundException(worldName) + + return Location( + world, + slices[1].toDouble(), + slices[2].toDouble(), + slices[3].toDouble(), + slices.getOrNull(4)?.toFloat() ?: 0f, + slices.getOrNull(5)?.toFloat() ?: 0f, + ) + } + + override fun serialize(encoder: Encoder, value: Location) { + encoder.encodeString("${value.world!!.name}$LOCATION_SEPARATOR${value.x}$LOCATION_SEPARATOR${value.y}$LOCATION_SEPARATOR${value.z}$LOCATION_SEPARATOR${value.yaw}$LOCATION_SEPARATOR${value.pitch}") + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/MaterialDataSerializer.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/MaterialDataSerializer.kt new file mode 100644 index 0000000..159947d --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/MaterialDataSerializer.kt @@ -0,0 +1,49 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.serializers + +import me.redtea.kotlinbukkitkit.extensions.asMaterialData +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import org.bukkit.Material +import org.bukkit.material.MaterialData + +@Serializer(forClass = MaterialData::class) +public object MaterialDataSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor( + "org.bukkit.material.MaterialData", + PrimitiveKind.STRING, + ) + + override fun deserialize(decoder: Decoder): MaterialData { + return fromString(decoder.decodeString()) + } + + override fun serialize(encoder: Encoder, value: MaterialData) { + encoder.encodeString(toString(value)) + } + + private fun toString(material: MaterialData): String { + return "${material.itemType}:${material.data}" + } + + private fun fromString(content: String): MaterialData { + val slices = content.split(":") + + val material = slices[0] + val data = slices.getOrNull(1)?.toIntOrNull() ?: 0 + + return Material.getMaterial(material.toUpperCase())!!.asMaterialData(data.toByte()) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/MaterialSerializer.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/MaterialSerializer.kt new file mode 100644 index 0000000..e6e204a --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/MaterialSerializer.kt @@ -0,0 +1,34 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.serialization.serializers + +import me.redtea.kotlinbukkitkit.serialization.serializers.exceptions.MaterialNotFoundException +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import org.bukkit.Material + +public object MaterialSerializer : KSerializer { + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("org.bukkit.Material", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): Material { + val materialName = decoder.decodeString() + + return Material.values().find { it.name.equals(materialName, true) } + ?: throw MaterialNotFoundException(materialName) + } + + override fun serialize(encoder: Encoder, value: Material) { + encoder.encodeString(value.name.toLowerCase()) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/WorldSerializer.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/WorldSerializer.kt new file mode 100644 index 0000000..f9faed1 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/WorldSerializer.kt @@ -0,0 +1,35 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.serialization +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + + +package me.redtea.kotlinbukkitkit.serialization.serializers + +import me.redtea.kotlinbukkitkit.serialization.serializers.exceptions.WorldNotFoundException +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import org.bukkit.Bukkit +import org.bukkit.World + +public object WorldSerializer : KSerializer { + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("org.bukkit.World", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): World { + val worldName = decoder.decodeString() + + return Bukkit.getWorld(worldName) ?: throw WorldNotFoundException(worldName) + } + + override fun serialize(encoder: Encoder, value: World) { + encoder.encodeString(value.name) + } +} diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/exceptions/MaterialNotFoundException.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/exceptions/MaterialNotFoundException.kt new file mode 100644 index 0000000..f131d9b --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/exceptions/MaterialNotFoundException.kt @@ -0,0 +1,5 @@ +package me.redtea.kotlinbukkitkit.serialization.serializers.exceptions + +import java.lang.Exception + +public class MaterialNotFoundException(public val material: String) : Exception("Could not deserialize the Material=$material because it do not exist.") diff --git a/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/exceptions/WorldNotFoundException.kt b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/exceptions/WorldNotFoundException.kt new file mode 100644 index 0000000..ff5a5c8 --- /dev/null +++ b/serialization/src/main/kotlin/me/redtea/kotlinbukkitkit/serialization/serializers/exceptions/WorldNotFoundException.kt @@ -0,0 +1,3 @@ +package me.redtea.kotlinbukkitkit.serialization.serializers.exceptions + +public class WorldNotFoundException(public val world: String) : Exception("Could not deserialize the World=$world because was not found on the Server.") diff --git a/settings.gradle.kts b/settings.gradle.kts index b6e7577..07dc374 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,3 +3,4 @@ rootProject.name = "kotlinbukkitkit" include("architecture") include("messages") include("extensions") +include("serialization")