diff --git a/src/main/java/cloudburst/rejects/MeteorRejectsAddon.java b/src/main/java/cloudburst/rejects/MeteorRejectsAddon.java index 41fe25f..4e4753c 100644 --- a/src/main/java/cloudburst/rejects/MeteorRejectsAddon.java +++ b/src/main/java/cloudburst/rejects/MeteorRejectsAddon.java @@ -54,6 +54,7 @@ public class MeteorRejectsAddon extends MeteorAddon { modules.add(new ColorSigns()); modules.add(new Confuse()); modules.add(new CoordLogger()); + modules.add(new CustomPackets()); modules.add(new InteractionMenu()); modules.add(new Lavacast()); modules.add(new NewChunks()); diff --git a/src/main/java/cloudburst/rejects/events/CustomPayloadEvent.java b/src/main/java/cloudburst/rejects/events/CustomPayloadEvent.java new file mode 100644 index 0000000..3ec817d --- /dev/null +++ b/src/main/java/cloudburst/rejects/events/CustomPayloadEvent.java @@ -0,0 +1,18 @@ +package cloudburst.rejects.events; + +import cloudburst.rejects.mixin.CustomPayloadS2CPacketMixin; +import meteordevelopment.meteorclient.events.Cancellable; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +public class CustomPayloadEvent extends PacketEvent { + public CustomPayloadS2CPacket packet; + + private static final CustomPayloadEvent INSTANCE = new CustomPayloadEvent(); + + public static CustomPayloadEvent get(CustomPayloadS2CPacket packet) { + INSTANCE.setCancelled(false); + INSTANCE.packet = packet; + return INSTANCE; + } +} diff --git a/src/main/java/cloudburst/rejects/mixin/CustomPayloadS2CPacketMixin.java b/src/main/java/cloudburst/rejects/mixin/CustomPayloadS2CPacketMixin.java new file mode 100644 index 0000000..6ebe1ad --- /dev/null +++ b/src/main/java/cloudburst/rejects/mixin/CustomPayloadS2CPacketMixin.java @@ -0,0 +1,28 @@ +package cloudburst.rejects.mixin; + +import cloudburst.rejects.events.CustomPayloadEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.network.listener.ClientPlayPacketListener; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.util.Identifier; +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 class CustomPayloadS2CPacketMixin { + @Shadow + private Identifier channel; + + @Inject(method = "apply(Lnet/minecraft/network/listener/ClientPlayPacketListener;)V", + at = @At(value = "HEAD"), cancellable = true) + private void onApply(ClientPlayPacketListener clientPlayPacketListener, CallbackInfo info) { + CustomPayloadS2CPacket packet = (CustomPayloadS2CPacket) (Object) this; + CustomPayloadEvent event = MeteorClient.EVENT_BUS.post(CustomPayloadEvent.get(packet)); + if (event.isCancelled()) { + info.cancel(); + } + } +} diff --git a/src/main/java/cloudburst/rejects/modules/CustomPackets.java b/src/main/java/cloudburst/rejects/modules/CustomPackets.java new file mode 100644 index 0000000..0b96c23 --- /dev/null +++ b/src/main/java/cloudburst/rejects/modules/CustomPackets.java @@ -0,0 +1,119 @@ +package cloudburst.rejects.modules; + +import cloudburst.rejects.MeteorRejectsAddon; +import cloudburst.rejects.events.CustomPayloadEvent; +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.text.*; +import net.minecraft.util.Formatting; + +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.*; + +public class CustomPackets extends Module { + private static final Gson GSON_NON_PRETTY = new GsonBuilder().enableComplexMapKeySerialization().disableHtmlEscaping().create(); + private static final Type BADLION_MODS_TYPE = new TypeToken>() {}.getType(); + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final SettingGroup sgBadlion = settings.createGroup("Bad Lion"); + + + private final Setting unknownPackets = sgGeneral.add(new BoolSetting.Builder() + .name("unknown-packets") + .description("Whether to print unknown packets.") + .defaultValue(false) + .build() + ); + + private final Setting mods = sgBadlion.add(new BoolSetting.Builder() + .name("disallowed-mods") + .description("Whether to print what badlion mods are disallowed.") + .defaultValue(true) + .build() + ); + + public CustomPackets() { + super(MeteorRejectsAddon.CATEGORY, "custom-packets", "Handles different non-vanilla protocols."); + } + + @EventHandler + private void onCustomPayloadPacket(CustomPayloadEvent event) { + switch (event.packet.getChannel().toString()) { + case "badlion:mods" -> onBadlionModsPacket(event); + default -> onUnknownPacket(event); + } + } + + private void onUnknownPacket(CustomPayloadEvent event) { + if (!unknownPackets.get()) return; + BaseText text = new LiteralText(event.packet.getChannel().toString()); + text.setStyle(text.getStyle() + .withHoverEvent(new HoverEvent( + HoverEvent.Action.SHOW_TEXT, + new LiteralText(readString(event.packet.getData())) + ))); + info(text); + } + + private void onBadlionModsPacket(CustomPayloadEvent event) { + if (!mods.get()) return; + String json = readString(event.packet.getData()); + Map mods = GSON_NON_PRETTY.fromJson(json, BADLION_MODS_TYPE); + ChatUtils.sendMsg("Badlion", format("Mods", formatMods(mods))); + event.cancel(); + } + + private BaseText format(String type, BaseText message) { + BaseText text = new LiteralText(String.format("[%s%s%s]", + Formatting.AQUA, + type, + Formatting.GRAY + )); + text.append(" "); + text.append(message); + return text; + } + + private BaseText format(String type, String message) { + return format(type, new LiteralText(message)); + } + + private String readString(PacketByteBuf data) { + return data.readCharSequence( + data.readableBytes(), + StandardCharsets.UTF_8 + ).toString(); + } + + private BaseText formatMods(Map mods) { + BaseText text = new LiteralText("Disallowed mods: \n"); + + mods.forEach((name, data) -> { + BaseText modLine = new LiteralText(String.format("- %s%s%s ", Formatting.YELLOW, name, Formatting.GRAY)); + modLine.append(data.disabled ? "disabled" : "enabled"); + modLine.append("\n"); + if (data.extra_data != null) { + modLine.setStyle(modLine.getStyle() + .withHoverEvent(new HoverEvent( + HoverEvent.Action.SHOW_TEXT, + new LiteralText(data.extra_data.toString()) + ))); + } + text.append(modLine); + }); + + return text; + } + + private static class BadlionMod { + private boolean disabled; + private JsonObject extra_data; + private JsonObject settings; + } +} diff --git a/src/main/resources/meteor-rejects.mixins.json b/src/main/resources/meteor-rejects.mixins.json index c4c179d..4cf088a 100644 --- a/src/main/resources/meteor-rejects.mixins.json +++ b/src/main/resources/meteor-rejects.mixins.json @@ -5,6 +5,7 @@ "mixins": [ ], "client": [ + "CustomPayloadS2CPacketMixin", "Deadmau5FeatureRendererMixin", "EntityAccessor", "StructureVoidBlockMixin",