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 -}