diff options
| author | Wyvest <wyvestbusiness@gmail.com> | 2023-11-22 08:18:19 +0900 |
|---|---|---|
| committer | Wyvest <wyvestbusiness@gmail.com> | 2023-11-22 08:18:19 +0900 |
| commit | 8b373f577d9c6dde26357ef3fc86691f1efef9b4 (patch) | |
| tree | a5328e995d8f4df21a9fe94ac8e384be08833c70 /src/main/java/org/polyfrost | |
| parent | 64230799777473246b5f98efbc596206c5bbf42d (diff) | |
| download | Chatting-8b373f577d9c6dde26357ef3fc86691f1efef9b4.tar.gz Chatting-8b373f577d9c6dde26357ef3fc86691f1efef9b4.tar.bz2 Chatting-8b373f577d9c6dde26357ef3fc86691f1efef9b4.zip | |
update PGT and relocate to org.polyfrost
Diffstat (limited to 'src/main/java/org/polyfrost')
16 files changed, 1069 insertions, 0 deletions
diff --git a/src/main/java/org/polyfrost/chatting/hook/ChatLineHook.java b/src/main/java/org/polyfrost/chatting/hook/ChatLineHook.java new file mode 100644 index 0000000..50b9ce3 --- /dev/null +++ b/src/main/java/org/polyfrost/chatting/hook/ChatLineHook.java @@ -0,0 +1,17 @@ +package org.polyfrost.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(); + + long getUniqueId(); +} diff --git a/src/main/java/org/polyfrost/chatting/hook/GuiNewChatHook.java b/src/main/java/org/polyfrost/chatting/hook/GuiNewChatHook.java new file mode 100644 index 0000000..84097bd --- /dev/null +++ b/src/main/java/org/polyfrost/chatting/hook/GuiNewChatHook.java @@ -0,0 +1,21 @@ +package org.polyfrost.chatting.hook; + +import net.minecraft.client.gui.ChatLine; + +import java.awt.datatransfer.Transferable; + +public interface GuiNewChatHook { + int getRight(); + + boolean isHovering(); + + ChatLine getHoveredLine(int mouseY); + + Transferable getChattingChatComponent(int mouseY); + + default ChatLine getFullMessage(ChatLine line) { + throw new AssertionError("getFullMessage not overridden on GuiNewChat"); + } + + int getTextOpacity(); +} diff --git a/src/main/java/org/polyfrost/chatting/mixin/ChatLineMixin.java b/src/main/java/org/polyfrost/chatting/mixin/ChatLineMixin.java new file mode 100644 index 0000000..2e5f21c --- /dev/null +++ b/src/main/java/org/polyfrost/chatting/mixin/ChatLineMixin.java @@ -0,0 +1,114 @@ +/* + * 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 org.polyfrost.chatting.mixin; + +import org.polyfrost.chatting.config.ChattingConfig; +import org.polyfrost.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; + private static long lastUniqueId = 0; + private long uniqueId = 0; + + @Inject(method = "<init>", at = @At("RETURN")) + private void onInit(int i, IChatComponent iChatComponent, int j, CallbackInfo ci) { + lastUniqueId++; + uniqueId = lastUniqueId; + chatLines.add(new WeakReference<>((ChatLine) (Object) this)); + NetHandlerPlayClient netHandler = Minecraft.getMinecraft().getNetHandler(); + if (netHandler == null) return; + Map<String, NetworkPlayerInfo> nicknameCache = new HashMap<>(); + try { + 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; + } + } + } catch (Exception ignored) { + } + } + + @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; + } + } + + @Override + public long getUniqueId() { + return uniqueId; + } +} diff --git a/src/main/java/org/polyfrost/chatting/mixin/ClientCommandHandlerMixin.java b/src/main/java/org/polyfrost/chatting/mixin/ClientCommandHandlerMixin.java new file mode 100644 index 0000000..ee63ed3 --- /dev/null +++ b/src/main/java/org/polyfrost/chatting/mixin/ClientCommandHandlerMixin.java @@ -0,0 +1,33 @@ +package org.polyfrost.chatting.mixin; + +import kotlin.Pair; +import net.minecraft.client.Minecraft; +import net.minecraft.command.CommandHandler; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.BlockPos; +import net.minecraftforge.client.ClientCommandHandler; +import net.minecraftforge.fml.client.FMLClientHandler; +import org.polyfrost.chatting.chat.ChatShortcuts; +import org.polyfrost.chatting.config.ChattingConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.List; + +@Mixin(value = ClientCommandHandler.class, remap = false) +public class ClientCommandHandlerMixin extends CommandHandler { + @Redirect(method = "autoComplete", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/client/ClientCommandHandler;getTabCompletionOptions(Lnet/minecraft/command/ICommandSender;Ljava/lang/String;Lnet/minecraft/util/BlockPos;)Ljava/util/List;")) + private List<String> addChatShortcuts(ClientCommandHandler instance, ICommandSender iCommandSender, String leftOfCursor, BlockPos blockPos) { + Minecraft mc = FMLClientHandler.instance().getClient(); + List<String> autocompleteList = instance.getTabCompletionOptions(mc.thePlayer, leftOfCursor, mc.thePlayer.getPosition()); + if (ChattingConfig.INSTANCE.getChatShortcuts()) { + for (Pair<String, String> pair : ChatShortcuts.INSTANCE.getShortcuts()) { + if (pair.getFirst().startsWith(leftOfCursor)) { + autocompleteList.add(pair.getFirst()); + } + } + } + return autocompleteList; + } +} diff --git a/src/main/java/org/polyfrost/chatting/mixin/EntityPlayerSPMixin.java b/src/main/java/org/polyfrost/chatting/mixin/EntityPlayerSPMixin.java new file mode 100644 index 0000000..d59d7f2 --- /dev/null +++ b/src/main/java/org/polyfrost/chatting/mixin/EntityPlayerSPMixin.java @@ -0,0 +1,41 @@ +package org.polyfrost.chatting.mixin; + +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.network.Packet; +import net.minecraft.network.play.client.C01PacketChatMessage; +import org.polyfrost.chatting.chat.ChatTab; +import org.polyfrost.chatting.chat.ChatTabs; +import org.polyfrost.chatting.config.ChattingConfig; +import org.spongepowered.asm.mixin.Final; +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.Redirect; + +@Mixin(value = EntityPlayerSP.class, priority = 0) +public class EntityPlayerSPMixin { + @Shadow @Final public NetHandlerPlayClient sendQueue; + + @Redirect(method = "sendChatMessage", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/NetHandlerPlayClient;addToSendQueue(Lnet/minecraft/network/Packet;)V")) + private void handleSentMessages(NetHandlerPlayClient instance, Packet<?> packet, String value) { + if (value.startsWith("/")) { + sendQueue.addToSendQueue(packet); + return; + } + if (ChattingConfig.INSTANCE.getChatTabs() && !ChatTabs.INSTANCE.getCurrentTabs().isEmpty()) { + boolean sent = false; + for (ChatTab tab : ChatTabs.INSTANCE.getCurrentTabs()) { + if (tab.getPrefix() != null && !tab.getPrefix().isEmpty()) { + sendQueue.addToSendQueue(new C01PacketChatMessage(tab.getPrefix() + value)); + sent = true; + } + } + if (!sent) { + sendQueue.addToSendQueue(packet); + } + } else { + sendQueue.addToSendQueue(packet); + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/polyfrost/chatting/mixin/GuiChatMixin.java b/src/main/java/org/polyfrost/chatting/mixin/GuiChatMixin.java new file mode 100644 index 0000000..303326f --- /dev/null +++ b/src/main/java/org/polyfrost/chatting/mixin/GuiChatMixin.java @@ -0,0 +1,143 @@ +package org.polyfrost.chatting.mixin; + +import org.polyfrost.chatting.chat.*; +import org.polyfrost.chatting.config.ChattingConfig; +import org.polyfrost.chatting.gui.components.ClearButton; +import org.polyfrost.chatting.gui.components.ScreenshotButton; +import org.polyfrost.chatting.gui.components.SearchButton; +import org.polyfrost.chatting.hook.ChatLineHook; +import org.polyfrost.chatting.hook.GuiNewChatHook; +import com.google.common.collect.Lists; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ChatLine; +import net.minecraft.client.gui.GuiChat; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.MathHelper; +import net.minecraftforge.fml.client.config.GuiUtils; +import org.apache.commons.lang3.StringUtils; +import org.lwjgl.input.Mouse; +import org.polyfrost.chatting.chat.ChatSearchingManager; +import org.polyfrost.chatting.chat.ChatShortcuts; +import org.polyfrost.chatting.utils.ModCompatHooks; +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.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.awt.*; +import java.awt.datatransfer.Transferable; +import java.util.List; + +@Mixin(GuiChat.class) +public abstract class GuiChatMixin extends GuiScreen { + + @Unique + private static final List<String> COPY_TOOLTIP = Lists.newArrayList( + "\u00A7e\u00A7lCopy To Clipboard", + "\u00A7b\u00A7lNORMAL CLICK\u00A7r \u00A78- \u00A77Full Message", + "\u00A7b\u00A7lCTRL CLICK\u00A7r \u00A78- \u00A77Single Line", + "\u00A7b\u00A7lSHIFT CLICK\u00A7r \u00A78- \u00A77Screenshot Line", + "", + "\u00A7e\u00A7lModifiers", + "\u00A7b\u00A7lALT\u00A7r \u00A78- \u00A77Formatting Codes"); + + private SearchButton searchButton; + + @Inject(method = "initGui", at = @At("TAIL")) + private void init(CallbackInfo ci) { + if (ChattingConfig.INSTANCE.getChatSearch()) { + searchButton = new SearchButton(); + buttonList.add(searchButton); + } + buttonList.add(new ScreenshotButton()); + buttonList.add(new ClearButton()); + if (ChattingConfig.INSTANCE.getChatTabs()) { + for (ChatTab chatTab : ChatTabs.INSTANCE.getTabs()) { + buttonList.add(chatTab.getButton()); + } + } + } + + @Inject(method = "updateScreen", at = @At("HEAD")) + private void updateScreen(CallbackInfo ci) { + if (ChattingConfig.INSTANCE.getChatSearch() && searchButton.isEnabled()) { + searchButton.getInputField().updateCursorCounter(); + } + } + + @Inject(method = "keyTyped", at = @At("HEAD"), cancellable = true) + private void keyTyped(char typedChar, int keyCode, CallbackInfo ci) { + if (ChattingConfig.INSTANCE.getChatSearch() && searchButton.isEnabled()) { + ci.cancel(); + if (keyCode == 1) { + searchButton.onMousePress(); + return; + } + searchButton.getInputField().textboxKeyTyped(typedChar, keyCode); + ChatSearchingManager.INSTANCE.setLastSearch(searchButton.getInputField().getText()); + } + } + + @Inject(method = "drawScreen", at = @At("HEAD")) + private void onDrawScreen(int mouseX, int mouseY, float partialTicks, CallbackInfo ci) { + GuiNewChatHook hook = ((GuiNewChatHook) Minecraft.getMinecraft().ingameGUI.getChatGUI()); + float f = mc.ingameGUI.getChatGUI().getChatScale(); + int x = MathHelper.floor_float((float) mouseX / f); + if (hook.isHovering() && (hook.getRight() + ModCompatHooks.getXOffset() + 3) <= x && (hook.getRight() + ModCompatHooks.getXOffset()) + 13 > x) { + GuiUtils.drawHoveringText(COPY_TOOLTIP, mouseX, mouseY, width, height, -1, fontRendererObj); + GlStateManager.disableLighting(); + } + } + + @ModifyArg(method = "drawScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiChat;drawRect(IIIII)V"), index = 2) + private int modifyRight(int right) { + return ChattingConfig.INSTANCE.getCompactInputBox() ? (MathHelper.ceiling_float_int((float) mc.ingameGUI.getChatGUI().getChatWidth() / mc.ingameGUI.getChatGUI().getChatScale()) + 6) : right; + } + + @ModifyArg(method = "drawScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiChat;drawRect(IIIII)V"), index = 4) + private int modifyInputBoxColor(int color) { + return ChattingConfig.INSTANCE.getInputBoxBackgroundColor().getRGB(); + } + + @Inject(method = "mouseClicked", at = @At("HEAD")) + private void mouseClicked(int mouseX, int mouseY, int mouseButton, CallbackInfo ci) { + GuiNewChatHook hook = ((GuiNewChatHook) Minecraft.getMinecraft().ingameGUI.getChatGUI()); + float f = mc.ingameGUI.getChatGUI().getChatScale(); + int x = MathHelper.floor_float((float) mouseX / f); + if (hook.isHovering()) { + if (((hook.getRight() + ModCompatHooks.getXOffset() + 3) <= x && (hook.getRight() + ModCompatHooks.getXOffset()) + 13 > x) || (mouseButton == 1 && ChattingConfig.INSTANCE.getRightClickCopy())) { + Transferable message = hook.getChattingChatComponent(Mouse.getY()); + if (message == null) return; + try { + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(message, null); + } catch (Exception e) { + e.printStackTrace(); + } + } else if ((hook.getRight() + ModCompatHooks.getXOffset() + 13) <= x && (hook.getRight() + ModCompatHooks.getXOffset()) + 23 > x) { + ChatLine chatLine = hook.getHoveredLine(Mouse.getY()); + if (chatLine == null) return; + ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines().removeIf(line -> ((ChatLineHook) line).getUniqueId() == ((ChatLineHook) chatLine).getUniqueId()); + ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getChatLines().removeIf(line -> ((ChatLineHook) line).getUniqueId() == ((ChatLineHook) chatLine).getUniqueId()); + } + } + + } + + @ModifyArg(method = "keyTyped", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiChat;sendChatMessage(Ljava/lang/String;)V"), index = 0) + private String modifySentMessage(String original) { + if (ChattingConfig.INSTANCE.getChatShortcuts()) { + if (original.startsWith("/")) { + return "/" + ChatShortcuts.INSTANCE.handleSentCommand(StringUtils.substringAfter(original, "/")); + } + } + return original; + } + + @Inject(method = "handleMouseInput", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiNewChat;scroll(I)V")) + private void handleMouseInput(CallbackInfo ci) { + ChatScrollingHook.INSTANCE.setShouldSmooth(true); + } +} diff --git a/src/main/java/org/polyfrost/chatting/mixin/GuiNewChatAccessor.java b/src/main/java/org/polyfrost/chatting/mixin/GuiNewChatAccessor.java new file mode 100644 index 0000000..d0630ca --- /dev/null +++ b/src/main/java/org/polyfrost/chatting/mixin/GuiNewChatAccessor.java @@ -0,0 +1,20 @@ +package org.polyfrost.chatting.mixin; + +import net.minecraft.client.gui.ChatLine; +import net.minecraft.client.gui.GuiNewChat; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(GuiNewChat.class) +public interface GuiNewChatAccessor { + @Accessor + List<ChatLine> getDrawnChatLines(); + + @Accessor + List<ChatLine> getChatLines(); + + @Accessor + int getScrollPos(); +} diff --git a/src/main/java/org/polyfrost/chatting/mixin/GuiNewChatMapMixin.java b/src/main/java/org/polyfrost/chatting/mixin/GuiNewChatMapMixin.java new file mode 100644 index 0000000..ca1c0df --- /dev/null +++ b/src/main/java/org/polyfrost/chatting/mixin/GuiNewChatMapMixin.java @@ -0,0 +1,78 @@ +package org.polyfrost.chatting.mixin; + +import net.minecraft.client.gui.ChatLine; +import net.minecraft.client.gui.GuiNewChat; +import net.minecraft.util.IChatComponent; +import org.polyfrost.chatting.hook.GuiNewChatHook; +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.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Mixin(value = GuiNewChat.class, priority = Integer.MIN_VALUE) +public abstract class GuiNewChatMapMixin implements GuiNewChatHook { + + @Unique private final Map<ChatLine, ChatLine> drawnToFull = new HashMap<>(); + @Unique private final List<ChatLine> tempDrawnLines = new ArrayList<>(); + @Unique private ChatLine lastTempLine = null; + + @Shadow @Final private List<ChatLine> drawnChatLines; + @Shadow @Final private List<ChatLine> chatLines; + + @Inject(method = "setChatLine", at = @At("HEAD")) + private void handleSetChatLine(IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly, CallbackInfo ci) { + tempDrawnLines.clear(); + } + + @Inject(method = "setChatLine", at = @At(value = "INVOKE", target = "Ljava/util/List;add(ILjava/lang/Object;)V", ordinal = 0, shift = At.Shift.AFTER, remap = false)) + private void handleDrawnLineAdded(IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly, CallbackInfo ci) { + if (!displayOnly) tempDrawnLines.add(drawnChatLines.get(0)); + else if (lastTempLine != null) { + drawnToFull.put(drawnChatLines.get(0), lastTempLine); + } + } + + @Inject(method = "setChatLine", at = @At(value = "INVOKE", target = "Ljava/util/List;remove(I)Ljava/lang/Object;", ordinal = 0, shift = At.Shift.BEFORE, remap = false)) + private void handleDrawnLineRemoved(IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly, CallbackInfo ci) { + drawnToFull.remove(drawnChatLines.get(drawnChatLines.size() - 1)); + } + + @Inject(method = "setChatLine", at = @At("RETURN")) + private void handleLineAdded(IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly, CallbackInfo ci) { + if (!displayOnly) { + ChatLine masterLine = chatLines.get(0); + for (ChatLine tempDrawnLine : tempDrawnLines) drawnToFull.put(tempDrawnLine, masterLine); + }else { + lastTempLine = null; + } + } + + @Inject(method = "refreshChat", at = @At("HEAD")) + private void handleRefreshedChat(CallbackInfo ci) { + drawnToFull.clear(); + } + + @Inject(method = "refreshChat", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiNewChat;setChatLine(Lnet/minecraft/util/IChatComponent;IIZ)V", ordinal = 0, shift = At.Shift.BEFORE)) + private void handleLineRefresh(CallbackInfo ci, int i, ChatLine chatline) { + lastTempLine = chatline; + } + + @Inject(method = "clearChatMessages", at = @At("HEAD")) + private void handleChatCleared(CallbackInfo ci) { + drawnToFull.clear(); + } + + @Override + public ChatLine getFullMessage(ChatLine line) { + return drawnToFull.getOrDefault(line, null); + } +} diff --git a/src/main/java/org/polyfrost/chatting/mixin/GuiNewChatMixin.java b/src/main/java/org/polyfrost/chatting/mixin/GuiNewChatMixin.java new file mode 100644 index 0000000..bc90730 --- /dev/null +++ b/src/main/java/org/polyfrost/chatting/mixin/GuiNewChatMixin.java @@ -0,0 +1,257 @@ +package org.polyfrost.chatting.mixin; + +import cc.polyfrost.oneconfig.libs.universal.UMouse; +import cc.polyfrost.oneconfig.utils.Notifications; +import org.polyfrost.chatting.Chatting; +import org.polyfrost.chatting.chat.ChatSearchingManager; +import org.polyfrost.chatting.config.ChattingConfig; +import org.polyfrost.chatting.hook.GuiNewChatHook; +import org.polyfrost.chatting.utils.ModCompatHooks; +import org.polyfrost.chatting.utils.RenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.*; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; +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.*; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.image.BufferedImage; +import java.util.List; + +@Mixin(value = GuiNewChat.class, priority = 990) +public abstract class GuiNewChatMixin extends Gui implements GuiNewChatHook { + @Unique + private int chatting$right = 0; + @Unique + private boolean chatting$isHovering; + @Unique + private boolean chatting$chatCheck; + @Unique + private int chatting$textOpacity; + @Shadow + @Final + private Minecraft mc; + @Shadow + @Final + private List<ChatLine> drawnChatLines; + @Shadow + public abstract boolean getChatOpen(); + + @Shadow + public abstract float getChatScale(); + + @Shadow + public abstract int getLineCount(); + + @Shadow + private int scrollPos; + + @Shadow public abstract int getChatWidth(); + + @Unique + private static final ResourceLocation COPY = new ResourceLocation("chatting:copy.png"); + @Unique + private static final ResourceLocation DELETE = new ResourceLocation("chatting:delete.png"); + + /*? + @Unique + private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); + @ModifyArg(method = "setChatLine", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/ChatLine;<init>(ILnet/minecraft/util/IChatComponent;I)V")) + private IChatComponent handleAddDrawnLine(IChatComponent iChatComponent) { + if (!ChattingConfig.INSTANCE.getShowTimestamp()) return iChatComponent; + String time = " §7["+ sdf.format(new Date(System.currentTimeMillis())) + "]§r"; + iChatComponent.appendSibling(new ChatComponentText(time)); + return iChatComponent; + } + + */ + + @Inject(method = "drawChat", at = @At("HEAD")) + private void checkScreenshotKeybind(int j2, CallbackInfo ci) { + if (Chatting.INSTANCE.getKeybind().isPressed()) { + Chatting.INSTANCE.setDoTheThing(true); + } + chatting$chatCheck = false; + } + + @ModifyVariable(method = "drawChat", at = @At("HEAD"), argsOnly = true) + private int setUpdateCounterWhenYes(int updateCounter) { + return Chatting.INSTANCE.getDoTheThing() ? 0 : updateCounter; + } + + @ModifyVariable(method = "drawChat", at = @At("STORE"), index = 2) + private int setChatLimitWhenYes(int linesToDraw) { + return Chatting.INSTANCE.getDoTheThing() + ? GuiNewChat.calculateChatboxHeight(mc.gameSettings.chatHeightFocused) / 9 + : linesToDraw; + } + + private boolean lineInBounds = false; + + @ModifyArgs(method = "drawChat", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiNewChat;drawRect(IIIII)V"), slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/util/MathHelper;clamp_double(DDD)D"), to = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;enableBlend()V"))) + private void captureDrawRect(Args args) { + args.set(4, ChattingConfig.INSTANCE.getChatBackgroundColor().getRGB()); + if (mc.currentScreen instanceof GuiChat) { + int left = args.get(0); + int top = args.get(1); + int right = args.get(2); + int bottom = args.get(3); + if (isInBounds(left, top, right, bottom, getChatScale())) { + chatting$isHovering = true; + lineInBounds = true; + args.set(4, ChattingConfig.INSTANCE.getHoveredChatBackgroundColor().getRGB()); + } + } + } + + @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) { + float f = this.getChatScale(); + int left = 0; + int top = (int) ((float) args.get(2) - 1); + int right = MathHelper.ceiling_float_int((float)getChatWidth() / f) + 4; + int bottom = (int) ((float) args.get(2) + 8); + if ((chatting$isHovering && lineInBounds) || isInBounds(left, top, right, bottom, f)) { + chatting$isHovering = true; + drawCopyChatBox(right, top); + } + } + lineInBounds = false; + } + + private boolean isInBounds(int left, int top, int right, int bottom, float chatScale) { + int mouseX = MathHelper.floor_double(UMouse.getScaledX()) - 3; + int mouseY = MathHelper.floor_double(UMouse.getScaledY()) - 27 + ModCompatHooks.getYOffset() - ModCompatHooks.getChatPosition(); + mouseX = MathHelper.floor_float((float) mouseX / chatScale); + mouseY = -(MathHelper.floor_float((float) mouseY / chatScale)); //WHY DO I NEED TO DO THIS + return mouseX >= (left + ModCompatHooks.getXOffset()) && mouseY < bottom && mouseX < (right + 23 + ModCompatHooks.getXOffset()) && mouseY >= top; + } + + @ModifyVariable(method = "drawChat", at = @At("STORE"), ordinal = 7) + private int modifyYeah(int value) { + return chatting$textOpacity = (int) (((float) (getChatOpen() ? 255 : value)) * (mc.gameSettings.chatOpacity * 0.9F + 0.1F)); + } + /*/ + @Inject(method = "drawChat", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;scale(FFF)V")) + private void drawPre(int updateCounter, CallbackInfo ci) { + RenderUtils.timestampPre(); + } + + @Inject(method = "drawChat", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;popMatrix()V")) + private void drawPost(int updateCounter, CallbackInfo ci) { + RenderUtils.timestampPost(); + } + + */ + + @Inject(method = "drawChat", at = @At("RETURN")) + private void checkStuff(int j2, CallbackInfo ci) { + if (!chatting$chatCheck && chatting$isHovering) { + chatting$isHovering = false; + } + } + + @Override + public int getRight() { + return chatting$right; + } + + @Override + public boolean isHovering() { + return chatting$isHovering; + } + + private void drawCopyChatBox(int right, int top) { + chatting$chatCheck = true; + GlStateManager.enableRescaleNormal(); + GlStateManager.enableBlend(); + GlStateManager.enableDepth(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.pushMatrix(); + mc.getTextureManager().bindTexture(COPY); + GlStateManager.enableRescaleNormal(); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(516, 0.1f); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(770, 771); + GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); + chatting$right = right; + drawModalRectWithCustomSizedTexture(right + 1, top, 0f, 0f, 9, 9, 9, 9); + drawRect(right + 1, top, right + 10, top + 9, (((right + ModCompatHooks.getXOffset() + 3) <= (UMouse.getScaledX() / mc.ingameGUI.getChatGUI().getChatScale()) && (right + ModCompatHooks.getXOffset()) + 13 > (UMouse.getScaledX() / mc.ingameGUI.getChatGUI().getChatScale())) ? ChattingConfig.INSTANCE.getChatButtonHoveredBackgroundColor().getRGB() : ChattingConfig.INSTANCE.getChatButtonBackgroundColor().getRGB())); + GlStateManager.disableAlpha(); + GlStateManager.disableRescaleNormal(); + mc.getTextureManager().bindTexture(DELETE); + GlStateManager.enableRescaleNormal(); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(516, 0.1f); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(770, 771); + GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); + drawModalRectWithCustomSizedTexture(right + 11, top, 0f, 0f, 9, 9, 9, 9); + drawRect(right + 11, top, right + 20, top + 9, (((right + ModCompatHooks.getXOffset() + 13) <= (UMouse.getScaledX() / mc.ingameGUI.getChatGUI().getChatScale()) && (right + ModCompatHooks.getXOffset()) + 23 > (UMouse.getScaledX() / mc.ingameGUI.getChatGUI().getChatScale())) ? ChattingConfig.INSTANCE.getChatButtonHoveredBackgroundColor().getRGB() : ChattingConfig.INSTANCE.getChatButtonBackgroundColor().getRGB())); + GlStateManager.disableLighting(); + GlStateManager.popMatrix(); + } + + @Override + public ChatLine getHoveredLine(int mouseY) { + if (this.getChatOpen()) { + ScaledResolution scaledresolution = new ScaledResolution(this.mc); + int i = scaledresolution.getScaleFactor(); + float f = this.getChatScale(); + int k = mouseY / i - 27 + ModCompatHooks.getYOffset() - ModCompatHooks.getChatPosition(); + k = MathHelper.floor_float((float) k / f); + + if (k >= 0) { + int l = Math.min(this.getLineCount(), this.drawnChatLines.size()); + + if (k < this.mc.fontRendererObj.FONT_HEIGHT * l + l) { + int i1 = k / this.mc.fontRendererObj.FONT_HEIGHT + this.scrollPos; + + if (i1 >= 0 && i1 < this.drawnChatLines.size()) { + List<ChatLine> m = ChatSearchingManager.filterMessages(ChatSearchingManager.INSTANCE.getLastSearch(), this.drawnChatLines |
