diff options
-rw-r--r-- | src/main/java/com/raeids/stratus/hook/GuiNewChatHook.java | 4 | ||||
-rw-r--r-- | src/main/java/com/raeids/stratus/mixin/GuiChatMixin.java | 35 | ||||
-rw-r--r-- | src/main/java/com/raeids/stratus/mixin/GuiNewChatAccessor.java | 4 | ||||
-rw-r--r-- | src/main/java/com/raeids/stratus/mixin/GuiNewChatMixin.java | 33 | ||||
-rw-r--r-- | src/main/kotlin/com/raeids/stratus/Stratus.kt | 60 | ||||
-rw-r--r-- | src/main/kotlin/com/raeids/stratus/config/StratusConfig.kt | 13 | ||||
-rw-r--r-- | src/main/kotlin/com/raeids/stratus/hook/ChatSearching.kt | 8 | ||||
-rw-r--r-- | src/main/kotlin/com/raeids/stratus/hook/CleanSearchButton.kt | 18 | ||||
-rw-r--r-- | src/main/kotlin/com/raeids/stratus/hook/ScreenshotButton.kt | 34 | ||||
-rw-r--r-- | src/main/kotlin/com/raeids/stratus/utils/ImageTransferable.kt | 22 | ||||
-rw-r--r-- | src/main/kotlin/com/raeids/stratus/utils/RenderHelper.kt | 159 | ||||
-rw-r--r-- | src/main/resources/assets/stratus/screenshot.png | bin | 0 -> 162 bytes | |||
-rw-r--r-- | src/main/resources/assets/stratus/search.png | bin | 0 -> 158 bytes |
13 files changed, 336 insertions, 54 deletions
diff --git a/src/main/java/com/raeids/stratus/hook/GuiNewChatHook.java b/src/main/java/com/raeids/stratus/hook/GuiNewChatHook.java index e37995a..aaa182e 100644 --- a/src/main/java/com/raeids/stratus/hook/GuiNewChatHook.java +++ b/src/main/java/com/raeids/stratus/hook/GuiNewChatHook.java @@ -2,10 +2,12 @@ package com.raeids.stratus.hook; import net.minecraft.client.gui.ChatLine; +import java.awt.datatransfer.Transferable; + public interface GuiNewChatHook { int getRight(); boolean shouldCopy(); - String getStratusChatComponent(int mouseY); + Transferable getStratusChatComponent(int mouseY); default ChatLine getFullMessage(ChatLine line) { throw new AssertionError("getFullMessage not overridden on GuiNewChat"); } diff --git a/src/main/java/com/raeids/stratus/mixin/GuiChatMixin.java b/src/main/java/com/raeids/stratus/mixin/GuiChatMixin.java index 4b8142c..37fb0f3 100644 --- a/src/main/java/com/raeids/stratus/mixin/GuiChatMixin.java +++ b/src/main/java/com/raeids/stratus/mixin/GuiChatMixin.java @@ -1,27 +1,43 @@ package com.raeids.stratus.mixin; +import com.google.common.collect.Lists; import com.raeids.stratus.Stratus; import com.raeids.stratus.config.StratusConfig; import com.raeids.stratus.hook.*; import net.minecraft.client.Minecraft; 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.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.StringSelection; +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( + "\u00A73\u00A7l\u00A7nCopy To Clipboard", + "\u00A7lNORMAL CLICK\u00A7r - Full Message", + "\u00A7lCTRL CLICK\u00A7r - Single Line", + "\u00A7lSHIFT CLICK\u00A7r - Screenshot Line", + "", + "\u00A73\u00A7l\u00A7nModifiers", + "\u00A7lALT\u00A7r - Formatting Codes"); + private CleanSearchButton searchButton; + private ScreenshotButton screenshotButton; @Inject(method = "initGui", at = @At("TAIL")) private void init(CallbackInfo ci) { @@ -29,6 +45,8 @@ public abstract class GuiChatMixin extends GuiScreen { searchButton = new CleanSearchButton(); buttonList.add(searchButton); } + screenshotButton = new ScreenshotButton(); + buttonList.add(screenshotButton); if (StratusConfig.INSTANCE.getChatTabs()) { for (ChatTab chatTab : ChatTabs.INSTANCE.getTabs()) { buttonList.add(chatTab.getButton()); @@ -56,14 +74,27 @@ public abstract class GuiChatMixin extends GuiScreen { } } + @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.shouldCopy() && (hook.getRight() + (Stratus.INSTANCE.isBetterChat() ? ModCompatHooks.getXOffset() : 0)) <= x && (hook.getRight() + (Stratus.INSTANCE.isBetterChat() ? ModCompatHooks.getXOffset() : 0)) + 9 > x) { + GuiUtils.drawHoveringText(COPY_TOOLTIP, mouseX, mouseY, width, height, -1, fontRendererObj); + GlStateManager.disableLighting(); + } + } + @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.shouldCopy() && (hook.getRight() + (Stratus.INSTANCE.isBetterChat() ? ModCompatHooks.getXOffset() : 0)) <= x && (hook.getRight() + (Stratus.INSTANCE.isBetterChat() ? ModCompatHooks.getXOffset() : 0)) + 9 > x) { + Transferable message = hook.getStratusChatComponent(Mouse.getY()); + if (message == null) return; try { - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(hook.getStratusChatComponent(Mouse.getY())), null); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(message, null); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/com/raeids/stratus/mixin/GuiNewChatAccessor.java b/src/main/java/com/raeids/stratus/mixin/GuiNewChatAccessor.java index cc697d0..9b68d48 100644 --- a/src/main/java/com/raeids/stratus/mixin/GuiNewChatAccessor.java +++ b/src/main/java/com/raeids/stratus/mixin/GuiNewChatAccessor.java @@ -1,7 +1,6 @@ package com.raeids.stratus.mixin; import net.minecraft.client.gui.ChatLine; -import net.minecraft.client.gui.GuiChat; import net.minecraft.client.gui.GuiNewChat; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -12,4 +11,7 @@ import java.util.List; public interface GuiNewChatAccessor { @Accessor List<ChatLine> getDrawnChatLines(); + + @Accessor + int getScrollPos(); } diff --git a/src/main/java/com/raeids/stratus/mixin/GuiNewChatMixin.java b/src/main/java/com/raeids/stratus/mixin/GuiNewChatMixin.java index 8d2602b..09c464b 100644 --- a/src/main/java/com/raeids/stratus/mixin/GuiNewChatMixin.java +++ b/src/main/java/com/raeids/stratus/mixin/GuiNewChatMixin.java @@ -1,12 +1,12 @@ package com.raeids.stratus.mixin; -import com.google.common.collect.Lists; import com.raeids.stratus.Stratus; import com.raeids.stratus.config.StratusConfig; import com.raeids.stratus.hook.ChatSearchingKt; import com.raeids.stratus.hook.ChatTabs; import com.raeids.stratus.hook.GuiNewChatHook; import com.raeids.stratus.hook.ModCompatHooks; +import com.raeids.stratus.utils.RenderHelper; import gg.essential.universal.UMouse; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.*; @@ -15,7 +15,6 @@ import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.IChatComponent; import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.client.config.GuiUtils; import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -25,6 +24,9 @@ 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 = Integer.MIN_VALUE) @@ -51,14 +53,6 @@ public abstract class GuiNewChatMixin extends Gui implements GuiNewChatHook { @Unique private static final ResourceLocation COPY = new ResourceLocation("stratus:copy.png"); - @Unique private static final List<String> COPY_TOOLTIP = Lists.newArrayList( - "\u00A73\u00A7l\u00A7nCopy To Clipboard", - "\u00A7lNORMAL CLICK\u00A7r - Full Message", - "\u00A7lCTRL CLICK\u00A7r - Single Line", - "", - "\u00A73\u00A7l\u00A7nModifiers", - "\u00A7lALT\u00A7r - Formatting Codes"); - @Inject(method = "printChatMessageWithOptionalDeletion", at = @At("HEAD"), cancellable = true) private void handlePrintChatMessage(IChatComponent chatComponent, int chatLineId, CallbackInfo ci) { handleChatTabMessage(chatComponent, chatLineId, mc.ingameGUI.getUpdateCounter(), false, ci); @@ -104,7 +98,7 @@ public abstract class GuiNewChatMixin extends Gui implements GuiNewChatHook { mouseY = -(MathHelper.floor_float((float)mouseY / f)); //WHY DO I NEED TO DO THIS if (mouseX >= (left + (Stratus.INSTANCE.isBetterChat() ? ModCompatHooks.getXOffset() : 0)) && mouseY < bottom && mouseX < (right + 9 + (Stratus.INSTANCE.isBetterChat() ? ModCompatHooks.getXOffset() : 0)) && mouseY >= top) { stratus$shouldCopy = true; - drawCopyChatBox(right, top, mouseX, mouseY); + drawCopyChatBox(right, top); } } } @@ -150,7 +144,7 @@ public abstract class GuiNewChatMixin extends Gui implements GuiNewChatHook { } } - private void drawCopyChatBox(int right, int top, int mouseX, int mouseY) { + private void drawCopyChatBox(int right, int top) { stratus$chatCheck = true; GlStateManager.enableRescaleNormal(); GlStateManager.enableBlend(); @@ -166,7 +160,6 @@ public abstract class GuiNewChatMixin extends Gui implements GuiNewChatHook { GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); stratus$right = right; Gui.drawModalRectWithCustomSizedTexture(right, top, 0f, 0f, 9, 9, 9, 9); - if (mouseX >= right) GuiUtils.drawHoveringText(COPY_TOOLTIP, mouseX, mouseY, mc.currentScreen.width, mc.currentScreen.height, 300, mc.fontRendererObj); GlStateManager.disableAlpha(); GlStateManager.disableRescaleNormal(); GlStateManager.disableLighting(); @@ -174,7 +167,7 @@ public abstract class GuiNewChatMixin extends Gui implements GuiNewChatHook { } @Override - public String getStratusChatComponent(int mouseY) { + public Transferable getStratusChatComponent(int mouseY) { if (this.getChatOpen()) { ScaledResolution scaledresolution = new ScaledResolution(this.mc); int i = scaledresolution.getScaleFactor(); @@ -190,9 +183,17 @@ public abstract class GuiNewChatMixin extends Gui implements GuiNewChatHook { if (i1 >= 0 && i1 < this.drawnChatLines.size()) { ChatLine subLine = this.drawnChatLines.get(i1); - ChatLine line = GuiScreen.isCtrlKeyDown() ? subLine : this.getFullMessage(subLine); + ChatLine fullLine = this.getFullMessage(subLine); + if (GuiScreen.isShiftKeyDown()) { + if (fullLine != null) { + BufferedImage image = Stratus.INSTANCE.screenshotLine(fullLine); + if (image != null) RenderHelper.INSTANCE.copyBufferedImageToClipboard(image); + } + return null; + } + ChatLine line = GuiScreen.isCtrlKeyDown() ? subLine : fullLine; String message = line == null ? "Could not find chat message." : line.getChatComponent().getFormattedText(); - return GuiScreen.isAltKeyDown() ? message : EnumChatFormatting.getTextWithoutFormattingCodes(message); + return new StringSelection(GuiScreen.isAltKeyDown() ? message : EnumChatFormatting.getTextWithoutFormattingCodes(message)); } } diff --git a/src/main/kotlin/com/raeids/stratus/Stratus.kt b/src/main/kotlin/com/raeids/stratus/Stratus.kt index d771915..7588749 100644 --- a/src/main/kotlin/com/raeids/stratus/Stratus.kt +++ b/src/main/kotlin/com/raeids/stratus/Stratus.kt @@ -4,17 +4,18 @@ import com.raeids.stratus.command.StratusCommand import com.raeids.stratus.config.StratusConfig import com.raeids.stratus.hook.ChatShortcuts import com.raeids.stratus.hook.ChatTabs +import com.raeids.stratus.hook.GuiNewChatHook +import com.raeids.stratus.hook.filterMessages import com.raeids.stratus.mixin.GuiNewChatAccessor import com.raeids.stratus.updater.Updater import com.raeids.stratus.utils.RenderHelper import gg.essential.api.EssentialAPI import gg.essential.universal.UDesktop import net.minecraft.client.Minecraft -import net.minecraft.client.gui.FontRenderer -import net.minecraft.client.gui.GuiChat -import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.gui.* import net.minecraft.client.settings.KeyBinding import net.minecraft.client.shader.Framebuffer +import net.minecraft.util.MathHelper import net.minecraftforge.common.MinecraftForge.EVENT_BUS import net.minecraftforge.fml.client.registry.ClientRegistry import net.minecraftforge.fml.common.Loader @@ -25,6 +26,7 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.common.gameevent.TickEvent import org.lwjgl.input.Keyboard +import java.awt.image.BufferedImage import java.io.File import java.text.SimpleDateFormat import java.util.* @@ -81,38 +83,51 @@ object Stratus { fun onTickEvent(event: TickEvent.ClientTickEvent) { if (event.phase == TickEvent.Phase.START && Minecraft.getMinecraft().theWorld != null && Minecraft.getMinecraft().thePlayer != null && (Minecraft.getMinecraft().currentScreen == null || Minecraft.getMinecraft().currentScreen is GuiChat)) { if (doTheThing) { - screenshot() + screenshotChat() doTheThing = false } } } - private fun screenshot() { + fun screenshotLine(line: ChatLine): BufferedImage? { val hud = Minecraft.getMinecraft().ingameGUI val chat = hud.chatGUI + val i = MathHelper.floor_float(chat.chatWidth/chat.chatScale) + return screenshot(GuiUtilRenderComponents.splitText(line.chatComponent, i, Minecraft.getMinecraft().fontRendererObj, false, false).map { it.formattedText }.reversed(), chat.chatWidth) + } + + private fun screenshotChat() { + screenshotChat(0) + } + + fun screenshotChat(scrollPos: Int) { + val hud = Minecraft.getMinecraft().ingameGUI + val chat = hud.chatGUI + val chatLines = ArrayList<String>() + filterMessages((chat as GuiNewChatHook).prevText, (chat as GuiNewChatAccessor).drawnChatLines)?.let { drawnLines -> + for (i in scrollPos until drawnLines.size.coerceAtMost(scrollPos+GuiNewChat.calculateChatboxHeight(Minecraft.getMinecraft().gameSettings.chatHeightFocused)/9)){ + chatLines.add(drawnLines[i].chatComponent.formattedText) + } - /* Render chat fully. */ - var w = chat.chatWidth - var h = chat.chatHeight - if ((chat as GuiNewChatAccessor).drawnChatLines.size < 20) { - h = (chat as GuiNewChatAccessor).drawnChatLines - .size * Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT + screenshot(chatLines, chat.chatWidth)?.let { + RenderHelper.copyBufferedImageToClipboard(it) + } } - if (w <= 0 || h <= 0 || (chat as GuiNewChatAccessor).drawnChatLines.isEmpty()) { + } + + private fun screenshot(messages: List<String>, width: Int): BufferedImage? { + if (messages.isEmpty()) { EssentialAPI.getNotifications().push("Stratus", "Chat window is empty.") - return + return null } - val chatLines: MutableList<String> = ArrayList() + val fr: FontRenderer = Minecraft.getMinecraft().fontRendererObj - for (chatLine in (chat as GuiNewChatAccessor).drawnChatLines) chatLines.add(chatLine.chatComponent.formattedText) - if (chatLines.isNotEmpty()) { - w = fr.getStringWidth(chatLines.stream().max(Comparator.comparingInt { obj: String -> obj.length }).get()) - } - val fb: Framebuffer = RenderHelper.createBindFramebuffer(w, h) - GlStateManager.translate(-2f, (160 - (180 - h)).toFloat(), 0f) - chat.drawChat(hud.updateCounter) + val fb: Framebuffer = RenderHelper.createBindFramebuffer(width, messages.size*9) val file = File(Minecraft.getMinecraft().mcDataDir, "screenshots/chat/" + fileFormatter.format(Date())) - RenderHelper.screenshotFramebuffer(fb, file) + + for (i in messages.indices) fr.drawStringWithShadow(messages[i], 0f, (messages.size-1-i)*9f, 0xffffff) + + val image = RenderHelper.screenshotFramebuffer(fb, file) Minecraft.getMinecraft().entityRenderer.setupOverlayRendering() Minecraft.getMinecraft().framebuffer.bindFramebuffer(true) EssentialAPI.getNotifications() @@ -121,5 +136,6 @@ object Stratus { EssentialAPI.getNotifications().push("Stratus", "Could not browse!") } } + return image } } diff --git a/src/main/kotlin/com/raeids/stratus/config/StratusConfig.kt b/src/main/kotlin/com/raeids/stratus/config/StratusConfig.kt index e9d2401..ecc0c09 100644 --- a/src/main/kotlin/com/raeids/stratus/config/StratusConfig.kt +++ b/src/main/kotlin/com/raeids/stratus/config/StratusConfig.kt @@ -24,6 +24,19 @@ object StratusConfig : Vigilant(File(Stratus.modDir, "${Stratus.ID}.toml"), Stra var chatSearch = true @Property( + type = PropertyType.SELECTOR, + name = "Screenshot Mode", + description = "The mode in which screenshotting will work.", + category = "Screenshotting", + options = [ + "Save To System", + "Add To Clipboard", + "Both" + ] + ) + var copyMode = 0 + + @Property( type = PropertyType.SWITCH, name = "Chat Tabs", description = "Add chat tabs.", diff --git a/src/main/kotlin/com/raeids/stratus/hook/ChatSearching.kt b/src/main/kotlin/com/raeids/stratus/hook/ChatSearching.kt index 57cfc93..6dd4904 100644 --- a/src/main/kotlin/com/raeids/stratus/hook/ChatSearching.kt +++ b/src/main/kotlin/com/raeids/stratus/hook/ChatSearching.kt @@ -22,14 +22,14 @@ private var POOL: ThreadPoolExecutor = ThreadPoolExecutor( ) } -val cache: Cache<String, List<ChatLine?>> = Caffeine.newBuilder().executor(POOL).maximumSize(5000).build() +val cache: Cache<String, List<ChatLine>> = Caffeine.newBuilder().executor(POOL).maximumSize(5000).build() -fun filterMessages(text: String, list: List<ChatLine?>?): List<ChatLine?>? { - if (list.isNullOrEmpty() || text.isBlank()) return list +fun filterMessages(text: String, list: List<ChatLine>): List<ChatLine>? { + if (text.isBlank()) return list val cached = cache.getIfPresent(text) return cached ?: run { cache.put(text, list.filter { - it != null && UTextComponent.stripFormatting(it.chatComponent.unformattedText).lowercase() + UTextComponent.stripFormatting(it.chatComponent.unformattedText).lowercase() .contains(text.lowercase()) }) cache.getIfPresent(text) diff --git a/src/main/kotlin/com/raeids/stratus/hook/CleanSearchButton.kt b/src/main/kotlin/com/raeids/stratus/hook/CleanSearchButton.kt index 4b7ba5a..7a68c75 100644 --- a/src/main/kotlin/com/raeids/stratus/hook/CleanSearchButton.kt +++ b/src/main/kotlin/com/raeids/stratus/hook/CleanSearchButton.kt @@ -1,10 +1,14 @@ package com.raeids.stratus.hook +import com.raeids.stratus.Stratus import gg.essential.universal.UResolution import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Gui import net.minecraft.client.gui.GuiTextField +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.util.ResourceLocation -class CleanSearchButton: CleanButton(3993935, {UResolution.scaledWidth - 42}, {UResolution.scaledHeight - 27}, 40, 12, "Search") { +class CleanSearchButton: CleanButton(3993935, {UResolution.scaledWidth - 14}, {UResolution.scaledHeight - 27}, 12, 12, "") { val inputField = SearchTextField() private var chatBox = false @@ -13,7 +17,6 @@ class CleanSearchButton: CleanButton(3993935, {UResolution.scaledWidth - 42}, {U } override fun onMousePress() { - println("hi") chatBox = !chatBox inputField.setEnabled(chatBox) inputField.isFocused = chatBox @@ -24,6 +27,17 @@ class CleanSearchButton: CleanButton(3993935, {UResolution.scaledWidth - 42}, {U override fun drawButton(mc: Minecraft, mouseX: Int, mouseY: Int) { inputField.drawTextBox() super.drawButton(mc, mouseX, mouseY) + if (visible) { + mc.textureManager.bindTexture(ResourceLocation(Stratus.ID, "search.png")) + if (isEnabled()) { + GlStateManager.color(224f/255f, 224f/255f, 224f/255f) + } else if (mouseX >= xPosition && mouseX <= xPosition + 10 && mouseY >= yPosition && mouseY <= yPosition + 10) { + GlStateManager.color(1f, 1f, 160f/255f) + } else { + GlStateManager.color(1f, 1f, 1f) + } + Gui.drawModalRectWithCustomSizedTexture(xPosition+1, yPosition+1, 0f, 0f, 10, 10, 10f, 10f) + } } inner class SearchTextField: GuiTextField(69420, Minecraft.getMinecraft().fontRendererObj, UResolution.scaledWidth * 4 / 5 - 60, UResolution.scaledHeight - 27, UResolution.scaledWidth / 5, 12) { diff --git a/src/main/kotlin/com/raeids/stratus/hook/ScreenshotButton.kt b/src/main/kotlin/com/raeids/stratus/hook/ScreenshotButton.kt new file mode 100644 index 0000000..70c64c2 --- /dev/null +++ b/src/main/kotlin/com/raeids/stratus/hook/ScreenshotButton.kt @@ -0,0 +1,34 @@ +package com.raeids.stratus.hook + +import com.raeids.stratus.Stratus +import com.raeids.stratus.mixin.GuiNewChatAccessor +import gg.essential.api.utils.GuiUtil +import gg.essential.universal.UResolution +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Gui +import net.minecraft.client.gui.GuiChat +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.util.ResourceLocation + +class ScreenshotButton: CleanButton(448318, { UResolution.scaledWidth - 28}, { UResolution.scaledHeight - 27}, 12, 12, "") { + + override fun onMousePress() { + val chat = Minecraft.getMinecraft().ingameGUI.chatGUI + if (GuiUtil.getOpenedScreen() is GuiChat) { + Stratus.screenshotChat((chat as GuiNewChatAccessor).scrollPos) + } + } + + override fun drawButton(mc: Minecraft, mouseX: Int, mouseY: Int) { + super.drawButton(mc, mouseX, mouseY) + if (visible) { + if (hovered) { + GlStateManager.color(1f, 1f, 160f / 255f) + } else { + GlStateManager.color(1f, 1f, 1f) + } + mc.textureManager.bindTexture(ResourceLocation(Stratus.ID, "screenshot.png")) + Gui.drawModalRectWithCustomSizedTexture(xPosition + 1, yPosition + 1, 0f, 0f, 10, 10, 10f, 10f) + } + } +}
\ No newline at end of file diff --git a/src/main/kotlin/com/raeids/stratus/utils/ImageTransferable.kt b/src/main/kotlin/com/raeids/stratus/utils/ImageTransferable.kt new file mode 100644 index 0000000..81571a5 --- /dev/null +++ b/src/main/kotlin/com/raeids/stratus/utils/ImageTransferable.kt @@ -0,0 +1,22 @@ +package com.raeids.stratus.utils + +import java.awt.Image +import java.awt.datatransfer.DataFlavor +import java.awt.datatransfer.Transferable +import java.awt.datatransfer.UnsupportedFlavorException + +class ImageTransferable(private val image: Image): Transferable { + + override fun getTransferDataFlavors(): Array<DataFlavor> { + return arrayOf(DataFlavor.imageFlavor) + } + + override fun isDataFlavorSupported(flavor: DataFlavor?): Boolean { + return DataFlavor.imageFlavor.equals(flavor) + } + + override fun getTransferData(flavor: DataFlavor?): Any { + if (isDataFlavorSupported(flavor)) return image + throw UnsupportedFlavorException(flavor) + } +}
\ No newline at end of file diff --git a/src/main/kotlin/com/raeids/stratus/utils/RenderHelper.kt b/src/main/kotlin/com/raeids/stratus/utils/RenderHelper.kt index d2aac4d..664f5de 100644 --- a/src/main/kotlin/com/raeids/stratus/utils/RenderHelper.kt +++ b/src/main/kotlin/com/raeids/stratus/utils/RenderHelper.kt @@ -1,21 +1,165 @@ package com.raeids.stratus.utils +import com.raeids.stratus.config.StratusConfig import net.minecraft.client.renderer.GlStateManager import net.minecraft.client.renderer.texture.TextureUtil import net.minecraft.client.shader.Framebuffer +import org.apache.commons.lang3.SystemUtils import org.lwjgl.BufferUtils import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL12 +import sun.awt.datatransfer.DataTransferer +import sun.awt.datatransfer.SunClipboard +import java.awt.Toolkit import java.awt.image.BufferedImage import java.io.File +import java.lang.reflect.Field +import java.lang.reflect.Method +import java.nio.ByteBuffer +import java.nio.ByteOrder import javax.imageio.ImageIO object RenderHelper { /** * Taken from https://github.com/Moulberry/HyChat + * Modified so if not on Windows just in case it will switch it to RGB and remove the transparent background. */ - fun screenshotFramebuffer(framebuffer: Framebuffer, file: File) { + fun copyBufferedImageToClipboard(bufferedImage: BufferedImage) { + if (SystemUtils.IS_OS_WINDOWS) { + try { + val width = bufferedImage.width + val height = bufferedImage.height + val hdrSize = 0x28 + val buffer: ByteBuffer = ByteBuffer.allocate(hdrSize + width * height * 4) + buffer.order(ByteOrder.LITTLE_ENDIAN) + //Header size + buffer.putInt(hdrSize) + //Width + buffer.putInt(width) + //Int32 biHeight; + buffer.putInt(height) + //Int16 biPlanes; + buffer.put(1.toByte()) + buffer.put(0.toByte()) + //Int16 biBitCount; + buffer.put(32.toByte()) + buffer.put(0.toByte()) + //Compression + buffer.putInt(0) + //Int32 biSizeImage; + buffer.putInt(width * height * 4) + buffer.putInt(0) + buffer.putInt(0) + buffer.putInt(0) + buffer.putInt(0) + + //Image data + for (y in 0 until height) { + for (x in 0 until width) { + val argb: Int = bufferedImage.getRGB(x, height - y - 1) + if (argb shr 24 and 0xFF == 0) { + buffer.putInt(0x00000000) + } else { + buffer.putInt(argb) + } + } + } + buffer.flip() + val hdrSizev5 = 0x7C + val bufferv5: ByteBuffer = ByteBuffer.allocate(hdrSizev5 + width * height * 4) + bufferv5.order(ByteOrder.LITTLE_ENDIAN) + //Header size + bufferv5.putInt(hdrSizev5) + //Width + bufferv5.putInt(width) + //Int32 biHeight; + bufferv5.putInt(height) + //Int16 biPlanes; + bufferv5.put(1.toByte()) + bufferv5.put(0.toByte()) + //Int16 biBitCount; + bufferv5.put(32.toByte()) + bufferv5.put(0.toByte()) + //Compression + bufferv5.putInt(0) + //Int32 biSizeImage; + bufferv5.putInt(width * height * 4) + bufferv5.putInt(0) + bufferv5.putInt(0) + bufferv5.putInt(0) + bufferv5.putInt(0) + bufferv5.order(ByteOrder.BIG_ENDIAN) + bufferv5.putInt(-0x1000000) + bufferv5.putInt(0x00FF0000) + bufferv5.putInt(0x0000FF00) + bufferv5.putInt(0x000000FF) + bufferv5.order(ByteOrder.LITTLE_ENDIAN) + + //BGRs + bufferv5.put(0x42.toByte()) + bufferv5.put(0x47.toByte()) + bufferv5.put(0x52.toByte()) + bufferv5.put(0x73.toByte()) + for (i in bufferv5.position() until hdrSizev5) { + bufferv5.put(0.toByte()) + } + + //Image data + for (y in 0 until height) { + for (x in 0 until width) { + val argb: Int = bufferedImage.getRGB(x, height - y - 1) + val a = argb shr 24 and 0xFF + var r = argb shr 16 and 0xFF + var g = argb shr 8 and 0xFF + var b = argb and 0xFF + r = r * a / 0xFF + g = g * a / 0xFF + b = b * a / 0xFF + bufferv5.putInt(a shl 24 or (r shl 16) or (g shl 8) or b) + } + } + bufferv5.flip() + val clip = Toolkit.getDefaultToolkit().systemClipboard + val dt = DataTransferer.getInstance() + val f: Field = dt.javaClass.getDeclaredField("CF_DIB") + f.isAccessible = true + val format: Long = f.getLong(null) + val openClipboard: Method = clip.javaClass.getDeclaredMethod("openClipboard", SunClipboard::class.java) + openClipboard.isAccessible = true + openClipboard.invoke(clip, clip) + val publishClipboardData: Method = clip.javaClass.getDeclaredMethod( + "publishClipboardData", + Long::class.javaPrimitiveType, + ByteArray::class.java + ) + publishClipboardData.isAccessible = true + val arr: ByteArray = buffer.array() + publishClipboardData.invoke(clip, format, arr) + val closeClipboard: Method = clip.javaClass.getDeclaredMethod("closeClipboard") + closeClipboard.isAccessible = true + closeClipboard.invoke(clip) + return + } catch (e: Exception) { + e.printStackTrace() + } + } + val pixels: IntArray = bufferedImage.getRGB(0, 0, bufferedImage.width, bufferedImage.height, null, 0, bufferedImage.width) + val newImage = BufferedImage(bufferedImage.width, bufferedImage.height, BufferedImage.TYPE_INT_RGB) + newImage.setRGB(0, 0, newImage.width, newImage.height, pixels, 0, newImage.width) + + try { + Toolkit.getDefaultToolkit().systemClipboard.setContents(ImageTransferable(bufferedImage), null) + } catch (e: Exception) { + e.printStackTrace() + } + } + + + /** + * Taken from https://github.com/Moulberry/HyChat + */ + fun screenshotFramebuffer(framebuffer: Framebuffer, file: File): BufferedImage { val w = framebuffer.framebufferWidth val h = framebuffer.framebufferHeight val i = w * h @@ -34,12 +178,15 @@ object RenderHelper { bufferedimage.setRGB(l, k - j, pixelValues[k * framebuffer.framebufferTextureWidth + l]) } } - try { - file.parentFile.mkdirs() - ImageIO.write(bufferedimage, "png", file) - } catch (e: Exception) { - e.printStackTrace() + if (StratusConfig.copyMode != 1) { + try { + file.parentFile.mkdirs() + ImageIO.write(bufferedimage, "png", file) + } catch (e: Exception) { + e.printStackTrace() + } } + return bufferedimage } /** diff --git a/src/main/resources/assets/stratus/screenshot.png b/src/main/resources/assets/stratus/screenshot.png Binary files differnew file mode 100644 index 0000000..8b6cc48 --- /dev/null +++ b/src/main/resources/assets/stratus/screenshot.png diff --git a/src/main/resources/assets/stratus/search.png b/src/main/resources/assets/stratus/search.png Binary files differnew file mode 100644 index 0000000..a5be877 --- /dev/null +++ b/src/main/resources/assets/stratus/search.png |