diff --git a/README.md b/README.md index 9765b1e..b21d756 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,6 @@ # Girlboss -Girlboss is a mod that lets you detect when someone sends a private message to another player and attempts to detect who the receiving player is. +Girlboss is a mod that detects when people are sending private messages, and who has seen them. This is done by detecting acknowledgements of messages you haven't received via the last seen field. -The detection of someone sending a message is achieved by listening to "header packets" which are sent whenever a private message is sent. - -The detection of who received it is achieved by comparing the "last message" field on the receiver's next chat message. - -[Demo Video](https://www.youtube.com/watch?v=xnvMJV1unEY) +[Demo Video](https://www.youtube.com/watch?v=qnf4P1dGR9g) diff --git a/gradle.properties b/gradle.properties index c343948..e190fdb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,13 +2,13 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.19.2 -yarn_mappings=1.19.2+build.1 -loader_version=0.14.9 +minecraft_version=1.19.3 +yarn_mappings=1.19.3+build.5 +loader_version=0.14.12 # Mod Properties mod_version=1.0-SNAPSHOT maven_group=gg.nodus archives_base_name=girlboss # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.58.6+1.19.2 +fabric_version=0.70.0+1.19.3 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..41d9927 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..aa991fc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/src/main/java/gg/nodus/girlboss/Girlboss.java b/src/main/java/gg/nodus/girlboss/Girlboss.java deleted file mode 100644 index ad520f2..0000000 --- a/src/main/java/gg/nodus/girlboss/Girlboss.java +++ /dev/null @@ -1,10 +0,0 @@ -package gg.nodus.girlboss; - -import net.fabricmc.api.ModInitializer; - -public class Girlboss implements ModInitializer { - @Override - public void onInitialize() { - - } -} diff --git a/src/main/java/gg/nodus/girlboss/SignatureTracker.java b/src/main/java/gg/nodus/girlboss/SignatureTracker.java index 7407c5c..e56fcda 100644 --- a/src/main/java/gg/nodus/girlboss/SignatureTracker.java +++ b/src/main/java/gg/nodus/girlboss/SignatureTracker.java @@ -2,21 +2,56 @@ import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.text.Text; -import java.util.Arrays; -import java.util.Collection; -import java.util.UUID; +import java.nio.ByteBuffer; +import java.util.*; public class SignatureTracker { - private static final Multimap signatures = MultimapBuilder.hashKeys().hashSetValues().build(); + private static final Multimap signatures = MultimapBuilder.hashKeys().hashSetValues().build(); + private static final Set seen = new HashSet<>(); + private static final Set alertsSent = new HashSet<>(); + private static int alertsClearedTick = -1; + private static boolean hasSentFirstAlert = false; - public static void addSignature(UUID sender, byte[] signature) { - signatures.put(sender, signature); + public static void receivedMessage(final ByteBuffer signature) { + seen.add(signature); } - public static Collection getSignatures(UUID sender) { - return signatures.get(sender); - } + public static void addSeenSignature(final UUID sender, final ByteBuffer signature) { + if (seen.contains(signature) || signatures.containsEntry(signature, sender)) { + return; + } + + signatures.put(signature, sender); + if (MinecraftClient.getInstance().world == null) { + return; + } + + final Collection uuids = signatures.get(signature); + final List names = new ArrayList<>(); + for (final UUID uuid : uuids) { + final PlayerEntity playerEntity = MinecraftClient.getInstance().world.getPlayerByUuid(uuid); + if (playerEntity != null) { + names.add(playerEntity.getName().getString()); + } + } + final int last = names.size() - 1; + final String joinedNames = String.join(" and ", String.join(", ", names.subList(0, last)), names.get(last)); + final String verb = names.size() > 1 ? "have" : "has"; + + final String message = "§a[Girlboss] §7" + (names.size() == 1 ? names.get(0) : joinedNames) + " " + verb + " seen a message you haven't!"; + if (MinecraftClient.getInstance().player.age != alertsClearedTick) { + alertsClearedTick = MinecraftClient.getInstance().player.age; + alertsSent.clear(); + } + if (alertsSent.add(message) && hasSentFirstAlert) { + MinecraftClient.getInstance().player.sendMessage(Text.literal(message)); + } + hasSentFirstAlert = true; + } } diff --git a/src/main/java/gg/nodus/girlboss/mixin/MixinClientPlayNetworkHandler.java b/src/main/java/gg/nodus/girlboss/mixin/MixinClientPlayNetworkHandler.java deleted file mode 100644 index 9d90363..0000000 --- a/src/main/java/gg/nodus/girlboss/mixin/MixinClientPlayNetworkHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -package gg.nodus.girlboss.mixin; - -import gg.nodus.girlboss.SignatureTracker; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.network.packet.s2c.play.ChatMessageS2CPacket; -import net.minecraft.network.packet.s2c.play.MessageHeaderS2CPacket; -import net.minecraft.text.Text; -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; - -import java.util.Arrays; - -@Mixin(ClientPlayNetworkHandler.class) -public class MixinClientPlayNetworkHandler { - - @Inject(method = "onMessageHeader", at = @At("TAIL")) - public void onHeader(MessageHeaderS2CPacket packet, CallbackInfo ci) { - var sender = MinecraftClient.getInstance().world.getPlayerByUuid(packet.header().sender()); - var senderName = sender.getName().getString(); - var signature = packet.headerSignature().data(); - SignatureTracker.addSignature(sender.getUuid(), signature); - MinecraftClient.getInstance().player.sendMessage(Text.literal("§a[Girlboss] §7" + senderName + "§7 just sent a private message!")); - } - - @Inject(method = "onChatMessage", at = @At("TAIL")) - public void onMessage(ChatMessageS2CPacket packet, CallbackInfo ci) { - for (var entry : packet.message().signedBody().lastSeenMessages().entries()) { - if (entry.profileId() == packet.message().signedHeader().sender()) { - continue; - } - var sigs = SignatureTracker.getSignatures(entry.profileId()); - for (var sig : sigs) { - if (Arrays.equals(sig, entry.lastSignature().data())) { - var receiver = MinecraftClient.getInstance().world.getPlayerByUuid(packet.message().signedHeader().sender()); - var sender = MinecraftClient.getInstance().world.getPlayerByUuid(entry.profileId()); - if (sender != receiver) { - MinecraftClient.getInstance().player.sendMessage(Text.literal("§a[Girlboss] §7" + receiver.getName().getString() + "§7 received a private message from " + sender.getName().getString() + "!")); - } - } - } - } - } - -} diff --git a/src/main/java/gg/nodus/girlboss/mixin/MixinMessageHandler.java b/src/main/java/gg/nodus/girlboss/mixin/MixinMessageHandler.java new file mode 100644 index 0000000..4a7877f --- /dev/null +++ b/src/main/java/gg/nodus/girlboss/mixin/MixinMessageHandler.java @@ -0,0 +1,31 @@ +package gg.nodus.girlboss.mixin; + +import com.mojang.authlib.GameProfile; +import gg.nodus.girlboss.SignatureTracker; +import net.minecraft.client.network.message.MessageHandler; +import net.minecraft.network.message.MessageSignatureData; +import net.minecraft.network.message.MessageType; +import net.minecraft.network.message.SignedMessage; +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; + +import java.nio.ByteBuffer; + +@Mixin(MessageHandler.class) +public class MixinMessageHandler { + + @Inject(method = "onChatMessage", at = @At("HEAD")) + public void onChatMessage(final SignedMessage message, final GameProfile sender, final MessageType.Parameters params, final CallbackInfo ci) { + if (message.signature() == null) { + return; + } + SignatureTracker.receivedMessage(message.signature().toByteBuffer()); + for (final MessageSignatureData lastSeen : message.signedBody().lastSeenMessages().entries()) { + final ByteBuffer signatureByteBuffer = lastSeen.toByteBuffer(); + SignatureTracker.addSeenSignature(sender.getId(), signatureByteBuffer); + } + } + +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 48b0086..6152e72 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -11,16 +11,12 @@ "license": "MIT", "icon": "assets/girlboss/icon.png", "environment": "*", - "entrypoints": { - "main": [ - "gg.nodus.girlboss.Girlboss" - ] - }, + "entrypoints": {}, "mixins": [ "girlboss.mixins.json" ], "depends": { "fabricloader": ">=0.14.8", - "minecraft": "1.19.2" + "minecraft": "1.19.3" } } diff --git a/src/main/resources/girlboss.mixins.json b/src/main/resources/girlboss.mixins.json index b996da4..ef1a7ef 100644 --- a/src/main/resources/girlboss.mixins.json +++ b/src/main/resources/girlboss.mixins.json @@ -3,10 +3,8 @@ "minVersion": "0.8", "package": "gg.nodus.girlboss.mixin", "compatibilityLevel": "JAVA_17", - "mixins": [ - ], "client": [ - "MixinClientPlayNetworkHandler" + "MixinMessageHandler" ], "injectors": { "defaultRequire": 1