aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/cc/woverflow/chatting/hook/ChatLineHook.java15
-rw-r--r--src/main/java/cc/woverflow/chatting/mixin/ChatLineMixin.java101
-rw-r--r--src/main/java/cc/woverflow/chatting/mixin/GuiNewChatMixin.java29
-rw-r--r--src/main/kotlin/cc/woverflow/chatting/config/ChattingConfig.kt27
-rw-r--r--src/main/resources/mixins.chatting.json31
5 files changed, 189 insertions, 14 deletions
diff --git a/src/main/java/cc/woverflow/chatting/hook/ChatLineHook.java b/src/main/java/cc/woverflow/chatting/hook/ChatLineHook.java
new file mode 100644
index 0000000..fb10225
--- /dev/null
+++ b/src/main/java/cc/woverflow/chatting/hook/ChatLineHook.java
@@ -0,0 +1,15 @@
+package cc.woverflow.chatting.hook;
+
+import net.minecraft.client.gui.ChatLine;
+import net.minecraft.client.network.NetworkPlayerInfo;
+
+import java.lang.ref.WeakReference;
+import java.util.HashSet;
+
+public interface ChatLineHook {
+ HashSet<WeakReference<ChatLine>> chatLines = new HashSet<>();
+ boolean hasDetected();
+ NetworkPlayerInfo getPlayerInfo();
+
+ void updatePlayerInfo();
+}
diff --git a/src/main/java/cc/woverflow/chatting/mixin/ChatLineMixin.java b/src/main/java/cc/woverflow/chatting/mixin/ChatLineMixin.java
new file mode 100644
index 0000000..b739284
--- /dev/null
+++ b/src/main/java/cc/woverflow/chatting/mixin/ChatLineMixin.java
@@ -0,0 +1,101 @@
+/*
+ * This file is from chat_heads is licensed under MPL-2.0, which can be found at https://www.mozilla.org/en-US/MPL/2.0/
+ * See: https://github.com/dzwdz/chat_heads/blob/fabric-1.16.x/LICENSE
+ */
+
+package cc.woverflow.chatting.mixin;
+
+import cc.woverflow.chatting.config.ChattingConfig;
+import cc.woverflow.chatting.hook.ChatLineHook;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ChatLine;
+import net.minecraft.client.network.NetHandlerPlayClient;
+import net.minecraft.client.network.NetworkPlayerInfo;
+import net.minecraft.util.IChatComponent;
+import org.jetbrains.annotations.Nullable;
+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.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+
+@Mixin(ChatLine.class)
+public class ChatLineMixin implements ChatLineHook {
+ private boolean detected = false;
+ private boolean first = true;
+ private NetworkPlayerInfo playerInfo;
+ private NetworkPlayerInfo detectedPlayerInfo;
+ private static NetworkPlayerInfo lastPlayerInfo;
+
+ @Inject(method = "<init>", at = @At("RETURN"))
+ private void onInit(int i, IChatComponent iChatComponent, int j, CallbackInfo ci) {
+ chatLines.add(new WeakReference<>((ChatLine) (Object) this));
+ NetHandlerPlayClient netHandler = Minecraft.getMinecraft().getNetHandler();
+ Map<String, NetworkPlayerInfo> nicknameCache = new HashMap<>();
+ for (String word : iChatComponent.getFormattedText().split("(ยง.)|\\W")) {
+ if (word.isEmpty()) continue;
+ playerInfo = netHandler.getPlayerInfo(word);
+ if (playerInfo == null) {
+ playerInfo = getPlayerFromNickname(word, netHandler, nicknameCache);
+ }
+ if (playerInfo != null) {
+ detectedPlayerInfo = playerInfo;
+ detected = true;
+ if (playerInfo == lastPlayerInfo) {
+ first = false;
+ if (ChattingConfig.INSTANCE.getHideChatHeadOnConsecutiveMessages()) {
+ playerInfo = null;
+ }
+ } else {
+ lastPlayerInfo = playerInfo;
+ }
+ break;
+ }
+ }
+ }
+
+ @Nullable
+ private static NetworkPlayerInfo getPlayerFromNickname(String word, NetHandlerPlayClient connection, Map<String, NetworkPlayerInfo> nicknameCache) {
+ if (nicknameCache.isEmpty()) {
+ for (NetworkPlayerInfo p : connection.getPlayerInfoMap()) {
+ IChatComponent displayName = p.getDisplayName();
+ if (displayName != null) {
+ String nickname = displayName.getUnformattedTextForChat();
+ if (word.equals(nickname)) {
+ nicknameCache.clear();
+ return p;
+ }
+
+ nicknameCache.put(nickname, p);
+ }
+ }
+ } else {
+ // use prepared cache
+ return nicknameCache.get(word);
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean hasDetected() {
+ return detected;
+ }
+
+ @Override
+ public NetworkPlayerInfo getPlayerInfo() {
+ return playerInfo;
+ }
+
+ @Override
+ public void updatePlayerInfo() {
+ if (ChattingConfig.INSTANCE.getHideChatHeadOnConsecutiveMessages() && !first) {
+ playerInfo = null;
+ } else {
+ playerInfo = detectedPlayerInfo;
+ }
+ }
+}
diff --git a/src/main/java/cc/woverflow/chatting/mixin/GuiNewChatMixin.java b/src/main/java/cc/woverflow/chatting/mixin/GuiNewChatMixin.java
index 13c91ef..a430f8e 100644
--- a/src/main/java/cc/woverflow/chatting/mixin/GuiNewChatMixin.java
+++ b/src/main/java/cc/woverflow/chatting/mixin/GuiNewChatMixin.java
@@ -1,17 +1,20 @@
package cc.woverflow.chatting.mixin;
import cc.polyfrost.oneconfig.config.core.OneColor;
+import cc.polyfrost.oneconfig.utils.color.ColorUtils;
import cc.woverflow.chatting.Chatting;
import cc.woverflow.chatting.chat.ChatSearchingManager;
import cc.woverflow.chatting.chat.ChatTabs;
import cc.woverflow.chatting.config.ChattingConfig;
import cc.woverflow.chatting.gui.components.CleanButton;
+import cc.woverflow.chatting.hook.ChatLineHook;
import cc.woverflow.chatting.hook.GuiNewChatHook;
import cc.woverflow.chatting.utils.ModCompatHooks;
import cc.woverflow.chatting.utils.RenderUtils;
import cc.polyfrost.oneconfig.libs.universal.UMouse;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.*;
+import net.minecraft.client.network.NetworkPlayerInfo;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
@@ -25,6 +28,7 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
import java.awt.datatransfer.StringSelection;
@@ -141,6 +145,14 @@ public abstract class GuiNewChatMixin extends Gui implements GuiNewChatHook {
}
}
+ @Unique
+ private ChatLine chatting$drawingLine = null;
+
+ @Inject(method = "drawChat", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/ChatLine;getChatComponent()Lnet/minecraft/util/IChatComponent;"), locals = LocalCapture.CAPTURE_FAILSOFT)
+ private void captureChatLine(int updateCounter, CallbackInfo ci, int i, boolean bl, int j, int k, float f, float g, int l, int m, ChatLine chatLine, int n, double d, int o, int p, int q) {
+ chatting$drawingLine = chatLine;
+ }
+
@ModifyArgs(method = "drawChat", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/FontRenderer;drawStringWithShadow(Ljava/lang/String;FFI)I"))
private void drawChatBox(Args args) {
if (mc.currentScreen instanceof GuiChat) {
@@ -155,6 +167,23 @@ public abstract class GuiNewChatMixin extends Gui implements GuiNewChatHook {
}
}
lineInBounds = false;
+ if (ChattingConfig.INSTANCE.getShowChatHeads()) {
+ ChatLineHook hook = ((ChatLineHook) chatting$drawingLine);
+ if (hook.hasDetected() || ChattingConfig.INSTANCE.getOffsetNonPlayerMessages()) {
+ args.set(1, ((float) args.get(1)) + 10f);
+ }
+ NetworkPlayerInfo networkPlayerInfo = hook.getPlayerInfo();
+ if (networkPlayerInfo != null) {
+ GlStateManager.enableBlend();
+ GlStateManager.enableAlpha();
+ mc.getTextureManager().bindTexture(networkPlayerInfo.getLocationSkin());
+ GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
+ GlStateManager.color(1.0F, 1.0F, 1.0F, ColorUtils.getAlpha(args.get(3)) / 255f);
+ Gui.drawScaledCustomSizeModalRect((int) ((float) args.get(1) - 10f), (int) ((float) args.get(2) - 1f), 8.0F, 8.0F, 8, 8, 8, 8, 64.0F, 64.0F);
+ Gui.drawScaledCustomSizeModalRect((int) ((float) args.get(1) - 10f), (int) ((float) args.get(2) - 1f), 40.0F, 8.0F, 8, 8, 8, 8, 64.0F, 64.0F);
+ GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+ }
+ }
}
private boolean isInBounds(int left, int top, int right, int bottom, float chatScale) {
diff --git a/src/main/kotlin/cc/woverflow/chatting/config/ChattingConfig.kt b/src/main/kotlin/cc/woverflow/chatting/config/ChattingConfig.kt
index 40ebd9a..a7f6ffe 100644
--- a/src/main/kotlin/cc/woverflow/chatting/config/ChattingConfig.kt
+++ b/src/main/kotlin/cc/woverflow/chatting/config/ChattingConfig.kt
@@ -13,6 +13,7 @@ import cc.woverflow.chatting.chat.ChatShortcuts
import cc.woverflow.chatting.chat.ChatTab
import cc.woverflow.chatting.chat.ChatTabs
import cc.woverflow.chatting.gui.components.TabButton
+import cc.woverflow.chatting.hook.ChatLineHook
import java.io.File
object ChattingConfig :
@@ -66,6 +67,27 @@ object ChattingConfig :
)
var informForAlternatives = true
+ @Switch(
+ name = "Show Chat Heads",
+ description = "Show the chat heads of players in chat",
+ category = "Chat Heads"
+ )
+ var showChatHeads = true
+
+ @Switch(
+ name = "Offset Non-Player Messages",
+ description = "Offset all messages, even if a player has not been detected.",
+ category = "Chat Heads"
+ )
+ var offsetNonPlayerMessages = false
+
+ @Switch(
+ name = "Hide Chat Head on Consecutive Messages",
+ description = "Hide the chat head if the previous message was from the same player.",
+ category = "Chat Heads"
+ )
+ var hideChatHeadOnConsecutiveMessages = true
+
/*/
@Property(
type = PropertyType.SWITCH,
@@ -191,6 +213,11 @@ object ChattingConfig :
init {
initialize()
+ addDependency("offsetNonPlayerMessages", "showChatHeads")
+ addDependency("hideChatHeadOnConsecutiveMessages", "showChatHeads")
+ addListener("hideChatHeadOnConsecutiveMessages") {
+ ChatLineHook.chatLines.map { it.get() as ChatLineHook? }.forEach { it?.updatePlayerInfo() }
+ }
addListener("chatTabs") {
ChatTabs.initialize()
if (!chatTabs) {
diff --git a/src/main/resources/mixins.chatting.json b/src/main/resources/mixins.chatting.json
index 5a7c5bf..78b43c5 100644
--- a/src/main/resources/mixins.chatting.json
+++ b/src/main/resources/mixins.chatting.json
@@ -1,16 +1,19 @@
{
- "compatibilityLevel": "JAVA_8",
- "minVersion": "0.7",
- "package": "cc.woverflow.chatting.mixin",
- "refmap": "mixins.${id}.refmap.json",
- "mixins": [
- "ClientCommandHandlerMixin",
- "EntityPlayerSPMixin",
- "GuiChatMixin",
- "GuiNewChatAccessor",
- "GuiNewChatMapMixin",
- "GuiNewChatMixin",
- "GuiUtilsMixin"
- ],
- "verbose": true
+ "compatibilityLevel": "JAVA_8",
+ "minVersion": "0.7",
+ "package": "cc.woverflow.chatting.mixin",
+ "refmap": "mixins.${id}.refmap.json",
+ "mixins": [
+ "ClientCommandHandlerMixin",
+ "EntityPlayerSPMixin",
+ "GuiChatMixin",
+ "GuiNewChatAccessor",
+ "GuiNewChatMapMixin",
+ "GuiNewChatMixin",
+ "GuiUtilsMixin"
+ ],
+ "verbose": true,
+ "client": [
+ "ChatLineMixin"
+ ]
} \ No newline at end of file