diff --git a/build.gradle.kts b/build.gradle.kts index c918abd..844f009 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,6 +15,7 @@ version = fancyBotVersion repositories { mavenCentral() mavenLocal() + maven("https://repo.opencollab.dev/main/") maven("https://oss.sonatype.org/content/repositories/snapshots") maven("https://repo.rtast.cn/api/v4/projects/33/packages/maven") maven("https://repo.rtast.cn/api/v4/projects/19/packages/maven") @@ -51,6 +52,7 @@ dependencies { implementation(libs.slf4j.api) implementation(libs.aws.s3.sdk) implementation(libs.rconlib) + implementation("org.geysermc.mcprotocollib:protocol:1.21-SNAPSHOT") } tasks.build { diff --git a/src/main/kotlin/cn/rtast/fancybot/Const.kt b/src/main/kotlin/cn/rtast/fancybot/Const.kt index f1bf8eb..c7f1def 100644 --- a/src/main/kotlin/cn/rtast/fancybot/Const.kt +++ b/src/main/kotlin/cn/rtast/fancybot/Const.kt @@ -140,5 +140,5 @@ val commands = listOf( MinecraftWikiCommand(), GaoKaoDaysRemainCommand(), IdiomExplainCommand(), NiuziManagerCommand(), TodayEatCommand(), TodayDrinkCommand(), MCLoginCommand(), RCONCommand(), GravatarCommand(), PastebinCommand(), ShuffleEchoCommand(), TodayDontEatCommand(), - TodayDontDrinkCommand() + TodayDontDrinkCommand(), MCBotCommand() ) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/misc/MinecraftCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/misc/MinecraftCommand.kt index bee1abe..215f586 100644 --- a/src/main/kotlin/cn/rtast/fancybot/commands/misc/MinecraftCommand.kt +++ b/src/main/kotlin/cn/rtast/fancybot/commands/misc/MinecraftCommand.kt @@ -4,7 +4,7 @@ * Date: 2024/10/9 */ -@file:Suppress("KDocUnresolvedReference") +@file:Suppress("KDocUnresolvedReference", "unused") package cn.rtast.fancybot.commands.misc @@ -30,6 +30,8 @@ import cn.rtast.fancybot.enums.mc.MCVersionType import cn.rtast.fancybot.rconManager import cn.rtast.fancybot.util.Http import cn.rtast.fancybot.util.Logger +import cn.rtast.fancybot.util.mcbot.MCBot +import cn.rtast.fancybot.util.mcbot.MCClient import cn.rtast.fancybot.util.misc.isFullyTransparent import cn.rtast.fancybot.util.misc.scaleImage import cn.rtast.fancybot.util.misc.toByteArray @@ -38,11 +40,11 @@ import cn.rtast.fancybot.util.str.convertToHTML import cn.rtast.fancybot.util.str.decodeToString import cn.rtast.fancybot.util.str.encodeToBase64 import cn.rtast.fancybot.util.str.fromJson +import cn.rtast.fancybot.util.str.generateRandomString import cn.rtast.fancybot.util.str.toJson import cn.rtast.fancybot.util.str.uriEncode import cn.rtast.motdpinger.BedrockPing import cn.rtast.motdpinger.JavaPing -import cn.rtast.rcon.RCon import cn.rtast.rcon.exceptions.AuthFailedException import cn.rtast.rob.entity.GroupMessage import cn.rtast.rob.entity.PrivateMessage @@ -52,13 +54,15 @@ import cn.rtast.rob.util.ob.OneBotListener import cn.rtast.rob.util.ob.asMessageChain import cn.rtast.rob.util.ob.asNode import okhttp3.FormBody +import org.geysermc.mcprotocollib.network.tcp.TcpClientSession import java.awt.AlphaComposite import java.awt.Color import java.awt.image.BufferedImage import java.net.SocketException import java.net.URI -import java.util.Random +import java.util.concurrent.Executors import javax.imageio.ImageIO +import kotlin.random.Random @CommandDescription("获取MC最新的版本!") class MCVersionCommand : BaseCommand() { @@ -593,4 +597,46 @@ class RCONCommand : BaseCommand() { } } } +} + +class MCBotCommand : BaseCommand() { + override val commandNames = listOf("/mcbot") + + private val userClientMap = mutableMapOf>() + + override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List) { + val clients = mutableListOf() + val action = args.first() + when (action) { + "s" -> { + val executor = Executors.newFixedThreadPool(100) + val host = args[1] + val port = args[2].toInt() + val count = args[3].toInt() + val msgContent = args.drop(4).joinToString(" ").trim() + val delay = if (args.size == 5) 2000L else args[5].toLong() + val continueSendMessage = msgContent.contains("!!while!!") + (1..count).forEach { + val botName = generateRandomString() + val client = MCClient(host, port, botName).createClient() + clients.add(client) + } + clients.forEach { + executor.execute { + val bot = MCBot(msgContent.replace("!!while!!", ""), continueSendMessage, delay, it) + bot.run() + } + } + userClientMap[message.sender.userId] = clients + } + + "c" -> { + if (userClientMap.containsKey(message.sender.userId)) { + userClientMap[message.sender.userId]!!.forEach { it.disconnect("Bye~") } + userClientMap.remove(message.sender.userId) + message.reply("成功取消任务") + } + } + } + } } \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCBot.kt b/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCBot.kt new file mode 100644 index 0000000..52f724f --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCBot.kt @@ -0,0 +1,55 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/10/17 + */ + + +package cn.rtast.fancybot.util.mcbot + +import org.geysermc.mcprotocollib.network.Session +import org.geysermc.mcprotocollib.network.event.session.SessionAdapter +import org.geysermc.mcprotocollib.network.packet.Packet +import org.geysermc.mcprotocollib.network.tcp.TcpClientSession +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket +import java.time.Instant +import java.util.BitSet + +class MCBot( + private val content: String = "FancyBot喵~", + private val continueSendMessage: Boolean = false, + private val sendDelay: Long = 2000L, + private val client: TcpClientSession +) : Runnable { + + private fun sendMessage() = + client.send(ServerboundChatPacket(content, Instant.now().toEpochMilli(), 0L, null, 0, BitSet())) + + override fun run() { + client.addListener(object : SessionAdapter() { + override fun packetReceived(session: Session, packet: Packet) { + if (packet is ClientboundLoginPacket) { + if (continueSendMessage) { + while (true) { + try { + sendMessage() + Thread.sleep(sendDelay) + } catch (_: InterruptedException) { + Thread.currentThread().interrupt() + } + } + } else { + sendMessage() + } + } else if (packet is ClientboundPlayerPositionPacket) { + val p = packet + client.send(ServerboundAcceptTeleportationPacket(p.teleportId)); + } + } + }) + client.connect() + } +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCClient.kt b/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCClient.kt new file mode 100644 index 0000000..897710a --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCClient.kt @@ -0,0 +1,23 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/10/17 + */ + + +package cn.rtast.fancybot.util.mcbot + +import org.geysermc.mcprotocollib.network.tcp.TcpClientSession +import org.geysermc.mcprotocollib.protocol.MinecraftProtocol + +class MCClient( + private val serverHost: String, + private val serverPort: Int, + private val botName: String +) { + fun createClient(): TcpClientSession { + val protocol = MinecraftProtocol(botName) + val client = TcpClientSession(serverHost, serverPort, protocol) + return client + } +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/str/String.kt b/src/main/kotlin/cn/rtast/fancybot/util/str/String.kt new file mode 100644 index 0000000..de9c97c --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/util/str/String.kt @@ -0,0 +1,18 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/10/18 + */ + + +package cn.rtast.fancybot.util.str + +import kotlin.random.Random + +fun generateRandomString(): String { + val allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" + val nameLength = Random.nextInt(3, 17) + return (1..nameLength) + .map { allowedChars.random() } + .joinToString("") +} \ No newline at end of file