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 124f1cd..838746a 100644 --- a/src/main/kotlin/cn/rtast/fancybot/commands/misc/MinecraftCommand.kt +++ b/src/main/kotlin/cn/rtast/fancybot/commands/misc/MinecraftCommand.kt @@ -613,6 +613,10 @@ class MCBotCommand : BaseCommand() { val action = args.first() when (action) { "start" -> { + if (userClientMap.containsKey(message.sender.userId)) { + message.reply("你有一个正在进行的任务不能开启另外一个任务请先使用`/mcbot cancel`取消任务") + return + } val address = args[1] val host = address.split(":").first() val port = address.split(":").last().toInt() diff --git a/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCClient.kt b/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCClient.kt index 5d3b517..945f2f1 100644 --- a/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCClient.kt +++ b/src/main/kotlin/cn/rtast/fancybot/util/mcbot/MCClient.kt @@ -15,18 +15,29 @@ import org.geysermc.mcprotocollib.network.tcp.TcpClientSession import org.geysermc.mcprotocollib.protocol.MinecraftProtocol import org.geysermc.mcprotocollib.protocol.data.game.ClientCommand import org.geysermc.mcprotocollib.protocol.data.game.ResourcePackStatus +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundResourcePackPushPacket import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundResourcePackPacket import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerChatPacket import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundSystemChatPacket +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundDamageEventPacket +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundMoveEntityPosPacket import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerCombatKillPacket import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerRotPacket import java.time.Instant import java.util.BitSet +import java.util.Timer +import java.util.TimerTask +import kotlin.math.pow +import kotlin.math.sqrt +import kotlin.random.Random class MCClient( private val serverHost: String, @@ -35,6 +46,8 @@ class MCClient( ) { private lateinit var client: TcpClientSession private val logger = Logger.getLogger() + private val timer = Timer() + private val entitiesId = mutableMapOf>() fun createClient(): TcpClientSession { val protocol = MinecraftProtocol(botName) @@ -45,29 +58,86 @@ class MCClient( fun runBot(): MCClient { client.addListener(object : SessionAdapter() { override fun packetReceived(session: Session, packet: Packet) { - if (packet is ClientboundResourcePackPushPacket) { - val loadedPacket = ServerboundResourcePackPacket(packet.id, ResourcePackStatus.SUCCESSFULLY_LOADED) - session.send(loadedPacket) - } - if (packet is ClientboundPlayerPositionPacket) { - session.send(ServerboundAcceptTeleportationPacket(packet.teleportId)); - } - if (packet is ClientboundSystemChatPacket) { - logger.trace("系统 >>> {}", packet.content) - } - if (packet is ClientboundPlayerChatPacket) { - logger.trace("{} >>> {}", packet.name, packet.content) - } - if (packet is ClientboundPlayerCombatKillPacket) { - logger.info("Bot已死亡自动复活中") - session.send(ServerboundClientCommandPacket(ClientCommand.RESPAWN)) + when (packet) { + is ClientboundResourcePackPushPacket -> { + val loadedPacket = + ServerboundResourcePackPacket(packet.id, ResourcePackStatus.SUCCESSFULLY_LOADED) + session.send(loadedPacket) + } + + is ClientboundPlayerPositionPacket -> { + session.send(ServerboundAcceptTeleportationPacket(packet.teleportId)); + } + + is ClientboundSystemChatPacket -> { + logger.trace("系统 >>> {}", packet.content) + } + + is ClientboundPlayerChatPacket -> { + logger.trace("{} >>> {}", packet.name, packet.content) + } + + is ClientboundPlayerCombatKillPacket -> { + logger.info("Bot: $botName 死亡, 已自动复活") + session.send(ServerboundClientCommandPacket(ClientCommand.RESPAWN)) + } + + is ClientboundDamageEventPacket -> { + session.send( + ServerboundMovePlayerRotPacket( + true, + Random.nextInt(-90, 90).toFloat(), + Random.nextInt(-90, 90).toFloat() + ) + ) + } + + is ClientboundMoveEntityPosPacket -> { + val entityId = packet.entityId + val x = packet.moveX + val y = packet.moveY + val z = packet.moveZ + entitiesId[entityId] = Triple(x, y, z) + } } } }) client.connect() + timer.scheduleAtFixedRate(object : TimerTask() { + override fun run() { + if (client.isConnected) { + entitiesId.forEach { + val x = it.value.first + val y = it.value.second + val z = it.value.third + val entityId = it.key + if (isWithinRange(x, y, z)) { + attackEntity(entityId) + } else { + entitiesId.remove(entityId) + } + } + } + } + }, 1000L, 1000L) return this } + private fun isWithinRange(x: Double, y: Double, z: Double): Boolean { + val playerX = 0.0 + val playerY = 0.0 + val playerZ = 0.0 + val distance = sqrt((x - playerX).pow(2) + (y - playerY).pow(2) + (z - playerZ).pow(2)) + return distance <= 5 + } + + + private fun attackEntity(entityId: Int) { + val attackPacket = + ServerboundInteractPacket(entityId, InteractAction.ATTACK, Hand.entries.random(), Random.nextBoolean()) + client.send(attackPacket) + } + private fun sendMessage(content: String) = client.send(ServerboundChatPacket(content, Instant.now().toEpochMilli(), 0L, null, 0, BitSet()))