aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/org/polyfrost/chatting/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/org/polyfrost/chatting/utils')
-rw-r--r--src/main/kotlin/org/polyfrost/chatting/utils/EaseOutQuart.kt7
-rw-r--r--src/main/kotlin/org/polyfrost/chatting/utils/ModCompatHooks.kt100
-rw-r--r--src/main/kotlin/org/polyfrost/chatting/utils/RenderUtils.kt259
3 files changed, 366 insertions, 0 deletions
diff --git a/src/main/kotlin/org/polyfrost/chatting/utils/EaseOutQuart.kt b/src/main/kotlin/org/polyfrost/chatting/utils/EaseOutQuart.kt
new file mode 100644
index 0000000..4b6b7a5
--- /dev/null
+++ b/src/main/kotlin/org/polyfrost/chatting/utils/EaseOutQuart.kt
@@ -0,0 +1,7 @@
+package org.polyfrost.chatting.utils
+
+import cc.polyfrost.oneconfig.gui.animations.Animation
+
+class EaseOutQuart(duration: Float, start: Float, end: Float, reverse: Boolean) : Animation(duration, start, end, reverse) {
+ override fun animate(x: Float) = -1 * (x - 1) * (x - 1) * (x - 1) * (x - 1) + 1
+} \ No newline at end of file
diff --git a/src/main/kotlin/org/polyfrost/chatting/utils/ModCompatHooks.kt b/src/main/kotlin/org/polyfrost/chatting/utils/ModCompatHooks.kt
new file mode 100644
index 0000000..ad7d329
--- /dev/null
+++ b/src/main/kotlin/org/polyfrost/chatting/utils/ModCompatHooks.kt
@@ -0,0 +1,100 @@
+package org.polyfrost.chatting.utils
+
+import cc.polyfrost.oneconfig.renderer.TextRenderer
+import cc.polyfrost.oneconfig.utils.dsl.getAlpha
+import cc.polyfrost.oneconfig.utils.dsl.mc
+import org.polyfrost.chatting.Chatting.isBetterChat
+import org.polyfrost.chatting.Chatting.isPatcher
+import org.polyfrost.chatting.config.ChattingConfig.offsetNonPlayerMessages
+import org.polyfrost.chatting.config.ChattingConfig.showChatHeads
+import org.polyfrost.chatting.config.ChattingConfig.textRenderType
+import club.sk1er.patcher.config.PatcherConfig
+import com.llamalad7.betterchat.BetterChat
+import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.ChatLine
+import net.minecraft.client.gui.FontRenderer
+import net.minecraft.client.gui.Gui
+import net.minecraft.client.renderer.GlStateManager
+import org.polyfrost.chatting.hook.ChatLineHook
+import org.polyfrost.chatting.hook.GuiNewChatHook
+
+// This exists because mixin doesn't like dummy classes
+object ModCompatHooks {
+ @JvmStatic
+ val xOffset
+ get() = if (isBetterChat) BetterChat.getSettings().xOffset else 0
+
+ @JvmStatic
+ val yOffset
+ get() = if (isBetterChat) BetterChat.getSettings().yOffset else 0
+
+ @JvmStatic
+ val chatPosition
+ get() = if (isPatcher && PatcherConfig.chatPosition) 12 else 0
+
+ @JvmStatic
+ val betterChatSmoothMessages
+ get() = if (isBetterChat) BetterChat.getSettings().smooth else false
+
+ @JvmStatic
+ val extendedChatLength
+ get() = if (isPatcher) 32667 else 0
+
+ @JvmStatic
+ val fontRenderer: FontRenderer
+ get() = Minecraft.getMinecraft().fontRendererObj
+
+ @JvmStatic
+ fun redirectDrawString(text: String, x: Float, y: Float, color: Int, chatLine: ChatLine, screenshot: Boolean): Int {
+ var actualX = x
+ if (showChatHeads && !screenshot) {
+ val hook = chatLine as ChatLineHook
+ if (hook.hasDetected() || offsetNonPlayerMessages) {
+ actualX += 10f
+ }
+ val networkPlayerInfo = hook.playerInfo
+ if (networkPlayerInfo != null) {
+ GlStateManager.enableBlend()
+ GlStateManager.enableAlpha()
+ GlStateManager.enableTexture2D()
+ mc.textureManager.bindTexture(networkPlayerInfo.locationSkin)
+ GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0)
+ GlStateManager.color(1.0f, 1.0f, 1.0f, color.getAlpha() / 255f)
+ Gui.drawScaledCustomSizeModalRect(
+ (x).toInt(),
+ (y - 1f).toInt(),
+ 8.0f,
+ 8.0f,
+ 8,
+ 8,
+ 8,
+ 8,
+ 64.0f,
+ 64.0f
+ )
+ Gui.drawScaledCustomSizeModalRect(
+ (x).toInt(),
+ (y - 1f).toInt(),
+ 40.0f,
+ 8.0f,
+ 8,
+ 8,
+ 8,
+ 8,
+ 64.0f,
+ 64.0f
+ )
+ GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f)
+ }
+ }
+ return when (textRenderType) {
+ 0 -> fontRenderer.drawString(text, actualX, y, color, false)
+ 2 -> TextRenderer.drawBorderedText(text,
+ actualX,
+ y,
+ color,
+ (Minecraft.getMinecraft().ingameGUI.chatGUI as GuiNewChatHook).textOpacity)
+ else -> fontRenderer.drawString(text, actualX, y, color, true)
+ }
+ }
+}
diff --git a/src/main/kotlin/org/polyfrost/chatting/utils/RenderUtils.kt b/src/main/kotlin/org/polyfrost/chatting/utils/RenderUtils.kt
new file mode 100644
index 0000000..6eaa78b
--- /dev/null
+++ b/src/main/kotlin/org/polyfrost/chatting/utils/RenderUtils.kt
@@ -0,0 +1,259 @@
+@file:JvmName("RenderUtils")
+
+package org.polyfrost.chatting.utils
+
+import cc.polyfrost.oneconfig.utils.IOUtils
+import org.polyfrost.chatting.config.ChattingConfig
+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
+
+/**
+ * Taken from https://github.com/Moulberry/HyChat
+ */
+fun createBindFramebuffer(w: Int, h: Int): Framebuffer {
+ val framebuffer = Framebuffer(w, h, false)
+ framebuffer.framebufferColor[0] = 0x36 / 255f
+ framebuffer.framebufferColor[1] = 0x39 / 255f
+ framebuffer.framebufferColor[2] = 0x3F / 255f
+ framebuffer.framebufferClear()
+ GlStateManager.matrixMode(5889)
+ GlStateManager.loadIdentity()
+ GlStateManager.ortho(0.0, w.toDouble(), h.toDouble(), 0.0, 1000.0, 3000.0)
+ GlStateManager.matrixMode(5888)
+ GlStateManager.loadIdentity()
+ GlStateManager.translate(0.0f, 0.0f, -2000.0f)
+ framebuffer.bindFramebuffer(true)
+ return framebuffer
+}
+
+/**
+ * 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 BufferedImage.copyToClipboard() {
+ if (SystemUtils.IS_OS_WINDOWS) {
+ try {
+ val width = this.width
+ val height = this.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 = this.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 = this.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 =
+ this.getRGB(0, 0, this.width, this.height, null, 0, this.width)
+ val newImage = BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB)
+ newImage.setRGB(0, 0, newImage.width, newImage.height, pixels, 0, newImage.width)
+
+ try {
+ IOUtils.copyImageToClipboard(this)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+}
+
+/**
+ * Taken from https://github.com/Moulberry/HyChat
+ */
+fun Framebuffer.screenshot(file: File): BufferedImage {
+ val w = this.framebufferWidth
+ val h = this.framebufferHeight
+ val i = w * h
+ val pixelBuffer = BufferUtils.createIntBuffer(i)
+ val pixelValues = IntArray(i)
+ GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1)
+ GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1)
+ GlStateManager.bindTexture(this.framebufferTexture)
+ GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer)
+ pixelBuffer[pixelValues] //Load buffer into array
+ TextureUtil.processPixelValues(pixelValues, w, h) //Flip vertically
+ val bufferedimage = BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB)
+ val j = this.framebufferTextureHeight - this.framebufferHeight
+ for (k in j until this.framebufferTextureHeight) {
+ for (l in 0 until this.framebufferWidth) {
+ bufferedimage.setRGB(l, k - j, pixelValues[k * this.framebufferTextureWidth + l])
+ }
+ }
+ if (ChattingConfig.copyMode != 1) {
+ try {
+ file.parentFile.mkdirs()
+ ImageIO.write(bufferedimage, "png", file)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ return bufferedimage
+}
+/*/
+private val timePattern = Regex("\\[\\d+:\\d+:\\d+]")
+private var lastLines = mutableListOf<ChatLine>()
+fun timestampPre() {
+ if (!ChattingConfig.showTimestampHover) return
+ val drawnChatLines = (Minecraft.getMinecraft().ingameGUI.chatGUI as GuiNewChatAccessor).drawnChatLines
+ val chatLine = getChatLineOverMouse(UMouse.getTrueX().roundToInt(), UMouse.getTrueY().roundToInt())
+
+ lastLines.clear()
+ for (line in drawnChatLines) {
+ val chatComponent = line.chatComponent.createCopy()
+ val newline = ChatLine(line.updatedCounter, chatComponent, line.chatLineID)
+ lastLines.add(newline)
+ }
+
+ drawnChatLines.map {
+ if (it != chatLine) it.chatComponent.siblings.removeAll { itt ->
+ timePattern.find(ChatColor.stripControlCodes(itt.unformattedText)!!) != null
+ }
+ }
+}
+
+fun timestampPost() {
+ if (!ChattingConfig.showTimestampHover) return
+ val drawnChatLines = (Minecraft.getMinecraft().ingameGUI.chatGUI as GuiNewChatAccessor).drawnChatLines
+ drawnChatLines.clear()
+ drawnChatLines.addAll(lastLines)
+}
+
+private fun getChatLineOverMouse(mouseX: Int, mouseY: Int): ChatLine? {
+ val chat = Minecraft.getMinecraft().ingameGUI.chatGUI
+ if (!chat.chatOpen) return null
+ val scaledResolution = ScaledResolution(Minecraft.getMinecraft())
+ val i = scaledResolution.scaleFactor
+ val f = chat.chatScale
+ val j = MathHelper.floor_float((mouseX / i - 3).toFloat() / f)
+ val k = MathHelper.floor_float((mouseY / i - 27).toFloat() / f)
+ if (j < 0 || k < 0) return null
+ val drawnChatLines = (chat as GuiNewChatAccessor).drawnChatLines
+ val l = chat.lineCount.coerceAtMost(drawnChatLines.size)
+ if (j <= MathHelper.floor_float(chat.chatWidth.toFloat() / f) && k < fontRenderer.FONT_HEIGHT * l + l) {
+ val m = k / Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT + chat.scrollPos
+ if (m >= 0 && m < drawnChatLines.size)
+ return drawnChatLines[m]
+ }
+ return null
+}
+
+ */ \ No newline at end of file