aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhannibal2 <24389977+hannibal00212@users.noreply.github.com>2023-08-03 23:37:13 +0200
committerhannibal2 <24389977+hannibal00212@users.noreply.github.com>2023-08-03 23:37:13 +0200
commitbb4d8d809aa576ad70cf91f8c16cea6f083f69fe (patch)
treeec4a2ac2de097c584bbf195653f92b699eae8689
parentdb51db7bfda2f660bb798aa39804c255c49f39d5 (diff)
parenta4c61672d93aaf7418568ca6b3704289d890f48b (diff)
downloadskyhanni-bb4d8d809aa576ad70cf91f8c16cea6f083f69fe.tar.gz
skyhanni-bb4d8d809aa576ad70cf91f8c16cea6f083f69fe.tar.bz2
skyhanni-bb4d8d809aa576ad70cf91f8c16cea6f083f69fe.zip
Merge branch 'feat/chatfiltergui' into beta
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/ChatManager.kt73
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilterGui.kt119
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/chat/CompactBestiaryChatMessage.kt10
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/IdentityCharacteristics.kt12
6 files changed, 210 insertions, 10 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
index 14650eff9..7e314e16d 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
@@ -135,7 +135,7 @@ class SkyHanniMod {
// utils
loadModule(this)
- loadModule(ChatManager())
+ loadModule(ChatManager)
loadModule(HypixelData())
loadModule(DungeonData())
loadModule(ScoreboardData())
diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
index 66f291f26..e83a14c5c 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
+++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
@@ -4,9 +4,11 @@ import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.config.ConfigGuiManager
import at.hannibal2.skyhanni.config.commands.SimpleCommand.ProcessCommandRunnable
import at.hannibal2.skyhanni.data.ApiDataLoader
+import at.hannibal2.skyhanni.data.ChatManager
import at.hannibal2.skyhanni.data.GuiEditManager
import at.hannibal2.skyhanni.features.bingo.BingoCardDisplay
import at.hannibal2.skyhanni.features.bingo.BingoNextStepHelper
+import at.hannibal2.skyhanni.features.chat.ChatFilterGui
import at.hannibal2.skyhanni.features.event.diana.BurrowWarpHelper
import at.hannibal2.skyhanni.features.event.diana.InquisitorWaypointShare
import at.hannibal2.skyhanni.features.garden.GardenAPI
@@ -48,6 +50,7 @@ object Commands {
ConfigGuiManager.openConfigGui(it.joinToString(" "))
}
} else {
+ val arr = mutableListOf<String>()
ConfigGuiManager.openConfigGui()
}
}
@@ -186,6 +189,7 @@ object Commands {
private fun developersCodingHelp() {
registerCommand("shtest", "Unused test command.") { SkyHanniTestCommand.testCommand(it) }
registerCommand("shreloadlocalrepo", "Reloading the local repo data") { SkyHanniMod.repo.reloadLocalRepo() }
+ registerCommand("shchathistory", "Show the unfiltered chat history") { ChatManager.openChatFilterGUI() }
registerCommand(
"shstoplisteners",
"Unregistering all loaded forge event listeners"
diff --git a/src/main/java/at/hannibal2/skyhanni/data/ChatManager.kt b/src/main/java/at/hannibal2/skyhanni/data/ChatManager.kt
index 643ef46ff..8b6330f6d 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/ChatManager.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/ChatManager.kt
@@ -1,26 +1,67 @@
package at.hannibal2.skyhanni.data
+import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.events.LorenzActionBarEvent
import at.hannibal2.skyhanni.events.LorenzChatEvent
import at.hannibal2.skyhanni.events.PacketEvent
import at.hannibal2.skyhanni.events.SeaCreatureFishEvent
+import at.hannibal2.skyhanni.features.chat.ChatFilterGui
import at.hannibal2.skyhanni.features.fishing.SeaCreatureManager
+import at.hannibal2.skyhanni.utils.IdentityCharacteristics
import at.hannibal2.skyhanni.utils.LorenzLogger
import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.makeAccessible
+import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.ChatLine
+import net.minecraft.client.gui.GuiNewChat
import net.minecraft.event.HoverEvent
import net.minecraft.network.play.server.S02PacketChat
+import net.minecraft.util.EnumChatFormatting
import net.minecraft.util.IChatComponent
import net.minecraftforge.client.event.ClientChatReceivedEvent
import net.minecraftforge.fml.common.eventhandler.EventPriority
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.relauncher.ReflectionHelper
+import java.lang.invoke.MethodHandles
-class ChatManager {
+object ChatManager {
private val loggerAll = LorenzLogger("chat/all")
private val loggerFiltered = LorenzLogger("chat/blocked")
private val loggerAllowed = LorenzLogger("chat/allowed")
private val loggerModified = LorenzLogger("chat/modified")
private val loggerFilteredTypes = mutableMapOf<String, LorenzLogger>()
+ private val messageHistory =
+ object : LinkedHashMap<IdentityCharacteristics<IChatComponent>, MessageFilteringResult>() {
+ override fun removeEldestEntry(eldest: MutableMap.MutableEntry<IdentityCharacteristics<IChatComponent>, MessageFilteringResult>?): Boolean {
+ return size > 100
+ }
+ }
+
+ fun getRecentMessageHistory(): List<MessageFilteringResult> = messageHistory.toList().map { it.second }
+
+ enum class ActionKind(format: Any) {
+ BLOCKED(EnumChatFormatting.RED.toString() + EnumChatFormatting.BOLD),
+ RETRACTED(EnumChatFormatting.DARK_PURPLE.toString() + EnumChatFormatting.BOLD),
+ MODIFIED(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD),
+ ALLOWED(EnumChatFormatting.GREEN),
+ ;
+
+ val renderedString = "$format$name"
+
+ companion object {
+ val maxLength by lazy {
+ entries.maxOf { Minecraft.getMinecraft().fontRendererObj.getStringWidth(it.renderedString) }
+ }
+ }
+ }
+
+ data class MessageFilteringResult(
+ val message: IChatComponent,
+ var actionKind: ActionKind,
+ var actionReason: String?,
+ val modified: IChatComponent?
+ )
@SubscribeEvent(priority = EventPriority.LOW, receiveCanceled = true)
fun onActionBarPacket(event: PacketEvent.ReceiveEvent) {
@@ -43,7 +84,7 @@ class ChatManager {
val message = LorenzUtils.stripVanillaMessage(original.formattedText)
if (message.startsWith("§f{\"server\":\"")) return
-
+ val key = IdentityCharacteristics(original)
val chatEvent = LorenzChatEvent(message, original)
if (!isSoopyMessage(event.message)) {
chatEvent.postAndCatch()
@@ -56,6 +97,7 @@ class ChatManager {
loggerAll.log("[$blockReason] $message")
loggerFilteredTypes.getOrPut(blockReason) { LorenzLogger("chat/filter_blocked/$blockReason") }
.log(message)
+ messageHistory.put(key, MessageFilteringResult(original, ActionKind.BLOCKED, blockReason, null))
return
}
@@ -67,6 +109,9 @@ class ChatManager {
loggerModified.log(" ")
loggerModified.log("[original] " + original.formattedText)
loggerModified.log("[modified] " + modified.formattedText)
+ messageHistory.put(key, MessageFilteringResult(original, ActionKind.MODIFIED, null, modified))
+ } else {
+ messageHistory.put(key, MessageFilteringResult(original, ActionKind.ALLOWED, null, null))
}
}
@@ -104,4 +149,28 @@ class ChatManager {
val seaCreature = SeaCreatureManager.getSeaCreature(chatEvent.message) ?: return
SeaCreatureFishEvent(seaCreature, chatEvent).postAndCatch()
}
+
+ fun openChatFilterGUI() {
+ SkyHanniMod.screenToOpen = ChatFilterGui(getRecentMessageHistory())
+ }
+
+ val chatLinesField by lazy {
+ MethodHandles.publicLookup().unreflectGetter(
+ ReflectionHelper.findField(GuiNewChat::class.java, "chatLines", "field_146252_h", "h")
+ .makeAccessible()
+ )
+ }
+
+ fun retractMessage(message: IChatComponent?, reason: String) {
+ if (message == null) return
+ val chatGUI = Minecraft.getMinecraft().ingameGUI.chatGUI
+ @Suppress("UNCHECKED_CAST")
+ val chatLines = chatLinesField.invokeExact(chatGUI) as MutableList<ChatLine>
+ if (!chatLines.removeIf { it.chatComponent === message }) return
+ chatGUI.refreshChat()
+
+ val history = messageHistory[IdentityCharacteristics(message)] ?: return
+ history.actionKind = ActionKind.RETRACTED
+ history.actionReason = reason.uppercase()
+ }
} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilterGui.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilterGui.kt
new file mode 100644
index 000000000..971878306
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilterGui.kt
@@ -0,0 +1,119 @@
+package at.hannibal2.skyhanni.features.chat
+
+import at.hannibal2.skyhanni.data.ChatManager
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.OSUtils
+import io.github.moulberry.moulconfig.internal.GlScissorStack
+import io.github.moulberry.moulconfig.internal.RenderUtils
+import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.GuiScreen
+import net.minecraft.client.gui.GuiUtilRenderComponents
+import net.minecraft.client.gui.ScaledResolution
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.util.IChatComponent
+import org.lwjgl.input.Mouse
+
+class ChatFilterGui(private val history: List<ChatManager.MessageFilteringResult>) : GuiScreen() {
+ private var scroll = -1.0
+ private val w = 500
+ private var wasMouseButtonDown = false
+ private val h = 300
+ private val reasonMaxLength =
+ history.maxOf { it.actionReason?.let { Minecraft.getMinecraft().fontRendererObj.getStringWidth(it) } ?: 0 }
+ private val historySize by lazy {
+ history.sumOf { splitLine(it.message).size * 10 + if (it.modified != null) splitLine(it.modified).size * 10 else 0 }
+ }
+
+ override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) {
+ super.drawScreen(mouseX, mouseY, partialTicks)
+ drawDefaultBackground()
+ GlStateManager.pushMatrix()
+ val l = (width / 2.0 - w / 2.0).toInt()
+ val t = (height / 2.0 - h / 2.0).toInt()
+ GlStateManager.translate(l + 0.0, t + 0.0, 0.0)
+ RenderUtils.drawFloatingRectDark(0, 0, w, h)
+ GlStateManager.translate(5.0, 5.0 - scroll, 0.0)
+ var mouseX = mouseX - l
+ val isMouseButtonDown = if (mouseX in 0..w && mouseY in t..(t + h)) Mouse.isButtonDown(0) else false
+ var mouseY = mouseY - (t - scroll).toInt()
+ val sr = ScaledResolution(mc)
+ GlScissorStack.push(l + 5, t + 5, w + l - 5, h + t - 5, sr)
+
+ for (msg in history) {
+ drawString(mc.fontRendererObj, msg.actionKind.renderedString, 0, 0, -1)
+ drawString(mc.fontRendererObj, msg.actionReason, ChatManager.ActionKind.maxLength + 5, 0, -1)
+ var size = drawMultiLineText(
+ msg.message,
+ ChatManager.ActionKind.maxLength + reasonMaxLength + 10,
+ )
+ if (msg.modified != null) {
+ drawString(
+ mc.fontRendererObj,
+ "§e§lNEW TEXT",
+ 0, 0, -1
+ )
+ size += drawMultiLineText(
+ msg.modified,
+ ChatManager.ActionKind.maxLength + reasonMaxLength + 10,
+ )
+ }
+ if (mouseX in 0..w && mouseY in 0..(size * 10) && (isMouseButtonDown && !wasMouseButtonDown)) {
+ if (LorenzUtils.isShiftKeyDown()) {
+ OSUtils.copyToClipboard(IChatComponent.Serializer.componentToJson(msg.message))
+ LorenzUtils.chat("Copied structured chat line to clipboard")
+ } else {
+ OSUtils.copyToClipboard(msg.message.formattedText)
+ LorenzUtils.chat("Copied chat line to clipboard")
+ }
+ }
+ mouseY -= size * 10
+ }
+ GlScissorStack.pop(sr)
+ wasMouseButtonDown = isMouseButtonDown
+ GlStateManager.popMatrix()
+ GlStateManager.color(1f, 1f, 1f, 1f)
+ }
+
+ fun splitLine(comp: IChatComponent): List<IChatComponent> {
+ return GuiUtilRenderComponents.splitText(
+ comp,
+ w - (ChatManager.ActionKind.maxLength + reasonMaxLength + 10 + 10),
+ mc.fontRendererObj,
+ false,
+ true
+ )
+ }
+
+ override fun initGui() {
+ super.initGui()
+ if (this.scroll < 0) {
+ setScroll(1000000000.0)
+ }
+ }
+
+ fun setScroll(newScroll: Double) {
+ this.scroll = newScroll.coerceAtMost(historySize - h + 10.0).coerceAtLeast(0.0)
+ }
+
+ fun drawMultiLineText(comp: IChatComponent, xPos: Int): Int {
+ val modifiedSplitText = splitLine(comp)
+ for (line in modifiedSplitText) {
+ drawString(
+ mc.fontRendererObj,
+ line.formattedText,
+ xPos,
+ 0,
+ -1
+ )
+ GlStateManager.translate(0F, 10F, 0F)
+ }
+ return modifiedSplitText.size
+ }
+
+
+ override fun handleMouseInput() {
+ super.handleMouseInput()
+ setScroll(scroll - Mouse.getEventDWheel())
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/CompactBestiaryChatMessage.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/CompactBestiaryChatMessage.kt
index 7b893afcf..67c76617b 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/chat/CompactBestiaryChatMessage.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/chat/CompactBestiaryChatMessage.kt
@@ -1,6 +1,7 @@
package at.hannibal2.skyhanni.features.chat
import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.ChatManager
import at.hannibal2.skyhanni.events.LorenzChatEvent
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.LorenzUtils.makeAccessible
@@ -41,13 +42,8 @@ class CompactBestiaryChatMessage {
if (message == titleMessage) {
event.blockedReason = "bestiary"
- val chatGUI = Minecraft.getMinecraft().ingameGUI.chatGUI
- val chatLinesField = ReflectionHelper.findField(chatGUI.javaClass, "chatLines")
- val chatLines = chatLinesField.makeAccessible().get(chatGUI) as MutableList<ChatLine>
-
- lastBorder?.let { chat -> chatLines.removeIf { it.chatComponent === chat } }
- lastEmpty?.let { chat -> chatLines.removeIf { it.chatComponent === chat } }
- chatGUI.refreshChat()
+ ChatManager.retractMessage(lastBorder, "bestiary")
+ ChatManager.retractMessage(lastEmpty, "bestiary")
lastBorder = null
lastEmpty = null
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/IdentityCharacteristics.kt b/src/main/java/at/hannibal2/skyhanni/utils/IdentityCharacteristics.kt
new file mode 100644
index 000000000..5b1399f73
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/IdentityCharacteristics.kt
@@ -0,0 +1,12 @@
+package at.hannibal2.skyhanni.utils
+
+class IdentityCharacteristics<T>(val value: T) {
+ override fun equals(other: Any?): Boolean {
+ if (other !is IdentityCharacteristics<*>) return false
+ return this.value === other.value
+ }
+
+ override fun hashCode(): Int {
+ return System.identityHashCode(value)
+ }
+}