Skip to content

Commit

Permalink
feat(BetterChat): copy chat line (CCBlueX#4958)
Browse files Browse the repository at this point in the history
  • Loading branch information
sqlerrorthing authored and commandblock2 committed Dec 31, 2024
1 parent 2b65d58 commit aa66b99
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,31 @@

import com.llamalad7.mixinextras.sugar.Local;
import net.ccbluex.liquidbounce.features.module.modules.misc.betterchat.ModuleBetterChat;
import net.ccbluex.liquidbounce.interfaces.ChatHudAddition;
import net.ccbluex.liquidbounce.interfaces.ChatMessageAddition;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.ChatHud;
import net.minecraft.client.gui.hud.ChatHudLine;
import net.minecraft.text.OrderedText;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArgs;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;

import java.util.List;

@Mixin(ChatHud.class)
public abstract class MixinChatHud {
public abstract class MixinChatHud implements ChatHudAddition {

@Shadow
@Final
private List<ChatHudLine.Visible> visibleMessages;
public List<ChatHudLine.Visible> visibleMessages;

@Shadow
public abstract boolean isChatFocused();
Expand All @@ -57,6 +62,12 @@ public abstract class MixinChatHud {
@Final
public List<ChatHudLine> messages;

@Shadow
public abstract int getWidth();

@Unique
private int chatY = -1;

/**
* Spoofs the message size to be empty to avoid deletion.
*/
Expand Down Expand Up @@ -85,7 +96,6 @@ public void hookClear(boolean clearHistory, CallbackInfo ci) {
* Modifies {@link ChatHud#addVisibleMessage(ChatHudLine)} so, that the id is
* forwarded and if {@link ModuleBetterChat} is enabled, older lines won't be removed.
*/
@SuppressWarnings("JavadocReference")
@Inject(method = "addVisibleMessage", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/ChatHud;isChatFocused()Z", shift = At.Shift.BEFORE), cancellable = true)
public void hookAddVisibleMessage(ChatHudLine message, CallbackInfo ci, @Local List<OrderedText> list) {
var focused = isChatFocused();
Expand Down Expand Up @@ -117,4 +127,32 @@ public void hookAddVisibleMessage(ChatHudLine message, CallbackInfo ci, @Local L
ci.cancel();
}

@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/ChatHud;getLineHeight()I", ordinal = 0))
public void hookStoreChatY(DrawContext context, int currentTick, int mouseX, int mouseY, boolean focused, CallbackInfo ci, @Local(ordinal = 7) int m) {
this.chatY = m;
}

@ModifyArgs(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;fill(IIIII)V", ordinal = 0))
private void modifyArgs(
Args args,
@Local(ordinal = 1, argsOnly = true) int mouseX,
@Local(ordinal = 2, argsOnly = true) int mouseY
) {
if(!(ModuleBetterChat.INSTANCE.getRunning() && ModuleBetterChat.Copy.INSTANCE.getRunning() && ModuleBetterChat.Copy.INSTANCE.getHighlight())) {
return;
}

var hovering = mouseX >= 0 && mouseX <= ((int) args.get(2)) -4 &&
mouseY >= ((int)args.get(1)+1) && mouseY <= ((int)args.get(3));

if (hovering) {
args.set(4, 140 << 24);
}
}

@Override
public int liquidbounce_getChatY() {
return chatY;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.ccbluex.liquidbounce.injection.mixins.minecraft.gui;

import net.minecraft.client.gui.hud.ChatHud;
import net.minecraft.client.gui.hud.ChatHudLine;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;

import java.util.List;

/**
* @author 00101110001100010111000101111
* @since 12/18/2024
**/
@Mixin(ChatHud.class)
public interface MixinChatHudAccessor {
@Invoker("toChatLineY")
double invokeToChatLineY(double y);

@Invoker("getMessageIndex")
int invokeGetMessageIndex(double chatLineX, double chatLineY);

@Invoker("getLineHeight")
int invokeGetLineHeight();

@Accessor
List<ChatHudLine.Visible> getVisibleMessages();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,26 @@

import net.ccbluex.liquidbounce.event.EventManager;
import net.ccbluex.liquidbounce.event.events.ChatSendEvent;
import net.ccbluex.liquidbounce.event.events.NotificationEvent;
import net.ccbluex.liquidbounce.features.module.modules.misc.betterchat.ModuleBetterChat;
import net.ccbluex.liquidbounce.interfaces.ChatHudAddition;
import net.ccbluex.liquidbounce.utils.client.ClientUtilsKt;
import net.minecraft.client.gui.hud.ChatHud;
import net.minecraft.client.gui.hud.ChatHudLine;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.text.CharacterVisitor;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.ArrayList;
import java.util.List;

@Mixin(ChatScreen.class)
public abstract class MixinChatScreen extends MixinScreen {

Expand Down Expand Up @@ -56,4 +69,111 @@ private void handleChatMessage(String chatText, boolean addToHistory, CallbackIn
}
}

@Inject(method = "mouseClicked", at = @At("HEAD"))
private void hookMouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) {
if (!(ModuleBetterChat.INSTANCE.getRunning() && ModuleBetterChat.Copy.INSTANCE.getRunning())) {
return;
}

int[] activeMessage = getActiveMessage((int)mouseX, (int)mouseY);

if (activeMessage == null) {
return;
}

ChatHud chatHud = this.client.inGameHud.getChatHud();
MixinChatHudAccessor accessor = (MixinChatHudAccessor) chatHud;

List<ChatHudLine.Visible> visibleMessages = accessor.getVisibleMessages();
List<ChatHudLine.Visible> messageParts = new ArrayList<>();
messageParts.add(visibleMessages.get(activeMessage[3]));

for (int index = activeMessage[3] + 1; index < visibleMessages.size(); index++) {
if (visibleMessages.get(index).endOfEntry())
break;

messageParts.addFirst(visibleMessages.get(index));
}

if (messageParts.isEmpty())
return;

copyMessage(messageParts, button);
}

@Unique
private void copyMessage(List<ChatHudLine.Visible> messageParts, int button) {
final StringBuilder builder = new StringBuilder();

CharacterVisitor visitor = (index, style, codePoint) -> {
builder.append((char) codePoint);
return true;
};

for (ChatHudLine.Visible line : messageParts) {
line.content().accept(visitor);
}

if (isPressed(GLFW.GLFW_KEY_LEFT_SHIFT, GLFW.GLFW_KEY_RIGHT_SHIFT) && button == GLFW.GLFW_MOUSE_BUTTON_1) {
client.keyboard.setClipboard(builder.toString());

if (ModuleBetterChat.Copy.INSTANCE.getNotification()) {
ClientUtilsKt.notification(
"ChatCopy",
"The line is copied",
NotificationEvent.Severity.SUCCESS
);
}
} else if (button == GLFW.GLFW_MOUSE_BUTTON_2) {
if (client.currentScreen instanceof ChatScreen chat) {
((MixinChatScreenAccessor) chat).getChatField().setText(builder.toString());
}
}
}

@Unique
private boolean isPressed(int... keys) {
for (int key : keys) {
if (GLFW.glfwGetKey(client.getWindow().getHandle(), key) == GLFW.GLFW_PRESS) {
return true;
}
}

return false;
}

// [0] - y,
// [1] - width,
// [2] - height,
// [3] - (message) index
@Unique
private int @Nullable [] getActiveMessage(int mouseX, int mouseY) {
ChatHud chatHud = this.client.inGameHud.getChatHud();
MixinChatHudAccessor accessor = (MixinChatHudAccessor) chatHud;
ChatHudAddition addition = (ChatHudAddition) chatHud;

float chatScale = (float) chatHud.getChatScale();
int chatLineY = (int) accessor.invokeToChatLineY(mouseY);
int messageIndex = accessor.invokeGetMessageIndex(0, chatLineY);
int buttonX = (int) (chatHud.getWidth() + 14 * chatScale);

if (messageIndex == -1 || mouseX > buttonX + 14 * chatScale)
return null;

int chatY = addition.liquidbounce_getChatY();

int buttonSize = (int) (9 * chatScale);
int lineHeight = accessor.invokeGetLineHeight();
int scaledButtonY = chatY - (chatLineY + 1) * lineHeight + (int) Math.ceil((lineHeight - 9) / 2.0);
float buttonY = scaledButtonY * chatScale;

boolean hovering = mouseX >= 0 && mouseX <= buttonX && mouseY >= buttonY && mouseY <= buttonY + buttonSize;

if (hovering) {
return new int[]{(int) buttonY, buttonX, buttonSize, messageIndex};
} else {
return null;
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package net.ccbluex.liquidbounce.injection.mixins.minecraft.gui;

import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.widget.TextFieldWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

@Mixin(ChatScreen.class)
public interface MixinChatScreenAccessor {
@Accessor("chatField")
TextFieldWidget getChatField();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package net.ccbluex.liquidbounce.interfaces;

public interface ChatHudAddition {
int liquidbounce_getChatY();
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,16 @@ object ModuleBetterChat : ClientModule("BetterChat", Category.MISC, aliases = ar
private val forceUnicodeChat by boolean("ForceUnicodeChat", false)

init {
tree(AntiSpam)
treeAll(
AntiSpam,
Copy
)
}


object Copy : ToggleableConfigurable(this, "Copy", true) {
val notification by boolean("Notificate", true)
val highlight by boolean("Highlight", true)
}

var antiChatClearPaused = false
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/liquidbounce.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@
"minecraft.fluid.MixinFlowableFluid",
"minecraft.gui.MixinBossBarHud",
"minecraft.gui.MixinChatHud",
"minecraft.gui.MixinChatHudAccessor",
"minecraft.gui.MixinChatInputSuggestor",
"minecraft.gui.MixinChatScreen",
"minecraft.gui.MixinChatScreenAccessor",
"minecraft.gui.MixinHandledScreen",
"minecraft.gui.MixinInGameHud",
"minecraft.gui.MixinPlayerListHud",
Expand Down

0 comments on commit aa66b99

Please sign in to comment.