diff options
author | Wyvest <45589059+Wyvest@users.noreply.github.com> | 2021-12-21 17:55:14 +0700 |
---|---|---|
committer | Wyvest <45589059+Wyvest@users.noreply.github.com> | 2021-12-21 17:55:14 +0700 |
commit | 870da2e7fcf370233c9e64d55dd0295cec6665f0 (patch) | |
tree | aad94b09e4cc0d8362d516a0696a0b1d1c23f6bc /src/main/kotlin | |
download | Chatting-870da2e7fcf370233c9e64d55dd0295cec6665f0.tar.gz Chatting-870da2e7fcf370233c9e64d55dd0295cec6665f0.tar.bz2 Chatting-870da2e7fcf370233c9e64d55dd0295cec6665f0.zip |
initial commit
Diffstat (limited to 'src/main/kotlin')
7 files changed, 436 insertions, 0 deletions
diff --git a/src/main/kotlin/com/raeids/stratus/Stratus.kt b/src/main/kotlin/com/raeids/stratus/Stratus.kt new file mode 100644 index 0000000..3c8984b --- /dev/null +++ b/src/main/kotlin/com/raeids/stratus/Stratus.kt @@ -0,0 +1,115 @@ +package com.raeids.stratus + +import com.raeids.stratus.command.StratusCommand +import com.raeids.stratus.config.StratusConfig +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.settings.KeyBinding +import net.minecraft.client.shader.Framebuffer +import net.minecraftforge.common.MinecraftForge.EVENT_BUS +import net.minecraftforge.fml.client.registry.ClientRegistry +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.event.FMLInitializationEvent +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.io.File +import java.io.IOException +import java.text.SimpleDateFormat +import java.util.* + + +@Mod( + modid = Stratus.ID, + name = Stratus.NAME, + version = Stratus.VER, + modLanguageAdapter = "gg.essential.api.utils.KotlinAdapter" +) +object Stratus { + + val keybind = KeyBinding("Screenshot Chat", Keyboard.KEY_NONE, "Stratus") + const val NAME = "@NAME@" + const val VER = "@VER@" + const val ID = "@ID@" + var doTheThing = false + lateinit var jarFile: File + private set + + val modDir = File(File(Minecraft.getMinecraft().mcDataDir, "W-OVERFLOW"), NAME) + + @Mod.EventHandler + fun onFMLPreInitialization(event: FMLPreInitializationEvent) { + if (!modDir.exists()) modDir.mkdirs() + jarFile = event.sourceFile + } + + private val fileFormatter: SimpleDateFormat = SimpleDateFormat("yyyy-MM-dd_HH.mm.ss'.png'") + + private fun screenshot() { + val hud = Minecraft.getMinecraft().ingameGUI + val chat = hud.chatGUI + + /* 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 + } + if (w <= 0 || h <= 0 || (chat as GuiNewChatAccessor).drawnChatLines.isEmpty()) { + EssentialAPI.getNotifications().push("Stratus", "Chat window is empty.") + return + } + 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 file = File(Minecraft.getMinecraft().mcDataDir, "screenshots/chat/" + fileFormatter.format(Date())) + RenderHelper.screenshotFramebuffer(fb, file) + Minecraft.getMinecraft().entityRenderer.setupOverlayRendering() + Minecraft.getMinecraft().framebuffer.bindFramebuffer(true) + EssentialAPI.getNotifications() + .push("Stratus", "Chat screenshotted successfully.\nClick to open.") { + try { + UDesktop.browse(file.toURI()) + } catch (e: IOException) { + e.printStackTrace() + } catch (e: UnsupportedOperationException) { + e.printStackTrace() + EssentialAPI.getNotifications().push("Stratus", "Could not browse!") + } + } + } + + @Mod.EventHandler + fun onInitialization(event: FMLInitializationEvent) { + StratusConfig.preload() + StratusCommand.register() + ClientRegistry.registerKeyBinding(keybind) + EVENT_BUS.register(this) + Updater.update() + } + + @SubscribeEvent + 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() + doTheThing = false + } + } + } +} diff --git a/src/main/kotlin/com/raeids/stratus/command/StratusCommand.kt b/src/main/kotlin/com/raeids/stratus/command/StratusCommand.kt new file mode 100644 index 0000000..2954885 --- /dev/null +++ b/src/main/kotlin/com/raeids/stratus/command/StratusCommand.kt @@ -0,0 +1,15 @@ +package com.raeids.stratus.command + +import com.raeids.stratus.Stratus +import com.raeids.stratus.config.StratusConfig +import gg.essential.api.EssentialAPI +import gg.essential.api.commands.Command +import gg.essential.api.commands.DefaultHandler + +object StratusCommand : Command(Stratus.ID, true) { + + @DefaultHandler + fun handle() { + EssentialAPI.getGuiUtil().openScreen(StratusConfig.gui()) + } +}
\ No newline at end of file diff --git a/src/main/kotlin/com/raeids/stratus/config/StratusConfig.kt b/src/main/kotlin/com/raeids/stratus/config/StratusConfig.kt new file mode 100644 index 0000000..7a2dc65 --- /dev/null +++ b/src/main/kotlin/com/raeids/stratus/config/StratusConfig.kt @@ -0,0 +1,48 @@ +package com.raeids.stratus.config + +import com.raeids.stratus.Stratus +import com.raeids.stratus.updater.DownloadGui +import com.raeids.stratus.updater.Updater +import gg.essential.api.EssentialAPI +import gg.essential.vigilance.Vigilant +import gg.essential.vigilance.data.Property +import gg.essential.vigilance.data.PropertyType +import java.io.File + +object StratusConfig : Vigilant(File(Stratus.modDir, "${Stratus.ID}.toml"), Stratus.NAME) { + + @Property( + type = PropertyType.SWITCH, + name = "Chat Searching", + description = "Add a chat search bar.", + category = "General" + ) + var chatSearch = true + + @Property( + type = PropertyType.SWITCH, + name = "Show Update Notification", + description = "Show a notification when you start Minecraft informing you of new updates.", + category = "Updater" + ) + var showUpdate = true + + @Property( + type = PropertyType.BUTTON, + name = "Update Now", + description = "Update by clicking the button.", + category = "Updater" + ) + fun update() { + if (Updater.shouldUpdate) EssentialAPI.getGuiUtil() + .openScreen(DownloadGui()) else EssentialAPI.getNotifications() + .push( + Stratus.NAME, + "No update had been detected at startup, and thus the update GUI has not been shown." + ) + } + + init { + initialize() + } +}
\ No newline at end of file diff --git a/src/main/kotlin/com/raeids/stratus/hook/ChatHook.kt b/src/main/kotlin/com/raeids/stratus/hook/ChatHook.kt new file mode 100644 index 0000000..c056161 --- /dev/null +++ b/src/main/kotlin/com/raeids/stratus/hook/ChatHook.kt @@ -0,0 +1,41 @@ +package com.raeids.stratus.hook + +import gg.essential.universal.wrappers.message.UTextComponent +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.ChatLine +import net.minecraft.client.gui.GuiTextField +import net.minecraft.client.gui.ScaledResolution + +var inputField: GuiTextField? = null +var sr: ScaledResolution? = null +var prevText = "" + +fun initGui() { + sr = ScaledResolution(Minecraft.getMinecraft()) + inputField = GuiTextField( + 694209000, + Minecraft.getMinecraft().fontRendererObj, + sr!!.scaledWidth * 4 / 5 - 1, + sr!!.scaledHeight - 13, + sr!!.scaledWidth / 5, + 12 + ) + inputField!!.maxStringLength = 100 + inputField!!.enableBackgroundDrawing = true + inputField!!.isFocused = false + inputField!!.text = "" + inputField!!.setCanLoseFocus(true) + prevText = "" +} + +fun updateScreen() { + inputField?.updateCursorCounter() +} + +fun filterMessages(list: List<ChatLine?>?): List<ChatLine?>? { + if (inputField == null || list == null || inputField?.text.isNullOrBlank()) return list + return list.filter { + it != null && UTextComponent.stripFormatting(it.chatComponent.unformattedText).lowercase() + .contains(inputField!!.text!!.lowercase()) + } +}
\ No newline at end of file diff --git a/src/main/kotlin/com/raeids/stratus/updater/DownloadGui.kt b/src/main/kotlin/com/raeids/stratus/updater/DownloadGui.kt new file mode 100644 index 0000000..d3fa69e --- /dev/null +++ b/src/main/kotlin/com/raeids/stratus/updater/DownloadGui.kt @@ -0,0 +1,53 @@ +package com.raeids.stratus.updater + +import com.raeids.stratus.Stratus +import gg.essential.api.EssentialAPI +import gg.essential.api.gui.buildConfirmationModal +import gg.essential.api.utils.Multithreading +import gg.essential.elementa.WindowScreen +import gg.essential.elementa.dsl.childOf +import java.io.File + +class DownloadGui : WindowScreen(true, true, true, -1) { + override fun initScreen(width: Int, height: Int) { + super.initScreen(width, height) + EssentialAPI.getEssentialComponentFactory().buildConfirmationModal { + this.text = "Are you sure you want to update?" + this.secondaryText = + "(This will update from v${Stratus.VER} to ${Updater.latestTag})" + this.onConfirm = { + restorePreviousScreen() + Multithreading.runAsync { + if (Updater.download( + Updater.updateUrl, + File( + "mods/${Stratus.NAME}-${ + Updater.latestTag!!.substringAfter("v") + }.jar" + ) + ) && Updater.download( + "https://github.com/Wyvest/Deleter/releases/download/v1.2/Deleter-1.2.jar", + File(Stratus.modDir.parentFile, "Deleter-1.2.jar") + ) + ) { + EssentialAPI.getNotifications() + .push( + Stratus.NAME, + "The ingame updater has successfully installed the newest version." + ) + Updater.addShutdownHook() + Updater.shouldUpdate = false + } else { + EssentialAPI.getNotifications().push( + Stratus.NAME, + "The ingame updater has NOT installed the newest version as something went wrong." + ) + } + } + } + this.onDeny = { + restorePreviousScreen() + } + } childOf this.window + } +}
\ No newline at end of file diff --git a/src/main/kotlin/com/raeids/stratus/updater/Updater.kt b/src/main/kotlin/com/raeids/stratus/updater/Updater.kt new file mode 100644 index 0000000..2f48cdb --- /dev/null +++ b/src/main/kotlin/com/raeids/stratus/updater/Updater.kt @@ -0,0 +1,101 @@ +package com.raeids.stratus.updater + +import com.raeids.stratus.Stratus +import com.raeids.stratus.config.StratusConfig +import gg.essential.api.EssentialAPI +import gg.essential.api.utils.Multithreading +import gg.essential.api.utils.WebUtil.downloadToFile +import gg.essential.api.utils.WebUtil.fetchJSON +import gg.essential.universal.UDesktop.open +import net.minecraft.client.Minecraft +import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion +import java.io.File +import java.io.IOException + +object Updater { + var updateUrl = "" + var latestTag: String? = null + var shouldUpdate = false + + fun update() { + Multithreading.runAsync { + try { + val latestRelease = + fetchJSON("https://api.github.com/repos/W-OVERFLOW/${Stratus.ID}/releases/latest").getObject() + latestTag = latestRelease["tag_name"].asString + val currentVersion = + DefaultArtifactVersion(Stratus.VER.substringBefore("-")) + val latestVersion = DefaultArtifactVersion(latestTag!!.substringAfter("v").substringBefore("-")) + if (currentVersion >= latestVersion) { + return@runAsync + } + updateUrl = + latestRelease["assets"].asJsonArray[0].asJsonObject["browser_download_url"] + .asString + if (updateUrl.isNotEmpty()) { + if (StratusConfig.showUpdate) { + EssentialAPI.getNotifications().push( + Stratus.NAME, + "${Stratus.NAME} has a new update ($latestTag)! Click here to download it automatically!" + ) { EssentialAPI.getGuiUtil().openScreen(DownloadGui()) } + } + shouldUpdate = true + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + + fun download(url: String, file: File): Boolean { + var url = url + if (file.exists()) return true + url = url.replace(" ", "%20") + try { + downloadToFile(url, file, "${Stratus.NAME}/${Stratus.VER}") + } catch (e: Exception) { + e.printStackTrace() + return false + } + return file.exists() + } + + /** + * Adapted from RequisiteLaunchwrapper under LGPLv3 + * https://github.com/Qalcyo/RequisiteLaunchwrapper/blob/main/LICENSE + */ + fun addShutdownHook() { + Runtime.getRuntime().addShutdownHook(Thread { + println("Opening Deleter task...") + try { + val runtime = javaRuntime + if (Minecraft.isRunningOnMac) { + open(Stratus.jarFile.parentFile) + } + val file = File(Stratus.modDir.parentFile, "Deleter-1.2.jar") + Runtime.getRuntime() + .exec("\"" + runtime + "\" -jar \"" + file.absolutePath + "\" \"" + Stratus.jarFile.absolutePath + "\"") + } catch (e: Exception) { + e.printStackTrace() + } + Thread.currentThread().interrupt() + }) + } + + /** + * Gets the current Java runtime being used. + * + * @link https://stackoverflow.com/a/47925649 + */ + @get:Throws(IOException::class) + val javaRuntime: String + get() { + val os = System.getProperty("os.name") + val java = System.getProperty("java.home") + File.separator + "bin" + File.separator + + if (os != null && os.lowercase().startsWith("windows")) "java.exe" else "java" + if (!File(java).isFile) { + throw IOException("Unable to find suitable java runtime at $java") + } + return java + } +}
\ 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 new file mode 100644 index 0000000..d2aac4d --- /dev/null +++ b/src/main/kotlin/com/raeids/stratus/utils/RenderHelper.kt @@ -0,0 +1,63 @@ +package com.raeids.stratus.utils + +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.texture.TextureUtil +import net.minecraft.client.shader.Framebuffer +import org.lwjgl.BufferUtils +import org.lwjgl.opengl.GL11 +import org.lwjgl.opengl.GL12 +import java.awt.image.BufferedImage +import java.io.File +import javax.imageio.ImageIO + + +object RenderHelper { + /** + * Taken from https://github.com/Moulberry/HyChat + */ + fun screenshotFramebuffer(framebuffer: Framebuffer, file: File) { + val w = framebuffer.framebufferWidth + val h = framebuffer.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(framebuffer.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 = framebuffer.framebufferTextureHeight - framebuffer.framebufferHeight + for (k in j until framebuffer.framebufferTextureHeight) { + for (l in 0 until framebuffer.framebufferWidth) { + bufferedimage.setRGB(l, k - j, pixelValues[k * framebuffer.framebufferTextureWidth + l]) + } + } + try { + file.parentFile.mkdirs() + ImageIO.write(bufferedimage, "png", file) + } catch (e: Exception) { + e.printStackTrace() + } + } + + /** + * 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 + } +}
\ No newline at end of file |