Improve location and profile detection
This commit is contained in:
@@ -79,6 +79,7 @@ allprojects {
|
|||||||
}
|
}
|
||||||
maven("https://repo.hypixel.net/repository/Hypixel/")
|
maven("https://repo.hypixel.net/repository/Hypixel/")
|
||||||
maven("https://maven.azureaaron.net/snapshots")
|
maven("https://maven.azureaaron.net/snapshots")
|
||||||
|
maven("https://maven.azureaaron.net/releases")
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,6 +129,8 @@ dependencies {
|
|||||||
modImplementation(libs.moulconfig)
|
modImplementation(libs.moulconfig)
|
||||||
modImplementation(libs.manninghamMills)
|
modImplementation(libs.manninghamMills)
|
||||||
modCompileOnly(libs.explosiveenhancement)
|
modCompileOnly(libs.explosiveenhancement)
|
||||||
|
modImplementation(libs.hypixelmodapi)
|
||||||
|
include(libs.hypixelmodapi.fabric)
|
||||||
compileOnly(project(":javaplugin"))
|
compileOnly(project(":javaplugin"))
|
||||||
annotationProcessor(project(":javaplugin"))
|
annotationProcessor(project(":javaplugin"))
|
||||||
include(libs.manninghamMills)
|
include(libs.manninghamMills)
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ mixinextras = "0.3.5"
|
|||||||
jarvis = "1.1.3"
|
jarvis = "1.1.3"
|
||||||
nealisp = "1.0.0"
|
nealisp = "1.0.0"
|
||||||
moulconfig = "3.0.0-beta.14"
|
moulconfig = "3.0.0-beta.14"
|
||||||
|
hypixelmodapi = "1.0.1"
|
||||||
|
hypixelmodapi_fabric = "1.0.1+build.1+mc1.21"
|
||||||
manninghamMills = "2.4.1"
|
manninghamMills = "2.4.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
@@ -47,6 +49,9 @@ jarvis_fabric = { module = "moe.nea.jarvis:jarvis-fabric", version.ref = "jarvis
|
|||||||
nealisp = { module = "moe.nea:nealisp", version.ref = "nealisp" }
|
nealisp = { module = "moe.nea:nealisp", version.ref = "nealisp" }
|
||||||
explosiveenhancement = { module = "maven.modrinth:explosive-enhancement", version.ref = "explosiveenhancement" }
|
explosiveenhancement = { module = "maven.modrinth:explosive-enhancement", version.ref = "explosiveenhancement" }
|
||||||
manninghamMills = { module = "me.shedaniel:mm", version.ref = "manninghamMills" }
|
manninghamMills = { module = "me.shedaniel:mm", version.ref = "manninghamMills" }
|
||||||
|
aaronhmapi = { module = "net.azureaaron:hm-api", version = "1.0.0+1.21" }
|
||||||
|
hypixelmodapi = { module = "net.hypixel:mod-api", version.ref = "hypixelmodapi" }
|
||||||
|
hypixelmodapi_fabric = { module = "maven.modrinth:hypixel-mod-api", version.ref = "hypixelmodapi_fabric" }
|
||||||
# Runtime:
|
# Runtime:
|
||||||
notenoughanimations = { module = "maven.modrinth:not-enough-animations", version.ref = "notenoughanimations" }
|
notenoughanimations = { module = "maven.modrinth:not-enough-animations", version.ref = "notenoughanimations" }
|
||||||
hotswap = { module = "virtual.github.hotswapagent:hotswap-agent", version.ref = "hotswap_agent" }
|
hotswap = { module = "virtual.github.hotswapagent:hotswap-agent", version.ref = "hotswap_agent" }
|
||||||
@@ -67,11 +72,12 @@ runtime_required = [
|
|||||||
"rei_fabric",
|
"rei_fabric",
|
||||||
"notenoughanimations",
|
"notenoughanimations",
|
||||||
"femalegender",
|
"femalegender",
|
||||||
|
"hypixelmodapi_fabric",
|
||||||
]
|
]
|
||||||
runtime_optional = [
|
runtime_optional = [
|
||||||
"devauth",
|
"devauth",
|
||||||
"freecammod",
|
"freecammod",
|
||||||
# "sodium",
|
"sodium",
|
||||||
# "qolify",
|
# "qolify",
|
||||||
# "citresewn",
|
# "citresewn",
|
||||||
# "ncr",
|
# "ncr",
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public class SectionBuilderRiser extends RiserUtils {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new RuntimeException("Could not inject tesselation hook despite fabric renderer indigo being loaded").printStackTrace();
|
System.err.println("Could not inject indigo rendering hook. Is a custom renderer installed (e.g. sodium)?");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleIndigo(MethodNode method) {
|
private void handleIndigo(MethodNode method) {
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.mixins.custompayload;
|
|
||||||
|
|
||||||
import moe.nea.firmament.apis.ingame.FirmamentCustomPayload;
|
|
||||||
import moe.nea.firmament.events.FirmamentCustomPayloadEvent;
|
|
||||||
import net.minecraft.client.network.ClientCommonNetworkHandler;
|
|
||||||
import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(value = ClientCommonNetworkHandler.class, priority = 500)
|
|
||||||
public class CustomPayloadEventDispatcher {
|
|
||||||
@Inject(method = "onCustomPayload(Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;)V", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void handleFirmamentParsedPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) {
|
|
||||||
if (packet.payload() instanceof FirmamentCustomPayload customPayload) {
|
|
||||||
FirmamentCustomPayloadEvent.Companion.publishSync(new FirmamentCustomPayloadEvent(customPayload));
|
|
||||||
ci.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.mixins.custompayload;
|
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
|
||||||
import moe.nea.firmament.apis.ingame.InGameCodecWrapper;
|
|
||||||
import net.minecraft.network.PacketByteBuf;
|
|
||||||
import net.minecraft.network.codec.PacketCodec;
|
|
||||||
import net.minecraft.network.packet.CustomPayload;
|
|
||||||
import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(priority = 1001, value = CustomPayloadC2SPacket.class)
|
|
||||||
public class InjectCustomCodecIntoC2SCustomPayloadPacket {
|
|
||||||
|
|
||||||
@WrapOperation(method = "<clinit>", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/CustomPayload;createCodec(Lnet/minecraft/network/packet/CustomPayload$CodecFactory;Ljava/util/List;)Lnet/minecraft/network/codec/PacketCodec;"))
|
|
||||||
private static PacketCodec<PacketByteBuf, CustomPayload> wrapFactory(
|
|
||||||
CustomPayload.CodecFactory<PacketByteBuf> unknownCodecFactory,
|
|
||||||
List<CustomPayload.Type<PacketByteBuf, ?>> types,
|
|
||||||
Operation<PacketCodec<PacketByteBuf, CustomPayload>> original) {
|
|
||||||
|
|
||||||
var originalCodec = original.call(unknownCodecFactory, types);
|
|
||||||
|
|
||||||
return new InGameCodecWrapper(originalCodec, InGameCodecWrapper.Direction.C2S);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.mixins.custompayload;
|
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
|
||||||
import moe.nea.firmament.apis.ingame.InGameCodecWrapper;
|
|
||||||
import net.minecraft.network.PacketByteBuf;
|
|
||||||
import net.minecraft.network.codec.PacketCodec;
|
|
||||||
import net.minecraft.network.packet.CustomPayload;
|
|
||||||
import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(priority = 1001, value = CustomPayloadS2CPacket.class)
|
|
||||||
public abstract class InjectCustomCodecIntoS2CCustomPayloadPacket {
|
|
||||||
|
|
||||||
@WrapOperation(method = "<clinit>", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/CustomPayload;createCodec(Lnet/minecraft/network/packet/CustomPayload$CodecFactory;Ljava/util/List;)Lnet/minecraft/network/codec/PacketCodec;"))
|
|
||||||
private static PacketCodec<PacketByteBuf, CustomPayload> wrapFactory(
|
|
||||||
CustomPayload.CodecFactory<PacketByteBuf> unknownCodecFactory,
|
|
||||||
List<CustomPayload.Type<PacketByteBuf, ?>> types,
|
|
||||||
Operation<PacketCodec<PacketByteBuf, CustomPayload>> original) {
|
|
||||||
|
|
||||||
var originalCodec = original.call(unknownCodecFactory, types);
|
|
||||||
|
|
||||||
return new InGameCodecWrapper(originalCodec, InGameCodecWrapper.Direction.S2C);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.mixins.custompayload;
|
|
||||||
|
|
||||||
import moe.nea.firmament.apis.ingame.JoinedCustomPayload;
|
|
||||||
import net.minecraft.network.listener.ClientCommonPacketListener;
|
|
||||||
import net.minecraft.network.packet.CustomPayload;
|
|
||||||
import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(CustomPayloadS2CPacket.class)
|
|
||||||
public abstract class SplitJoinedCustomPayload {
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract CustomPayload payload();
|
|
||||||
|
|
||||||
@Inject(method = "apply(Lnet/minecraft/network/listener/ClientCommonPacketListener;)V", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void onApply(ClientCommonPacketListener clientCommonPacketListener, CallbackInfo ci) {
|
|
||||||
if (payload() instanceof JoinedCustomPayload joinedCustomPayload) {
|
|
||||||
new CustomPayloadS2CPacket(joinedCustomPayload.getOriginal()).apply(clientCommonPacketListener);
|
|
||||||
new CustomPayloadS2CPacket(joinedCustomPayload.getSmuggled()).apply(clientCommonPacketListener);
|
|
||||||
ci.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -113,8 +113,6 @@ object Firmament {
|
|||||||
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance ->
|
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance ->
|
||||||
TickEvent.publish(TickEvent(tick++))
|
TickEvent.publish(TickEvent(tick++))
|
||||||
})
|
})
|
||||||
// TODO: remove me
|
|
||||||
Class.forName(SectionBuilder::class.java.name)
|
|
||||||
IDataHolder.registerEvents()
|
IDataHolder.registerEvents()
|
||||||
RepoManager.initialize()
|
RepoManager.initialize()
|
||||||
SBData.init()
|
SBData.init()
|
||||||
|
|||||||
@@ -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<out CustomPayload> {
|
|
||||||
return CustomPayload.id(identifier.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun <B : ByteBuf> createCodec(identifier: Identifier): PacketCodec<B, Unhandled> {
|
|
||||||
return object : PacketCodec<B, Unhandled> {
|
|
||||||
override fun decode(buf: B): Unhandled {
|
|
||||||
return Unhandled(identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun encode(buf: B, value: Unhandled) {
|
|
||||||
// we will never send an unhandled packet stealthy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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<PacketByteBuf, CustomPayload>,
|
|
||||||
val direction: Direction,
|
|
||||||
) : PacketCodec<PacketByteBuf, CustomPayload> {
|
|
||||||
enum class Direction {
|
|
||||||
S2C,
|
|
||||||
C2S,
|
|
||||||
;
|
|
||||||
|
|
||||||
var customCodec: PacketCodec<PacketByteBuf, FirmamentCustomPayload> = createStealthyCodec()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun createStealthyCodec(vararg codecs: CustomPayload.Type<PacketByteBuf, out FirmamentCustomPayload>): PacketCodec<PacketByteBuf, FirmamentCustomPayload> {
|
|
||||||
return CustomPayload.createCodec(
|
|
||||||
{ FirmamentCustomPayload.Unhandled.createCodec(it) },
|
|
||||||
codecs.toList()
|
|
||||||
) as PacketCodec<PacketByteBuf, FirmamentCustomPayload>
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<JoinedCustomPayload>("firmament:joined")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getId(): CustomPayload.Id<out JoinedCustomPayload> {
|
|
||||||
return joinedId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<T : FirmamentCustomPayload> {
|
|
||||||
val ID: CustomPayload.Id<T>
|
|
||||||
val CODEC: PacketCodec<PacketByteBuf, T>
|
|
||||||
|
|
||||||
fun id(name: String): CustomPayload.Id<T> {
|
|
||||||
return CustomPayload.Id<T>(Identifier.of(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun intoType(): CustomPayload.Type<PacketByteBuf, T> {
|
|
||||||
return CustomPayload.Type(ID, CODEC)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class PartyInfoRequest(val version: Int) : FirmamentCustomPayload {
|
|
||||||
companion object : FirmamentCustomPayloadMeta<PartyInfoRequest> {
|
|
||||||
override val ID = id("hypixel:party_info")
|
|
||||||
override val CODEC =
|
|
||||||
PacketCodecs.VAR_INT.cast<PacketByteBuf>()
|
|
||||||
.xmap(::PartyInfoRequest, PartyInfoRequest::version)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getId(): CustomPayload.Id<out CustomPayload> {
|
|
||||||
return ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed interface PartyInfoResponseV
|
|
||||||
sealed interface HypixelVersionedPacketData<out T>
|
|
||||||
data class HypixelSuccessfulResponse<T>(val data: T) : HypixelVersionedPacketData<T>
|
|
||||||
data class HypixelUnknownVersion(val version: Int) : HypixelVersionedPacketData<Nothing>
|
|
||||||
data class HypixelApiError(val label: String, val errorId: Int) : HypixelVersionedPacketData<Nothing> {
|
|
||||||
companion object {
|
|
||||||
fun <B : ByteBuf> createCodec(label: String): PacketCodec<B, HypixelApiError> {
|
|
||||||
return PacketCodecs.VAR_INT
|
|
||||||
.cast<B>()
|
|
||||||
.xmap({ HypixelApiError(label, it) }, HypixelApiError::errorId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object CodecUtils {
|
|
||||||
fun <B : PacketByteBuf, T> dispatchVersioned(
|
|
||||||
versions: Map<Int, PacketCodec<B, out T>>,
|
|
||||||
errorCodec: PacketCodec<B, HypixelApiError>
|
|
||||||
): PacketCodec<B, HypixelVersionedPacketData<T>> {
|
|
||||||
return object : PacketCodec<B, HypixelVersionedPacketData<T>> {
|
|
||||||
override fun decode(buf: B): HypixelVersionedPacketData<T> {
|
|
||||||
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<T>?) {
|
|
||||||
error("Cannot encode a hypixel packet")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <B : PacketByteBuf, T> dispatchS2CBoolean(
|
|
||||||
ifTrue: PacketCodec<B, out T>,
|
|
||||||
ifFalse: PacketCodec<B, out T>
|
|
||||||
): PacketCodec<B, T> {
|
|
||||||
return object : PacketCodec<B, T> {
|
|
||||||
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<UUID>,
|
|
||||||
) : PartyInfoResponseV {
|
|
||||||
data object PartyMember
|
|
||||||
companion object {
|
|
||||||
val CODEC: PacketCodec<PacketByteBuf, PartyInfoResponseV1> =
|
|
||||||
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<PartyInfoResponseV>) : FirmamentCustomPayload {
|
|
||||||
companion object : FirmamentCustomPayloadMeta<PartyInfoResponse> {
|
|
||||||
override val ID = id("hypixel:party_info")
|
|
||||||
override val CODEC =
|
|
||||||
CodecUtils
|
|
||||||
.dispatchVersioned<PacketByteBuf, PartyInfoResponseV>(
|
|
||||||
mapOf(
|
|
||||||
1 to PartyInfoResponseV1.CODEC,
|
|
||||||
),
|
|
||||||
HypixelApiError.createCodec("PartyInfoResponse"))
|
|
||||||
.xmap(::PartyInfoResponse, PartyInfoResponse::data)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getId(): CustomPayload.Id<out CustomPayload> {
|
|
||||||
return ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<FirmamentCustomPayloadEvent>()
|
|
||||||
}
|
|
||||||
@@ -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<ServerConnectedEvent>() {
|
||||||
|
init {
|
||||||
|
ClientPlayConnectionEvents.INIT.register(ClientPlayConnectionEvents.Init { clientPlayNetworkHandler: ClientPlayNetworkHandler, minecraftClient: MinecraftClient ->
|
||||||
|
publishSync(ServerConnectedEvent(clientPlayNetworkHandler.connection))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,37 +1,53 @@
|
|||||||
|
|
||||||
|
|
||||||
package moe.nea.firmament.util
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
import kotlinx.serialization.SerializationException
|
import java.util.UUID
|
||||||
import kotlinx.serialization.decodeFromString
|
import net.hypixel.modapi.HypixelModAPI
|
||||||
import moe.nea.firmament.Firmament
|
import net.hypixel.modapi.packet.impl.clientbound.event.ClientboundLocationPacket
|
||||||
import moe.nea.firmament.events.OutgoingPacketEvent
|
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.ProcessChatEvent
|
||||||
|
import moe.nea.firmament.events.ServerConnectedEvent
|
||||||
import moe.nea.firmament.events.SkyblockServerUpdateEvent
|
import moe.nea.firmament.events.SkyblockServerUpdateEvent
|
||||||
import moe.nea.firmament.events.WorldReadyEvent
|
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 {
|
object SBData {
|
||||||
private val profileRegex = "Profile ID: ([a-z0-9\\-]+)".toRegex()
|
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
|
var profileId: UUID? = null
|
||||||
|
|
||||||
private var lastLocrawSent = Timer()
|
|
||||||
private val anyLocrawSent = Timer()
|
|
||||||
private val locrawRoundtripTime: Duration = 5.seconds
|
|
||||||
private var hasReceivedProfile = false
|
private var hasReceivedProfile = false
|
||||||
private var hasSentLocraw = false
|
|
||||||
var locraw: Locraw? = null
|
var locraw: Locraw? = null
|
||||||
val skyblockLocation: SkyBlockIsland? get() = locraw?.skyblockLocation
|
val skyblockLocation: SkyBlockIsland? get() = locraw?.skyblockLocation
|
||||||
val hasValidLocraw get() = locraw?.server !in listOf("limbo", null)
|
val hasValidLocraw get() = locraw?.server !in listOf("limbo", null)
|
||||||
val isOnSkyblock get() = locraw?.gametype == "SKYBLOCK"
|
val isOnSkyblock get() = locraw?.gametype == "SKYBLOCK"
|
||||||
|
var lastProfileIdRequest = TimeMark.farPast()
|
||||||
fun init() {
|
fun init() {
|
||||||
OutgoingPacketEvent.subscribe { event ->
|
ServerConnectedEvent.subscribe {
|
||||||
if (event.packet is CommandExecutionC2SPacket && event.packet.command == "locraw") {
|
HypixelModAPI.getInstance().subscribeToEventPacket(ClientboundLocationPacket::class.java)
|
||||||
anyLocrawSent.markNow()
|
}
|
||||||
|
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 ->
|
ProcessChatEvent.subscribe(receivesCancelled = true) { event ->
|
||||||
@@ -40,60 +56,11 @@ object SBData {
|
|||||||
try {
|
try {
|
||||||
profileId = UUID.fromString(profileMatch.groupValues[1])
|
profileId = UUID.fromString(profileMatch.groupValues[1])
|
||||||
hasReceivedProfile = true
|
hasReceivedProfile = true
|
||||||
if (!hasValidLocraw && !hasSentLocraw && anyLocrawSent.timePassed() > locrawRoundtripTime) {
|
|
||||||
sendLocraw()
|
|
||||||
}
|
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
profileId = null
|
profileId = null
|
||||||
e.printStackTrace()
|
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<Locraw>(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")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user