From 7c24e3d6b8019e3faf1286433f0f17ad2e9042a1 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Sat, 16 Mar 2024 16:21:13 -0400 Subject: [PATCH 01/18] chore: Update geary, idofront, publish action --- .github/workflows/publish.yml | 9 +++++---- build.gradle.kts | 10 +++++----- core/build.gradle.kts | 16 ++++++++-------- .../com/mineinabyss/emojy/EmojyContext.kt | 2 ++ .../com/mineinabyss/emojy/EmojyGenerator.kt | 6 +++--- .../kotlin/com/mineinabyss/emojy/EmojyPlugin.kt | 17 ++++++++++++----- .../com/mineinabyss/emojy/config/EmojyConfig.kt | 5 +++-- gradle.properties | 2 +- gradle/{emojyLibs.toml => libs.versions.toml} | 0 settings.gradle.kts | 3 +-- v1_19_R1/build.gradle.kts | 10 +++++----- v1_19_R2/build.gradle.kts | 10 +++++----- v1_19_R3/build.gradle.kts | 10 +++++----- v1_20_R1/build.gradle.kts | 10 +++++----- v1_20_R2/build.gradle.kts | 10 +++++----- v1_20_R3/build.gradle.kts | 10 +++++----- 16 files changed, 70 insertions(+), 60 deletions(-) rename gradle/{emojyLibs.toml => libs.versions.toml} (100%) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 35ef6bc..48ebe24 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,13 +12,14 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 - - uses: MineInAbyss/publish-action@master + - uses: MineInAbyss/publish-action@develop with: maven-metadata-url: https://repo.mineinabyss.com/releases/com/mineinabyss/emojy/maven-metadata.xml - pages-path: build/dokka/htmlMultiModule/ - dokka: dokkaHtmlMultiModule + maven-snapshot-metadata-url: https://repo.mineinabyss.com/snapshots/com/mineinabyss/emojy/maven-metadata.xml maven-username: ${{ secrets.MAVEN_PUBLISH_USERNAME }} maven-password: ${{ secrets.MAVEN_PUBLISH_PASSWORD }} release-files: | diff --git a/build.gradle.kts b/build.gradle.kts index 142244f..76f4b00 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,11 +27,11 @@ allprojects { dependencies { // MineInAbyss platform - compileOnly(libs.bundles.idofront.core) - compileOnly(libs.kotlinx.serialization.json) - compileOnly(libs.kotlinx.serialization.kaml) - compileOnly(libs.kotlinx.coroutines) - compileOnly(libs.minecraft.mccoroutine) + compileOnly(idofrontLibs.bundles.idofront.core) + compileOnly(idofrontLibs.kotlinx.serialization.json) + compileOnly(idofrontLibs.kotlinx.serialization.kaml) + compileOnly(idofrontLibs.kotlinx.coroutines) + compileOnly(idofrontLibs.minecraft.mccoroutine) // Shaded paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") //NMS diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 9920f3f..1956639 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -2,7 +2,7 @@ plugins { id("com.mineinabyss.conventions.kotlin.jvm") id("com.mineinabyss.conventions.papermc") id("com.mineinabyss.conventions.autoversion") - alias(libs.plugins.kotlinx.serialization) + alias(idofrontLibs.plugins.kotlinx.serialization) } repositories { @@ -15,14 +15,14 @@ repositories { dependencies { // MineInAbyss platform - compileOnly(libs.bundles.idofront.core) - compileOnly(libs.kotlinx.serialization.json) - compileOnly(libs.kotlinx.serialization.kaml) - compileOnly(libs.kotlinx.coroutines) - compileOnly(libs.minecraft.mccoroutine) + compileOnly(idofrontLibs.bundles.idofront.core) + compileOnly(idofrontLibs.kotlinx.serialization.json) + compileOnly(idofrontLibs.kotlinx.serialization.kaml) + compileOnly(idofrontLibs.kotlinx.coroutines) + compileOnly(idofrontLibs.minecraft.mccoroutine) - compileOnly(libs.creative.api) - compileOnly(libs.creative.serializer.minecraft) + compileOnly(idofrontLibs.creative.api) + compileOnly(idofrontLibs.creative.serializer.minecraft) // Shaded implementation("com.aaaaahhhhh.bananapuncher714:GifConverter:1.0") diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyContext.kt b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyContext.kt index e0b89ee..a4d540c 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyContext.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyContext.kt @@ -8,6 +8,7 @@ import com.mineinabyss.emojy.nms.EmojyNMSHandlers import com.mineinabyss.emojy.nms.IEmojyNMSHandler import com.mineinabyss.emojy.translator.EmojyLanguage import com.mineinabyss.idofront.di.DI +import com.mineinabyss.idofront.messaging.ComponentLogger val emojy by DI.observe() val emojyConfig by DI.observe() @@ -18,4 +19,5 @@ interface EmojyContext { val gifs: Set val languages: Set val handler: IEmojyNMSHandler + val logger: ComponentLogger } diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyGenerator.kt b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyGenerator.kt index b3005db..6628ac1 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyGenerator.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyGenerator.kt @@ -33,13 +33,13 @@ object EmojyGenerator { resourcePack.font(font.toBuilder().addProvider(FontProvider.space().advance("\uE101", -1).build()).build()) // If the font has already added an entry for the emote, skip it font.providers().any { it is BitMapFontProvider && it.file() == emote.texture } -> - return@forEach if (emojyConfig.debug) logWarn("Skipping ${emote.id}-font because it is a bitmap and already added") else {} + return@forEach emojy.logger.d("Skipping ${emote.id}-font because it is a bitmap and already added") } resourcePack.font(emote.appendFont(resourcePack)) emotesFolder.listFiles()?.find { f -> f.nameWithoutExtension == emote.texture.value().substringAfterLast("/").removeSuffix(".png") }?.let { resourcePack.texture(Texture.texture(emote.texture, Writable.file(it))) - } ?: if (emojyConfig.debug) logWarn("Could not find texture for ${emote.id}") else {} + } ?: emojy.logger.d("Could not find texture for ${emote.id}") } emojy.gifs.forEach { it.generateSplitGif(resourcePack) @@ -58,7 +58,7 @@ object EmojyGenerator { Texture.texture(Key.key("${framePath.asString()}${it.name}"), Writable.file(it)) }?.forEach(resourcePack::texture) }.onFailure { - if (emojyConfig.debug) logError("Could not generate split gif for ${id}.gif: ${it.message}") + emojy.logger.d("Could not generate split gif for ${id}.gif: ${it.message}") } } } diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyPlugin.kt b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyPlugin.kt index e579ee6..0c48575 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyPlugin.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyPlugin.kt @@ -10,6 +10,10 @@ import com.mineinabyss.emojy.translator.EmojyLanguage import com.mineinabyss.emojy.translator.EmojyTranslator import com.mineinabyss.idofront.config.config import com.mineinabyss.idofront.di.DI +import com.mineinabyss.idofront.messaging.ComponentLogger +import com.mineinabyss.idofront.messaging.injectLogger +import com.mineinabyss.idofront.messaging.observeLogger +import com.mineinabyss.idofront.plugin.dataPath import com.mineinabyss.idofront.plugin.listeners import net.kyori.adventure.key.Key import net.kyori.adventure.translation.GlobalTranslator @@ -49,20 +53,23 @@ class EmojyPlugin : JavaPlugin() { fun createEmojyContext() { DI.remove() - DI.add(config("config", dataFolder.toPath(), EmojyConfig()).getOrLoad()) + DI.add(config("config", dataPath, EmojyConfig(), onLoad = { + this@EmojyPlugin.injectLogger(ComponentLogger.forPlugin(this@EmojyPlugin, it.logLevel)) + }).getOrLoad()) DI.remove() - DI.add(config("templates", dataFolder.toPath(), EmojyTemplates()).getOrLoad()) + DI.add(config("templates", dataPath, EmojyTemplates()).getOrLoad()) DI.remove() DI.add(object : EmojyContext { override val plugin: EmojyPlugin = this@EmojyPlugin - override val emotes: Set = config("emotes", dataFolder.toPath(), Emotes()).getOrLoad().emotes - override val gifs: Set = config("gifs", dataFolder.toPath(), Gifs()).getOrLoad().gifs + override val emotes: Set = config("emotes", dataPath, Emotes()).getOrLoad().emotes + override val gifs: Set = config("gifs", dataPath, Gifs()).getOrLoad().gifs override val languages: Set = emojyConfig.supportedLanguages.map { EmojyLanguage(it.split("_").let { l -> Locale(l.first(), l.last().uppercase()) }, - config>(it, dataFolder.toPath() / "languages", mapOf()).getOrLoad()) + config>(it, dataPath / "languages", mapOf()).getOrLoad()) }.toSet() + override val logger by plugin.observeLogger() override val handler: IEmojyNMSHandler = EmojyNMSHandlers.setup() }) diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/config/EmojyConfig.kt b/core/src/main/kotlin/com/mineinabyss/emojy/config/EmojyConfig.kt index 446b88f..5c1e87a 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/config/EmojyConfig.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/config/EmojyConfig.kt @@ -2,6 +2,7 @@ package com.mineinabyss.emojy.config +import co.touchlab.kermit.Severity import com.mineinabyss.emojy.* import com.mineinabyss.idofront.messaging.* import com.mineinabyss.idofront.serialization.KeySerializer @@ -39,7 +40,7 @@ data class EmojyConfig( val requirePermissions: Boolean = true, val supportForceUnicode: Boolean = true, - val debug: Boolean = true, + val logLevel: Severity = Severity.Debug, val emojyList: EmojyList = EmojyList(), val supportedLanguages: Set = mutableSetOf("en_us"), ) { @@ -206,7 +207,7 @@ data class Gifs(val gifs: Set = mutableSetOf()) { aspectRatio = reader.getAspectRatio(0) reader.getNumImages(true) }.onFailure { - if (emojyConfig.debug) logError("Could not get frame count for ${id}.gif") + emojy.logger.d("Could not get frame count for ${id}.gif") }.getOrNull() ?: run { aspectRatio = 1f 0 diff --git a/gradle.properties b/gradle.properties index e409055..b8debd1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ group=com.mineinabyss version=0.8 -idofrontVersion=0.21.2 +idofrontVersion=0.23.0 diff --git a/gradle/emojyLibs.toml b/gradle/libs.versions.toml similarity index 100% rename from gradle/emojyLibs.toml rename to gradle/libs.versions.toml diff --git a/settings.gradle.kts b/settings.gradle.kts index 58b5595..2db4462 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,10 +27,9 @@ dependencyResolutionManagement { } versionCatalogs { - create("libs"){ + create("idofrontLibs"){ from("com.mineinabyss:catalog:$idofrontVersion") } - create("emojyLibs").from(files("gradle/emojyLibs.toml")) } } diff --git a/v1_19_R1/build.gradle.kts b/v1_19_R1/build.gradle.kts index 8798848..58d0d94 100644 --- a/v1_19_R1/build.gradle.kts +++ b/v1_19_R1/build.gradle.kts @@ -13,13 +13,13 @@ repositories { dependencies { // MineInAbyss platform - compileOnly(libs.kotlinx.serialization.json) - compileOnly(libs.kotlinx.serialization.kaml) - compileOnly(libs.kotlinx.coroutines) - compileOnly(libs.minecraft.mccoroutine) + compileOnly(idofrontLibs.kotlinx.serialization.json) + compileOnly(idofrontLibs.kotlinx.serialization.kaml) + compileOnly(idofrontLibs.kotlinx.coroutines) + compileOnly(idofrontLibs.minecraft.mccoroutine) // Shaded - implementation(libs.bundles.idofront.core) + implementation(idofrontLibs.bundles.idofront.core) implementation(project(":core")) paperweight.paperDevBundle("1.19.2-R0.1-SNAPSHOT") //NMS } diff --git a/v1_19_R2/build.gradle.kts b/v1_19_R2/build.gradle.kts index 478258e..0e33bc5 100644 --- a/v1_19_R2/build.gradle.kts +++ b/v1_19_R2/build.gradle.kts @@ -13,13 +13,13 @@ repositories { dependencies { // MineInAbyss platform - compileOnly(libs.kotlinx.serialization.json) - compileOnly(libs.kotlinx.serialization.kaml) - compileOnly(libs.kotlinx.coroutines) - compileOnly(libs.minecraft.mccoroutine) + compileOnly(idofrontLibs.kotlinx.serialization.json) + compileOnly(idofrontLibs.kotlinx.serialization.kaml) + compileOnly(idofrontLibs.kotlinx.coroutines) + compileOnly(idofrontLibs.minecraft.mccoroutine) // Shaded - implementation(libs.bundles.idofront.core) + implementation(idofrontLibs.bundles.idofront.core) implementation(project(":core")) paperweight.paperDevBundle("1.19.3-R0.1-SNAPSHOT") //NMS } diff --git a/v1_19_R3/build.gradle.kts b/v1_19_R3/build.gradle.kts index 1626f96..ccb8d43 100644 --- a/v1_19_R3/build.gradle.kts +++ b/v1_19_R3/build.gradle.kts @@ -13,13 +13,13 @@ repositories { dependencies { // MineInAbyss platform - compileOnly(libs.kotlinx.serialization.json) - compileOnly(libs.kotlinx.serialization.kaml) - compileOnly(libs.kotlinx.coroutines) - compileOnly(libs.minecraft.mccoroutine) + compileOnly(idofrontLibs.kotlinx.serialization.json) + compileOnly(idofrontLibs.kotlinx.serialization.kaml) + compileOnly(idofrontLibs.kotlinx.coroutines) + compileOnly(idofrontLibs.minecraft.mccoroutine) // Shaded - implementation(libs.bundles.idofront.core) + implementation(idofrontLibs.bundles.idofront.core) implementation(project(":core")) paperweight.paperDevBundle("1.19.4-R0.1-SNAPSHOT") //NMS } diff --git a/v1_20_R1/build.gradle.kts b/v1_20_R1/build.gradle.kts index b0a079d..14eea49 100644 --- a/v1_20_R1/build.gradle.kts +++ b/v1_20_R1/build.gradle.kts @@ -13,13 +13,13 @@ repositories { dependencies { // MineInAbyss platform - compileOnly(libs.kotlinx.serialization.json) - compileOnly(libs.kotlinx.serialization.kaml) - compileOnly(libs.kotlinx.coroutines) - compileOnly(libs.minecraft.mccoroutine) + compileOnly(idofrontLibs.kotlinx.serialization.json) + compileOnly(idofrontLibs.kotlinx.serialization.kaml) + compileOnly(idofrontLibs.kotlinx.coroutines) + compileOnly(idofrontLibs.minecraft.mccoroutine) // Shaded - implementation(libs.bundles.idofront.core) + implementation(idofrontLibs.bundles.idofront.core) implementation(project(":core")) paperweight.paperDevBundle("1.20-R0.1-SNAPSHOT") //NMS } diff --git a/v1_20_R2/build.gradle.kts b/v1_20_R2/build.gradle.kts index 2cb241f..c32e7c5 100644 --- a/v1_20_R2/build.gradle.kts +++ b/v1_20_R2/build.gradle.kts @@ -13,13 +13,13 @@ repositories { dependencies { // MineInAbyss platform - compileOnly(libs.kotlinx.serialization.json) - compileOnly(libs.kotlinx.serialization.kaml) - compileOnly(libs.kotlinx.coroutines) - compileOnly(libs.minecraft.mccoroutine) + compileOnly(idofrontLibs.kotlinx.serialization.json) + compileOnly(idofrontLibs.kotlinx.serialization.kaml) + compileOnly(idofrontLibs.kotlinx.coroutines) + compileOnly(idofrontLibs.minecraft.mccoroutine) // Shaded - implementation(libs.bundles.idofront.core) + implementation(idofrontLibs.bundles.idofront.core) implementation(project(":core")) paperweight.paperDevBundle("1.20.2-R0.1-SNAPSHOT") //NMS } diff --git a/v1_20_R3/build.gradle.kts b/v1_20_R3/build.gradle.kts index 2214a76..16fe9bf 100644 --- a/v1_20_R3/build.gradle.kts +++ b/v1_20_R3/build.gradle.kts @@ -13,13 +13,13 @@ repositories { dependencies { // MineInAbyss platform - compileOnly(libs.kotlinx.serialization.json) - compileOnly(libs.kotlinx.serialization.kaml) - compileOnly(libs.kotlinx.coroutines) - compileOnly(libs.minecraft.mccoroutine) + compileOnly(idofrontLibs.kotlinx.serialization.json) + compileOnly(idofrontLibs.kotlinx.serialization.kaml) + compileOnly(idofrontLibs.kotlinx.coroutines) + compileOnly(idofrontLibs.minecraft.mccoroutine) // Shaded - implementation(libs.bundles.idofront.core) + implementation(idofrontLibs.bundles.idofront.core) implementation(project(":core")) paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") //NMS } From 7b1c993146c7c9686513eb0a9746324213a87377 Mon Sep 17 00:00:00 2001 From: Boy Date: Sun, 5 May 2024 22:15:46 +0200 Subject: [PATCH 02/18] feat: 1.20.5+ support --- .github/workflows/build.yml | 2 +- build.gradle.kts | 43 +-- core/build.gradle.kts | 1 + .../mineinabyss/emojy/nms/EmojyNMSHandlers.kt | 4 +- gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle.kts | 4 +- v1_19_R1/build.gradle.kts | 5 +- v1_19_R2/build.gradle.kts | 5 +- v1_19_R3/build.gradle.kts | 5 +- v1_20_R1/build.gradle.kts | 5 +- v1_20_R2/build.gradle.kts | 5 +- .../emojy/nms/v1_20_R2/EmojyNMSHandler.kt | 3 +- v1_20_R3/build.gradle.kts | 5 +- v1_20_R4/build.gradle.kts | 48 +++ .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 313 ++++++++++++++++++ 16 files changed, 414 insertions(+), 40 deletions(-) create mode 100644 v1_20_R4/build.gradle.kts create mode 100644 v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1eaaad1..872e257 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: temurin - java-version: 17 + java-version: 21 cache: gradle - name: Build diff --git a/build.gradle.kts b/build.gradle.kts index 76f4b00..9c001fe 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,4 @@ +import io.papermc.paperweight.userdev.ReobfArtifactConfiguration import net.minecrell.pluginyml.paper.PaperPluginDescription plugins { @@ -8,19 +9,19 @@ plugins { id("com.mineinabyss.conventions.autoversion") id("xyz.jpenilla.run-paper") version "2.0.1" // Adds runServer and runMojangMappedServer tasks for testing id("net.minecrell.plugin-yml.paper") version "0.6.0" - id("io.papermc.paperweight.userdev") version "1.5.11" + id("io.papermc.paperweight.userdev") version "1.7.1" } +paperweight.reobfArtifactConfiguration.set(ReobfArtifactConfiguration.MOJANG_PRODUCTION) + allprojects { apply(plugin = "java") version = rootProject.version - dependencies { - compileOnly(kotlin("stdlib-jdk8")) - } - repositories { + maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") mavenLocal() } } @@ -34,14 +35,15 @@ dependencies { compileOnly(idofrontLibs.minecraft.mccoroutine) // Shaded - paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") //NMS + paperweight.paperDevBundle("1.20.6-R0.1-SNAPSHOT") //NMS implementation(project(path = ":core")) - implementation(project(path = ":v1_19_R1", configuration = "reobf")) - implementation(project(path = ":v1_19_R2", configuration = "reobf")) - implementation(project(path = ":v1_19_R3", configuration = "reobf")) - implementation(project(path = ":v1_20_R1", configuration = "reobf")) - implementation(project(path = ":v1_20_R2", configuration = "reobf")) - implementation(project(path = ":v1_20_R3", configuration = "reobf")) + //implementation(project(path = ":v1_19_R1", configuration = "reobf")) + //implementation(project(path = ":v1_19_R2", configuration = "reobf")) + //implementation(project(path = ":v1_19_R3", configuration = "reobf")) + //implementation(project(path = ":v1_20_R1", configuration = "reobf")) + //implementation(project(path = ":v1_20_R2", configuration = "reobf")) + //implementation(project(path = ":v1_20_R3", configuration = "reobf")) + implementation(project(path = ":v1_20_R4")) } tasks { @@ -52,7 +54,7 @@ tasks { compileJava { options.encoding = Charsets.UTF_8.name() - options.release.set(17) + options.release.set(21) } javadoc { @@ -69,12 +71,13 @@ tasks { } shadowJar { - dependsOn(":v1_19_R1:reobfJar") - dependsOn(":v1_19_R2:reobfJar") - dependsOn(":v1_19_R3:reobfJar") - dependsOn(":v1_20_R1:reobfJar") - dependsOn(":v1_20_R2:reobfJar") - dependsOn(":v1_20_R3:reobfJar") + //dependsOn(":v1_19_R1:reobfJar") + //dependsOn(":v1_19_R2:reobfJar") + //dependsOn(":v1_19_R3:reobfJar") + //dependsOn(":v1_20_R1:reobfJar") + //dependsOn(":v1_20_R2:reobfJar") + //dependsOn(":v1_20_R3:reobfJar") + dependsOn(":v1_20_R4:reobfJar") archiveFileName.set("Emojy.jar") } @@ -88,7 +91,7 @@ paper { val version: String by project this.version = version authors = listOf("boy0000") - apiVersion = "1.19" + apiVersion = "1.20" serverDependencies { register("Idofront") { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 1956639..af2933d 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -8,6 +8,7 @@ plugins { repositories { gradlePluginPortal() maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.unnamed.team/repository/unnamed-public/") google() diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt b/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt index b93c672..2acac7e 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt @@ -13,12 +13,12 @@ import org.bukkit.entity.Player object EmojyNMSHandlers { - private val SUPPORTED_VERSION = arrayOf("v1_19_R1", "v1_19_R2", "v1_19_R3", "v1_20_R1", "v1_20_R2", "v1_20_R3") + private val SUPPORTED_VERSION = arrayOf(/*"v1_19_R1", "v1_19_R2", "v1_19_R3", "v1_20_R1", "v1_20_R2", "v1_20_R3", */"v1_20_R4") fun setup(): IEmojyNMSHandler { SUPPORTED_VERSION.forEach { version -> runCatching { - Class.forName("org.bukkit.craftbukkit.$version.entity.CraftPlayer") + //Class.forName("org.bukkit.craftbukkit.entity.CraftPlayer") return Class.forName("com.mineinabyss.emojy.nms.${version}.EmojyNMSHandler").getConstructor() .newInstance() as IEmojyNMSHandler } diff --git a/gradle.properties b/gradle.properties index b8debd1..7906906 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ group=com.mineinabyss -version=0.8 -idofrontVersion=0.23.0 +version=0.9 +idofrontVersion=0.24.0-dev.10 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a595206..48c0a02 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle.kts b/settings.gradle.kts index 2db4462..67f995e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,6 +8,7 @@ pluginManagement { mavenCentral() google() maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") maven("https://repo.papermc.io/repository/maven-public/") mavenLocal() } @@ -23,6 +24,7 @@ dependencyResolutionManagement { repositories { maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") mavenLocal() } @@ -33,4 +35,4 @@ dependencyResolutionManagement { } } -include("core", "v1_19_R1", "v1_19_R2", "v1_19_R3", "v1_20_R1", "v1_20_R2", "v1_20_R3") +include("core", /*"v1_19_R1", "v1_19_R2", "v1_19_R3", "v1_20_R1", "v1_20_R2", */"v1_20_R3", "v1_20_R4") diff --git a/v1_19_R1/build.gradle.kts b/v1_19_R1/build.gradle.kts index 58d0d94..4641baa 100644 --- a/v1_19_R1/build.gradle.kts +++ b/v1_19_R1/build.gradle.kts @@ -1,12 +1,13 @@ plugins { id("com.mineinabyss.conventions.kotlin.jvm") id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.5.11" + id("io.papermc.paperweight.userdev") version "1.7.1" } repositories { gradlePluginPortal() maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") maven("https://repo.papermc.io/repository/maven-public/") google() } @@ -32,7 +33,7 @@ tasks { compileJava { options.encoding = Charsets.UTF_8.name() - options.release.set(17) + options.release.set(21) } javadoc { options.encoding = Charsets.UTF_8.name() diff --git a/v1_19_R2/build.gradle.kts b/v1_19_R2/build.gradle.kts index 0e33bc5..8da5352 100644 --- a/v1_19_R2/build.gradle.kts +++ b/v1_19_R2/build.gradle.kts @@ -1,12 +1,13 @@ plugins { id("com.mineinabyss.conventions.kotlin.jvm") id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.5.11" + id("io.papermc.paperweight.userdev") version "1.7.1" } repositories { gradlePluginPortal() maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") maven("https://repo.papermc.io/repository/maven-public/") google() } @@ -32,7 +33,7 @@ tasks { compileJava { options.encoding = Charsets.UTF_8.name() - options.release.set(17) + options.release.set(21) } javadoc { options.encoding = Charsets.UTF_8.name() diff --git a/v1_19_R3/build.gradle.kts b/v1_19_R3/build.gradle.kts index ccb8d43..634f20e 100644 --- a/v1_19_R3/build.gradle.kts +++ b/v1_19_R3/build.gradle.kts @@ -1,12 +1,13 @@ plugins { id("com.mineinabyss.conventions.kotlin.jvm") id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.5.11" + id("io.papermc.paperweight.userdev") version "1.7.1" } repositories { gradlePluginPortal() maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") maven("https://repo.papermc.io/repository/maven-public/") google() } @@ -32,7 +33,7 @@ tasks { compileJava { options.encoding = Charsets.UTF_8.name() - options.release.set(17) + options.release.set(21) } javadoc { options.encoding = Charsets.UTF_8.name() diff --git a/v1_20_R1/build.gradle.kts b/v1_20_R1/build.gradle.kts index 14eea49..000763d 100644 --- a/v1_20_R1/build.gradle.kts +++ b/v1_20_R1/build.gradle.kts @@ -1,12 +1,13 @@ plugins { id("com.mineinabyss.conventions.kotlin.jvm") id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.5.11" + id("io.papermc.paperweight.userdev") version "1.7.1" } repositories { gradlePluginPortal() maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") maven("https://repo.papermc.io/repository/maven-public/") google() } @@ -32,7 +33,7 @@ tasks { compileJava { options.encoding = Charsets.UTF_8.name() - options.release.set(17) + options.release.set(21) } javadoc { options.encoding = Charsets.UTF_8.name() diff --git a/v1_20_R2/build.gradle.kts b/v1_20_R2/build.gradle.kts index c32e7c5..856d82c 100644 --- a/v1_20_R2/build.gradle.kts +++ b/v1_20_R2/build.gradle.kts @@ -1,12 +1,13 @@ plugins { id("com.mineinabyss.conventions.kotlin.jvm") id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.5.11" + id("io.papermc.paperweight.userdev") version "1.7.1" } repositories { gradlePluginPortal() maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") maven("https://repo.papermc.io/repository/maven-public/") google() } @@ -32,7 +33,7 @@ tasks { compileJava { options.encoding = Charsets.UTF_8.name() - options.release.set(17) + options.release.set(21) } javadoc { options.encoding = Charsets.UTF_8.name() diff --git a/v1_20_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R2/EmojyNMSHandler.kt b/v1_20_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R2/EmojyNMSHandler.kt index 8fb1d39..6c3588b 100644 --- a/v1_20_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R2/EmojyNMSHandler.kt +++ b/v1_20_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R2/EmojyNMSHandler.kt @@ -17,6 +17,7 @@ import io.netty.handler.codec.ByteToMessageDecoder import io.netty.handler.codec.MessageToByteEncoder import io.papermc.paper.adventure.PaperAdventure import net.kyori.adventure.text.Component +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag import net.minecraft.nbt.StringTag @@ -161,7 +162,7 @@ class EmojyNMSHandler : IEmojyNMSHandler { override fun readUtf(maxLength: Int): String { return super.readUtf(maxLength).let { string -> - runCatching { string.miniMsg() }.recover { legacy.deserialize(string) } + runCatching { string.miniMsg() }.recover { LegacyComponentSerializer.legacySection().deserialize(string) } .getOrNull()?.transform(player, true)?.serialize() ?: string } } diff --git a/v1_20_R3/build.gradle.kts b/v1_20_R3/build.gradle.kts index 16fe9bf..0478735 100644 --- a/v1_20_R3/build.gradle.kts +++ b/v1_20_R3/build.gradle.kts @@ -1,12 +1,13 @@ plugins { id("com.mineinabyss.conventions.kotlin.jvm") id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.5.11" + id("io.papermc.paperweight.userdev") version "1.7.1" } repositories { gradlePluginPortal() maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") maven("https://repo.papermc.io/repository/maven-public/") google() } @@ -32,7 +33,7 @@ tasks { compileJava { options.encoding = Charsets.UTF_8.name() - options.release.set(17) + options.release.set(21) } javadoc { options.encoding = Charsets.UTF_8.name() diff --git a/v1_20_R4/build.gradle.kts b/v1_20_R4/build.gradle.kts new file mode 100644 index 0000000..11b747f --- /dev/null +++ b/v1_20_R4/build.gradle.kts @@ -0,0 +1,48 @@ +import io.papermc.paperweight.userdev.ReobfArtifactConfiguration + +plugins { + id("com.mineinabyss.conventions.kotlin.jvm") + id("com.mineinabyss.conventions.autoversion") + id("io.papermc.paperweight.userdev") version "1.7.1" +} + +repositories { + gradlePluginPortal() + maven("https://repo.mineinabyss.com/releases") + maven("https://repo.mineinabyss.com/snapshots") + maven("https://repo.papermc.io/repository/maven-public/") + google() +} + +paperweight.reobfArtifactConfiguration.set(ReobfArtifactConfiguration.MOJANG_PRODUCTION) + +dependencies { + // MineInAbyss platform + compileOnly(idofrontLibs.kotlinx.serialization.json) + compileOnly(idofrontLibs.kotlinx.serialization.kaml) + compileOnly(idofrontLibs.kotlinx.coroutines) + compileOnly(idofrontLibs.minecraft.mccoroutine) + + // Shaded + implementation(idofrontLibs.bundles.idofront.core) + implementation(project(":core")) + paperweight.paperDevBundle("1.20.6-R0.1-SNAPSHOT") //NMS +} + +tasks { + + build { + dependsOn(reobfJar) + } + + compileJava { + options.encoding = Charsets.UTF_8.name() + options.release.set(21) + } + javadoc { + options.encoding = Charsets.UTF_8.name() + } + processResources { + filteringCharset = Charsets.UTF_8.name() + } +} diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt new file mode 100644 index 0000000..06b3dc4 --- /dev/null +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -0,0 +1,313 @@ +@file:Suppress("unused") + +package com.mineinabyss.emojy.nms.v1_20_R4 + +import com.mineinabyss.emojy.emojy +import com.mineinabyss.emojy.escapeEmoteIDs +import com.mineinabyss.emojy.legacy +import com.mineinabyss.emojy.nms.EmojyNMSHandlers +import com.mineinabyss.emojy.nms.IEmojyNMSHandler +import com.mineinabyss.emojy.transformEmoteIDs +import com.mineinabyss.idofront.messaging.broadcastVal +import com.mineinabyss.idofront.messaging.logVal +import com.mineinabyss.idofront.textcomponents.miniMsg +import com.mineinabyss.idofront.textcomponents.serialize +import io.netty.buffer.ByteBuf +import io.netty.buffer.Unpooled +import io.netty.channel.ChannelHandlerContext +import io.papermc.paper.adventure.AdventureComponent +import io.papermc.paper.adventure.PaperAdventure +import net.kyori.adventure.text.Component +import net.minecraft.core.RegistryAccess +import net.minecraft.nbt.* +import net.minecraft.network.* +import net.minecraft.network.chat.ComponentSerialization +import net.minecraft.network.protocol.Packet +import net.minecraft.network.protocol.game.GameProtocols +import org.bukkit.craftbukkit.CraftServer +import org.bukkit.craftbukkit.entity.CraftPlayer +import org.bukkit.entity.Player +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.DataInputStream +import java.io.DataOutputStream +import java.util.function.Function + +class EmojyNMSHandler : IEmojyNMSHandler { + + private var INFO_BY_ENCODER: Function, ProtocolInfo<*>> + private var INFO_BY_DECODER: Function, ProtocolInfo<*>> + + companion object { + private fun Player.connection() = (this as CraftPlayer).handle.connection.connection + private fun Player.channel() = (this as CraftPlayer).handle.connection.connection.channel + private fun registryAccess(): RegistryAccess = + (emojy.plugin.server as CraftServer).handle.server.registryAccess() + } + + init { + val encoder = PacketEncoder::class.java.declaredFields.firstOrNull { + ProtocolInfo::class.java.isAssignableFrom(it.type) + }?.apply { isAccessible = true } ?: throw NullPointerException() + + val decoder = PacketDecoder::class.java.declaredFields.firstOrNull { + ProtocolInfo::class.java.isAssignableFrom(it.type) + }?.apply { isAccessible = true } ?: throw NullPointerException() + + INFO_BY_ENCODER = Function, ProtocolInfo<*>> { e: PacketEncoder<*> -> + return@Function run { encoder.get(e) } as ProtocolInfo<*> + } + INFO_BY_DECODER = Function, ProtocolInfo<*>> { e: PacketDecoder<*> -> + return@Function run { decoder.get(e) } as ProtocolInfo<*> + } + } + + override fun inject(player: Player) { + val channel = player.channel() + val handler = PlayerHandler(player) + channel.eventLoop().submit { + val pipeline = channel.pipeline() + pipeline.forEach { + pipeline.replace( + it.key, it.key, when (it.value) { + is PacketEncoder<*> -> handler.encoder(INFO_BY_ENCODER.apply(it.value as PacketEncoder<*>)) + is PacketDecoder<*> -> handler.decoder(INFO_BY_DECODER.apply(it.value as PacketDecoder<*>)) + else -> return@forEach + } + ) + } + } + } + + override fun uninject(player: Player) { + val channel = player.channel() + val pipeline = channel.pipeline() + pipeline.forEach { + pipeline.replace( + it.key, it.key, when (it.value) { + is PlayerHandler.EmojyEncoder -> PacketEncoder((it.value as PlayerHandler.EmojyEncoder).protocolInfo) + is PlayerHandler.EmojyDecoder -> PacketDecoder((it.value as PlayerHandler.EmojyDecoder).protocolInfo) + else -> return@forEach + } + ) + } + } + + private class EmojyBuffer(val originalBuffer: ByteBuf, val player: Player?) : RegistryFriendlyByteBuf(originalBuffer, registryAccess()) { + override fun copy(): EmojyBuffer { + return EmojyBuffer(Unpooled.copiedBuffer(originalBuffer), player) + } + + override fun writeUtf(string: String, maxLength: Int): FriendlyByteBuf { + return EmojyNMSHandlers.writeTransformer(player, true, true).invoke(string).let { super.writeUtf(it, maxLength) } + } + + override fun readUtf(maxLength: Int): String { + return super.readUtf(maxLength).let { string -> + runCatching { string.miniMsg() }.recover { legacy.deserialize(string) } + .getOrNull()?.escapeEmoteIDs(player)?.serialize() ?: string + } + } + + override fun writeNbt(compound: Tag?): FriendlyByteBuf { + return super.writeNbt(compound?.apply { + when (this) { + is CompoundTag -> transform(this, EmojyNMSHandlers.writeTransformer(player, false, true)) + is StringTag -> transform(this, EmojyNMSHandlers.writeTransformer(player, false,true)) + } + }) + } + + override fun readNbt(): CompoundTag? { + return super.readNbt()?.apply { + transform(this, EmojyNMSHandlers.readTransformer(player)) + } + } + + private fun transform(compound: CompoundTag, transformer: Function) { + for (key in compound.allKeys) when (val base = compound.get(key)) { + is CompoundTag -> transform(base, transformer) + is ListTag -> transform(base, transformer) + is StringTag -> compound.put(key, StringTag.valueOf(transformer.apply(base.asString))) + } + } + + private fun transform(list: ListTag, transformer: Function) { + val listCopy = list.toList() + for (base in listCopy) when (base) { + is CompoundTag -> transform(base, transformer) + is ListTag -> transform(base, transformer) + is StringTag -> list.indexOf(base).let { index -> + list[index] = StringTag.valueOf(transformer.apply(base.asString)) + } + } + } + + private fun transform(string: StringTag, transformer: Function) { + transformer.apply(string.asString) + } + } + + @Suppress("UNCHECKED_CAST") + private data class PlayerHandler(val player: Player) { + + private fun hasComponent(clazz: Class<*>): Boolean { + return clazz.declaredFields.any { net.minecraft.network.chat.Component::class.java.isAssignableFrom(it.type) } + || clazz.declaredFields.any { hasComponent(it::class.java) } + } + + fun decoder(protocolInfo: ProtocolInfo<*>) = EmojyDecoder(protocolInfo as ProtocolInfo) + fun encoder(protocolInfo: ProtocolInfo<*>) = EmojyEncoder(protocolInfo as ProtocolInfo) + private fun writeNewNbt( + original: EmojyBuffer, + clientbound: Boolean + ): EmojyBuffer { + val newBuffer = EmojyBuffer(Unpooled.buffer(), player) + val id = VarInt.read(original) + VarInt.write(newBuffer, id) + + val bytes = ByteArray(original.readableBytes()) + original.readBytes(bytes) + val list: MutableList = ArrayList(bytes.size) + var index = 0 + try { + loop@ while (index < bytes.size) { + val aByte = bytes[index++] + list.add(aByte) + val size = bytes.size - index + val nbtByte = ByteArray(size) + System.arraycopy(bytes, index, nbtByte, 0, nbtByte.size) + + when (TagTypes.getType(aByte.toInt())) { + ListTag.TYPE -> { + emojy.logger.s("list: " + clientbound) + /*val size = bytes.size - index + val nbtByte = ByteArray(size) + System.arraycopy(bytes, index, nbtByte, 0, nbtByte.size) + + runCatching { + DataInputStream(ByteArrayInputStream(nbtByte)).use { input -> + val getTag = ListTag.TYPE.load(input) + } + }*/ + } + StringTag.TYPE -> index = handleString(index, nbtByte, clientbound, list) + CompoundTag.TYPE -> index = handleCompound(index, nbtByte, clientbound, list) + } + } + val newByte = ByteArray(list.size) + var i = 0 + for (b in list) newByte[i++] = b + newBuffer.writeBytes(newByte) + return newBuffer + } catch (e: Exception) { + throw RuntimeException(e) + } + } + + private fun handleString(index: Int, nbtByte: ByteArray, clientbound: Boolean, list: MutableList): Int { + emojy.logger.e("string: " + clientbound) + var index = index + runCatching { + DataInputStream(ByteArrayInputStream(nbtByte)).use { input -> + val getTag = StringTag.TYPE.load(input, NbtAccounter.create(FriendlyByteBuf.DEFAULT_NBT_QUOTA.toLong())).takeIf { it.asString.isNotBlank() } ?: return@use + val oldComponent = PaperAdventure.asAdventure(ComponentSerialization.CODEC.decode(NbtOps.INSTANCE, getTag).getOrThrow().first) + val newComponent: Component = when (clientbound) { + true -> oldComponent.logVal("").transformEmoteIDs(player, true, true).logVal("") + false -> oldComponent.escapeEmoteIDs(player) + } + val newTag = + ComponentSerialization.CODEC.encode( + PaperAdventure.asVanilla(newComponent), + NbtOps.INSTANCE, + StringTag.valueOf("") + ).getOrThrow() as StringTag + val stream = ByteArrayOutputStream() + DataOutputStream(stream).use { output -> + newTag.write(output) + index += nbtByte.size - input.available() + for (b in stream.toByteArray()) { + list.add(b) + } + } + } + } + return index + } + + private fun handleCompound(index: Int, nbtByte: ByteArray, clientbound: Boolean, list: MutableList): Int { + emojy.logger.w("compoundtag: " + clientbound) + var index = index + runCatching { + DataInputStream(ByteArrayInputStream(nbtByte)).use { input -> + val getTag = CompoundTag.TYPE.load( + input, + NbtAccounter.create(FriendlyByteBuf.DEFAULT_NBT_QUOTA.toLong()) + ) + if (getTag.isEmpty) return@use + val oldComponent = + PaperAdventure.asAdventure( + ComponentSerialization.CODEC.decode( + NbtOps.INSTANCE, + getTag + ).getOrThrow().first + ) + val newComponent: Component = when (clientbound) { + true -> oldComponent.logVal("").transformEmoteIDs(player, true, true).logVal("") + false -> oldComponent.escapeEmoteIDs(player) + } + val newTag = + ComponentSerialization.CODEC.encode( + PaperAdventure.asVanilla(newComponent), + NbtOps.INSTANCE, + CompoundTag() + ).getOrThrow() as CompoundTag + val stream = ByteArrayOutputStream() + DataOutputStream(stream).use { output -> + newTag.write(output) + index += nbtByte.size - input.available() + for (b in stream.toByteArray()) { + list.add(b) + } + } + } + } + + return index + } + + inner class EmojyEncoder(var protocolInfo: ProtocolInfo) : + PacketEncoder(protocolInfo) { + + + init { + protocolInfo = (GameProtocols.CLIENTBOUND.bind { EmojyBuffer(it, null) }.takeIf { protocolInfo.id() == ConnectionProtocol.PLAY } ?: protocolInfo) as ProtocolInfo + } + + override fun encode(ctx: ChannelHandlerContext, packet: Packet, byteBuf: ByteBuf) { + if (hasComponent(packet.javaClass)) runCatching { + val newBuffer = EmojyBuffer(Unpooled.buffer(), player) + protocolInfo.codec().encode(newBuffer, packet) + byteBuf.writeBytes(writeNewNbt(newBuffer, true)) + ProtocolSwapHandler.handleOutboundTerminalPacket(ctx, packet) + } else super.encode(ctx, packet, byteBuf) + } + } + + inner class EmojyDecoder(val protocolInfo: ProtocolInfo) : + PacketDecoder(protocolInfo) { + + override fun decode(ctx: ChannelHandlerContext, byteBuf: ByteBuf, list: MutableList) { + + runCatching { + val packet = protocolInfo.codec().decode(writeNewNbt(EmojyBuffer(byteBuf, player), false)) + list += packet + ProtocolSwapHandler.handleInboundTerminalPacket(ctx, packet) + }.onFailure { super.decode(ctx, byteBuf, list) } + } + } + } + + + override val supported get() = true +} From ece6f363fd943dba84d96d564bb96e1c024301f3 Mon Sep 17 00:00:00 2001 From: Boy Date: Tue, 28 May 2024 20:39:49 +0200 Subject: [PATCH 03/18] refactor: edit codec instead --- .../com/mineinabyss/emojy/EmojyHelpers.kt | 4 +- .../com/mineinabyss/emojy/EmojyPlugin.kt | 14 +- .../mineinabyss/emojy/nms/EmojyNMSHandlers.kt | 53 +-- .../mineinabyss/emojy/nms/IEmojyNMSHandler.kt | 5 +- settings.gradle.kts | 2 +- .../emojy/nms/v1_20_R4}/EmojyListener.kt | 11 +- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 333 +++--------------- 7 files changed, 78 insertions(+), 344 deletions(-) rename {core/src/main/kotlin/com/mineinabyss/emojy => v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4}/EmojyListener.kt (83%) diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt index 17af042..c6de4e9 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt @@ -17,8 +17,8 @@ fun Component.transform(player: Player?, insert: Boolean, unescape: Boolean = tr val legacy = LegacyComponentSerializer.legacySection() private val spaceRegex: Regex = "(?() DI.add(config("config", dataPath, EmojyConfig(), onLoad = { @@ -70,7 +58,7 @@ class EmojyPlugin : JavaPlugin() { config>(it, dataPath / "languages", mapOf()).getOrLoad()) }.toSet() override val logger by plugin.observeLogger() - override val handler: IEmojyNMSHandler = EmojyNMSHandlers.setup() + override val handler: IEmojyNMSHandler = EmojyNMSHandlers.setup(this@EmojyPlugin) }) GlobalTranslator.translator().sources().filter { it.name() == EmojyTranslator.key }.forEach(GlobalTranslator.translator()::removeSource) diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt b/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt index 2acac7e..e812c1f 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt @@ -2,6 +2,7 @@ package com.mineinabyss.emojy.nms import com.google.gson.JsonObject import com.google.gson.JsonParser +import com.mineinabyss.emojy.EmojyPlugin import com.mineinabyss.emojy.escapeEmoteIDs import com.mineinabyss.emojy.transform import com.mineinabyss.emojy.transformEmoteIDs @@ -9,61 +10,21 @@ import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer +import org.bukkit.Bukkit import org.bukkit.entity.Player object EmojyNMSHandlers { - private val SUPPORTED_VERSION = arrayOf(/*"v1_19_R1", "v1_19_R2", "v1_19_R3", "v1_20_R1", "v1_20_R2", "v1_20_R3", */"v1_20_R4") + private val SUPPORTED_VERSION = arrayOf("v1_20_R4") - fun setup(): IEmojyNMSHandler { + fun setup(emojy: EmojyPlugin): IEmojyNMSHandler { SUPPORTED_VERSION.forEach { version -> runCatching { - //Class.forName("org.bukkit.craftbukkit.entity.CraftPlayer") - return Class.forName("com.mineinabyss.emojy.nms.${version}.EmojyNMSHandler").getConstructor() - .newInstance() as IEmojyNMSHandler - } + return Class.forName("com.mineinabyss.emojy.nms.${version}.EmojyNMSHandler").getConstructor(EmojyPlugin::class.java) + .newInstance(emojy) as IEmojyNMSHandler + }.onFailure { it.printStackTrace() } } throw IllegalStateException("Unsupported server version") } - - private val gson = GsonComponentSerializer.gson() - private val plain = PlainTextComponentSerializer.plainText() - //TODO toPlainText fixes the anvil issue with tags being escaped - // It does break all other formatting everywhere else though by removing tags - // serialize() doesnt but keeps the escaped tag from gson - // anvil goes like this, inputItem -> readUtf -> renameField -> writeNbt from raw string, which is why it breaks - fun JsonObject.formatString(player: Player? = null) : String { - return if (this.has("args") || this.has("text") || this.has("extra") || this.has("translate")) { - gson.serialize(gson.deserializeFromTree(this)/*.toPlainText()*/.serialize().miniMsg().transform(player, true, true)) - } else this.toString() - } - - fun writeTransformer(player: Player?, insert: Boolean, unescape: Boolean) = { string: String -> - runCatching { - val jsonObject = JsonParser.parseString(string).takeIf { it.isJsonObject }?.asJsonObject ?: return@runCatching string - if (jsonObject.has("args") || jsonObject.has("text") || jsonObject.has("extra") || jsonObject.has("translate")) { - val formatted = gson.deserializeFromTree(jsonObject).transformEmoteIDs(player, insert, unescape) - gson.serialize(formatted) - } else string - }.getOrNull() ?: string - } - - fun readTransformer(player: Player?) = { string: String -> - runCatching { - val jsonObject = JsonParser.parseString(string).takeIf { it.isJsonObject }?.asJsonObject ?: return@runCatching string - if (jsonObject.has("args") || jsonObject.has("text") || jsonObject.has("extra") || jsonObject.has("translate")) { - val formatted = gson.deserializeFromTree(jsonObject).escapeEmoteIDs(player) - gson.serialize(formatted) - } else string - }.getOrNull() ?: string - } - - fun transformer(player: Player? = null) = { string: String -> - runCatching { - val element = JsonParser.parseString(string) - if (element.isJsonObject) element.asJsonObject.formatString(player) - else string - }.getOrNull() ?: string - } } diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/nms/IEmojyNMSHandler.kt b/core/src/main/kotlin/com/mineinabyss/emojy/nms/IEmojyNMSHandler.kt index a25cb37..7d03dca 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/nms/IEmojyNMSHandler.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/nms/IEmojyNMSHandler.kt @@ -1,12 +1,13 @@ package com.mineinabyss.emojy.nms import org.bukkit.entity.Player +import java.util.Locale interface IEmojyNMSHandler { - fun inject(player: Player) + val locals: MutableSet - fun uninject(player: Player) + fun addLocaleCodec(locale: Locale) {} val supported get() = false } diff --git a/settings.gradle.kts b/settings.gradle.kts index 67f995e..f8e20d7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,4 +35,4 @@ dependencyResolutionManagement { } } -include("core", /*"v1_19_R1", "v1_19_R2", "v1_19_R3", "v1_20_R1", "v1_20_R2", */"v1_20_R3", "v1_20_R4") +include("core", "v1_20_R4") diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyListener.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt similarity index 83% rename from core/src/main/kotlin/com/mineinabyss/emojy/EmojyListener.kt rename to v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt index 6324a9b..f8697dc 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyListener.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt @@ -1,6 +1,9 @@ -package com.mineinabyss.emojy +package com.mineinabyss.emojy.nms.v1_20_R4 +import com.mineinabyss.emojy.emojy +import com.mineinabyss.emojy.escapeEmoteIDs import com.mineinabyss.emojy.nms.EmojyNMSHandlers +import com.mineinabyss.emojy.transform import com.mineinabyss.idofront.items.editItemMeta import com.mineinabyss.idofront.messaging.logError import com.mineinabyss.idofront.messaging.logVal @@ -22,14 +25,14 @@ import org.bukkit.inventory.AnvilInventory class EmojyListener : Listener { @EventHandler - fun PlayerJoinEvent.injectPlayer() { - emojy.handler.inject(player) + fun PlayerJoinEvent.onJoin() { + emojy.handler.addLocaleCodec(player.locale()) } // Replace with result not original message to avoid borking other chat formatting @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) fun AsyncChatDecorateEvent.onPlayerChat() { - result(result().transform(player(), true, true)) + result(result().escapeEmoteIDs(player())) } @EventHandler diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index 06b3dc4..62babaa 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -2,312 +2,93 @@ package com.mineinabyss.emojy.nms.v1_20_R4 -import com.mineinabyss.emojy.emojy -import com.mineinabyss.emojy.escapeEmoteIDs -import com.mineinabyss.emojy.legacy -import com.mineinabyss.emojy.nms.EmojyNMSHandlers +import com.mineinabyss.emojy.* import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.emojy.transformEmoteIDs -import com.mineinabyss.idofront.messaging.broadcastVal +import com.mineinabyss.idofront.messaging.idofrontLogger import com.mineinabyss.idofront.messaging.logVal -import com.mineinabyss.idofront.textcomponents.miniMsg +import com.mineinabyss.idofront.plugin.listeners import com.mineinabyss.idofront.textcomponents.serialize +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult import io.netty.buffer.ByteBuf -import io.netty.buffer.Unpooled -import io.netty.channel.ChannelHandlerContext -import io.papermc.paper.adventure.AdventureComponent +import io.netty.handler.codec.DecoderException +import io.netty.handler.codec.EncoderException +import io.papermc.paper.adventure.AdventureCodecs import io.papermc.paper.adventure.PaperAdventure import net.kyori.adventure.text.Component -import net.minecraft.core.RegistryAccess -import net.minecraft.nbt.* -import net.minecraft.network.* +import net.kyori.adventure.text.TextReplacementConfig +import net.kyori.adventure.translation.GlobalTranslator +import net.minecraft.nbt.NbtAccounter +import net.minecraft.nbt.NbtOps +import net.minecraft.nbt.Tag +import net.minecraft.network.RegistryFriendlyByteBuf import net.minecraft.network.chat.ComponentSerialization -import net.minecraft.network.protocol.Packet -import net.minecraft.network.protocol.game.GameProtocols -import org.bukkit.craftbukkit.CraftServer -import org.bukkit.craftbukkit.entity.CraftPlayer -import org.bukkit.entity.Player -import java.io.ByteArrayInputStream -import java.io.ByteArrayOutputStream -import java.io.DataInputStream -import java.io.DataOutputStream -import java.util.function.Function +import net.minecraft.network.codec.ByteBufCodecs +import net.minecraft.network.codec.StreamCodec +import java.lang.reflect.Field +import java.lang.reflect.Modifier +import java.util.* +import java.util.function.Supplier -class EmojyNMSHandler : IEmojyNMSHandler { +class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { - private var INFO_BY_ENCODER: Function, ProtocolInfo<*>> - private var INFO_BY_DECODER: Function, ProtocolInfo<*>> - - companion object { - private fun Player.connection() = (this as CraftPlayer).handle.connection.connection - private fun Player.channel() = (this as CraftPlayer).handle.connection.connection.channel - private fun registryAccess(): RegistryAccess = - (emojy.plugin.server as CraftServer).handle.server.registryAccess() - } + override val locals: MutableSet = mutableSetOf() init { - val encoder = PacketEncoder::class.java.declaredFields.firstOrNull { - ProtocolInfo::class.java.isAssignableFrom(it.type) - }?.apply { isAccessible = true } ?: throw NullPointerException() - - val decoder = PacketDecoder::class.java.declaredFields.firstOrNull { - ProtocolInfo::class.java.isAssignableFrom(it.type) - }?.apply { isAccessible = true } ?: throw NullPointerException() + emojy.listeners(EmojyListener()) - INFO_BY_ENCODER = Function, ProtocolInfo<*>> { e: PacketEncoder<*> -> - return@Function run { encoder.get(e) } as ProtocolInfo<*> - } - INFO_BY_DECODER = Function, ProtocolInfo<*>> { e: PacketDecoder<*> -> - return@Function run { decoder.get(e) } as ProtocolInfo<*> - } - } + val codecs = (PaperAdventure::class.java.getDeclaredField("LOCALIZED_CODECS").apply { isAccessible = true } + .get(null) as MutableMap>) - override fun inject(player: Player) { - val channel = player.channel() - val handler = PlayerHandler(player) - channel.eventLoop().submit { - val pipeline = channel.pipeline() - pipeline.forEach { - pipeline.replace( - it.key, it.key, when (it.value) { - is PacketEncoder<*> -> handler.encoder(INFO_BY_ENCODER.apply(it.value as PacketEncoder<*>)) - is PacketDecoder<*> -> handler.decoder(INFO_BY_DECODER.apply(it.value as PacketDecoder<*>)) - else -> return@forEach - } - ) - } - } - } - - override fun uninject(player: Player) { - val channel = player.channel() - val pipeline = channel.pipeline() - pipeline.forEach { - pipeline.replace( - it.key, it.key, when (it.value) { - is PlayerHandler.EmojyEncoder -> PacketEncoder((it.value as PlayerHandler.EmojyEncoder).protocolInfo) - is PlayerHandler.EmojyDecoder -> PacketDecoder((it.value as PlayerHandler.EmojyDecoder).protocolInfo) - else -> return@forEach - } + for (locale in Locale.getAvailableLocales()) { + codecs[locale] = AdventureCodecs.COMPONENT_CODEC.xmap( + { component -> component }, // decode + { component -> GlobalTranslator.render(component.transformEmotes(), locale) } // encode ) } } - private class EmojyBuffer(val originalBuffer: ByteBuf, val player: Player?) : RegistryFriendlyByteBuf(originalBuffer, registryAccess()) { - override fun copy(): EmojyBuffer { - return EmojyBuffer(Unpooled.copiedBuffer(originalBuffer), player) - } - - override fun writeUtf(string: String, maxLength: Int): FriendlyByteBuf { - return EmojyNMSHandlers.writeTransformer(player, true, true).invoke(string).let { super.writeUtf(it, maxLength) } - } - - override fun readUtf(maxLength: Int): String { - return super.readUtf(maxLength).let { string -> - runCatching { string.miniMsg() }.recover { legacy.deserialize(string) } - .getOrNull()?.escapeEmoteIDs(player)?.serialize() ?: string - } - } - - override fun writeNbt(compound: Tag?): FriendlyByteBuf { - return super.writeNbt(compound?.apply { - when (this) { - is CompoundTag -> transform(this, EmojyNMSHandlers.writeTransformer(player, false, true)) - is StringTag -> transform(this, EmojyNMSHandlers.writeTransformer(player, false,true)) - } - }) - } - - override fun readNbt(): CompoundTag? { - return super.readNbt()?.apply { - transform(this, EmojyNMSHandlers.readTransformer(player)) - } - } - - private fun transform(compound: CompoundTag, transformer: Function) { - for (key in compound.allKeys) when (val base = compound.get(key)) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> compound.put(key, StringTag.valueOf(transformer.apply(base.asString))) - } - } - - private fun transform(list: ListTag, transformer: Function) { - val listCopy = list.toList() - for (base in listCopy) when (base) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> list.indexOf(base).let { index -> - list[index] = StringTag.valueOf(transformer.apply(base.asString)) - } - } - } - - private fun transform(string: StringTag, transformer: Function) { - transformer.apply(string.asString) - } - } - - @Suppress("UNCHECKED_CAST") - private data class PlayerHandler(val player: Player) { + companion object { - private fun hasComponent(clazz: Class<*>): Boolean { - return clazz.declaredFields.any { net.minecraft.network.chat.Component::class.java.isAssignableFrom(it.type) } - || clazz.declaredFields.any { hasComponent(it::class.java) } + fun net.minecraft.network.chat.Component.transformEmotes(): net.minecraft.network.chat.Component { + return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).transformEmotes()) } - fun decoder(protocolInfo: ProtocolInfo<*>) = EmojyDecoder(protocolInfo as ProtocolInfo) - fun encoder(protocolInfo: ProtocolInfo<*>) = EmojyEncoder(protocolInfo as ProtocolInfo) - private fun writeNewNbt( - original: EmojyBuffer, - clientbound: Boolean - ): EmojyBuffer { - val newBuffer = EmojyBuffer(Unpooled.buffer(), player) - val id = VarInt.read(original) - VarInt.write(newBuffer, id) - - val bytes = ByteArray(original.readableBytes()) - original.readBytes(bytes) - val list: MutableList = ArrayList(bytes.size) - var index = 0 - try { - loop@ while (index < bytes.size) { - val aByte = bytes[index++] - list.add(aByte) - val size = bytes.size - index - val nbtByte = ByteArray(size) - System.arraycopy(bytes, index, nbtByte, 0, nbtByte.size) - - when (TagTypes.getType(aByte.toInt())) { - ListTag.TYPE -> { - emojy.logger.s("list: " + clientbound) - /*val size = bytes.size - index - val nbtByte = ByteArray(size) - System.arraycopy(bytes, index, nbtByte, 0, nbtByte.size) + fun Component.transformEmotes(): Component { + var component = this + val serialized = this.serialize() - runCatching { - DataInputStream(ByteArrayInputStream(nbtByte)).use { input -> - val getTag = ListTag.TYPE.load(input) - } - }*/ - } - StringTag.TYPE -> index = handleString(index, nbtByte, clientbound, list) - CompoundTag.TYPE -> index = handleCompound(index, nbtByte, clientbound, list) - } - } - val newByte = ByteArray(list.size) - var i = 0 - for (b in list) newByte[i++] = b - newBuffer.writeBytes(newByte) - return newBuffer - } catch (e: Exception) { - throw RuntimeException(e) - } - } + for (emote in emojy.emotes) emote.baseRegex.findAll(serialized).forEach { match -> - private fun handleString(index: Int, nbtByte: ByteArray, clientbound: Boolean, list: MutableList): Int { - emojy.logger.e("string: " + clientbound) - var index = index - runCatching { - DataInputStream(ByteArrayInputStream(nbtByte)).use { input -> - val getTag = StringTag.TYPE.load(input, NbtAccounter.create(FriendlyByteBuf.DEFAULT_NBT_QUOTA.toLong())).takeIf { it.asString.isNotBlank() } ?: return@use - val oldComponent = PaperAdventure.asAdventure(ComponentSerialization.CODEC.decode(NbtOps.INSTANCE, getTag).getOrThrow().first) - val newComponent: Component = when (clientbound) { - true -> oldComponent.logVal("").transformEmoteIDs(player, true, true).logVal("") - false -> oldComponent.escapeEmoteIDs(player) - } - val newTag = - ComponentSerialization.CODEC.encode( - PaperAdventure.asVanilla(newComponent), - NbtOps.INSTANCE, - StringTag.valueOf("") - ).getOrThrow() as StringTag - val stream = ByteArrayOutputStream() - DataOutputStream(stream).use { output -> - newTag.write(output) - index += nbtByte.size - input.available() - for (b in stream.toByteArray()) { - list.add(b) - } - } - } - } - return index - } + val colorable = colorableRegex in match.value + val bitmapIndex = bitmapIndexRegex.find(match.value)?.groupValues?.get(1)?.toIntOrNull() ?: -1 - private fun handleCompound(index: Int, nbtByte: ByteArray, clientbound: Boolean, list: MutableList): Int { - emojy.logger.w("compoundtag: " + clientbound) - var index = index - runCatching { - DataInputStream(ByteArrayInputStream(nbtByte)).use { input -> - val getTag = CompoundTag.TYPE.load( - input, - NbtAccounter.create(FriendlyByteBuf.DEFAULT_NBT_QUOTA.toLong()) - ) - if (getTag.isEmpty) return@use - val oldComponent = - PaperAdventure.asAdventure( - ComponentSerialization.CODEC.decode( - NbtOps.INSTANCE, - getTag - ).getOrThrow().first + component = component.replaceText( + TextReplacementConfig.builder() + .match(emote.baseRegex.pattern).once() + .replacement( + emote.formattedUnicode( + insert = false, + colorable = colorable, + bitmapIndex = bitmapIndex + ) ) - val newComponent: Component = when (clientbound) { - true -> oldComponent.logVal("").transformEmoteIDs(player, true, true).logVal("") - false -> oldComponent.escapeEmoteIDs(player) - } - val newTag = - ComponentSerialization.CODEC.encode( - PaperAdventure.asVanilla(newComponent), - NbtOps.INSTANCE, - CompoundTag() - ).getOrThrow() as CompoundTag - val stream = ByteArrayOutputStream() - DataOutputStream(stream).use { output -> - newTag.write(output) - index += nbtByte.size - input.available() - for (b in stream.toByteArray()) { - list.add(b) - } - } - } + .build() + ) } - return index - } - - inner class EmojyEncoder(var protocolInfo: ProtocolInfo) : - PacketEncoder(protocolInfo) { - - - init { - protocolInfo = (GameProtocols.CLIENTBOUND.bind { EmojyBuffer(it, null) }.takeIf { protocolInfo.id() == ConnectionProtocol.PLAY } ?: protocolInfo) as ProtocolInfo - } - - override fun encode(ctx: ChannelHandlerContext, packet: Packet, byteBuf: ByteBuf) { - if (hasComponent(packet.javaClass)) runCatching { - val newBuffer = EmojyBuffer(Unpooled.buffer(), player) - protocolInfo.codec().encode(newBuffer, packet) - byteBuf.writeBytes(writeNewNbt(newBuffer, true)) - ProtocolSwapHandler.handleOutboundTerminalPacket(ctx, packet) - } else super.encode(ctx, packet, byteBuf) + for (gif in emojy.gifs) gif.baseRegex.findAll(serialized).forEach { _ -> + component = component.replaceText( + TextReplacementConfig.builder() + .match(gif.baseRegex.pattern).once() + .replacement(gif.formattedUnicode(insert = false)) + .build() + ) } - } - - inner class EmojyDecoder(val protocolInfo: ProtocolInfo) : - PacketDecoder(protocolInfo) { - override fun decode(ctx: ChannelHandlerContext, byteBuf: ByteBuf, list: MutableList) { - - runCatching { - val packet = protocolInfo.codec().decode(writeNewNbt(EmojyBuffer(byteBuf, player), false)) - list += packet - ProtocolSwapHandler.handleInboundTerminalPacket(ctx, packet) - }.onFailure { super.decode(ctx, byteBuf, list) } - } + return component } } - override val supported get() = true } From 8fac2557298029e2ffa5669c206aa6ea8b8b0fde Mon Sep 17 00:00:00 2001 From: Boy Date: Wed, 29 May 2024 11:21:11 +0200 Subject: [PATCH 04/18] fix: use packets to handle title/subtitle/actionbar with no permission checks --- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 60 ++++++++++++++----- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index 62babaa..e8d73d9 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -4,31 +4,27 @@ package com.mineinabyss.emojy.nms.v1_20_R4 import com.mineinabyss.emojy.* import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.idofront.messaging.idofrontLogger -import com.mineinabyss.idofront.messaging.logVal import com.mineinabyss.idofront.plugin.listeners import com.mineinabyss.idofront.textcomponents.serialize import com.mojang.serialization.Codec -import com.mojang.serialization.DataResult -import io.netty.buffer.ByteBuf -import io.netty.handler.codec.DecoderException -import io.netty.handler.codec.EncoderException +import io.netty.channel.Channel +import io.netty.channel.ChannelDuplexHandler +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.ChannelPromise import io.papermc.paper.adventure.AdventureCodecs import io.papermc.paper.adventure.PaperAdventure +import io.papermc.paper.network.ChannelInitializeListenerHolder import net.kyori.adventure.text.Component import net.kyori.adventure.text.TextReplacementConfig import net.kyori.adventure.translation.GlobalTranslator -import net.minecraft.nbt.NbtAccounter -import net.minecraft.nbt.NbtOps -import net.minecraft.nbt.Tag -import net.minecraft.network.RegistryFriendlyByteBuf -import net.minecraft.network.chat.ComponentSerialization -import net.minecraft.network.codec.ByteBufCodecs -import net.minecraft.network.codec.StreamCodec -import java.lang.reflect.Field -import java.lang.reflect.Modifier +import net.minecraft.network.Connection +import net.minecraft.network.protocol.common.ServerboundResourcePackPacket +import net.minecraft.network.protocol.configuration.ClientboundFinishConfigurationPacket +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket +import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket +import org.bukkit.NamespacedKey import java.util.* -import java.util.function.Supplier class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { @@ -46,6 +42,38 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { { component -> GlobalTranslator.render(component.transformEmotes(), locale) } // encode ) } + + val key = NamespacedKey.fromString("configuration_listener", emojy) + ChannelInitializeListenerHolder.addListener(key!!) { channel: Channel -> + channel.pipeline().addBefore("packet_handler", key.toString(), object : ChannelDuplexHandler() { + private val connection = channel.pipeline()["packet_handler"] as Connection + + override fun write(ctx: ChannelHandlerContext, packet: Any, promise: ChannelPromise) { + ctx.write( + when (packet) { + is ClientboundSetTitleTextPacket -> ClientboundSetTitleTextPacket(packet.text.transformEmotes()) + is ClientboundSetSubtitleTextPacket -> ClientboundSetSubtitleTextPacket(packet.text.transformEmotes()) + is ClientboundSetActionBarTextPacket -> ClientboundSetActionBarTextPacket(packet.text.transformEmotes()) + else -> packet + }, promise + ) + } + + /*override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { + if (msg is ServerboundResourcePackPacket && msg.id() == OraxenPlugin.get().packServer() + .packInfo().id() + ) { + if (!finishConfigPhase(msg.action())) return@addListener + ctx.pipeline() + .remove(this) // We no longer need to listen or process ClientboundFinishConfigurationPacket that we send ourselves + connection.send(ClientboundFinishConfigurationPacket.INSTANCE) + return@addListener + } + ctx.fireChannelRead(msg) + }*/ + } + ) + } } companion object { From 650b4ae5892f59126341193b501d24137c8783ba Mon Sep 17 00:00:00 2001 From: Boy Date: Wed, 29 May 2024 11:56:34 +0200 Subject: [PATCH 05/18] fix: space-ids not being transformed --- .../main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt | 2 +- .../mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt index c6de4e9..5e10083 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt @@ -15,7 +15,7 @@ import java.util.* fun Component.transform(player: Player?, insert: Boolean, unescape: Boolean = true) = player?.let { escapeEmoteIDs(it) } ?: transformEmoteIDs(player, insert, unescape) val legacy = LegacyComponentSerializer.legacySection() -private val spaceRegex: Regex = "(? + val space = match.groupValues[1].toIntOrNull() ?: return@forEach + val spaceRegex = "(? Date: Wed, 29 May 2024 11:57:16 +0200 Subject: [PATCH 06/18] fix: use packetlistener for inventory-titles & entity data --- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index cc1ae43..519b9f1 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -12,17 +12,16 @@ import io.netty.channel.ChannelDuplexHandler import io.netty.channel.ChannelHandlerContext import io.netty.channel.ChannelPromise import io.papermc.paper.adventure.AdventureCodecs +import io.papermc.paper.adventure.AdventureComponent import io.papermc.paper.adventure.PaperAdventure import io.papermc.paper.network.ChannelInitializeListenerHolder import net.kyori.adventure.text.Component import net.kyori.adventure.text.TextReplacementConfig import net.kyori.adventure.translation.GlobalTranslator import net.minecraft.network.Connection -import net.minecraft.network.protocol.common.ServerboundResourcePackPacket -import net.minecraft.network.protocol.configuration.ClientboundFinishConfigurationPacket -import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket -import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket -import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket +import net.minecraft.network.protocol.game.* +import net.minecraft.network.syncher.EntityDataSerializer +import net.minecraft.network.syncher.SynchedEntityData import org.bukkit.NamespacedKey import java.util.* @@ -54,6 +53,16 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { is ClientboundSetTitleTextPacket -> ClientboundSetTitleTextPacket(packet.text.transformEmotes()) is ClientboundSetSubtitleTextPacket -> ClientboundSetSubtitleTextPacket(packet.text.transformEmotes()) is ClientboundSetActionBarTextPacket -> ClientboundSetActionBarTextPacket(packet.text.transformEmotes()) + is ClientboundOpenScreenPacket -> ClientboundOpenScreenPacket(packet.containerId, packet.type, packet.title.transformEmotes()) + is ClientboundSetEntityDataPacket -> ClientboundSetEntityDataPacket(packet.id, packet.packedItems.map { + when (val value = it.value) { + is AdventureComponent -> + SynchedEntityData.DataValue(it.id, it.serializer as EntityDataSerializer, + AdventureComponent(PaperAdventure.asAdventure(value.transformEmotes())) + ) + else -> it + } + }) else -> packet }, promise ) From a4cf47acfdb238556d9681e3388c33d25ecca281 Mon Sep 17 00:00:00 2001 From: Boy Date: Wed, 29 May 2024 12:42:04 +0200 Subject: [PATCH 07/18] fix: signs formatting minimessage and emotes --- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index 519b9f1..9e43a70 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -4,7 +4,9 @@ package com.mineinabyss.emojy.nms.v1_20_R4 import com.mineinabyss.emojy.* import com.mineinabyss.emojy.nms.IEmojyNMSHandler +import com.mineinabyss.idofront.messaging.broadcastVal import com.mineinabyss.idofront.plugin.listeners +import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize import com.mojang.serialization.Codec import io.netty.channel.Channel @@ -18,10 +20,13 @@ import io.papermc.paper.network.ChannelInitializeListenerHolder import net.kyori.adventure.text.Component import net.kyori.adventure.text.TextReplacementConfig import net.kyori.adventure.translation.GlobalTranslator +import net.minecraft.nbt.ListTag +import net.minecraft.nbt.StringTag import net.minecraft.network.Connection import net.minecraft.network.protocol.game.* import net.minecraft.network.syncher.EntityDataSerializer import net.minecraft.network.syncher.SynchedEntityData +import net.minecraft.world.level.block.entity.BlockEntityType import org.bukkit.NamespacedKey import java.util.* @@ -42,27 +47,53 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { ) } - val key = NamespacedKey.fromString("configuration_listener", emojy) + val key = NamespacedKey.fromString("packet_listener", emojy) ChannelInitializeListenerHolder.addListener(key!!) { channel: Channel -> channel.pipeline().addBefore("packet_handler", key.toString(), object : ChannelDuplexHandler() { private val connection = channel.pipeline()["packet_handler"] as Connection override fun write(ctx: ChannelHandlerContext, packet: Any, promise: ChannelPromise) { + fun Connection.locale() = player.bukkitEntity.locale() ctx.write( when (packet) { - is ClientboundSetTitleTextPacket -> ClientboundSetTitleTextPacket(packet.text.transformEmotes()) - is ClientboundSetSubtitleTextPacket -> ClientboundSetSubtitleTextPacket(packet.text.transformEmotes()) - is ClientboundSetActionBarTextPacket -> ClientboundSetActionBarTextPacket(packet.text.transformEmotes()) - is ClientboundOpenScreenPacket -> ClientboundOpenScreenPacket(packet.containerId, packet.type, packet.title.transformEmotes()) + is ClientboundSetTitleTextPacket -> ClientboundSetTitleTextPacket(packet.text.transformEmotes(connection.locale())) + is ClientboundSetSubtitleTextPacket -> ClientboundSetSubtitleTextPacket(packet.text.transformEmotes(connection.locale())) + is ClientboundSetActionBarTextPacket -> ClientboundSetActionBarTextPacket(packet.text.transformEmotes(connection.locale())) + is ClientboundOpenScreenPacket -> ClientboundOpenScreenPacket(packet.containerId, packet.type, packet.title.transformEmotes(connection.locale())) is ClientboundSetEntityDataPacket -> ClientboundSetEntityDataPacket(packet.id, packet.packedItems.map { when (val value = it.value) { is AdventureComponent -> SynchedEntityData.DataValue(it.id, it.serializer as EntityDataSerializer, - AdventureComponent(PaperAdventure.asAdventure(value.transformEmotes())) + AdventureComponent(PaperAdventure.asAdventure(value).transformEmotes(connection.locale())) ) else -> it } }) + is ClientboundBlockEntityDataPacket -> when (packet.type) { + BlockEntityType.SIGN -> ClientboundBlockEntityDataPacket(packet.pos, packet.type, packet.tag.apply { + val locale = connection.locale() + val frontText = getCompound("front_text").apply { + put("messages", ListTag() + .apply { addAll(getList("messages", StringTag.TAG_STRING.toInt()) + .map { it.asString.drop(1).dropLast(1).miniMsg().transformEmotes(locale) } + .map { m -> StringTag.valueOf(PaperAdventure.asJsonString(m, locale)) }) + } + ) + } + val backText = getCompound("back_text").apply { + put("messages", ListTag() + .apply { addAll(getList("messages", StringTag.TAG_STRING.toInt()) + .map { it.asString.drop(1).dropLast(1).miniMsg().transformEmotes(locale) } + .map { m -> StringTag.valueOf(PaperAdventure.asJsonString(m, locale)) }) + } + ) + } + + put("front_text", frontText) + put("back_text", backText) + }) + else -> packet + } else -> packet }, promise ) @@ -87,12 +118,12 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { companion object { - fun net.minecraft.network.chat.Component.transformEmotes(): net.minecraft.network.chat.Component { - return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).transformEmotes()) + fun net.minecraft.network.chat.Component.transformEmotes(locale: Locale? = null): net.minecraft.network.chat.Component { + return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).transformEmotes(locale)) } - fun Component.transformEmotes(): Component { - var component = this + fun Component.transformEmotes(locale: Locale? = null): Component { + var component = GlobalTranslator.render(this, locale ?: Locale.US) val serialized = this.serialize() for (emote in emojy.emotes) emote.baseRegex.findAll(serialized).forEach { match -> From d065f503e4494d18c9274bbbe62a6963d44c3420 Mon Sep 17 00:00:00 2001 From: Boy Date: Wed, 29 May 2024 12:53:40 +0200 Subject: [PATCH 08/18] fix: tablist footer/header parsing emotes --- .../com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index 9e43a70..f608e05 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -4,7 +4,6 @@ package com.mineinabyss.emojy.nms.v1_20_R4 import com.mineinabyss.emojy.* import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.idofront.messaging.broadcastVal import com.mineinabyss.idofront.plugin.listeners import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize @@ -60,6 +59,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { is ClientboundSetSubtitleTextPacket -> ClientboundSetSubtitleTextPacket(packet.text.transformEmotes(connection.locale())) is ClientboundSetActionBarTextPacket -> ClientboundSetActionBarTextPacket(packet.text.transformEmotes(connection.locale())) is ClientboundOpenScreenPacket -> ClientboundOpenScreenPacket(packet.containerId, packet.type, packet.title.transformEmotes(connection.locale())) + is ClientboundTabListPacket -> ClientboundTabListPacket(packet.header.transformEmotes(connection.locale()), packet.footer.transformEmotes(connection.locale())) is ClientboundSetEntityDataPacket -> ClientboundSetEntityDataPacket(packet.id, packet.packedItems.map { when (val value = it.value) { is AdventureComponent -> From db27965f10e4bb708fcd8becee47b155f3fb16b4 Mon Sep 17 00:00:00 2001 From: Boy Date: Wed, 29 May 2024 13:08:28 +0200 Subject: [PATCH 09/18] fix: handle anvil renaming by escaping in client-sent RenameItem packet and transforming in server-side event --- .../emojy/nms/v1_20_R4/EmojyListener.kt | 14 ++----------- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 21 +++++++------------ 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt index f8697dc..da55aaf 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt @@ -2,24 +2,15 @@ package com.mineinabyss.emojy.nms.v1_20_R4 import com.mineinabyss.emojy.emojy import com.mineinabyss.emojy.escapeEmoteIDs -import com.mineinabyss.emojy.nms.EmojyNMSHandlers -import com.mineinabyss.emojy.transform +import com.mineinabyss.emojy.transformEmoteIDs import com.mineinabyss.idofront.items.editItemMeta -import com.mineinabyss.idofront.messaging.logError -import com.mineinabyss.idofront.messaging.logVal import com.mineinabyss.idofront.textcomponents.miniMsg -import com.mineinabyss.idofront.textcomponents.serialize import io.papermc.paper.event.player.AsyncChatDecorateEvent -import io.papermc.paper.event.player.AsyncChatEvent -import net.kyori.adventure.text.Component -import org.bukkit.Bukkit -import org.bukkit.entity.Player import org.bukkit.event.EventHandler import org.bukkit.event.EventPriority import org.bukkit.event.Listener import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.event.player.PlayerJoinEvent -import org.bukkit.inventory.AnvilInventory @Suppress("UnstableApiUsage") class EmojyListener : Listener { @@ -38,8 +29,7 @@ class EmojyListener : Listener { @EventHandler fun PrepareAnvilEvent.onAnvil() { if (result?.itemMeta?.hasDisplayName() != true) return - val inventory = inventory as? AnvilInventory ?: return - val displayName = ((inventory.renameText?.miniMsg() ?: inventory.firstItem?.itemMeta?.displayName())?.transform(inventory.viewers.firstOrNull() as? Player, false)) + val displayName = (inventory.renameText?.miniMsg() ?: inventory.firstItem?.itemMeta?.displayName())?.transformEmoteIDs(null, false, true) result = result?.editItemMeta { displayName(displayName) } diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index f608e05..a8d1ed0 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -4,6 +4,7 @@ package com.mineinabyss.emojy.nms.v1_20_R4 import com.mineinabyss.emojy.* import com.mineinabyss.emojy.nms.IEmojyNMSHandler +import com.mineinabyss.idofront.messaging.broadcastVal import com.mineinabyss.idofront.plugin.listeners import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize @@ -50,9 +51,9 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { ChannelInitializeListenerHolder.addListener(key!!) { channel: Channel -> channel.pipeline().addBefore("packet_handler", key.toString(), object : ChannelDuplexHandler() { private val connection = channel.pipeline()["packet_handler"] as Connection + fun Connection.locale() = player.bukkitEntity.locale() override fun write(ctx: ChannelHandlerContext, packet: Any, promise: ChannelPromise) { - fun Connection.locale() = player.bukkitEntity.locale() ctx.write( when (packet) { is ClientboundSetTitleTextPacket -> ClientboundSetTitleTextPacket(packet.text.transformEmotes(connection.locale())) @@ -99,18 +100,12 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { ) } - /*override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { - if (msg is ServerboundResourcePackPacket && msg.id() == OraxenPlugin.get().packServer() - .packInfo().id() - ) { - if (!finishConfigPhase(msg.action())) return@addListener - ctx.pipeline() - .remove(this) // We no longer need to listen or process ClientboundFinishConfigurationPacket that we send ourselves - connection.send(ClientboundFinishConfigurationPacket.INSTANCE) - return@addListener - } - ctx.fireChannelRead(msg) - }*/ + override fun channelRead(ctx: ChannelHandlerContext, packet: Any) { + ctx.fireChannelRead(when (packet) { + is ServerboundRenameItemPacket -> ServerboundRenameItemPacket(packet.name.broadcastVal().miniMsg().escapeEmoteIDs(connection.player.bukkitEntity).serialize()) + else -> packet + }) + } } ) } From 41947c7f8a9c1bb5f704e2db61e4e090b3093451 Mon Sep 17 00:00:00 2001 From: Boy Date: Wed, 29 May 2024 13:23:19 +0200 Subject: [PATCH 10/18] fix: more chat client events --- .../com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index a8d1ed0..92958c1 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -43,7 +43,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { for (locale in Locale.getAvailableLocales()) { codecs[locale] = AdventureCodecs.COMPONENT_CODEC.xmap( { component -> component }, // decode - { component -> GlobalTranslator.render(component.transformEmotes(), locale) } // encode + { component -> GlobalTranslator.render(component, locale) } // encode ) } @@ -56,6 +56,8 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { override fun write(ctx: ChannelHandlerContext, packet: Any, promise: ChannelPromise) { ctx.write( when (packet) { + is ClientboundDisguisedChatPacket -> ClientboundDisguisedChatPacket(packet.message.transformEmotes(connection.locale()), packet.chatType) + is ClientboundSystemChatPacket -> ClientboundSystemChatPacket(packet.content.transformEmotes(connection.locale()), packet.overlay) is ClientboundSetTitleTextPacket -> ClientboundSetTitleTextPacket(packet.text.transformEmotes(connection.locale())) is ClientboundSetSubtitleTextPacket -> ClientboundSetSubtitleTextPacket(packet.text.transformEmotes(connection.locale())) is ClientboundSetActionBarTextPacket -> ClientboundSetActionBarTextPacket(packet.text.transformEmotes(connection.locale())) @@ -103,6 +105,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { override fun channelRead(ctx: ChannelHandlerContext, packet: Any) { ctx.fireChannelRead(when (packet) { is ServerboundRenameItemPacket -> ServerboundRenameItemPacket(packet.name.broadcastVal().miniMsg().escapeEmoteIDs(connection.player.bukkitEntity).serialize()) + is ServerboundChatPacket -> ServerboundChatPacket(packet.message, packet.timeStamp, packet.salt, packet.signature, packet.lastSeenMessages) else -> packet }) } From 3f226bd39a532e734f2b6b5196b5bcaa92ed6cbd Mon Sep 17 00:00:00 2001 From: Boy Date: Wed, 29 May 2024 17:20:55 +0200 Subject: [PATCH 11/18] fix: sign handling moved to events --- build.gradle.kts | 8 ++ .../mineinabyss/emojy/nms/IEmojyNMSHandler.kt | 7 -- .../emojy/nms/v1_20_R4/EmojyListener.kt | 57 ++++++++- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 115 ++++++++++++------ 4 files changed, 135 insertions(+), 52 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9c001fe..ca8ac41 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,8 +22,13 @@ allprojects { repositories { maven("https://repo.mineinabyss.com/releases") maven("https://repo.mineinabyss.com/snapshots") + maven("https://hub.jeff-media.com/nexus/repository/jeff-media-public/") mavenLocal() } + + dependencies { + implementation("com.jeff_media:MorePersistentDataTypes:2.4.0") + } } dependencies { @@ -78,6 +83,9 @@ tasks { //dependsOn(":v1_20_R2:reobfJar") //dependsOn(":v1_20_R3:reobfJar") dependsOn(":v1_20_R4:reobfJar") + + //relocate("com.jeff_media.morepersistentdatatypes", "com.mineinabyss.shaded.morepersistentdatatypes") + archiveFileName.set("Emojy.jar") } diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/nms/IEmojyNMSHandler.kt b/core/src/main/kotlin/com/mineinabyss/emojy/nms/IEmojyNMSHandler.kt index 7d03dca..961e8c8 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/nms/IEmojyNMSHandler.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/nms/IEmojyNMSHandler.kt @@ -1,13 +1,6 @@ package com.mineinabyss.emojy.nms -import org.bukkit.entity.Player -import java.util.Locale - interface IEmojyNMSHandler { - val locals: MutableSet - - fun addLocaleCodec(locale: Locale) {} - val supported get() = false } diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt index da55aaf..ba564c7 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt @@ -1,31 +1,76 @@ package com.mineinabyss.emojy.nms.v1_20_R4 +import com.github.shynixn.mccoroutine.bukkit.launch +import com.github.shynixn.mccoroutine.bukkit.ticks +import com.jeff_media.morepersistentdatatypes.DataType import com.mineinabyss.emojy.emojy import com.mineinabyss.emojy.escapeEmoteIDs +import com.mineinabyss.emojy.nms.v1_20_R4.EmojyNMSHandler.Companion.transformEmotes import com.mineinabyss.emojy.transformEmoteIDs import com.mineinabyss.idofront.items.editItemMeta import com.mineinabyss.idofront.textcomponents.miniMsg +import com.mineinabyss.idofront.textcomponents.serialize import io.papermc.paper.event.player.AsyncChatDecorateEvent +import io.papermc.paper.event.player.PlayerOpenSignEvent +import kotlinx.coroutines.delay +import net.minecraft.core.BlockPos +import net.minecraft.world.level.block.entity.BlockEntityType +import org.bukkit.block.Sign +import org.bukkit.block.sign.Side +import org.bukkit.craftbukkit.entity.CraftPlayer import org.bukkit.event.EventHandler import org.bukkit.event.EventPriority import org.bukkit.event.Listener +import org.bukkit.event.block.SignChangeEvent import org.bukkit.event.inventory.PrepareAnvilEvent -import org.bukkit.event.player.PlayerJoinEvent @Suppress("UnstableApiUsage") class EmojyListener : Listener { - @EventHandler - fun PlayerJoinEvent.onJoin() { - emojy.handler.addLocaleCodec(player.locale()) - } - // Replace with result not original message to avoid borking other chat formatting @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) fun AsyncChatDecorateEvent.onPlayerChat() { result(result().escapeEmoteIDs(player())) } + @EventHandler + fun SignChangeEvent.onSign() { + val state = (block.state as Sign) + val type = DataType.asList(DataType.STRING) + val sideLines = lines().map { it.serialize() }.toList() + val frontLines = if (side == Side.FRONT) sideLines else state.persistentDataContainer.getOrDefault(EmojyNMSHandler.ORIGINAL_SIGN_FRONT_LINES, type, mutableListOf("", "", "", "")) + val backLines = if (side == Side.BACK) sideLines else state.persistentDataContainer.getOrDefault(EmojyNMSHandler.ORIGINAL_SIGN_BACK_LINES, type, mutableListOf("", "", "", "")) + + state.persistentDataContainer.set(EmojyNMSHandler.ORIGINAL_SIGN_FRONT_LINES, type, frontLines) + state.persistentDataContainer.set(EmojyNMSHandler.ORIGINAL_SIGN_BACK_LINES, type, backLines) + state.update(true) + + lines().forEachIndexed { index, s -> + line(index, s?.escapeEmoteIDs(player)?.transformEmotes()) + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + fun PlayerOpenSignEvent.onSignEdit() { + if (cause == PlayerOpenSignEvent.Cause.PLACE) return + + sign.persistentDataContainer.get(when (sign.getInteractableSideFor(player)) { + Side.FRONT -> EmojyNMSHandler.ORIGINAL_SIGN_FRONT_LINES + Side.BACK -> EmojyNMSHandler.ORIGINAL_SIGN_BACK_LINES + }, DataType.asList(DataType.STRING))?.forEachIndexed { index, s -> + sign.getSide(side).line(index, s.miniMsg()) + } + sign.update(true) + isCancelled = true + emojy.plugin.launch { + delay(2.ticks) + (player as CraftPlayer).handle.level().getBlockEntity(BlockPos(sign.x, sign.y, sign.z), BlockEntityType.SIGN).ifPresent { + it.setAllowedPlayerEditor(player.uniqueId) + (player as CraftPlayer).handle.openTextEdit(it, side == Side.FRONT) + } + } + } + @EventHandler fun PrepareAnvilEvent.onAnvil() { if (result?.itemMeta?.hasDisplayName() != true) return diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index 92958c1..2a7a9d1 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -3,8 +3,8 @@ package com.mineinabyss.emojy.nms.v1_20_R4 import com.mineinabyss.emojy.* +import com.mineinabyss.emojy.config.SPACE_PERMISSION import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.idofront.messaging.broadcastVal import com.mineinabyss.idofront.plugin.listeners import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize @@ -17,22 +17,20 @@ import io.papermc.paper.adventure.AdventureCodecs import io.papermc.paper.adventure.AdventureComponent import io.papermc.paper.adventure.PaperAdventure import io.papermc.paper.network.ChannelInitializeListenerHolder +import net.kyori.adventure.key.Key import net.kyori.adventure.text.Component import net.kyori.adventure.text.TextReplacementConfig import net.kyori.adventure.translation.GlobalTranslator -import net.minecraft.nbt.ListTag -import net.minecraft.nbt.StringTag import net.minecraft.network.Connection import net.minecraft.network.protocol.game.* import net.minecraft.network.syncher.EntityDataSerializer import net.minecraft.network.syncher.SynchedEntityData -import net.minecraft.world.level.block.entity.BlockEntityType import org.bukkit.NamespacedKey +import org.bukkit.entity.Player import java.util.* class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { - override val locals: MutableSet = mutableSetOf() init { emojy.listeners(EmojyListener()) @@ -64,39 +62,12 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { is ClientboundOpenScreenPacket -> ClientboundOpenScreenPacket(packet.containerId, packet.type, packet.title.transformEmotes(connection.locale())) is ClientboundTabListPacket -> ClientboundTabListPacket(packet.header.transformEmotes(connection.locale()), packet.footer.transformEmotes(connection.locale())) is ClientboundSetEntityDataPacket -> ClientboundSetEntityDataPacket(packet.id, packet.packedItems.map { - when (val value = it.value) { - is AdventureComponent -> - SynchedEntityData.DataValue(it.id, it.serializer as EntityDataSerializer, - AdventureComponent(PaperAdventure.asAdventure(value).transformEmotes(connection.locale())) - ) - else -> it - } + (it.value as? AdventureComponent)?.let { value -> + SynchedEntityData.DataValue(it.id, it.serializer as EntityDataSerializer, + AdventureComponent(PaperAdventure.asAdventure(value).transformEmotes(connection.locale())) + ) + } ?: it }) - is ClientboundBlockEntityDataPacket -> when (packet.type) { - BlockEntityType.SIGN -> ClientboundBlockEntityDataPacket(packet.pos, packet.type, packet.tag.apply { - val locale = connection.locale() - val frontText = getCompound("front_text").apply { - put("messages", ListTag() - .apply { addAll(getList("messages", StringTag.TAG_STRING.toInt()) - .map { it.asString.drop(1).dropLast(1).miniMsg().transformEmotes(locale) } - .map { m -> StringTag.valueOf(PaperAdventure.asJsonString(m, locale)) }) - } - ) - } - val backText = getCompound("back_text").apply { - put("messages", ListTag() - .apply { addAll(getList("messages", StringTag.TAG_STRING.toInt()) - .map { it.asString.drop(1).dropLast(1).miniMsg().transformEmotes(locale) } - .map { m -> StringTag.valueOf(PaperAdventure.asJsonString(m, locale)) }) - } - ) - } - - put("front_text", frontText) - put("back_text", backText) - }) - else -> packet - } else -> packet }, promise ) @@ -104,8 +75,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { override fun channelRead(ctx: ChannelHandlerContext, packet: Any) { ctx.fireChannelRead(when (packet) { - is ServerboundRenameItemPacket -> ServerboundRenameItemPacket(packet.name.broadcastVal().miniMsg().escapeEmoteIDs(connection.player.bukkitEntity).serialize()) - is ServerboundChatPacket -> ServerboundChatPacket(packet.message, packet.timeStamp, packet.salt, packet.signature, packet.lastSeenMessages) + is ServerboundRenameItemPacket -> ServerboundRenameItemPacket(packet.name.escapeEmoteIDs(connection.player.bukkitEntity)) else -> packet }) } @@ -116,6 +86,73 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { companion object { + val ORIGINAL_SIGN_FRONT_LINES = NamespacedKey.fromString("emojy:original_front_lines")!! + val ORIGINAL_SIGN_BACK_LINES = NamespacedKey.fromString("emojy:original_back_lines")!! + + fun String.escapeEmoteIDs(player: Player?): String { + return miniMsg().escapeEmoteIDs(player).serialize() + } + + fun net.minecraft.network.chat.Component.escapeEmoteIDs(player: Player?): net.minecraft.network.chat.Component { + return PaperAdventure.asVanilla((PaperAdventure.asAdventure(this)).escapeEmoteIDs(player)) + } + + fun Component.escapeEmoteIDs(player: Player?): Component { + var msg = this + val serialized = msg.serialize() + + // Replace all unicodes found in default font with a random one + // This is to prevent use of unicodes from the font the chat is in + val (defaultKey, randomKey) = Key.key("default") to Key.key("random") + for (emote in emojy.emotes.filter { it.font == defaultKey && !it.checkPermission(player) }) emote.unicodes.forEach { + msg = msg.replaceText( + TextReplacementConfig.builder() + .matchLiteral(it) + .replacement(it.miniMsg().font(randomKey)) + .build() + ) + } + + for (emote in emojy.emotes) emote.baseRegex.findAll(serialized).forEach { match -> + if (emote.checkPermission(player)) return@forEach + + msg = msg.replaceText( + TextReplacementConfig.builder() + .matchLiteral(match.value).once() + .replacement("\\${match.value}".miniMsg()) + .build() + ) + } + + for (gif in emojy.gifs) gif.baseRegex.findAll(serialized).forEach { match -> + if (gif.checkPermission(player)) return@forEach + msg = msg.replaceText( + TextReplacementConfig.builder() + .matchLiteral(match.value).once() + .replacement("\\${match.value}".miniMsg()) + .build() + ) + } + + spaceRegex.findAll(serialized).forEach { match -> + if (player?.hasPermission(SPACE_PERMISSION) != false) return@forEach + val space = match.groupValues[1].toIntOrNull() ?: return@forEach + + msg = msg.replaceText( + TextReplacementConfig.builder() + .matchLiteral(match.value).once() + .replacement("\\:space_$space:".miniMsg()) + .build() + ) + } + + return msg + } + + fun String.transformEmotes(locale: Locale? = null): String { + return miniMsg().transformEmotes(locale).serialize() + } + fun net.minecraft.network.chat.Component.transformEmotes(locale: Locale? = null): net.minecraft.network.chat.Component { return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).transformEmotes(locale)) } From 717fdf2997a874200d17f90544389cec383666be Mon Sep 17 00:00:00 2001 From: Boy Date: Wed, 29 May 2024 19:50:53 +0200 Subject: [PATCH 12/18] fix: anvil renaming storing original rename name for next rename --- .../emojy/nms/v1_20_R4/EmojyListener.kt | 13 +++++++++++-- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt index ba564c7..a05cd2a 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt @@ -5,6 +5,7 @@ import com.github.shynixn.mccoroutine.bukkit.ticks import com.jeff_media.morepersistentdatatypes.DataType import com.mineinabyss.emojy.emojy import com.mineinabyss.emojy.escapeEmoteIDs +import com.mineinabyss.emojy.nms.v1_20_R4.EmojyNMSHandler.Companion.ORIGINAL_ITEM_RENAME_TEXT import com.mineinabyss.emojy.nms.v1_20_R4.EmojyNMSHandler.Companion.transformEmotes import com.mineinabyss.emojy.transformEmoteIDs import com.mineinabyss.idofront.items.editItemMeta @@ -73,9 +74,17 @@ class EmojyListener : Listener { @EventHandler fun PrepareAnvilEvent.onAnvil() { - if (result?.itemMeta?.hasDisplayName() != true) return - val displayName = (inventory.renameText?.miniMsg() ?: inventory.firstItem?.itemMeta?.displayName())?.transformEmoteIDs(null, false, true) + if (result?.itemMeta?.hasDisplayName() != true || inventory.renameText == null) { + result?.editItemMeta { persistentDataContainer.remove(ORIGINAL_ITEM_RENAME_TEXT) } + return + } + val displayName = inventory.renameText?.miniMsg()?.transformEmoteIDs(null, false, true) ?: run { + result?.editItemMeta { persistentDataContainer.remove(ORIGINAL_ITEM_RENAME_TEXT) } + return + } + result = result?.editItemMeta { + persistentDataContainer.set(ORIGINAL_ITEM_RENAME_TEXT, DataType.STRING, inventory.renameText!!) displayName(displayName) } } diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index 2a7a9d1..65639e3 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -2,9 +2,11 @@ package com.mineinabyss.emojy.nms.v1_20_R4 +import com.jeff_media.morepersistentdatatypes.DataType import com.mineinabyss.emojy.* import com.mineinabyss.emojy.config.SPACE_PERMISSION import com.mineinabyss.emojy.nms.IEmojyNMSHandler +import com.mineinabyss.idofront.items.editItemMeta import com.mineinabyss.idofront.plugin.listeners import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize @@ -21,12 +23,15 @@ import net.kyori.adventure.key.Key import net.kyori.adventure.text.Component import net.kyori.adventure.text.TextReplacementConfig import net.kyori.adventure.translation.GlobalTranslator +import net.minecraft.core.NonNullList import net.minecraft.network.Connection import net.minecraft.network.protocol.game.* import net.minecraft.network.syncher.EntityDataSerializer import net.minecraft.network.syncher.SynchedEntityData import org.bukkit.NamespacedKey +import org.bukkit.craftbukkit.inventory.CraftItemStack import org.bukkit.entity.Player +import org.bukkit.inventory.AnvilInventory import java.util.* class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { @@ -68,6 +73,16 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { ) } ?: it }) + is ClientboundContainerSetContentPacket -> { + (connection.player.bukkitEntity.openInventory.topInventory as? AnvilInventory)?.let { + ClientboundContainerSetContentPacket(packet.containerId, packet.stateId, + NonNullList.of(packet.items.first(), *packet.items.map { + CraftItemStack.asNMSCopy(CraftItemStack.asBukkitCopy(it.copy()).editItemMeta { + setDisplayName(persistentDataContainer.get(ORIGINAL_ITEM_RENAME_TEXT, DataType.STRING) ?: return@editItemMeta) + }) + }.toTypedArray()), packet.carriedItem) + } ?: packet + } else -> packet }, promise ) @@ -88,6 +103,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { val ORIGINAL_SIGN_FRONT_LINES = NamespacedKey.fromString("emojy:original_front_lines")!! val ORIGINAL_SIGN_BACK_LINES = NamespacedKey.fromString("emojy:original_back_lines")!! + val ORIGINAL_ITEM_RENAME_TEXT = NamespacedKey.fromString("emojy:original_item_rename")!! fun String.escapeEmoteIDs(player: Player?): String { return miniMsg().escapeEmoteIDs(player).serialize() From 1c820a37a4f3f40a6e27b5c27f35219caed3c685 Mon Sep 17 00:00:00 2001 From: Boy Date: Wed, 29 May 2024 21:37:22 +0200 Subject: [PATCH 13/18] fix: properly unescape escaped emoteids --- .../com/mineinabyss/emojy/EmojyHelpers.kt | 2 +- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 118 ++++++++++++------ 2 files changed, 79 insertions(+), 41 deletions(-) diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt index 5e10083..055b78b 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt @@ -16,7 +16,7 @@ fun Component.transform(player: Player?, insert: Boolean, unescape: Boolean = tr val legacy = LegacyComponentSerializer.legacySection() val spaceRegex: Regex = "(?>) - for (locale in Locale.getAvailableLocales()) { + /*for (locale in Locale.getAvailableLocales()) { codecs[locale] = AdventureCodecs.COMPONENT_CODEC.xmap( { component -> component }, // decode { component -> GlobalTranslator.render(component, locale) } // encode ) - } + }*/ val key = NamespacedKey.fromString("packet_listener", emojy) ChannelInitializeListenerHolder.addListener(key!!) { channel: Channel -> @@ -59,8 +59,8 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { override fun write(ctx: ChannelHandlerContext, packet: Any, promise: ChannelPromise) { ctx.write( when (packet) { - is ClientboundDisguisedChatPacket -> ClientboundDisguisedChatPacket(packet.message.transformEmotes(connection.locale()), packet.chatType) - is ClientboundSystemChatPacket -> ClientboundSystemChatPacket(packet.content.transformEmotes(connection.locale()), packet.overlay) + is ClientboundDisguisedChatPacket -> ClientboundDisguisedChatPacket(packet.message.transformEmotes(connection.locale()).unescapeEmoteIds(), packet.chatType) + is ClientboundSystemChatPacket -> ClientboundSystemChatPacket(packet.content.transformEmotes(connection.locale()).unescapeEmoteIds(), packet.overlay) is ClientboundSetTitleTextPacket -> ClientboundSetTitleTextPacket(packet.text.transformEmotes(connection.locale())) is ClientboundSetSubtitleTextPacket -> ClientboundSetSubtitleTextPacket(packet.text.transformEmotes(connection.locale())) is ClientboundSetActionBarTextPacket -> ClientboundSetActionBarTextPacket(packet.text.transformEmotes(connection.locale())) @@ -105,6 +105,60 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { val ORIGINAL_SIGN_BACK_LINES = NamespacedKey.fromString("emojy:original_back_lines")!! val ORIGINAL_ITEM_RENAME_TEXT = NamespacedKey.fromString("emojy:original_item_rename")!! + fun String.transformEmotes(locale: Locale? = null): String { + return miniMsg().transformEmotes(locale).serialize() + } + + fun net.minecraft.network.chat.Component.transformEmotes(locale: Locale? = null): net.minecraft.network.chat.Component { + return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).transformEmotes(locale)) + } + + fun Component.transformEmotes(locale: Locale? = null): Component { + var component = GlobalTranslator.render(this, locale ?: Locale.US) + val serialized = this.serialize() + + for (emote in emojy.emotes) emote.baseRegex.findAll(serialized).forEach { match -> + + val colorable = colorableRegex in match.value + val bitmapIndex = bitmapIndexRegex.find(match.value)?.groupValues?.get(1)?.toIntOrNull() ?: -1 + + component = component.replaceText( + TextReplacementConfig.builder() + .match(emote.baseRegex.pattern).once() + .replacement( + emote.formattedUnicode( + insert = false, + colorable = colorable, + bitmapIndex = bitmapIndex + ) + ) + .build() + ) + } + + for (gif in emojy.gifs) gif.baseRegex.findAll(serialized).forEach { _ -> + component = component.replaceText( + TextReplacementConfig.builder() + .match(gif.baseRegex.pattern).once() + .replacement(gif.formattedUnicode(insert = false)) + .build() + ) + } + + spaceRegex.findAll(serialized).forEach { match -> + val space = match.groupValues[1].toIntOrNull() ?: return@forEach + val spaceRegex = "(? if (emote.checkPermission(player)) return@forEach - msg = msg.replaceText( + component = component.replaceText( TextReplacementConfig.builder() .matchLiteral(match.value).once() .replacement("\\${match.value}".miniMsg()) @@ -142,7 +196,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { for (gif in emojy.gifs) gif.baseRegex.findAll(serialized).forEach { match -> if (gif.checkPermission(player)) return@forEach - msg = msg.replaceText( + component = component.replaceText( TextReplacementConfig.builder() .matchLiteral(match.value).once() .replacement("\\${match.value}".miniMsg()) @@ -154,7 +208,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { if (player?.hasPermission(SPACE_PERMISSION) != false) return@forEach val space = match.groupValues[1].toIntOrNull() ?: return@forEach - msg = msg.replaceText( + component = component.replaceText( TextReplacementConfig.builder() .matchLiteral(match.value).once() .replacement("\\:space_$space:".miniMsg()) @@ -162,56 +216,40 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { ) } - return msg - } - - fun String.transformEmotes(locale: Locale? = null): String { - return miniMsg().transformEmotes(locale).serialize() + return component } - fun net.minecraft.network.chat.Component.transformEmotes(locale: Locale? = null): net.minecraft.network.chat.Component { - return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).transformEmotes(locale)) + fun net.minecraft.network.chat.Component.unescapeEmoteIds(): net.minecraft.network.chat.Component { + return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).unescapeEmoteIds()) } - fun Component.transformEmotes(locale: Locale? = null): Component { - var component = GlobalTranslator.render(this, locale ?: Locale.US) + fun Component.unescapeEmoteIds(): Component { + var component = this val serialized = this.serialize() - for (emote in emojy.emotes) emote.baseRegex.findAll(serialized).forEach { match -> - - val colorable = colorableRegex in match.value - val bitmapIndex = bitmapIndexRegex.find(match.value)?.groupValues?.get(1)?.toIntOrNull() ?: -1 - + for (emote in emojy.emotes) emote.escapedRegex.findAll(serialized).forEach { match -> component = component.replaceText( TextReplacementConfig.builder() - .match(emote.baseRegex.pattern).once() - .replacement( - emote.formattedUnicode( - insert = false, - colorable = colorable, - bitmapIndex = bitmapIndex - ) - ) + .match(emote.escapedRegex.pattern).once() + .replacement(match.value.removePrefix("\\")) .build() ) } - for (gif in emojy.gifs) gif.baseRegex.findAll(serialized).forEach { _ -> + for (gif in emojy.gifs) gif.escapedRegex.findAll(serialized).forEach { match -> component = component.replaceText( TextReplacementConfig.builder() - .match(gif.baseRegex.pattern).once() - .replacement(gif.formattedUnicode(insert = false)) + .match(gif.escapedRegex.pattern).once() + .replacement(match.value.removePrefix("\\")) .build() ) } - spaceRegex.findAll(serialized).forEach { match -> - val space = match.groupValues[1].toIntOrNull() ?: return@forEach - val spaceRegex = "(? component = component.replaceText( TextReplacementConfig.builder() - .match(spaceRegex.pattern).once() - .replacement(spaceComponent(space)) + .match(match.value).once() + .replacement(match.value.removePrefix("\\")) .build() ) } From dea5286c408d15d0af1fdae683184976238e31e1 Mon Sep 17 00:00:00 2001 From: Boy Date: Thu, 30 May 2024 10:40:02 +0200 Subject: [PATCH 14/18] chore: bump idofront --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7906906..e14b3ee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ group=com.mineinabyss version=0.9 -idofrontVersion=0.24.0-dev.10 +idofrontVersion=0.24.0 From 5365a74703356dba2e2d79efa19f490ccff52894 Mon Sep 17 00:00:00 2001 From: Boy Date: Thu, 30 May 2024 10:48:59 +0200 Subject: [PATCH 15/18] fix: emotes in chat not containing inserts --- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index 3087ec4..d5660ff 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -59,8 +59,8 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { override fun write(ctx: ChannelHandlerContext, packet: Any, promise: ChannelPromise) { ctx.write( when (packet) { - is ClientboundDisguisedChatPacket -> ClientboundDisguisedChatPacket(packet.message.transformEmotes(connection.locale()).unescapeEmoteIds(), packet.chatType) - is ClientboundSystemChatPacket -> ClientboundSystemChatPacket(packet.content.transformEmotes(connection.locale()).unescapeEmoteIds(), packet.overlay) + is ClientboundDisguisedChatPacket -> ClientboundDisguisedChatPacket(packet.message.transformEmotes(connection.locale(), true).unescapeEmoteIds(), packet.chatType) + is ClientboundSystemChatPacket -> ClientboundSystemChatPacket(packet.content.transformEmotes(connection.locale(), true).unescapeEmoteIds(), packet.overlay) is ClientboundSetTitleTextPacket -> ClientboundSetTitleTextPacket(packet.text.transformEmotes(connection.locale())) is ClientboundSetSubtitleTextPacket -> ClientboundSetSubtitleTextPacket(packet.text.transformEmotes(connection.locale())) is ClientboundSetActionBarTextPacket -> ClientboundSetActionBarTextPacket(packet.text.transformEmotes(connection.locale())) @@ -105,15 +105,15 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { val ORIGINAL_SIGN_BACK_LINES = NamespacedKey.fromString("emojy:original_back_lines")!! val ORIGINAL_ITEM_RENAME_TEXT = NamespacedKey.fromString("emojy:original_item_rename")!! - fun String.transformEmotes(locale: Locale? = null): String { - return miniMsg().transformEmotes(locale).serialize() + fun String.transformEmotes(locale: Locale? = null, insert: Boolean = false): String { + return miniMsg().transformEmotes(locale, insert).serialize() } - fun net.minecraft.network.chat.Component.transformEmotes(locale: Locale? = null): net.minecraft.network.chat.Component { - return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).transformEmotes(locale)) + fun net.minecraft.network.chat.Component.transformEmotes(locale: Locale? = null, insert: Boolean = false): net.minecraft.network.chat.Component { + return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).transformEmotes(locale, insert)) } - fun Component.transformEmotes(locale: Locale? = null): Component { + fun Component.transformEmotes(locale: Locale? = null, insert: Boolean = false): Component { var component = GlobalTranslator.render(this, locale ?: Locale.US) val serialized = this.serialize() @@ -127,7 +127,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { .match(emote.baseRegex.pattern).once() .replacement( emote.formattedUnicode( - insert = false, + insert = insert, colorable = colorable, bitmapIndex = bitmapIndex ) From f36eb7ca537329f074a874d744d3ab4acbda2972 Mon Sep 17 00:00:00 2001 From: Boy Date: Thu, 30 May 2024 11:12:53 +0200 Subject: [PATCH 16/18] refactor: remove old version impl --- build.gradle.kts | 14 +- v1_19_R1/build.gradle.kts | 44 --- .../emojy/nms/v1_19_R1/EmojyNMSHandler.kt | 247 ---------------- v1_19_R2/build.gradle.kts | 44 --- .../emojy/nms/v1_19_R2/EmojyNMSHandler.kt | 249 ----------------- v1_19_R3/build.gradle.kts | 44 --- .../emojy/nms/v1_19_R3/EmojyNMSHandler.kt | 264 ------------------ v1_20_R1/build.gradle.kts | 44 --- .../emojy/nms/v1_20_R1/EmojyNMSHandler.kt | 239 ---------------- v1_20_R2/build.gradle.kts | 44 --- .../emojy/nms/v1_20_R2/EmojyNMSHandler.kt | 251 ----------------- v1_20_R3/build.gradle.kts | 44 --- .../emojy/nms/v1_20_R3/EmojyNMSHandler.kt | 258 ----------------- 13 files changed, 1 insertion(+), 1785 deletions(-) delete mode 100644 v1_19_R1/build.gradle.kts delete mode 100644 v1_19_R1/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R1/EmojyNMSHandler.kt delete mode 100644 v1_19_R2/build.gradle.kts delete mode 100644 v1_19_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R2/EmojyNMSHandler.kt delete mode 100644 v1_19_R3/build.gradle.kts delete mode 100644 v1_19_R3/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R3/EmojyNMSHandler.kt delete mode 100644 v1_20_R1/build.gradle.kts delete mode 100644 v1_20_R1/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R1/EmojyNMSHandler.kt delete mode 100644 v1_20_R2/build.gradle.kts delete mode 100644 v1_20_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R2/EmojyNMSHandler.kt delete mode 100644 v1_20_R3/build.gradle.kts delete mode 100644 v1_20_R3/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R3/EmojyNMSHandler.kt diff --git a/build.gradle.kts b/build.gradle.kts index ca8ac41..23ed2f3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -42,12 +42,6 @@ dependencies { // Shaded paperweight.paperDevBundle("1.20.6-R0.1-SNAPSHOT") //NMS implementation(project(path = ":core")) - //implementation(project(path = ":v1_19_R1", configuration = "reobf")) - //implementation(project(path = ":v1_19_R2", configuration = "reobf")) - //implementation(project(path = ":v1_19_R3", configuration = "reobf")) - //implementation(project(path = ":v1_20_R1", configuration = "reobf")) - //implementation(project(path = ":v1_20_R2", configuration = "reobf")) - //implementation(project(path = ":v1_20_R3", configuration = "reobf")) implementation(project(path = ":v1_20_R4")) } @@ -76,15 +70,9 @@ tasks { } shadowJar { - //dependsOn(":v1_19_R1:reobfJar") - //dependsOn(":v1_19_R2:reobfJar") - //dependsOn(":v1_19_R3:reobfJar") - //dependsOn(":v1_20_R1:reobfJar") - //dependsOn(":v1_20_R2:reobfJar") - //dependsOn(":v1_20_R3:reobfJar") dependsOn(":v1_20_R4:reobfJar") - //relocate("com.jeff_media.morepersistentdatatypes", "com.mineinabyss.shaded.morepersistentdatatypes") + relocate("com.jeff_media.morepersistentdatatypes", "com.mineinabyss.shaded.morepersistentdatatypes") archiveFileName.set("Emojy.jar") } diff --git a/v1_19_R1/build.gradle.kts b/v1_19_R1/build.gradle.kts deleted file mode 100644 index 4641baa..0000000 --- a/v1_19_R1/build.gradle.kts +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id("com.mineinabyss.conventions.kotlin.jvm") - id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.7.1" -} - -repositories { - gradlePluginPortal() - maven("https://repo.mineinabyss.com/releases") - maven("https://repo.mineinabyss.com/snapshots") - maven("https://repo.papermc.io/repository/maven-public/") - google() -} - -dependencies { - // MineInAbyss platform - compileOnly(idofrontLibs.kotlinx.serialization.json) - compileOnly(idofrontLibs.kotlinx.serialization.kaml) - compileOnly(idofrontLibs.kotlinx.coroutines) - compileOnly(idofrontLibs.minecraft.mccoroutine) - - // Shaded - implementation(idofrontLibs.bundles.idofront.core) - implementation(project(":core")) - paperweight.paperDevBundle("1.19.2-R0.1-SNAPSHOT") //NMS -} - -tasks { - - build { - dependsOn(reobfJar) - } - - compileJava { - options.encoding = Charsets.UTF_8.name() - options.release.set(21) - } - javadoc { - options.encoding = Charsets.UTF_8.name() - } - processResources { - filteringCharset = Charsets.UTF_8.name() - } -} diff --git a/v1_19_R1/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R1/EmojyNMSHandler.kt b/v1_19_R1/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R1/EmojyNMSHandler.kt deleted file mode 100644 index ba16ce9..0000000 --- a/v1_19_R1/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R1/EmojyNMSHandler.kt +++ /dev/null @@ -1,247 +0,0 @@ -@file:Suppress("unused") - -package com.mineinabyss.emojy.nms.v1_19_R1 - -import com.github.shynixn.mccoroutine.bukkit.launch -import com.github.shynixn.mccoroutine.bukkit.minecraftDispatcher -import com.google.gson.JsonObject -import com.google.gson.JsonParser -import com.mineinabyss.emojy.emojy -import com.mineinabyss.emojy.legacy -import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.emojy.transform -import com.mineinabyss.idofront.textcomponents.miniMsg -import com.mineinabyss.idofront.textcomponents.serialize -import io.netty.buffer.ByteBuf -import io.netty.channel.* -import io.netty.handler.codec.ByteToMessageDecoder -import io.netty.handler.codec.MessageToByteEncoder -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.nbt.StringTag -import net.minecraft.network.* -import net.minecraft.network.protocol.Packet -import net.minecraft.network.protocol.PacketFlow -import net.minecraft.server.MinecraftServer -import net.minecraft.server.network.ServerConnectionListener -import org.bukkit.Bukkit -import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer -import org.bukkit.entity.Player -import java.io.IOException -import java.util.* -import java.util.function.Function - -class EmojyNMSHandler : IEmojyNMSHandler { - private val encoder = Collections.synchronizedMap(WeakHashMap()) - private val decoder = Collections.synchronizedMap(WeakHashMap()) - - @Suppress("unused", "UNCHECKED_CAST", "FunctionName") - fun EmojyNMSHandler() { - val connections: List = MinecraftServer.getServer().connection?.connections ?: emptyList() - // Have to set it accessible because unlike connections it is private - val channelFutures = ServerConnectionListener::class.java.getDeclaredField("f").apply { this.isAccessible = true; }.get(MinecraftServer.getServer().connection) as List - - - // Handle connected channels - val endInitProtocol: ChannelInitializer = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - try { - // This can take a while, so we need to stop the main thread from interfering - synchronized(connections) { - // Stop injecting channels - channel.eventLoop().submit { channel.inject() } - } - } catch (e: java.lang.Exception) { - e.printStackTrace() - } - } - } - - // Handle channels that are connecting - val beginInitProtocol = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - var handler: ChannelHandler? = null - - channel.pipeline().forEach { - if (it.value.javaClass.name == "com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer") { - handler = it.value as ChannelHandler - } - } - handler?.let { - val initChannel = ChannelInitializer::class.java.getDeclaredMethod("initChannel", Channel::class.java).apply { isAccessible = true } - val original = it.javaClass.getDeclaredField("original").apply { this.isAccessible = true } - val initializer = original.get(it) as ChannelInitializer<*> - val miniInit = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - initChannel.invoke(initializer, channel) - channel.eventLoop().submit { channel.inject() } - } - } - original.set(handler, miniInit) - } ?: channel.pipeline().addLast(endInitProtocol) - } - } - - val serverChannelHandler = object : ChannelInboundHandlerAdapter() { - override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { - (msg as Channel).pipeline().addFirst(beginInitProtocol) - ctx.fireChannelRead(msg) - } - } - - try { - bind(channelFutures, serverChannelHandler) - } catch (e: IllegalArgumentException) { - emojy.plugin.launch(emojy.plugin.minecraftDispatcher) { - bind(channelFutures, serverChannelHandler) - } - } - } - - private fun bind(channelFutures: List, serverChannelHandler: ChannelInboundHandlerAdapter) { - channelFutures.forEach { future -> future.channel().pipeline().addFirst(serverChannelHandler) } - Bukkit.getOnlinePlayers().forEach(::inject) - } - - private fun Channel.inject(player: Player? = null) { - if (this !in encoder.keys && this.pipeline().get("encoder") !is CustomPacketEncoder) - encoder[this] = this.pipeline().replace("encoder", "encoder", CustomPacketEncoder(player)) - - if (this !in decoder.keys && this.pipeline().get("decoder") !is CustomPacketDecoder) - decoder[this] = this.pipeline().replace("decoder", "decoder", CustomPacketDecoder(player)) - - } - - override fun inject(player: Player) { - val channel = (player as CraftPlayer).handle.connection.connection.channel ?: return - channel.eventLoop().submit { channel.inject(player) } - } - - override fun uninject(player: Player) { - (player as CraftPlayer).handle.connection.connection.channel.uninject() - } - - private fun Channel.uninject() { - if (this in encoder.keys) { - val prevHandler = encoder.remove(this) - val handler = if (prevHandler is PacketEncoder) PacketEncoder(PacketFlow.CLIENTBOUND) else prevHandler - handler?.let { this.pipeline().replace("encoder", "encoder", handler) } - } - - if (this in decoder.keys) { - val prevHandler = decoder.remove(this) - val handler = if (prevHandler is PacketDecoder) PacketDecoder(PacketFlow.SERVERBOUND) else prevHandler - handler?.let { this.pipeline().replace("decoder", "decoder", handler) } - } - } - - private class CustomPacketEncoder(val player: Player?) : MessageToByteEncoder>() { - private val protocolDirection = PacketFlow.CLIENTBOUND - - override fun encode(ctx: ChannelHandlerContext, msg: Packet<*>, out: ByteBuf) { - val enumProt = ctx.channel()?.attr(Connection.ATTRIBUTE_PROTOCOL)?.get() - ?: throw RuntimeException("ConnectionProtocol unknown: $out") - val int = msg.let { enumProt.getPacketId(this.protocolDirection, it) } - ?: throw IOException("Can't serialize unregistered packet") - val packetDataSerializer: FriendlyByteBuf = CustomDataSerializer(player, out) - packetDataSerializer.writeVarInt(int) - - try { - val int2 = packetDataSerializer.writerIndex() - msg.write(packetDataSerializer) - val int3 = packetDataSerializer.writerIndex() - int2 - if (int3 > 8388608) { - throw IllegalArgumentException("Packet too big (is $int3, should be less than 8388608): $msg") - } - } catch (e: Exception) { - if (msg.isSkippable) - throw SkipPacketException(e) - throw e - } - } - } - - private class CustomPacketDecoder(val player: Player?) : ByteToMessageDecoder() { - - override fun decode(ctx: ChannelHandlerContext, msg: ByteBuf, out: MutableList) { - if (msg.readableBytes() == 0) return - - val dataSerializer = CustomDataSerializer(player, msg) - val packetID = dataSerializer.readVarInt() - val packet = ctx.channel().attr(Connection.ATTRIBUTE_PROTOCOL).get() - .createPacket(PacketFlow.SERVERBOUND, packetID, dataSerializer) - ?: throw IOException("Bad packet id $packetID") - - if (dataSerializer.readableBytes() > 0) { - throw IOException("Packet $packetID ($packet) was larger than I expected, found ${dataSerializer.readableBytes()} bytes extra whilst reading packet $packetID") - } - out.add(packet) - } - } - - private class CustomDataSerializer(val player: Player?, bytebuf: ByteBuf) : FriendlyByteBuf(bytebuf) { - val gson = GsonComponentSerializer.gson() - - override fun writeUtf(string: String, maxLength: Int): FriendlyByteBuf { - runCatching { - val element = JsonParser.parseString(string) - if (element.isJsonObject) - return super.writeUtf(element.asJsonObject.returnFormattedString(), maxLength) - } - - return super.writeUtf(string, maxLength) - } - - override fun writeNbt(compound: CompoundTag?): FriendlyByteBuf { - return super.writeNbt(compound?.apply { - transform(this, Function { string: String -> - try { - val element = JsonParser.parseString(string) - if (element.isJsonObject) - return@Function element.asJsonObject.returnFormattedString() - } catch (ignored: Exception) { - } - string - }) - }) - } - - private fun JsonObject.returnFormattedString(insert: Boolean = true): String { - return if (this.has("args") || this.has("text") || this.has("extra") || this.has("translate")) { - gson.serialize(gson.deserialize(this.toString()).transform(null, insert)) - } else this.toString() - } - - private fun transform(compound: CompoundTag, transformer: Function) { - for (key in compound.allKeys) when (val base = compound.get(key)) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> compound.put(key, StringTag.valueOf(transformer.apply(base.asString))) - } - } - - private fun transform(list: ListTag, transformer: Function) { - for (base in list) when (base) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> list.indexOf(base).let { index -> - list.add(index, StringTag.valueOf(transformer.apply(base.asString))) - list.removeAt(index + 1) - } - } - } - - override fun readUtf(maxLength: Int): String { - return super.readUtf(maxLength).let { string -> - runCatching { string.miniMsg() }.recover { legacy.deserialize(string) } - .getOrNull()?.transform(player, true)?.serialize() ?: string - } - } - - - - } - - override val supported get() = true -} diff --git a/v1_19_R2/build.gradle.kts b/v1_19_R2/build.gradle.kts deleted file mode 100644 index 8da5352..0000000 --- a/v1_19_R2/build.gradle.kts +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id("com.mineinabyss.conventions.kotlin.jvm") - id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.7.1" -} - -repositories { - gradlePluginPortal() - maven("https://repo.mineinabyss.com/releases") - maven("https://repo.mineinabyss.com/snapshots") - maven("https://repo.papermc.io/repository/maven-public/") - google() -} - -dependencies { - // MineInAbyss platform - compileOnly(idofrontLibs.kotlinx.serialization.json) - compileOnly(idofrontLibs.kotlinx.serialization.kaml) - compileOnly(idofrontLibs.kotlinx.coroutines) - compileOnly(idofrontLibs.minecraft.mccoroutine) - - // Shaded - implementation(idofrontLibs.bundles.idofront.core) - implementation(project(":core")) - paperweight.paperDevBundle("1.19.3-R0.1-SNAPSHOT") //NMS -} - -tasks { - - build { - dependsOn(reobfJar) - } - - compileJava { - options.encoding = Charsets.UTF_8.name() - options.release.set(21) - } - javadoc { - options.encoding = Charsets.UTF_8.name() - } - processResources { - filteringCharset = Charsets.UTF_8.name() - } -} diff --git a/v1_19_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R2/EmojyNMSHandler.kt b/v1_19_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R2/EmojyNMSHandler.kt deleted file mode 100644 index 4faf8d1..0000000 --- a/v1_19_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R2/EmojyNMSHandler.kt +++ /dev/null @@ -1,249 +0,0 @@ -@file:Suppress("unused") - -package com.mineinabyss.emojy.nms.v1_19_R2 - -import com.github.shynixn.mccoroutine.bukkit.launch -import com.github.shynixn.mccoroutine.bukkit.minecraftDispatcher -import com.google.gson.JsonObject -import com.google.gson.JsonParser -import com.mineinabyss.emojy.emojy -import com.mineinabyss.emojy.legacy -import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.emojy.transform -import com.mineinabyss.idofront.textcomponents.miniMsg -import com.mineinabyss.idofront.textcomponents.serialize -import io.netty.buffer.ByteBuf -import io.netty.channel.* -import io.netty.handler.codec.ByteToMessageDecoder -import io.netty.handler.codec.MessageToByteEncoder -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.nbt.StringTag -import net.minecraft.network.* -import net.minecraft.network.protocol.Packet -import net.minecraft.network.protocol.PacketFlow -import net.minecraft.server.MinecraftServer -import net.minecraft.server.network.ServerConnectionListener -import org.bukkit.Bukkit -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer -import org.bukkit.entity.Player -import java.io.IOException -import java.util.* -import java.util.function.Function - -class EmojyNMSHandler : IEmojyNMSHandler { - private val encoder = Collections.synchronizedMap(WeakHashMap()) - private val decoder = Collections.synchronizedMap(WeakHashMap()) - - @Suppress("unused", "UNCHECKED_CAST", "FunctionName") - fun EmojyNMSHandler() { - val connections: List = MinecraftServer.getServer().connection?.connections ?: emptyList() - // Have to set it accessible because unlike connections it is private - val channelFutures = ServerConnectionListener::class.java.getDeclaredField("f").apply { this.isAccessible = true; }.get(MinecraftServer.getServer().connection) as List - - - // Handle connected channels - val endInitProtocol: ChannelInitializer = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - try { - // This can take a while, so we need to stop the main thread from interfering - synchronized(connections) { - // Stop injecting channels - channel.eventLoop().submit { channel.inject() } - } - } catch (e: java.lang.Exception) { - e.printStackTrace() - } - } - } - - // Handle channels that are connecting - val beginInitProtocol = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - var handler: ChannelHandler? = null - - channel.pipeline().forEach { - if (it.value.javaClass.name == "com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer") { - handler = it.value as ChannelHandler - } - } - handler?.let { - val initChannel = ChannelInitializer::class.java.getDeclaredMethod("initChannel", Channel::class.java).apply { isAccessible = true } - val original = it.javaClass.getDeclaredField("original").apply { this.isAccessible = true } - val initializer = original.get(it) as ChannelInitializer<*> - val miniInit = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - initChannel.invoke(initializer, channel) - channel.eventLoop().submit { channel.inject() } - } - } - original.set(handler, miniInit) - } ?: channel.pipeline().addLast(endInitProtocol) - } - } - - val serverChannelHandler = object : ChannelInboundHandlerAdapter() { - override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { - (msg as Channel).pipeline().addFirst(beginInitProtocol) - ctx.fireChannelRead(msg) - } - } - - try { - bind(channelFutures, serverChannelHandler) - } catch (e: IllegalArgumentException) { - emojy.plugin.launch(emojy.plugin.minecraftDispatcher) { - bind(channelFutures, serverChannelHandler) - } - } - } - - private fun bind(channelFutures: List, serverChannelHandler: ChannelInboundHandlerAdapter) { - channelFutures.forEach { future -> - future.channel().pipeline().addFirst(serverChannelHandler) - } - - Bukkit.getOnlinePlayers().forEach(::inject) - } - - private fun Channel.inject(player: Player? = null) { - if (this !in encoder.keys && this.pipeline().get("encoder") !is CustomPacketEncoder) - encoder[this] = this.pipeline().replace("encoder", "encoder", CustomPacketEncoder(player)) - - if (this !in decoder.keys && this.pipeline().get("decoder") !is CustomPacketDecoder) - decoder[this] = this.pipeline().replace("decoder", "decoder", CustomPacketDecoder(player)) - - } - - override fun inject(player: Player) { - val channel = (player as CraftPlayer).handle.connection.connection.channel ?: return - channel.eventLoop().submit { channel.inject(player) } - } - - override fun uninject(player: Player) { - (player as CraftPlayer).handle.connection.connection.channel.uninject() - } - - private fun Channel.uninject() { - if (this in encoder.keys) { - val prevHandler = encoder.remove(this) - val handler = if (prevHandler is PacketEncoder) PacketEncoder(PacketFlow.CLIENTBOUND) else prevHandler - handler?.let { this.pipeline().replace("encoder", "encoder", handler) } - } - - if (this in decoder.keys) { - val prevHandler = decoder.remove(this) - val handler = if (prevHandler is PacketDecoder) PacketDecoder(PacketFlow.SERVERBOUND) else prevHandler - handler?.let { this.pipeline().replace("decoder", "decoder", handler) } - } - } - - private class CustomPacketEncoder(val player: Player?) : MessageToByteEncoder>() { - private val protocolDirection = PacketFlow.CLIENTBOUND - - override fun encode(ctx: ChannelHandlerContext, msg: Packet<*>, out: ByteBuf) { - val enumProt = ctx.channel()?.attr(Connection.ATTRIBUTE_PROTOCOL)?.get() - ?: throw RuntimeException("ConnectionProtocol unknown: $out") - val int = msg.let { enumProt.getPacketId(this.protocolDirection, it) } - ?: throw IOException("Can't serialize unregistered packet") - val packetDataSerializer: FriendlyByteBuf = CustomDataSerializer(player, out) - packetDataSerializer.writeVarInt(int) - - try { - val int2 = packetDataSerializer.writerIndex() - msg.write(packetDataSerializer) - val int3 = packetDataSerializer.writerIndex() - int2 - if (int3 > 8388608) { - throw IllegalArgumentException("Packet too big (is $int3, should be less than 8388608): $msg") - } - } catch (e: Exception) { - if (msg.isSkippable) - throw SkipPacketException(e) - throw e - } - } - } - - private class CustomPacketDecoder(val player: Player?) : ByteToMessageDecoder() { - - override fun decode(ctx: ChannelHandlerContext, msg: ByteBuf, out: MutableList) { - if (msg.readableBytes() == 0) return - - val dataSerializer = CustomDataSerializer(player, msg) - val packetID = dataSerializer.readVarInt() - val packet = ctx.channel().attr(Connection.ATTRIBUTE_PROTOCOL).get() - .createPacket(PacketFlow.SERVERBOUND, packetID, dataSerializer) - ?: throw IOException("Bad packet id $packetID") - - if (dataSerializer.readableBytes() > 0) { - throw IOException("Packet $packetID ($packet) was larger than I expected, found ${dataSerializer.readableBytes()} bytes extra whilst reading packet $packetID") - } - out.add(packet) - } - } - - private class CustomDataSerializer(val player: Player?, bytebuf: ByteBuf) : FriendlyByteBuf(bytebuf) { - val gson = GsonComponentSerializer.gson() - - override fun writeUtf(string: String, maxLength: Int): FriendlyByteBuf { - try { - val element = JsonParser.parseString(string) - if (element.isJsonObject) - return super.writeUtf(element.asJsonObject.returnFormattedString(), maxLength) - } catch (_: Exception) { - } - - return super.writeUtf(string, maxLength) - } - - override fun writeNbt(compound: CompoundTag?): FriendlyByteBuf { - return super.writeNbt(compound?.apply { - transform(this, Function { string: String -> - try { - val element = JsonParser.parseString(string) - if (element.isJsonObject) - return@Function element.asJsonObject.returnFormattedString() - } catch (ignored: Exception) { - } - string - }) - }) - } - - private fun JsonObject.returnFormattedString(): String { - return if (this.has("args") || this.has("text") || this.has("extra") || this.has("translate")) { - gson.serialize(gson.deserialize(this.toString()).transform(null, true)) - } else this.toString() - } - - private fun transform(compound: CompoundTag, transformer: Function) { - for (key in compound.allKeys) when (val base = compound.get(key)) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> compound.put(key, StringTag.valueOf(transformer.apply(base.asString))) - } - } - - private fun transform(list: ListTag, transformer: Function) { - for (base in list) when (base) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> list.indexOf(base).let { index -> - list.add(index, StringTag.valueOf(transformer.apply(base.asString))) - list.removeAt(index + 1) - } - } - } - - override fun readUtf(maxLength: Int): String { - return super.readUtf(maxLength).let { string -> - runCatching { string.miniMsg() }.recover { legacy.deserialize(string) } - .getOrNull()?.transform(player, true)?.serialize() ?: string - } - } - - } - - override val supported get() = true -} diff --git a/v1_19_R3/build.gradle.kts b/v1_19_R3/build.gradle.kts deleted file mode 100644 index 634f20e..0000000 --- a/v1_19_R3/build.gradle.kts +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id("com.mineinabyss.conventions.kotlin.jvm") - id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.7.1" -} - -repositories { - gradlePluginPortal() - maven("https://repo.mineinabyss.com/releases") - maven("https://repo.mineinabyss.com/snapshots") - maven("https://repo.papermc.io/repository/maven-public/") - google() -} - -dependencies { - // MineInAbyss platform - compileOnly(idofrontLibs.kotlinx.serialization.json) - compileOnly(idofrontLibs.kotlinx.serialization.kaml) - compileOnly(idofrontLibs.kotlinx.coroutines) - compileOnly(idofrontLibs.minecraft.mccoroutine) - - // Shaded - implementation(idofrontLibs.bundles.idofront.core) - implementation(project(":core")) - paperweight.paperDevBundle("1.19.4-R0.1-SNAPSHOT") //NMS -} - -tasks { - - build { - dependsOn(reobfJar) - } - - compileJava { - options.encoding = Charsets.UTF_8.name() - options.release.set(21) - } - javadoc { - options.encoding = Charsets.UTF_8.name() - } - processResources { - filteringCharset = Charsets.UTF_8.name() - } -} diff --git a/v1_19_R3/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R3/EmojyNMSHandler.kt b/v1_19_R3/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R3/EmojyNMSHandler.kt deleted file mode 100644 index 741324e..0000000 --- a/v1_19_R3/src/main/kotlin/com/mineinabyss/emojy/nms/v1_19_R3/EmojyNMSHandler.kt +++ /dev/null @@ -1,264 +0,0 @@ -@file:Suppress("unused") - -package com.mineinabyss.emojy.nms.v1_19_R3 - -import com.github.shynixn.mccoroutine.bukkit.launch -import com.github.shynixn.mccoroutine.bukkit.minecraftDispatcher -import com.google.gson.JsonObject -import com.google.gson.JsonParser -import com.mineinabyss.emojy.emojy -import com.mineinabyss.emojy.legacy -import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.emojy.transform -import com.mineinabyss.idofront.textcomponents.miniMsg -import com.mineinabyss.idofront.textcomponents.serialize -import io.netty.buffer.ByteBuf -import io.netty.channel.* -import io.netty.handler.codec.ByteToMessageDecoder -import io.netty.handler.codec.MessageToByteEncoder -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.nbt.StringTag -import net.minecraft.network.Connection -import net.minecraft.network.FriendlyByteBuf -import net.minecraft.network.PacketDecoder -import net.minecraft.network.PacketEncoder -import net.minecraft.network.SkipPacketException -import net.minecraft.network.protocol.Packet -import net.minecraft.network.protocol.PacketFlow -import net.minecraft.network.protocol.game.ServerboundChatPacket -import net.minecraft.server.MinecraftServer -import net.minecraft.server.network.ServerConnectionListener -import org.bukkit.Bukkit -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer -import org.bukkit.entity.Player -import java.io.IOException -import java.util.* -import java.util.function.Function - -class EmojyNMSHandler : IEmojyNMSHandler { - private val encoder = Collections.synchronizedMap(WeakHashMap()) - private val decoder = Collections.synchronizedMap(WeakHashMap()) - - @Suppress("unused", "UNCHECKED_CAST", "FunctionName") - fun EmojyNMSHandler() { - val connections: List = MinecraftServer.getServer().connection?.connections ?: emptyList() - // Have to set it accessible because unlike connections it is private - val channelFutures = - ServerConnectionListener::class.java.getDeclaredField("f").apply { this.isAccessible = true; } - .get(MinecraftServer.getServer().connection) as List - - - // Handle connected channels - val endInitProtocol: ChannelInitializer = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - try { - // This can take a while, so we need to stop the main thread from interfering - synchronized(connections) { - // Stop injecting channels - channel.eventLoop().submit { channel.inject() } - } - } catch (e: java.lang.Exception) { - e.printStackTrace() - } - } - } - - // Handle channels that are connecting - val beginInitProtocol = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - var handler: ChannelHandler? = null - - channel.pipeline().forEach { - if (it.value.javaClass.name == "com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer") { - handler = it.value as ChannelHandler - } - } - handler?.let { - val initChannel = - ChannelInitializer::class.java.getDeclaredMethod("initChannel", Channel::class.java) - .apply { isAccessible = true } - val original = it.javaClass.getDeclaredField("original").apply { this.isAccessible = true } - val initializer = original.get(it) as ChannelInitializer<*> - val miniInit = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - initChannel.invoke(initializer, channel) - channel.eventLoop().submit { channel.inject() } - } - } - original.set(handler, miniInit) - } ?: channel.pipeline().addLast(endInitProtocol) - } - } - - val serverChannelHandler = object : ChannelInboundHandlerAdapter() { - override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { - (msg as Channel).pipeline().addFirst(beginInitProtocol) - ctx.fireChannelRead(msg) - } - } - - try { - bind(channelFutures, serverChannelHandler) - } catch (e: IllegalArgumentException) { - emojy.plugin.launch(emojy.plugin.minecraftDispatcher) { - bind(channelFutures, serverChannelHandler) - } - } - } - - private fun bind(channelFutures: List, serverChannelHandler: ChannelInboundHandlerAdapter) { - channelFutures.forEach { future -> - future.channel().pipeline().addFirst(serverChannelHandler) - } - - Bukkit.getOnlinePlayers().forEach(::inject) - } - - override fun inject(player: Player) { - val channel = (player as CraftPlayer).handle.connection.connection.channel ?: return - channel.eventLoop().submit { channel.inject(player) } - } - - override fun uninject(player: Player) { - (player as CraftPlayer).handle.connection.connection.channel.uninject() - } - - private fun Channel.inject(player: Player? = null) { - if (this !in encoder.keys && this.pipeline().get("encoder") !is CustomPacketEncoder) - encoder[this] = this.pipeline().replace("encoder", "encoder", CustomPacketEncoder(player)) - - if (this !in decoder.keys && this.pipeline().get("decoder") !is CustomPacketDecoder) - decoder[this] = this.pipeline().replace("decoder", "decoder", CustomPacketDecoder(player)) - - } - - private fun Channel.uninject() { - if (this in encoder.keys) { - val prevHandler = encoder.remove(this) - val handler = if (prevHandler is PacketEncoder) PacketEncoder(PacketFlow.CLIENTBOUND) else prevHandler - handler?.let { this.pipeline().replace("encoder", "encoder", handler) } - } - - if (this in decoder.keys) { - val prevHandler = decoder.remove(this) - val handler = if (prevHandler is PacketDecoder) PacketDecoder(PacketFlow.SERVERBOUND) else prevHandler - handler?.let { this.pipeline().replace("decoder", "decoder", handler) } - } - } - - private class CustomPacketEncoder(val player: Player?) : MessageToByteEncoder>() { - private val protocolDirection = PacketFlow.CLIENTBOUND - - override fun encode(ctx: ChannelHandlerContext, msg: Packet<*>, out: ByteBuf) { - val enumProt = ctx.channel()?.attr(Connection.ATTRIBUTE_PROTOCOL)?.get() - ?: throw RuntimeException("ConnectionProtocol unknown: $out") - val int = msg.let { enumProt.getPacketId(this.protocolDirection, it) } - val packetDataSerializer: FriendlyByteBuf = CustomDataSerializer(player, out) - packetDataSerializer.writeVarInt(int) - - try { - val int2 = packetDataSerializer.writerIndex() - msg.write(packetDataSerializer) - val int3 = packetDataSerializer.writerIndex() - int2 - if (int3 > 8388608) { - throw IllegalArgumentException("Packet too big (is $int3, should be less than 8388608): $msg") - } - } catch (e: Exception) { - if (msg.isSkippable) - throw SkipPacketException(e) - throw e - } - } - } - - private class CustomPacketDecoder(val player: Player?) : ByteToMessageDecoder() { - - override fun decode(ctx: ChannelHandlerContext, buffer: ByteBuf, out: MutableList) { - val buffferCopy = buffer.copy() - if (buffer.readableBytes() == 0) return - - val dataSerializer: FriendlyByteBuf = CustomDataSerializer(player, buffer) - val packetID = dataSerializer.readVarInt() - val protocol = ctx.channel().attr(Connection.ATTRIBUTE_PROTOCOL).get() - var packet = protocol.createPacket(PacketFlow.SERVERBOUND, packetID, dataSerializer) ?: throw IOException("Bad packet id $packetID") - - when { - dataSerializer.readableBytes() > 0 -> throw IOException("Packet $packetID ($packet) was larger than I expected, found ${dataSerializer.readableBytes()} bytes extra whilst reading packet $packetID") - packet is ServerboundChatPacket -> { - val serializer = FriendlyByteBuf(buffferCopy) - serializer.readVarInt() - packet = protocol.createPacket(PacketFlow.SERVERBOUND, packetID, serializer) ?: throw IOException("Bad packet id $packetID") - } - } - - out += packet - } - } - - private class CustomDataSerializer(val player: Player?, bytebuf: ByteBuf) : FriendlyByteBuf(bytebuf) { - val gson = GsonComponentSerializer.gson() - - override fun writeUtf(string: String, maxLength: Int): FriendlyByteBuf { - try { - val element = JsonParser.parseString(string) - if (element.isJsonObject) - return super.writeUtf(element.asJsonObject.returnFormattedString(), maxLength) - } catch (_: Exception) { - } - - return super.writeUtf(string, maxLength) - } - - override fun writeNbt(compound: CompoundTag?): FriendlyByteBuf { - return super.writeNbt(compound?.apply { - transform(this, Function { string: String -> - try { - val element = JsonParser.parseString(string) - if (element.isJsonObject) - return@Function element.asJsonObject.returnFormattedString() - } catch (ignored: Exception) { - } - string - }) - }) - } - - private fun JsonObject.returnFormattedString(): String { - return if (this.has("args") || this.has("text") || this.has("extra") || this.has("translate")) { - gson.serialize(gson.deserialize(this.toString()).transform(player, true)) - } else this.toString() - } - - private fun transform(compound: CompoundTag, transformer: Function) { - for (key in compound.allKeys) when (val base = compound.get(key)) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> compound.put(key, StringTag.valueOf(transformer.apply(base.asString))) - } - } - - private fun transform(list: ListTag, transformer: Function) { - for (base in list) when (base) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> list.indexOf(base).let { index -> - list.add(index, StringTag.valueOf(transformer.apply(base.asString))) - list.removeAt(index + 1) - } - } - } - - override fun readUtf(maxLength: Int): String { - return super.readUtf(maxLength).let { string -> - runCatching { string.miniMsg() }.recover { legacy.deserialize(string) } - .getOrNull()?.transform(player, true)?.serialize() ?: string - } - } - - - } - - override val supported get() = true -} diff --git a/v1_20_R1/build.gradle.kts b/v1_20_R1/build.gradle.kts deleted file mode 100644 index 000763d..0000000 --- a/v1_20_R1/build.gradle.kts +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id("com.mineinabyss.conventions.kotlin.jvm") - id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.7.1" -} - -repositories { - gradlePluginPortal() - maven("https://repo.mineinabyss.com/releases") - maven("https://repo.mineinabyss.com/snapshots") - maven("https://repo.papermc.io/repository/maven-public/") - google() -} - -dependencies { - // MineInAbyss platform - compileOnly(idofrontLibs.kotlinx.serialization.json) - compileOnly(idofrontLibs.kotlinx.serialization.kaml) - compileOnly(idofrontLibs.kotlinx.coroutines) - compileOnly(idofrontLibs.minecraft.mccoroutine) - - // Shaded - implementation(idofrontLibs.bundles.idofront.core) - implementation(project(":core")) - paperweight.paperDevBundle("1.20-R0.1-SNAPSHOT") //NMS -} - -tasks { - - build { - dependsOn(reobfJar) - } - - compileJava { - options.encoding = Charsets.UTF_8.name() - options.release.set(21) - } - javadoc { - options.encoding = Charsets.UTF_8.name() - } - processResources { - filteringCharset = Charsets.UTF_8.name() - } -} diff --git a/v1_20_R1/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R1/EmojyNMSHandler.kt b/v1_20_R1/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R1/EmojyNMSHandler.kt deleted file mode 100644 index 83265ac..0000000 --- a/v1_20_R1/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R1/EmojyNMSHandler.kt +++ /dev/null @@ -1,239 +0,0 @@ -@file:Suppress("unused") - -package com.mineinabyss.emojy.nms.v1_20_R1 - -import com.google.gson.JsonParser -import com.mineinabyss.emojy.emojy -import com.mineinabyss.emojy.legacy -import com.mineinabyss.emojy.nms.EmojyNMSHandlers -import com.mineinabyss.emojy.nms.EmojyNMSHandlers.formatString -import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.emojy.transform -import com.mineinabyss.idofront.messaging.broadcast -import com.mineinabyss.idofront.textcomponents.miniMsg -import com.mineinabyss.idofront.textcomponents.serialize -import io.netty.buffer.ByteBuf -import io.netty.channel.* -import io.netty.handler.codec.ByteToMessageDecoder -import io.netty.handler.codec.MessageToByteEncoder -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.nbt.StringTag -import net.minecraft.network.* -import net.minecraft.network.protocol.Packet -import net.minecraft.network.protocol.PacketFlow -import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket -import net.minecraft.network.protocol.game.ServerboundChatPacket -import net.minecraft.server.MinecraftServer -import net.minecraft.server.network.ServerConnectionListener -import org.bukkit.Bukkit -import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer -import org.bukkit.entity.Player -import org.bukkit.scheduler.BukkitRunnable -import java.io.IOException -import java.util.* -import java.util.function.Function - -class EmojyNMSHandler : IEmojyNMSHandler { - private val encoder = Collections.synchronizedMap(WeakHashMap()) - private val decoder = Collections.synchronizedMap(WeakHashMap()) - - @Suppress("unused", "UNCHECKED_CAST", "FunctionName") - fun EmojyNMSHandler() { - val connections = MinecraftServer.getServer().connection?.connections ?: emptyList() - // Have to set it accessible because unlike connections it is private - val channelFutures = ServerConnectionListener::class.java.getDeclaredField("f").apply { this.isAccessible = true; }.get(MinecraftServer.getServer().connection) as List - - - // Handle connected channels - val endInitProtocol: ChannelInitializer = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - runCatching { - synchronized(connections) { - // Stop injecting channels - channel.eventLoop().submit { channel.inject() } - } - }.onFailure { it.printStackTrace() } - } - } - - // Handle channels that are connecting - val beginInitProtocol = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - var handler: ChannelHandler? = null - - channel.pipeline().forEach { - if (it.value.javaClass.name == "com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer") { - handler = it.value as ChannelHandler - } - } - handler?.let { - val initChannel = ChannelInitializer::class.java.getDeclaredMethod("initChannel", Channel::class.java).apply { isAccessible = true } - val original = it.javaClass.getDeclaredField("original").apply { this.isAccessible = true } - val initializer = original.get(it) as ChannelInitializer<*> - val miniInit = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - initChannel.invoke(initializer, channel) - channel.eventLoop().submit { channel.inject() } - } - } - original.set(handler, miniInit) - } ?: channel.pipeline().addLast(endInitProtocol) - } - } - - val serverChannelHandler = object : ChannelInboundHandlerAdapter() { - override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { - (msg as Channel).pipeline().addFirst(beginInitProtocol) - ctx.fireChannelRead(msg) - } - } - - runCatching { - bind(channelFutures, serverChannelHandler) - }.onFailure { - object : BukkitRunnable() { - override fun run() { - bind(channelFutures, serverChannelHandler) - } - }.runTask(emojy.plugin) - } - } - - private fun bind(channelFutures: List, serverChannelHandler: ChannelInboundHandlerAdapter) { - channelFutures.forEach { future -> - future.channel().pipeline().addFirst(serverChannelHandler) - } - - Bukkit.getOnlinePlayers().forEach(::inject) - } - - private fun Channel.inject(player: Player? = null) { - if (this !in encoder.keys && (this.pipeline().get("encoder") as ChannelHandler) !is CustomPacketEncoder) - encoder[this] = this.pipeline().replace("encoder", "encoder", CustomPacketEncoder(player)) - - if (this !in decoder.keys && (this.pipeline().get("decoder") as ChannelHandler) !is CustomPacketDecoder) - decoder[this] = this.pipeline().replace("decoder", "decoder", CustomPacketDecoder(player)) - - } - - private fun Channel.uninject() { - if (this in encoder.keys) { - val prevHandler = encoder.remove(this) - val handler = if (prevHandler is PacketEncoder) PacketEncoder(PacketFlow.CLIENTBOUND) else prevHandler - handler?.let { this.pipeline().replace("encoder", "encoder", handler) } - } - - if (this in decoder.keys) { - val prevHandler = decoder.remove(this) - val handler = if (prevHandler is PacketDecoder) PacketDecoder(PacketFlow.SERVERBOUND) else prevHandler - handler?.let { this.pipeline().replace("decoder", "decoder", handler) } - } - } - - override fun inject(player: Player) { - val channel = (player as? CraftPlayer)?.handle?.connection?.connection?.channel ?: return - channel.eventLoop().submit { channel.inject(player) } - } - - override fun uninject(player: Player) { - (player as? CraftPlayer)?.handle?.connection?.connection?.channel?.uninject() - } - - private class CustomDataSerializer(val player: Player?, bytebuf: ByteBuf) : FriendlyByteBuf(bytebuf) { - override fun writeComponent(component: net.kyori.adventure.text.Component): FriendlyByteBuf { - return super.writeComponent(component.transform(null, true, true)) - } - - override fun writeUtf(string: String, maxLength: Int): FriendlyByteBuf { - runCatching { - val element = JsonParser.parseString(string) - if (element.isJsonObject) return super.writeUtf(element.asJsonObject.formatString(), maxLength) - } - - return super.writeUtf(string, maxLength) - } - - override fun writeNbt(compound: CompoundTag?): FriendlyByteBuf { - return super.writeNbt(compound?.apply { - transform(this, EmojyNMSHandlers.transformer()) - }) - } - - private fun transform(compound: CompoundTag, transformer: Function) { - for (key in compound.allKeys) when (val base = compound.get(key)) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> compound.put(key, StringTag.valueOf(transformer.apply(base.asString))) - } - } - - private fun transform(list: ListTag, transformer: Function) { - for (base in list) when (base) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> list.indexOf(base).let { index -> - list.add(index, StringTag.valueOf(transformer.apply(base.asString))) - list.removeAt(index + 1) - } - } - } - - override fun readUtf(maxLength: Int): String { - return super.readUtf(maxLength).let { string -> - runCatching { string.miniMsg() }.recover { legacy.deserialize(string) } - .getOrNull()?.transform(player, true)?.serialize() ?: string - } - } - - } - - private class CustomPacketEncoder(val player: Player?) : MessageToByteEncoder>() { - private val protocolDirection = PacketFlow.CLIENTBOUND - - override fun encode(ctx: ChannelHandlerContext, msg: Packet<*>, out: ByteBuf) { - val enumProt = ctx.channel()?.attr(Connection.ATTRIBUTE_PROTOCOL)?.get() ?: throw RuntimeException("ConnectionProtocol unknown: $out") - val int = msg.let { enumProt.getPacketId(this.protocolDirection, it) } - val packetDataSerializer: FriendlyByteBuf = CustomDataSerializer(player, out) - packetDataSerializer.writeVarInt(int) - - runCatching { - val int2 = packetDataSerializer.writerIndex() - msg.write(packetDataSerializer) - val int3 = packetDataSerializer.writerIndex() - int2 - if (int3 > 8388608) { - throw IllegalArgumentException("Packet too big (is $int3, should be less than 8388608): $msg") - } - }.onFailure { - if (msg.isSkippable) throw SkipPacketException(it) - throw it - } - } - } - - private class CustomPacketDecoder(val player: Player?) : ByteToMessageDecoder() { - - override fun decode(ctx: ChannelHandlerContext, buffer: ByteBuf, out: MutableList) { - val buffferCopy = buffer.copy() - if (buffer.readableBytes() == 0) return - - val customDataSerializer: FriendlyByteBuf = CustomDataSerializer(player, buffer) - val packetID = customDataSerializer.readVarInt() - val protocol = ctx.channel().attr(Connection.ATTRIBUTE_PROTOCOL).get() - val packet = protocol.createPacket(PacketFlow.SERVERBOUND, packetID, customDataSerializer) ?: throw IOException("Bad packet id $packetID") - - out += when { - customDataSerializer.readableBytes() > 0 -> throw IOException("Packet $packetID ($packet) was larger than I expected, found ${customDataSerializer.readableBytes()} bytes extra whilst reading packet $packetID") - packet is ServerboundChatPacket || packet is ClientboundPlayerChatPacket -> { - broadcast((player?.name ?: "null") + ": " + packet.javaClass.name) - val baseSerializer = FriendlyByteBuf(buffferCopy) - val basePacketId = baseSerializer.readVarInt() - protocol.createPacket(PacketFlow.SERVERBOUND, basePacketId, baseSerializer) ?: throw IOException("Bad packet id $basePacketId") - } - else -> packet - } - } - } - - override val supported get() = true -} diff --git a/v1_20_R2/build.gradle.kts b/v1_20_R2/build.gradle.kts deleted file mode 100644 index 856d82c..0000000 --- a/v1_20_R2/build.gradle.kts +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id("com.mineinabyss.conventions.kotlin.jvm") - id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.7.1" -} - -repositories { - gradlePluginPortal() - maven("https://repo.mineinabyss.com/releases") - maven("https://repo.mineinabyss.com/snapshots") - maven("https://repo.papermc.io/repository/maven-public/") - google() -} - -dependencies { - // MineInAbyss platform - compileOnly(idofrontLibs.kotlinx.serialization.json) - compileOnly(idofrontLibs.kotlinx.serialization.kaml) - compileOnly(idofrontLibs.kotlinx.coroutines) - compileOnly(idofrontLibs.minecraft.mccoroutine) - - // Shaded - implementation(idofrontLibs.bundles.idofront.core) - implementation(project(":core")) - paperweight.paperDevBundle("1.20.2-R0.1-SNAPSHOT") //NMS -} - -tasks { - - build { - dependsOn(reobfJar) - } - - compileJava { - options.encoding = Charsets.UTF_8.name() - options.release.set(21) - } - javadoc { - options.encoding = Charsets.UTF_8.name() - } - processResources { - filteringCharset = Charsets.UTF_8.name() - } -} diff --git a/v1_20_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R2/EmojyNMSHandler.kt b/v1_20_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R2/EmojyNMSHandler.kt deleted file mode 100644 index 6c3588b..0000000 --- a/v1_20_R2/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R2/EmojyNMSHandler.kt +++ /dev/null @@ -1,251 +0,0 @@ -@file:Suppress("unused") - -package com.mineinabyss.emojy.nms.v1_20_R2 - -import com.google.gson.JsonParser -import com.mineinabyss.emojy.emojy -import com.mineinabyss.emojy.legacy -import com.mineinabyss.emojy.nms.EmojyNMSHandlers -import com.mineinabyss.emojy.nms.EmojyNMSHandlers.formatString -import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.emojy.transform -import com.mineinabyss.idofront.textcomponents.miniMsg -import com.mineinabyss.idofront.textcomponents.serialize -import io.netty.buffer.ByteBuf -import io.netty.channel.* -import io.netty.handler.codec.ByteToMessageDecoder -import io.netty.handler.codec.MessageToByteEncoder -import io.papermc.paper.adventure.PaperAdventure -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.nbt.StringTag -import net.minecraft.nbt.Tag -import net.minecraft.network.* -import net.minecraft.network.protocol.Packet -import net.minecraft.network.protocol.PacketFlow -import net.minecraft.network.protocol.game.ServerboundChatPacket -import net.minecraft.server.MinecraftServer -import net.minecraft.server.network.ServerConnectionListener -import org.bukkit.Bukkit -import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer -import org.bukkit.entity.Player -import org.bukkit.scheduler.BukkitRunnable -import java.io.IOException -import java.util.* -import java.util.function.Function - -class EmojyNMSHandler : IEmojyNMSHandler { - private val encoder = Collections.synchronizedMap(WeakHashMap()) - private val decoder = Collections.synchronizedMap(WeakHashMap()) - - @Suppress("unused", "UNCHECKED_CAST", "FunctionName") - fun EmojyNMSHandler() { - val connections = MinecraftServer.getServer().connection.connections ?: emptyList() - // Have to set it accessible because unlike connections it is private - val channelFutures = ServerConnectionListener::class.java.getDeclaredField("f").apply { this.isAccessible = true; }.get(MinecraftServer.getServer().connection) as List - - - // Handle connected channels - val endInitProtocol: ChannelInitializer = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - runCatching { - synchronized(connections) { - // Stop injecting channels - channel.eventLoop().submit { channel.inject() } - } - }.onFailure { it.printStackTrace() } - } - } - - // Handle channels that are connecting - val beginInitProtocol = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - var handler: ChannelHandler? = null - - channel.pipeline().forEach { - if (it.value.javaClass.name == "com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer") { - handler = it.value as ChannelHandler - } - } - handler?.let { - val initChannel = ChannelInitializer::class.java.getDeclaredMethod("initChannel", Channel::class.java).apply { isAccessible = true } - val original = it.javaClass.getDeclaredField("original").apply { this.isAccessible = true } - val initializer = original.get(it) as ChannelInitializer<*> - val miniInit = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - initChannel.invoke(initializer, channel) - channel.eventLoop().submit { channel.inject() } - } - } - original.set(handler, miniInit) - } ?: channel.pipeline().addLast(endInitProtocol) - } - } - - val serverChannelHandler = object : ChannelInboundHandlerAdapter() { - override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { - (msg as Channel).pipeline().addFirst(beginInitProtocol) - ctx.fireChannelRead(msg) - } - } - - runCatching { - bind(channelFutures, serverChannelHandler) - }.onFailure { - object : BukkitRunnable() { - override fun run() { - bind(channelFutures, serverChannelHandler) - } - }.runTask(emojy.plugin) - } - } - - private fun bind(channelFutures: List, serverChannelHandler: ChannelInboundHandlerAdapter) { - channelFutures.forEach { future -> - future.channel().pipeline().addFirst(serverChannelHandler) - } - - Bukkit.getOnlinePlayers().forEach(::inject) - } - - private fun Channel.inject(player: Player? = null) { - if (this !in encoder.keys && (this.pipeline().get("encoder") as ChannelHandler) !is CustomPacketEncoder) - encoder[this] = this.pipeline().replace("encoder", "encoder", CustomPacketEncoder(player)) - - if (this !in decoder.keys && (this.pipeline().get("decoder") as ChannelHandler) !is CustomPacketDecoder) - decoder[this] = this.pipeline().replace("decoder", "decoder", CustomPacketDecoder(player)) - - } - - private fun Channel.uninject() { - if (this in encoder.keys) { - val prevHandler = encoder.remove(this) - val handler = if (prevHandler is PacketEncoder) PacketEncoder(Connection.ATTRIBUTE_CLIENTBOUND_PROTOCOL) else prevHandler - handler?.let { this.pipeline().replace("encoder", "encoder", handler) } - } - - if (this in decoder.keys) { - val prevHandler = decoder.remove(this) - val handler = if (prevHandler is PacketDecoder) PacketDecoder(Connection.ATTRIBUTE_SERVERBOUND_PROTOCOL) else prevHandler - handler?.let { this.pipeline().replace("decoder", "decoder", handler) } - } - } - - override fun inject(player: Player) { - val channel = (player as? CraftPlayer)?.handle?.connection?.connection?.channel ?: return - channel.eventLoop().submit { channel.inject(player) } - } - - override fun uninject(player: Player) { - (player as? CraftPlayer)?.handle?.connection?.connection?.channel?.uninject() - } - - private class CustomDataSerializer(val player: Player?, bytebuf: ByteBuf) : FriendlyByteBuf(bytebuf) { - override fun writeComponent(component: Component): FriendlyByteBuf { - return super.writeComponent(component.transform(null, true, false)) - } - - override fun readComponent(): net.minecraft.network.chat.Component { - return PaperAdventure.asVanilla(PaperAdventure.asAdventure(super.readComponent()).transform(player, true, false)) - } - - override fun writeUtf(string: String, maxLength: Int): FriendlyByteBuf { - runCatching { - val element = JsonParser.parseString(string) - if (element.isJsonObject) return super.writeUtf(element.asJsonObject.formatString(), maxLength) - } - - return super.writeUtf(string, maxLength) - } - - override fun readUtf(maxLength: Int): String { - return super.readUtf(maxLength).let { string -> - runCatching { string.miniMsg() }.recover { LegacyComponentSerializer.legacySection().deserialize(string) } - .getOrNull()?.transform(player, true)?.serialize() ?: string - } - } - - override fun writeNbt(compound: Tag?): FriendlyByteBuf { - return super.writeNbt(compound?.apply { - transform(this as CompoundTag, EmojyNMSHandlers.transformer()) - }) - } - - override fun readNbt(): CompoundTag? { - return super.readNbt()?.apply { - transform(this, EmojyNMSHandlers.transformer(player)) - } - } - - private fun transform(compound: CompoundTag, transformer: Function) { - for (key in compound.allKeys) when (val base = compound.get(key)) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> compound.put(key, StringTag.valueOf(transformer.apply(base.asString))) - } - } - - private fun transform(list: ListTag, transformer: Function) { - val listCopy = list.toList() - for (base in listCopy) when (base) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> list.indexOf(base).let { index -> - list[index] = StringTag.valueOf(transformer.apply(base.asString)) - } - } - } - - } - - private class CustomPacketEncoder(val player: Player? = null) : MessageToByteEncoder>() { - private val protocolDirection = PacketFlow.CLIENTBOUND - - override fun encode(ctx: ChannelHandlerContext, msg: Packet<*>, out: ByteBuf) { - val enumProt = ctx.channel()?.attr(Connection.ATTRIBUTE_CLIENTBOUND_PROTOCOL)?.get() ?: throw RuntimeException("ConnectionProtocol unknown: $out") - val packetID = enumProt.protocol().codec(protocolDirection).packetId(msg) - val packetDataSerializer: FriendlyByteBuf = CustomDataSerializer(player, out) - packetDataSerializer.writeVarInt(packetID) - - runCatching { - val int2 = packetDataSerializer.writerIndex() - msg.write(packetDataSerializer) - val int3 = packetDataSerializer.writerIndex() - int2 - if (int3 > 8388608) { - throw IllegalArgumentException("Packet too big (is $int3, should be less than 8388608): $msg") - } - }.onFailure { - if (msg.isSkippable) throw SkipPacketException(it) - throw it - } - } - } - - private class CustomPacketDecoder(val player: Player? = null) : ByteToMessageDecoder() { - - override fun decode(ctx: ChannelHandlerContext, buffer: ByteBuf, out: MutableList) { - val bufferCopy = buffer.copy() - if (buffer.readableBytes() == 0) return - - val customDataSerializer = CustomDataSerializer(player, buffer) - val packetID = customDataSerializer.readVarInt() - val attribute = ctx.channel().attr(Connection.ATTRIBUTE_SERVERBOUND_PROTOCOL) - val packet = attribute.get().createPacket(packetID, customDataSerializer) ?: throw IOException("Bad packet id $packetID") - //ObfHelper.INSTANCE.deobfClassName(packet.javaClass.name).logVal("Packet: ") - out += when { - customDataSerializer.readableBytes() > 0 -> throw IOException("Packet $packetID ($packet) was larger than I expected, found ${customDataSerializer.readableBytes()} bytes extra whilst reading packet $packetID") - packet is ServerboundChatPacket -> { - val baseSerializer = FriendlyByteBuf(bufferCopy) - val basePacketID = baseSerializer.readVarInt() - attribute.get().createPacket(basePacketID, baseSerializer) ?: throw IOException("Bad packet id $basePacketID") - } - else -> packet - } - ProtocolSwapHandler.swapProtocolIfNeeded(attribute, packet) - } - } - - override val supported get() = true -} diff --git a/v1_20_R3/build.gradle.kts b/v1_20_R3/build.gradle.kts deleted file mode 100644 index 0478735..0000000 --- a/v1_20_R3/build.gradle.kts +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id("com.mineinabyss.conventions.kotlin.jvm") - id("com.mineinabyss.conventions.autoversion") - id("io.papermc.paperweight.userdev") version "1.7.1" -} - -repositories { - gradlePluginPortal() - maven("https://repo.mineinabyss.com/releases") - maven("https://repo.mineinabyss.com/snapshots") - maven("https://repo.papermc.io/repository/maven-public/") - google() -} - -dependencies { - // MineInAbyss platform - compileOnly(idofrontLibs.kotlinx.serialization.json) - compileOnly(idofrontLibs.kotlinx.serialization.kaml) - compileOnly(idofrontLibs.kotlinx.coroutines) - compileOnly(idofrontLibs.minecraft.mccoroutine) - - // Shaded - implementation(idofrontLibs.bundles.idofront.core) - implementation(project(":core")) - paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") //NMS -} - -tasks { - - build { - dependsOn(reobfJar) - } - - compileJava { - options.encoding = Charsets.UTF_8.name() - options.release.set(21) - } - javadoc { - options.encoding = Charsets.UTF_8.name() - } - processResources { - filteringCharset = Charsets.UTF_8.name() - } -} diff --git a/v1_20_R3/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R3/EmojyNMSHandler.kt b/v1_20_R3/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R3/EmojyNMSHandler.kt deleted file mode 100644 index 5d0ea47..0000000 --- a/v1_20_R3/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R3/EmojyNMSHandler.kt +++ /dev/null @@ -1,258 +0,0 @@ -@file:Suppress("unused") - -package com.mineinabyss.emojy.nms.v1_20_R3 - -import com.mineinabyss.emojy.emojy -import com.mineinabyss.emojy.escapeEmoteIDs -import com.mineinabyss.emojy.legacy -import com.mineinabyss.emojy.nms.EmojyNMSHandlers -import com.mineinabyss.emojy.nms.IEmojyNMSHandler -import com.mineinabyss.emojy.transformEmoteIDs -import com.mineinabyss.idofront.textcomponents.miniMsg -import com.mineinabyss.idofront.textcomponents.serialize -import io.netty.buffer.ByteBuf -import io.netty.channel.* -import io.netty.handler.codec.ByteToMessageDecoder -import io.netty.handler.codec.MessageToByteEncoder -import io.papermc.paper.adventure.AdventureComponent -import io.papermc.paper.adventure.PaperAdventure -import net.kyori.adventure.text.Component -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.nbt.StringTag -import net.minecraft.nbt.Tag -import net.minecraft.network.* -import net.minecraft.network.protocol.Packet -import net.minecraft.network.protocol.PacketFlow -import net.minecraft.network.protocol.game.ServerboundChatPacket -import net.minecraft.server.MinecraftServer -import net.minecraft.server.network.ServerConnectionListener -import org.bukkit.Bukkit -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer -import org.bukkit.entity.Player -import org.bukkit.scheduler.BukkitRunnable -import java.io.IOException -import java.util.* -import java.util.function.Function - -class EmojyNMSHandler : IEmojyNMSHandler { - private val encoder = Collections.synchronizedMap(WeakHashMap()) - private val decoder = Collections.synchronizedMap(WeakHashMap()) - - @Suppress("unused", "UNCHECKED_CAST", "FunctionName") - fun EmojyNMSHandler() { - val connections = MinecraftServer.getServer().connection.connections ?: emptyList() - // Have to set it accessible because unlike connections it is private - val channelFutures = ServerConnectionListener::class.java.getDeclaredField("f").apply { this.isAccessible = true; }.get(MinecraftServer.getServer().connection) as List - - - // Handle connected channels - val endInitProtocol: ChannelInitializer = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - runCatching { - synchronized(connections) { - // Stop injecting channels - channel.eventLoop().submit { channel.inject() } - } - }.onFailure { it.printStackTrace() } - } - } - - // Handle channels that are connecting - val beginInitProtocol = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - var handler: ChannelHandler? = null - - channel.pipeline().forEach { - if (it.value.javaClass.name == "com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer") { - handler = it.value as ChannelHandler - } - } - handler?.let { - val initChannel = ChannelInitializer::class.java.getDeclaredMethod("initChannel", Channel::class.java).apply { isAccessible = true } - val original = it.javaClass.getDeclaredField("original").apply { this.isAccessible = true } - val initializer = original.get(it) as ChannelInitializer<*> - val miniInit = object : ChannelInitializer() { - override fun initChannel(channel: Channel) { - initChannel.invoke(initializer, channel) - channel.eventLoop().submit { channel.inject() } - } - } - original.set(handler, miniInit) - } ?: channel.pipeline().addLast(endInitProtocol) - } - } - - val serverChannelHandler = object : ChannelInboundHandlerAdapter() { - override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { - (msg as Channel).pipeline().addFirst(beginInitProtocol) - ctx.fireChannelRead(msg) - } - } - - runCatching { - bind(channelFutures, serverChannelHandler) - }.onFailure { - object : BukkitRunnable() { - override fun run() { - bind(channelFutures, serverChannelHandler) - } - }.runTask(emojy.plugin) - } - } - - private fun bind(channelFutures: List, serverChannelHandler: ChannelInboundHandlerAdapter) { - channelFutures.forEach { future -> - future.channel().pipeline().addFirst(serverChannelHandler) - } - - Bukkit.getOnlinePlayers().forEach(::inject) - } - - private fun Channel.inject(player: Player? = null) { - if (this !in encoder.keys && (this.pipeline().get("encoder") as ChannelHandler) !is CustomPacketEncoder) - encoder[this] = this.pipeline().replace("encoder", "encoder", CustomPacketEncoder(player)) - - if (this !in decoder.keys && (this.pipeline().get("decoder") as ChannelHandler) !is CustomPacketDecoder) - decoder[this] = this.pipeline().replace("decoder", "decoder", CustomPacketDecoder(player)) - - } - - private fun Channel.uninject() { - if (this in encoder.keys) { - val prevHandler = encoder.remove(this) - val handler = if (prevHandler is PacketEncoder) PacketEncoder(Connection.ATTRIBUTE_CLIENTBOUND_PROTOCOL) else prevHandler - handler?.let { this.pipeline().replace("encoder", "encoder", handler) } - } - - if (this in decoder.keys) { - val prevHandler = decoder.remove(this) - val handler = if (prevHandler is PacketDecoder) PacketDecoder(Connection.ATTRIBUTE_SERVERBOUND_PROTOCOL) else prevHandler - handler?.let { this.pipeline().replace("decoder", "decoder", handler) } - } - } - - override fun inject(player: Player) { - val channel = (player as? CraftPlayer)?.handle?.connection?.connection?.channel ?: return - channel.eventLoop().submit { channel.inject(player) } - } - - override fun uninject(player: Player) { - (player as? CraftPlayer)?.handle?.connection?.connection?.channel?.uninject() - } - - private class CustomDataSerializer(val player: Player?, bytebuf: ByteBuf) : FriendlyByteBuf(bytebuf) { - - override fun writeComponent(component: Component): FriendlyByteBuf { - return super.writeComponent(component.transformEmoteIDs(player, true, true)) - } - - override fun writeComponent(text: net.minecraft.network.chat.Component): FriendlyByteBuf { - if (text is AdventureComponent) return writeComponent(text.deepConverted()) - return writeComponent(PaperAdventure.asAdventure(text).transformEmoteIDs(player, true, false)) - } - - override fun readComponent(): net.minecraft.network.chat.Component { - return PaperAdventure.asVanilla(PaperAdventure.asAdventure(super.readComponentTrusted()).escapeEmoteIDs(player)) - } - - override fun writeUtf(string: String, maxLength: Int): FriendlyByteBuf { - return EmojyNMSHandlers.writeTransformer(player, true, true).invoke(string).let { super.writeUtf(it, maxLength) } - } - - override fun readUtf(maxLength: Int): String { - return super.readUtf(maxLength).let { string -> - runCatching { string.miniMsg() }.recover { legacy.deserialize(string) } - .getOrNull()?.escapeEmoteIDs(player)?.serialize() ?: string - } - } - - override fun writeNbt(compound: Tag?): FriendlyByteBuf { - return super.writeNbt(compound?.apply { - when (this) { - is CompoundTag -> transform(this, EmojyNMSHandlers.writeTransformer(player, false, true)) - is StringTag -> transform(this, EmojyNMSHandlers.writeTransformer(player, false,true)) - } - }) - } - - override fun readNbt(): CompoundTag? { - return super.readNbt()?.apply { - transform(this, EmojyNMSHandlers.readTransformer(player)) - } - } - - private fun transform(compound: CompoundTag, transformer: Function) { - for (key in compound.allKeys) when (val base = compound.get(key)) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> compound.put(key, StringTag.valueOf(transformer.apply(base.asString))) - } - } - - private fun transform(list: ListTag, transformer: Function) { - val listCopy = list.toList() - for (base in listCopy) when (base) { - is CompoundTag -> transform(base, transformer) - is ListTag -> transform(base, transformer) - is StringTag -> list.indexOf(base).let { index -> - list[index] = StringTag.valueOf(transformer.apply(base.asString)) - } - } - } - - private fun transform(string: StringTag, transformer: Function) { - transformer.apply(string.asString) - } - - } - - private class CustomPacketEncoder(val player: Player? = null) : MessageToByteEncoder>() { - private val protocolDirection = PacketFlow.CLIENTBOUND - - override fun encode(ctx: ChannelHandlerContext, msg: Packet<*>, out: ByteBuf) { - val enumProt = ctx.channel()?.attr(Connection.ATTRIBUTE_CLIENTBOUND_PROTOCOL)?.get() ?: throw RuntimeException("ConnectionProtocol unknown: $out") - val packetID = enumProt.protocol().codec(protocolDirection).packetId(msg) - val packetDataSerializer: FriendlyByteBuf = CustomDataSerializer(player, out) - packetDataSerializer.writeVarInt(packetID) - - runCatching { - val int2 = packetDataSerializer.writerIndex() - msg.write(packetDataSerializer) - val int3 = packetDataSerializer.writerIndex() - int2 - if (int3 > 8388608) { - throw IllegalArgumentException("Packet too big (is $int3, should be less than 8388608): $msg") - } - }.onFailure { - if (msg.isSkippable) throw SkipPacketException(it) - throw it - } - } - } - - private class CustomPacketDecoder(val player: Player? = null) : ByteToMessageDecoder() { - - override fun decode(ctx: ChannelHandlerContext, buffer: ByteBuf, out: MutableList) { - val bufferCopy = buffer.copy() - if (buffer.readableBytes() == 0) return - - val customDataSerializer = CustomDataSerializer(player, buffer) - val packetID = customDataSerializer.readVarInt() - val attribute = ctx.channel().attr(Connection.ATTRIBUTE_SERVERBOUND_PROTOCOL) - val packet = attribute.get().createPacket(packetID, customDataSerializer) ?: throw IOException("Bad packet id $packetID") - - out += when { - customDataSerializer.readableBytes() > 0 -> throw IOException("Packet $packetID ($packet) was larger than I expected, found ${customDataSerializer.readableBytes()} bytes extra whilst reading packet $packetID") - packet is ServerboundChatPacket -> { - val baseSerializer = FriendlyByteBuf(bufferCopy) - val basePacketID = baseSerializer.readVarInt() - attribute.get().createPacket(basePacketID, baseSerializer) ?: throw IOException("Bad packet id $basePacketID") - } - else -> packet - } - ProtocolSwapHandler.swapProtocolIfNeeded(attribute, packet) - } - } - - override val supported get() = true -} From e212ab6f3e898bb8069e2576f707b1b21d104b94 Mon Sep 17 00:00:00 2001 From: Boy Date: Thu, 30 May 2024 11:31:22 +0200 Subject: [PATCH 17/18] fix: signed messages not transforming emoteids --- build.gradle.kts | 2 +- .../com/mineinabyss/emojy/EmojyHelpers.kt | 150 +++++++++--------- .../mineinabyss/emojy/nms/EmojyNMSHandlers.kt | 11 -- .../emojy/nms/v1_20_R4/EmojyListener.kt | 21 ++- .../emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 136 +--------------- 5 files changed, 89 insertions(+), 231 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 23ed2f3..60879fe 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -66,7 +66,7 @@ tasks { } runServer { - minecraftVersion("1.20.2") + minecraftVersion("1.20.6") } shadowJar { diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt index 055b78b..67b0de9 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt @@ -9,28 +9,76 @@ import net.kyori.adventure.text.Component import net.kyori.adventure.text.TextReplacementConfig import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer import net.kyori.adventure.translation.GlobalTranslator +import org.bukkit.NamespacedKey import org.bukkit.entity.Player import java.util.* -fun Component.transform(player: Player?, insert: Boolean, unescape: Boolean = true) = player?.let { escapeEmoteIDs(it) } ?: transformEmoteIDs(player, insert, unescape) - -val legacy = LegacyComponentSerializer.legacySection() val spaceRegex: Regex = "(? + + val colorable = colorableRegex in match.value + val bitmapIndex = bitmapIndexRegex.find(match.value)?.groupValues?.get(1)?.toIntOrNull() ?: -1 + + component = component.replaceText( + TextReplacementConfig.builder() + .match(emote.baseRegex.pattern).once() + .replacement( + emote.formattedUnicode( + insert = insert, + colorable = colorable, + bitmapIndex = bitmapIndex + ) + ) + .build() + ) + } + + for (gif in emojy.gifs) gif.baseRegex.findAll(serialized).forEach { _ -> + component = component.replaceText( + TextReplacementConfig.builder() + .match(gif.baseRegex.pattern).once() + .replacement(gif.formattedUnicode(insert = false)) + .build() + ) + } + + spaceRegex.findAll(serialized).forEach { match -> + val space = match.groupValues[1].toIntOrNull() ?: return@forEach + val spaceRegex = "(? if (emote.checkPermission(player)) return@forEach - msg = msg.replaceText( + component = component.replaceText( TextReplacementConfig.builder() .matchLiteral(match.value).once() .replacement("\\${match.value}".miniMsg()) @@ -51,7 +99,7 @@ fun Component.escapeEmoteIDs(player: Player?): Component { for (gif in emojy.gifs) gif.baseRegex.findAll(serialized).forEach { match -> if (gif.checkPermission(player)) return@forEach - msg = msg.replaceText( + component = component.replaceText( TextReplacementConfig.builder() .matchLiteral(match.value).once() .replacement("\\${match.value}".miniMsg()) @@ -63,7 +111,7 @@ fun Component.escapeEmoteIDs(player: Player?): Component { if (player?.hasPermission(SPACE_PERMISSION) != false) return@forEach val space = match.groupValues[1].toIntOrNull() ?: return@forEach - msg = msg.replaceText( + component = component.replaceText( TextReplacementConfig.builder() .matchLiteral(match.value).once() .replacement("\\:space_$space:".miniMsg()) @@ -71,75 +119,33 @@ fun Component.escapeEmoteIDs(player: Player?): Component { ) } - return msg + return component } -/** - * Formats emote-ids in a component to their unicode representation, ignoring escaped emote-ids. - * This is because we handle with a player-context first, and escape that in-which should not be formatted. - */ -fun Component.transformEmoteIDs(player: Player?, insert: Boolean = true, unescape: Boolean): Component { - val locale = emojy.languages.find { it.locale == player?.locale() }?.locale ?: Locale.US - var msg = GlobalTranslator.render(this, locale) +fun Component.unescapeEmoteIds(): Component { + var component = this val serialized = this.serialize() - for (emote in emojy.emotes) { - emote.baseRegex.findAll(serialized).forEach { match -> - - val colorable = colorableRegex in match.value - val bitmapIndex = bitmapIndexRegex.find(match.value)?.groupValues?.get(1)?.toIntOrNull() ?: -1 - - msg = msg.replaceText( - TextReplacementConfig.builder() - .match(emote.baseRegex.pattern).once() - .replacement(emote.formattedUnicode(insert = insert, colorable = colorable, bitmapIndex = bitmapIndex)) - .build() - ) - } - - if (unescape) emote.escapedRegex.findAll(serialized).forEach { match -> - msg = msg.replaceText( - TextReplacementConfig.builder() - .match(emote.escapedRegex.pattern).once() - .replacement(match.value.removePrefix("\\")) - .build() - ) - } - } - - for (gif in emojy.gifs) { - gif.baseRegex.findAll(serialized).forEach { match -> - msg = msg.replaceText( - TextReplacementConfig.builder() - .match(gif.baseRegex.pattern).once() - .replacement(gif.formattedUnicode(insert = insert)) - .build() - ) - } - - if (unescape) gif.escapedRegex.findAll(serialized).forEach { match -> - msg = msg.replaceText( - TextReplacementConfig.builder() - .match(gif.escapedRegex.pattern).once() - .replacement(match.value.removePrefix("\\")) - .build() - ) - } + for (emote in emojy.emotes) emote.escapedRegex.findAll(serialized).forEach { match -> + component = component.replaceText( + TextReplacementConfig.builder() + .match(emote.escapedRegex.pattern).once() + .replacement(match.value.removePrefix("\\")) + .build() + ) } - spaceRegex.findAll(serialized).forEach { match -> - val space = match.groupValues[1].toIntOrNull() ?: return@forEach - val spaceRegex = "(? + component = component.replaceText( TextReplacementConfig.builder() - .match(spaceRegex.pattern).once() - .replacement(spaceComponent(space)) + .match(gif.escapedRegex.pattern).once() + .replacement(match.value.removePrefix("\\")) .build() ) } - if (unescape) escapedSpaceRegex.findAll(serialized).forEach { match -> - msg = msg.replaceText( + escapedSpaceRegex.findAll(serialized).forEach { match -> + component = component.replaceText( TextReplacementConfig.builder() .match(match.value).once() .replacement(match.value.removePrefix("\\")) @@ -147,7 +153,5 @@ fun Component.transformEmoteIDs(player: Player?, insert: Boolean = true, unescap ) } - return msg + return component } - -fun spaceComponent(space: Int) = Component.textOfChildren(Component.text(Space.of(space)).font(emojyConfig.spaceFont)) diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt b/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt index e812c1f..bd7358a 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/nms/EmojyNMSHandlers.kt @@ -1,17 +1,6 @@ package com.mineinabyss.emojy.nms -import com.google.gson.JsonObject -import com.google.gson.JsonParser import com.mineinabyss.emojy.EmojyPlugin -import com.mineinabyss.emojy.escapeEmoteIDs -import com.mineinabyss.emojy.transform -import com.mineinabyss.emojy.transformEmoteIDs -import com.mineinabyss.idofront.textcomponents.miniMsg -import com.mineinabyss.idofront.textcomponents.serialize -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer -import org.bukkit.Bukkit -import org.bukkit.entity.Player object EmojyNMSHandlers { diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt index a05cd2a..ec88073 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyListener.kt @@ -3,15 +3,12 @@ package com.mineinabyss.emojy.nms.v1_20_R4 import com.github.shynixn.mccoroutine.bukkit.launch import com.github.shynixn.mccoroutine.bukkit.ticks import com.jeff_media.morepersistentdatatypes.DataType -import com.mineinabyss.emojy.emojy -import com.mineinabyss.emojy.escapeEmoteIDs -import com.mineinabyss.emojy.nms.v1_20_R4.EmojyNMSHandler.Companion.ORIGINAL_ITEM_RENAME_TEXT -import com.mineinabyss.emojy.nms.v1_20_R4.EmojyNMSHandler.Companion.transformEmotes -import com.mineinabyss.emojy.transformEmoteIDs +import com.mineinabyss.emojy.* import com.mineinabyss.idofront.items.editItemMeta import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize import io.papermc.paper.event.player.AsyncChatDecorateEvent +import io.papermc.paper.event.player.AsyncChatEvent import io.papermc.paper.event.player.PlayerOpenSignEvent import kotlinx.coroutines.delay import net.minecraft.core.BlockPos @@ -39,11 +36,11 @@ class EmojyListener : Listener { val state = (block.state as Sign) val type = DataType.asList(DataType.STRING) val sideLines = lines().map { it.serialize() }.toList() - val frontLines = if (side == Side.FRONT) sideLines else state.persistentDataContainer.getOrDefault(EmojyNMSHandler.ORIGINAL_SIGN_FRONT_LINES, type, mutableListOf("", "", "", "")) - val backLines = if (side == Side.BACK) sideLines else state.persistentDataContainer.getOrDefault(EmojyNMSHandler.ORIGINAL_SIGN_BACK_LINES, type, mutableListOf("", "", "", "")) + val frontLines = if (side == Side.FRONT) sideLines else state.persistentDataContainer.getOrDefault(ORIGINAL_SIGN_FRONT_LINES, type, mutableListOf("", "", "", "")) + val backLines = if (side == Side.BACK) sideLines else state.persistentDataContainer.getOrDefault(ORIGINAL_SIGN_BACK_LINES, type, mutableListOf("", "", "", "")) - state.persistentDataContainer.set(EmojyNMSHandler.ORIGINAL_SIGN_FRONT_LINES, type, frontLines) - state.persistentDataContainer.set(EmojyNMSHandler.ORIGINAL_SIGN_BACK_LINES, type, backLines) + state.persistentDataContainer.set(ORIGINAL_SIGN_FRONT_LINES, type, frontLines) + state.persistentDataContainer.set(ORIGINAL_SIGN_BACK_LINES, type, backLines) state.update(true) lines().forEachIndexed { index, s -> @@ -56,8 +53,8 @@ class EmojyListener : Listener { if (cause == PlayerOpenSignEvent.Cause.PLACE) return sign.persistentDataContainer.get(when (sign.getInteractableSideFor(player)) { - Side.FRONT -> EmojyNMSHandler.ORIGINAL_SIGN_FRONT_LINES - Side.BACK -> EmojyNMSHandler.ORIGINAL_SIGN_BACK_LINES + Side.FRONT -> ORIGINAL_SIGN_FRONT_LINES + Side.BACK -> ORIGINAL_SIGN_BACK_LINES }, DataType.asList(DataType.STRING))?.forEachIndexed { index, s -> sign.getSide(side).line(index, s.miniMsg()) } @@ -78,7 +75,7 @@ class EmojyListener : Listener { result?.editItemMeta { persistentDataContainer.remove(ORIGINAL_ITEM_RENAME_TEXT) } return } - val displayName = inventory.renameText?.miniMsg()?.transformEmoteIDs(null, false, true) ?: run { + val displayName = inventory.renameText?.miniMsg()?.transformEmotes(null, false)?.unescapeEmoteIds() ?: run { result?.editItemMeta { persistentDataContainer.remove(ORIGINAL_ITEM_RENAME_TEXT) } return } diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index d5660ff..2a65682 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -7,6 +7,7 @@ import com.mineinabyss.emojy.* import com.mineinabyss.emojy.config.SPACE_PERMISSION import com.mineinabyss.emojy.nms.IEmojyNMSHandler import com.mineinabyss.idofront.items.editItemMeta +import com.mineinabyss.idofront.messaging.logVal import com.mineinabyss.idofront.plugin.listeners import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize @@ -59,6 +60,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { override fun write(ctx: ChannelHandlerContext, packet: Any, promise: ChannelPromise) { ctx.write( when (packet) { + is ClientboundPlayerChatPacket -> ClientboundPlayerChatPacket(packet.sender, packet.index, packet.signature, packet.body, packet.unsignedContent?.transformEmotes(connection.locale(), true)?.unescapeEmoteIds(), packet.filterMask, packet.chatType) is ClientboundDisguisedChatPacket -> ClientboundDisguisedChatPacket(packet.message.transformEmotes(connection.locale(), true).unescapeEmoteIds(), packet.chatType) is ClientboundSystemChatPacket -> ClientboundSystemChatPacket(packet.content.transformEmotes(connection.locale(), true).unescapeEmoteIds(), packet.overlay) is ClientboundSetTitleTextPacket -> ClientboundSetTitleTextPacket(packet.text.transformEmotes(connection.locale())) @@ -101,10 +103,6 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { companion object { - val ORIGINAL_SIGN_FRONT_LINES = NamespacedKey.fromString("emojy:original_front_lines")!! - val ORIGINAL_SIGN_BACK_LINES = NamespacedKey.fromString("emojy:original_back_lines")!! - val ORIGINAL_ITEM_RENAME_TEXT = NamespacedKey.fromString("emojy:original_item_rename")!! - fun String.transformEmotes(locale: Locale? = null, insert: Boolean = false): String { return miniMsg().transformEmotes(locale, insert).serialize() } @@ -113,52 +111,6 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).transformEmotes(locale, insert)) } - fun Component.transformEmotes(locale: Locale? = null, insert: Boolean = false): Component { - var component = GlobalTranslator.render(this, locale ?: Locale.US) - val serialized = this.serialize() - - for (emote in emojy.emotes) emote.baseRegex.findAll(serialized).forEach { match -> - - val colorable = colorableRegex in match.value - val bitmapIndex = bitmapIndexRegex.find(match.value)?.groupValues?.get(1)?.toIntOrNull() ?: -1 - - component = component.replaceText( - TextReplacementConfig.builder() - .match(emote.baseRegex.pattern).once() - .replacement( - emote.formattedUnicode( - insert = insert, - colorable = colorable, - bitmapIndex = bitmapIndex - ) - ) - .build() - ) - } - - for (gif in emojy.gifs) gif.baseRegex.findAll(serialized).forEach { _ -> - component = component.replaceText( - TextReplacementConfig.builder() - .match(gif.baseRegex.pattern).once() - .replacement(gif.formattedUnicode(insert = false)) - .build() - ) - } - - spaceRegex.findAll(serialized).forEach { match -> - val space = match.groupValues[1].toIntOrNull() ?: return@forEach - val spaceRegex = "(? - if (emote.checkPermission(player)) return@forEach - - component = component.replaceText( - TextReplacementConfig.builder() - .matchLiteral(match.value).once() - .replacement("\\${match.value}".miniMsg()) - .build() - ) - } - - for (gif in emojy.gifs) gif.baseRegex.findAll(serialized).forEach { match -> - if (gif.checkPermission(player)) return@forEach - component = component.replaceText( - TextReplacementConfig.builder() - .matchLiteral(match.value).once() - .replacement("\\${match.value}".miniMsg()) - .build() - ) - } - - spaceRegex.findAll(serialized).forEach { match -> - if (player?.hasPermission(SPACE_PERMISSION) != false) return@forEach - val space = match.groupValues[1].toIntOrNull() ?: return@forEach - - component = component.replaceText( - TextReplacementConfig.builder() - .matchLiteral(match.value).once() - .replacement("\\:space_$space:".miniMsg()) - .build() - ) - } - - return component - } - fun net.minecraft.network.chat.Component.unescapeEmoteIds(): net.minecraft.network.chat.Component { return PaperAdventure.asVanilla(PaperAdventure.asAdventure(this).unescapeEmoteIds()) } - fun Component.unescapeEmoteIds(): Component { - var component = this - val serialized = this.serialize() - - for (emote in emojy.emotes) emote.escapedRegex.findAll(serialized).forEach { match -> - component = component.replaceText( - TextReplacementConfig.builder() - .match(emote.escapedRegex.pattern).once() - .replacement(match.value.removePrefix("\\")) - .build() - ) - } - - for (gif in emojy.gifs) gif.escapedRegex.findAll(serialized).forEach { match -> - component = component.replaceText( - TextReplacementConfig.builder() - .match(gif.escapedRegex.pattern).once() - .replacement(match.value.removePrefix("\\")) - .build() - ) - } - - escapedSpaceRegex.findAll(serialized).forEach { match -> - component = component.replaceText( - TextReplacementConfig.builder() - .match(match.value).once() - .replacement(match.value.removePrefix("\\")) - .build() - ) - } - return component - } } override val supported get() = true From a8e6e0ec125fa1d98096124bc2373979e4de0dbc Mon Sep 17 00:00:00 2001 From: Boy Date: Thu, 30 May 2024 11:48:26 +0200 Subject: [PATCH 18/18] fix: transform emotes not based on translated component --- core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt | 2 +- .../com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt index 67b0de9..6b9a6e1 100644 --- a/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt +++ b/core/src/main/kotlin/com/mineinabyss/emojy/EmojyHelpers.kt @@ -26,7 +26,7 @@ fun spaceComponent(space: Int) = Component.textOfChildren(Component.text(Space.o fun Component.transformEmotes(locale: Locale? = null, insert: Boolean = false): Component { var component = GlobalTranslator.render(this, locale ?: Locale.US) - val serialized = this.serialize() + val serialized = component.serialize() for (emote in emojy.emotes) emote.baseRegex.findAll(serialized).forEach { match -> diff --git a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt index 2a65682..0b86c85 100644 --- a/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt +++ b/v1_20_R4/src/main/kotlin/com/mineinabyss/emojy/nms/v1_20_R4/EmojyNMSHandler.kt @@ -71,7 +71,7 @@ class EmojyNMSHandler(emojy: EmojyPlugin) : IEmojyNMSHandler { is ClientboundSetEntityDataPacket -> ClientboundSetEntityDataPacket(packet.id, packet.packedItems.map { (it.value as? AdventureComponent)?.let { value -> SynchedEntityData.DataValue(it.id, it.serializer as EntityDataSerializer, - AdventureComponent(PaperAdventure.asAdventure(value).transformEmotes(connection.locale())) + AdventureComponent(value.`adventure$component`().transformEmotes(connection.locale())) ) } ?: it })