From b8a45b9a0438a12ba3c609f6e416d519829471be Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Mon, 12 Aug 2024 22:15:07 +0200 Subject: Improve location and profile detection --- src/main/kotlin/moe/nea/firmament/Firmament.kt | 2 - .../apis/ingame/FirmamentCustomPayload.kt | 31 ----- .../moe/nea/firmament/apis/ingame/HypixelModAPI.kt | 51 -------- .../firmament/apis/ingame/InGameCodecWrapper.kt | 48 -------- .../firmament/apis/ingame/JoinedCustomPayload.kt | 20 --- .../apis/ingame/packets/PartyInfoRequest.kt | 134 --------------------- .../events/FirmamentCustomPayloadEvent.kt | 10 -- .../nea/firmament/events/ServerConnectedEvent.kt | 18 +++ src/main/kotlin/moe/nea/firmament/util/SBData.kt | 101 ++++++---------- 9 files changed, 52 insertions(+), 363 deletions(-) delete mode 100644 src/main/kotlin/moe/nea/firmament/apis/ingame/FirmamentCustomPayload.kt delete mode 100644 src/main/kotlin/moe/nea/firmament/apis/ingame/HypixelModAPI.kt delete mode 100644 src/main/kotlin/moe/nea/firmament/apis/ingame/InGameCodecWrapper.kt delete mode 100644 src/main/kotlin/moe/nea/firmament/apis/ingame/JoinedCustomPayload.kt delete mode 100644 src/main/kotlin/moe/nea/firmament/apis/ingame/packets/PartyInfoRequest.kt delete mode 100644 src/main/kotlin/moe/nea/firmament/events/FirmamentCustomPayloadEvent.kt create mode 100644 src/main/kotlin/moe/nea/firmament/events/ServerConnectedEvent.kt (limited to 'src/main/kotlin/moe/nea/firmament') diff --git a/src/main/kotlin/moe/nea/firmament/Firmament.kt b/src/main/kotlin/moe/nea/firmament/Firmament.kt index 400dcf2..c1801f4 100644 --- a/src/main/kotlin/moe/nea/firmament/Firmament.kt +++ b/src/main/kotlin/moe/nea/firmament/Firmament.kt @@ -113,8 +113,6 @@ object Firmament { ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance -> TickEvent.publish(TickEvent(tick++)) }) - // TODO: remove me - Class.forName(SectionBuilder::class.java.name) IDataHolder.registerEvents() RepoManager.initialize() SBData.init() diff --git a/src/main/kotlin/moe/nea/firmament/apis/ingame/FirmamentCustomPayload.kt b/src/main/kotlin/moe/nea/firmament/apis/ingame/FirmamentCustomPayload.kt deleted file mode 100644 index 10af7d0..0000000 --- a/src/main/kotlin/moe/nea/firmament/apis/ingame/FirmamentCustomPayload.kt +++ /dev/null @@ -1,31 +0,0 @@ - -package moe.nea.firmament.apis.ingame - -import io.netty.buffer.ByteBuf -import net.minecraft.network.codec.PacketCodec -import net.minecraft.network.packet.CustomPayload -import net.minecraft.util.Identifier - -interface FirmamentCustomPayload : CustomPayload { - - class Unhandled private constructor(val identifier: Identifier) : FirmamentCustomPayload { - override fun getId(): CustomPayload.Id { - return CustomPayload.id(identifier.toString()) - } - - companion object { - fun createCodec(identifier: Identifier): PacketCodec { - return object : PacketCodec { - override fun decode(buf: B): Unhandled { - return Unhandled(identifier) - } - - override fun encode(buf: B, value: Unhandled) { - // we will never send an unhandled packet stealthy - } - } - } - } - - } -} diff --git a/src/main/kotlin/moe/nea/firmament/apis/ingame/HypixelModAPI.kt b/src/main/kotlin/moe/nea/firmament/apis/ingame/HypixelModAPI.kt deleted file mode 100644 index fb01a2f..0000000 --- a/src/main/kotlin/moe/nea/firmament/apis/ingame/HypixelModAPI.kt +++ /dev/null @@ -1,51 +0,0 @@ - -package moe.nea.firmament.apis.ingame - -import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket -import net.minecraft.text.Text -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.apis.ingame.packets.PartyInfoRequest -import moe.nea.firmament.apis.ingame.packets.PartyInfoResponse -import moe.nea.firmament.commands.thenExecute -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.events.FirmamentCustomPayloadEvent -import moe.nea.firmament.events.subscription.SubscriptionOwner -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.features.debug.DeveloperFeatures -import moe.nea.firmament.util.MC - - -object HypixelModAPI : SubscriptionOwner { - init { - InGameCodecWrapper.Direction.C2S.customCodec = - InGameCodecWrapper.createStealthyCodec( - PartyInfoRequest.intoType() - ) - InGameCodecWrapper.Direction.S2C.customCodec = - InGameCodecWrapper.createStealthyCodec( - PartyInfoResponse.intoType() - ) - } - - @JvmStatic - fun sendRequest(packet: FirmamentCustomPayload) { - MC.networkHandler?.sendPacket(CustomPayloadC2SPacket(packet)) - } - - @Subscribe - fun testCommand(event: CommandEvent.SubCommand) { - event.subcommand("sendpartyrequest") { - thenExecute { - sendRequest(PartyInfoRequest(1)) - } - } - } - - @Subscribe - fun logEvents(event: FirmamentCustomPayloadEvent) { - MC.sendChat(Text.stringifiedTranslatable("firmament.modapi.event", event.toString())) - } - - override val delegateFeature: FirmamentFeature - get() = DeveloperFeatures -} diff --git a/src/main/kotlin/moe/nea/firmament/apis/ingame/InGameCodecWrapper.kt b/src/main/kotlin/moe/nea/firmament/apis/ingame/InGameCodecWrapper.kt deleted file mode 100644 index 1a4710f..0000000 --- a/src/main/kotlin/moe/nea/firmament/apis/ingame/InGameCodecWrapper.kt +++ /dev/null @@ -1,48 +0,0 @@ - -package moe.nea.firmament.apis.ingame - -import net.minecraft.network.PacketByteBuf -import net.minecraft.network.codec.PacketCodec -import net.minecraft.network.packet.CustomPayload - -class InGameCodecWrapper( - val wrapped: PacketCodec, - val direction: Direction, -) : PacketCodec { - enum class Direction { - S2C, - C2S, - ; - - var customCodec: PacketCodec = createStealthyCodec() - } - - companion object { - fun createStealthyCodec(vararg codecs: CustomPayload.Type): PacketCodec { - return CustomPayload.createCodec( - { FirmamentCustomPayload.Unhandled.createCodec(it) }, - codecs.toList() - ) as PacketCodec - } - - } - - override fun decode(buf: PacketByteBuf): CustomPayload { - val duplicateBuffer = PacketByteBuf(buf.slice()) - val original = wrapped.decode(buf) - buf.skipBytes(buf.readableBytes()) - val duplicate = runCatching { direction.customCodec.decode(duplicateBuffer) } - .getOrNull() - if (duplicate is FirmamentCustomPayload.Unhandled || duplicate == null) - return original - return JoinedCustomPayload(original, duplicate) - } - - override fun encode(buf: PacketByteBuf, value: CustomPayload) { - if (value is FirmamentCustomPayload) { - direction.customCodec.encode(buf, value) - } else { - wrapped.encode(buf, value) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/apis/ingame/JoinedCustomPayload.kt b/src/main/kotlin/moe/nea/firmament/apis/ingame/JoinedCustomPayload.kt deleted file mode 100644 index 4b6a6bc..0000000 --- a/src/main/kotlin/moe/nea/firmament/apis/ingame/JoinedCustomPayload.kt +++ /dev/null @@ -1,20 +0,0 @@ - -package moe.nea.firmament.apis.ingame - -import net.minecraft.network.packet.CustomPayload - -/** - * A class to smuggle two parsed instances of the same custom payload packet. - */ -class JoinedCustomPayload( - val original: CustomPayload, - val smuggled: FirmamentCustomPayload -) : CustomPayload { - companion object { - val joinedId = CustomPayload.id("firmament:joined") - } - - override fun getId(): CustomPayload.Id { - return joinedId - } -} diff --git a/src/main/kotlin/moe/nea/firmament/apis/ingame/packets/PartyInfoRequest.kt b/src/main/kotlin/moe/nea/firmament/apis/ingame/packets/PartyInfoRequest.kt deleted file mode 100644 index a1b4a71..0000000 --- a/src/main/kotlin/moe/nea/firmament/apis/ingame/packets/PartyInfoRequest.kt +++ /dev/null @@ -1,134 +0,0 @@ - -package moe.nea.firmament.apis.ingame.packets - -import io.netty.buffer.ByteBuf -import java.util.UUID -import net.minecraft.network.PacketByteBuf -import net.minecraft.network.codec.PacketCodec -import net.minecraft.network.codec.PacketCodecs -import net.minecraft.network.packet.CustomPayload -import net.minecraft.util.Identifier -import net.minecraft.util.Uuids -import moe.nea.firmament.apis.ingame.FirmamentCustomPayload - -interface FirmamentCustomPayloadMeta { - val ID: CustomPayload.Id - val CODEC: PacketCodec - - fun id(name: String): CustomPayload.Id { - return CustomPayload.Id(Identifier.of(name)) - } - - fun intoType(): CustomPayload.Type { - return CustomPayload.Type(ID, CODEC) - } -} - -data class PartyInfoRequest(val version: Int) : FirmamentCustomPayload { - companion object : FirmamentCustomPayloadMeta { - override val ID = id("hypixel:party_info") - override val CODEC = - PacketCodecs.VAR_INT.cast() - .xmap(::PartyInfoRequest, PartyInfoRequest::version) - } - - override fun getId(): CustomPayload.Id { - return ID - } -} - -sealed interface PartyInfoResponseV -sealed interface HypixelVersionedPacketData -data class HypixelSuccessfulResponse(val data: T) : HypixelVersionedPacketData -data class HypixelUnknownVersion(val version: Int) : HypixelVersionedPacketData -data class HypixelApiError(val label: String, val errorId: Int) : HypixelVersionedPacketData { - companion object { - fun createCodec(label: String): PacketCodec { - return PacketCodecs.VAR_INT - .cast() - .xmap({ HypixelApiError(label, it) }, HypixelApiError::errorId) - } - } -} - -object CodecUtils { - fun dispatchVersioned( - versions: Map>, - errorCodec: PacketCodec - ): PacketCodec> { - return object : PacketCodec> { - override fun decode(buf: B): HypixelVersionedPacketData { - if (!buf.readBoolean()) { - return errorCodec.decode(buf) - } - val version = buf.readVarInt() - val versionCodec = versions[version] - ?: return HypixelUnknownVersion(version) - return HypixelSuccessfulResponse(versionCodec.decode(buf)) - } - - override fun encode(buf: B, value: HypixelVersionedPacketData?) { - error("Cannot encode a hypixel packet") - } - } - } - - fun dispatchS2CBoolean( - ifTrue: PacketCodec, - ifFalse: PacketCodec - ): PacketCodec { - return object : PacketCodec { - override fun decode(buf: B): T { - return if (buf.readBoolean()) { - ifTrue.decode(buf) - } else { - ifFalse.decode(buf) - } - } - - override fun encode(buf: B, value: T) { - error("Cannot reverse dispatch boolean") - } - } - } - -} - - -data object PartyInfoResponseVUnknown : PartyInfoResponseV -data class PartyInfoResponseV1( - val leader: UUID?, - val members: Set, -) : PartyInfoResponseV { - data object PartyMember - companion object { - val CODEC: PacketCodec = - CodecUtils.dispatchS2CBoolean( - PacketCodec.tuple( - Uuids.PACKET_CODEC, PartyInfoResponseV1::leader, - Uuids.PACKET_CODEC.collect(PacketCodecs.toCollection(::HashSet)), PartyInfoResponseV1::members, - ::PartyInfoResponseV1 - ), - PacketCodec.unit(PartyInfoResponseV1(null, setOf()))) - } -} - - -data class PartyInfoResponse(val data: HypixelVersionedPacketData) : FirmamentCustomPayload { - companion object : FirmamentCustomPayloadMeta { - override val ID = id("hypixel:party_info") - override val CODEC = - CodecUtils - .dispatchVersioned( - mapOf( - 1 to PartyInfoResponseV1.CODEC, - ), - HypixelApiError.createCodec("PartyInfoResponse")) - .xmap(::PartyInfoResponse, PartyInfoResponse::data) - - } - - override fun getId(): CustomPayload.Id { - return ID - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/FirmamentCustomPayloadEvent.kt b/src/main/kotlin/moe/nea/firmament/events/FirmamentCustomPayloadEvent.kt deleted file mode 100644 index 779ca51..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/FirmamentCustomPayloadEvent.kt +++ /dev/null @@ -1,10 +0,0 @@ - -package moe.nea.firmament.events - -import moe.nea.firmament.apis.ingame.FirmamentCustomPayload - -data class FirmamentCustomPayloadEvent( - val payload: FirmamentCustomPayload -) : FirmamentEvent() { - companion object : FirmamentEventBus() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ServerConnectedEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ServerConnectedEvent.kt new file mode 100644 index 0000000..26897f2 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/events/ServerConnectedEvent.kt @@ -0,0 +1,18 @@ +package moe.nea.firmament.events + +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents +import net.minecraft.client.MinecraftClient +import net.minecraft.client.network.ClientPlayNetworkHandler +import net.minecraft.network.ClientConnection + +data class ServerConnectedEvent( + val connection: ClientConnection +) : FirmamentEvent() { + companion object : FirmamentEventBus() { + init { + ClientPlayConnectionEvents.INIT.register(ClientPlayConnectionEvents.Init { clientPlayNetworkHandler: ClientPlayNetworkHandler, minecraftClient: MinecraftClient -> + publishSync(ServerConnectedEvent(clientPlayNetworkHandler.connection)) + }) + } + } +} diff --git a/src/main/kotlin/moe/nea/firmament/util/SBData.kt b/src/main/kotlin/moe/nea/firmament/util/SBData.kt index 797cc0a..b30c6fb 100644 --- a/src/main/kotlin/moe/nea/firmament/util/SBData.kt +++ b/src/main/kotlin/moe/nea/firmament/util/SBData.kt @@ -1,37 +1,53 @@ - - package moe.nea.firmament.util -import kotlinx.serialization.SerializationException -import kotlinx.serialization.decodeFromString -import moe.nea.firmament.Firmament -import moe.nea.firmament.events.OutgoingPacketEvent +import java.util.UUID +import net.hypixel.modapi.HypixelModAPI +import net.hypixel.modapi.packet.impl.clientbound.event.ClientboundLocationPacket +import kotlin.jvm.optionals.getOrNull +import kotlin.time.Duration.Companion.seconds +import moe.nea.firmament.events.AllowChatEvent import moe.nea.firmament.events.ProcessChatEvent +import moe.nea.firmament.events.ServerConnectedEvent import moe.nea.firmament.events.SkyblockServerUpdateEvent import moe.nea.firmament.events.WorldReadyEvent -import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket -import java.util.* -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds object SBData { private val profileRegex = "Profile ID: ([a-z0-9\\-]+)".toRegex() + val profileSuggestTexts = listOf( + "CLICK THIS TO SUGGEST IT IN CHAT [DASHES]", + "CLICK THIS TO SUGGEST IT IN CHAT [NO DASHES]", + ) var profileId: UUID? = null - private var lastLocrawSent = Timer() - private val anyLocrawSent = Timer() - private val locrawRoundtripTime: Duration = 5.seconds private var hasReceivedProfile = false - private var hasSentLocraw = false var locraw: Locraw? = null val skyblockLocation: SkyBlockIsland? get() = locraw?.skyblockLocation val hasValidLocraw get() = locraw?.server !in listOf("limbo", null) val isOnSkyblock get() = locraw?.gametype == "SKYBLOCK" - + var lastProfileIdRequest = TimeMark.farPast() fun init() { - OutgoingPacketEvent.subscribe { event -> - if (event.packet is CommandExecutionC2SPacket && event.packet.command == "locraw") { - anyLocrawSent.markNow() + ServerConnectedEvent.subscribe { + HypixelModAPI.getInstance().subscribeToEventPacket(ClientboundLocationPacket::class.java) + } + HypixelModAPI.getInstance().createHandler(ClientboundLocationPacket::class.java) { + MC.onMainThread { + val lastLocraw = locraw + locraw = Locraw(it.serverName, + it.serverType.getOrNull()?.name?.uppercase(), + it.mode.getOrNull(), + it.map.getOrNull()) + SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, null)) + } + } + SkyblockServerUpdateEvent.subscribe { + if (!hasReceivedProfile && isOnSkyblock && lastProfileIdRequest.passedTime() > 30.seconds) { + lastProfileIdRequest = TimeMark.now() + MC.sendServerCommand("profileid") + } + } + AllowChatEvent.subscribe { event -> + if (event.unformattedString in profileSuggestTexts && lastProfileIdRequest.passedTime() < 5.seconds) { + event.cancel() } } ProcessChatEvent.subscribe(receivesCancelled = true) { event -> @@ -40,60 +56,11 @@ object SBData { try { profileId = UUID.fromString(profileMatch.groupValues[1]) hasReceivedProfile = true - if (!hasValidLocraw && !hasSentLocraw && anyLocrawSent.timePassed() > locrawRoundtripTime) { - sendLocraw() - } } catch (e: IllegalArgumentException) { profileId = null e.printStackTrace() } } - if (event.unformattedString.startsWith("{")) { - if (tryReceiveLocraw(event.unformattedString)) { - if (lastLocrawSent.timePassed() < locrawRoundtripTime) { - lastLocrawSent.markFarPast() - event.cancel() - } - if (!hasValidLocraw && !hasSentLocraw && hasReceivedProfile) { - sendLocraw() - } - } - } - } - - WorldReadyEvent.subscribe { - val lastLocraw = locraw - locraw = null - SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, null)) - hasSentLocraw = false - hasReceivedProfile = false - } - } - - private fun tryReceiveLocraw(unformattedString: String, update: Boolean = true): Boolean = try { - val lastLocraw = locraw - val n = Firmament.json.decodeFromString(unformattedString) - if (update) { - if (n.gametype != "SKYBLOCK") - profileId = null - locraw = n - SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, locraw)) } - true - } catch (e: SerializationException) { - e.printStackTrace() - false - } catch (e: IllegalArgumentException) { - e.printStackTrace() - false - } - - fun sendLocraw() { - hasSentLocraw = true - lastLocrawSent.markNow() - val nh = MC.player?.networkHandler ?: return - nh.sendChatCommand("locraw") } - - } -- cgit